iptables - Soll das Paket an eine bestimmte Schnittstelle weitergeleitet werden?

25

Mein Heimserver verfügt über zwei Hauptschnittstellen eth1(eine Standard-Internetverbindung) und tun0(einen OpenVPN-Tunnel). Ich möchte verwenden, um iptableszu erzwingen, dass alle Pakete, die von einem lokalen Prozess im Besitz der UID 1002 generiert wurden tun0, beendet werden und alle anderen Pakete beendet werden eth1.

Ich kann leicht übereinstimmende Pakete markieren:

iptables -A OUTPUT -m owner --uid-owner 1002 -j MARK --set-mark 11

Jetzt möchte ich einige Regeln in die POSTROUTING-Kette (wahrscheinlich der Mangle-Tabelle) aufnehmen, um Pakete zuzuordnen, die mit 11 markiert sind, und sie an zu senden tun0, gefolgt von einer Regel, die allen Paketen entspricht und sie an sendet eth1.

Ich habe das ROUTE-Ziel gefunden, aber das scheint nur die Quellschnittstelle neu zu schreiben (es sei denn, ich lese es falsch).

Ist iptables dazu in der Lage? Muss ich stattdessen mit der Routing-Tabelle herumspielen (über ip routeoder nur über die Legacy- routeBefehle)?

Edit: Ich dachte, dass ich vielleicht mehr Informationen geben sollte. Ich habe derzeit keine anderen iptables-Regeln (obwohl ich möglicherweise einige Regeln für die zukünftige Ausführung von nicht verwandten Aufgaben erstellt habe). Außerdem ist die Ausgabe von ip route:

default via 192.168.1.254 dev eth1  metric 203
10.32.0.49 dev tun0  proto kernel  scope link  src 10.32.0.50
85.17.27.71 via 192.168.1.254 dev eth1
192.168.1.0/24 dev eth1  proto kernel  scope link  src 192.168.1.73  metric 203

Ich habe die Routing-Tabelle nicht angerührt - so ist sie derzeit (obwohl sie ziemlich schmutzig aussieht). Es tut mir leid, aber ich habe den Legacy- routeBefehl nicht auf diesem Computer installiert.

Und die Ausgabe von ip addr(natürlich können eth0 und eth2 ignoriert werden - das sind NICs, die derzeit nicht verwendet werden):

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
    link/ether 1c:6f:65:2a:73:3f brd ff:ff:ff:ff:ff:ff
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast     state UP qlen 1000
    link/ether 00:1b:21:9d:4e:bb brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.73/24 brd 192.168.1.255 scope global eth1
    inet6 fe80::21b:21ff:fe9d:4ebb/64 scope link
       valid_lft forever preferred_lft forever
4: eth2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
    link/ether 00:1b:21:6a:c0:4b brd ff:ff:ff:ff:ff:ff
5: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc     pfifo_fast state UNKNOWN qlen 100
    link/none
    inet 10.32.0.50 peer 10.32.0.49/32 scope global tun0

Bearbeiten: Ich habe etwas zum Laufen gebracht, aber es leitet keine markierten Pakete an tun0 weiter. Grundsätzlich habe ich eine Tabelle (11) hinzugefügt und verwendet:

ip route add table 11 via 10.32.0.49 dev tun0
ip rule add priority 10000 fwmark 11 table 11

Wenn ich das gerade sudo -u user1000 wget -qO- whatismyip.orgmache sudo -u user1002 wget -qO- whatismyip.org, bekomme ich die externe IP-Adresse meines Hauses, aber wenn ich das tue , bekomme ich auch die IP-Adresse meines Hauses (aber ich sollte die IP am anderen Ende des OpenVPN-Tunnels bekommen).

Beim Ausführen wird iptables -vLbestätigt, dass die Pakete mit der Markierungsregel übereinstimmen, sie scheinen jedoch nicht der Routing-Regel zu entsprechen.

EDIT: Ich habe eine lange Zeit damit verbracht und obwohl es immer noch nicht funktioniert, denke ich, dass ich ein bisschen näher dran bin.

Die iptables-Regel muss sich in der mangleOUTPUT-Kette der Tabelle befinden. Ich denke, ich brauche auch eine MASQUERADE-Regel in der natPOSTROUTING-Kette der Tabelle, um die Quelladresse festzulegen. Die Umleitung, die nach der Störung von OUTPUT auftritt, funktioniert jedoch nicht richtig.

Ich habe jetzt 5 Stunden damit verbracht, deshalb mache ich eine Pause und werde wahrscheinlich später heute Abend oder irgendwann morgen darauf zurückkommen.

Ethan
quelle

Antworten:

26

