BenBE's humble thoughts Thoughts the world doesn't need yet …

09.09.2009

SRS mit Postfix

Filed under: Server — Schlagwörter: , , , , , — BenBE @ 20:24:46

Wer auf seinem Server SPF einsätzt, oder eMails von anderen, die SPF einsätzen weiterleiten will, der hat es mit Postfix derzeit noch etwas schwer. Es gab zwar bereits vor längerer Zeit einen Patch für Postfix 2.1.4, der SRS direkt in Postfix integriert und der auch nahezu vollständig konfigurierbar war, jedoch hat es dieser Patch nie in die aktuelle Distribution geschafft, weshalb man die für SRS nötige Funktionalität in aktuellen Postfix-Versionen vergeblich sucht.

Einzig durch längere Suche auf der Seite des libsrs2-Projektes findet man unter Umständen Abhilfe. die dort vermerkten Konfigurationshinweise beziehen sich jedoch auf oben erwähnten Patch, weshalb sie für die Nutzung nicht tauglich sind.

Nach kurzer Kontaktaufnahme mit dem für das libsrs2-Paket zuständigen Package-Maintainer von Debian kam ich auf die Postfix Tools (pfixtools), die als canonical_map via TCP-Verbindung an Postfix gebunden werden. Jedoch sind diese derzeit weder in stable, testing noch unstable als Paket verfügbar, womit ein wenig manuelles Hand an den Compiler anlegen angesagt ist. Nach Installation der Prerequisites für das Compilieren (hier scheint neben den in der Anleitung genannten auch Git nötig zu sein, da vom Makefile immer wieder aufgerufen) landete ich bei einer Konfiguration, bei der zwar mit pfix-srsd der benötigte Daemon funktionierte, jedoch der Postfix seine Arbeit verweigerte – dazu aber später mehr.

Vor dem Starten des Daemons muss nun die Konfiguration für SRS vorbereitet werden. Hierfür kann man sich im einfachsten Falle mit einem kleinen PHP-Script

<?php
$salt = "Bitte was zufälliges eintragen";
for ($i = 0; $i < 10; $i++) {
    usleep(rand(5000, 100000));
    echo sha1($salt . microtime(true)) . "\n";
}
?>

oder der Version als bash-Einzeiler

echo 'for ($i = 0; $i < 10; $i++) { usleep(rand(5000, 100000)); echo sha1("Bitte was zufälliges eintragen" . microtime(true)) . "\n"; }'|php5

eine Datei mit Server-Secrets erzeugen (Name siehe weiter unten im Startscript), oder diese von Hand schnell erzeugen (Einfache Textdatei mit einem Passwort pro Zeile). Diese legt man sich am besten in das Postfix-Verzeichnis und reduziert deren Sichtbarkeit auf root\400 (pfix-srsd liest sie vor dem Droppen seiner Rechte). Somit verhindert man das unbefugte Auslesen der Schlüssel, die später die Grundlage für die Berechnung der Hashes in den SRS-Nachrichten bilden.

Als weitere Datei muss die Datei /etc/default/pfix-srsd angelegt werden. In ihr folgen im Bash-Stil die später für den Start des Daemons notwendigen Optionen. Hier ist es empfehlenswert, die Option -I, die durch den unten erwähnten Patch dem Daemon hinzugefügt wird, gleich mit einzutragen. Eine Beispieldatei für den Mailserver mail.example.com könnte demnach so aussehen:

DOMAIN=mail.example.com
SECRETS=/etc/postfix/pfix-srs.secrets
OPTIONS=-I

Nun muss man nur noch dem Postfix bescheid geben, dass er bitte Address Rewriting ausführen soll. Hierfür kann man canonical_maps nutzen. Für SRS sind hierbei lediglich die Envelope-Adressen zu bearbeiten – KEINE Message Header umschreiben lassen! Hierfür fügt man in der main.cf folgende Zeilen als eigenen Block ein:

#For SRS Address mapping:
recipient_canonical_maps = hash:/etc/postfix/pfix-srs.norewrite, tcp:127.0.0.1:10002
recipient_canonical_classes = envelope_recipient
sender_canonical_maps = hash:/etc/postfix/pfix-srs.norewrite, tcp:127.0.0.1:10001
sender_canonical_classes = envelope_sender

Danach legt man noch die Adress-Mapping-Datei an, in der man das Umschreiben der Adressen nach RFC deaktiviert:

