Warum?

Jeder der einen eMail- Account hat wird früher oder später in den zweifelhaften Genuß von Werbebotschaften kommen, die ihm kleine Pillchen extrem günstig anbieten oder Offerten nach dem Motto "gib mir heute einen Euro und Du bekommst morgen 100.000 zurück" machen.
Auch wer länger Online ist und mal beobachtet wer so alles auf Port 25 anklopft um dort einen potentiellen Mailserver zu erreichen wird staunen.
Das Volumen dieser Nachrichten nimmt von Jahr zu Jahr zu. Um hier wenigstens einen kleinen Beitrag zu leisten dies einzudämmen betreibe ich an meinem meist eh ungenutzten Linuxrechner eine kleine "Fußangel".
Das Ganze basiert auf einer modifizierten Version der Perl- basierten Version von SMTarPit von Paul Grosse. Die Modifikation besteht darin, daß SMTarPit nun in eine MySQL-Datenbank protokolliert und es somit sehr einfach ist Auswertungen zu erstellen oder auch die Daten für Blacklists zu verwenden.

Vorbereitungen

Die Erweiterungen zur Protokollierung verwenden die Perlmodule
Net::DNS und
DBD::mysql Um diese Module, sofern nicht bereits vorhanden, zu installieren genügt ein Aufruf von "perl -MCPAN -e shell". Dieser wirft uns in eine "cpan shell", in der es einfachst möglich ist neue Module zu installieren. Um die beiden o.g. Module dem System hinzuzufügen reichen folgende beiden Befehle:  
install Net::DNS
install DBD::mysql
  Benötigte zusätzliche Pakete, wie z.B. DBI werden nach Rückfrage normalerweise selbständig mitinstalliert. Nachdem nun die Voraussetzungen für Perl geschaffen sind muß noch smtarpit selbst installiert werden. Die Quellen hierzu gibt es auf der Homepage des Projektes. Ist auch das erledigt muß das Programm erstmal konfiguriert werden. Dies geschieht im Script selbst und ist selbsterklärend.
Hierauf kann ein erster Start erfolgen. Eine Verbindung auf den konfigurierten Port (bei mir 2525) sollte eine Reaktion wie bei einem echten Mailserver hervorrufen:  
# telnet 192.168.1.1 2525
Trying 192.168.1.1...
Connected to 192.168.1.1.
Escape character is '^]'.
220 smtp.neon.foo.com Sendmail 8.12.7/8.12.7; ready
  Der Serverstring der zurückkommt wird aus einem im Script definierten Pool zufällig ausgewählt und kann frei definiert werden. Hierzu existieren die Variablen @srvdom und @srvtype. Die entsprechende Linkliste ist in @linklist definiert. Das System ist nun erstmal betriebsbereit, allerdings noch nicht von Außen zu erreichen. Dies machen wir erst im letzten Schritt- wir wollen ja nichts verpassen.

Die Datenbank

Bei mir kommt MySQL zu Einsatz.
Für die Protokollierung müssen zuerst mal eine Datenbank und dann noch zwei Tabellen angelegt werden. Das Schema sieht wie folgt aus:  
CREATE DATABASE smtarpit;
   