Ich bin kürzlich auf ein ähnliches Problem gestoßen, wenn auch etwas anderes. Ich wollte nur TCP-Port 25 (SMTP) über eine OpenVPN-tap0-Schnittstelle routen, während der gesamte andere Datenverkehr (auch für denselben Host) über die Standardschnittstelle routet.

Dazu musste ich Pakete markieren und Regeln für den Umgang damit aufstellen. Fügen Sie zunächst eine Regel hinzu, mit der die Kernel-Routenpakete 2durch die Tabelle gekennzeichnet werden 3(wird später erläutert):

ip rule add fwmark 2 table 3

Sie hätten einen symbolischen Namen hinzufügen können /etc/iproute2/rt_tables, aber ich habe mich nicht darum gekümmert. Die Anzahl 2und 3werden zufällig ausgewählt. Tatsächlich können diese identisch sein, aber aus Gründen der Übersichtlichkeit habe ich dies in diesem Beispiel nicht getan (obwohl ich es in meinem eigenen Setup getan habe).

Fügen Sie eine Route für die Umleitung des Datenverkehrs über eine andere Schnittstelle hinzu, vorausgesetzt, das Gateway ist 10.0.0.1:

ip route add default via 10.0.0.1 table 3

Sehr wichtig! Leeren Sie den Routing-Cache, sonst erhalten Sie keine Antwort und sitzen einige Stunden mit den Händen im Haar:

ip route flush cache

Legen Sie nun eine Firewall-Regel zum Markieren von angegebenen Paketen fest:

iptables -t mangle -A OUTPUT -p tcp --dport 465 -j MARK --set-mark 2

Die obige Regel gilt nur, wenn die Pakete vom lokalen Computer stammen. Siehe http://inai.de/images/nf-packet-flow.png . Passen Sie es an Ihre Anforderungen an. Wenn Sie beispielsweise nur ausgehenden HTTP-Verkehr über die tap0Schnittstelle weiterleiten möchten , ändern Sie 465 in 80.

Um zu verhindern, dass die gesendeten Pakete tap0Ihre LAN-Adresse als Quell-IP erhalten, verwenden Sie die folgende Regel, um sie in Ihre Schnittstellenadresse zu ändern (vorausgesetzt 10.0.0.2als IP-Adresse für die Schnittstelle tap0):

iptables -t nat -A POSTROUTING -o tap0 -j SNAT --to-source 10.0.0.2

Zum Schluss lockern Sie die Validierung der Reverse Path-Quelle. Einige schlagen vor, es auf einzustellen 0, aber 2laut https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt scheint es eine bessere Wahl zu sein . Wenn Sie dies überspringen, erhalten Sie Pakete (dies kann mit bestätigt werden tcpdump -i tap0 -n), aber Pakete werden nicht akzeptiert. Der Befehl zum Ändern der Einstellung, damit Pakete akzeptiert werden:

sysctl -w net.ipv4.conf.tap0.rp_filter=2
Lekensteyn
quelle
Warum benutzt du SNAT anstelle von MASQUERADE? Tut MASQUERADE nicht dasselbe, außer dass die IP-Adresse zur "Laufzeit" von der Schnittstelle abgerufen und nicht fest in die Konfigurationsdatei codiert wird?
Ethan
6
@Ethan From man iptables: Diese Option sollte nur bei dynamisch zugewiesenen IP-Verbindungen (Einwählverbindungen) verwendet werden. Wenn Sie eine statische IP-Adresse haben, sollten Sie das SNAT-Ziel verwenden. Masquerading entspricht der Angabe einer Zuordnung zu der IP-Adresse der Schnittstelle, an die das Paket gesendet wird, hat jedoch auch den Effekt, dass Verbindungen vergessen werden, wenn die Schnittstelle ausfällt. Sie haben Recht, aber da sich meine IP-Adresse niemals ändern würde, habe ich mich für die Verwendung von SNAT auf Empfehlung der Manpage entschieden.
Lekensteyn
Ich denke (obwohl nicht getestet), ist der letzte Schritt (Reverse Path Source Validation) nicht notwendig. Sie können der PREROUTINGKette einfach eine weitere Regel zur DNATrichtigen Quelladresse hinzufügen (entsprechend Ihrem Standard-Gateway).
Christian Wolf
7

Ich habe das gelöst. Das Problem lag bei den Routing-Regeln in Tabelle 11. Tabelle 11 wurde zwar getroffen, ist aber aufgrund der Routing-Regeln nicht mehr funktionsfähig. Dieses Skript verwende ich jetzt und es scheint gut zu funktionieren (obwohl es offensichtlich spezifisch für mein Setup ist). Außerdem habe ich eine neue Tabelle 21 erstellt, die dem Haupt-Uplink (eth1) gewidmet ist.

