Sniffles, libunaccept pt. 2
Ewelina and I have colds. We are missing parties and fun as a result, but instead I am being somewhat productive on PageKite and such things.
After the first 24 hours of my spam filtering experiments, I have 62 spam messages in my spam folder.
This is probably a bit less than I would have using the AVES system, but the
downside is none of them are flagged as spam and if I weren't using GMail to
klaki.net e-mail, they would all be sitting right there in my inbox.
I am going to evaluate the current policy for another 24 hours, and then
libunaccept entirely for a final 24 to get a feel for how much
of a difference it makes.
So, what's this
libunaccept thing then?
(Update: more here)
It is probably best described as a minimal user-space firewall written in C, which allows DNS-based policies and can be enabled for any application without the need to recompile.
How it works
On Unix, the standard function for receiving an incoming TCP/IP connection is
accept, and it is used by the vast majority of the servers written
for the Internet - e-mail servers included.
libunaccept does, is it wraps some filtering logic around the
function. This logic consults a file named
decide if the connection is to be permitted or not. Rules can be based on
IP networks or DNS names.
/etc/libunaccept.rc file might contain the following lines:
allow 127.0.0.0 255.0.0.0 allow:host klaki.net tarpit:host spammer.com deny 0.0.0.0 0.0.0.0
These lines are processed in order and processing stops when something matches. So:
- first, allow all connections from the local network,
- second, allow all connections from machines with DNS names containing
- third, be nasty to connections from
spammer.comand leave them hanging without passing them on to the calling application,
- and finally, reject all other connections.
Every time a new connection is received
libunaccept checks if its
configuration file has been modified, to make sure it is always using the
libunaccept as a spam blocker
libunaccept for Klaki's mailserver was very simple, if a bit
hackish. First I created a shell script in
/usr/local/sbin with the
#!/bin/bash export LD_PRELOAD=/usr/local/lib/libunaccept.so exec /usr/sbin/sendmail "$@"
Then I edited the
/etc/init.d/sendmail script (yes, Klaki still uses
sendmail, hawk, spit) to invoke that script instead of the standard binary.
That was enough to add
libunaccept support to
The next step was to create two policy files:
/etc/libunaccept-nodirect.rcallows only white-listed connections.
/etc/libunaccept-nodialup.rcallows all connections except those from hosts with suspicious names or IPs.
Finally, I added the following lines to
# Rotate SMTP access policy a few times day 00 07 * * * root cp -f /etc/libunaccept-nodialup.rc /etc/libunaccept.rc 00 12 * * * root cp -f /dev/null /etc/libunaccept.rc 00 18 * * * root cp -f /etc/libunaccept-nodialup.rc /etc/libunaccept.rc 00 00 * * * root cp -f /etc/libunaccept-nodirect.rc /etc/libunaccept.rc
Combined, those steps implement the time-of-day based spam policy I described in the previous post. Not too hard.
At the moment changes to the policy are made by manually editing the files
/etc/, but the file format is so simple that it would be trivial to
write log parsers which update white- or black-list fragments automatically
and activate those at different times of day instead of or in addition to
the hand-crafted policies.
So... why did I reinvent this particular wheel? Wouldn't it have been possible to use the kernel's firewall support or some more traditional tools? I could be wrong, but I think the answer was "not quite". Also, it was a rather fun project with lots of "hack value".
libunaccept has that
iptables lacks are:
- It can make decisions based on DNS names.
- It is easy to allow an unprivileged process to edit the config file, which allows easy policy scheduling or automated white/black-listing.
libunaccept has that
/etc/hosts.deny) lacks are:
- The application does not need to be recompiled, you can even wrap a Python or Perl program with LD_PRELOAD.
It would probably have been better to use something based on
rather than roll my own rules language and parser, but I was looking for
something as minimal as possible and I am not sure how easy it is (or if
it is even possible) to include external library code in something meant
for use with
If I decide that
libunaccept is a project worth spending more time on,
I may look into
libwrap integration again at some point.
Either way, I will probably write some docs and put it on github. It's
a shame to let the code rot unused on my hard-drive, at the very least it
is a nice working example of how to use
1) A cleaner way to do this would have been to create a new init script with the LD_PRELOAD line included, and disable the old sendmail startup script. I will probably switch to that method after publishing this post.