แจก SpamAssassin Plugin OriginatingCountry

จุดประสงค์:
เพิ่มความสามารถให้กับ SpamAssassin ในการตรวจสอบต้นทางของอีเมล โดยอ้างอิงจากหมายเลข IP Address และใช้ Module Geo::IP ของ perl ในการแปลงหมายเลข IP Address ให้เป็นชื่อประเทศ

*** ต้องติดตั้ง Module Geo::IP ก่อน

ไฟล์ OriginatingCountry.pm

package Mail::SpamAssassin::Plugin::OriginatingCountry;

use Mail::SpamAssassin::Plugin;
use Mail::SpamAssassin::Constants qw(:ip);
use strict;
use warnings;
use bytes;

use vars qw(@ISA);
@ISA = qw(Mail::SpamAssassin::Plugin);

sub new {
  my $class = shift;
  my $mailsaobject = shift;

  # some boilerplate...
  $class = ref($class) || $class;
  my $self = $class->SUPER::new($mailsaobject);
  bless ($self, $class);

  $self->register_eval_rule ("check_any_ip_header");

  return $self;
}

sub check_any_ip_header {
  my ($self, $permsgstatus, $rulename) = @_;
  return 0;
}


sub parsed_metadata {
  my ($self, $opts) = @_;
  my $scanner = $opts->{permsgstatus};

  my $gi;

  eval {
    require Geo::IP;
    $gi = Geo::IP->new();
  };
  if ($@) {
    dbg ("failed to load 'Geo::IP', skipping");
    return 1;
  }

  my %iplist = ();
  my $IP_ADDRESS = IP_ADDRESS;
  my $ip; 
  # check_x_ip_header
  for my $header ('X-X-Originating-IP', 'X-ORIGINATOR-IP', 'X-Apparently-From', 'X-Originating-IP', 'X-OriginatingIP', 'X-AOL-IP', 'X-SenderIP', 'X-Sender-IP', 'X-MDRemoteIP', 'X-Origin', 'X-MAIL-SOURCE-IP', 'X-IPADDR') {
  $ip = $scanner->get($header);
  next unless $ip;
  $ip =~ m/($IP_ADDRESS)/g;
  dbg("Found x-ip: $ip");
  $iplist{$ip} = 1;
 }

# check_yahoo_ip_header

if ($scanner->get("Received") =~ /\s?from\s+(\S+)\s+by\s+web[a-z0-9\.]+\.yahoo\.[a-z0-9\.]+\s+via\s+HTTP\;/) {
    $ip = $1;
    if ($ip =~ /$IP_ADDRESS/) {
       dbg("Found yahoo-ip: $ip");
       $iplist{$ip} = 1;
     }  
  }
if ($scanner->get("Received") =~ /\s?from\s+unknown\s+\(HELO\s+[\w.-]+\)\s+\([\w.-]+\@(\S+)\s+with\s+login\)/) {
    $ip = $1;
    if ($ip =~ /$IP_ADDRESS/) {
      dbg("Found yahoo-ip2: $ip");
      $iplist{$ip} = 1;
    }
}

if ($scanner->get("Received") =~ /\s?from\s+\[192\.168\.1\.1\]\s+\([\w._-]+\@(\S+)\s+with\s+plain\)/) {
    $ip = $1;
    if ($ip =~ /$IP_ADDRESS/) {
      dbg("Found yahoo-ip3: $ip");
      $iplist{$ip} = 1;
    }
}         

if ($scanner->get("X-Received") =~ /\s?from\s+\[192\.168\.1\.1\]\s+\([\w._-]+\@(\S+)\s+with\s+plain\)/) {
    $ip = $1;          
    if ($ip =~ /$IP_ADDRESS/) {  
      dbg("Found yahoo-ip4: $ip");             
      $iplist{$ip} = 1; 
    }
}

# check_authen_ip_header
if ($scanner->get("Received") =~ /\s?from\s+\w+\s+(\S+)/) {
    $ip = $1;
    if ($ip =~ /$IP_ADDRESS/) {
      dbg("Found authen-ip: $ip");
      $iplist{$ip} = 1;
    }  
}

if ($scanner->get("Received") =~ /\s?from\s[\w.-]+\s+\(unknown\s+(\S+)\)/) {
    $ip = $1; 
   if ($ip =~ /$IP_ADDRESS/) {
      dbg("Found authen-ip2: $ip");      
      $iplist{$ip} = 1;
    }  
}

if ($scanner->get("Received") =~ /\s?from\s[\w.-]+\s+\(unknown\s+(\S+)\)[\s
\r]+\(/) {
    $ip = $1;
   if ($ip =~ /$IP_ADDRESS/) {
      dbg("Found authen-ip3: $ip");
      $iplist{$ip} = 1;
    }
}

  
# check_squirrelmail_ip_header
if ($scanner->get("Received") =~ /\s?from\s+(\S+)[\s
\r]+\(SquirrelMail authenticated/) {
    $ip = $1;
   if ($ip =~ /$IP_ADDRESS/) {
      dbg("Found SquirrelMail-ip: $ip");
      $iplist{$ip} = 1;
    }  
}

if ($scanner->get("Received") =~ /\s?from\s[\w.-]+\s+\(proxying for\s+(\S+)\)[\s
\r]+\(SquirrelMail authenticated/) {
    $ip = $1;
   if ($ip =~ /$IP_ADDRESS/) {
      dbg("Found proxying: $ip");
      $iplist{$ip} = 1;
    }
}

# check_qmail_ip_header

if ($scanner->get("Received") =~ /\s?from\s+[\w.-]+\s+\(\S+\s+\S+\)\s+(\S+)\s+\(envelope\-sender/) {
    $ip = $1;
   if ($ip =~ /$IP_ADDRESS/) {
      dbg("Found qmail-ip: $ip");
      $iplist{$ip} = 1;
    }  
}
  
# check_phpscript_ip_header
if ($scanner->get("X-PHP-Script") =~ /\sfor\s(\S+)/) {
    $ip = $1;
   if ($ip =~ /$IP_ADDRESS/) {
      dbg("Found phpscript-ip: $ip");
      $iplist{$ip} = 1;
   }      
}

# check_webmail_ip1
if ($scanner->get("Received") =~ /\s?from\s+[\w.-]+\s+\(\S+\s+\S+\)\s+\([\.\-\_a-z0-9A-Z]+\@[\.\-\_a-z0-9A-Z]+\@(\S+)\)/) {
    $ip = $1;
   if ($ip =~ /$IP_ADDRESS/) {
      dbg("Found webmail-ip1: $ip");
      $iplist{$ip} = 1;      
   }
}

if ($scanner->get("Received") =~ /\s?from\s[\w.-]+\s+(\S+)\s+by\s+[\w.-]+\s+with\s+SMTP\;/) {
    $ip = $1;      
   if ($ip =~ /$IP_ADDRESS/) {
      dbg("Found SMTP-ip: $ip");
      $iplist{$ip} = 1;
    }
}

if ($scanner->get("Received") =~ /\s?from\s(\S+)\s+(?:\S+)[\s
\r]+by\s+[\w.-]+\s+with\s+esmtpa/) {
    $ip = $1;      
   if ($ip =~ /$IP_ADDRESS/) {
      dbg("Found Exim-ip1: $ip");
      $iplist{$ip} = 1;
    }
}

# rediffmail
if ($scanner->get("Received") =~ /(\S+)\sby\srediffmail\.com\svia\sHTTP\;/) {
    $ip = $1;
   if ($ip =~ /$IP_ADDRESS/) {
      dbg("Found rediffmail-ip: $ip");
      $iplist{$ip} = 1;
    }
}  

if ($scanner->get("Received") =~ /\s?from\s+(\S+)\s+by\s+[\w.-]+\s+with\s+HTTP$/) {
    $ip = $1;
   if ($ip =~ /$IP_ADDRESS/) {
      dbg("Found freewebmail: $ip");
      $iplist{$ip} = 1;
    }
}


# postfix
if ($scanner->get("Received") =~ /\s?from\s+unknown\s+\(HELO\s+[\w.-]+\)\s+\(\[(\S+)\]\)\s*by\s+[\w.-]+\s+with\s+ESMTP\;/) {
    $ip = $1;
    if ($ip =~ /$IP_ADDRESS/) {
      dbg("Found postfix-ip: $ip");
      $iplist{$ip} = 1;
    }
}

if ($scanner->get("Received") =~ /\s?from\s+(?:\S+)\s+(?:\S+)\s+\[(\S+)\]\)[\s
\r]+\(authenticated\s+user\s+\S+\)/) {
    $ip = $1;
   if ($ip =~ /$IP_ADDRESS/) {
      dbg("Found Postfix-ip1: $ip");
      $iplist{$ip} = 1;
    }
}        

  my %countries = ();
  my $ipadd;
  foreach my $ipaddr (keys(%iplist)) {
    $ipadd = $ipaddr;
    #if ($ipaddr =~ /(${IP_ADDRESS})/) { $ipadd = $1; }
    $ipaddr =~ s/[\x28\x29\x22\x5B\x5D]//gs;
    dbg("Test country on $ipadd");
    if ($ipaddr =~ /(${IP_ADDRESS})/) { 
        $ipadd = $1; 
        dbg("Check country on $ipadd");
    }
    my $cc = $gi->country_code_by_addr($ipadd);
    if ($cc) {
    dbg("$ipadd in $cc");
    $countries{uc($cc)} = 1;
    }
  }

  foreach my $rule (keys(%{$scanner->{conf}->{xipcountry}})) {
    my $country = uc($scanner->{conf}->{xipcountry}->{$rule});
    if($countries{$country}) {
      dbg ("hit rule: $country");
      $scanner->got_hit($rule, "");
    }
  }

  return 1;
}

sub parse_config {
  my ($self, $opts) = @_;
  my $key = $opts->{key};
  if ($key eq 'xipcountry') {
    if ($opts->{value} =~ /^(\S+)\s+(\S+)\s*$/) {
      my $rulename = $1;
      my $country = $2;

      dbg("registering $rulename");
      $opts->{conf}->{xipcountry}->{$rulename} = $country;
      $self->inhibit_further_callbacks(); return 1;
    }
  }

  return 0;
}


sub dbg { Mail::SpamAssassin::Plugin::dbg ("XIPCountry: @_"); }

1;

ไฟล์ OriginatingCountry.cf

ifplugin Mail::SpamAssassin::Plugin::OriginatingCountry

xipcountry XIPCOUNTRY_NG NG 
header   XIPCOUNTRY_NG  eval:check_any_ip_header('NG')
 describe XIPCOUNTRY_NG  Message was sending from Nigeria
score    XIPCOUNTRY_NG  20.00

endif

เพิ่มบรรทัดในไฟล์ init.pre

loadplugin Mail::SpamAssassin::Plugin::OriginatingCountry OriginatingCountry.pm