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;
pgp00000.pgp
Description: PGP signature