postfwd/tools/postfwd-rblcheck.pl

175 lines
4.6 KiB
Perl
Raw Normal View History

2013-11-05 16:31:59 +00:00
#!/usr/bin/perl -T -w
#
# Tool to query a bunch of dnsbls. Usage:
#
# postfwd-rblcheck.pl <hostname or ip> [<hostname or ip> ...]
#
# by JPK
use Net::DNS::Async;
use strict;
# length of screen
my $mylen = 79;
# RBLs (ip based)
my @rbls = qw(
query.bondedsender.org
exemptions.ahbl.org
spf.trusted-forwarder.org
list.dnswl.org
zz.countries.nerd.dk
zen.spamhaus.org
bl.spamcop.net
list.dsbl.org
multihop.dsbl.org
unconfirmed.dsbl.org
combined.njabl.org
dnsbl.sorbs.net
dnsbl.ahbl.org
ix.dnsbl.manitu.net
dnsbl-1.uceprotect.net
dnsbl-2.uceprotect.net
dnsbl-3.uceprotect.net
ips.backscatterer.org
sorbs.dnsbl.net.au
korea.services.net
blackholes.five-ten-sg.com
cbl.anti-spam.org.cn
cblplus.anti-spam.org.cn
cblless.anti-spam.org.cn
bogons.cymru.com
dynamic.tqmrbl.com
relays.tqmrbl.com
clients.tqmrbl.com
hostkarma.junkemailfilter.com
);
# RHSBLs (domain based)
my @rhsbls = qw(
rhsbl.sorbs.net
rhsbl.ahbl.org
multi.surbl.org
dsn.rfc-ignorant.org
abuse.rfc-ignorant.org
whois.rfc-ignorant.org
bogusmx.rfc-ignorant.org
blackhole.securitysage.com
ex.dnsbl.org
rddn.dnsbl.net.au
block.rhs.mailpolice.com
dynamic.rhs.mailpolice.com
dnsbl.cyberlogic.net
hostkarma.junkemailfilter.com
);
# async dns object
my $DNS = new Net::DNS::Async ( QueueSize => 100, Retries => 3, Timeout => 20 );
our %RBLres = ();
# async dns callback method
sub callback {
my $myresponse = shift;
my $query = ''; my $result = '';
# get query
if ( defined $myresponse ) {
foreach ($myresponse->question) {
next unless (($_->qtype eq 'A') or ($_->qtype eq 'TXT'));
$query = $_->qname;
};
# get answer and fill result hash
if ( defined $query ) {
foreach ($myresponse->answer) {
if ($_->type eq 'A') {
$result = $_->address;
$query ||= ''; $result ||= '';
$RBLres{$query}{result} = $result;
$RBLres{$query}{end} = time;
} elsif ($_->type eq 'TXT') {
$RBLres{$query}{text} = join(" ", $_->char_str_list());
$RBLres{$query}{end} = time;
};
};
};
};
};
# main, parse argument list
foreach (@ARGV) {
my $query = $_;
my $now = time;
my @lookups = ();
my $name = my $addr = my $res = 'unknown';
my $rblcount = my $rhlcount = 0;
# clear result hash
%RBLres = ();
# lookup hostname or ip address, remove localpart if email address
if ($query =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) {
$addr = $query;
$name = $res
if ( defined($res = gethostbyaddr (pack ('C4', (split /\./, $addr)), 2)) );
} else {
$name = ($query =~ /@([^@]+)$/) ? $1 : $query;
$addr = ( join ".", (unpack ('C4', $res)) )
if ( defined ($res = gethostbyname ($name.".")) );
};
# header
print "\n", "=" x $mylen, "\n";
print "QUERY: ", $query, " NAME: ", $name, " ADDR: ", $addr, "\n";
# prepare rbl lookups
unless ($addr eq 'unknown') {
$addr = join ".", reverse split /\./, $addr;
foreach my $rbl (@rbls) {
$RBLres{$addr.".".$rbl}{query} = $rbl;
$RBLres{$addr.".".$rbl}{type} = 'RBL';
$RBLres{$addr.".".$rbl}{start} = time;
push @lookups, $addr.".".$rbl;
#print "query ", $RBLres{$addr.".".$rbl}{query}, " for ", $addr.".".$rbl, "\n";
};
};
# prepare rhsbl lookups
unless ($name eq 'unknown') {
foreach my $rhsbl (@rhsbls) {
$RBLres{$name.".".$rhsbl}{query} = $rhsbl;
$RBLres{$name.".".$rhsbl}{type} = 'RHSBL';
$RBLres{$name.".".$rhsbl}{start} = time;
push @lookups, $name.".".$rhsbl;
#print "name ", $RBLres{$name.".".$rhsbl}{query}, " for ", $name.".".$rhsbl, "\n";
};
};
# perform lookups
map { $DNS->add (\&callback, $_) } @lookups;
map { $DNS->add (\&callback, $_, 'TXT') } @lookups;
$DNS->await();
# evaluate results
foreach $query (sort keys %RBLres) {
if ($query and (defined $RBLres{$query}{result})) {
print " ", "-" x ($mylen - 4), "\n";
printf " listed on %s:%s, result: %s, time: %ds\n %s\n",
$RBLres{$query}{type},
$RBLres{$query}{query}, $RBLres{$query}{result},
($RBLres{$query}{end} - $RBLres{$query}{start}),
((defined $RBLres{$query}{text}) ? "\"".$RBLres{$query}{text}."\"" : '<undef>');
$rblcount++ if $RBLres{$query}{type} eq 'RBL';
$rhlcount++ if $RBLres{$query}{type} eq 'RHSBL';
};
};
# footer
print " ", "-" x ($mylen - 4), "\n";
printf "%d of %d RBLs, ", $rblcount, $#rbls if ($rblcount > 0);
printf "%d of %d RHSBLs, ", $rhlcount, $#rhsbls if ($rhlcount > 0);
printf "Finished after %d seconds\n", (time - $now);
print "=" x $mylen, "\n\n";
};