Very cheap and aggressive spam handling

Aiko Barz <[email protected]>
Newsgroups gmane.mail.qmail.ldap
Organization deepcode
Message-ID <[email protected]>
Hello,

I always wanted to write this. Maybe it is useful to somebody. This
tutorial is about analysing simscan rejects to create a very harsh
qmail-smtpd.rules file.

Condition:
To reject ADSL networks at port 25, you must prepare another qmail-smtpd
service. Use the standard submission port (587) for example. Make sure,
nobody is able to deliver mails there without authentication. Example:
> :allow,SMTPAUTH="TLSREQUIRED",NOPBS="",AUTHREQUIRED="",SANITYCHECK="",RCPTCHECK="",SENDERCHECK="",LOGLEVEL="3"

Simscan:
Normally, you use simscan to reject high level junk mails during SMTP
transmission. Doing this can be very expensive. But it has advantages
too: The user doesn't have to handle 1000 mails in his junk folder every
day and the bounce handling must be done by the sending mailserver.

Simple script (Attached):
$ cat /var/log/qmail/qmail-smtpd/current |tail -n 200|log-reject.pl 
> .com (1)
>   corvel.com (1)
>     corvelusers64.corvel.com (1)
> 
> .net (2)
>   bezeqint.net (1)
>     bzq-79-183-18-2.red.bezeqint.net (1)
>   comunitel.net (1)
>     static-43-54-226-77.ipcom.comunitel.net (1)
It does a reverse DNS lookup of the rejected hosts and orders the data
according to its TLD and its domain. The numbers are hit counters. No
surprise here: Most of it comes from trojaned ADSL networks.

So, what to do if you get hit hard by a big German ADSL provider:
- p4fd751fa.dip.t-dialin.net
- p5dc53d87.dip.t-dialin.net
- p4ff0d754.dip.t-dialin.net
You have to reflect on it: Are there any good mails coming from? If
not, add this line to your qmail-smtpd.rules file:
> =.dip.t-dialin.net:allow,550GREETING="Access Denied",SMTP550DISCONNECT="",LOGLEVEL="3"
It rejects all connecting hosts with dip.t-dialin.net in their FQHN.

Complete example:
> 127.0.0.1:allow,RELAYCLIENT=""
>
> # localhost
> =localhost:allow,550GREETING="You are not me",SMTP550DISCONNECT="",LOGLEVEL="3"
> 
> # DE
> =.dip.t-dialin.net:allow,550GREETING="Access Denied",SMTP550DISCONNECT="",LOGLEVEL="3"
>
> # Main rule: $TCPREMOTEHOST needed
> =:allow,QMAILQUEUE="/var/qmail/bin/simscan",SANITYCHECK="",REJECTEXEC="",RETURNMXCHECK="",RCPTCHECK="",SENDERCHECK="",BLOCKRELAYPROBE="",LOGLEVEL="3"
>  
> # Drop connections without $TCPREMOTEHOST
> :allow,421GREETING="Reverse DNS lookup failed",SMTP550DISCONNECT="",LOGLEVEL="3"

This example also blocks hosts without a reverse DNS entry which is too
effective to ignore it. But it only returns a temporary 421 error.

Some numbers:
- No reverse DNS: About 50%
- Rejected reverse DNS entry: About 30%
- About >10% gets rejected by simscan using spamassassin and clamav.
- The rest gets deliverd. Only a few mails still enter the junk folders.
  They are mostly a result of crazy mail forwards.

Again, this is very aggressive and cannot be done in every situation.

I still hope that this text is of some use to somebody of you. Thank
you for your time. :)

So long,
    Aiko
-- 
:wq ✉
log-reject.pl (text/x-perl, 2.2 KB)
#!/usr/bin/perl -w
use strict;


my (%dnscache,%ip);
my (%tld,%domain,%host);


sub lookup
{
    my $input       = shift;
    my $dnscache    = shift;
    my $timeout     = 30;
    my $hostname    = "localhost";

    if ( $input !~ m/^\d+\.\d+\.\d+\.\d+$/ )
    {
        return($input);
    }

    if ( !$dnscache->{$input} )
    {
        eval
        {
#            alarm($timeout);
            ($hostname) = gethostbyaddr(pack('C4',split('\.',$input)),2);
#            alarm(0);
        };

        if ( $@ || !$hostname )
        {
            return($input);
        }
        
        $dnscache->{$input} = $hostname;
    }

    return lc($dnscache->{$input});
}


while ( $_ = <STDIN> )
{
    $_ =~ s/\n//;
    my ($addr,$fqhn,$tld,$domain);

    if ( $_ =~ m/.+ simscan:\[\d+\]:SPAM REJECT/ )
    {
        # Remove the beginning, so that using tai64nlocal makes no difference
        $_ =~ s/.+ simscan:\[\d+\]://;

        # IP address
        (undef,undef,undef,$addr) = split(/:/, $_);

        # FQHN
        $fqhn = lookup($addr, \%dnscache);
        if ( $host{$fqhn} )
        {
            $host{$fqhn} += 1;
        }
        else
        {
            $host{$fqhn} = 1;
        }

        # TLD
        $tld  = $fqhn;
        $tld  =~ s/.+\.(\S+)$/$1/;
        if ( $tld{$tld} )
        {
            $tld{$tld} += 1;
        }
        else
        {
            $tld{$tld} = 1;
        }

        # Domain
        $domain  = $fqhn;
        $domain  =~ s/.+\.(\S+\.\S+)$/$1/;
        if ( $domain{$domain} )
        {
            $domain{$domain} += 1;
        }
        else
        {
            $domain{$domain} = 1;
        }
    }
}


foreach my $tld (sort keys %tld)
{
    print ".".$tld." (".$tld{$tld}.")\n";

    foreach my $domain (sort keys %domain)
    {
        if ( $domain =~ m/\.$tld$/ )
        {
            print "  ".$domain." (".$domain{$domain}.")\n";
    
            foreach my $host (sort keys %host)
            {
                if ( $host =~ m/\.$domain$/ )
                {
                    print "    ".$host." (".$host{$host}.")\n";
                    delete $host{$host};
                }
            }
            delete $domain{$domain};
        }
    }
    print "\n";
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.