iptables - Cel skierować pakiet do określonego interfejsu?

25

Mój serwer domowy ma dwa główne interfejsy eth1(standardowe połączenie internetowe) i tun0(tunel OpenVPN). Chciałbym użyć, iptablesaby wymusić wyjście wszystkich pakietów wygenerowanych przez proces lokalny posiadany przez UID 1002 tun0i wszystkich innych pakietów do wyjścia eth1.

Mogę łatwo oznaczyć dopasowane pakiety:

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

Teraz chciałbym umieścić jakąś regułę w łańcuchu POSTROUTING (prawdopodobnie tabeli maglowania), aby dopasować pakiety oznaczone 11 i wysłać je do tun0, a następnie regułę, która pasuje do wszystkich pakietów i wysłać je do eth1.

Znalazłem cel ROUTE, ale wydaje się, że przepisuje tylko interfejs źródłowy (chyba że czytam go niepoprawnie).

Czy iptables jest w stanie to zrobić? Czy zamiast tego muszę zadzierać z tablicą routingu (za ip routepomocą zwykłych routepoleceń)?

Edycja: Pomyślałem, że może powinienem podać więcej informacji. Nie mam obecnie żadnych innych reguł iptables (chociaż mogę stworzyć pewne reguły, aby wykonywać niepowiązane zadania w przyszłości). Ponadto dane wyjściowe ip routeto:

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

Nie dotknąłem tabeli routingu - tak właśnie jest obecnie (choć wygląda dość brudno). Przykro mi, ale nie mam routezainstalowanego starszego polecenia na tym komputerze.

Wyjście ip addr(oczywiście eth0 i eth2 można zignorować - są to karty sieciowe, które nie są obecnie używane):

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

Edycja: Mam coś w rodzaju pracy, ale to nie jest przekazywanie oznaczonych pakietów do tun0. Zasadniczo dodałem tabelę (11) i użyłem:

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

Kiedy tylko sudo -u user1000 wget -qO- whatismyip.orgdostaję zewnętrzny adres IP mojego domu, ale jeśli to zrobię sudo -u user1002 wget -qO- whatismyip.org, dostaję także adres IP mojego domu (ale powinienem otrzymywać adres IP na drugim końcu tunelu OpenVPN).

Uruchomienie iptables -vLpotwierdza, że ​​pakiety są dopasowywane przez regułę znakowania, ale wydaje się, że nie są zgodne z regułą routingu.

EDYCJA: Spędziłem nad tym dużo czasu i chociaż nadal nie działa, myślę, że jestem trochę bliżej.

Reguła iptables musi znajdować się w manglełańcuchu WYJŚCIA tabeli. Myślę, że potrzebuję również reguły MASQUERADE w natłańcuchu POSTROUTING tabeli, aby ustawić adres źródłowy. Jednak przekierowanie, które występuje po maglecie OUTPUT, nie działa poprawnie.

Spędziłem na tym teraz 5 godzin, więc robię sobie przerwę i pewnie wrócę do niej później wieczorem lub jutro.

Ethan
źródło

Odpowiedzi:

26

Ostatnio natrafiłem na podobny problem, choć nieco inny. Chciałem przekierować tylko port TCP 25 (SMTP) przez interfejs tap0 OpenVPN, kierując cały pozostały ruch (nawet dla tego samego hosta) przez interfejs domyślny.

Aby to zrobić, musiałem oznaczyć pakiety i ustalić zasady ich obsługi. Najpierw dodaj regułę, która powoduje, że pakiety trasy jądra są oznaczone 2tabelą przelotową 3(wyjaśnione dalej):

ip rule add fwmark 2 table 3

Mogłeś dodać symboliczną nazwę /etc/iproute2/rt_tables, ale nie zawracałem sobie tym głowy. Liczba 2i 3są wybierane losowo. W rzeczywistości mogą być takie same, ale dla jasności nie zrobiłem tego w tym przykładzie (chociaż robię to we własnej konfiguracji).

Dodaj trasę przekierowywania ruchu przez inny interfejs, zakładając, że brama jest 10.0.0.1:

ip route add default via 10.0.0.1 table 3

Bardzo ważne! Opróżnij pamięć podręczną routingu, w przeciwnym razie nie otrzymasz odpowiedzi i nie będziesz siedzieć z rękami we włosach przez kilka godzin:

ip route flush cache

Teraz ustaw regułę zapory do oznaczania wyznaczonych pakietów:

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

Powyższa zasada ma zastosowanie tylko wtedy, gdy pakiety pochodzą z komputera lokalnego. Zobacz http://inai.de/images/nf-packet-flow.png . Dostosuj go do swoich wymagań. Na przykład, jeśli chcesz kierować wychodzący ruch HTTP przez tap0interfejs, zmień 465 na 80.

Aby zapobiec wysyłaniu pakietów przez tap0uzyskanie adresu LAN jako źródłowego adresu IP, użyj następującej reguły, aby zmienić go na adres interfejsu (zakładając, że 10.0.0.2jest to adres IP interfejsu tap0):

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

