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.");
  }


_______________________________________________
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 [email protected]
http://lists.roaringpenguin.com/mailman/listinfo/mimedefang

Reply via email to