Procmail und GeoIP

Wie man mit Hilfe von Perl und GeoIP Exim4 einen Header in Emails einfügen kann, der den CountryCode des Servers enthält, von dem wir die jeweilige Email zugestellt bekommen haben, ist in "Exim4 und GeoIP" beschrieben. Wer keinen Zugang zur Serverkonfiguration hat, kann sich z.B. mit Procmail behelfen.

Dass Procmail ein mächtiges Werkzeug ist, dürfte allgemein bekannt sein. Viele von uns benutzen es zum Filtern von Emails, als Auto-Responder, um Emails auf schädliche Inhalte oder Spam zu untersuchen.

Ein typisches Rezept um die Email an Spamassassin weiterzureichen sieht wohl so aus:

:0fw

* !\^X-Spam-Flag:.*YES.*
| /usr/bin/spamc -U /var/run/spamd

Die Email wird mit dem Flag "f" durch spamassassin hindurchgeschliffen, das Ergebnis an die folgenden Rezepte weitergereicht. Genauso können wir das mit unserem GeoIP-Scanner schicken:

# X-Received-From-Country-Code

:0fw
| $HOME/bin/procmail_geoip.pl

Brauchen wir noch das die eigentliche Arbeit verrichtende Skript "bin/procmail_geoip.pl":

#!/usr/bin/perl

use Mail::Internet;
use Mail::Header;
use Geo::IP;

# primary\_hostname
my $hostname = "mein.host.tld";

my $mail = new Mail::Internet \*STDIN;
my $head = mail->head;\
my $gi = Geo::IP->new(GEOIP_STANDARD);
my $ip;

if ($ip = &get_last_received) {
       
$mail->add("X-Received-From-Country-Code",&get_country_code_by_ip);
}
$mail->print( \*STDOUT );

sub get_last_received {
        local $rcvd = "";
        for (my $i=0;$i<$head->count("Received:");$i++) {
                $rcvd = $head->get("Received:", $i);
                 return $1 if $rcvd =~ /[((\d{1,3}\.){3}\d{1,3})]\)\s+by $hostname/sm;
        }
        return 0;
}

sub get_country_code_by_ip {
        local $country = $gi->country_code_by_addr($ip);
        $country = "--" unless $country;
        return $country;
}

Bingo! Das war's.

Was haben wir gemacht? Wir haben 3 CPAN-Module [1,2,3] geladen, den Standardinput in ein Mail::Internet-Object geladen, eine Referenz auf die Header erstellt, mit dieser Referenz alle Received-Header darauf geprüft, ob sie eine Zeichenkette enthalten, von der wir wissen, dass sie beim Emaileingang von unserem Mailserver geschrieben wurde und die die IP-Adresse des sendenden Mailservers enthält. Dieser Mailserver ist nicht zwangsläufig auch der, den der Absender benutzt hat, aber er ist der einzige, bei dem wir uns darauf verlassen können, dass er damit beschäftigt war, die Email an uns weiterzureichen. Alle anderen Received-Header können frei erfunden, gefälscht sein.

Haben wir die IP-Adresse, können wir mit Geo::IP aus dem CPAN-Archiv den CountryCode aus Maxmind's GeoIP-Datenbank [4] auslesen. Falls die IP-Adresse nicht in der Datenbank enthalten ist, nehmen wir einfach "--".

Schließlich fügen wir nur noch den X-Header "X-Received-From-Country-Code" in die Email ein und geben das ganze auf den Standardoutput aus, den Procmail gleich wieder einliest.
So bearbeitete Email haben dann einen solchen Header:

Den kann man nun wieder mit Spamassassin oder seinem MUA auswerten.

Viel Spaß.


[1] http://search.cpan.org/~markov/MailTools-1.77/Mail/Internet.pm
[2] http://search.cpan.org/~markov/MailTools-1.77/Mail/Header.pm
[3] http://search.cpan.org/~tjmather/Geo-IP-1.28/lib/Geo/IP.pm
[4] http://www.maxmind.com/app/geolitecountry
[5] http://www.procmail.org/
[6] http://spamassassin.apache.org/

Referenz(en)