added GeoIP2 support, partial ASN support
This commit is contained in:
parent
9862cdc042
commit
c61dbb5734
@ -30,8 +30,9 @@ WriteMakefile(
|
|||||||
# 'DBIx::Simple' => 0, # log2sql
|
# 'DBIx::Simple' => 0, # log2sql
|
||||||
# modules that cause Travis build tests to fail
|
# modules that cause Travis build tests to fail
|
||||||
# 'Mail::SpamAssassin' => 0,
|
# 'Mail::SpamAssassin' => 0,
|
||||||
# 'Geo::IP' => 0,
|
# 'GeoIP2' => 2,
|
||||||
# 'Math::Complex' => 0, # geodesic distance in Geo::IP
|
# 'Geo::IP' => 1,
|
||||||
|
# 'Math::Complex' => 0, # geodesic distance in geoip
|
||||||
# 'Mail::SPF' => 0,
|
# 'Mail::SPF' => 0,
|
||||||
},
|
},
|
||||||
ABSTRACT => 'Flexible smtpd daemon written in Perl',
|
ABSTRACT => 'Flexible smtpd daemon written in Perl',
|
||||||
|
@ -85,6 +85,8 @@ This plugin does not update the GeoIP databases. You may want to.
|
|||||||
|
|
||||||
=head1 CHANGES
|
=head1 CHANGES
|
||||||
|
|
||||||
|
2014-06 - Matt Simerson - added GeoIP2 support
|
||||||
|
|
||||||
2012-06 - Matt Simerson - added GeoIP City support, continent, distance
|
2012-06 - Matt Simerson - added GeoIP City support, continent, distance
|
||||||
|
|
||||||
2012-05 - Matt Simerson - added geoip_country_name note, added tests
|
2012-05 - Matt Simerson - added geoip_country_name note, added tests
|
||||||
@ -126,8 +128,25 @@ sub register {
|
|||||||
|
|
||||||
my $loaded = 0;
|
my $loaded = 0;
|
||||||
|
|
||||||
eval 'use GeoIP2';
|
eval 'use GeoIP2::Database::Reader';
|
||||||
if ($@) {
|
if (!$@) {
|
||||||
|
warn "using GeoIP2";
|
||||||
|
$self->log(LOGINFO, "using GeoIP2");
|
||||||
|
|
||||||
|
eval {
|
||||||
|
$self->{_geoip2_city} = GeoIP2::Database::Reader->new(
|
||||||
|
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";
|
warn "could not load GeoIP2";
|
||||||
$self->log(LOGERROR, "could not load GeoIP2");
|
$self->log(LOGERROR, "could not load GeoIP2");
|
||||||
|
|
||||||
@ -137,19 +156,47 @@ sub register {
|
|||||||
$self->log(LOGERROR, "could not load Geo::IP");
|
$self->log(LOGERROR, "could not load Geo::IP");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
$self->open_geoip_db();
|
||||||
|
|
||||||
# Note that opening the GeoIP DB only in register has caused problems before:
|
# Note that opening the GeoIP DB only in register has caused problems before:
|
||||||
# https://github.com/smtpd/qpsmtpd/commit/29ea9516806e9a8ca6519fcf987dbd684793ebdd#plugins/ident/geoip
|
# https://github.com/smtpd/qpsmtpd/commit/29ea9516806e9a8ca6519fcf987dbd684793ebdd#plugins/ident/geoip
|
||||||
# Opening the DB anew for every connection is horribly inefficient.
|
# Opening the DB anew for every connection is horribly inefficient.
|
||||||
# Instead, attempt to reopen upon connect if the DB connection fails.
|
# Instead, attempt to reopen upon connect if the DB connection fails.
|
||||||
$self->open_geoip_db();
|
|
||||||
|
|
||||||
$self->init_my_country_code();
|
$self->init_my_country_code();
|
||||||
|
|
||||||
$self->register_hook('connect', 'geoip_lookup');
|
$self->register_hook('connect', 'geoip_lookup');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub geoip2_lookup {
|
||||||
|
my $self = shift;
|
||||||
|
|
||||||
|
my $ip = $self->qp->connection->remote_ip;
|
||||||
|
|
||||||
|
if ($self->{_geoip2_city}) {
|
||||||
|
my $city_rec = $self->{_geoip2_city}->city(ip => $ip);
|
||||||
|
if ($city_rec) {
|
||||||
|
$self->qp->connection->notes('geoip_country', $city_rec->country->iso_code());
|
||||||
|
$self->qp->connection->notes('geoip_country_name', $city_rec->country->name());
|
||||||
|
$self->qp->connection->notes('geoip_continent', $city_rec->continent->code());
|
||||||
|
$self->qp->connection->notes('geoip_city', $city_rec->city->name());
|
||||||
|
$self->qp->connection->notes('geoip_asn', $city_rec->traits->autonomous_system_number());
|
||||||
|
return DECLINED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($self->{_geoip2_country}) {
|
||||||
|
my $country_rec = $self->{_geoip2_country}->country(ip => $ip);
|
||||||
|
if ($country_rec) {
|
||||||
|
$self->qp->connection->notes('geoip_country', $country_rec->country->iso_code());
|
||||||
|
$self->qp->connection->notes('geoip_country_name', $country_rec->country->name());
|
||||||
|
$self->qp->connection->notes('geoip_continent', $country_rec->continent->code());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return DECLINED;
|
||||||
|
}
|
||||||
|
|
||||||
sub geoip_lookup {
|
sub geoip_lookup {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
@ -200,10 +247,15 @@ sub open_geoip_db {
|
|||||||
# save the handles in different locations
|
# save the handles in different locations
|
||||||
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 /) {
|
||||||
if (-f "$db_dir/$db.dat") {
|
next if !-f "$db_dir/$db.dat";
|
||||||
$self->log(LOGDEBUG, "using db $db");
|
$self->log(LOGDEBUG, "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 /) {
|
||||||
|
next if !-f "$db_dir/$db.dat";
|
||||||
|
$self->log(LOGDEBUG, "using db $db");
|
||||||
|
$self->{$db} = Geo::IP->open("$db_dir/$db.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
|
||||||
@ -287,6 +339,26 @@ sub get_continent_gc {
|
|||||||
return $self->{_geoip_record}->continent_code();
|
return $self->{_geoip_record}->continent_code();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub set_asn {
|
||||||
|
my ($self) = @_;
|
||||||
|
my $remote_ip = $self->qp->connection->remote_ip;
|
||||||
|
return if ! $self->{GeoIPASNum};
|
||||||
|
|
||||||
|
my $asn = $self->{GeoIPASNum}
|
||||||
|
? $self->get_asn_gc($remote_ip)
|
||||||
|
: $self->{_geoip}->asn_by_addr($remote_ip);
|
||||||
|
|
||||||
|
$asn or return;
|
||||||
|
$self->qp->connection->notes('geoip_asn', $asn);
|
||||||
|
return $asn;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_asn_gc {
|
||||||
|
my $self = shift;
|
||||||
|
return if !$self->{GeoIPASNum};
|
||||||
|
return $self->{GeoIPASNum}->asn_by_addr();
|
||||||
|
}
|
||||||
|
|
||||||
sub set_city_gc {
|
sub set_city_gc {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
return if !$self->{_geoip_record};
|
return if !$self->{_geoip_record};
|
||||||
|
@ -9,6 +9,13 @@ use Qpsmtpd::Constants;
|
|||||||
sub register_tests {
|
sub register_tests {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
|
eval 'use GeoIP2::Database::Reader';
|
||||||
|
if ( !$@ ) {
|
||||||
|
warn "using GeoIP2\n";
|
||||||
|
$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 "could not load Geo::IP\n";
|
||||||
@ -22,6 +29,19 @@ sub register_tests {
|
|||||||
$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');
|
||||||
|
};
|
||||||
|
|
||||||
|
sub test_geoip2_lookup {
|
||||||
|
my $self = shift;
|
||||||
|
|
||||||
|
$self->qp->connection->remote_ip('24.24.24.24');
|
||||||
|
cmp_ok( $self->geoip2_lookup(), '==', DECLINED, "exit code");
|
||||||
|
|
||||||
|
cmp_ok( $self->connection->notes('geoip_country'), 'eq', 'US', "24.24.24.24 is in the US");
|
||||||
|
cmp_ok( $self->connection->notes('geoip_country_name'), 'eq', 'United States', "24.24.24.24 is in the United States");
|
||||||
|
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");
|
||||||
};
|
};
|
||||||
|
|
||||||
sub test_geoip_lookup {
|
sub test_geoip_lookup {
|
||||||
@ -30,7 +50,7 @@ sub test_geoip_lookup {
|
|||||||
$self->qp->connection->remote_ip('24.24.24.24');
|
$self->qp->connection->remote_ip('24.24.24.24');
|
||||||
cmp_ok( $self->geoip_lookup(), '==', DECLINED, "exit code");
|
cmp_ok( $self->geoip_lookup(), '==', DECLINED, "exit code");
|
||||||
|
|
||||||
cmp_ok( $self->connection->notes('geoip_country'), 'eq', 'US', "note");
|
cmp_ok( $self->connection->notes('geoip_country'), 'eq', 'US', "24.24.24.24 is in the US");
|
||||||
};
|
};
|
||||||
|
|
||||||
sub test_geoip_load_db {
|
sub test_geoip_load_db {
|
||||||
@ -74,10 +94,10 @@ sub test_set_country_code {
|
|||||||
|
|
||||||
$self->qp->connection->remote_ip('24.24.24.24');
|
$self->qp->connection->remote_ip('24.24.24.24');
|
||||||
$cc = $self->set_country_code();
|
$cc = $self->set_country_code();
|
||||||
cmp_ok( $cc, 'eq', 'US', "$cc");
|
cmp_ok( $cc, 'eq', 'US', "set_country_code result is $cc");
|
||||||
|
|
||||||
my $note = $self->connection->notes('geoip_country');
|
my $note = $self->connection->notes('geoip_country');
|
||||||
cmp_ok( $note, 'eq', 'US', "note has: $cc");
|
cmp_ok( $note, 'eq', 'US', "set_country_code set note to $cc");
|
||||||
};
|
};
|
||||||
|
|
||||||
sub test_set_country_name {
|
sub test_set_country_name {
|
||||||
@ -144,4 +164,3 @@ sub test_set_distance {
|
|||||||
ok( 1, "no distance data");
|
ok( 1, "no distance data");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user