the djb way


qmail-ofmipd service

OFMIP stands for the "Old-Fashioned Mail Injection Protocol". You won't find any RFCs that define it; OFMIP is based on Bernstein's observations regarding the typical fixups that some SMTP servers provide for some SMTP clients. The clients receiving OFMIP services are generally desktop email applications, otherwise known as "mail user agents", queueing messages from the local network for further delivery elsewhere.

Let's back up a minute. Broadly speaking, these days an SMTP server typically serves two types of clients:

In the first case, one SMTP server connects with another SMTP server, transmitting a message to its intended destination. This is what SMTP was designed for.

In the second case, a user's desktop MUA program --such as Sylpheed or Doubtlook-- connects with an SMTP server on the local network, using the SMTP protocol only for the purposes of "injecting" a message into the server's outbound queue.

Because many MUAs inject messages that are incomplete or incorrect with respect to RFC822 header information, an SMTP server may try to fix things up. So OFMIP is what an SMTP server does when it steps in to complete and/or correct the header information supplied by the client. Such services may include:

In typical djb fashion, Bernstein has recognized the distinctions between the two types of services, and has developed a server specifically designed for the purposes of accepting messages from MUAs on the local network. This is the ofmipd program included in the mess822 package.

When you setup a qmail-ofmipd service, it will almost always be done in conjuction with an existing qmail-smtpd service. That is, you will use the qmail-ofmipd service specifically for connections from the local network, while continuing to service remote SMTP connections as usual with qmail-smtpd.

Both services will usually be running on the same host, using the same qmail queue. But things need to be setup in such a way that each server provides for the clients it was designed for.

There are a couple ways you can go about partitioning a qmail installation to provide both OFMIP and SMTP services:

With the first strategy, qmail-smtpd runs on the SMTP port (25) as usual, while the qmail-ofmipd service runs on some alternative port. There is no port especially designated for OFMIP; port 26 is suggested by Bernstein. This requires that all the MUA clients on the local network be configured to connect to port 26, rather than the customary SMTP port 25.

The second strategy is usually more appropriate, and means your qmail server will be configured with (at least) two IP addresses. These two IP addresses may be obtained by either of two methods:

Either way, one IP address will be used by qmail-smtpd to service connections coming from remote hosts, as usual. The second IP address will be used by qmail-ofmipd to service connections from the local network.

Here's a sketch of the concept:

==================           ==================
| qmail-ofmipd   |           | qmail-smptd    |
|                |           |                |
|  |           |        |
| port 25        |           | port 25        |
==================           ==================
                  \         /
  [lan]       |.......   ............... [internet]
              |      :   :
"alice"       |      +---+  |      |   |
+---+.........|      |   |
|   |         |      |   |
|   |         |      +---+
|   |         |
+---+         |
"betty"       |  |
|   |         |
|   |         |
|   |

The first thing to do is to make a small change to the existing qmail-smtpd run script, telling tcpserver to listen on a specific IP address:

# qmail-smtpd/run
# daemontools run script for qmail smtp service
# ** specify IP address, to partition for ofmipd service **
# ===

exec 2>&1
echo "*** Starting qmail-smtpd..."
exec \
  envuidgid qmaild \
  softlimit -m 3000000 -f 10000000 \
  tcpserver -v -HR \
  -U \
  -c ${CONLIMIT} \
  -x /etc/tcprules/smtp.cdb \
  ${IP} ${PORT} \

### that's all, folks!

Name this script for now, and make sure it is executable, chmod 755. We'll restart the new qmail-smtpd service with it soon.

The tcpserver access rules in /etc/tcprules/smtp.rules may also be modified:

# smtp.rules
# force local clients to use ofmipd service:
# accept all remote connections:

The first "deny" rule here is rather extreme and is shown just as an example to emphasize our intent. Otherwise the rules assume we will be accepting connections from all remote SMTP servers. Notice also that we don't need to setup any RELAYCLIENTs anymore, since the qmail-ofmipd service will be used for that purpose instead.

Now we can proceed to setup the qmail-ofmipd service, using daemontools and ucspi-tcp in the usual way. First, make the local service directories:

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