Na koniec zrelaksuj sprawdzanie poprawności źródła ścieżki zwrotnej. Niektórzy sugerują, aby to ustawić 0, ale 2wydaje się lepszym wyborem według https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt . Jeśli pominiesz to, otrzymasz pakiety (można to potwierdzić za pomocą tcpdump -i tap0 -n), ale pakiety nie zostaną zaakceptowane. Polecenie zmiany ustawienia, aby pakiety zostały zaakceptowane:

sysctl -w net.ipv4.conf.tap0.rp_filter=2
Lekensteyn
źródło
Dlaczego używasz SNAT zamiast MASQUERADE? Czy MASQUERADE nie robi tego samego, z wyjątkiem tego, że adres IP jest zbierany z interfejsu w „środowisku wykonawczym” i nie jest zapisany na stałe w pliku konfiguracyjnym?
Ethan
6
@Ethan From man iptables: Powinno być używane tylko z dynamicznie przypisywanymi połączeniami IP (dialup): jeśli masz statyczny adres IP, powinieneś użyć celu SNAT. Maskarada jest równoważna z określeniem mapowania na adres IP interfejsu, z którego wychodzi pakiet, ale powoduje również, że połączenia są zapominane, gdy interfejs się psuje. Masz rację, ale ponieważ moje IP nigdy się nie zmieni, postanowiłem użyć SNAT zgodnie z zaleceniami strony man.
Lekensteyn
Myślę, że (chociaż nie przetestowano) ostatni krok (sprawdzanie źródła ścieżki odwrotnej) nie jest konieczny. Możesz po prostu dodać kolejną regułę do PREROUTINGłańcucha do DNATpoprawnego adresu źródłowego (zgodnie z domyślną bramą).
Christian Wolf
7

Rozwiązałem to. Problem dotyczył reguł routingu z tabeli 11. Tabela 11 została trafiona, ale reguły routingu uniemożliwiają jej działanie. Teraz używam tego skryptu i wydaje się, że działa dobrze (choć oczywiście jest specyficzny dla mojej konfiguracji). Stworzyłem także nową tabelę 21 poświęconą głównemu łączu w górę (eth1).

# 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

## Edycja kodu Meandering (ponieważ nie mogę jeszcze komentować)

Dzięki za tę odpowiedź! Wygląda na to, że może się to popsuć, ponieważ musisz tutaj zachować informacje o trasie (możliwe powielanie lub łamanie innych rzeczy, które mogą chcieć ustawić trasy).

Być może występują „dziwne rzeczy” w tabeli routingu z OpenVPN, ponieważ serwer jest skonfigurowany do „wypychania” tras, umożliwiając cały ruch do kierowania przez interfejs sieci VPN, a nie „czysty” internet. Lub twoja konfiguracja OpenVPN lub jakikolwiek skonfigurowany skrypt / aplikacja ustawia trasy.

W pierwszym przypadku można edytować konfigurację OpenVPN i umieścić w linii zawierającej „Route-nopull”
W tym ostatnim, konfiguracji wyboru dla OpenVPN lub owijki (network-manager-openvpn, na przykład na wielu obecnych dystrybucjach Linux Desktop)
Miejscowość w obu przypadkach wyeliminowanie konfiguracji routingu, w której się ustawia, jest czystsze i bezpieczniejsze niż opróżnianie tabeli, w zależności od tego, kiedy uruchomisz ten skrypt i co jeszcze robi Twój system.

Twoje zdrowie!

Ethan
źródło
2

Myślę, że chcesz:

/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

Ale nie testowałem powyższego.

mfarver
źródło
Pierwsze polecenie zwraca „Błąd: albo„ do ”jest zduplikowane lub„ 10.32.0.49 ”jest śmieciem.”
Ethan
Przepraszam, zapomniałem o wartości domyślnej między adresem domyślnym a adresem IP.
mfarver
Próbowałem tego. Wydaje się, że ma taki sam efekt jak pominięcie defaultsłowa kluczowego.
Ethan
Aby wyeliminować opcje, możesz spróbować przechwycić pakiet na tun0 i sprawdzić, czy pakiety kończą się na tym interfejsie. tcpdump -i tun0 .. alternatywnie, czy musisz oprzeć go na identyfikatorze użytkownika? Czy możesz to zrobić na podstawie docelowego adresu IP (łatwiej)? route add <host zdalny> przez 10.32.0.49
mfarver
Nie mogę bazować, jeśli nie na docelowym adresie IP - byłoby ich wiele. Mógłbym również teoretycznie oprzeć go na pid, ale jest to jeszcze trudniejsze, ponieważ nie poznam pid, dopóki demony nie wystartują.
Ethan
0

Można to zrobić bez polecenia iptables Wykonaj proste polecenie ip

Dla UID 1002:

ip rule add uidrange 1002-1002 table 502

Dodaj domyślną trasę dla tabeli 502 przez interfejs, który chcesz powiedzieć

eth0 ip rule add default via a.b.c.d dev eth0
jainendra
źródło
Przetestowałem to polecenie i nie zadziałało:Error: argument "uidrange" is wrong: Failed to parse rule type
kasperd
@kasperd, musiałeś robić to źle, bo to działa dobrze dla mnie.
horseyguy