[Mimedefang] Soliciting opinions on filtering based on bad MX records

Michael Sims michaels at crye-leike.com
Thu Sep 11 16:26:03 EDT 2003


Hi,

I've put some code into place to test the feasibility of filtering mail
based on the domain of the envelope sender having a "bogus MX record".  I
think I have something here that might be useful, but I wanted to run it by
the gurus on this list to get some opinions.  What I know about DNS I've
just picked up while administering my mail server, and I'm no expert by any
means, so it may be possible that I'm overlooking something.

I've created a new sub called "domainOfSenderHasBorkedDns" (yeah, I know how
cumbersome that is :) ), which I call in filter_sender.  It accepts a sender
address and returns true if the domain of the address has a "bogus MX
record".  I define a bogus MX record as one that points to a non-routable
address, whether this is 0.0.0.0, or a loopback address, or a reserved IP
address.  These are the checks that I perform, in order:

(1) Retrieve the MX record for the sender domain.  If it doesn't exist, I
retrieve all A records for the sender domain.  If they don't exist, I return
false.  If they do, I test each A record, returning true if any one of the
records is "bogus", false otherwise.

(2) If the MX record exists, I test it to see if it's in the format of an IP
address.  If it is, I test to see if it is "bogus", and I return true if it
is, false if it isn't.  I've noticed some domains have MX records like
"127.0.0.1" and so forth, so this catches those.

(3) If the MX record is a hostname, I retrieve the A records for it.  If
they don't exist, I return false.  If they do, I test each A record,
returning true if any one of the records is "bogus", false otherwise.

My basic approach is to only claim that a domain has bogus MX if I get some
sort of affirmative response from DNS with a non-routable address.  If I
don't get a response from DNS I return false, since I'm not sure if the
failure is due to bad DNS or intermittent DNS problems on my side.

So far I'm just logging the occurence of a "bogus MX record", and not
actually taking any action on it.  If it turns out to be reliable, I'm
considering using it as a basis to reject mail.

Relevant code follows.  I would appreciate any thoughts on the general
approach, as well as the code.  Thanks...

...

use Net::DNS 0.40;

my $DnsResolver = Net::DNS::Resolver->new(tcp_timeout => 1, udp_timeout =>
1, retry => 1);

sub domainOfSenderHasBorkedDns {

  my ($sender) = @_;

  # This hash defines a list of IPs and networks that are bogus when
  # used as an MX.  This list should contain any non-routable network,
  # such as loopback or reserved addresses. Each entry should be a
  # subnet/netmask pair.  To specify a single host, use 255.255.255.255
  # as the netmask
  my %bogusMXs = (

    '0.0.0.0'     => '255.255.255.255',
    '127.0.0.0'   => '255.0.0.0',
    '10.0.0.0'    => '255.0.0.0',
    '172.16.0.0'  => '255.240.0.0',
    '192.168.0.0' => '255.255.0.0'

  );

  my $dnsIsBorked = 0;

  my $senderDomain;
  if ($Sender =~ /^<?.*?\@(.*?)>?$/) {
    $senderDomain = $1;
  } else { return 0; } # This should never happen, as sendmail should have
blocked
                       # any message with a envelope sender address in a bad
format

  # Get MX record for domain of sender
  my $result = $DnsResolver->query($senderDomain, 'MX');

  unless (defined $result) {

    # No MX record for host, retrieve A record
    my $result = $DnsResolver->query($senderDomain, 'A');
    return 0 unless (defined $result);

    # Check each A record to see if any of them are bogus
    my @rrs = $result->answer;
    foreach my $rr (@rrs) {
      $dnsIsBorked = 1 if addrInSubnetHash($rr->address, \%bogusMXs);
    }

    return $dnsIsBorked;

  }

  my $mx = ($result->answer)[0]->exchange;
  return 0 unless defined($mx);

  # See if the MX hostname is actually an IP address, and if so check
  # it for bogosity
  return addrInSubnetHash($mx, \%bogusMXs) if ($mx =~
/^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/);

  # Retrieve A records for MX hostname
  $result = $DnsResolver->query($mx, 'A');
  return 0 unless (defined $result);

  # Check each A record to see if any of them are bogus
  my @rrs = $result->answer;
  foreach my $rr (@rrs) {
    $dnsIsBorked = 1 if addrInSubnetHash($rr->address, \%bogusMXs);
  }

  return $dnsIsBorked;

}

sub addrInSubnetHash {

  my ($address, $subnetHashRef) = @_;

  my $addr = inet_aton $address;
  while (my ($networkString, $netmaskString) = each %$subnetHashRef) {
    my $network = inet_aton $networkString;
    my $netmask = inet_aton $netmaskString;
    if (($addr & $netmask) eq $network) { return 1; }
  }

  return 0;

}

___________________________________________
Michael Sims
Project Analyst - Information Technology
Crye-Leike Realtors
Office: (901)758-5648  Pager: (901)769-3722
___________________________________________




More information about the MIMEDefang mailing list