Lines 32-39
Link Here
|
32 |
|
32 |
|
33 |
=head1 REQUIREMENT |
33 |
=head1 REQUIREMENT |
34 |
|
34 |
|
35 |
This plugin requires the Geo::IP module from CPAN. For backward |
35 |
This plugin requires the IP::Country::DB_File module from CPAN. For backward |
36 |
compatibility IP::Country::Fast is used if Geo::IP is not installed. |
36 |
compatibility IP::Country::Fast is used if IP::Country::DB_File is not installed. |
37 |
|
37 |
|
38 |
=cut |
38 |
=cut |
39 |
|
39 |
|
Lines 49-100
Link Here
|
49 |
|
49 |
|
50 |
our @ISA = qw(Mail::SpamAssassin::Plugin); |
50 |
our @ISA = qw(Mail::SpamAssassin::Plugin); |
51 |
|
51 |
|
52 |
my ($db, $dbv6); |
52 |
my $db; |
53 |
my $ip_to_cc; # will hold a sub() for the lookup |
53 |
my $ip_to_cc; # will hold a sub() for the lookup |
54 |
my $db_info; # will hold a sub() for database info |
54 |
my $db_info; # will hold a sub() for database info |
|
|
55 |
my $geoiploaded; |
55 |
|
56 |
|
56 |
# Try to load Geo::IP first |
|
|
57 |
eval { |
58 |
require Geo::IP; |
59 |
$db = Geo::IP->open_type(Geo::IP->GEOIP_COUNTRY_EDITION, Geo::IP->GEOIP_STANDARD); |
60 |
die "GeoIP.dat not found" unless $db; |
61 |
# IPv6 requires version Geo::IP 1.39+ with GeoIP C API 1.4.7+ |
62 |
if (Geo::IP->VERSION >= 1.39 && Geo::IP->api eq 'CAPI') { |
63 |
$dbv6 = Geo::IP->open_type(Geo::IP->GEOIP_COUNTRY_EDITION_V6, Geo::IP->GEOIP_STANDARD); |
64 |
if (!$dbv6) { |
65 |
dbg("metadata: RelayCountry: IPv6 support not enabled, GeoIPv6.dat not found"); |
66 |
} |
67 |
} else { |
68 |
dbg("metadata: RelayCountry: IPv6 support not enabled, versions Geo::IP 1.39, GeoIP C API 1.4.7 required"); |
69 |
} |
70 |
$ip_to_cc = sub { |
71 |
if ($dbv6 && $_[0] =~ /:/) { |
72 |
return $dbv6->country_code_by_addr_v6($_[0]) || "XX"; |
73 |
} else { |
74 |
return $db->country_code_by_addr($_[0]) || "XX"; |
75 |
} |
76 |
}; |
77 |
$db_info = sub { return "Geo::IP " . ($db->database_info || '?') }; |
78 |
1; |
79 |
} or do { |
80 |
my $eval_stat = $@ ne '' ? $@ : "errno=$!"; chomp $eval_stat; |
81 |
dbg("metadata: RelayCountry: failed to load 'Geo::IP', skipping: $eval_stat"); |
82 |
# Try IP::Country::Fast as backup |
83 |
eval { |
84 |
require IP::Country::Fast; |
85 |
$db = IP::Country::Fast->new(); |
86 |
$ip_to_cc = sub { |
87 |
return $db->inet_atocc($_[0]) || "XX"; |
88 |
}; |
89 |
$db_info = sub { return "IP::Country::Fast ".localtime($db->db_time()); }; |
90 |
1; |
91 |
} or do { |
92 |
my $eval_stat = $@ ne '' ? $@ : "errno=$!"; chomp $eval_stat; |
93 |
dbg("metadata: RelayCountry: failed to load 'IP::Country::Fast', skipping: $eval_stat"); |
94 |
return 1; |
95 |
}; |
96 |
}; |
97 |
|
98 |
# constructor: register the eval rule |
57 |
# constructor: register the eval rule |
99 |
sub new { |
58 |
sub new { |
100 |
my $class = shift; |
59 |
my $class = shift; |
Lines 104-115
Link Here
|
104 |
$class = ref($class) || $class; |
63 |
$class = ref($class) || $class; |
105 |
my $self = $class->SUPER::new($mailsaobject); |
64 |
my $self = $class->SUPER::new($mailsaobject); |
106 |
bless ($self, $class); |
65 |
bless ($self, $class); |
|
|
66 |
|
67 |
$self->set_config($mailsaobject->{conf}); |
107 |
return $self; |
68 |
return $self; |
108 |
} |
69 |
} |
109 |
|
70 |
|
|
|
71 |
sub set_config { |
72 |
my ($self, $conf) = @_; |
73 |
my @cmds; |
74 |
|
75 |
=head1 USER PREFERENCES |
76 |
|
77 |
The following options can be used in both site-wide (C<local.cf>) and |
78 |
user-specific (C<user_prefs>) configuration files to customize how |
79 |
SpamAssassin handles incoming email messages. |
80 |
|
81 |
=over 4 |
82 |
|
83 |
=item country_db_path STRING |
84 |
|
85 |
This option tells SpamAssassin where to find the country database. |
86 |
|
87 |
=back |
88 |
|
89 |
=cut |
90 |
|
91 |
push (@cmds, { |
92 |
setting => 'country_db_path', |
93 |
default => undef, |
94 |
type => $Mail::SpamAssassin::Conf::CONF_TYPE_STRING, |
95 |
code => sub { |
96 |
my ($self, $key, $value, $line) = @_; |
97 |
if (!defined $value || !length $value) { |
98 |
return $Mail::SpamAssassin::Conf::MISSING_REQUIRED_VALUE; |
99 |
} |
100 |
if (!-f $value) { |
101 |
info("config: country_db_path \"$value\" is not accessible"); |
102 |
return $Mail::SpamAssassin::Conf::INVALID_VALUE; |
103 |
} |
104 |
|
105 |
$self->{country_db_path} = $value; |
106 |
} |
107 |
}); |
108 |
|
109 |
$conf->{parser}->register_commands(\@cmds); |
110 |
} |
111 |
|
110 |
sub extract_metadata { |
112 |
sub extract_metadata { |
111 |
my ($self, $opts) = @_; |
113 |
my ($self, $opts) = @_; |
|
|
114 |
my $geo; |
115 |
my $cc; |
112 |
|
116 |
|
|
|
117 |
my $conf_country_db_path = $self->{'main'}{'resolver'}{'conf'}->{country_db_path}; |
118 |
|
119 |
# Try to load IP::Country::DB_File first |
120 |
eval { |
121 |
require IP::Country::DB_File; |
122 |
$db = IP::Country::DB_File->new($conf_country_db_path); |
123 |
die "Country db not found, please see build_ipcc.pl(1)" unless $db; |
124 |
$geoiploaded = 1; |
125 |
$db_info = sub { return "IP::Country::DB_File ".localtime($db->db_time()); }; |
126 |
1; |
127 |
} or do { |
128 |
my $eval_stat = $@ ne '' ? $@ : "errno=$!"; chomp $eval_stat; |
129 |
dbg("metadata: RelayCountry: failed to load 'IP::Country::DB_File', skipping: $eval_stat"); |
130 |
# Try IP::Country::Fast as backup |
131 |
$geoiploaded = 0; |
132 |
eval { |
133 |
require IP::Country::Fast; |
134 |
$db = IP::Country::Fast->new(); |
135 |
$db_info = sub { return "IP::Country::Fast ".localtime($db->db_time()); }; |
136 |
1; |
137 |
} or do { |
138 |
my $eval_stat = $@ ne '' ? $@ : "errno=$!"; chomp $eval_stat; |
139 |
dbg("metadata: RelayCountry: failed to load 'IP::Country::Fast', skipping: $eval_stat"); |
140 |
return 1; |
141 |
}; |
142 |
}; |
143 |
|
113 |
return 1 unless $db; |
144 |
return 1 unless $db; |
114 |
|
145 |
|
115 |
dbg("metadata: RelayCountry: Using database: ".$db_info->()); |
146 |
dbg("metadata: RelayCountry: Using database: ".$db_info->()); |
Lines 117-126
Link Here
|
117 |
|
148 |
|
118 |
my $countries = ''; |
149 |
my $countries = ''; |
119 |
my $IP_PRIVATE = IP_PRIVATE; |
150 |
my $IP_PRIVATE = IP_PRIVATE; |
|
|
151 |
my $IPV4_ADDRESS = IPV4_ADDRESS; |
120 |
foreach my $relay (@{$msg->{metadata}->{relays_untrusted}}) { |
152 |
foreach my $relay (@{$msg->{metadata}->{relays_untrusted}}) { |
121 |
my $ip = $relay->{ip}; |
153 |
my $ip = $relay->{ip}; |
122 |
# Private IPs will always be returned as '**' |
154 |
# Private IPs will always be returned as '**' |
123 |
my $cc = $ip =~ /^$IP_PRIVATE$/o ? '**' : $ip_to_cc->($ip); |
155 |
if ( $geoiploaded ) { |
|
|
156 |
if ( $ip !~ /^$IPV4_ADDRESS$/o ) { |
157 |
$cc = $db->inet6_atocc($ip) |
158 |
} else { |
159 |
$cc = $db->inet_atocc($ip) |
160 |
} |
161 |
} else { |
162 |
$geo = $db->inet_atocc($ip) || "XX"; |
163 |
$cc = $ip =~ /^$IP_PRIVATE$/o ? '**' : $geo; |
164 |
} |
124 |
$countries .= $cc." "; |
165 |
$countries .= $cc." "; |
125 |
} |
166 |
} |
126 |
|
167 |
|