How To Use DNS Blocklists to Detect Spam

One of the solutions to spam is a -frequent updated- database with IP addresses that appear to misbehave. This database should, preferably, be random accessible at high speed. DNS offers a solution for that.

Introduction.
Fortunately internet has found answers for the immens growing spam problem. A solution is a -frequent updated- database with IP addresses that appear to misbehave. This database should, preferably, be random accessible at high speed. DNS offers a solution for that.

DNS entries can be updated quickly. Also, mostly there is no need to download a copy of the (potentially large) database frequently. If a mail server can detect, in a fraction of a second, that the sending IP is currently blacklisted, for example because it was infected by a virus and used as open relay, it can effictively block reception.

A well-known DNSBL provider is spamhouse.org . For a (complete) list of DNSBL providers, look here

Usage
Both SMTP servers and mail clients (or mailbox cleaners) can use this method. The path a mail message went is always stored, so you can always retrieve the originating IP. This is an essential part of the SMTP protocol.

Using the POP3 protocol, you can watch a mail box, top (top means: fetch only the message header) headers of messages, and see if they are blacklisted by looking at the "Received: from somehost (1.2.3.4)" lines.

Since these spam databases can be updated frequently, they can effectively detect a large amount (>50% ?) of spam.

How does it work

Basically, what you need to do is verify against a DNSBL (DNS BlockList) source, like
www.spamhaus.org. This is done in the following way:

Suppose you want to check if IP adress 60.70.80.90 is a spammer, you just perform a DNS query to sbl.spamhaus.org, with the (reversed) ip address inserted, like
query dns: 90.80.70.60.sbl.spamhaus.org
if you get back a A record, this is a spammer. if you get back nothing, this ip is not on the spam list.

Test it
You can easily verify this using the 'ping' command.
if you would do:
ping 90.80.70.60.sbl.spamhaus.org, then there are two options:
* you get 'unknown host' message. This is ok, the IP is not blacklisted.
* You get '127.0.0.x', where x>1, like 127.0.0.2. X represents a status code. Generally, 2 is used for (semi)permanent netblocks, and 4 is used for 'open proxies' (like: machines infected by a virus).

Example
i use this unit succesfully in a mail client. Lubos has integrated this unit successfully in a SMTP/POP3 server suite.

you can use this unit with or without synapse tcp/ip library by setting the {$DEFINE SYNAPSE} directive.

spamchck.pas

unit spamchck;

interface

//Query's the spamhaus.org database of spammers

uses Classes, SysUtils, {$IFDEF SYNAPSE}SynaUtil, SynSock{$ELSE}WinSock{$ENDIF};

type
  TSpamCheck = class (TObject)
  protected
  public
    FDNSBL:String; //DNS BlockList
    constructor Create;
    function IsSpammer (IP:String):Integer; overload;
    function IsSpammer (MailHeader:TStrings):Integer; overload;
  end;

implementation

{ TSpamCheck }

constructor TSpamCheck.Create;
begin
  inherited;
  FDNSBL := 'sbl-xbl.spamhaus.org';
  // alternatively use sbl.spamhaus.org (spam) or
  // xbl.spamhaus.org (open relays, proxys)
  // or an alternative source DNSBL source.
  // the sbl-xbl is the combined list.
end;

function TSpamCheck.IsSpammer(IP: String): Integer;
var RevIP:String;
    i:Integer;
    p:PHostEnt;
begin
  //Query the database
  //First, reverse the IP
  Result := -1;
  {$IFDEF SYNAPSE}
  if IsIP (IP) then
  {$ENDIF}
    begin
      //Reverse the IP
      RevIP := '';
      for i:=0 to 2 do
        begin
          RevIP := '.'+Copy (IP, 1, pos ('.', IP)-1) + RevIP;
          IP := Copy (IP, pos('.', IP)+1, maxint);
        end;
      RevIP := IP + RevIP;

      //Now, query the database:
      RevIP := RevIP + '.' + FDNSBL;
      p := GetHostByName (PChar(RevIP));
      if Assigned (p) then
        begin //Results come back as 127.0.0.x where x > 1
              // 127.0.0.2 = spam
              // 127.0.0.4 = open relay etc.
          Result := byte(p^.h_addr^.S_un_b.s_b4);
        end
      else //no dns entry found, mark it as safe:
        Result := 0;
    end;

end;

function TSpamCheck.IsSpammer(MailHeader: TStrings): Integer;
var v,ip:String;
    i,r:Integer;
begin
  //Parse a email header
  //Look for 'Received' header
  //extract IP address, assuming form 'Received: from (a.b.c.d) by (w.x.y.z)
  //Validate this IP address at spamhaus.
  i := 0;
  Result := -1;
  while i<MailHeader.Count do
    begin
      if pos ('received: ', lowercase (MailHeader[i])) = 1 then
        begin
          v := MailHeader[i];
          //search for additional headers:
          while ((i+1)<MailHeader.Count) and
                (MailHeader[i+1]<>'') and
                (MailHeader[i+1][1]=' ') do
            begin
              inc (i);
              v := v+MailHeader[i];
            end;
          //v now contains one line, find from ip address:
          v := lowercase (v);
          //searching for:
          //Received: from somehost.com (1.2.3.4).
          v := copy (v, pos ('from', v)+4, maxint);
          v := copy (v, pos ('(', v)+1, maxint);
          v := copy (v, 1, pos (')', v)-1);

          if pos ('[', v)>0 then
            //valid format is also:
            //Received: from somehost.com (somehost.com [1.2.3.4])
            begin
              v := copy (v, pos ('[', v)+1, maxint);
              v := copy (v, 1, pos (']', v)-1);
            end;

          Result := IsSpammer (v);

          //a single received line is sufficient
          if Result > 0 then
            break;
          //
        end;
      inc (i);
    end;
end;

end.

 

Share this article!

Follow us!

Find more helpful articles:

Popular Searches

Add comment

The content of this field is kept private and will not be shown publicly.

More information about formatting options

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.