As mentioned in my last mail, my alias plugin allows setting notes per
recipient, which can be used by other plugins. This patch adds an option
per_recipient to denysoft_greylist. If it is set, the plugin will
immediately return DECLINED unless
$transaction->notes('recipient_options')->{denysoft_greylist} is true.

This allows me enable greylisting selectively for some addresses. E.g.,
my personal addresses have it enabled:

    hjp,peter.holzer                @wsr.ac.at, wifo.ac.at, wifo.at
    :[EMAIL PROTECTED]          (denysoft_greylist)

but the postmaster address doesn't:

    postmaster      @wsr.ac.at      :[EMAIL PROTECTED]

        hp


-- 
   _  | Peter J. Holzer    | We have failed our own creation and given
|_|_) | Sysadmin WSR       | birth something truly awful. We're just too
| |   | [EMAIL PROTECTED]         | busy cooing over the pram to notice.
__/   | http://www.hjp.at/ |       -- http://www.internetisshit.org
Index: plugins/denysoft_greylist
===================================================================
--- plugins/denysoft_greylist   (revision 22)
+++ plugins/denysoft_greylist   (working copy)
@@ -4,9 +4,9 @@
 
 =head1 DESCRIPTION
 
-Plugin to implement the 'greylisting' algorithm proposed by Evan Harris
-in http://projects.puremagic.com/greylisting/. Greylisting is a form of 
-denysoft filter, where unrecognised new connections are temporarily 
+Plugin to implement the 'greylisting' algorithm proposed by Ed Harris in
+http://projects.puremagic.com/greylisting/. Greylisting is a form of
+denysoft filter, where unrecognised new connections are temporarily
 denied for some initial period, to foil spammers using fire-and-forget 
 spamware, http_proxies, etc.
 
@@ -66,6 +66,13 @@
 but never actually issue DENYSOFTs. Useful for seeding the database 
 and testing without actually impacting deliveries. Default: 0.
 
+=item per_recipient <bool>
+
+Per recipient flag - if this is set, the plugin is only run for
+recipients which have recipient_option 'denysoft_greylist' set.
+This can be set by the aliases plugin.
+Default: 0.
+
 =back
 
 =head1 AUTHOR
@@ -86,6 +93,8 @@
 my $GREY_DEFAULT  = 3 * 3600 + 10 * 60;
 my $WHITE_DEFAULT = 36 * 24 * 3600;
 
+my @whitelist;
+
 sub register {
   my ($self, $qp, %arg) = @_;
   $self->{_greylist_ip}     = $arg{remote_ip};
@@ -98,11 +107,12 @@
   $self->{_greylist_grey}   = $arg{grey_timeout}  || $GREY_DEFAULT;
   $self->{_greylist_white}  = $arg{white_timeout} || $WHITE_DEFAULT;
   $self->{_greylist_testonly} = $arg{testonly};
+  $self->{_greylist_per_recipient} = $arg{per_recipient};
 
   if (open(WL, "<$DBDIR/denysoft_whitelist")) {
     while (<WL>) {
-      chomp;
-      $self->{_greylist_whitelist}{$_} = 1;
+      s/\s*(\#.*)$//s;
+      add_whitelist_entry($_);
     }
     close(WL);
   }
@@ -123,6 +133,12 @@
 
 sub rcpt_handler {
   my ($self, $transaction, $rcpt) = @_;
+
+  if ($self->{_greylist_per_recipient}) {
+    my $ro = $transaction->notes('recipient_options');
+    return DECLINED unless ($ro && $ro->{denysoft_greylist});
+  }
+
   my $sender = $transaction->sender;
   if ($self->{_greylist_rcpt}) {
     my ($status) = $self->denysoft_greylist($transaction, $sender, $rcpt);
@@ -153,15 +169,17 @@
   my $remote_ip = $self->qp->connection->remote_ip;
   my $fmt = "%s:%d:%d:%d";
 
-  if ($self->{_greylist_whitelist}{$remote_ip}) {
+  if (lookup_whitelist_entry($remote_ip)) {
     $self->log(2, "ip $remote_ip is whitelisted, skipping greylist checks");
     return DECLINED 
   }
   # Check denysoft db
+  print STDERR "denysoft_greylist: trying to tie to $DB\n";
   open(LOCK, ">$DB.lock") or die "cannot open $DB.lock: $!";
   flock(LOCK, LOCK_EX) or die "cannot lock $DB.lock: $!";
 
   tie my %db, 'AnyDBM_File', $DB, O_CREAT|O_RDWR, 0600 or return (DECLINED);
+  print STDERR "denysoft_greylist: tied to $DB\n";
   my @key;
   push @key, $remote_ip             if $self->{_greylist_ip};
   push @key, $sender->address || '' if $self->{_greylist_sender};
@@ -215,4 +233,39 @@
   return ($self->{_greylist_testonly} ? DECLINED : DENYSOFT);
 }
 
+sub add_whitelist_entry {
+    my ($s) = @_;
+    my ($ip, $mask);
+
+    if ($s =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)\/(\d+)/) {
+       $ip = ($1 << 24) | ($2 << 16) | ($3 << 8) | $4;
+       $mask = -1 << (32 - $5);
+    } elsif ($s =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/) {
+       $ip = ($1 << 24) | ($2 << 16) | ($3 << 8) | $4;
+       $mask = -1;
+    } else {
+       $self->log(1, "cannot parse whitelist entry $s");
+       return;
+    }
+    my $net = $ip & $mask;
+    my $bcast = $ip | ~$mask;
+    push @whitelist, [$net, $bcast];
+}
+
+sub lookup_whitelist_entry {
+    my ($s) = @_;
+    my ($ip, $mask);
+
+    if ($s =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/) {
+       $ip = ($1 << 24) | ($2 << 16) | ($3 << 8) | $4;
+    } else {
+       $self->log(1, "cannot parse ip address $s");
+       return;
+    }
+    for (@whitelist) {
+       return $_ if ($_->[0] <= $ip && $ip <= $_->[1]);
+    }
+    return undef;
+}
+
 1;

Attachment: pgp00000.pgp
Description: PGP signature

Reply via email to