//depot/projects/greylistd/lib/Mail/Greylist.pm#6 – edit change 208 (ktext) ·revision history
| 1 | package Mail::Greylist; |
| 2 | |
| 3 | # $Id$ |
| 4 | # |
| 5 | # Greylisting for Postfix: tempfail the first delivery attempt from any |
| 6 | # (client, sender, recipient) triplet we haven't seen before. Real MTAs |
| 7 | # retry. Ratware doesn't. |
| 8 | |
| 9 | use strict; |
| 10 | use warnings; |
| 11 | use DB_File; |
| 12 | use Fcntl; |
| 13 | |
| 14 | our $VERSION = '0.4'; |
| 15 | |
| 16 | my $DELAY = 300; # seconds a new triplet must wait |
| 17 | my $LIFETIME = 36 * 86400; # forget triplets after this long |
| 18 | my $MSG = "DEFER_IF_PERMIT Greylisted, see http://ttul.org/greylisting.html"; |
| 19 | |
| 20 | sub new { |
| 21 | my ($class, %args) = @_; |
| 22 | my $self = { |
| 23 | dbfile => $args{dbfile} || '/var/lib/greylistd/triplets.db', |
| 24 | delay => defined $args{delay} ? $args{delay} : $DELAY, |
| 25 | white => $args{whitelist} || [], |
| 26 | db => {}, |
| 27 | }; |
| 28 | tie %{ $self->{db} }, 'DB_File', $self->{dbfile}, O_RDWR|O_CREAT, 0600, $DB_HASH |
| 29 | or die "can't tie $self->{dbfile}: $!"; |
| 30 | return bless $self, $class; |
| 31 | } |
| 32 | |
| 33 | sub triplet { |
| 34 | my ($self, $ip, $from, $to) = @_; |
| 35 | # big ISPs retry from a different box in the same farm; key on the /24 |
| 36 | (my $net = $ip) =~ s/\.\d+$//; |
| 37 | return join("/", $net, lc($from || '<>'), lc $to); |
| 38 | } |
| 39 | |
| 40 | # returns "DUNNO" to let postfix carry on, or a defer action |
| 41 | sub check { |
| 42 | my ($self, %req) = @_; |
| 43 | for my $re (@{ $self->{white} }) { |
| 44 | return "DUNNO" if $req{client_address} =~ $re; |
| 45 | } |
| 46 | my $key = $self->triplet($req{client_address}, $req{sender}, $req{recipient}); |
| 47 | my $now = time; |
| 48 | |
| 49 | my $first = $self->{db}{$key}; |
| 50 | if (!defined $first) { |
| 51 | $self->{db}{$key} = $now; |
| 52 | return $MSG; |
| 53 | } |
| 54 | if ($now - $first < $self->{delay}) { |
| 55 | return $MSG; |
| 56 | } |
| 57 | return "DUNNO"; |
| 58 | } |
| 59 | |
| 60 | sub purge { |
| 61 | my $self = shift; |
| 62 | my $now = time; |
| 63 | my @old = grep { $now - $self->{db}{$_} > $LIFETIME } keys %{ $self->{db} }; |
| 64 | delete @{ $self->{db} }{@old}; |
| 65 | return scalar @old; |
| 66 | } |
| 67 | |
| 68 | sub DESTROY { |
| 69 | my $self = shift; |
| 70 | untie %{ $self->{db} }; |
| 71 | } |
| 72 | |
| 73 | 1; |
| 74 | __END__ |
| 75 | |
| 76 | =head1 NAME |
| 77 | |
| 78 | Mail::Greylist - greylisting policy engine for Postfix |
| 79 | |
| 80 | =head1 SYNOPSIS |
| 81 | |
| 82 | my $gl = Mail::Greylist->new(dbfile => '/tmp/gl.db'); |
| 83 | print $gl->check(client_address => '10.0.0.7', |
| 84 | sender => 'spammer@example.com', |
| 85 | recipient => 'ksimpson@ttul.org'); |
| 86 | |
| 87 | =head1 AUTHOR |
| 88 | |
| 89 | nullbyte <nullbyte@ttul.org> |
| 90 | |
| 91 | =cut |