#Addresses on mail.example.com that should not be rewritten
postmaster@mail.example.com       postmaster@mail.example.com
abuse@mail.example.com    abuse@mail.example.com
webmaster@mail.example.com        webmaster@mail.example.com

Nimmt man keine Mails auf diesen Adressen an, läuft nicht nur Postfix nicht, sondern man riskiert auch, auf diversen Blacklists wie RFC-Ignorant zu landen!

Startet man nun den pfix-srsd von Hand und gibt dem Postfix Server mit einem bestimmten

/etc/init.d/postfix reload

den freundlichen Hinweis auf eine geänderte Konfiguration, so stößt man auf eine ablehnende Haltung des Postfix-Servers gegenüber jeglichen zu verarbeitenden Mails.

An der Konfiguration jedenfalls liegt das nicht und auch der Daemon tut seine Aufgabe eigentlich korrekt. Nur leider passt dies nur bedingt in die gewünschte Verhaltensweise, weshalb eine kleine Änderung am Daemon von Nöten ist (Vielen Dank an Pierre Habouzit für den Patch):

index 917aa38..0c656f8 100644 (file)
--- a/pfix-srsd/main-srsd.c
+++ b/pfix-srsd/main-srsd.c
@@ -57,6 +57,8 @@ DECLARE_MAIN
 typedef struct srs_config_t {
     srs_t* srs;
     const char* domain;
+    int domainlen;
+    int ignore_ext;
 } srs_config_t;
 
@@ -75,7 +77,7 @@ static void *srsd_starter(listener_t *server)
 /* Processing {{{1
  */
 
-void urldecode(char *s, char *end)
+char *urldecode(char *s, char *end)
 {
     char *p = s;
 
@@ -92,7 +94,8 @@ void urldecode(char *s, char *end)
 
         *s++ = *p++;
     }
-    *s++ = '\0';
+    *s = '\0';
+    return s;
 }
 
 int process_srs(client_t *srsd, void* vconfig)
@@ -136,9 +139,21 @@ int process_srs(client_t *srsd, void* vconfig)
             goto skip;
         }
 
-        urldecode(p, q);
+        q = urldecode(p, q);
 
         if (decoder) {
+            if (config->ignore_ext) {
+                int dlen = config->domainlen;
+
+                if (q - p <= dlen || q[-1 - dlen] != '@' || +                    memcmp(q - dlen, config->domain, dlen))
+                {
+                    buffer_addstr(obuf, "200 ");
+                    buffer_add(obuf, p, q - p);
+                    buffer_addch(obuf, '\n');
+                    goto skip;
+                }
+            }
             err = srs_reverse(config->srs, buf, ssizeof(buf), p);
         } else {
             err = srs_forward(config->srs, buf, ssizeof(buf), p, config->domain);
@@ -260,6 +275,7 @@ void usage(void)
           "                 (default: "STR(DEFAULT_DECODER_PORT)")\n"
           "    -p
 file to write our pid to\n"
           "    -u           unsafe mode: don't drop privilegies\n"
+          "    -I           do not touch mails outside of \"domain\" in decoding mode\n"
           "    -f           stay in foreground\n"
          , stderr);
 }
@@ -275,7 +291,7 @@ int main(int argc, char *argv[])
     int port_dec = DEFAULT_DECODER_PORT;
     const char *pidfile = NULL;
 
