check_compat vs MIMEDefang
2011/09/27
We have a user that wishes to have messages sent from sender@host-xyzw.etp.eu.example.com discarded by our mailservers. The natural choice for such blocks seems to be FEATURE(compat_check). In fact we had a number of other users with similar requests that were serviced this way. The problem in this case was that the xyzw part of host-xyzw.etp.eu.example.com was not constant or predictable and finite. Naturally I thought that a local version of the check_compat ruleset would suffice, since $*.eu.etp.example.com matches all possible such hostnames. But it seems that according to the bat book this cannot be done while also using FEATURE(compat_check):
Note that although with V8.12 and later you can still write your own check_compat rule set, doing so has been made unnecessary by the FEATURE(compat_check) (§7.5.7 on page 288). But also note that, as of V8.12, you cannot both declare the FEATURE(compat_check) and use this check_compat rule set.
Since I did not wish to tamper with our sendmail.mc this time, MIMEDefang came to the rescue: filter_relay is called with arguments both the sender and the receiver and that took care of it. But again, had I chosen to write this using sendmail’s language, it might have looked ugly, but it would also have been a one-liner (ugly but elegant in its own way).
Poor man’s milter-ahead
2009/08/21
I have blogged before that the reason that I like MIMEDefang is that it gives the Postmaster a Perl interpreter (a programming language that is) and a library of functions that can be used to filter and manipulate incoming and outgoing email.
Of the functions available I believe that md_check_against_smtp_server() deserves special mention since it can be used to quickly implement a poor man’s milter-ahead or milter-sender. Of course milter-ahead implements many features (caching among others), but with some effort most (if not all) of the functionality can be implemented withing mimedefang-filter.
Then again, milter-ahead does not cost much (€90) even for small organizations, so the not invented here syndrome can be supressed.
Why I like running MIMEDefang
2008/06/08
I had a talk with a friend the other day and he told me that he does not run MIMEDefang on his systems. Well I do and since most people run MIMEDefang just to be able to run ClamAV and SpamAssassin from one place, I want to explain why. Because when you have a hammer it is better to have more than two nails.
I like running MIMEDefang because it gives me a Perl interpreter at hand and a set of handy routines to manipulate every message that passes through the mail server (header and body). So for any weird idea that I have and I need a proof of concept, I have a full programming language on my email server waiting to run it. And if I have performance issues, well I can always (re)write it in C.
I really think it pays off to invest sometime to learn how to change stuff in mimedefang-filter(5) and how to write your own versions of the filter_* routines.
MIMEDefang and virii
2006/06/28
OK so you use MIMEDefang together with ClamAV[*] to check incoming messages for viral content. But given the fact that an infected machine will bomb you with many many messages, why should you check every message sent for a given time window? This is what I came up with:
The default mimedefang-filter(5) has the following check which discards viral messages:
if ($FoundVirus) {
md_graphdefang_log('virus', $VirusName, $RelayAddr);
md_syslog('warning', "Discarding because of virus $VirusName");
return action_discard();
}
Changing it to:
if ($FoundVirus) {
# OK log $RelayAddr
# If you are on a Debian-like system you have to put
# use DB_File in /etc/mail/mimedefang.pl.conf
# otherwise you have to put it somewhere in mimedefang-filter
my %vbl;
my $now;
tie %vbl, 'DB_File', "/var/cache/local/virbl/virbl.db", O_CREAT|O_RDWR, 0644, $DB_BTREE or die;
$now = time;
$vbl{$RelayAddr} = $now;
untie %vbl;
md_graphdefang_log('virus', $VirusName, $RelayAddr);
md_syslog('warning', "Discarding because of virus $VirusName");
return action_discard();
}
logs $RelayAddr (the IP address of the infected machine) together with a timestamp in a BerkeleyDB B-Tree. In our example this is /var/cache/local/virbl/virbl.db. You have to make this file writeable by the user that runs MIMEDefang on your system. And now using the following sendmail.mc code one can block this IP address prior to inspecting the message content:
LOCAL_CONFIG
# .db is appended by sendmail automagically
Kvirbl btree -a.FOUND /var/cache/local/virbl/virbl
LOCAL_RULESETS
# Always remember: In sendmail the LHS and the RHS of the sendmail.mc/.cf is
# separated with tabs and not spaces. So do not copy-paste this fragment,
# type it.
SLocal_check_relay
R$* $: $&{client_addr}
R$* $: $(virbl $1 $: $1.NOTFOUND $)
# The next line broken in two for readability
R$* . FOUND $#error $@ 5.7.1 $: You have sent us mail containing
a virus and are blocked from our systems for an hour.
So now you need an expiration proccess. How long shall these IP addresses remain in your database? I keep them for one hour. It seems to be a reasonable default. A simple expiry script is the following perl snippet:
#!/usr/bin/perl
use DB_File;
$db = shift or die;
$threshold = shift or die;
tie %d, 'DB_File', $db, O_RDONLY, 0644, $DB_BTREE;
$now = time;
foreach $i (keys %d) {
$diff = $now - $d{$i};
if ($diff > $threshold) {
delete $d{$i};
}
}
untie %d;
You can run this script from cron every ten minutes or so. I’ve written my expiry program in C and run it every two minutes. If you also want to do this, you have to remember that the perl snippet on mimedefang-filter that logs $RelayAddr and the timestamp stores the timestamp as a string and not as an integer.
[*] There exist many HOWTOs on how to setup MIMEDefang to work with ClamAV. Just use Google.