Here's the "run" script for /var/svc.d/qmail-ofmipd/run:

# qmail-ofmipd/run
# daemontools run script for qmail ofmipd service
# ** ofmipd from mess822 package **
# ===

exec 2>&1
echo "*** Starting qmail-ofmipd..."
echo "*** >> using names from: ${CDB}"
exec \
  envuidgid qmaild \
  softlimit -m 3000000 -f 10000000 \
  tcpserver -v -hR \
  -U \
  -c ${CONLIMIT} \
  -x /etc/tcprules/ofmip.cdb \
  ${IP} ${PORT} /usr/local/bin/ofmipd ${CDB}

### that's all, folks!

Make sure the script is executable, chmod 755. Overall this script is nearly identical to the run script for the modified qmail-smtpd service, above. Of course we bind tcpserver to the specific IP address for the LAN connections, and use the ofmipd executable included with the mess822 package.

What is different here is that ofmipd may take an optional argument, the name of a cdb file to use for rewriting return-path ("From:") addresses. We'll look at this cdb file on the ofmipname page.

For now, go ahead install the multilog run script in /var/svc.d/qmail-ofmipd/log/run:

# qmail-ofmipd/log/run
# multilogger for qmail-ofmipd service
# ===
exec setuidgid multilog multilog t /var/multilog/qmail-ofmipd

Make the script executable, chmod 755. Then setup the multilog directory:

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

Next setup the access rules for tcpserver, in /etc/tcprules/ofmip.rules:

# ofmip.rules

These rules allow connections from the local network, ONLY! This is essential, because ofmipd treats all clients as RELAYCLIENTs. In other words, ofmipd is an open relay for any client that is able to make a connection. Be sure to lock down access to the qmail-ofmipd service with tcprules, so you don't give spammers a springboard for their garbage.

These rules also illustrate a couple of other crucial differences between ofmipd and qmail-smtpd:

So not only will ofmipd accept messages for any destination, it will also accept messages of any size. This is where the softlimit -f parameter comes into use, to force an upper limit on the size of message that ofmipd may actually accept. (Connections sending mail exceeding that size will gracefully fail with a "disk full" error message.)

"Compile" the new rules for smtp and ofmip:

# (cd /etc/tcprules; make all)

Now we are ready to start everything up:

# cd /service
# svc -d qmail-smtpd
# mv qmail-smtpd/ qmail-smtpd/run
# svc -u qmail-smtpd
# ln -s /var/svc.d/qmail-ofmipd /service/qmail-ofmipd

Take a look at the logs to see everything is rolling. Try a manual connection with the new service:

$ mconnect 25
220 ofmipd.local ESMTP
helo localhost
250 ofmipd.local
220 ofmipd.local

Then send some test messages from local MUA clients and check the headers. You should now notice "Received:" lines like this:

Received: (ofmipd; 26 Feb 2004 06:24:12 -0000

The service is working; you are now injecting with OFMIP!

Once the service is running, qmail-ofmipd may be further configured by:

The cdb file is discussed on the page covering ofmipname, coming up next.

The hostname rewriting facilities for both ofmipd and new-inject are discussed on the page control/rewrite.

note: qmail and leapseconds

If you take another look at the header of a message injected by ofmipd, you will actually see (at least) two "Received:" lines, and they may look something like this:

Received: (qmail 5102 invoked by uid 0); 26 Feb 2004 06:24:34 -0000
Received: (ofmipd; 26 Feb 2004 06:24:12 -0000

Look carefully at the timestamps. Did it actually take qmail 22 seconds to find the new message injected by ofmipd?

No, not really. The difference is that qmail-1.03 doesn't handle leapseconds properly, whereas mess822-0.58 does. (This is on a system where the timezone files have been setup the "right" way for a clockspeed installation.)

The mess822 timestamps represent TAI; that is, UTC plus leapseconds. The qmail timestamps don't think your system will be "right", so you get UTC plus leapseconds, plus leapseconds.

Bernstein has acknowledged the problem:

Copyright © 2004, Wayne Marshall.
All rights reserved.

Last edit 2004.03.09, wcm.