[Mimedefang] implementing spamass RBL checks in MD

Matt Cramer mscramer at armstrong.com
Wed Jan 21 16:02:50 EST 2004


The SA RBL checks make quite a difference to the amount of spam I catch,
so I wrote some code in my filter to perform the checks, score them the
same as SA would (given both Bayes and networking enabled), and then
modify the SA $report to reflect the tests.  I suppose a better way than
what I do below would be to read /usr/share/spamassassin/20_dnsrbl.cf and
50_scores.cf on the fly, but this stuff hasn't seemed to change too
frequently with the last few SA releases.

Realize this WILL slow down your processing, but we do about 30K inbound
mails/day and it hasn't been a problem.  Use at your own risk.  So here is
my filter_end....

[BTW I had to delete the last line of my report as set in my
/etc/mail/spamassassin/sa-mimedefang.cf and I add it after I get done
adding RBL hits to the report.  I also tolerate a blank line between the
report as generated by the call to spam_assassin_check and the RBL checks
I do in my code.  I am lazy and didn't feel like writing code to make it
look identical just for asthetics.]


 sub filter_end ($) {

    use Socket;

    my($entity) = @_;

    # If you want quarantine reports, uncomment next line
    # send_quarantine_notifications();

    # IMPORTANT NOTE:  YOU MUST CALL send_quarantine_notifications() AFTER
    # ANY PARTS HAVE BEEN QUARANTINED.  SO IF YOU MODIFY THIS FILTER TO
    # QUARANTINE SPAM, REWORK THE LOGIC TO CALL send_quarantine_notifications()
    # AT THE END!!!

    # No sense doing any extra work
    return if message_rejected();

    # Spam checks if SpamAssassin is installed
    if ($Features{"SpamAssassin"}) {
        if (-s "./INPUTMSG" < 200*1024) {
            # Only scan messages smaller than 200kB.  Larger messages
            # are extremely unlikely to be spam, and SpamAssassin is
            # dreadfully slow on very large messages.
            my($hits, $req, $names, $report) = spam_assassin_check();

            # check RBLs and add to $hits
            # this code emulates what spamass would do with net checks
            # when both net and bayes are enabled
            my($result);
            if ($result = (relay_is_blacklisted($RelayAddr, "dnsbl.njabl.org"))) {
                $result = inet_ntoa($result);
                # RCVD_IN_NJABL
                $hits = $hits + 0.100;
                $names = $names . ",RCVD_IN_NJABL";
                $report = $report . " 0.1 RCVD_IN_NJABL\tReceived via a relay in dnsbl.njabl.org\n";
                if ($result eq '127.0.0.2') {
                    # RCVD_IN_NJABL_RELAY
                    $hits = $hits + 0.001;
                    $names = $names . ",RCVD_IN_NJABL_RELAY";
                    $report = $report . " 0.0 RCVD_IN_NJABL_RELAY\tNJABL: sender is confirmed open relay\n";
                } elsif ($result eq '127.0.0.3') {
                    # RCVD_IN_NJABL_DIALUP
                    $hits = $hits + 3.536;
                    $names = $names . ",RCVD_IN_NJABL_DIALUP";
                    $report = $report . " 3.5 RCVD_IN_NJABL_DIALUP\tNJABL: dialup sender did non-local SMTP\n";
                } elsif ($result eq '127.0.0.4') {
                    # RCVD_IN_NJABL_SPAM
                    $hits = $hits + 1.206;
                    $names = $names . ",RCVD_IN_NJABL_SPAM";
                    $report = $report . " 1.2 RCVD_IN_NJABL_SPAM\tNJABL: sender is confirmed spam source\n";
                } elsif ($result eq '127.0.0.5') {
                    # RCVD_IN_NJABL_MULTI
                    $hits = $hits + 0.001;
                    $names = $names . ",RCVD_IN_NJABL_MULTI";
                    $report = $report . " 0.0 RCVD_IN_NJABL_MULTI\tNJABL: sent through multi-stage open relay\n"
                } elsif ($result eq '127.0.0.8') {
                    # RCVD_IN_NJABL_CGI
                    $hits = $hits + 0;
                    $names = $names . ",RCVD_IN_NJABL_CGI";
                    $report = $report . " 0 RCVD_IN_NJABL_CGI\tNJABL: sender is an open formmail\n";
                } elsif ($result eq '127.0.0.9') {
                    # RCVD_IN_NJABL_PROXY
                    $hits = $hits + 0.500;
                    $names = $names . ",RCVD_IN_NJABL_PROXY";
                    $report = $report . " 0.5 RCVD_IN_NJABL_PROXY\tNJABL: sender is an open proxy\n";
                }
            }
            if ($result = (relay_is_blacklisted($RelayAddr, "dnsbl.sorbs.net"))) {
                $result = inet_ntoa($result);
                # RCVD_IN_SORBS
                $hits = $hits + 0.100;
                $names = $names . ",RCVD_IN_SORBS";
                $report = $report . " 0.1 RCVD_IN_SORBS\tSORBS: sender is listed in SORBS\n";
                if ($result eq '127.0.0.2') {
                    # RCVD_IN_SORBS_HTTP
                    $hits = $hits + 1.101;
                    $names = $names . ",RCVD_IN_SORBS_HTTP";
                    $report = $report . " 1.1 RCVD_IN_SORBS_HTTP\tSORBS: sender is open HTTP proxy server\n"
                } elsif ($result eq '127.0.0.3') {
                    # RCVD_IN_SORBS_SOCKS
                    $hits = $hits + 1.204;
                    $names = $names . ",RCVD_IN_SORBS_SOCKS";
                    $report = $report . " 1.2 RCVD_IN_SORBS_SOCKS\tSORBS: sender is open SOCKS proxy server\n";
                } elsif ($result eq '127.0.0.4') {
                    # RCVD_IN_SORBS_MISC
                    $hits = $hits + 0.687;
                    $names = $names . ",RCVD_IN_SORBS_MISC";
                    $report = $report . " 0.7 RCVD_IN_SORBS_MISC\tSORBS: sender is open proxy server\n";
                } elsif ($result eq '127.0.0.5') {
                    # RCVD_IN_SORBS_SMTP
                    $hits = $hits + 2.700;
                    $names = $names . ",RCVD_IN_SORBS_SMTP";
                    $report = $report . " 2.7 RCVD_IN_SORBS_SMTP\tSORBS: sender is open SMTP relay\n";
                } elsif ($result eq '127.0.0.6') {
                    # RCVD_IN_SORBS_SPAM
                    $hits = $hits + 0;
                    $names = $names . ",RCVD_IN_SORBS_SPAM";
                    $report = $report . " 0 RCVD_IN_SORBS_SPAM\tSORBS: spam source or spam-supporting ISP\n";
                } elsif ($result eq '127.0.0.7') {
                    # RCVD_IN_SORBS_WEB
                    $hits = $hits + 0;
                    $names = $names . ",RCVD_IN_SORBS_WEB";
                    $report = $report . " 0 RCVD_IN_SORBS_WEB\tSORBS: sender is a abuseable web server\n";
                } elsif ($result eq '127.0.0.8') {
                    # RCVD_IN_SORBS_BLOCK
                    $hits = $hits + 0;
                    $names = $names . ",RCVD_IN_SORBS_BLOCK";
                    $report = $report . " 0 RCVD_IN_SORBS_BLOCK\tSORBS: sender demands to never be tested\n";
                } elsif ($result eq '127.0.0.9') {
                    # RCVD_IN_SORBS_ZOMBIE
                    $hits = $hits + 2.599;
                    $names = $names . ",RCVD_IN_SORBS_ZOMBIE";
                    $report = $report . " 2.6 RCVD_IN_SORBS_ZOMBIE\tSORBS: sender is on a hijacked network\n";
                } elsif ($result eq '127.0.0.10') {
                    # RCVD_IN_DYNABLOCK
                    $hits = $hits + 2.599;
                    $names = $names . ",RCVD_IN_DYNABLOCK";
                    $report = $report . " 2.6 RCVD_IN_DYNABLOCK\tSent directly from dynamic IP address\n";
                }
            }
            if ($result = (relay_is_blacklisted($RelayAddr, "opm.blitzed.org"))) {
                $result = inet_ntoa($result);
                # RCVD_IN_OPM
                $hits = $hits + 1.001;
                $names = $names . ",RCVD_IN_OPM";
                $report = $report . " 1.0 RCVD_IN_OPM\tReceived via a relay in opm.blitzed.org\n";
                if ($result eq '1') {
                    # RCVD_IN_OPM_WINGATE
                    $hits = $hits + 2.700;
                    $names = $names . ",RCVD_IN_OPM_WINGATE";
                    $report = $report . " 2.7 RCVD_IN_OPM_WINGATE\tOPM: sender is open WinGate proxy\n";
                } elsif ($result eq '2') {
                    # RCVD_IN_OPM_SOCKS
                    $hits = $hits + 1.257;
                    $names = $names . ",RCVD_IN_OPM_SOCKS";
                    $report = $report . " 1.3 RCVD_IN_OPM_SOCKS\tOPM: sender is open SOCKS proxy\n";
                } elsif ($result eq '4') {
                    # RCVD_IN_OPM_HTTP
                    $hits = $hits + 1.101;
                    $names = $names . ",RCVD_IN_OPM_HTTP";
                    $report = $report . " 1.1 RCVD_IN_OPM_HTTP\tOPM: sender is open HTTP CONNECT proxy\n";
                } elsif ($result eq '8') {
                    # RCVD_IN_OPM_ROUTER
                    $hits = $hits + 0;
                    $names = $names . ",RCVD_IN_OPM_ROUTER";
                    $report = $report . " 0 RCVD_IN_OPM_ROUTER\tOPM: sender is open router proxy\n";
                } elsif ($result eq '16') {
                    # RCVD_IN_OPM_HTTP_POST
                    $hits = $hits + 1.001;
                    $names = $names . ",RCVD_IN_OPM_HTTP_POST";
                    $report = $report . " 1.0 RCVD_IN_OPM_HTTP_POST\tOPM: sender is open HTTP POST proxy\n";
                }
            }
            if ($result = (relay_is_blacklisted($RelayAddr, "list.dsbl.org"))) {
                $result = inet_ntoa($result);
                # RCVD_IN_DSBL
                $hits = $hits + 0.706;
                $names = $names . ",RCVD_IN_DSBL";
                $report = $report . " 0.7 RCVD_IN_DSBL\tReceived via a relay in list.dsbl.org\n";
            }
            if ($result = (relay_is_blacklisted($RelayAddr, "ipwhois.rfc-ignorant.org"))) {
                $result = inet_ntoa($result);
                # RCVD_IN_RFCI
                $hits = $hits + 0.100;
                $names = $names . ",RCVD_IN_RFCI";
                $report = $report . " 0.1 RCVD_IN_RFCI\tSent via a relay in ipwhois.rfc-ignorant.org\n";
            }
#           if ($result = (relay_is_blacklisted($RelayAddr, "dsn.rfc-ignorant.org"))) {
#               $result = inet_ntoa($result);
                # DNS_FROM_RFCI_DSN
#               $hits = $hits + 0;
#               $names = $names . ",DNS_FROM_RFCI_DSN";
#               $report = $report . " 0 DNS_FROM_RFCI_DSN\tFrom: sender listed in dsn.rfc-ignorant.org\n";
#           }
            if ($result = (relay_is_blacklisted($RelayAddr, "sa-hil.habeas.com"))) {
                $result = inet_ntoa($result);
                # HABEAS_VIOLATOR
                $hits = $hits + 16;
                $names = $names . ",HABEAS_VIOLATOR";
                $report = $report . " 16 HABEAS_VIOLATOR\tHas Habeas warrant mark and on Infringer List\n";
            }
            if ($result = (relay_is_blacklisted($RelayAddr, "sa-trusted.bondedsender.org"))) {
                $result = inet_ntoa($result);
                # RCVD_IN_BSP_TRUSTED
                $hits = $hits - 4.3;
                $names = $names . ",RCVD_IN_BSP_TRUSTED";
                $report = $report . " -4.3 RCVD_IN_BSP_TRUSTED\tSender is in Bonded Sender Program (trusted relay)\n";
            }
            if ($result = (relay_is_blacklisted($RelayAddr, "sa-other.bondedsender.org"))) {
                $result = inet_ntoa($result);
                # RCVD_IN_BSP_OTHER
                $hits = $hits - 0.1;
                $names = $names . ",RCVD_IN_BSP_OTHER";
                $report = $report . " -0.1 RCVD_IN_BSP_OTHER\tSender is in Bonded Sender Program (other relay)\n";
            }
            if ($result = (relay_is_blacklisted($RelayAddr, "bl.spamcop.net"))) {
                $result = inet_ntoa($result);
                # RCVD_IN_BL_SPAMCOP_NET
                $hits = $hits + 1.50;
                $names = $names . ",RCVD_IN_BL_SPAMCOP_NET";
                $report = $report . " 1.5 RCVD_IN_BL_SPAMCOP_NET\tReceived via a relay in bl.spamcop.net\n";
            }
            $report =~ s/[0-9]+\.[0-9]+ hits/$hits hits/;
            $report = $report . ": -------------------- End of Spam Details -----------------------------";


            my($score);
            if ($hits < 40) {
                $score = "*" x int($hits);
            } else {
                $score = "*" x 40;
            }
            if ($hits >= $req) {
                # just drop obnoxiously high messages
                if ($hits > 10) {
                    md_graphdefang_log('discarded spam',  $hits, $RelayAddr);
                    action_discard();
                } else {
                        action_change_header("Subject", "\*\*\*\*\*SPAM\*\*\*\*\* $Subject");

                        # If you find the SA report useful, add it, I guess...
                        action_add_part($entity, "text/plain", "-suggest",
                                "$report\n",
                                "SpamAssassinReport.txt", "inline");
                        md_graphdefang_log('spam', $hits, $RelayAddr);
                }
            } else {
                md_graphdefang_log('clean', $hits, $RelayAddr);
            }
            # We add a header which looks like this:
            # X-Spam-Score: 6.8 (******) NAME_OF_TEST,NAME_OF_TEST
            # The number of asterisks in parens is the integer part
            # of the spam score clamped to a maximum of 40.
            # MUA filters can easily be written to trigger on a
            # minimum number of asterisks...
            action_change_header("X-Spam-Score", "$hits ($score) $names");
        } else {
            md_graphdefang_log('clean', '0', $RelayAddr);
        }

    }
}


-- 
Matthew S. Cramer <mscramer at armstrong.com>          Office: 717-396-5032
Infrastructure Security Analyst                     Fax:    717-396-5590
Armstrong World Industries, Inc.                    Cell:   717-917-7099



More information about the MIMEDefang mailing list