[Mimedefang] Filesystem based greylisting

Atanas atanas at asd.aplus.net
Thu Aug 26 16:25:23 EDT 2004


I'd like to share something that already works for me for about 2 
months. It's extremely simple, fast and reliable:

use String::CRC32;
my $grey_spooldir = '/var/spool/MD-Greylist';
my $grey_allow = 5*60;

sub filter_recipient
{   my ($to, $from, $ip, $name, $first, $helo) = @_;
     my $relay_ip = $ip;

     $ip =~ s/\.\d+$//;          # remove the last byte from IP addresses
     my $file = $ip.$from.$to;   # this is the greylist tuple file name
     $file =~ s/\///g;           # remove slashes from email sddresses

     my $path = sprintf "$grey_spooldir/%03X", (crc32 $file)%1024;
     #-d $path or mkdir $path;   # create hash subdirectory when necessary
     $file = "$path/$file";

     if( !-f $file ) {           # first attempt ==> tempfail

         open TF, ">$file";  close TF;
         md_syslog('info', "Tempfail $ip$from$to");
         return ('TEMPFAIL', 'Please try again');
     }

     my $now = time;
     if( !-x $file ) {           # next attempt (already tempfailed) ...

         my $dtime = $now - (stat _)[9];
         if( $dtime >= $grey_allow ) {   # ... long enough ==> greylist 
& continue

             chmod 0755, $file;
             utime $now, $now, $file;
             md_syslog('info', "Greylist $ip$from$to");

         } else {                        # otherwise ==> tempfail again

             md_syslog('info', "Tempfail (again) $ip$from$to")
             return ('TEMPFAIL', 'Please try again later');
         }

     } else {                    # already greylisted ==> update & continue

         utime $now, $now, $file;
         md_syslog('info', "Allow (greylisted) $ip$from$to");
     }
     return ('CONTINUE', 'OK');
}

The above is a stripped down version of the greylisting code only. It 
just creates or updates greylist entries (one empty file per entry). 
There's also a cron job for cleaning any expired entries, something for 
authenticated users to bypass the greylist, a whitelist per relay IP and 
recipient domain, simple HELO checks, etc.

It's not a rocket science and anybody knowing perl could write it, but 
if anyone is interested I could post the whole thing, it's probably just 
about 2-3 times bigger than the above.

For me it handles about 3M greylist entries and so far I had no 
problems. It runs on a single box together with Mimedefang/SA/Clamd 
processing about 350K messages a day. Before the greylist implementation 
the same box was hit by 550-600K messages a day, so the greylist 
effectively stops about 30-40% of the email traffic. Some time in the 
future I'm planning to share it among multilpe mimedefang machines over NFS.

Disclaimer: I'm not a perl programmer. The above code works for me, but 
might not work for you and/or could have bugs. I tried to make it 
efficient, but possibly it could have been written better.

Regards,
Atanas



More information about the MIMEDefang mailing list