our $default_db_name = "Proxmox_ruledb";
-our $cgreylist_merge_sql =
+# FIXME: drop Host column with PMG 7.0
+sub cgreylist_merge_sql {
+ my ($with_mask) = @_;
+
+ my $network = $with_mask ? 'network(set_masklen(?, ?))' : '?';
+
+ my $sql =
'INSERT INTO CGREYLIST (IPNet,Host,Sender,Receiver,Instance,RCTime,' .
'ExTime,Delay,Blocked,Passed,MTime,CID) ' .
- 'VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ' .
+ "VALUES ($network, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) " .
'ON CONFLICT (IPNet,Sender,Receiver) DO UPDATE SET ' .
'Host = CASE WHEN CGREYLIST.MTime >= excluded.MTime THEN CGREYLIST.Host ELSE excluded.Host END,' .
'CID = GREATEST(CGREYLIST.CID, excluded.CID), RCTime = LEAST(CGREYLIST.RCTime, excluded.RCTime),' .
'Blocked = GREATEST(CGREYLIST.Blocked, excluded.Blocked),' .
'Passed = GREATEST(CGREYLIST.Passed, excluded.Passed)';
+ return $sql;
+}
+
sub open_ruledb {
my ($database, $host, $port) = @_;
my $cgreylist_ctablecmd = <<__EOD;
CREATE TABLE CGreylist
- (IPNet VARCHAR(16) NOT NULL,
+ (IPNet VARCHAR(49) NOT NULL,
Host INTEGER NOT NULL,
Sender VARCHAR(255) NOT NULL,
Receiver VARCHAR(255) NOT NULL,
"AND value = 'content-type:application/x-java-vm';");
};
+ # FIXME: drop Host column with PMG 7.0
+ # increase column size of cgreylist.ipnet for ipv6 support and transfer data
+ eval {
+ my $sth = $dbh->prepare("SELECT character_maximum_length ".
+ "FROM information_schema.columns ".
+ "WHERE table_name = 'cgreylist' AND column_name = 'ipnet'");
+ $sth->execute();
+ my $res = $sth->fetchrow_hashref();
+ if ($res->{character_maximum_length} == 16) {
+ $dbh->begin_work;
+ $dbh->do("ALTER TABLE CGreylist ALTER COLUMN " .
+ "IPNet TYPE varchar(49)");
+ eval {
+ $dbh->do("UPDATE CGreylist cg1 SET IPNet = IPNet || '.0/24' ".
+ "WHERE position('/' in IPNet) = 0 AND ".
+ "NOT EXISTS (SELECT 1 FROM CGreylist cg2 WHERE ".
+ "cg2.IPNet = cg1.IPNet || '.0/24' AND ".
+ "cg1.Receiver = cg2.Receiver AND cg1.Sender = cg2.Sender)");
+ };
+ #ignore errors here - legacy rows will eventually expire
+ $dbh->commit;
+ }
+ };
+ if (my $err = $@) {
+ $dbh->rollback;
+ die $err;
+ }
+
foreach my $table (keys %$tables) {
eval { $dbh->do("ANALYZE $table"); };
warn $@ if $@;
my ($net, $host) = $ip =~ m/(\d+\.\d+\.\d+)\.(\d+)/; # IPv4 for now
return 'dunno' if !defined($net);
+ my $masklen = 24;
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();
if (!defined($ref->{rctime})) {
- $dbh->do($PMG::DBTools::cgreylist_merge_sql, undef,
- $net, $host, $sender, $rcpt, $instance,
+ # FIXME: drop Host column with PMG 7.0
+ $dbh->do(PMG::DBTools::cgreylist_merge_sql(1), undef,
+ $ip, $masklen, 0, $sender, $rcpt, $instance,
$ctime, $ctime + 10, 0, 100000, 0, $ctime, $self->{lcid});
}
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, 0, $sender, $rcpt, $instance,
+ $ctime, $ctime + $greylist_lifetime, 0, 1, 0, $ctime, $self->{lcid});
$res = $defer_res;
$self->log(3, "defer greylisted mail");
$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);
+ "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);
+ "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);
+ "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);
}
}
}