aboutsummaryrefslogtreecommitdiffstats
path: root/core/portmanager.lua
diff options
context:
space:
mode:
Diffstat (limited to 'core/portmanager.lua')
-rw-r--r--core/portmanager.lua58
1 files changed, 51 insertions, 7 deletions
diff --git a/core/portmanager.lua b/core/portmanager.lua
index bed5eca5..dc0d0abc 100644
--- a/core/portmanager.lua
+++ b/core/portmanager.lua
@@ -9,7 +9,8 @@ local set = require "util.set";
local table = table;
local setmetatable, rawset, rawget = setmetatable, rawset, rawget;
-local type, tonumber, tostring, ipairs = type, tonumber, tostring, ipairs;
+local type, tonumber, ipairs = type, tonumber, ipairs;
+local pairs = pairs;
local prosody = prosody;
local fire_event = prosody.events.fire_event;
@@ -95,25 +96,25 @@ local function activate(service_name)
}
bind_ports = set.new(type(bind_ports) ~= "table" and { bind_ports } or bind_ports );
- local mode, ssl = listener.default_mode or default_mode;
+ local mode = listener.default_mode or default_mode;
local hooked_ports = {};
for interface in bind_interfaces do
for port in bind_ports do
local port_number = tonumber(port);
if not port_number then
- log("error", "Invalid port number specified for service '%s': %s", service_info.name, tostring(port));
+ log("error", "Invalid port number specified for service '%s': %s", service_info.name, port);
elseif #active_services:search(nil, interface, port_number) > 0 then
log("error", "Multiple services configured to listen on the same port ([%s]:%d): %s, %s", interface, port,
active_services:search(nil, interface, port)[1][1].service.name or "<unnamed>", service_name or "<unnamed>");
else
- local err;
+ local ssl, cfg, err;
-- Create SSL context for this service/port
if service_info.encryption == "ssl" then
local global_ssl_config = config.get("*", "ssl") or {};
local prefix_ssl_config = config.get("*", config_prefix.."ssl") or global_ssl_config;
log("debug", "Creating context for direct TLS service %s on port %d", service_info.name, port);
- ssl, err = certmanager.create_context(service_info.name.." port "..port, "server",
+ ssl, err, cfg = certmanager.create_context(service_info.name.." port "..port, "server",
prefix_ssl_config[interface],
prefix_ssl_config[port],
prefix_ssl_config,
@@ -127,7 +128,12 @@ local function activate(service_name)
end
if not err then
-- Start listening on interface+port
- local handler, err = server.addserver(interface, port_number, listener, mode, ssl);
+ local handler, err = server.listen(interface, port_number, listener, {
+ read_size = mode,
+ tls_ctx = ssl,
+ tls_direct = service_info.encryption == "ssl";
+ sni_hosts = {},
+ });
if not handler then
log("error", "Failed to open server port %d on %s, %s", port_number, interface,
error_to_friendly_message(service_name, port_number, err));
@@ -137,6 +143,7 @@ local function activate(service_name)
active_services:add(service_name, interface, port_number, {
server = handler;
service = service_info;
+ tls_cfg = cfg;
});
end
end
@@ -163,7 +170,7 @@ end
local function register_service(service_name, service_info)
table.insert(services[service_name], service_info);
- if not active_services:get(service_name) then
+ if not active_services:get(service_name) and prosody.process_type == "prosody" then
log("debug", "No active service for %s, activating...", service_name);
local ok, err = activate(service_name);
if not ok then
@@ -222,15 +229,52 @@ end
-- Event handlers
+local function add_sni_host(host, service)
+ log("debug", "Gathering certificates for SNI for host %s, %s service", host, service or "default");
+ for name, interface, port, n, active_service --luacheck: ignore 213
+ in active_services:iter(service, nil, nil, nil) do
+ if active_service.server.hosts and active_service.tls_cfg then
+ local config_prefix = (active_service.config_prefix or name).."_";
+ if config_prefix == "_" then config_prefix = ""; end
+ local prefix_ssl_config = config.get(host, config_prefix.."ssl");
+ local alternate_host = service and config.get(host, service.."_host");
+ if not alternate_host and service == "https" then
+ -- TODO should this be some generic thing? e.g. in the service definition
+ alternate_host = config.get(host, "http_host");
+ end
+ local autocert = certmanager.find_host_cert(alternate_host or host);
+ -- luacheck: ignore 211/cfg
+ local ssl, err, cfg = certmanager.create_context(host, "server", prefix_ssl_config, autocert, active_service.tls_cfg);
+ if ssl then
+ active_service.server.hosts[alternate_host or host] = ssl;
+ else
+ log("error", "Error creating TLS context for SNI host %s: %s", host, err);
+ end
+ end
+ end
+end
prosody.events.add_handler("item-added/net-provider", function (event)
local item = event.item;
register_service(item.name, item);
+ for host in pairs(prosody.hosts) do
+ add_sni_host(host, item.name);
+ end
end);
prosody.events.add_handler("item-removed/net-provider", function (event)
local item = event.item;
unregister_service(item.name, item);
end);
+prosody.events.add_handler("host-activated", add_sni_host);
+prosody.events.add_handler("host-deactivated", function (host)
+ for name, interface, port, n, active_service --luacheck: ignore 213
+ in active_services:iter(nil, nil, nil, nil) do
+ if active_service.tls_cfg then
+ active_service.server.hosts[host] = nil;
+ end
+ end
+end);
+
return {
activate = activate;
deactivate = deactivate;