initial commit of file from CVS for smeserver-geoip on Sat Sep 7 20:26:07 AEST 2024

This commit is contained in:
Trevor Batley 2024-09-07 20:26:07 +10:00
parent 668d7517d0
commit ca710f1de3
25 changed files with 1033 additions and 2 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
*.rpm
*.log
*spec-20*
*.tar.gz

21
Makefile Normal file
View File

@ -0,0 +1,21 @@
# Makefile for source rpm: smeserver-geoip
# $Id: Makefile,v 1.1 2020/10/06 13:45:08 brianr Exp $
NAME := smeserver-geoip
SPECFILE = $(firstword $(wildcard *.spec))
define find-makefile-common
for d in common ../common ../../common ; do if [ -f $$d/Makefile.common ] ; then if [ -f $$d/CVS/Root -a -w $$/Makefile.common ] ; then cd $$d ; cvs -Q update ; fi ; echo "$$d/Makefile.common" ; break ; fi ; done
endef
MAKEFILE_COMMON := $(shell $(find-makefile-common))
ifeq ($(MAKEFILE_COMMON),)
# attept a checkout
define checkout-makefile-common
test -f CVS/Root && { cvs -Q -d $$(cat CVS/Root) checkout common && echo "common/Makefile.common" ; } || { echo "ERROR: I can't figure out how to checkout the 'common' module." ; exit -1 ; } >&2
endef
MAKEFILE_COMMON := $(shell $(checkout-makefile-common))
endif
include $(MAKEFILE_COMMON)

View File

