the djb way

qmail


qmail-qmtpd service

QMTP is the "Quick Mail Transport Protocol", developed by Daniel J. Bernstein. It is an alternative to SMTP, with a simpler and vastly more efficient client/server connection dialogue. Bernstein describes QMTP in this short document: http://cr.yp.to/proto/qmtp.txt.

We really like QMTP, and almost always setup a qmail-qmtpd service with each qmail installation. It is an essential piece of our qmail toolbox for poorly connected networks, as we describe in the section on "qmail unplugged" and the serialmail package. Also, by making a patch to qmail and configuring a suitable MX record, our qmail installations get to join the QMTP set whenever they find another QMTP host to talk to.

The standard qmail package includes a QMTP server, in the executable /var/qmail/bin/qmail-qmtpd. In the installation page, we recommended installing the qmtpd-netstring.patch to protect this service from buffer overflows with bad netstring input. If you skipped that patch earlier, we suggest you reinstall with it now.

Otherwise, all you need to run qmail-qmtpd is the usual daemontools/ucspi-tcp service. For slow typers this will take, oh, about 106 seconds.

First, make directories for the service definition:

# mkdir -p /var/svc.d/qmail-qmtpd/log

Then, install this daemontools "run" script in /var/svc.d/qmail-qmtpd/run:


#!/bin/sh
# qmail-qmtpd/run
# daemontools run script for qmail qmtp service
# ===
CONLIMIT=61

exec 2>&1
echo "*** Starting qmail-qmtpd..."
exec \
  envuidgid qmaild \
  softlimit -m 3000000 -f 10000000 \
  tcpserver -v -HR \
  -U \
  -c ${CONLIMIT} \
  -x /etc/tcprules/qmtp.cdb \
  0 209 \
    /var/qmail/bin/qmail-qmtpd

### that's all, folks!

Make sure the run script is executable, chmod 755. Note the similarity between this run script and the qmail-smtpd SMTP service. The key differences:

Here's the matching multilog service, for /var/svc.d/qmail-qmtpd/log/run:


#!/bin/sh
# qmail-qmtpd/log/run
# multilogger from qmail-qmtpd service
exec setuidgid multilog multilog t /var/multilog/qmail-qmtpd

Make sure the script is executable. Then setup the multilog directory:

# mkdir /var/multilog/qmail-qmtpd
# chown multilog /var/multilog/qmail-qmtpd

The service run script we've shown here makes use of the -x option to tcpserver, to define access rules for the service. Set up the rules as you want in /etc/tcprules/qmtp.rules:


# qmtp.rules
127.:allow,RELAYCLIENT=""
10.0.1.:allow,RELAYCLIENT=""
10.0.1.22:allow,RELAYCLIENT="",DATABYTES="8000000"

In this example we use the same rules as for the SMTP service, to illustrate that qmail-qmtpd is affected by the same environmental variables and control files as qmail-smtpd. When the rules suit your own installation, compile them as usual:

# (cd /etc/tcprules; make qmtp.cdb)

Link the service to bring it up:

# ln -s /var/svc.d/qmail-qmtpd /service/qmail-qmtpd

Check the multilog to see that the service is running ok, while testing a simple connection from the command line:

$ mconnect "" 209
enter
$

The log should show a successful connection and termination. That's about all we can do from the command line, as the QMTP dialogue is otherwise encoded in netstrings. For more testing and use of qmail-qmtpd, see the maildirqmtp utility in the serialmail package, described in the "qmail unplugged" section.

mxps and the qmtp cognoscenti

There aren't a lot of QMTP dialogues going on out there. Relatively few QMTP servers are deployed, and few QMTP client applications are available to use them.

But once we have a qmail-qmtpd service, it's a damn shame not to use it. We want to see connections to and from port 209, and feel the sheer thrill in being a member of the QMTP cognoscenti.

Two things are necessary to join the QMTP set:

These pieces work together. The patch lets our own qmail server recognize other QMTP servers with the special MX record, and enables it to send outbound email using QMTP whenever possible. Configuring the MX record for our domain lets other QMTP hosts know we have the capability of receiving via QMTP ourselves.

We will discuss the MX business first. Bernstein has defined the Mail Exchange Protocol Switch (MXPS) in this document at http://cr.yp.to/im/mxps.html. It describes the use of the MX record "distance" field as a simple means to indicate QMTP capability. If the MX record for a domain is assigned a distance number of 12801 (or any of 15 succeeding numbers at intervals of 16, up to and including 13041), an MXPS- and QMTP-aware client may/should try to use QMTP at port 209. Otherwise, if the QMTP connection attempt fails, or if the client is not MXPS/QMTP aware, the client falls back to SMTP at port 25 as usual.

Configuring the MX record(s) to indicate QMTP service is easily done by editing the data file used by tinydns:

# cd /service/tinydns/root
# vi data

If you have used the ./add-mx utility to enter your tinydns data, find the MX record for your domain that looks something like:

@example.org:1.2.3.5:a::86400

The leading @ "at-sign" indicates an MX record in the tinydns-data format. In this record the distance field is empty, as seen by the :: between the a and the 86400, representing the default distance of 0.

Now edit or create this line to insert an entry in the distance field, using one of the MXPS "magic" numbers (shown here in bold):

@example.org:1.2.3.5:a:12801:86400

If you have multiple QMTP-enabled servers receiving for your domain, make additional MX record entries as necessary:

@example.org:1.2.3.5:a:12801:86400
@example.org:1.2.3.6:b:12817:86400

In this example, host "1.2.3.5" will have a higher priority than "1.2.3.6". If you wanted both hosts to have the same priority, to balance load among each server, set each record with the same distance number instead, eg. 12801.

Then save the data file and rebuild data.cdb:

# make

Check the MX records now being published by tinydns:

$ dnsmx example.org
12801 a.mx.example.org
12817 b.mx.example.org

Good, these are MX records with "distance" fields to advise MXPS-aware applications of QMTP capability.

Now to patch qmail-remote, download Russell Nelson's qmail-1.03-qmtpc.patch into your local patch archive. (Also available locally here.) Then patch and rebuild qmail in the usual way as follows:

# cd /usr/local/djb/build/qmail-1.03
# patch -p1 < ../../patches/qmail-1.03.qmtpc.patch
# make

Bring down the qmail-send service temporarily. Then install the new qmail-remote binary and restart the service:

# cp /var/qmail/bin/qmail-remote /var/qmail/bin/qmail-remote.orig
# cp qmail-remote /var/qmail/bin/qmail-remote.qmtpc
# svc -d /service/qmail-send
# cp qmail-remote /var/qmail/bin/qmail-remote
# svc -u /service/qmail-send

Your qmail installation is now fully QMTP-aware and capable. Welcome to the QMTP set!


Copyright © 2004, Wayne Marshall.
All rights reserved.

Last edit 2004.10.04, wcm.