-    for (int c = 0; (c = getopt(argc, argv, "hfu" "e:d:p:")) >= 0; ) {
+    for (int c = 0; (c = getopt(argc, argv, "hfuI" "e:d:p:")) >= 0; ) {
         switch (c) {
           case 'e':
             port_enc = atoi(optarg);
@@ -292,6 +308,9 @@ int main(int argc, char *argv[])
           case 'u':
             unsafe = true;
             break;
+          case 'I':
+            config.ignore_ext = true;
+            break;
           default:
             usage();
             return EXIT_FAILURE;
@@ -310,6 +329,7 @@ int main(int argc, char *argv[])
     info("%s v%s...", DAEMON_NAME, DAEMON_VERSION);
 
     config.domain = argv[optind];
+    config.domainlen = strlen(config.domain);
     config.srs = srs_read_secrets(argv[optind + 1]);
     if (!config.srs
         || common_setup(pidfile, unsafe, RUNAS_USER, RUNAS_GROUP,

Dieser Patch lockert dabei das Vorgehen des Daemons beim Dekodieren von Mails, in dem er Mails für Fremddomains (alle außer der als Parameter angegebenen) ohne gültige SRS-Signatur ignoriert (200 Mit Original-Adresse), statt diese temporär abzulehnen (400 No SRS address). Mit diesem aktualisierten Daemon aktiv geschaltet und der nötigen Umleitung der Envelope-Froms mit Hilfe von Canonical Rewrite Maps – wie oben bereits konfiguriert – tut der Server nun wie geheißen und sendet jegliche ausgehende Mails mit entsprechender SRS-Absender-Adresse im Envelope (was man wunderbar als Spam-Schutz gegen Bounces nutzen kann, da auch die eigenen Domains umgeschrieben werden). Eingehende Mails mit ungültiger SRS-Kennung werden hierbei kommentarlos abgewiesen; Mails für Fremddomains (d.h. != der Signing Domain) werden hierbei ignoriert.

Zum Installieren dieses Daemons erfolgt dabei am einfachsten mit Git, gefolgt von einem einfachen make und dem obligatorischen make install zum Kopieren der Dateien:

cd
aptitude install libev3 libev-dev libsrs2-0 libsrs2-dev libtokyocabinet-dbg libtokyocabinet-dev libtokyocabinet3 tokyocabinet-bin libunbound0 libunbound1 libunbound-dev libpcre3 libpcre3-dev gcc pkg-config gperf xmlto docbook-xsl asciidoc
mkdir pfix-srsd
cd pfix-srsd
git clone git://git.madism.org/apps/pfixtools.git
make && make install

Fehlt nur noch das Init-Script für den Daemon, das sich jedoch schnell in Anlehnung an andere Scripte selbst bauen lässt:

#!/bin/sh
 
### BEGIN INIT INFO
# Provides:          pfix-srsd
# Required-Start:    $local_fs $remote_fs
# Required-Stop:     $local_fs $remote_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: pfixtools SRS Daemon backend for Postfix
### END INIT INFO
 
PFIXSRSD_CONFIG="/etc/default/pfix-srsd"
NAME="pfix-srsd"
DAEMON="/usr/local/sbin/pfix-srsd"
PID_FILE="/var/run/pfix-srsd.pid"
 
if [ -f $PFIXSRSD_CONFIG ]; then
  . $PFIXSRSD_CONFIG
else
  exit 0
fi
 
test -x $DAEMON || exit 0
 
case "$1" in
  start)
    echo -n "Starting Postfix SRS Daemon: $NAME"
    start-stop-daemon -S -q -b -p $PID_FILE -x $DAEMON -- -p $PID_FILE $OPTIONS $DOMAIN $SECRETS
    echo "."
    ;;
  stop)
    echo -n "Stopping Postfix SRS Daemon: $NAME"
    if [ -f $PID_FILE ]; then
      kill `cat $PID_FILE`
      rm $PID_FILE
    fi
    echo "."
    ;;
  restart)
    $0 stop
    $0 start
    ;;
  force-reload)
    $0 restart
    ;;
  *)
    echo "Usage: $0 start|stop|restart|force-reload"
    exit 1
    ;;
esac

Die Konfiguration für das Init-Script wird hierbei unter /etc/default/pfix-srsd abgelegt, von wo sie durch das Init-Script eingelesen wird. Zusätzlich sollte man sich mit sysv-rc-conf den Daemon in die Autostart-Liste für Runlevel 2-5 aufnehmen, bzw. jegliche Runlevel, in denen Postfix läuft (was aber in der Default-Konfiguration aussagenäquivalent ist). Jetzt nur noch einmal von Hand starten und der Rest sollte von alleine gehen.

Nach dieser Änderung droppte die Anzahl zugestellter Backscatter-Mails auf nahezu 0 … also zumindest hab ich bisher keine nennenswerten Anzahlen mehr wieder beobachtet 😉

Zusammenfassend kann man somit sagen, dass SRS, obwohl es für Relaying oder Forwarding extrem wichtig ist, in aktuellen Postfix-Versionen bisher leider noch zu wenig Aufmerksamkeit genießt und damit unnötig kompliziert zu konfigurieren geht, wodurch gerade Anfänger diese Funktion scheuen werden. Und das obwohl die Installation im Wesentlichen aus dem Setzen von wenigen Optionen, dem Installieren der Dependencies, dem Compilieren eines Programms und dem Schreiben eines Init-Scriptes besteht, womit sie in Form eines Debian-Paketes die Sache wesentlich besser aufgehoben wäre.

Flattr this!

