Folllow-up Test Code - Re: [Mimedefang] Potential for Business mail servers to nothavereverse DNS
John Rudd
john at rudd.cc
Fri Sep 22 21:44:04 EDT 2006
Kevin A. McGrail wrote:
> use strict;
> use Net::DNS;
Looks decent. I didn't use Net::DNS though (which basically just means
I don't get to specify my own timeouts ... I should probably look into
that).
The other things I do differently:
a) it's a good idea that you only search the sub-domain for dynamic
fingerprints... I hadn't thought about that; I might adapt to that. (so
far, any shawcable emails I've bounced would have bounced for other
reasons, but it has been my one worry about false-positives on the
dynamic hostname front)
b) I look for elements of the IP address in the domain (or, in the
sub-domain in your case).
Here's my filter_sender:
sub filter_sender {
my ($sender, $ip, $hostname, $helo) = @_;
my ($iaddr, $name, $aliases, $addrtype, $length, @addrs, $addr, $tmp);
my $found = 0;
# need this for checking for the SMTP-AUTH transaction
read_commands_file();
if ($sender =~ /\.local$/) {
# no .local senders, even from my own IP addrs or authenticated
senders
md_syslog('warning', "Rejecting .local sender address $sender");
return ('REJECT', "We do not accept .local sender addresses");
}
elsif ( (defined($SendmailMacros{'auth_authen'}))
|| ($ip =~ /^127\.0\.0\.1$/)
|| ($ip =~ /^128\.114\.125\./)
|| ($ip =~ /^128\.114\.2\.223/)
|| ($ip =~ /^10\.0\.1\./)
|| ($ip =~ /^69\.105\.229\.53$/)
|| ($ip =~ /^69\.12\.154\.165$/) ) {
# exempt my home/work IP addrs or authenticated senders from
further checks
return ('CONTINUE', "ok");
}
elsif ($hostname ne "[$ip]") {
# assume that $hostname was created from a rDNS check of $ip
# so, we don't need to do that again with the gethostbyaddr
# what we're doing is checking that $hostname isn't forged
# by being sure that the @addrs it returns has $ip in it
# (and, again, my own blocks or authentic senders are exempted above)
($name, $aliases, $addrtype, $length, @addrs) =
gethostbyname($hostname);
unless (defined ($name)) {
md_syslog('warning',
"Tempfail can't verify reverse DNS for $hostname $ip");
return ('TEMPFAIL',
"Can't verify that your reverse DNS matches your
forward DNS" .
" - either your PTR record returns something that
doesn't" .
" exist, or DNS for it is timing out - try again
later");
}
foreach $addr (@addrs) {
$tmp = join (".", unpack('C4', $addr));
if ($tmp eq $ip) {
$found = 1;
}
}
if (! ($found) ) { # we got an answer, it doesn't include $ip
# ! $found should mean that the rDNS is forged to some other
hostname
md_syslog('warning', "Forged rDNS - $hostname doesn't return $ip");
md_syslog('warning', "rDNS mismatch for $ip $name $hostname");
return ('REJECT',
"Forged DNS: reverse DNS doesn't match forward DNS " .
"- fix your PTR and A records.");
}
else {
# verified their reverse DNS matches, now lets do some checking
# IP address components that might be in the hostname:
my ($a, $b, $c, $d) = split(/\./, $ip);
# decimal encoded IP address that might be in the hostname:
my $e = ($a * 256 * 256 * 256) + ($b * 256 * 256) + ($c * 256)
+ $d;
# hexadecimal encoded IP address that might be in the hostname:
my $f = lc(sprintf("%x", $a));
my $g = lc(sprintf("%x", $b));
my $h = lc(sprintf("%x", $c));
my $i = lc(sprintf("%x", $d));
my $j = lc(sprintf("%x", $e));
#md_syslog('warning', "rDNS match for $ip $name $hostname");
$hostname = lc($hostname);
if ($hostname =~ /\.kr$/) {
# korean hostnames only seem to send me spam
md_syslog('warning', "Blocking .kr relay $hostname");
return ('REJECT', "We don't accept email from .kr hostnames");
}
elsif ($hostname =~ /\.mx$/) {
# mexican hostnames only seem to send me spam
md_syslog('warning', "Blocking .mx relay $hostname");
return ('REJECT', "We don't accept email from .mx hostnames");
}
elsif ( ($hostname =~ /(catv|cable|dsl|dhcp|ddns)/ ) ||
($hostname =~ /(dial-?up|dynamic|ppp|$e|$j)/ ) ||
($hostname =~ /($a.?0*$b|$b.?0*$c|$c.?0*$d)/ ) ||
($hostname =~ /($d.?0*$c|$c.?0*$b|$b.?0*$a)/ ) ||
($hostname =~ /($f.?0*$g|$g.?0*$h|$h.?0*$i)/ ) ||
($hostname =~ /($i.?0*$h|$h.?0*$g|$g.?0*$f)/ ) ) {
# The IP has a few key words in its hostname, or it has
components
# of its IP address in its hostname, then its probably an ISP
# assigned dynamic or dial-up host, and should either get
specific
# DNS to avoid looking like a client, or use its ISP's mail
server
md_syslog('warning', "Blocking end-client host $hostname $ip");
return ('REJECT',
"ISP clients IPs should use their ISPs mail server");
}
else { # otherwise, accept it
return ('CONTINUE', "ok");
}
}
}
elsif ($hostname eq "[$ip]") {
# Tempfail in case it was a transient DNS error.
# (and, again, my own blocks or authentic senders are exempted above)
md_syslog('warning', "Tempfail for no reverse DNS $ip");
return ('TEMPFAIL',
"You don't have valid reverse DNS - get a PTR record");
}
# we shouldn't get here ... the last two if conditions should cover
# _every_ message that wasn't caught by the first 3, so, tempfail
# if we get here
return ('TEMPFAIL', "This shouldn't happen.");
}
More information about the MIMEDefang
mailing list