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 ✉
#!/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";
}