On Mon, 2005-08-08 at 15:53 -0500, [EMAIL PROTECTED] wrote: > > > > It allows rules such as: > > uricountry URICOUNTRY_CN CN > > header URICOUNTRY_CN eval:check_uricountry('URICOUNTRY_CN') > > describe URICOUNTRY_CN Contains a URI hosted in China > > tflags URICOUNTRY_CN net > > score URICOUNTRY_CN 2.0 > > > > Derek > > > Oh yes, that type code would be very nice to have indeed for people like > me who can't outright RBL them. Do you also have code for Korea even? But > dare I ask too much. :-) I could give it a score of 4 or so... and up it > even more when spammer simpletons start thinking they are on to the latest > greatest China spam idea. :-)
The code will work for any country. Just write a rule for that country. Here's what's needed in your local.cf loadplugin Mail::SpamAssassin::Plugin::URICountry uricountry URICOUNTRY_CN CN header URICOUNTRY_CN eval:check_uricountry('URICOUNTRY_CN') describe URICOUNTRY_CN Contains a URI hosted in China tflags URICOUNTRY_CN net score URICOUNTRY_CN 2.0 uricountry URICOUNTRY_KR KR header URICOUNTRY_KR eval:check_uricountry('URICOUNTRY_KR') describe URICOUNTRY_KR Contains a URI hosted in Korea tflags URICOUNTRY_KR net score URICOUNTRY_KR 2.0 uricountry URICOUNTRY_BR BR header URICOUNTRY_BR eval:check_uricountry('URICOUNTRY_BR') describe URICOUNTRY_BR Contains a URI hosted in Brazil tflags URICOUNTRY_BR net score URICOUNTRY_BR 2.0 Derek -- code for the plugin follows -- =head1 NAME URICountry - add message metadata indicating the country code of each relay =head1 SYNOPSIS loadplugin Mail::SpamAssassin::Plugin::URICountry =head1 REQUIREMENT This plugin requires the IP::Country::Fast module from CPAN. =cut package Mail::SpamAssassin::Plugin::URICountry; use Mail::SpamAssassin::Plugin; use strict; use bytes; use vars qw(@ISA); @ISA = qw(Mail::SpamAssassin::Plugin); # constructor: register the eval rule 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_uricountry"); return $self; } # this is just a placeholder; in fact the results are dealt with later sub check_uricountry { my ($self, $permsgstatus, $rulename) = @_; return 0; } # and the eval rule itself sub parsed_metadata { my ($self, $opts) = @_; my $scanner = $opts->{permsgstatus}; my $reg; eval { require IP::Country::Fast; $reg = IP::Country::Fast->new(); }; if ($@) { dbg ("failed to load 'IP::Country::Fast', skipping"); return 1; } my %domlist = (); foreach my $uri ($scanner->get_uri_list()) { my $dom = my_uri_to_domain($uri); dbg("debug: URICountry $uri in $dom"); if ($dom) { $domlist{$dom} = 1; } } # Build a list of the countries for URIs in the message. my %countries = (); foreach my $dom (keys(%domlist)) { my $cc = $reg->inet_atocc($dom) || "XX"; dbg("debug: URICountry $dom in $cc"); $countries{lc($cc)} = 1; } # Now check if any match any defined rules. foreach my $rule (keys(%{$scanner->{conf}->{uricountry}})) { my $country = lc($scanner->{conf}->{uricountry}->{$rule}); if($countries{$country}) { dbg ("debug: URICountry hit rule: $country"); $scanner->got_hit($rule, ""); } } return 1; } sub parse_config { my ($self, $opts) = @_; my $key = $opts->{key}; if ($key eq 'uricountry') { if ($opts->{value} =~ /^(\S+)\s+(\S+)\s*$/) { my $rulename = $1; my $country = $2; dbg("debug: URICountry: registering $rulename"); $opts->{conf}->{uricountry}->{$rulename} = $country; $self->inhibit_further_callbacks(); return 1; } } return 0; } # Taken from the one in Util.pm but we don't want to drop the hostname doing so # often leaves us with no A record. sub my_uri_to_domain { my ($uri) = @_; # Javascript is not going to help us, so return. return if ($uri =~ /^javascript:/i); $uri =~ s,#.*$,,gs; # drop fragment $uri =~ s#^[a-z]+:/{0,2}##gsi; # drop the protocol $uri =~ s,^[^/]*\@,,gs; # username/passwd $uri =~ s,[/\?\&].*$,,gs; # path/cgi params $uri =~ s,:\d+$,,gs; # port return if $uri =~ /\%/; # skip undecoded URIs. # we'll see the decoded version as well # keep IPs intact if ($uri !~ /^\d+\.\d+\.\d+\.\d+$/) { # get rid of hostname part of domain, understanding delegation #$uri = Mail::SpamAssassin::Util::RegistrarBoundaries::trim_domain($uri); # ignore invalid domains return unless (Mail::SpamAssassin::Util::RegistrarBoundaries::is_domain_valid($uri)); } # $uri is now the domain only return lc $uri; } sub dbg { Mail::SpamAssassin::dbg (@_); } 1; -- end code --