Mark,
please find our DNSBL to policy bank patch attached.
The purpose of this patch is to query a (local) DNSBL service for a given IP
address and let amavis add the IP to a policy bank if the IP was listed on
that DNSBL list.
This is how we use it:
@client_ipaddr_policy = (
Amavis::Lookup::DNSBL::read_dns(qw(127.0.0.1), {port=>53,
tcp_timeout=>1, udp_timeout=>1, persistent_udp=>1, persistent_tcp=>1},
"%a.dnswl.csa",[qw(127.0.0.50 127.0.0.2)]) => 'CSA',
[qw( 0.0.0.0/8 127.0.0.1/32 [::] [::1] )] => 'LOCALHOST',
\@mynetworks => 'MYNETS'
);
In the example above read_dns configures amavis to connect to a DNS service on
127.0.0.1. amavis will query for a record constructed from the clients IP
address '%a' and the domainpart ".dnswl.csa". If the DNS service replies either
127.0.0.50 or 127.0.0.2 amavis should apply the settings configured in a CSA
policy_bank.
We use this feature to excempt particular IPs from SPAM scanning in a large
SMTP cluster, where it is easier to provide the IP list via DNS instead of
pushing a CIDR out to all scan nodes.
We find this feature quite useful to and I hope you will add it to amavis.
Regards
p@rick
--
[*] sys4 AG
https://sys4.de, +49 (89) 30 90 46 64
Franziskanerstraße 15, 81669 München
Sitz der Gesellschaft: München, Amtsgericht München: HRB 199263
Vorstand: Patrick Ben Koetter, Marc Schiffbauer
Aufsichtsratsvorsitzender: Florian Kirstein
Index: amavisd-new-2.11.0~pre2/amavisd
===================================================================
--- amavisd-new-2.11.0~pre2.orig/amavisd
+++ amavisd-new-2.11.0~pre2/amavisd
@@ -6568,6 +6568,8 @@ sub lookup_ip_acl($@) {
elsif (($ip_vec & $acl_mask) eq ($acl_ip_vec & $acl_mask)) { $found=1 }
last if $found;
}
+ } elsif ($t->isa('Amavis::Lookup::DNSBL')) { # DNSBL matcher obj
+ $found=$result=$t->lookup_ip($ip);
} elsif ($t->isa('Amavis::Lookup::Label')) { # logging label
# just a convenience for logging purposes, not a real lookup method
$label = $t->display; # grab the name, and proceed with the next table
@@ -6728,6 +6730,48 @@ sub new($$$;$) {
}
1;
+
+#
+package Amavis::Lookup::DNSBL;
+use Net::DNS;
+use Net::IP;
+
+sub read_dns {
+ return Amavis::Lookup::DNSBL->new(@_);
+}
+
+sub new {
+ my $class = shift;
+ my $target=shift; # DNSBL resolver to be used
+ my $targetoptions=shift; # override default options for Net::DNS::Resolver
+ my $self = {
+ _zone => shift, # DNSBL zone, %a is place-holder for the ip address to be queried
+ _reply => shift, # list of replies that qualify as a "match"
+ };
+ $$targetoptions{nameservers}=[$target];
+ $self->{_resolver} = Net::DNS::Resolver->new(%$targetoptions);
+ bless $self, $class;
+}
+
+sub lookup_ip {
+ my $NOMATCH=0; # return value when there is no match
+ my ( $self, $addr ) = @_;
+ my $ip = new Net::IP($addr);
+ my $reversedip=$ip->reverse_ip();
+ $reversedip =~ s/.in-addr.arpa.//; # strip ipv4 reverse zone
+ $reversedip =~ s/.ip6.arpa.//; # strip ipv6 reverse zone
+ my $lookup=$self->{_zone};
+ $lookup =~ s/%a/$reversedip/g; # create query for DNSBL zone
+
+ my $query = $self->{_resolver}->search( $lookup, 'A' ) or return $NOMATCH;
+ foreach my $rr ( $query->answer ) {
+ next unless $rr->type eq 'A';
+ if(grep($_ eq $rr->address, @{$self->{_reply}})) { return 1; }
+ }
+ return $NOMATCH;
+}
+
+1;
#
package Amavis::Lookup;