The smtpd-starttls-proxy-io program
smtpd-starttls-proxy-io is a program that runs in front of a UCSPI-compliant
SMTP server (such as qmail-smtpd) and extends it with STARTTLS
smtpd-starttls-proxy-io provides no TLS on its own;
instead, it expects to be run under a
server, and interfaces with it.
- smtpd-starttls-proxy-io forks and the parent execs into smtpd....
smtpd-starttls-proxy-io sticks around as a child process.
- smtpd-starttls-proxy-io interposes itself between the client connection
(stdin/stdout) and smtpd; the latter still talks to its stdin/stdout but those
are only connected to smtpd-starttls-proxy-io.
- smtpd-starttls-proxy-io acts as an SMTP server to the client, and as
an SMTP client to the server. It advertises STARTTLS capability to the client in addition
to smtpd's capabilities.
- If it receives a STARTTLS command, it triggers the UCSPI-TLS process to
perform a TLS handshake, then execs into
data between the TLS layer and smtpd until the end of the connection.
- If, instead, it receives a HELO command, which indicates lack of STARTTLS
support in the client, or a MAIL command, which indicates a desire to send mail
without requiring TLS, it deactivates the UCSPI-TLS process, then execs into
s6-ioconnect, this time
transmitting plaintext data between the network and smtpd until the end of the
smtpd-starttls-proxy-io expects to be run under a UCSPI-TLS server such as
sslserver -n. As a
consequence, it expects its environment to contain the following variables:
- SSLCTLFD: the file descriptor number of the UCSPI-TLS control socket
- SSLREADFD: the file descriptor number of the pipe used to read data from the TLS tunnel after it has been activated
- SSLWRITEFD: the file descriptor number of the pipe used to write data to the TLS tunnel after it has been activated.
smtpd-starttls-proxy-io will refuse to run if one of these variables
is nonexistent or contains invalid data.
You can run a STARTTLS-enabled qmail-smtpd mail receiver on
address hostip port port with the following steps:
- Install s6-networking
and make sure to activate TLS support. (bearssl is recommended over libtls.)
- Define proper environment variables for your TLS connection: at least
CERTFILE and KEYFILE. The environment you need is documented on the
- Refine your security with additional environment variables: TLS_UID and TLS_GID to
avoid running the TLS engine as root, and UID and GID to avoid running the SMTP server (and
smtpd-starttls-proxy-io!) as root.
- If you wish, also refine the following command line with various options to every tool
that appears, for fine tuning of connection parameters.
- The following command line is only one command line, which makes heavy use
of chainloading. It has been broken down into several lines for readability.
(Note that you don't need the backslashes if you're writing an
s6-tcpserver -- hostip port \
s6-tcpserver-access -Dl0 -t5000 -- \
s6-ucspitlsd -K30000 -- \
s6-applyuidgid -Uz -- \
will listen on socket TCP:hostip:port and spawn the rest of its
command line as a child for every client connection. (Think inetd-like.)
will fine-tune some TCP parameters of the connection. It can also do ip-based access
control, and that's its main use, but that's not what we're using it for here.
will create a control channel for opportunistic TLS and wait for a command.
- s6-applyuidgid will
drop root privileges.
- smtpd-starttls-proxy-io will exchange data with the client and the server,
and depending on what the client wants, tell
either to drop it entirely or to perform a TLS handshake.
- qmail-smtpd is the
real SMTP server, does nothing else than speak SMTP to its stdin/stdout, does not support
STARTTLS, and is blissfully unaware of all the plumbing and shenanigans that happen
- smtpd-starttls-proxy-io is significantly less polite than qmail-smtpd
when the client does not follow proper protocol.