transparenter Reverse-Proxy mit SNIProxy

Vor einer Weile haben wir uns mit SNIProxy als einem sehr einfachen Reverse Proxy befasst. Ein Nachteil, den die Verwendung von Reverse Proxies für Web-Zugriffe oft hat, ist, dass aus Sicht des dahinterliegenden Webservers Requests nicht vom eigentlichen Client zu kommen scheinen, sondern eben vom Proxy-Rechner. Das ist unpraktisch, da in Logs und Statistiken so der eigentliche Client nicht auftaucht.

Manche Proxies kennen Möglichkeiten, um dieses Problem zu umgehen. SNIProxy lässt sich in einem transparenten Modus betreiben, in dem die Quell-Adresse der Verbindungen beibehalten wird.

SNIProxy im transparenten Modus

SNIProxy in den transparenten Modus zu versetzen ist auf den ersten Blick ganz einfach: Über die Konfigurationsdirektive source client im passenden Listener teilt man dem SNIProxy mit, er möchte doch bitte als Quell-Adresse für die Verbindungen gegen innen die ursprüngliche IP des Clients verwenden, z.B. so:

listen 192.168.1.15 80 {
   proto http
   source client
....

Als Beispiel verwenden wir 192.168.1.15 als IP für den Proxy. Es gibt dabei allerdings die eine oder andere Hürde zu umschiffen:

  • Der transparente Modus funktioniert nur bei Listenern, die nur eine IP-Version verwenden. Es ist also notwendig, separate Listener für IPv4- und IPv6-Verbindungen einzurichten. In obigem Beispiel geben wir explizit die Adresse an, auf die der Listener hören soll, d.h. wir legen uns in diesem Beispiel auf IPv4 fest.
  • Die Antwort-Pakete der Webserver, auf die SNIProxy weiterverbindet, müssen durch den Proxy-Rechner geroutet werden. Im einfachsten Fall wird dieser als Router aufgesetzt und die Webserver erhalten ihn als Default-Gateway.
  • Auf dem Proxy-Rechner selbst muss per IPTables dafür gesorgt werden, dass die Pakete auch tatsächlich durch den transparenten Proxy laufen.
     

iptables und Policy Route auf dem Proxy-Rechner

Damit der Transparentmodus richtig funktioniert, müssen Pakete passend geleitet werden. Dies geschieht durch eine separate Routing-Tabelle, auf die Pakete per Markierung durch iptables geleitet werden:

iptables -t mangle -N DIVERT
iptables -t mangle -A PREROUTING -p tcp -m socket -j DIVERT
iptables -t mangle -A DIVERT -j MARK --set-mark 1
iptables -t mangle -A DIVERT -j ACCEPT

ip rule add fwmark 1 lookup 100
ip route add local 0.0.0.0/0 dev lo table 100

Auf dem Proxy-Rechner muss ausserdem Forwarding eingeschaltet sein, z.B. durch folgende Einträge in /etc/sysctl.conf:

net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1

Webtraffic auf den Webservern durch den Proxy umleiten

Im einfachsten Fall wird ganz einfach die Default-Route der Webserver auf den Proxy gelegt. Das ist nicht immer praktikabel. Eine Variante davon ist, lediglich die Antworten des Webservers über den Proxy umzuleiten. Auch dies gelingt mit einer Policy-Route und einer iptables-Markierung, etwa so:

iptables -t mangle -A OUTPUT -p tcp --sport 443 -j MARK --set-mark 0x8
iptables -t mangle -A OUTPUT -p tcp --sport 80 -j MARK --set-mark 0x8

ip rule add fwmark 8 lookup 101
ip route add 192.168.1.15 dev eth0 table 101
ip route add default via 192.168.1.15 table 101

Auch hier gegen wir als Beispiel wieder vom auf der Adresse 192.168.1.15 laufenden Proxy aus und leiten alle ausgehenden Pakete mit Quellport 80 oder 443 auf diesen um.