blackblog.

snippets of blackwings life

My c-plugins for qmail-spp: rblchecks and greylist

Tuesday January 30, 2007

In order to fight spam, methods such as using a dns-based realtime blacklist or greylisting have been proven effective.

I use qmail with the very useful qmail-spp patch-set, that adds plugin capabilities to qmail-smtpd. Instead of just adding more and more chained commands to the run; file of tcpserver, you just specify a small plugin that is executed by qmail-smtpd when a certain smtp command is issued. In fact, this method is way nicer than forking many programs in a row… My run-line for the smtpd grew constantly, due to addition of rblsmtpd, qgreylist, … and I started to really dislike the increasingly huge memory footprint of a single smtp session. So I started searching for a rbl and greylisting plugin for qmail-spp – preferably in c, because forking several perl-instances per smtp session is just overkill. What I found was:

  • greylisting-spp by Peter Conrad. His website indicated, that he claims greylisting-spp to be alpha-quality, so I kept away from using it (After writing my own greylisting solution and putting him into cc, he said that it is actually quite stable – but the website did not indicate it *argh*).
  • ra-plugins by Roberto Alsina. Great collection of plugins – including a rblchecks one. But unfortunately his implementation lacks whitelisting support.

Because of this I did some own implementation – rather small and in c. To be honest, both greylisting and rblchecks are based on existing ideas / implementations. I suggest the following usage in the [mail] section of qmail-spp:
[mail]
skip-if-relayclient
skip-if-smtpauthuser
rblchecks
greylist

Update: People keep asking me per mail, what kind of blacklists and so on I use: I use the dul.dnsbl.sorbs.net and ix.dnsbl.manitu.net as blacklist and whitelist common mailservers such as web.de, gmx.net etc.

rblchecks.c – Check TCPREMOTEIP against a list of white- / blacklists.

Based on rblchecks.c of ra-plugins written by Roberto Alsina. Features & behavior of this plugin as follows (are README, and Makefile will be added at a later point).

  • If SKIP_RBL is set, plugin exits without doing anything (so following plugins in the chain will be executed)
  • The bstring library is used. So please have its header files present.
  • If TCPREMOTEIP is listed in one of the servers specified in the RWLSERVERS environment variable, plugin exits with A answer code. Please use tcp.smtp to specify the RWLSERVERS. Multiple servers can be supplied using : as separator.
  • If TCPREMOTEIP is listed in RBLSERVERS, plugin will exit with error 541 and qmail-smtpd will quit the smtp session.
  • Be sure to set a DNS timeout via resolv.conf In a future version, there will be an timeout handling within this plugin.
  • Plugin will give diagnostic messages via STDERR, so that qmail-spp will pass them to the logging system of qmail.
  • In case a IPv6 connection is found ($PROTO=TCP6) the plugin exits with a note – because IPv6 is not (yet?) subject to realtime blacklists.

greylist.c – Perform greylisting on TCPREMOTEIP.

This plugin was inspired by qgreylist by Jon Atkins. This implementation does a IP based greylisting – Sender and Receiver addresses are not taken into account! Right now there is just the c-file. Documentation as in README will follow.

  • If SKIP_GREY is set, plugin exits without doing anything (so following plugins in the chain will be executed)
  • Greylist creates an empty file named by TCPREMOTEHOST in the specified BASEDIR (default is /var/qmail/greylist) when a host is first seen.
  • A host, that is seen the first time gets a temporary 451 error.
  • After a minimum waiting time set via GL_MIN_REJECT (default is 300s) a SMTP session is accepted.
  • If host comes back before GL_MIN_REJECT, it gets an 451 again.
  • Once a session was successful, the entry has a lifetime of GL_ACCEPT_GOOD (default is 32 days).
  • If a host does not come back after GL_MAX_WAIT (default is one day), the entry is subject to cleanup.
  • On every subsequent SMTP session of TCPREMOTEHOST the file-access-time of the corresponding file is updated to the current time.
  • The modification time of the file corresponds to the time, when the host was first seen, while the access time refers to the time when it has been seen for the last time.
  • Be sure to have enough inodes in the specified BASEDIR! For high-volume servers you might consider using a ramdisk. But even for a server with about 15000 mails per hour, there was no slowdown. Best results have been seen on ext3 with htree, xfs and reiserfs. (I personally use a ramdisk with reiserfs on it. Do NOT use ramfs/tmpfs!
  • BASEDIR must be read-/writetable for the qmail-smtp user (usually qmaild)
  • Concept is also valid (and working!) for IPv6.
  • A clean-up cronjob for the BASEDIR is suggested. Just cleanup files, that have not been seen again within GL_ACCEPT_GOOD (now > atime + accept good) or that exceed GL_MAX_WAIT (now > atime +maxwait and atime == utime). A simple perl-oneliner does that:
    perl -e "my $time = time(); for my $file ( </var/qmail/greylist/*> ) { my ( $atime, $mtime ) = (stat $file)[8,9]; if ( ( ( $atime == $mtime ) and ( $atime < $time - 300 ) ) or ( $atime < $time - 2764800 ) ) { unlink $file or print "unlink $file failed"; } }"

skip-if-relayclient.c and skip-if-smtpauthuser.c – Simple plugins that stop further qmail-spp processing if RELAYCLIENT or SMTPAUTHUSER

The use of creating a kind of if-then-else handling in qmail-spp made me write these trivial little programs. So get them in front of your tool-chain in order to stop further plugins from being executed when you have a trusted sender!

  • If SMTPAUTHUSER or RELAYCLIENT are set, plugin exits using the A answer code (no further plugins in the chain will be executed)

3 Comments »

  1. Sorbs.net can be easily defeated. All the sender has to do is change their SMTP port setting from 25 (the standard default) to 587.

    This is a public service announcement from a non-spammer who is on Sorb’s black list ONLY because my ISP is AT&T/SBCGlobal.net.

    Comment by Big Gay Al — Wednesday, January 31 2007 @ 22:01

  2. bugs in rblchecks.c :

    * a closing ‘)’ is missing
    * strcmp returns 0 for equal strings, so we have to negate the PROTO = TCP6 check

    — rblchecks.c.orig 2007-10-18 23:54:02.625000000 +0800
    +++ rblchecks.c 2007-10-18 23:58:14.234375000 +0800
    @@ -93,7 +93,7 @@
    }

    // be IPv6 safe and just exit if PROTO = TCP6
    - if (strcmp(getenv (“PROTO”),”TCP6″)
    + if (!strcmp(getenv (“PROTO”),”TCP6″))
    {
    fprintf (stderr, “rblchecks: pid %d – IPv6 not subject to RBL! Accepted %s\n”, ppid, ip->data);
    exit (0);

    Comment by ax — Friday, October 19 2007 @ 00:10

  3. you are completely right – the distributed version was an old cvs one :(

    thanks anyway.

    Comment by blackwing — Saturday, October 27 2007 @ 03:10

RSS feed for comments on this post. TrackBack URI

Leave a comment

Powered by WordPress