#!/usr/bin/perl # # rbl-check.pl v1.14 - by Bjarni R. Einarsson, http://bre.klaki.net/. # # Welcome to my source code. Read the embedded documentation with a # command like "perldoc rbl-check.pl", or scroll down a bit to read the # embedded stuff directly. # # Change log: # # 1.14 Updated & expanded list of RBL zones # 1.13 Removed orbs.dorkslayers.com # 1.12 Added relays.osirusoft.com, removed the defunct ORBS. [hpn] # Added -dsbl, -dsbl-unc, -visi and -2mbit [bre] # 1.11 Added -f switch for filtering, and -test for testing. # 1.10 Added orbs.dorkslayers.com, fixed docs. # 1.9 Updated to use ORDB.org/ORBZ.org instead of ORBS. # 1.8 Fixed bugs, updated for new ORBS lists. # 1.7 Fixed minor typos in documentation. # 1.6 Added pod-documentation and exception lists. # WARNING: Command line parameters now begin with a '-'. # 1.5 Everything works. # ############################################################################## use Socket; $debug = 0; $filter = 0; $header = "X-RBL-Check"; $rbl = { "-spamcop" => "bl.spamcop.net", "-sorbs" => "dnsbl.sorbs.net", "-spews" => "l2.spews.dnsbl.sorbs.net", "-dsbl" => "list.dsbl.org", "-spamhaus" => "sbl.spamhaus.org", "-rss" => "relays.mail-abuse.org", "-blackholes" => "blackholes.mail-abuse.org", "-osirusoft" => "relays.osirusoft.com", # "-dul" => "dialups.mail-abuse.org", "-njabl" => "dnsbl.njabl.org", "-njabl-dul" => "dnsbl.njabl.org", "-njabl-all" => "dnsbl.njabl.org", "-ordb" => "relays.ordb.org", "-dorks" => "DEAD", # orbs.dorkslayers.com "-dsbl" => "list.dsbl.org", "-dsbl-unc" => "unconfirmed.dsbl.org", "-visi" => "relays.visi.com", "-2mbit" => "blackholes.2mbit.com", "-test" => "klaki.net", "-orbz" => "DEAD", "-orbz-outputs" => "DEAD", }; $bad = { # These all return 127.0.0.x for black-listed addresses. "-spamcop" => '^127\.0\.0\.', "-sorbs" => '^127\.0\.0\.', "-spews" => '^127\.0\.0\.', "-dsbl" => '^127\.0\.0\.', "-spamhaus" => '^127\.0\.0\.', "-rss" => '^127\.0\.0\.', "-blackholes" => '^127\.0\.0\.', # "-dul" => '^127\.0\.0\.', "-njabl" => '^127\.0\.0\.[24589]$', "-njabl-dul" => '^127\.0\.0\.3$', "-njabl-all" => '^127\.0\.0\.', "-osirusoft" => '^127\.0\.0\.', "-ordb" => '^127\.0\.0\.2$', # "-dorks" => '^127\.0\.0\.2$', "-2mbit" => '^127\.0\.0\.2$', "-dsbl" => '^127\.0\.0\.2$', "-dsbl-unc" => '^127\.0\.0\.2$', "-visi" => '^127\.0\.0\.2$', "-test" => '.*', }; # Read command-line parameters # @BLACK = ( ); @WHITE = ( ); foreach $arg (@ARGV) { if ($arg eq "-d") { $debug = !$debug; } elsif ($arg =~ "-f(.*)") { $header = $1 if ($1); $filter++; print STDERR "Incremented filter level to $filter\n" if ($debug); } elsif ($rbl->{lc($arg)}) { # This will simply ignore outdated command line arguments. unless ($rbl->{lc($arg)} eq "DEAD") { push @BLACK, lc($arg); print STDERR "Added $arg to black list list...\n" if ($debug); } } else { unless (open(WHITELIST, "< $arg")) { print STDERR "Invalid list or exception file: $arg\n"; exit 0; # Die w/o error code, so mail isn't flagged as spam. } while ($line = ) { chomp $line; $line =~ s/\s*\#.*$//g; # Strip comments $line =~ s/\s+//g; # Strip whitespace $line =~ s/\./\\./g; # Quote dots. if ($line !~ /^\s*$/) { push @WHITE, $line; print STDERR "Added $line to white list...\n" if ($debug); } } close(WHITELIST); } } # Check the message # @evil_relays = ( ); $inheader = 1; while ($line = ) { if (!$inheader) { print $line if ($filter); } else { $oline = $line; if ($line =~ /^$/) { $inheader = 0; print $header, ": ", join(", ", @evil_relays), "\n" if ($filter && @evil_relays); } chop $line; # This may only work with Received: lines generated by sendmail... if (((!@evil_relays) || ($filter > 1)) && $line =~ /^(Received:|\s+).*[\[\(]([012]?\d?\d\.[012]?\d?\d\.[012]?\d?\d\.[012]?\d?\d)[\]\)]/i) { my $addr = $2; print STDERR "Checking $addr ...\n" if ($debug); if (!in_white($addr) && in_black($addr)) { push @evil_relays, $addr; last unless ($filter); } } print $oline if ($filter); } } exit 1 if ((@evil_relays) && (!$filter)); exit 0; sub in_black { my ($addr) = @_; foreach $srv (@BLACK) { my $check = join(".", reverse(split(/\./, $addr))) .".". $rbl->{$srv}; my ($name,$aliases,$addrtype,$length,@addrs) = gethostbyname($check); next unless (@addrs); my $result = inet_ntoa($addrs[0]); print STDERR "Lookup returned: $result (". $rbl->{$srv} .")\n" if ($debug); if ($result =~ $bad->{$srv}) { print STDERR "$addr found in $srv, mail is probably spam.\n"; return 1 } next; } return undef; } sub in_white { my ($addr) = @_; foreach $rule (@WHITE) { if ($addr =~ $rule) { print STDERR "Found $addr in white list.\n" if ($debug); return 1 } } return undef; } ############################################################################## # Documentation =head1 NAME rbl-check.pl - a script to check email for evidence that it passed through a mail gateway listed on the RBL or ORBS black-lists. This can help block spam sent via. an unprotected forwarding account. =head1 SYNOPSIS rbl-check.pl [-d] [-f] [-fHdr] [-] [-] ... [exception_file] =head1 DESCRIPTION This script will search the headers of an email message for IP addresses, and then look those IPs up in the various anti-spam blackhole listings. The script has the advantage over protection at the mailer level, that it will also block spam sent to an unprotected account and then B to your real one. It returns a non-zero exit code if the message appears to be spam. The script has the disadvantage of being pretty slow. =head1 USAGE =head2 Command-Line Parameters Usually, rbl-check.pl takes as arguments a list of words or filenames. The reserved words are the names of the lists you want to compare the gateway IP addresses against, the filenames point to one or more lists of exceptions, IP addresses you want to receive mail from even if they are black-listed. The different blackhole lists are checked up in the order they are specified on the command line - specifying them in order of size (largest list first) will save you a few CPU cycles. =over =item B<->B Toggle debugging output to standard error. Depending on where (and how often) this appears on the command line, slightly different things will be debugged. Most useful is a single B<->B at the beginning or at the end of the command line. =item B<->B B<->BHdr Enable filtering - specifying it twice will force all found IP addresses to be checked, instead of short-circuiting when a match is found. The found IPs will be listed in a new header named X-RBL-Check by default, or the value of Hdr, if specified. =item B<-ordb> Check the B output list. See http://www.ordb.org/ for info. This check appears at the moment to be the most effective spam-stopper (largest list according to dorkslayers.com, 15. september 2001, and my own tests), but it may also discard a signifigant amount of legitimate mail. =item B<-blackholes> Check the MAPS RBL (Realtime Blackhole List). This list contains unrepentant spam-friendly networks. See http://www.mail-abuse.org/rbl/ for info. Always checking this list is probably a good idea, unless you disagree with MAPS methodology and politics... =item B<-rss> Check the MAPS RSS (Relay Spam Stopper) list. This is a database of spam-relaying mail servers. Only hosts known to have been abused are supposed to be on the list. See http://www.mail-abuse.org/rss/ for info. =item B<->B Check the MAPS DUL (Dial-up User List). Using this list is probably a Very Bad Idea for such an indescriminate test as this. This feature is currently disabled in the script source - enable it at your own risk. See http://www.mail-abuse.org/dul/ for info. =item B<-osirusoft> Check the OsiruSoft RBL list. These guys take a pretty no-nonsense approach to it, as you can see if you read their FAQ. Their mantra: "When a site tests positive, it's listed as such. When a site is secured, it's tested, removed, and we move on." See http://relays.osirusoft.com/ for more information. =item B<-visi> Check Visi.com's Relay Stop List. From their FAQ: "Sites are listed on RSL only if we received what we believe to be spam from the server and we were able to confirm that it is open to third-party relay." See http://relays.visi.com/ for further details. =item B<-2mbit> Check the blackholes.2mbit.com blacklist. From their FAQ: "We test for open relays when we recieve UCE via what we believe to be an open relay, when we recieve a complaint of an open relay, as well as whenever we are made aware of the existance of an open relay through other channels. We don't blindly scan for open relays, we test when there is reason to believe that a server is in fact an open relay." See http://antispam.2mbit.com/blackholes/ for further details. =item B<-dsbl> Check the Distributed Sender Boycott List. From their FAQ: "DSBL waits for incoming email on listme (at) dsbl (dot) org and adds the server that handed the message to DSBL to the list. If a server is non-secure, anybody will be able to make it send out email to anywhere; not only does this give spammers an opportunity to abuse the server, it also makes it possible for people to let the server notify DSBL and add itself to the list." See http://dsbl.org/ for more information. =item B<-dsbl-unc> This list is the same as the Distributed Sender Boycott List, with the addition of listing servers with unaccountable users, such as unattentive free ISPs and free e-mail services. =item B The file is read and lines it contains are placed on a white-list. IP addresses found in this list will not be looked up in any of the black-lists (they are assumed to be OK). Example: # This is a comment ^10.1.2.3$ # We like this guy! ^10.1.2.(1|2|45)$ # And these guys! ^10.1. # Heck, we like the whole 10.1. network! Each line is actually a perl regular expression, with the exception that "." characters are not interpreted as wildcards. Note that the ^ character binds to the beginning of the IP address, and the $ character to the end - omitting either may produce unexpected results. Not terminating a network definition (like ^10.1. in the example) with a period may also cause problems. Domain names don't work - only IP addresses. B: Putting networks you communicate with frequently in an exception list can save quite a few CPU cycles/DNS lookups, which is the preferred reason for using this feature. Please resist the temptation to add black-listed hosts to your exception list - try and get them fixed instead! =back =head2 Using rbl-check.pl with Procmail This script is very easy to use with procmail, just add something like the following lines your .procmailrc file: # Use ORBS to block spam, even from forwarded accounts. :0 i * ! ? /path/to/rbl-check.pl -ordb /path/to/exceptions spamfolder If you want to check all mail received by your host, you can add similar rules to the bottom of /etc/procmailrc: # Creating mailboxes owned by root (or mail) is a bad idea. DROPPRIVS=yes # Use ORBS to block spam, even from forwarded accounts. :0 i * ! ? /path/to/rbl-check.pl -ordb /path/to/exceptions $HOME/spamfolder =head1 SCRIPT CATEGORIES UNIX/System_administration Mail =head1 AUTHOR AND COPYRIGHT B was written by Bjarni R. Einarsson Ebre@klaki.netE. This script is released to the Public Domain. New versions will be put here: http://bre.klaki.net/programs/spam/rbl-check.pl.txt If you like this script, you might also like the Anomy sanitizer at http://mailtools.anomy.net/. :-) [hpn modifications made by Harald P. Nagel, Jr. Erblcheck@haraldnagel.comE] =head1 README rbl-check.pl - a script to check email for evidence that it passed through a mail gateway listed on the RBL or ORBS black-lists. This can help block spam sent via. an unprotected forwarding account. =cut __END__ # vi:ts=4 expandtab