On May 3, 2006, at 5:43 AM, David F. Skoll wrote:
For what it's worth, this is my code to detect a likely-looking dynamic
IP address, based on the PTR record.
and, here's my filter_sender (where I do my similar checks) ...
sub filter_sender {
my ($sender, $ip, $hostname, $helo) = @_;
my ($iaddr, $name, $aliases, $addrtype, $length, @addrs, $addr,
$tmp);
my $found = 0;
if ($sender =~ /\.local$/) {
# no .local senders, even from my own IP addrs or authenticated
senders
# CGP does weird things with .local addresses
md_syslog('warning', "Rejecting .local sender address $sender");
return ('REJECT', "We do not accept .local sender addresses");
}
elsif (authenticated_user() || exempt_ip_addr($ip)) {
# exempt certain IP addrs or authenticated senders from further
checks
return ('CONTINUE', "ok");
}
elsif ($helo =~ /(\@|\.)rudd\.cc\>?$/i) {
# if it got here, then it's not one of my ip addrs, so reject
# it if it claims a helo/ehlo of *.rudd.cc
md_syslog('warning', "Rejecting forged helo address $helo $ip
$hostname");
return ('REJECT', "You're not actually in the rudd.cc domain");
}
elsif ($sender =~ /(\@|\.)rudd\.cc\>?$/i) {
# if they really are from my domain, they'd be caught by my
exemptions
# or use my webmail system if they can't use SMTP-AUTH that moment
md_syslog ('warning', "Rejecting forged local sender $sender
$ip");
return ('REJECT', "You're not actually from the rudd.cc domain");
}
elsif ( ($sender =~ /^\<?noreply\@/i) &&
($sender !~ /(\@|\.)freshmeat\.net\>?$/i) && # freshmeat
uses it
($sender !~ /(\@|\.)adc\.apple\.com\>?$/i) && # apple adc
uses it
($sender !~ /(\@|\.)google\.com\>?$/i) ) { # google uses
it
# noreply@ seems to mostly be used by spammers these days
# with just a couple known exceptions
md_syslog ('warning', "Rejecting noreply sender $sender $ip");
return ('REJECT', "We don't accept noreply senders");
}
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 versions of IP address components:
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)); # should be redundant to
"$f$g$h$i"
$hostname = lc($hostname); # instead of lots of //i matches
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|ddns|dhcp)/ ) ||
($hostname =~ /(dial-?up|dynamic|$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]") {
# everyone else better have valid rDNS, or use an ISP whose
customer
# relay that has valid rDNS. Tempfail in case it was a transient
# DNS error.
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 5, so, tempfail
# if we get here
return ('TEMPFAIL', "This shouldn't happen.");
}
_______________________________________________
NOTE: If there is a disclaimer or other legal boilerplate in the above
message, it is NULL AND VOID. You may ignore it.
Visit http://www.mimedefang.org and http://www.roaringpenguin.com
MIMEDefang mailing list MIMEDefang@lists.roaringpenguin.com
http://lists.roaringpenguin.com/mailman/listinfo/mimedefang