4 Comments »

  1. Danke für Deine Anleitung. Seit gestern läuft der Server nun. Kleine Anmerkungen:

    1. Bei dem PHP Skript fehlt nach dem for eine (
    2. Bei den Paketinstallationen gibt es unter Debian kein libunbound1 meintest du vielleicht libunbound2?
    3. Die Adress-Mapping-Datei muss natürlich mit postmap übersetzt werden, nicht vergessen!

    Dann noch eine Frage:
    Seit der Installation habe ich ein paar Logeinträge, wahrscheinlich von Spam verursacht, aber die sollten glaube nicht auftreten:
    Feb 3 11:33:00 myhost postfix/qmgr[6180]: 236CB95E07D: from=, size=50101, nrcpt=1 (queue active)
    Feb 3 11:33:00 myhost postfix/cleanup[2207]: warning: 52A2995E085: sender_canonical_maps map lookup problem for ""
    Feb 3 11:33:00 myhost postfix/qmgr[6180]: 236CB95E07D: status=deferred (bounce failed)

    Weist Du vielleicht wo die her kommen?

    Kommentar by crifi — 03.02.2011 @ 18:17:58

  2. Danke für den Hinweis mit der fehlenden Klammer im PHP-Teil. Ist behoben (auch in dem Bash-Einzeiler).

    Zum Zeitpunkt, wo diese Anleitung entstanden ist (ist ja immerhin schon über ein Jahr her), hieß das Paket noch libubound1. libubound2 ist der Nachfolger und sollte genauso funktionieren.

    Auf 3. weist einen Postfix mit den Logausgaben auch hin (Mapfile ist älter als Datenbank o.s.ä.). Aber stimmt. Das sollte man noch mit beachten.

    Die Meldungen bzgl. leeren adressen basieren darauf, dass mit einem leeren Envelope Sender die Verfügbarkeit des Empfänger-Postfaches geprüft wird. Hierzu bitte den besagten Patch einspielen UND den Daemon so starten, dass er leere Adressen unbehandelt durchreicht.

    Kommentar by BenBE — 05.02.2011 @ 13:34:15

  3. Was ich noch nicht ganz verstehe:
    1. Was soll das mit der Mapping Datei für postmaster, absue, etc? Ich sehe noch nicht ganz warum das wichtig ist.
    2. Welche Sender werden eigentlich umgeschrieben, bzw. wie erkennt es den Unterschied zwichen:
    – Mail kommt von lokal und geht nach extern (keine Weiterleitung, also kein SRS notwendig)
    – Mail kommt von extern und geht an eine lokale Box (keine Weiterleitung, also kein SRS notwendig)
    – Mail kommt von extern und wird nach extern durchgereicht, aber Domain hat keinen SPF Eintrag (SRS nicht notwendig)
    – Mail kommt von extern und wird nach extern durchgereicht, Domain hat einen SPF Eintrag (SRS muss angewendet werden)

    Kommentar by peter — 10.07.2011 @ 19:39:36

  4. Die Mapping-Datei sorgt dafür, dass bestimmte Postfach-Namen nicht umgeschrieben werden.

    Dies ist notwendig, da in der vorgestellten Konfiguration von Haus aus alle Mails (unabhängig von Herkunft, Empfänger, Hautfarbe) umgeschrieben werden. Dies erspart einem insbesondere die Unterscheidung, ob SPF für die Quelldomain benötigt wird oder nicht. Selbst wenn dies nämlich nicht nötig ist (kein SPF auf Quelldomain) ist es einfach guter Ton, die Mail an den eigenen Mailserver zurück zu leiten, statt Backscatter auf dem Quellserver zu erzeugen. Hintergrund dazu ist, dass man auf diese Weise Rückläufer erkennt und z.B. nicht mehr funktionierende Mailadressen besser erkennen kann. Auch vermeidet man auf diese Weise, dass man selber als Illegitimer Spam-Server gebrandmarkt wird, weil man unter falscher Domain, die einem nicht gehört, Mails versendet. Neben SPF gibt es noch andere Schutzverfahren, bei denen man auf diese Weise Probleme vermeidet.

    Die Unterscheidung, ob eine Mail von Lokal kommt, bzw. ob diese extern weitergeleitet wurde, kann man, wenn gewünscht, durch Konfiguration mehrerer Mailpfade innerhalb von Postfix erreichen. Das hätte aber den Rahmen doch erheblich gesprengt.

    Kommentar by BenBE — 11.07.2011 @ 13:43:55

RSS feed for comments on this post. TrackBack URL

Leave a comment

Powered by WordPress