Line
Link Here
|
0 |
-- init.pre-orig 2015-01-23 09:39:49.000000000 -0800 |
0 |
++ init.pre 2015-01-23 09:42:13.000000000 -0800 |
Lines 17-23
Link Here
|
17 |
# RelayCountry - add metadata for Bayes learning, marking the countries |
17 |
# RelayCountry - add metadata for Bayes learning, marking the countries |
18 |
# a message was relayed through |
18 |
# a message was relayed through |
19 |
# |
19 |
# |
20 |
# Note: This requires the IP::Country::Fast Perl module |
20 |
# Note: This requires the Geo::IP Perl module |
21 |
# |
21 |
# |
22 |
loadplugin Mail::SpamAssassin::Plugin::RelayCountry |
22 |
loadplugin Mail::SpamAssassin::Plugin::RelayCountry |
23 |
|
23 |
|
24 |
-- RelayCountry.pm-orig 2015-01-23 09:38:49.000000000 -0800 |
24 |
++ RelayCountry.pm 2015-01-23 09:41:15.000000000 -0800 |
Lines 25-38
Link Here
|
25 |
|
25 |
|
26 |
=head1 DESCRIPTION |
26 |
=head1 DESCRIPTION |
27 |
|
27 |
|
28 |
By the RelayCountry plugin attempts to determine the domain country |
28 |
The RelayCountry plugin attempts to determine the domain country codes |
29 |
codes of each relay used in the delivery path of messages and add that |
29 |
of each relay used in the delivery path of messages and add that information |
30 |
information to the message metadata as "X-Relay-Countries", or |
30 |
to the message metadata as "X-Relay-Countries", or the C<_RELAYCOUNTRY_> |
31 |
the C<_RELAYCOUNTRY_> header markup. |
31 |
header markup. |
32 |
|
32 |
|
33 |
=head1 REQUIREMENT |
33 |
=head1 REQUIREMENT |
34 |
|
34 |
|
35 |
This plugin requires the IP::Country module from CPAN. |
35 |
This plugin requires the Geo::IP module from CPAN. For backward |
|
|
36 |
compatibility IP::Country::Fast is used if Geo::IP is not installed. |
36 |
|
37 |
|
37 |
=cut |
38 |
=cut |
38 |
|
39 |
|
Lines 40-45
Link Here
|
40 |
|
41 |
|
41 |
use Mail::SpamAssassin::Plugin; |
42 |
use Mail::SpamAssassin::Plugin; |
42 |
use Mail::SpamAssassin::Logger; |
43 |
use Mail::SpamAssassin::Logger; |
|
|
44 |
use Mail::SpamAssassin::Constants qw(:ip); |
43 |
use strict; |
45 |
use strict; |
44 |
use warnings; |
46 |
use warnings; |
45 |
use bytes; |
47 |
use bytes; |
Lines 48-53
Link Here
|
48 |
use vars qw(@ISA); |
50 |
use vars qw(@ISA); |
49 |
@ISA = qw(Mail::SpamAssassin::Plugin); |
51 |
@ISA = qw(Mail::SpamAssassin::Plugin); |
50 |
|
52 |
|
|
|
53 |
my ($db, $dbv6); |
54 |
my $ip_to_cc; # will hold a sub() for the lookup |
55 |
my $db_info; # will hold a sub() for database info |
56 |
|
57 |
# Try to load Geo::IP first |
58 |
eval { |
59 |
require Geo::IP; |
60 |
$db = Geo::IP->open_type(Geo::IP->GEOIP_COUNTRY_EDITION, Geo::IP->GEOIP_STANDARD); |
61 |
die "GeoIP.dat not found" unless $db; |
62 |
# IPv6 requires version Geo::IP 1.39+ with GeoIP C API 1.4.7+ |
63 |
if (Geo::IP->VERSION >= 1.39 && Geo::IP->api eq 'CAPI') { |
64 |
$dbv6 = Geo::IP->open_type(Geo::IP->GEOIP_COUNTRY_EDITION_V6, Geo::IP->GEOIP_STANDARD); |
65 |
if (!$dbv6) { |
66 |
dbg("metadata: RelayCountry: IPv6 support not enabled, GeoIPv6.dat not found"); |
67 |
} |
68 |
} else { |
69 |
dbg("metadata: RelayCountry: IPv6 support not enabled, versions Geo::IP 1.39, GeoIP C API 1.4.7 required"); |
70 |
} |
71 |
$ip_to_cc = sub { |
72 |
if ($dbv6 && $_[0] =~ /:/) { |
73 |
return $dbv6->country_code_by_addr_v6($_[0]) || "XX"; |
74 |
} else { |
75 |
return $db->country_code_by_addr($_[0]) || "XX"; |
76 |
} |
77 |
}; |
78 |
$db_info = sub { return "Geo::IP " . ($db->database_info || '?') }; |
79 |
1; |
80 |
} or do { |
81 |
my $eval_stat = $@ ne '' ? $@ : "errno=$!"; chomp $eval_stat; |
82 |
dbg("metadata: RelayCountry: failed to load 'Geo::IP', skipping: $eval_stat"); |
83 |
# Try IP::Country::Fast as backup |
84 |
eval { |
85 |
require IP::Country::Fast; |
86 |
$db = IP::Country::Fast->new(); |
87 |
$ip_to_cc = sub { |
88 |
return $db->inet_atocc($_[0]) || "XX"; |
89 |
}; |
90 |
$db_info = sub { return "IP::Country::Fast ".localtime($db->db_time()); }; |
91 |
1; |
92 |
} or do { |
93 |
my $eval_stat = $@ ne '' ? $@ : "errno=$!"; chomp $eval_stat; |
94 |
dbg("metadata: RelayCountry: failed to load 'IP::Country::Fast', skipping: $eval_stat"); |
95 |
return 1; |
96 |
}; |
97 |
}; |
98 |
|
51 |
# constructor: register the eval rule |
99 |
# constructor: register the eval rule |
52 |
sub new { |
100 |
sub new { |
53 |
my $class = shift; |
101 |
my $class = shift; |
Lines 63-86
Link Here
|
63 |
sub extract_metadata { |
111 |
sub extract_metadata { |
64 |
my ($self, $opts) = @_; |
112 |
my ($self, $opts) = @_; |
65 |
|
113 |
|
66 |
my $reg; |
114 |
return 1 unless $db; |
67 |
|
|
|
68 |
eval { |
69 |
require IP::Country::Fast; |
70 |
$reg = IP::Country::Fast->new(); |
71 |
1; |
72 |
} or do { |
73 |
my $eval_stat = $@ ne '' ? $@ : "errno=$!"; chomp $eval_stat; |
74 |
dbg("metadata: failed to load 'IP::Country::Fast', skipping: $eval_stat"); |
75 |
return 1; |
76 |
}; |
77 |
|
115 |
|
|
|
116 |
dbg("metadata: RelayCountry: Using database: ".$db_info->()); |
78 |
my $msg = $opts->{msg}; |
117 |
my $msg = $opts->{msg}; |
79 |
|
118 |
|
80 |
my $countries = ''; |
119 |
my $countries = ''; |
|
|
120 |
my $IP_PRIVATE = IP_PRIVATE; |
81 |
foreach my $relay (@{$msg->{metadata}->{relays_untrusted}}) { |
121 |
foreach my $relay (@{$msg->{metadata}->{relays_untrusted}}) { |
82 |
my $ip = $relay->{ip}; |
122 |
my $ip = $relay->{ip}; |
83 |
my $cc = $reg->inet_atocc($ip) || "XX"; |
123 |
# Private IPs will always be returned as '**' |
|
|
124 |
my $cc = $ip =~ /^$IP_PRIVATE$/o ? '**' : $ip_to_cc->($ip); |
84 |
$countries .= $cc." "; |
125 |
$countries .= $cc." "; |
85 |
} |
126 |
} |
86 |
|
127 |
|
Lines 93-100
Link Here
|
93 |
|
134 |
|
94 |
sub parsed_metadata { |
135 |
sub parsed_metadata { |
95 |
my ($self, $opts) = @_; |
136 |
my ($self, $opts) = @_; |
|
|
137 |
|
138 |
return 1 unless $db; |
139 |
|
140 |
my $countries = |
141 |
$opts->{permsgstatus}->get_message->get_metadata('X-Relay-Countries'); |
142 |
my @c_list = split(' ', $countries); |
96 |
$opts->{permsgstatus}->set_tag ("RELAYCOUNTRY", |
143 |
$opts->{permsgstatus}->set_tag ("RELAYCOUNTRY", |
97 |
$opts->{permsgstatus}->get_message->get_metadata('X-Relay-Countries')); |
144 |
@c_list == 1 ? $c_list[0] : \@c_list); |
98 |
return 1; |
145 |
return 1; |
99 |
} |
146 |
} |
100 |
|
147 |
|