use Time::Zone;
use PVE::INotify;
-use PVE::Tools;
+use PVE::Tools qw($IPV4RE $IPV6RE);
use PVE::SafeSyslog;
use PMG::Utils;
my $sth = $dbh->prepare(
'INSERT INTO LocalStat (Time, RBLCount, PregreetCount, CID, MTime) ' .
- 'VALUES (?, ?, ?, ?, EXTRACT(EPOCH FROM now())) ' .
+ 'VALUES (?, ?, ?, ?, EXTRACT(EPOCH FROM now())::INTEGER) ' .
'ON CONFLICT (Time, CID) DO UPDATE SET ' .
'RBLCount = LocalStat.RBLCount + excluded.RBLCount, ' .
'PregreetCount = LocalStat.PregreetCount + excluded.PregreetCount, ' .
sub run_dequeue {
my $self = shift;
- $self->log(2, "starting policy database maintainance (greylist, rbl)");
+ $self->log(2, "starting policy database maintenance (greylist, rbl)");
my $cinfo = PMG::ClusterConfig->new();
my $lcid = $cinfo->{local}->{cid};
$self->log(0, "greylist database update error: $err");
}
- $self->log(2, "end policy database maintainance ($rbltime ms, $ptime ms)");
+ $self->log(2, "end policy database maintenance ($rbltime ms, $ptime ms)");
$dbh->disconnect() if $dbh;
}
# reloading server configuration
if (defined $prop->{children}) {
foreach my $pid (keys %{$prop->{children}}) {
- kill(10, $pid); # SIGUSR1 childs
+ kill(10, $pid); # SIGUSR1 children
}
}
};
my $pmg_cfg = PMG::Config->new ();
$self->{use_spf} = $pmg_cfg->get('mail', 'spf');
$self->{use_greylist} = $pmg_cfg->get('mail', 'greylist');
+ $self->{use_greylist6} = $pmg_cfg->get('mail', 'greylist6');
+ $self->{greylistmask4} = $pmg_cfg->get('mail', 'greylistmask4');
+ $self->{greylistmask6} = $pmg_cfg->get('mail', 'greylistmask6');
if ($opt_testmode) {
$self->{use_spf} = 1;
$self->{use_greylist} = 1;
+ $self->{use_greylist6} = 1;
}
my $nodename = PVE::INotify::nodename();
my $auth_expl;
# we only use helo tests when we have no sender,
- # helo is sometimes empty, so we cant use SPF helo tests
+ # helo is sometimes empty, so we can't use SPF helo tests
# in that case - strange
if ($helo && !$sender) {
my $query;
$self->{cache}->{$dkey}->{status} = 1;
my @mxa = grep { $_->type eq 'MX' } $mx->answer;
my @mxl = sort { $a->preference <=> $b->preference } @mxa;
- # shift @mxl; # optionaly skip primary MX ?
+ # shift @mxl; # optionally skip primary MX ?
foreach my $rr (@mxl) {
my $a = $resolver->send ($rr->exchange, 'A');
if ($a) {
if (defined ($user) && defined ($domain)) {
# see http://cr.yp.to/proto/verp.txt
$user =~ s/\+.*//; # strip extensions (mailing-list VERP)
- $user =~ s/\b\d+\b/#/g; #replace nubmers in VERP address
+ $user =~ s/\b\d+\b/#/g; #replace numbers in VERP address
$sender = "$user\@$domain";
}
return 'dunno';
}
- my ($net, $host) = $ip =~ m/(\d+\.\d+\.\d+)\.(\d+)/; # IPv4 for now
- return 'dunno' if !defined($net);
+ my $masklen;
+ my $do_greylist = 0;
+ if ($ip =~ m/$IPV4RE/) {
+ $masklen = $self->{greylistmask4};
+ $do_greylist = $self->{use_greylist};
+ } elsif ($ip =~ m/$IPV6RE/) {
+ $masklen = $self->{greylistmask6};
+ $do_greylist = $self->{use_greylist6};
+ } else {
+ return 'dunno';
+ }
my $spf_header;
# check if there is already a record in the GL database
my $sth = $dbh->prepare(
"SELECT * FROM CGreylist " .
- "where IPNet = ? AND Sender = ? AND Receiver = ?");
+ "WHERE IPNet::cidr = network(set_masklen(?, ?)) AND ".
+ "Sender = ? AND Receiver = ?");
- $sth->execute($net, $sender, $rcpt);
+ $sth->execute($ip, $masklen, $sender, $rcpt);
my $ref = $sth->fetchrow_hashref();
$sth->finish();
# table later. We set 'blocked' to 100000 to identify those entries.
if (!defined($ref->{rctime})) {
-
- $dbh->do($PMG::DBTools::cgreylist_merge_sql, undef,
- $net, $host, $sender, $rcpt, $instance,
+ $dbh->do(PMG::DBTools::cgreylist_merge_sql(1), undef,
+ $ip, $masklen, $sender, $rcpt, $instance,
$ctime, $ctime + 10, 0, 100000, 0, $ctime, $self->{lcid});
}
$self->{cache}->{$instance}->{spf_header_added} = 1;
}
- return $res if !$self->{use_greylist};
+ return $res if !$do_greylist;
my $defer_res = "defer_if_permit Service is unavailable (try later)";
eval {
- # we dont use alarm here, because it does not work with DBI
+ # we don't use alarm here, because it does not work with DBI
$dbh->begin_work;
my $sth = $dbh->prepare(
"SELECT * FROM CGreylist " .
- "where IPNet = ? AND Sender = ? AND Receiver = ?");
+ "WHERE IPNet::cidr = network(set_masklen(?, ?)) AND ".
+ "Sender = ? AND Receiver = ?");
- $sth->execute($net, $sender, $rcpt);
+ $sth->execute($ip, $masklen, $sender, $rcpt);
my $ref = $sth->fetchrow_hashref();
if (!defined($ref->{rctime})) {
- $dbh->do($PMG::DBTools::cgreylist_merge_sql, undef,
- $net, $host, $sender, $rcpt, $instance,
- $ctime, $ctime + $greylist_lifetime, 0, 1, 0, $ctime, $self->{lcid});
+ $dbh->do(
+ PMG::DBTools::cgreylist_merge_sql(1), undef, $ip, $masklen,
+ $sender, $rcpt, $instance, $ctime, $ctime + $greylist_lifetime,
+ 0, 1, 0, $ctime, $self->{lcid}
+ );
$res = $defer_res;
$self->log(3, "defer greylisted mail");
# defer (resent within greylist_delay window)
$res = $defer_res;
$self->log(3, "defer greylisted mail");
- $dbh->do("UPDATE CGreylist " .
- "SET Blocked = Blocked + 1, Host = ?, MTime = ? " .
- "WHERE IPNet = ? AND Sender = ? AND Receiver = ?", undef,
- $host, $ctime, $net, $sender, $rcpt);
+ $dbh->do(
+ "UPDATE CGreylist " .
+ "SET Blocked = Blocked + 1, MTime = ? " .
+ "WHERE IPNet::cidr = network(set_masklen(?, ?)) ".
+ " AND Sender = ? AND Receiver = ?", undef,
+ $ctime, $ip, $masklen, $sender, $rcpt
+ );
} else {
if ($ctime < $ref->{extime}) {
# accept (not expired)
my $lifetime = $sender eq "" ? 0 : $greylist_awlifetime;
my $delay = $ref->{passed} ? "" : "Delay = $age, ";
- $dbh->do("UPDATE CGreylist " .
- "SET Passed = Passed + 1, $delay Host = ?, ExTime = ?, MTime = ? " .
- "WHERE IPNet = ? AND Sender = ? AND Receiver = ?", undef,
- $host, $ctime + $lifetime, $ctime, $net, $sender, $rcpt);
+ $dbh->do(
+ "UPDATE CGreylist " .
+ "SET Passed = Passed + 1, $delay ExTime = ?, MTime = ? " .
+ "WHERE IPNet::cidr = network(set_masklen(?, ?)) ".
+ " AND Sender = ? AND Receiver = ?", undef,
+ $ctime + $lifetime, $ctime, $ip, $masklen, $sender, $rcpt
+ );
} else {
# defer (record is expired)
$res = $defer_res;
- $dbh->do("UPDATE CGreylist " .
- "SET Host = ?, RCTime = ?, ExTime = ?, MTime = ?, Instance = ?, " .
- "Blocked = 1, Passed = 0 " .
- "WHERE IPNet = ? AND Sender = ? AND Receiver = ?", undef,
- $host, $ctime, $ctime + $greylist_lifetime, $ctime, $instance,
- $net, $sender, $rcpt);
+ $dbh->do(
+ "UPDATE CGreylist " .
+ "SET RCTime = ?, ExTime = ?, MTime = ?, Instance = ?, " .
+ "Blocked = 1, Passed = 0 " .
+ "WHERE IPNet::cidr = network(set_masklen(?, ?)) ".
+ " AND Sender = ? AND Receiver = ?", undef,
+ $ctime, $ctime + $greylist_lifetime, $ctime, $instance,
+ $ip, $masklen, $sender, $rcpt
+ );
}
}
}
if (defined $prop->{children}) {
foreach my $pid (keys %{$prop->{children}}) {
- kill(1, $pid); # HUP childs
+ kill(1, $pid); # HUP children
}
}
- # nicely shutdown childs (give them max 30 seconds to shut down)
+ # nicely shutdown children (give them max 30 seconds to shut down)
my $previous_alarm = alarm(30);
eval {
local $SIG{ALRM} = sub { die "Timed Out!\n" };
# subroutine to start up a specified number of children.
# We need to block signals until handlers are set up correctly.
# Else its possible that HUP occurs after fork, which triggers
-# singal TERM at childs and calls server_close() instead of
+# signal TERM at children and calls server_close() instead of
# simply exit the child.
# Note: on server startup signals are setup to trigger
# asynchronously for a short period of time (in PreForkSimple]::loop,