the djb way

you've got spam!


rblsmtpd

rblsmtpd is a tiny, special-purpose SMTP server included with the ucspi-tcp package. It's pretty good at blocking spam. Let's get right to it by looking at a qmail-smtpd service modified to use rblsmtpd, as shown in the following "run" script:


#!/bin/sh
# qmail-smtpd/run
# daemontools run script for qmail smtp service
#   + use rblsmtpd spam block
# ===
CONLIMIT=49

exec 2>&1

echo "*** Starting qmail-smtpd..."
exec \
  envuidgid qmaild \
    softlimit -m 3000000 -f 10000000 \
      tcpserver -v -PHR \
      -U \
      -c ${CONLIMIT} \
      -x /etc/tcprules/smtp.cdb \
      0 25 \
        /usr/local/bin/rblsmtpd -B -t 300 \
        -r l2.spews.dnsbl.sorbs.net \
        -r sbl-xbl.spamhaus.org \
          /var/qmail/bin/qmail-smtpd

### that's all, folks!

This is the same qmail-smtpd service under tcpserver as in our original qmail installation, only now shielded by the rblsmtpd utility. (The differences with the original service are shown above in bold.)

Here's what happens:

  1. When tcpserver gets an incoming connection on port 25, it launches rblsmtpd.

  2. rblsmtpd first looks up the remote IP address by making special DNS queries to the specified RBL servers.

  3. If no RBL record is returned for the remote IP address, rblsmtpd launches the qmail-smtpd server as usual.

  4. If an RBL record is returned, qmail-smtpd is not run. Instead, rblsmtpd maintains a limited dialogue with the incoming connection, returning either a temporary (4.5.1) or permanent (5.5.3) error.

In the example run script shown here, rblsmtpd is configured to check two publicly available RBL services:

These are only two of many RBL publishers active at the time of this writing (fall 2004). We picked these as representative examples, because they are aggressive, and because they are noted in the OpenBSD spamd configuration. See the Links/Resources for some other RBLs.

Any number of RBL basenames may be specified with separate -r options. Each RBL is queried in sequence; rblsmtpd stops at the first positive response.

It is also possible to specify "whitelists" to rblsmtpd, as arguments used with the -a option. These options are summarized below:

option mnemonic description
-a whitelist "accept" accept if A record found in whitelist lookup
-r blacklist "reject" reject if TXT record found in blacklist lookup

Because each RBL is checked in the order found on the command line, it is most common to put "accept" lists before "reject" lists. This allows a site to override RBL records for specific IP addresses if necessary. (The means for overriding blacklisted addresses and creating whitelists will be covered later in the sections on rbldns.)

As shown in the example run script, the rblsmtpd program also accepts a few other options:

option description
-B block with temporary error code (451) [default]
-b block with permanent error code (553)
-t secs timeout in seconds [default 60 seconds]

The -B and -t options can be used to try to effect a penalty on the remote host. That is, a temporary fail and possibly longer connection will tie up the resources of the spammer's host a little, adding a "cost" to their operations. Otherwise, the -b option will generally cause the remote host not to waste any more time with your server; they can quickly move on to spam others.

rbl queries

It is useful to understand how rblsmtpd uses DNS to perform queries against RBLs. First, rblsmtpd makes its query on the basis of the IP address of the remote server, as provided by the $TCPREMOTEIP variable set up by tcpserver.

Then the dot-quad notation of this remote IP address is reversed, such as from "1.2.3.4" to "4.3.2.1". The reversed IP address is then prepended to the basename of the RBL service. The resulting string forms an artificial, fully-qualified domain name, such as "4.3.2.1.basename".

Now a DNS query is made to lookup the resulting domain name. If the DNS lookup returns a TXT record, rblsmtpd uses the string in that TXT record as the error message returned to the remote client. The presumed spammer is blocked, and the regular qmail-smtpd service is never run.