# Add relevant iptables entries.
iptables -t mangle -A OUTPUT -m owner --uid-owner 1002 -j MARK --set-mark 11
iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE

# Flush ALL THE THINGS.
ip route flush table main
ip route flush table 11
ip route flush table 21
ip rule flush

# Restore the basic rules and add our own.
ip rule add lookup default priority 32767
ip rule add lookup main priority 32766
ip rule add fwmark 11 priority 1000 table 11
# This next rule basically sends all other traffic down eth1.
ip rule add priority 2000 table 21

# Restore the main table.  I flushed it because OpenVPN does weird things to it.
ip route add 127.0.0.0/8 via 127.0.0.1 dev lo
ip route add 192.168.1.0/24 dev eth1 src 192.168.1.73
ip route add default via 192.168.1.254

# Set up table 21.  This sends all traffic to eth1.
ip route add 192.168.1.0/24 dev eth1 table 21
ip route add default via 192.168.1.254 dev eth1 table 21

# Set up table 11.  I honestly don't know why 'default' won't work, or
# why the second line here is needed.  But it works this way.
ip route add 10.32.0.49/32 dev tun0 table 11
ip route add 10.32.0.1 via 10.32.0.50 dev tun0 table 11
ip route add 0.0.0.0/1 via 10.32.0.50 dev tun0 table 11

ip route flush cache

## MeanderingCode edit (da ich noch keinen Kommentar abgeben kann)

Danke für diese Antwort! Es sieht so aus, als ob dies chaotisch werden könnte, da Sie die Routeninformationen hier pflegen müssten (möglicherweise duplizieren oder andere Dinge brechen, die Routen festlegen möchten).

Es kann sein, dass OpenVPN "seltsame Dinge" in Ihrer Routingtabelle anzeigt, da der Server so konfiguriert ist, dass er Routen "pusht", sodass der gesamte Datenverkehr über die VPN-Netzwerkschnittstelle und nicht über das "bloße" Internet geleitet werden kann. Oder Ihre OpenVPN-Konfiguration oder das von ihr eingerichtete Skript / Programm legt Routen fest.

Im ersten Fall können Sie Ihre OpenVPN - Konfiguration und in einer Zeile mit „route-nopull“ bearbeiten
In letzterem Check - Konfiguration für OpenVPN oder jede Wrapper (network-manager-openvpn, zum Beispiel auf vielen aktuellen Linux - Desktop - Distributionen)
in In beiden Fällen ist es sauberer und sicherer, die Routing-Konfiguration zu entfernen, in der sie eingerichtet wird, als die Tabelle zu leeren. Dies hängt davon ab, wann Sie dieses Skript ausführen und was Ihr System sonst noch tut.

Prost!

Ethan
quelle
2

Ich denke du willst:

/sbin/ip route add default via 10.32.0.49 dev tun0 table 11
/sbin/ip rule add priority 10000 fwmark 11 table 11

http://lartc.org/howto/lartc.netfilter.html

Aber ich habe das oben nicht getestet.

mfarver
quelle
Der erste Befehl gibt "Fehler: Entweder" bis "ist doppelt, oder" 10.32.0.49 "ist ein Müll."
Ethan
Sorry habe das via zwischen default und der IP vergessen.
mfarver
Ich versuchte es. Es scheint den gleichen Effekt zu haben wie das Auslassen des defaultSchlüsselworts.
Ethan
Um Optionen zu eliminieren, können Sie versuchen, auf tun0 eine Paketerfassung durchzuführen und festzustellen, ob Pakete auf dieser Schnittstelle landen. tcpdump -i tun0 .. alternativ müssen Sie es auf Benutzer-ID basieren? Könnten Sie dies einfach anhand der Ziel-IP-Adresse tun (einfacher)? route add <remote host> via 10.32.0.49
mfarver
Ich kann mich nicht auf die Ziel-IP-Adresse stützen - es würde viele davon geben. Ich könnte es theoretisch auch mit pid begründen, aber das ist noch schwieriger, da ich die pid erst kenne, wenn die Daemons starten.
Ethan
0

Dies kann ohne den Befehl iptables erfolgen. Führen Sie einen einfachen Befehl ip aus

Für UID 1002:

ip rule add uidrange 1002-1002 table 502

Fügen Sie die Standardroute für Tabelle 502 über die gewünschte Schnittstelle hinzu

eth0 ip rule add default via a.b.c.d dev eth0
Jainendra
quelle
Ich habe diesen Befehl getestet und er hat nicht funktioniert:Error: argument "uidrange" is wrong: Failed to parse rule type
kasperd 30.12.15
@kasperd du musst er falsch gemacht haben, denn es funktioniert gut für mich.
Horseyguy