ASN lookups now work

This commit is contained in:
Matt Simerson 2014-11-05 13:50:19 -08:00
parent 4eba2a39bc
commit f2eda74074
3 changed files with 113 additions and 54 deletions

View File

@ -39,4 +39,11 @@ sub is_valid_ip {
return; return;
} }
sub is_ipv6 {
my ($self, $ip) = @_;
return if !$ip;
return 1 if Net::IP::ip_is_ipv6($ip);
return;
};
1; 1;

View File

@ -102,6 +102,8 @@ data source: http://software77.net/geo-ip/
=head1 ACKNOWLEDGEMENTS =head1 ACKNOWLEDGEMENTS
MaxMind - the packager and distributor of the free GeoIP data
Stevan Bajic, the DSPAM author, who suggested SNARE, which describes using Stevan Bajic, the DSPAM author, who suggested SNARE, which describes using
geodesic distance to determine spam probability. The research paper on SNARE geodesic distance to determine spam probability. The research paper on SNARE
can be found here: can be found here:
@ -126,27 +128,12 @@ sub register {
$self->{_args} = {@args}; $self->{_args} = {@args};
$self->{_args}{db_dir} ||= '/usr/local/share/GeoIP'; $self->{_args}{db_dir} ||= '/usr/local/share/GeoIP';
eval 'use GeoIP2::Database::Reader'; $self->load_geoip2() and return;
if (!$@) { $self->load_geoip1();
warn "using GeoIP2"; }
$self->log(LOGINFO, "using GeoIP2");
eval { sub load_geoip1 {
$self->{_geoip2_city} = GeoIP2::Database::Reader->new( my $self = shift;
file => $self->{_args}{db_dir} . '/GeoLite2-City.mmdb',
);
};
eval {
$self->{_geoip2_country} = GeoIP2::Database::Reader->new(
file => $self->{_args}{db_dir} . '/GeoLite2-Country.mmdb',
);
};
$self->register_hook('connect', 'geoip2_lookup');
return;
}
warn "could not load GeoIP2";
$self->log(LOGERROR, "could not load GeoIP2");
eval 'use Geo::IP'; eval 'use Geo::IP';
if ($@) { if ($@) {
@ -166,6 +153,43 @@ sub register {
$self->register_hook('connect', 'geoip_lookup'); $self->register_hook('connect', 'geoip_lookup');
} }
sub load_geoip2 {
my $self = shift;
eval 'use GeoIP2::Database::Reader';
if ($@) {
$self->log(LOGERROR, "could not load GeoIP2");
return;
}
$self->log(LOGINFO, "GeoIP2 loaded");
eval {
$self->{_geoip2_city} = GeoIP2::Database::Reader->new(
file => $self->{_args}{db_dir} . '/GeoLite2-City.mmdb',
);
};
if ($@) {
$self->log(LOGERROR, "unable to load GeoLite2-City.mmdb");
}
eval {
$self->{_geoip2_country} = GeoIP2::Database::Reader->new(
file => $self->{_args}{db_dir} . '/GeoLite2-Country.mmdb',
);
};
if ($@) {
$self->log(LOGERROR, "unable to load GeoLite2-Country.mmdb");
}
if ($self->{_geoip2_city} || $self->{_geoip2_country}) {
$self->register_hook('connect', 'geoip2_lookup');
return 1;
}
return;
}
sub geoip2_lookup { sub geoip2_lookup {
my $self = shift; my $self = shift;
@ -246,14 +270,18 @@ sub open_geoip_db {
my $db_dir = $self->{_args}{db_dir}; my $db_dir = $self->{_args}{db_dir};
foreach my $db (qw/ GeoIPCity GeoLiteCity /) { foreach my $db (qw/ GeoIPCity GeoLiteCity /) {
next if !-f "$db_dir/$db.dat"; next if !-f "$db_dir/$db.dat";
$self->log(LOGDEBUG, "using db $db"); $self->log(LOGINFO, "using db $db");
$self->{_geoip_city} = Geo::IP->open("$db_dir/$db.dat"); $self->{_geoip_city} = Geo::IP->open("$db_dir/$db.dat");
} }
foreach my $db (qw/ GeoIPASNum GeoIPASNumv6 /) { if (-f "$db_dir/GeoIPASNum.dat") {
next if !-f "$db_dir/$db.dat"; $self->log(LOGINFO, "using GeoIPASNum");
$self->log(LOGDEBUG, "using db $db"); $self->{GeoIPASNum} = Geo::IP->open("$db_dir/GeoIPASNum.dat");
$self->{$db} = Geo::IP->open("$db_dir/$db.dat"); }
if (-f "$db_dir/GeoIPASNumv6.dat") {
$self->log(LOGINFO, "using GeoIPASNumv6");
$self->{GeoIPASNumv6} = Geo::IP->open("$db_dir/GeoIPASNumv6.dat");
} }
# can't think of a good reason to load country if city data is present # can't think of a good reason to load country if city data is present
@ -338,23 +366,28 @@ sub get_continent_gc {
} }
sub set_asn { sub set_asn {
my ($self) = @_; my ($self, $ip) = @_;
my $remote_ip = $self->qp->connection->remote_ip; $ip ||= $self->qp->connection->remote_ip;
if (Qpsmtpd::Base->is_ipv6($ip)) {
return $self->set_asn_ipv6($ip);
}
return if ! $self->{GeoIPASNum}; return if ! $self->{GeoIPASNum};
my $asn = $self->{GeoIPASNum} my $asn = $self->{GeoIPASNum}->name_by_addr($ip) or return;
? $self->get_asn_gc($remote_ip)
: $self->{_geoip}->asn_by_addr($remote_ip);
$asn or return;
$self->qp->connection->notes('geoip_asn', $asn); $self->qp->connection->notes('geoip_asn', $asn);
return $asn; return $asn;
} }
sub get_asn_gc { sub set_asn_ipv6 {
my $self = shift; my ($self, $ip) = @_;
return if !$self->{GeoIPASNum}; $ip ||= $self->qp->connection->remote_ip;
return $self->{GeoIPASNum}->asn_by_addr();
return if ! $self->{GeoIPASNumv6};
my $asn = $self->{GeoIPASNumv6}->name_by_addr_v6($ip) or return;
$self->qp->connection->notes('geoip_asn', $asn);
return $asn;
} }
sub set_city_gc { sub set_city_gc {

View File

@ -13,35 +13,37 @@ sub register_tests {
if ( !$@ ) { if ( !$@ ) {
warn "using GeoIP2\n"; warn "using GeoIP2\n";
$self->register_test('test_geoip2_lookup'); $self->register_test('test_geoip2_lookup');
return;
} }
eval 'use Geo::IP'; eval 'use Geo::IP';
if ( $@ ) { if ( !$@ ) {
warn "could not load Geo::IP\n"; warn "loaded Geo::IP\n";
return;
};
$self->register_test('test_geoip_lookup'); $self->register_test('test_geoip_lookup');
$self->register_test('test_geoip_load_db'); $self->register_test('test_geoip_load_db');
$self->register_test('test_geoip_init_cc'); $self->register_test('test_geoip_init_cc');
$self->register_test('test_set_country_code'); $self->register_test('test_set_country_code');
$self->register_test('test_set_country_name'); $self->register_test('test_set_country_name');
$self->register_test('test_set_continent'); $self->register_test('test_set_continent');
$self->register_test('test_set_distance'); $self->register_test('test_set_distance');
$self->register_test('test_set_isp'); $self->register_test('test_set_asn');
};
}; };
sub test_geoip2_lookup { sub test_geoip2_lookup {
my $self = shift; my $self = shift;
$self->qp->connection->remote_ip('24.24.24.24'); $self->qp->connection->remote_ip('24.24.24.24');
cmp_ok( $self->geoip2_lookup(), '==', DECLINED, "exit code"); cmp_ok( $self->geoip2_lookup(), '==', DECLINED, "exit code DECLINED");
cmp_ok( $self->connection->notes('geoip_country'), 'eq', 'US', "24.24.24.24 is in the US"); if (!$self->load_geoip2()) {
cmp_ok( $self->connection->notes('geoip_country_name'), 'eq', 'United States', "24.24.24.24 is in the United States"); warn "failed to load GeoIP2\n";
cmp_ok( $self->connection->notes('geoip_continent'), 'eq', 'NA', "24.24.24.24 is in NA"); }
cmp_ok( $self->connection->notes('geoip_city'), 'eq', 'Deer Park', "24.24.24.24 is in Deer Park");
cmp_ok( $self->connection->notes('geoip_country'), 'eq', 'US', "24.24.24.24 is in country US");
cmp_ok( $self->connection->notes('geoip_country_name'), 'eq', 'United States', "24.24.24.24 is in country United States");
cmp_ok( $self->connection->notes('geoip_continent'), 'eq', 'NA', "24.24.24.24 is in continent NA");
cmp_ok( $self->connection->notes('geoip_city'), 'eq', 'Deer Park', "24.24.24.24 is in city of Deer Park");
}; };
sub test_geoip_lookup { sub test_geoip_lookup {
@ -164,3 +166,20 @@ sub test_set_distance {
ok( 1, "no distance data"); ok( 1, "no distance data");
} }
}; };
sub test_set_asn {
my $self = shift;
$self->qp->connection->remote_ip('');
$self->set_asn();
my $asn = $self->set_asn();
ok( ! $asn, "undef") or warn "$asn\n";
$self->qp->connection->remote_ip('24.24.24.24');
$asn = $self->set_asn();
ok( $self->connection->notes('geoip_asn') =~ /^AS11351/, "note has: $asn");
$self->qp->connection->remote_ip('66.128.51.163');
$asn = $self->set_asn();
ok( $self->connection->notes('geoip_asn') =~ /^AS7819/, "note has: $asn");
};