For example, let's say the remote connection is from the IP address 202.63.160.111. The dot-quad of this IP address is reversed to form the string "111.160.63.202". This string is then prepended to the RBL basename "sbl-xbl.spamhaus.org", forming the artificial domain name:

111.160.63.202.sbl-xbl.spamhaus.org

Now rblsmptd performs a DNS lookup on this constructed hostname, checking for a TXT record just as we might use our djbdns utilities from the command line:

$ dnstxt 111.160.63.202.sbl-xbl.spamhaus.org
http://www.spamhaus.org/SBL/sbl.lasso?query=SBL16876

The presence of any TXT record indicates the remote host is listed in the Spamhaus RBL. In this case, the contents of that TXT record is the string:

rblsmtpd passes this string back to the remote host as the error message. If the remote administrator happens to be checking her logs, she may find a clue as to why mail delivery is failing. The Spamhaus RBL record kindly provides a URL pointing to an information page, so the administrator may take corrective action as necessary.

We can observe the behavior of an rblsmtpd session by running it from the command line:

$ TCPREMOTEIP="202.63.160.111" rblsmtpd -B -t 300 -r sbl-xbl.spamhaus.org echo "hello"
rblsmtpd: 202.63.160.111 pid 747: 451 http://www.spamhaus.org/SBL/sbl.lasso?query=SBL16876
220 rblsmtpd.local
HELO mail.spammer.net
250 rblsmtpd.local
MAIL From: blah@spammer.net
250 rblsmtpd.local
RCPT To: user@example.org
451 http://www.spamhaus.org/SBL/sbl.lasso?query=SBL16876
DATA
451 http://www.spamhaus.org/SBL/sbl.lasso?query=SBL16876
QUIT
221 rblsmtpd.local

In the example above we invoke rblsmtpd with the $TCPREMOTEIP environmental variable set to a known RBL-listed IP address. (The echo "hello" is used here only as a substitute for a real SMTP program.)

The first line of output is from stderr, and would normally appear in the multilog for the running service. It shows that rblsmptd did find the remote IP address listed in the RBL. The following lines then show a simulated SMTP dialogue that might occur; what we type is in bold.

The spammer doesn't get much out of the session with rblsmtpd. Just repeated "451" responses, with the string found in the RBL's TXT record.

Here is the same session, only using the -b option, showing the return of "553" permanent error responses instead:

$ TCPREMOTEIP="202.63.160.111" rblsmtpd -b -r sbl-xbl.spamhaus.org echo "hello"
rblsmtpd: 202.63.160.111 pid 746: 553 http://www.spamhaus.org/SBL/sbl.lasso?query=SBL16876
220 rblsmtpd.local
HELO mail.spammer.net
250 rblsmtpd.local
MAIL From: blah@spammer.net
250 rblsmtpd.local
RCPT To: user@example.org
553 http://www.spamhaus.org/SBL/sbl.lasso?query=SBL16876
DATA
553 http://www.spamhaus.org/SBL/sbl.lasso?query=SBL16876
QUIT
221 rblsmtpd.local

Presumably in a real SMTP dialogue, the remote client would disconnect at the first "553" encountered, and stop further delivery attempts for the message.

The common convention among RBLs is to publish both TXT records and A records. Let's try another DNS query for the same IP address, asking now for an A record:

$ dnsip 111.160.63.202.sbl-xbl.spamhaus.org
127.0.0.2

The answer the RBL returns is the IP address "127.0.0.2". This is a common convention among RBLs, to publish A records of blacklisted hosts with IP addresses of the form "127.0.0.n", where n is some small positive integer. An information page at the website of each RBL service will describe how to interpret the different uses of n for their service.

Understanding how rblsmtpd uses DNS queries will now help us fine-tune the behavior of rblsmtpd in the sections that follow.


Copyright © 2003, 2004, Wayne Marshall.
All rights reserved.

Last edit 2004.09.26, wcm.