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;

Reply via email to