diff --git a/spamd/spamd.raw b/spamd/spamd.raw index 7215d4dbdd..278b56433d 100755 --- a/spamd/spamd.raw +++ b/spamd/spamd.raw @@ -812,6 +812,26 @@ my @listen_socket_specs = @{$opt{'listen-sockets'}}; # supply a default socket (loopback IP address) if none specified push(@listen_socket_specs, 'localhost') if !@listen_socket_specs; +# When --ssl-port is set and no spec uses an explicit ssl: prefix, the user +# has explicitly requested both a plain-TCP port and an SSL port. Expand +# each address spec into a plain/SSL pair so that both listeners are created +# on every requested address. The port assignment logic below will use +# --port for the plain socket and --ssl-port for the SSL one. +# This applies whether the addresses came from -i or from the localhost +# default above. +if (defined $opt{'ssl-port'} && !grep { m{^ssl:}i } @listen_socket_specs) { + @listen_socket_specs = map { ($_, "ssl:$_") } @listen_socket_specs; +} + +# Detect whether any socket spec uses an explicit "ssl:" prefix. When the +# user is mixing SSL and plain-TCP sockets via per-socket prefixes they are +# exercising explicit per-socket SSL control. In that mode the global --ssl +# flag (which may have been implied by --ssl-verify / --ssl-ca-file) must not +# forcibly upgrade non-prefixed sockets to SSL; the absence of a prefix +# unambiguously means "plain TCP". The legacy single-socket --ssl behaviour +# is preserved when no spec carries an explicit "ssl:" prefix. +my $has_explicit_ssl_spec = grep { m{^ssl:}i } @listen_socket_specs; + for (@listen_socket_specs) { my $socket_specs = $_; @@ -839,7 +859,15 @@ for (@listen_socket_specs) { (?: : ( [a-z0-9-]* ) )? \z }xsi) { my($proto,$addr,$port) = ($1, $2||$3||$4||$5, $6); $addr = 'localhost' if !defined $addr; - $proto = 'ssl' if defined $opt{'ssl'} || defined $opt{'ssl-port'}; + # Apply the global --ssl / --ssl-port default only when the user has NOT + # used explicit "ssl:" prefixes anywhere in their -i specs. If any spec + # carries an explicit "ssl:" prefix the user is doing per-socket SSL + # control: a spec without the prefix deliberately means plain TCP and + # must not be overridden here (even when --ssl was implied by, e.g., + # --ssl-ca-file). When no spec uses the prefix the legacy behaviour is + # preserved: --ssl (or anything that implies it) makes all sockets SSL. + $proto = 'ssl' if !$has_explicit_ssl_spec && !defined $proto + && (defined $opt{'ssl'} || defined $opt{'ssl-port'}); $proto = !defined($proto) ? '' : lc($proto); $port = $opt{'ssl-port'} if !defined $port && $proto eq 'ssl'; $port = $opt{'port'} if !defined $port || $port eq ''; @@ -3497,15 +3525,22 @@ global --port (and --ssl-port) setting. An IPv6 addresses should be enclosed in square brackets, e.g. [::1]:783. For compatibility square brackets on an IPv6 address may be omitted if a port number specification is also omitted. +Note that listening on non-loopback addresses does not automatically permit +connections from those addresses. The B<-A> / B<--allowed-ips> option +controls which source addresses may connect, and defaults to localhost only +(127.0.0.1 and ::1). If you listen on external interfaces you must add the +appropriate addresses to B<-A> explicitly. + =item B<-p> I, B<--port>=I Optionally specifies the port number for the server to listen on (default: 783). -If the B<--ssl> switch is used, and B<--ssl-port> is not supplied, then this -port will be used to accept SSL connections instead of unencrypted connections. -If the B<--ssl> switch is used, and B<--ssl-port> is set, then unencrypted -connections will be accepted on the B<--port> at the same time as encrypted -connections are accepted at B<--ssl-port>. +If the B<--ssl> switch is used without B<--ssl-port>, this port accepts SSL +connections instead of unencrypted connections. If B<--ssl-port> is also set +(which itself implies B<--ssl>), then unencrypted connections are accepted on +B<--port> and encrypted connections are accepted on B<--ssl-port> +simultaneously. Use B<-i> / B<--listen> with an C prefix for finer +control over which addresses and ports carry SSL vs plain-TCP traffic. =item B<-q>, B<--sql-config> @@ -3733,6 +3768,20 @@ connections from specified test networks and from localhost. In absence of the B<-A> option, connections are only accepted from IP address 127.0.0.1 or ::1, i.e. from localhost on a loopback interface. +To allow connections from any address, use B<-A 0.0.0.0/0> for IPv4 and +B<-A ::/0> for IPv6. Do not do this unless spamd is on a private network +and/or protected by an OS-level firewall. + +If you add external addresses to B<-A> in order to listen on non-loopback +interfaces, you must also explicitly include C<127.0.0.1> and/or C<::1> in +the list if you still want to allow local connections; the default is +replaced, not extended. + +Note that the allowed-IP list is global across all listening sockets — there +is no per-socket access control. A source address permitted by B<-A> may +connect to any socket spamd is listening on, regardless of which interface +that socket is bound to. For tighter control, firewall rules at the OS level +can be used alongside B<-A> as a belt-and-suspenders measure. =item B<-D> [I], B<--debug> [I] @@ -3850,20 +3899,25 @@ home directory instead. =item B<--ssl> -Accept only SSL connections on the associated port. -The B perl module must be installed. +Accept SSL connections. The B perl module must be installed. -If the B<--ssl> switch is used, and B<--ssl-port> is not supplied, then -B<--port> port will be used to accept SSL connections instead of unencrypted -connections. If the B<--ssl> switch is used, and B<--ssl-port> is set, then -unencrypted connections will be accepted on the B<--port>, at the same time as -encrypted connections are accepted at B<--ssl-port>. +When used without B<-i> / B<--listen> and without B<--ssl-port>, the single +default listener (B<--port>) is converted to SSL. When used together with +B<--ssl-port> (which also implies B<--ssl>), two default listeners are +created: a plain-TCP listener on B<--port> and an SSL listener on +B<--ssl-port>. When B<-i> / B<--listen> options are present, B<--ssl> has no +effect on individual sockets — use the C prefix on B<-i> arguments +instead (e.g. C<-i ssl:*:784 -i *:783>). =item B<--ssl-verify> -Implies B<--ssl>. Request a client certificate and verify the certificate. +Implies B<--ssl>. Request a client certificate and verify the certificate. Requires B<--ssl-ca-file> or B<--ssl-ca-path>. +Note that verification is limited to confirming the certificate is signed by +the specified CA. Hostname (CN) matching and CRL checking are not performed, +as spamd has no options to configure either. + =item B<--ssl-ca-file>=I Implies B<--ssl-verify>. Use the specified Certificate Authority @@ -3873,23 +3927,35 @@ be signed by this certificate. =item B<--ssl-ca-path>=I Implies B<--ssl-verify>. Use the Certificate Authority certificate files in -the specified set of directories to verify the client certificate. The -client certificate must be signed by one of these Certificate Authorities. -See the man page for B for additional details. +the specified directory to verify the client certificate. The client +certificate must be signed by one of these Certificate Authorities. The +directory must be hashed in the usual manner (see B(1)). =item B<--ssl-port>=I -Optionally specifies the port number for the server to listen on for -SSL connections (default: whatever --port uses). See B<--ssl> for -more details. +Specifies the port number for SSL connections. Implies B<--ssl>. When +B<-i> / B<--listen> options are given without explicit C prefixes, +each address is expanded into a plain-TCP listener on B<--port> and an SSL +listener on B<--ssl-port>, matching the no-B<-i> behaviour. + +If you intend to accept SSL connections from non-local clients you should +think carefully about which addresses each listener is bound to. Use +explicit C prefixes on B<-i> arguments if you need independent control +over the address bindings for the plain-TCP and SSL sockets. For example, +C<-i ssl:*:11784 -i *:11783> listens on all interfaces for both SSL and +plain-TCP, while C<-i ssl:*:11784 -i localhost:11783> accepts SSL connections +from any host but restricts plain-TCP to local connections only, avoiding SSL +overhead for processes on the same machine. =item B<--server-key> I -Specify the SSL key file to use for SSL connections. +Specify the SSL key file to use for SSL connections. Defaults to +F<@@LOCAL_RULES_DIR@@/certs/server-key.pem>. =item B<--server-cert> I -Specify the SSL certificate file to use for SSL connections. +Specify the SSL certificate file to use for SSL connections. Defaults to +F<@@LOCAL_RULES_DIR@@/certs/server-cert.pem>. =item B<--socketpath> I