{"id":388,"date":"2009-09-09T20:24:46","date_gmt":"2009-09-09T18:24:46","guid":{"rendered":"http:\/\/blog.benny-baumann.de\/?p=388"},"modified":"2011-02-05T13:25:30","modified_gmt":"2011-02-05T12:25:30","slug":"srs-mit-postfix","status":"publish","type":"post","link":"http:\/\/blog.benny-baumann.de\/?p=388","title":{"rendered":"SRS mit Postfix"},"content":{"rendered":"<p>Wer auf seinem Server <a href=\"http:\/\/openspf.org\/\">SPF<\/a> eins\u00e4tzt, oder eMails von anderen, die SPF eins\u00e4tzen weiterleiten will, der hat es mit Postfix derzeit noch etwas schwer. Es gab zwar bereits vor l\u00e4ngerer Zeit einen <a href=\"http:\/\/www.libsrs2.org\/patch\/postfix-libsrs2-2.1.4-1.patch\">Patch f\u00fcr Postfix 2.1.4<\/a>, der SRS direkt in Postfix integriert und der auch <a href=\"http:\/\/www.libsrs2.org\/docs\/mta-users.html\">nahezu vollst\u00e4ndig konfigurierbar<\/a> war, jedoch hat es dieser Patch nie in die aktuelle Distribution geschafft, weshalb man die f\u00fcr SRS n\u00f6tige Funktionalit\u00e4t in aktuellen Postfix-Versionen vergeblich sucht.<\/p>\n<p>Einzig durch l\u00e4ngere Suche auf <a href=\"http:\/\/libsrs2.org\/\">der Seite des libsrs2-Projektes<\/a> findet man unter Umst\u00e4nden Abhilfe. die dort vermerkten Konfigurationshinweise beziehen sich jedoch auf oben erw\u00e4hnten Patch, weshalb sie f\u00fcr die Nutzung nicht tauglich sind.<!--more--><\/p>\n<p>Nach kurzer Kontaktaufnahme mit dem f\u00fcr das libsrs2-Paket zust\u00e4ndigen Package-Maintainer von Debian kam ich auf die <a href=\"http:\/\/pfixtools.mymind.fr\/trac\/\">Postfix Tools<\/a> (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\u00fcgbar, womit ein wenig manuelles Hand an den Compiler anlegen angesagt ist. Nach Installation der Prerequisites f\u00fcr das Compilieren (hier scheint neben den in der Anleitung genannten auch Git n\u00f6tig zu sein, da vom Makefile immer wieder aufgerufen) landete ich bei einer Konfiguration, bei der zwar mit pfix-srsd der ben\u00f6tigte Daemon funktionierte, jedoch der Postfix seine Arbeit verweigerte &#8211; dazu aber sp\u00e4ter mehr.<\/p>\n<p>Vor dem Starten des Daemons muss nun die Konfiguration f\u00fcr SRS vorbereitet werden. Hierf\u00fcr kann man sich im einfachsten Falle mit einem kleinen PHP-Script<\/p>\n<pre lang=\"php\" escaped=\"true\">&lt;?php\r\n$salt = \"Bitte was zuf\u00e4lliges eintragen\";\r\nfor ($i = 0; $i &lt; 10; $i++) {\r\n    usleep(rand(5000, 100000));\r\n    echo sha1($salt . microtime(true)) . \"\\n\";\r\n}\r\n?&gt;<\/pre>\n<p>oder der Version als bash-Einzeiler<\/p>\n<pre lang=\"bash\" escaped=\"true\">echo 'for ($i = 0; $i &lt; 10; $i++) { usleep(rand(5000, 100000)); echo sha1(\"Bitte was zuf\u00e4lliges eintragen\" . microtime(true)) . \"\\n\"; }'|php5<\/pre>\n<p>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\u00fcssel, die sp\u00e4ter die Grundlage f\u00fcr die Berechnung der Hashes in den SRS-Nachrichten bilden.<\/p>\n<p>Als weitere Datei muss die Datei \/etc\/default\/pfix-srsd angelegt werden. In ihr folgen im Bash-Stil die sp\u00e4ter f\u00fcr den Start des Daemons notwendigen Optionen. Hier ist es empfehlenswert, die Option -I, die durch den unten erw\u00e4hnten Patch dem Daemon hinzugef\u00fcgt wird, gleich mit einzutragen. Eine Beispieldatei f\u00fcr den Mailserver mail.example.com k\u00f6nnte demnach so aussehen:<\/p>\n<pre lang=\"bash\" escaped=\"true\">DOMAIN=mail.example.com\r\nSECRETS=\/etc\/postfix\/pfix-srs.secrets\r\nOPTIONS=-I<\/pre>\n<p>Nun muss man nur noch dem Postfix bescheid geben, dass er bitte <a href=\"http:\/\/www.postfix.org\/ADDRESS_REWRITING_README.html#canonical\">Address Rewriting<\/a> ausf\u00fchren soll. Hierf\u00fcr kann man <a href=\"http:\/\/www.postfix.org\/postconf.5.html#canonical_maps\">canonical_maps<\/a> nutzen. F\u00fcr SRS sind hierbei lediglich die Envelope-Adressen zu bearbeiten &#8211; <strong>KEINE Message Header umschreiben lassen!<\/strong> Hierf\u00fcr f\u00fcgt man in der main.cf folgende Zeilen als eigenen Block ein:<\/p>\n<pre lang=\"ini\" escaped=\"true\">#For SRS Address mapping:\r\nrecipient_canonical_maps = hash:\/etc\/postfix\/pfix-srs.norewrite, tcp:127.0.0.1:10002\r\nrecipient_canonical_classes = envelope_recipient\r\nsender_canonical_maps = hash:\/etc\/postfix\/pfix-srs.norewrite, tcp:127.0.0.1:10001\r\nsender_canonical_classes = envelope_sender<\/pre>\n<p>Danach legt man noch die Adress-Mapping-Datei an, in der man das Umschreiben der Adressen nach RFC deaktiviert:<\/p>\n<pre lang=\"text\" escaped=\"true\">#Addresses on mail.example.com that should not be rewritten\r\npostmaster@mail.example.com       postmaster@mail.example.com\r\nabuse@mail.example.com    abuse@mail.example.com\r\nwebmaster@mail.example.com        webmaster@mail.example.com<\/pre>\n<p><strong>Nimmt man keine Mails auf diesen Adressen an, l\u00e4uft nicht nur Postfix nicht, sondern man riskiert auch, auf diversen Blacklists wie <a href=\"http:\/\/rfc-ignorant.org\/\">RFC-Ignorant<\/a> zu landen!<\/strong><\/p>\n<p>Startet man nun den pfix-srsd von Hand und gibt dem Postfix Server mit einem bestimmten<\/p>\n<pre lang=\"bash\" escaped=\"true\">\/etc\/init.d\/postfix reload<\/pre>\n<p>den freundlichen Hinweis auf eine ge\u00e4nderte Konfiguration, so st\u00f6\u00dft man auf eine ablehnende Haltung des Postfix-Servers gegen\u00fcber jeglichen zu verarbeitenden Mails.<\/p>\n<p>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\u00fcnschte Verhaltensweise, weshalb eine kleine \u00c4nderung am Daemon von N\u00f6ten ist (Vielen Dank an Pierre Habouzit f\u00fcr <a href=\"http:\/\/git.madism.org\/?p=apps\/pfixtools.git;a=commitdiff;h=7cb4e99bfb9cad2d4f22c8c0566117c7e9490ddc\">den Patch<\/a>):<\/p>\n<pre lang=\"diff\" escaped=\"true\">index 917aa38..0c656f8 100644 (file)\r\n--- a\/pfix-srsd\/main-srsd.c\r\n+++ b\/pfix-srsd\/main-srsd.c\r\n@@ -57,6 +57,8 @@ DECLARE_MAIN\r\n typedef struct srs_config_t {\r\n     srs_t* srs;\r\n     const char* domain;\r\n+    int domainlen;\r\n+    int ignore_ext;\r\n } srs_config_t;\r\n \r\n@@ -75,7 +77,7 @@ static void *srsd_starter(listener_t *server)\r\n \/* Processing {{{1\r\n  *\/\r\n \r\n-void urldecode(char *s, char *end)\r\n+char *urldecode(char *s, char *end)\r\n {\r\n     char *p = s;\r\n \r\n@@ -92,7 +94,8 @@ void urldecode(char *s, char *end)\r\n \r\n         *s++ = *p++;\r\n     }\r\n-    *s++ = '\\0';\r\n+    *s = '\\0';\r\n+    return s;\r\n }\r\n \r\n int process_srs(client_t *srsd, void* vconfig)\r\n@@ -136,9 +139,21 @@ int process_srs(client_t *srsd, void* vconfig)\r\n             goto skip;\r\n         }\r\n \r\n-        urldecode(p, q);\r\n+        q = urldecode(p, q);\r\n \r\n         if (decoder) {\r\n+            if (config-&gt;ignore_ext) {\r\n+                int dlen = config-&gt;domainlen;\r\n+\r\n+                if (q - p &lt;= dlen || q[-1 - dlen] != '@' || +                    memcmp(q - dlen, config-&gt;domain, dlen))\r\n+                {\r\n+                    buffer_addstr(obuf, \"200 \");\r\n+                    buffer_add(obuf, p, q - p);\r\n+                    buffer_addch(obuf, '\\n');\r\n+                    goto skip;\r\n+                }\r\n+            }\r\n             err = srs_reverse(config-&gt;srs, buf, ssizeof(buf), p);\r\n         } else {\r\n             err = srs_forward(config-&gt;srs, buf, ssizeof(buf), p, config-&gt;domain);\r\n@@ -260,6 +275,7 @@ void usage(void)\r\n           \"                 (default: \"STR(DEFAULT_DECODER_PORT)\")\\n\"\r\n           \"    -p\r\n file to write our pid to\\n\"\r\n           \"    -u           unsafe mode: don't drop privilegies\\n\"\r\n+          \"    -I           do not touch mails outside of \\\"domain\\\" in decoding mode\\n\"\r\n           \"    -f           stay in foreground\\n\"\r\n          , stderr);\r\n }\r\n@@ -275,7 +291,7 @@ int main(int argc, char *argv[])\r\n     int port_dec = DEFAULT_DECODER_PORT;\r\n     const char *pidfile = NULL;\r\n \r\n-    for (int c = 0; (c = getopt(argc, argv, \"hfu\" \"e:d:p:\")) &gt;= 0; ) {\r\n+    for (int c = 0; (c = getopt(argc, argv, \"hfuI\" \"e:d:p:\")) &gt;= 0; ) {\r\n         switch (c) {\r\n           case 'e':\r\n             port_enc = atoi(optarg);\r\n@@ -292,6 +308,9 @@ int main(int argc, char *argv[])\r\n           case 'u':\r\n             unsafe = true;\r\n             break;\r\n+          case 'I':\r\n+            config.ignore_ext = true;\r\n+            break;\r\n           default:\r\n             usage();\r\n             return EXIT_FAILURE;\r\n@@ -310,6 +329,7 @@ int main(int argc, char *argv[])\r\n     info(\"%s v%s...\", DAEMON_NAME, DAEMON_VERSION);\r\n \r\n     config.domain = argv[optind];\r\n+    config.domainlen = strlen(config.domain);\r\n     config.srs = srs_read_secrets(argv[optind + 1]);\r\n     if (!config.srs\r\n         || common_setup(pidfile, unsafe, RUNAS_USER, RUNAS_GROUP,<\/pre>\n<p>Dieser Patch lockert dabei das Vorgehen des Daemons beim Dekodieren von Mails, in dem er Mails f\u00fcr Fremddomains (alle au\u00dfer der als Parameter angegebenen) ohne g\u00fcltige SRS-Signatur ignoriert (200 Mit Original-Adresse), statt diese tempor\u00e4r abzulehnen (400 No SRS address). Mit diesem aktualisierten Daemon aktiv geschaltet und der n\u00f6tigen Umleitung der Envelope-Froms mit Hilfe von Canonical Rewrite Maps &#8211; wie oben bereits konfiguriert &#8211; tut der Server nun wie gehei\u00dfen 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\u00fcltiger SRS-Kennung werden hierbei kommentarlos abgewiesen; Mails f\u00fcr Fremddomains (d.h. != der Signing Domain) werden hierbei ignoriert.<\/p>\n<p>Zum Installieren dieses Daemons erfolgt dabei am einfachsten mit Git, gefolgt von einem einfachen make und dem obligatorischen make install zum Kopieren der Dateien:<\/p>\n<pre lang=\"bash\" escaped=\"true\">cd\r\naptitude 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\r\nmkdir pfix-srsd\r\ncd pfix-srsd\r\ngit clone git:\/\/git.madism.org\/apps\/pfixtools.git\r\nmake &amp;&amp; make install<\/pre>\n<p>Fehlt nur noch das Init-Script f\u00fcr den Daemon, das sich jedoch schnell in Anlehnung an andere Scripte selbst bauen l\u00e4sst:<\/p>\n<pre lang=\"bash\" escaped=\"true\">#!\/bin\/sh\r\n\r\n### BEGIN INIT INFO\r\n# Provides:          pfix-srsd\r\n# Required-Start:    $local_fs $remote_fs\r\n# Required-Stop:     $local_fs $remote_fs\r\n# Default-Start:     2 3 4 5\r\n# Default-Stop:      0 1 6\r\n# Short-Description: pfixtools SRS Daemon backend for Postfix\r\n### END INIT INFO\r\n\r\nPFIXSRSD_CONFIG=\"\/etc\/default\/pfix-srsd\"\r\nNAME=\"pfix-srsd\"\r\nDAEMON=\"\/usr\/local\/sbin\/pfix-srsd\"\r\nPID_FILE=\"\/var\/run\/pfix-srsd.pid\"\r\n\r\nif [ -f $PFIXSRSD_CONFIG ]; then\r\n  . $PFIXSRSD_CONFIG\r\nelse\r\n  exit 0\r\nfi\r\n\r\ntest -x $DAEMON || exit 0\r\n\r\ncase \"$1\" in\r\n  start)\r\n    echo -n \"Starting Postfix SRS Daemon: $NAME\"\r\n    start-stop-daemon -S -q -b -p $PID_FILE -x $DAEMON -- -p $PID_FILE $OPTIONS $DOMAIN $SECRETS\r\n    echo \".\"\r\n    ;;\r\n  stop)\r\n    echo -n \"Stopping Postfix SRS Daemon: $NAME\"\r\n    if [ -f $PID_FILE ]; then\r\n      kill `cat $PID_FILE`\r\n      rm $PID_FILE\r\n    fi\r\n    echo \".\"\r\n    ;;\r\n  restart)\r\n    $0 stop\r\n    $0 start\r\n    ;;\r\n  force-reload)\r\n    $0 restart\r\n    ;;\r\n  *)\r\n    echo \"Usage: $0 start|stop|restart|force-reload\"\r\n    exit 1\r\n    ;;\r\nesac<\/pre>\n<p>Die Konfiguration f\u00fcr das Init-Script wird hierbei unter \/etc\/default\/pfix-srsd abgelegt, von wo sie durch das Init-Script eingelesen wird. Zus\u00e4tzlich sollte man sich mit  <a href=\"http:\/\/packages.debian.org\/search?keywords=sysv-rc-conf\">sysv-rc-conf<\/a> den Daemon in die Autostart-Liste f\u00fcr Runlevel 2-5 aufnehmen, bzw. jegliche Runlevel, in denen Postfix l\u00e4uft (was aber in der Default-Konfiguration aussagen\u00e4quivalent ist). Jetzt nur noch einmal von Hand starten und der Rest sollte von alleine gehen.<\/p>\n<p>Nach dieser \u00c4nderung droppte die Anzahl zugestellter Backscatter-Mails auf nahezu 0 &#8230; also zumindest hab ich bisher keine nennenswerten Anzahlen mehr wieder beobachtet \ud83d\ude09<\/p>\n<p>Zusammenfassend kann man somit sagen, dass SRS, obwohl es f\u00fcr Relaying oder Forwarding extrem wichtig ist, in aktuellen Postfix-Versionen bisher leider noch zu wenig Aufmerksamkeit genie\u00dft und damit unn\u00f6tig kompliziert zu konfigurieren geht, wodurch gerade Anf\u00e4nger 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\u00e4re.<\/p>\n<p class=\"wp-flattr-button\"><a href=\"http:\/\/blog.benny-baumann.de\/?flattrss_redirect&amp;id=388&amp;md5=0960e2af979a6803a90694b615bb4c04\" title=\"Flattr\" target=\"_blank\"><img src=\"http:\/\/blog.benny-baumann.de\/wp-content\/plugins\/flattr\/img\/flattr-badge-large.png\" srcset=\"http:\/\/blog.benny-baumann.de\/wp-content\/plugins\/flattr\/img\/flattr-badge-large.png\" alt=\"Flattr this!\"\/><\/a><\/p>","protected":false},"excerpt":{"rendered":"<p>Wer auf seinem Server SPF eins\u00e4tzt, oder eMails von anderen, die SPF eins\u00e4tzen weiterleiten will, der hat es mit Postfix derzeit noch etwas schwer. Es gab zwar bereits vor l\u00e4ngerer Zeit einen Patch f\u00fcr Postfix 2.1.4, der SRS direkt in Postfix integriert und der auch nahezu vollst\u00e4ndig konfigurierbar war, jedoch hat es dieser Patch nie [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"ngg_post_thumbnail":0,"footnotes":""},"categories":[4],"tags":[10,13,231,204,346,230],"class_list":["post-388","post","type-post","status-publish","format-standard","hentry","category-server","tag-debian","tag-patch","tag-pfixtools","tag-postfix","tag-server","tag-srs"],"_links":{"self":[{"href":"http:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/posts\/388","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/blog.benny-baumann.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=388"}],"version-history":[{"count":10,"href":"http:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/posts\/388\/revisions"}],"predecessor-version":[{"id":989,"href":"http:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/posts\/388\/revisions\/989"}],"wp:attachment":[{"href":"http:\/\/blog.benny-baumann.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=388"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/blog.benny-baumann.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=388"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/blog.benny-baumann.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=388"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}