CREATE TABLE IF NOT EXISTS connects (
  tstamp int(10) default NULL,
  ip char(15) collate latin1_german1_ci NOT NULL,
  duration int(6) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_german1_ci;
   
CREATE TABLE IF NOT EXISTS hosts (
  ip char(15) collate latin1_german1_ci NOT NULL,
  hostname char(254) collate latin1_german1_ci NOT NULL,
  connect int(11) NOT NULL,
  last timestamp NULL default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_german1_ci;
  Auf Indizes habe ich im Schema bewusst verzichtet, da diese angepasst für den jeweiligen Anwendungsfall erstellt werden sollten. Zum Schreiben in die Tabelle sind Indizes erstmal nicht nötig. Um es nun einem Benutzer smtarpit zu ermöglichen mit dem Kennwort smtarpitpwd darauf zuzugreifen sind noch folgende Kommandos notwendig:  
CREATE USER 'smtarpit'@'localhost' IDENTIFIED BY 'smtarpitpwd';

GRANT USAGE ON * . * TO 'smtarpit'@'localhost' IDENTIFIED BY 'smtarpitpwd'
WITH MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0
MAX_USER_CONNECTIONS 0 ;
GRANT SELECT , INSERT , UPDATE , DELETE , EXECUTE ON `smtarpit` . * TO 'smtarpit'@'localhost';
FLUSH PRIVILEGES;
  connects
In diese Tabelle wandert jede einzelne erfolgreiche Verbindung zur Teergrube. Im Feld "tstamp" befindet sich der Unix-Timestamp als die Verbindung geschlossen wurde. In "ip" wird die IP der Gegenstelle aufgezeichnet. "duration" hält die Verbindungsdauer in Sekunden vor. hosts
In dieser Tabelle erfolgt das Zusammenfassen (Verdichten) der Daten. "ip" ist die IP-Adresse und bildet in gewissem Sinne den Primärschlüssel. "hostname" ist der Reverse- Eintrag zur IP-Adresse, den uns die Net::DNS Bibliothek geliefert hat. In "connect" wird die Anzahl der Verbindungen von der jeweiligen IP-Adresse aufsummiert. "last" ist der Zeitstempel wann die jeweilige IP das letzte Mal mit dem System verbunden war. Durch dieses Feld läßt sich ein "Garbage-Collect" einfach realisieren.

Änderungen an SMTarPit

Die Änderungen am Programm selbst beziehen sich alle auf die Funktion "done". Hierzu einfach im Script nach 'sub done' suchen und nach der Zeile 'close (SMTPLOG);' folgenden Block einfügen:  
use DBI;
my $dbh = DBI->connect("dbi:mysql:smtarpit:localhost", "smtarpit", "smtarpitpwd",
{RaiseError => 0, PrintError => 0} )
or die("Cannot connect to the database:: $DBI::errstr");
### insert data of single connect ###
$sql = "INSERT INTO connects (tstamp,ip,duration) VALUES ($f_time, '$rhost', $delta_t);";
$dbh->do($sql);
### update or insert summary data for hosts ###
$sql = "SELECT * FROM hosts WHERE ip = '$rhost';";
  if ( $dbh -> do($sql) == 0 ) {
    # record does not exist so insert a new one
    # first of all resolve hostname
    use Net::DNS;
    my $res = new Net::DNS::Resolver;
    my $query = $res -> search ($rhost);
    if ($query) {
      foreach my $rr ($query->answer) {
        next unless $rr->type eq "PTR";
       $hostname = $rr->rdatastr;
      }
    }
    else {
      $hostname = "NA";
    }
    $sql = "INSERT INTO hosts (ip, hostname, connect, last) VALUES ('$rhost', '$hostname', 1, NOW())";
    $dbh -> do($sql);
  }
  else {
    # record with ip already exists so update counter
    $sql = "UPDATE hosts SET connect=connect+1, last=NOW() WHERE ip = '$rhost'";
    $dbh -> do($sql);
  }
  $dbh->disconnect();
  Sind diese Änderungen erfolgt, so kann das originale nun gegen das modifizierte Script ausgetauscht werden. Ein Test mittels eines Telnet auf den konfigurierten Port (siehe oben) sollte nach einem QUIT, und etwas Wartezeit- schließlich ist es eine Teergrube ;-) - Einträge in den beiden Datenbanktabellen hinterlassen.

Firewallregel

Unser System bekommt nun noch keinerlei Daten von Außen. Um das zu ändern muß in der jeweiligen Firewall ein sogenanntes Port- Forwarding eingerichtet werden. In meinem Fall sollen alle Pakete, die von Außen an Port 25 der Firewall ankommen auf den Port 2525 meines Linux-Systems umgebogen werden. In IPTables sieht das in etwa so aus:  
iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 25 -j REDIRECT --to-port 2525
  eth1 ist hierbei das Interface an dem das böse böse Internet angeschlossen ist.

Wohin mit den Daten?

Da die Teergrube ja derzeit nur Müll abbekommt und keine echten Mails, sind die gesammelten Daten meines Erachtens ideal um damit zum Beispiel eine Blacklist in einem MySQL- basierten Postfix- System zu füttern. Das Stichwort hierzu lautet access_client. Das Füllen der Tabelle, bzw. das Aufräumen kann entweder durch kleine externe Helferscripte erfolgen, oder aber direkt durch Trigger in der Datenbank- jeder nach seinem Gusto.