Hat man einen Server mit mehreren IP-Adressen, gibt es gewisse Situationen, in denen man ausgehende Verbindungen gezielt routen möchte. Hat man da nämlich einen Mail-Server am Laufen, der auf allen Adressen annehmen, aber nur unter einer bestimmten Adresse versenden soll, artet es leicht in Gefrickel aus. Aber es geht einfacher.
Für den Zweck des Routings gibt es zwar zum einen mit
ip route
ein mächtiges Werkzeug, was einem das Routing erfolgreich so einrichten kann, dass versucht wird, bestimmte Adressbereiche über spezifische Interfaces anzusprechen, aber dies ist in seiner brauchbaren Form sehr darauf begrenzt, dass man seine Ziele kennt und daher nicht einfach zu brauchen.
Daneben gibt es mit
ip rule
aber auch einen mächtigen Zwilling, mit dem man die im Kernel definierten Source Routing Rules überschreiben kann. Dies findet zwar hauptsächlich in Mesh-Netzwerken mit OLSR eine Anwendung, wäre aber prinzipiell auch für mein Problem eine Lösung, würde es denn auf Port-Ebene arbeiten: Tut es aber leider nicht.
Also muss man doch etwas anders an die Sache ran. Und witziger Weise können Firewalls nicht nur Pakete wegwerfen oder die Lautstärke der Namensauflösung begrenzen, sondern auch „The Right Thing“ tuen, um die Quelle einer TCP-Verbindung umzuleiten.
Und wie das bei Linux-Firewalls nun einmal ist, können die manchmal mehr, als man nach zwei Stunden Studium des Handbuches überblickt. Da gehört das Binden auf eine bestimmte Quell-IP so eher in die Morgenübungen der Firewall, wenn der Rauschende Datenstrom des nächtlichen Backups nocht nicht ganz überstanden ist.
Aber zurück zum Problem: Gegeben sei ein beliebiger Mailserver aus der Kategorie „Why Broken Software Works„, sowie ein Server mit mehreren IPv4-Adressen, von denen nur eine zum Versenden von Email verwendet werden soll.
Und weil das so einfach ist, kann das sogar jeder Plaste-Router zu hause. Nunja, er tut es einfach, wenn auch etwas anders: Er NATtet. Denn der Trick ist an sich ganz einfach: Statt direkte Verbindungen nach außen umzuschreiben, kann man auch einfach dem Kernel sagen, er soll jede ausgehende Verbindung mit einer Source-NAT versehen, die die zu verwendende Adresse enthält. Nun wäre das alleine sicherlich keinen Blog-Post wert, wäre da nicht die Sache mit dem: Nur der Mailserver. Das Interessante hieran ist nämlich, dass für den Mail-Server ausgehend nur ganz wenige Ports überhaupt von Bedeutung sind:
- Port 25: Für ein- und ausgehende Mails ohne SSL
- Port 465: Für ein- und ausgehende Mails mit SSL
- Port 587: Für eingehende Mails mit Authentifizierung
Von diesen 3 Ports ist Port 465 inzwischen „veraltet“ und sollte daher nicht mehr verwendet werden, womit für ausgehende Mails allein Port 25 übrig bleibt. Also kann man gezielt auch nur diesen ausgehend NATen:
iptables -t nat -A POSTROUTING -m iprange --src-range $START-$ENDE -p tcp -m tcp --dport 25 -j SNAT --to-source $ZIEL
And that’s it! Eine Zeile in der Firewall und jede ausgehende Mail ist automagisch auf die Ziel-IP (also die zu verwendende Quelladresse) gebunden, egal, von welcher der IPs der Server versucht zu senden. Und schon klappt das auch mit dem SPF 😉
Das verstehe ich nicht. Warum muss man sich denn da so anstellen?
postconf -e smtp_bind_address=$ip
Andere MTAs können das sicherlich genau so einfach.
Mit der Lösung in deinem Beitrag gibt es Kollateralschäden – spätestens, wenn jemand von außen mit Quellport 25 ankommt. Unwahrscheinlich, aber nicht unmöglich. Außerdem ist es überhaupt nicht portabel.
Kommentar by Nik — 03.08.2012 @ 23:37:23
Theoretisch ja, funktioniert nur in der Praxis leider nicht zuverlässig. Zumal (kann mich da verlesen haben) das sowohl Inbound Listen als auch Outbound Client Verbindungen betrifft; ich die definierte IP aber wirklich nur outbound benötige. Und ganz interessant wird es, wenn man sich durchliest, dass die Doku sagt, man solle das auf Multihomed-Systemen doch bitte auf 0.0.0.0 setzen.
Kommentar by BenBE — 04.08.2012 @ 23:06:06