[Mimedefang] Greylisting is GREY-ATE

Mark Sheppard mark at ddf.net
Thu Jan 1 00:49:34 EST 2004


On 2003-12-31 (Wednesday) at 22:36:54 +0100, Jonas Eckerman wrote:
> On Sun, 28 Dec 2003 01:59:00 -0600, Steven Rocha wrote:
>
> >  WOW!!!  This is about all I can say.
>
> Agreed. :-)
>
> >  their installations.  I have looked at Jonas' greylisting
> >  implementation but I could not get around the O_EXLOCK flag, YET!
>
> I don't think that'd bee too hard. I think David uses the more
> portable method with a lock file in his code. That method should
> work fine with my code as well.

I use this in my mimedefang-filter (on a Debian system):

  use BerkeleyDB;
  use LockFile::Simple;

  # must be writable be user "defang"
  my $greylist_db_file = '/var/spool/MIMEDefang/greylist.db';
  my $greylist_min = 30;          # 30 seconds
  my $greylist_max = 60 * 60 * 24;# 24 hours
  my $lockmgr;

  BEGIN{
    $lockmgr = LockFile::Simple->make(-format => '%f.lock',
                                      -hold   => 600,
                                      -delay  => 1);
  }

[...]

  sub greylist{
    my($key) = @_;

    $lockmgr->lock($greylist_db_file) or
      die "Can't lock `$greylist_db_file'\n";
    my $db = BerkeleyDB::Hash->new(-Filename => $greylist_db_file,
                                   -Flags    => DB_CREATE) or
      die "Can't open `$greylist_db_file': $!\n";
    my $now = time();
    my $bad = 0;
    my $then;
    if($db->db_get($key, $then) or
       ($now - $then) < $greylist_min or
       ($now - $then) > $greylist_max){
      # never seen before, or not in the greylist window
      $bad = 1;
    }
    my $status = $db->db_put($key, $now);
    if($status){
      die "Can't set `$key' in database: $status $Berkeley::Error\n";
    }
    md_syslog('warning', "Set $key = $now in greylist, " .
              ($bad? 'rejecting': 'accepting'));
    $db->db_close();
    $lockmgr->unlock($greylist_db_file);
    return $bad;
  }


Then this after the SpamAssassin stuff in filter_end():

  # greylisting
  if(greylist($RelayAddr)){
    action_tempfail("Not seen $RelayAddr recently, try again to verify you're not brain-dead spamware");
    md_syslog('warning', "Temp failed $RelayAddr ($RelayHostname) due to greylist");
    return;
  }


Seems to work quite well.  The Berkeley DB library supports database
locking, but after banging my head against a brick wall for far too
long I gave up on it.  I don't know if it's me or the perl module at
fault, but it just wasn't happening.  So I wrapped all the database
access stuff in a LockFile::Simple which neatly side-stepped the
problem.

Mark.



More information about the MIMEDefang mailing list