Exim4 und GeoIP

In letzter Zeit bekomme ich Unmengen an Emails aus Japan und Israel, soweit ich das überblicken kann Porno- und Kontaktmarkt-Spam. Dies brachte mich auf den Gedanken, mal zu schauen, woher mich Email so erreicht.

Den erste Gedanke, einfach die Toplevel-Domains auszuwerten, verwarf ich sofort wieder: zu ungenau. Also muss die IP-Adresse herhalten, in diesem Beispiel die des letzten Mailservers vor dem meinigen, alles andere könnte gefälscht sein.

Um das Ganze ordentlich filtern und auswerten zu können, soll mir mein Mailserver in jede nicht lokal erzeugte Email einen Header einfügen, der das Länderkürzel des zustellenden Mailservers enthält.

Nichts leichter als das. In Exim4 kann man Perl-Code einbetten bzw. eine externe Perl-Funktions-Bibliothek:

# /etc/exim4/exim4.conf
# MAIN CONFIGURATION
SETTINGS
...
perl_startup = do '/usr/local/lib/exim4/exim4_geoiplookup.pm'
...

Nun stehen uns alle in /usr/local/lib/exim4/exim4_geoiplookup.pm definierten Funktionen direkt in der exim4.conf zur Vefügung. Machen wir davon Gebrauch und fügen den Header ein:

# /etc/exim4/exim4.conf
# ACL CONFIGURATION
begin acl
...
acl_whitelist_local_deny:
...
  warn message = X-SenderHostCountry: ${perl{geoip_lookup_address}{$sender_host_address}}

acl_check_rcpt:
...

Was wir gerade getan haben, ist folgendes: wir fügen in die Email einen Header namens “X-SenderHostCountry” ein. Den Content des Headers bekommen wir aus der Funktion “geoip_lookup_address”, die wir noch in unserem Skript definieren müssen. Einziger Parameter der Funktion ist eine IP-Adresse, in diesem Fall die des sendenden Mailservers, von Exim in $sender_host_address gespeichert. Diese Funktion ist schnell erstellt, gebraucht werden nur das CPAN-Modul Geo::IP und natürlich die GeoIP-Datenbank von Maxmind:

#!/usr/bin/perl
#/usr/local/lib/exim4/exim4_geoiplookup.pm

use Geo::IP;
my $gi = Geo::IP->new(GEOIP_STANDARD);

# lookup sender host address:
#
# ${perl{geoip_lookup_address}{$sender_host_address}}
#
sub geoip_lookup_address {
  local $ip = shift;
  local $country = $gi->country_code_by_addr($ip);
  return $country ? $country : "--";
}

Das Geo::IP-Object erstellen wir nur einmal, es ist sehr teuer. Der eigentliche Lookup ist dafür um so schneller. Für den Fall, daß GeoIP die IP-Adresse nicht zuordnen kann, geben wir “–” zurück.
Nach dem Neustart des Mailservers werden alle eingehenden Emails mit dem “X-SenderHostCountry” versehen, die Sortierung in extra Verzeichnisse etc. überlassen wir getrost den MUAs, meinetwegen auch Procmail und Konsorten. Mal schauen, ob ich jemals Post aus Israel bekomme, die kein Spam ist.

Wie das gleiche ohne Zugriff auf den Mailserver zu bewerkstelligen ist, zeigt “Procmail und GeoIP”.

[0] http://www.exim4.org
[1] http://www.maxmind.com
[2] http://search.cpan.org/~tjmather/Geo-IP-1.28/

Referenz(en)