@ -1,3 +1,18 @@
# smeserver-geoip
# <img src="https://www.koozali.org/images/koozali/Logo/Png/Koozali_logo_2016.png" width="25%" vertical="auto" style="vertical-align:bottom"> smeserver-geoip
SMEServer Koozali developed git repo for smeserver-geoip smecontribs
SMEServer Koozali developed git repo for smeserver-geoip smecontribs
## Wiki
<br />https://wiki.koozali.org/GeoIP
<br />https://wiki.koozali.org/Xt_geoip
<br />https://wiki.koozali.org/Qpsmtpd:ident/geoip
<br />https://wiki.koozali.org/Xt_geoip/fr
## Bugzilla
Show list of outstanding bugs: [here](https://bugs.koozali.org/buglist.cgi?component=smeserver-geoip&product=SME%20Contribs&query_format=advanced&limit=0&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&bug_status=CONFIRMED)
## Description
<br />*This description has been generated by an LLM AI system and cannot be relied on to be fully correct.*
*Once it has been checked, then this comment will be deleted*
<br />

1
contriborbase Normal file
View File

@ -0,0 +1 @@
contribs10

70
createlinks Normal file
View File

@ -0,0 +1,70 @@
#! /usr/bin/perl -w
use esmith::Build::CreateLinks qw(:all);
#--------------------------------------------------
# actions for geoip-update event
#--------------------------------------------------
#for my $event (qw(geoip-update))
#{
#templates2events("/var/service/qpsmtpd/config/badcountries", $event);
#event_link("smeserver-geopip-download-action", $event, "10");
#}
my $event = "geoip-update";
foreach (qw(
/var/service/qpsmtpd/config/badcountries
/etc/GeoIP.conf
/etc/crontab
/var/service/qpsmtpd/config/peers/0
))
{
templates2events("$_", qw(
geoip-update
smeserver-geoip-update
));
}
event_link("smeserver-geopip-download-action", $event, "10");
event_link("smeserver-geopip-download-action", 'smeserver-geoip-update', "10");
#--------------------------------------------------
# actions for email-update event
#--------------------------------------------------
#for my $event (qw(
# bootstrap-console-save
# email-update))
#{
#templates2events("/var/service/qpsmtpd/config/badcountries", $event);
#}
#my $event = "email-update";
foreach (qw(
/var/service/qpsmtpd/config/badcountries
/etc/GeoIP.conf
/etc/crontab
/var/service/qpsmtpd/config/peers/0
))
{
templates2events("$_", qw(
post-upgrade
bootstrap-console-save
console-save
email-update
));
}
event_services('smeserver-geoip-update', 'qpsmtpd' => 'restart', 'sqpsmtpd' => 'restart') ;
safe_symlink("../../plugins/18check_badcountries", "root//etc/e-smith/templates/var/service/qpsmtpd/config/peers/0/18check_badcountries");

View File

@ -0,0 +1 @@
enabled

View File

@ -0,0 +1 @@
service

View File

@ -0,0 +1 @@
enabled

View File

@ -0,0 +1,2 @@
#!/bin/bash
/usr/bin/geoipupdate

View File

@ -0,0 +1,12 @@
# The following AccountID and LicenseKey are required placeholders.
# For geoipupdate versions earlier than 2.5.0, use UserId here instead of AccountID.
#AccountID 0
AccountID { $geoip{AccountID} ||'0' }
LicenseKey { $geoip{LicenseKey} ||'000000000000'}
# Include one or more of the following edition IDs:
# * GeoLite2-City - GeoLite 2 City
# * GeoLite2-Country - GeoLite2 Country
# For geoipupdate versions earlier than 2.5.0, use ProductIds here instead of EditionIDs.
EditionIDs GeoLite2-City GeoLite2-Country
#ProductIds GeoLite2-City GeoLite2-Country

View File

@ -0,0 +1,9 @@
# The remaining settings are OPTIONAL.
# The directory to store the database files. Defaults to /usr/share/GeoIP
# DatabaseDirectory /usr/share/GeoIP
{
my $DatabaseDirectory = $geoip{DatabaseDirectory} || '/usr/share/GeoIP';
$OUT ="DatabaseDirectory $DatabaseDirectory";
}

View File

@ -0,0 +1,7 @@
# The server to use. Defaults to "updates.maxmind.com".
# Host updates.maxmind.com
{
my $GEOserver = $geoip{Host} || 'updates.maxmind.com';
$OUT ="Host $GEOserver";
}

View File

@ -0,0 +1,8 @@
# The proxy host name or IP address. You may optionally specify a
# port number, e.g., 127.0.0.1:8888. If no port number is specified, 1080
# will be used.
# Proxy 127.0.0.1:8888
# The user name and password to use with your proxy server.
# ProxyUserPassword username:password

View File

@ -0,0 +1,8 @@
# Whether to preserve modification times of files downloaded from the server.
# Defaults to "0".
# PreserveFileTimes 0
{
my $FT = $geoip{PreserveFileTimes} || '0';
$OUT ="PreserveFileTimes $FT";
}

View File

@ -0,0 +1,6 @@
# The lock file to use. This ensures only one geoipupdate process can run at a
# time.
# Note: Once created, this lockfile is not removed from the filesystem.
# Defaults to ".geoipupdate.lock" under the DatabaseDirectory.
# LockFile /usr/share/GeoIP/.geoipupdate.lock

View File

@ -0,0 +1,3 @@
# Updating the GeoIP database monthly on the 5th at 0:00h.
0 0 10 * * root /usr/bin/geoipupdate

View File

@ -0,0 +1,7 @@
{
my @badcountries = split /[,:]/, ${qpsmtpd}{BadCountries} || '';
return "# No BadCountries are defined" unless (scalar @badcountries);
return join "\n", @badcountries;
}

View File

@ -0,0 +1 @@
../../plugins/18check_badcountries

View File

@ -0,0 +1,6 @@
{
return "# geoip disabled" unless (${qpsmtpd}{GeoIP} eq "enabled");
"check_badcountries";
}

26
root/usr/bin/geocity.pl Executable file
View File

@ -0,0 +1,26 @@
#!/usr/bin/perl
use GeoIP2::Database::Reader;
# GeoLite2-City.mmdb
if ( $ARGV[0] eq '-h' || $ARGV[0] eq '-help' || $ARGV[0] eq '' ) {
help();
exit;
}
my $reader = GeoIP2::Database::Reader->new(
file => '/usr/share/GeoIP/GeoLite2-City.mmdb',
locales => [ 'en', 'de', ]
);
my $city = $reader->city( ip => $ARGV[0] );
my $city_rec = $city->city();
print "City: ", $city_rec->name(), "\n";
my $country = $city->country();
print "Country: ", $country->iso_code(), "\n";
sub help {
print "Usage: ./geoipcity.pl 1.2.3.4\n";
}

22
root/usr/bin/geocountry.pl Executable file
View File

@ -0,0 +1,22 @@
#!/usr/bin/perl
use GeoIP2::Database::Reader;
if ( $ARGV[0] eq '-h' || $ARGV[0] eq '-help' || $ARGV[0] eq '' ) {
help();
exit;
}
my $reader = GeoIP2::Database::Reader->new(
file => '/usr/share/GeoIP/GeoLite2-Country.mmdb',
locales => [ 'en', 'de', ]
);
my $country = $reader->country( ip => $ARGV[0] );
my $country_rec = $country->country();
print "Country ", $country_rec->iso_code(), "\n";
sub help {
print "Usage: ./geoipcountry.pl 1.2.3.4\n";
}

6
root/usr/bin/geoiplook Normal file
View File

@ -0,0 +1,6 @@
#!/bin/bash
for var in "$@"
do
/usr/bin/mmdblookup --file /usr/share/GeoIP/GeoLite2-Country.mmdb --ip $1 country iso_code |cut -d\" -f2| tr -d '\n'
echo ""
done

View File

@ -0,0 +1,595 @@
#!perl -w
=head1 NAME
geoip - provide geographic information about mail senders.
=head1 SYNOPSIS
Use MaxMind's GeoIP databases and the GeoIP2 or Geo::IP perl modules to report
geographic information about incoming connections.
=head1 DESCRIPTION
Save geographic information about the sender in the following connection notes:
geoip_country - 2 char country code
geoip_country_name - english name of country
geoip_continent - 2 char continent code
geoip_city - english name of city
geoip_distance - distance in kilometers
geoip_asn - network number
And adds entries like this to your logs:
(connect) ident::geoip: NA, US, United States, 1319 km
(connect) ident::geoip: AS, IN, India, 13862 km
(connect) ident::geoip: fail: no results
(connect) ident::geoip: NA, CA, Canada, 2464 km
(connect) ident::geoip: NA, US, United States, 2318 km
(connect) ident::geoip: AS, PK, Pakistan, 12578 km
(connect) ident::geoip: AS, TJ, Tajikistan, 11965 km
(connect) ident::geoip: EU, AT, Austria, 8745 km
(connect) ident::geoip: AS, IR, Iran, Islamic Republic of, 12180 km
(connect) ident::geoip: EU, BY, Belarus, 9030 km
(connect) ident::geoip: AS, CN, China, 11254 km
(connect) ident::geoip: NA, PA, Panama, 3163 km
Calculating the distance has three prerequsites:
1. The MaxMind city database (free or subscription)
2. The Math::Complex perl module
3. The IP address of this mail server (see CONFIG)
Other plugins can utilize the geographic notes to alter the
connection, reject, greylist, etc.
=head1 CONFIG
The following options can be appended in this plugins config/plugins entry.
(With the free v2 'Lite' databases you can only access Countries and Cities)
=head2 distance <IP Address>
Enables geodesic distance calculation. Will calculate the distance "as the
crow flies" from the remote mail server. Accepts a single argument, the IP
address to calculate the distance from. This will typically be the public
IP of your mail server.
ident/geoip [ distance 192.0.1.5 ]
Default: none. (no distance calculations)
=head2 too_far <distance in km>
Assign negative karma to connections further than this many km.
Default: none
=head2 db_dir </path/to/GeoIP>
The path to the GeoIP database directory.
ident/geoip [ db_dir /etc/GeoIP ]
Default: /usr/local/share/GeoIP
=head2 add_headers <true|false>
Add message headers with GeoIP data
ident/geoip [ add_headers (true|false) ]
Default: true
=head1 LIMITATIONS
The distance calculations are more concerned with being fast than accurate.
The MaxMind location data is collected from whois and is of limited accuracy.
MaxMind offers more accurate data for a fee.
For distance calculations, the earth is considered a perfect sphere. In
reality, it is not. Accuracy should be within 1%.
This plugin does not update the GeoIP databases. You may want to.
=head1 CHANGES
2019-10 - JP Pialasse - reintroduce block country functionality with geoip v1
2019-01 - John Crisp - modify to work correctly with mailstats
2019-01 - JP Pialasse - make it compatible with old v1 + improve log level
2018-06 - John Crisp - modify to work with SME server
2014-06 - Matt Simerson - added GeoIP2 support
2012-06 - Matt Simerson - added GeoIP City support, continent, distance
2012-05 - Matt Simerson - added geoip_country_name note, added tests
=head1 SEE ALSO
MaxMind: http://www.maxmind.com/
Databases: http://geolite.maxmind.com/download/geoip/database
It may become worth adding support for Geo::IPfree, which uses another
data source: http://software77.net/geo-ip/
=head1 ACKNOWLEDGEMENTS
Based on qpsmtpd ident/geoip plugin
Originally by Doug Kruhm <dakruhm@daknetworks.net>
MaxMind - the packager and distributor of the free GeoIP data
Stevan Bajic, the DSPAM author, who suggested SNARE, which describes using
geodesic distance to determine spam probability. The research paper on SNARE
can be found here:
http://smartech.gatech.edu/bitstream/handle/1853/25135/GT-CSE-08-02.pdf
=cut
use strict;
use warnings;
use Qpsmtpd::Constants;
#use GeoIP2; # eval'ed in register()
#use Geo::IP; # eval loaded if GeoIP2 doesn't
#use Math::Trig; # eval'ed in set_distance_gc
sub register {
my ($self, $qp, @args) = @_;
$self->log(LOGERROR, "Bad arguments") if @args % 2;
$self->{_args} = {@args};
$self->{_args}{db_dir} ||= '/usr/share/GeoIP';
$self->load_geoip() or return;
my $enabled = $self->{_args}{add_headers};
$enabled = 'true' if ! defined $enabled;
return if $enabled =~ /false/i;
$self->register_hook( data_post => 'add_headers' );
}
sub load_geoip {
my ( $self ) = @_;
$self->load_geoip2() and return 1;
$self->load_geoip1() and return 1; #only search v1 if v2 not available
return 0;
}
sub load_geoip1 {
my $self = shift;
eval 'use Geo::IP';
if ($@) {
warn "could not load Geo::IP";
$self->log(LOGERROR, "could not load Geo::IP");
return;
}
$self->open_geoip_db();
# Note that opening the GeoIP DB only in register has caused problems before:
# https://github.com/smtpd/qpsmtpd/commit/29ea9516806e9a8ca6519fcf987dbd684793ebdd#plugins/ident/geoip
# Opening the DB anew for every connection is horribly inefficient.
# Instead, attempt to reopen upon connect if the DB connection fails.
$self->init_my_country_code();
$self->register_hook('connect', 'geoip_lookup');
return 1;
}
sub load_geoip2 {
my $self = shift;
eval 'use GeoIP2::Database::Reader';
if ($@) {
$self->log(LOGERROR, "could not load GeoIP2");
return;
}
# warn "Using GeoIP2."
# . " ASN data is not currently available using the GeoIP2 module!\n";
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 add_headers {
my ( $self, $txn ) = @_;
for my $h (qw( Country Continent City ASN )) {
my $note = lc "geoip_$h";
next if ! $self->connection->notes($note);
$txn->header->delete("X-GeoIP-$h");
$txn->header->add( "X-GeoIP-$h", $self->connection->notes($note), 0 );
}
return DECLINED;
}
sub geoip2_lookup {
my $self = shift;
my $ip = $self->qp->connection->remote_ip;
return DECLINED if $self->is_localhost($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());
#my $city = $self->qp->connection->notes('geoip_city');
#warn ("At City: $city");
# 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());
#my $country = $country_rec->country->iso_code();
#warn ("At country: $country");
};
}
# City Information in case we want to play later
my $city = $self->qp->connection->notes('geoip_city') // '';
#warn ("At City (check): $city");
$self->log(LOGNOTICE, "GeoIP RemoteIP: $ip");
if ($city eq '') {
$self->log(LOGNOTICE, "GeoIP City: NA");
}
else {
$self->log(LOGNOTICE, "GeoIP City: $city");
}
my $country = $self->qp->connection->notes('geoip_country');
# Returns DECLINED if there are no countries found above
return DECLINED unless $country;
$self->log(LOGNOTICE, "GeoIP Country: $country");
if ( $self->qp->config("badcountries") ) {
my @badcountries = $self->qp->config("badcountries");
for (@badcountries) {
my ($pattern, $response) = split /\s+/, $_, 2;
#my $whitelisthost = $connection->notes('whitelisthost');
my $whitelisthost = $self->qp->connection->notes('whitelisthost');
if ($whitelisthost) {
$self->log(LOGNOTICE, "Country $country Pattern $pattern Whitehost $whitelisthost RemoteIP $ip");
$self->log(LOGNOTICE, "Geoip whitelisthost found $whitelisthost");
return OK;
}
else {
return (DENY, "Country is on Blocked List") if ($country eq $pattern);
}
}
}
return DECLINED;
}
sub geoip_lookup {
my $self = shift;
my $ip = $self->qp->connection->remote_ip;
return DECLINED if $self->is_localhost($ip);
# reopen the DB if Geo::IP failed due to DB update
$self->open_geoip_db();
my $c_code = $self->set_country_code() or do {
$self->log(LOGINFO, "skip, no results");
return DECLINED;
};
$self->set_asn();
my $c_name = $self->set_country_name();
my ($city, $continent_code, $distance) = '';
if ($self->{_my_country_code}) {
$continent_code = $self->set_continent($c_code);
$city = $self->set_city_gc();
$distance = $self->set_distance_gc();
}
my @msg_parts;
if ($continent_code && $continent_code ne '--') {
push @msg_parts, $continent_code;
};
push @msg_parts, $c_code if $c_code;
#push @msg_parts, $c_name if $c_name;
push @msg_parts, $city if $city;
if ($distance) {
push @msg_parts, "\t$distance km";
if ($self->{_args}{too_far} && $distance > $self->{_args}{too_far}) {
$self->adjust_karma(-1);
}
}
$self->log(LOGINFO, join(", ", @msg_parts));
my $country = $self->qp->connection->notes('geoip_country');
# Returns DECLINED if there are no countries found above
return DECLINED unless $country;
$self->log(LOGNOTICE, "GeoIP Country: $country");
if ( $self->qp->config("badcountries") ) {
my @badcountries = $self->qp->config("badcountries");
for (@badcountries) {
my ($pattern, $response) = split /\s+/, $_, 2;
#my $whitelisthost = $connection->notes('whitelisthost');
my $whitelisthost = $self->qp->connection->notes('whitelisthost');
if ($whitelisthost) {
$self->log(LOGNOTICE, "Country $country Pattern $pattern Whitehost $whitelisthost RemoteIP $ip");
$self->log(LOGNOTICE, "Geoip whitelisthost found $whitelisthost");
return OK;
}
else {
return (DENY, "Country is on Blocked List") if ($country eq $pattern);
}
}
}
return DECLINED;
}
sub open_geoip_db {
my $self = shift;
# this might detect if the DB connection failed. If not, this is where
# to add more code to do it.
return if (defined $self->{_geoip_city} || defined $self->{_geoip});
# The methods for using GeoIP work differently for the City vs Country DB
# save the handles in different locations
my $db_dir = $self->{_args}{db_dir};
foreach my $db (qw/ GeoIPCity GeoLiteCity /) {
next if !-f "$db_dir/$db.dat";
$self->log(LOGDEBUG, "using db $db");
$self->{_geoip_city} = Geo::IP->open("$db_dir/$db.dat");
last if $self->{_geoip_city};
}
warn "Missing GeoIP City data!\n" if ! $self->{_geoip_city};
if (-f "$db_dir/GeoIPASNum.dat") {
$self->log(LOGDEBUG, "using GeoIPASNum");
$self->{GeoIPASNum} = Geo::IP->open("$db_dir/GeoIPASNum.dat");
}
warn "Missing GeoIP ASN data!\n" if ! $self->{GeoIPASNum};
if (-f "$db_dir/GeoIPASNumv6.dat") {
$self->log(LOGDEBUG, "using GeoIPASNumv6");
$self->{GeoIPASNumv6} = Geo::IP->open("$db_dir/GeoIPASNumv6.dat");
warn "Missing GeoIP ASN IPV6 data!\n" if ! $self->{GeoIPASNum};
}
# can't think of a good reason to load country if city data is present
if (!$self->{_geoip_city}) {
$self->log(LOGDEBUG, "using default db");
eval { $self->{_geoip} = Geo::IP->new(); }; # loads default Country DB
if (!$self->{_geoip}) {
my $err = $@ || 'Unknown error';
warn "Missing GeoIP Country data:$err\n";
}
}
}
sub init_my_country_code {
my $self = shift;
my $ip = $self->{_args}{distance} or return;
$self->{_my_country_code} = $self->get_country_code($ip);
}
sub set_country_code {
my $self = shift;
my $ip = $self->qp->connection->remote_ip;
my $code = $self->get_country_code($ip) or return;
$self->qp->connection->notes('geoip_country', $code);
return $code;
}
sub get_country_code {
my $self = shift;
my $ip = shift || $self->qp->connection->remote_ip;
if ($self->{_geoip_city}) {
return $self->get_country_code_gc($ip);
}
if ($self->{_geoip}) {
return $self->{_geoip}->country_code_by_addr($ip);
}
return undef;
}
sub get_country_code_gc {
my $self = shift;
my $ip = shift || $self->qp->connection->remote_ip;
$self->{_geoip_record} = $self->{_geoip_city}->record_by_addr($ip)
or return;
return $self->{_geoip_record}->country_code;
}
sub set_country_name {
my $self = shift;
my $ip = $self->qp->connection->remote_ip;
my $name = $self->get_country_name($ip) or return;
$self->qp->connection->notes('geoip_country_name', $name);
return $name;
}
sub get_country_name {
my $self = shift;
my $ip = shift || $self->qp->connection->remote_ip;
if ($self->{_geoip_city}) {
return $self->get_country_name_gc($ip);
}
if ($self->{_geoip}) {
return $self->{_geoip}->country_name_by_addr($ip);
}
return undef;
}
sub get_country_name_gc {
my $self = shift;
return if !$self->{_geoip_record};
return $self->{_geoip_record}->country_name();
}
sub set_continent {
my ($self, $country_code) = @_;
return if !$country_code;
my $continent = $self->get_continent($country_code) or return;
$self->qp->connection->notes('geoip_continent', $continent);
return $continent;
}
sub get_continent {
my ($self, $country_code) = @_;
return if !$country_code;
if ($self->{_geoip_city}) {
return $self->get_continent_gc();
}
if ($self->{_geoip}) {
return $self->{_geoip}->continent_code_by_country_code($country_code);
}
return undef;
}
sub get_continent_gc {
my $self = shift;
return if !$self->{_geoip_record};
return $self->{_geoip_record}->continent_code();
}
sub set_asn {
my ($self, $ip) = @_;
$ip ||= $self->qp->connection->remote_ip;
if ($self->is_ipv6($ip)) {
return $self->set_asn_ipv6($ip);
}
return if ! $self->{GeoIPASNum};
return if ! $self->{GeoIPASNum}->can('name_by_addr');# prior Geo-IP 1.39 should use org_by_addr
my $asn = $self->{GeoIPASNum}->name_by_addr($ip) or return;
if ('AS' eq substr($asn, 0, 2)) {
$asn = substr($asn, 2);
}
$self->qp->connection->notes('geoip_asn', $asn);
return $asn;
}
sub set_asn_ipv6 {
my ($self, $ip) = @_;
$ip ||= $self->qp->connection->remote_ip;
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 {
my $self = shift;
return if !$self->{_geoip_record};
my $city = $self->{_geoip_record}->city() or return;
$self->qp->connection->notes('geoip_city', $city);
return $city;
}
sub set_distance_gc {
my $self = shift;
return if !$self->{_geoip_record};
my ($self_lat, $self_lon) = $self->get_my_lat_lon() or return;
my ($sender_lat, $sender_lon) = $self->get_sender_lat_lon() or return;
eval 'use Math::Trig qw(great_circle_distance deg2rad)';
if ($@) {
$self->log(LOGERROR,
"can't calculate distance, Math::Trig not installed");
return;
}
# Notice the 90 - latitude: phi zero is at the North Pole.
sub NESW { deg2rad($_[0]), deg2rad(90 - $_[1]) }
my @me = NESW($self_lon, $self_lat);
my @sender = NESW($sender_lon, $sender_lat);
my $km = great_circle_distance(@me, @sender, 6378);
$km = sprintf("%.0f", $km);
$self->qp->connection->notes('geoip_distance', $km);
#$self->log( LOGINFO, "distance $km km");
return $km;
}
sub get_my_lat_lon {
my $self = shift;
return if !$self->{_geoip_city};
if ($self->{_latitude} && $self->{_longitude}) {
return $self->{_latitude}, $self->{_longitude}; # cached
}
my $ip = $self->{_args}{distance} or return;
my $record = $self->{_geoip_city}->record_by_addr($ip) or do {
$self->log(LOGERROR, "no record for my Geo::IP location");
return;
};
$self->{_latitude} = $record->latitude();
$self->{_longitude} = $record->longitude();
if (!$self->{_latitude} || !$self->{_longitude}) {
$self->log(LOGNOTICE, "could not get my lat/lon");
}
return $self->{_latitude}, $self->{_longitude};
}
sub get_sender_lat_lon {
my $self = shift;
my $lat = $self->{_geoip_record}->latitude();
my $lon = $self->{_geoip_record}->longitude();
if (!$lat || !$lon) {
$self->log(LOGNOTICE, "could not get sender lat/lon");
return;
}
return $lat, $lon;
}

198
smeserver-geoip.spec Normal file
View File

@ -0,0 +1,198 @@
%define name smeserver-geoip
%define version 1.2
%define release 19
Summary: SME Server geoip plugin
Name: %{name}
Version: %{version}
Release: %{release}%{?dist}
License: GPL
Group: Email
Source: %{name}-%{version}.tar.xz
Packager: Doug Kruhm <dakruhm@daknetworks.net>
BuildRoot: /var/tmp/%{name}-%{version}-%{release}-buildroot
BuildArchitectures: noarch
Requires: perl-GeoIP2
Requires: libmaxminddb >= 1.1.1
Requires: libmaxminddb-devel >= 1.1.1
Requires: geoipupdate
Requires: geolite2-country
Requires: geolite2-city
# for legacy
Requires: perl-Geo-IP
Requires: GeoIP >= 1.6.5
#
Provides: smeserver-geoip2 = %{version}-%{release}
PRovides: smeserver-geoip-legacy = %{version}-%{release}
BuildRequires: e-smith-devtools >= 1.13.1-03
%description
The GEOIP plugin lets us know which country our mail server is receiving mail from. If we're receiving too much spam from a particular country, this will help track it down and then use that info to reject connections from that country. This ends up taking the load off our servers.
CHANGE THE CONFIG DB: config setprop qpsmtpd BadCountries <countrycode> (i.e. config setprop qpsmtpd BadCountries BR)
SIGNAL EVENT: signal-event email-update
#----------------------------------------------------
#%package -n smeserver-geoip-legacy
#Summary: SME Server geoip plugin v1
#Group: Email
#Requires: perl-Geo-IP
#Requires: GeoIP >= 1.6.5
#Requires: smeserver-geoip = %{version}-%{release}
#BuildRequires: e-smith-devtools >= 1.13.1-03
#%description -n smeserver-geoip-legacy
#Package to use the legacy plugin. DB are not updated since 2018
#The GEOIP plugin lets us know which country our mail server is receiving mail from. If we're receiving too much spam from a particular country, this will help track it down and then use that info to reject connections from that country. This ends up taking the load off our servers.
#----------------------------------------------------
%changelog
* Sat Sep 07 2024 cvs2git.sh aka Brian Read <brianr@koozali.org> 1.2-19.sme
- Roll up patches and move to git repo [SME: 12338]
* Sat Sep 07 2024 BogusDateBot
- Eliminated rpmbuild "bogus date" warnings due to inconsistent weekday,
by assuming the date is correct and changing the weekday.
Thu Jun 16 2007 --> Thu Jun 14 2007 or Sat Jun 16 2007 or Thu Jun 21 2007 or ....
* Thu Mar 18 2021 Brian Read <brianr@bjsystems.co.uk> 1.2-18.sme
- Add expand template for the qpsmtpd peers [SME: 11023]
* Sun Mar 14 2021 Jean-Philippe Pialasse <tests@pialasse.com> 1.2-17.sme
- merge legacy with main as we have few packages still using legacy [SME: 11023]
those are php*-pecl-geoip proftpd bind-libs* bind-utils.
* Sat Mar 13 2021 Jean-Philipe Pialasse <tests@pialasse.com> 1.2-16.sme
- rebuild for SME10 [SME: 11023]
make geoip2 default
create geoip-legacy package with old geoip1 stuffs
smeserver-geoip(-legacy)-update events
* Tue Oct 06 2020 Brian Read <brianr@bjsystems.co.uk> 1.2-15.sme
- Import to SME10 tree [SME: 11023]
* Wed Jan 22 2020 John Crisp <jcrisp@safeandsoundit.co.uk> 1.2-14.sme
- Change template from EditionID to ProductID
- fix 20databasestore has a trailing tilde
* Tue Jan 21 2020 Jean-Philipe Pialasse <tests@pialasse.com> 1.2-13.sme
- add support for mmdblookup [SME: 10740]
- add support for download with AccountID and LicenseKey [SME: 10859]
* Sun Oct 20 2019 Jean-Philipe Pialasse <tests@pialasse.com> 1.2-10.sme
- fix country not logged if no badcountries defined [SME: 10815]
* Fri Oct 18 2019 Jean-Philipe Pialasse <tests@pialasse.com> 1.2-9.sme
- revert blocking country for geoipv1 qpsmtpd plugin [SME: 10820]
* Thu Jan 24 2019 Jean-Philipe Pialasse <tests@pialasse.com> 1.2-8.sme
- make smeserver-geoip2 requires smeserver-geoip [SME: 10691]
this will avoid having both packages sharing few files.
* Tue Jan 15 2019 John Crisp <jcrisp@safeandsoundit.co.uk> 1.2-7.sme
- Update check_badcountries to work with mailstats
* Sat Jan 05 2019 Jean-Philipe Pialasse <tests@pialasse.com> 1.2-6.sme
- remove crontab fragment for v1 [SME: 10691]
* Sat Jan 05 2019 Jean-Philipe Pialasse <tests@pialasse.com> 1.2-5.sme
- fix wrong loglevel LOGINFO instead of LOGNOTICE needed [SME: 10679]
- try first db v2 and back on v1 if not available [SME: 10691]
- workaround FATAL PLUGIN ERROR when method name_by_addr not existing priori geo-ip 1.39 [SME: 10691]
* Fri Jan 04 2019 Jean-Philipe Pialasse <tests@pialasse.com> 1.2-4.sme
- split smeserver-geoip into smeserver-geoip and smeserver-geoip2 for compatibility [SME: 10691]
- TODO: workaround to find for plugin compatibility
* Mon Oct 29 2018 John Crisp <jcrisp@safeandsoundit.co.uk> 1.2-3.sme
- Fix Use of uninitialized value $city in string eq
- Fix createlinks geoip-update action
* Sat Jun 23 2018 John Crisp <jcrisp@safeandsoundit.co.uk> 1.2-2.sme
- Fix typo in createlinks
* Tue Jun 12 2018 John Crisp <jcrisp@safeandsoundit.co.uk> 1.2-1.sme
- Update to latest v2 DBs [SME: 9033]
- add geocity.pl and geocountry.pl test files
* Wed Feb 15 2017 Jean-Philipe Pialasse <tests@pialasse.com> 1.1.2-7.sme
- update requirement for GeoIP 1.6.5 [SME: 9714]
* Thu Dec 22 2016 John Crisp <jcrisp@safeandsoundit.co.uk> 1.1.2-6
- Use newer versions of GeoIP databases [SME: 9714]
* Wed Sep 23 2015 John Crisp <jcrisp@safeandsoundit.co.uk> 1.1.2-5
- Add ability to whitelist an IP [SME:8981]
* Tue Sep 22 2015 stephane de Labrusse <stephdl@de-labrusse.fr> 1.1.2-4
- the event geoip-update download the geoip database
- added smeserver-geoip-1.1.2.geoip-update-event.patch
* Sun Jun 14 2015 stephane de Labrusse <stephdl@de-labrusse.fr> 1.1.2-2
- added createlinks
- added actions and crontab to download geoip database
* Mon Sep 03 2012 Doug Kruhm <dakruhm@daknetworks.net> 1.0.5
- defining $country to reduce noise if not found [SME: 5011]
- fixed misspelling in response if country is blocked [SME: 7058]
- cleaning up versioning to MAJOR-MINOR-PATCH
* Fri May 01 2009 Doug Kruhm <dakruhm@daknetworks.net> 1.0.0-04
- added response to connecting server if blocked [SME: 5011]
* Fri May 01 2009 Doug Kruhm <dakruhm@daknetworks.net> 1.0.0-03
- added line to reduce log noise [SME: 5011]
* Fri May 01 2009 Doug Kruhm <dakruhm@daknetworks.net> 1.0.0-02
- db defaults migrated from SPEC file to rpm files [SME: 5193]
- removed %post and %postun macros [SME: 5194]
- added Requires perl-Geo-IP [SME: 1866]
- added e-smith-devtools as a requirement [SME: 1866]
* Sat Jun 16 2007 Doug Kruhm <dakruhm@daknetworks.net>
Thu Jun 16 2007 --> Thu Jun 14 2007 or Sat Jun 16 2007 or Thu Jun 21 2007 or ....
- 1.0.0-01
- Original version
%prep
%setup
rm -rf root/var/
# commented for legacy
#mkdir -p root/etc/e-smith/events/smeserver-geoip-legacy
%build
perl createlinks
%install
rm -rf $RPM_BUILD_ROOT
(cd root ; find . -depth -print | cpio -dump $RPM_BUILD_ROOT)
rm -f %{name}-%{version}-filelist
/sbin/e-smith/genfilelist $RPM_BUILD_ROOT \
--file /usr/bin/geoiplook 'attr(0755,root,root)' \
> %{name}-%{version}-filelist
cat %{name}-%{version}-filelist \
|grep -v 'etc/e-smith/events/smeserver-geoip-legacy' \
> %{name}-%{version}-filelist-base
#cat %{name}-%{version}-filelist \
#|grep 'etc/e-smith/events/smeserver-geoip-legacy' \
#> %{name}-%{version}-filelist-legacy
%clean
rm -rf $RPM_BUILD_ROOT
%post
%postun
%files -f %{name}-%{version}-filelist-base
%defattr(-,root,root)
#%files -n smeserver-geoip-legacy -f %{name}-%{version}-filelist-legacy
#%defattr(-,root,root,-)