Milter-Filter nach Empfänger für sendmail
Problemstellung
Sobald Netzwerke über mehrere Mail-Server bzw Rechner, die Mails akzeptieren, verfügen, existiert das Problem, dass nicht jeder Server darüber Kenntnis hat, ob eine bestimmte Mail-Adresse existiert. Eine gängige Konfiguration sieht vor, dass es einen zentralen Mail-Server gibt, der von ausserhalb des Netzwerkes, also meist vom Internet aus, erreichbar ist. Auf diesem werden die Filterungen nach Viren und Spam durchgeführt und dann werden die Mails an die entsprechenden Rechner innerhalb des Netzwerkes weitergeleitet. Der zentrale Mail-Server leitet die Mails weiter, wenn es ihm möglich ist die Domaine und/oder den Zielhost zu erreichen. An dieser Stelle ist es irrelevant und nicht überprüfbar, ob der spezifische Nutzer, an den die Mail adressiert ist, überhaupt existiert. Sollte der Nutzer nicht existieren, wird die Mail verworfen bzw eine Antwort-Mail mit dem Inhalt, dass die Adresse nicht existiert, zurückgesendet, sobald die Mail den Zielrechner erreicht. Das eigentliche Problem besteht darin, dass aufwendige Verfahren, wie z.B. Virenfilter, bereits durchgeführt wurden und den zentralen Mail-Server unnötig belastet haben. Um diesem Problem entgegenzuwirken, sollten fehlerhaft adressierte Mails bzw generierte Spam-Mails schon vom zentralen Mail-Server aussortiert werden.
Lösungsansätze
Zur Lösung des zuvor beschriebenen Problems gibt es 2 Lösungsansätze.
Lösung 1
Der zentrale Mail-Server befragt bei jeder eingehenden Mail den Zielhost, ob der adressierte Benutzer auf diesem existiert.
Vorteile:
Kein zusätzlicher Administrationsaufwand
Änderungen am Nutzerstamm werden sofort bemerkt
Nebeneffekt: Nichterreichbarkeit von Servern wird bemerkt
Nachteile:
Verzögerung der Abarbeitung der Mail (Netzwerklast, Last des sek. Servers, DNS-Abfrage, usw)
Lösung 2
Der zentrale Mail-Server befragt eine Datenbank, in der die existierende Nutzer mit den dazugehörigen Hosts und Subdomains gespeichert sind.
Vorteile:
Höhere Geschwindigkeit, vor allem wenn die DB lokal verfügbar ist
Autark von sekundären Servern
Keine Netzwerklast
Nachteile:
Erhöhter Administrationsaufwand
Entscheidung
Da die Performance im Vordergrund steht und der zusätzliche Administrationsaufwand im Verhältnis gering ausfällt, da der Nutzerstamm sich in den meisten Fällen nur gering und selten ändert, liegt es nahe die Lösung 2 zu verwenden.
Implementation
Die Implentation splittet sich in Datenbank-Design und Implentierung des eigentlichen Filters auf. Als Datenbank wird MySQL eingesetzt. Der Filter verwendet Sendmail und die Milter-API.
Datenbank-Design
Die Datenbank besteht aus 3 Tabellen, in denen jeweils getrennt Benutzer, Hosts und Subdomains verwaltet werden. Die einzelnen Einträge können mittels IDs innerhalb ihrer Kategorien gruppiert werden. Die Zuordung zwischen den Kategorien basiert auf den zuvorgenannten IDs und hat den Vorteil, dass sich logische Gruppen bilden, die sich gemeinsam administrieren lassen und auf diese Weise redundante und wiederholende Einträge in der Datenbank vermieden werden.
Filter-Design
Sendmail parst die eingehende Mail sukzessive, so dass die einzelnen Elemente wie Absender, Adressat, Inhalt usw seperat verarbeitet werden. Die Milter-API bietet für jeden einzelnen Abarbeitungsschritt eine Callback-Funktion mittels der Einfluss auf die Abarbeitung genommen werden kann. Dieser Filter beschränkt sich vollkommen auf die Zieladresse. Zuerst wird eine syntaktische Überprüfung vorgenommen. Sollte der Nutzername mehr als 64 Zeichen oder die Domain mehr als 255 Zeichen umfassen, wird die Mail sofort verworfen. Im nächsten Schritt wird überprüft, ob die Domaine und unter Umständen der Zielhost in der Datenbank bekannt sind. Falls dies nicht der Fall ist, wird die Filterung an dieser Stelle abgebrochen und die Nachricht weitergeleitet. Sollte bisher noch keine Abbruchbedingung zum Tragen gekommen seien, dann wird nun eine Anfrage an die Datenbank gestellt, ob ein entsprechender Eintrag für den Nutzer in Verbindung mit dem Zielhost und der Domain existiert. Ist dies der Fall wird die Nachricht weiterverarbeitet ansonsten wird sie vom System abgelehnt und an den Absender eine Mail gesendet, die darüber informiert, dass eine entsprechende Adresse nicht existiert.
Download und Installation
Download des Filters und dazugehöriger Skripte : addr-filter.tar.gz
System-Voraussetzung:
MySQL Version >=5
Sendmail mit Milter-API
Zuerst wird ein neuer Benutzer in der MySQL-Datenbank benötigt über den die Kommunikation und Administration ausgeführt wird. Als Standard wurde der Benutzer milter mit dem Passwort milter verwendet. Sollte ein anderer Benutzer verwendet werden, so muss dieses sowohl in den mitgelieferten Shell-Skripten als auch in der Konfigurationsdatei für den Filter entsprechend angepasst werden. Es stehen Makefiles für Solaris und Linux zur Verfügung. Durch das Setzen des Makros DEBUG in der Datei addr.c lässt sich der Filter im Debug-Modus kompilieren. Dies hat eine detailierte Ausgabe der Aktionen, die dieser durchführt, zur Folge. Mittels make bzw make -f makefile.solaris wird der Filter kompiliert.
In der Sendmail-Konfigurationsdatei (/etc/mail/sendmail.mc) müssen folgende Zeilen hinzugefügt werden:
INPUT_MAIL_FILTER(`addr', `S=unix:/var/run/addr.socket, T=C:2m')
define(`confINPUT_MAIL_FILTERS', `addr')
Das Einrichten der Datenbank erfolgt über das Skript db-install.sh.
Der Filter erwartet die Konfigurationsdatei /etc/mail/addr-filter oder eine beliebige Konfigurationsdatei, deren Pfad mittels Parameter -c beim Start an den Filter übergeben wird.
Folgende Optionen lassen sich dort beeinflussen (in Klammern stehen jeweils die Standard-Werte):
mail_socket=unix:/var/run/addr.socket
db_host=localhost
db=addr
db_port=0
db_user=milter
db_passwd=milter
Der Filter selbst wird mittels addr gestartet und benötigt root-Rechte.
Die Konfiguration von eMail-Adressen wird mittels 3er Skripte gesteuert:
Der Benutzername und das Passwort für den Datenbank-Nutzer muss in den Skripten angepasst werden, sollte vom Standard (User:milter,Passwort:milter)
abgewichen worden seien.
add_subnet:
Fügt ein Subnet/Subdomain zur Datenbank hinzu. Das Skript erwartet folgende Parameter:
-u subnet_name : Der Name des Subnetzes/Subdomain
-s subnet_group_id: Jedes Subnetz/Subdomain muss einer Gruppe zugewiesen werden, über welche intern die Verknüpfung zu Hostnamen und Benutzer durchgeführt wird.
add_host::
Fügt einen Hostnamen oder einen leeren Eintrag zur Datenbank hinzu. Leere Einträge werden in dem Fall benötigt, dass
das Subnetz gleichzeitig den Zielhost spezifiziert.
-u hostname: Hostname spezifizieren
-n: leerer Hostname
-g group_id: Hosts müssen ebenfalls in Gruppen zusammengefasst werden
-s subnet_id: Zuordnung eines Host zu einer Gruppe von Subnetzen
add_user:
Fügt einen Nutzer in die Datenbank ein
-u username: Spezifiziert Nutzernamen
-g host_group_id: Ordnet den Nutzer eine Gruppe von Hosts zu