iptables - Destinazione per instradare il pacchetto verso un'interfaccia specifica?


25

Il mio server di casa ha due interfacce principali, eth1(una connessione Internet standard) e tun0(un tunnel OpenVPN). Vorrei usare iptablesper forzare l'uscita di tutti i pacchetti generati da un processo locale di proprietà dell'UID 1002 tun0e tutti gli altri pacchetti eth1.

Posso facilmente contrassegnare i pacchetti abbinati:

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

Ora, vorrei mettere alcune regole nella catena POSTROUTING (probabilmente della tabella mangle) per abbinare i pacchetti contrassegnati con 11 e inviarli a tun0, seguiti da una regola che corrisponda a tutti i pacchetti e li invii a eth1.

Ho trovato il target ROUTE, ma sembra riscrivere solo l'interfaccia di origine (a meno che non lo stia leggendo in modo errato).

Iptables è in grado di farlo? Devo invece scherzare con la tabella di routing (tramite ip routeo solo i routecomandi legacy )?

Modifica: ho pensato che forse avrei dovuto fornire ulteriori informazioni. Non ho altre regole iptables al momento (anche se potrei creare alcune regole per svolgere attività non correlate in futuro). Inoltre, l'output di 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

Non ho toccato la tabella di routing - questo è come è attualmente (anche se sembra abbastanza sporco). Mi dispiace, ma non ho il routecomando legacy installato su questa macchina.

E l'output di ip addr(ovviamente, eth0 ed eth2 può essere ignorato - sono schede di rete che al momento non vengono utilizzate):

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

Modifica: ho ottenuto qualcosa che funziona, ma non sta inoltrando pacchetti contrassegnati a tun0. In sostanza, ho aggiunto una tabella (11) e usato:

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

Appena sudo -u user1000 wget -qO- whatismyip.orgottengo l'indirizzo IP esterno della mia casa, ma se lo faccio sudo -u user1002 wget -qO- whatismyip.org, ottengo anche l'indirizzo IP della mia casa (ma dovrei ottenere l'IP dall'altra parte del tunnel OpenVPN).

L'esecuzione iptables -vLconferma che i pacchetti vengono abbinati dalla regola di marcatura, ma non sembrano seguire la regola di routing.

EDIT: ho trascorso molto tempo su questo, e anche se ancora non funziona, penso di essere un po 'più vicino.

La regola iptables deve essere nella manglecatena OUTPUT della tabella. Penso di aver bisogno anche di una regola MASQUERADE nella natcatena POSTROUTING della tabella, per impostare l'indirizzo di origine. Tuttavia, il reinstradamento che si verifica dopo il mangle di OUTPUT non funziona correttamente.

Ho trascorso 5 ore su questo ora, quindi sto facendo una pausa e probabilmente ci tornerò più tardi stasera o domani.

Risposte:


26

Di recente ho riscontrato un problema simile, anche se leggermente diverso. Volevo instradare solo la porta TCP 25 (SMTP) su un'interfaccia tap0 OpenVPN, mentre instradavo tutto il resto del traffico (anche per lo stesso host) sull'interfaccia predefinita.

Per fare ciò, ho dovuto contrassegnare i pacchetti e impostare le regole per gestirli. Innanzitutto, aggiungi una regola che renda i pacchetti della route del kernel contrassegnati con la 2tabella through 3(spiegata più avanti):

ip rule add fwmark 2 table 3

Avresti potuto aggiungere un nome simbolico a /etc/iproute2/rt_tables, ma non mi sono preoccupato di farlo. Il numero 2e 3sono scelti casualmente. In effetti, questi possono essere gli stessi, ma per chiarezza non l'ho fatto in questo esempio (anche se lo faccio nella mia configurazione).

Aggiungi una route per reindirizzare il traffico su un'interfaccia diversa, supponendo che il gateway sia 10.0.0.1:

ip route add default via 10.0.0.1 table 3

Molto importante! Svuota la cache del routing, altrimenti non otterrai una risposta e ti siederai con le mani tra i capelli per alcune ore:

ip route flush cache

Ora, imposta una regola firewall per contrassegnare i pacchetti designati:

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

La regola sopra si applica solo se i pacchetti provengono dal computer locale. Vedi http://inai.de/images/nf-packet-flow.png . Adattalo alle tue esigenze. Ad esempio, se si desidera instradare solo il traffico HTTP in uscita tap0sull'interfaccia, modificare 465 su 80.

Per impedire ai pacchetti inviati di tap0ottenere l'indirizzo LAN come IP di origine, utilizzare la seguente regola per cambiarlo nell'indirizzo dell'interfaccia (assumendo 10.0.0.2come indirizzo IP per l'interfaccia tap0):

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

Infine, rilassare la convalida della sorgente del percorso inverso. Alcuni suggeriscono di impostarlo su 0, ma 2sembra una scelta migliore secondo https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt . Se salti questo, riceverai pacchetti (questo può essere confermato usando tcpdump -i tap0 -n), ma i pacchetti non vengono accettati. Il comando per modificare l'impostazione in modo che i pacchetti vengano accettati:

sysctl -w net.ipv4.conf.tap0.rp_filter=2

Perché usi SNAT invece di MASQUERADE? MASQUERADE non fa la stessa cosa, tranne che l'indirizzo IP viene raccolto dall'interfaccia in "runtime" e non codificato nel file di configurazione?
Ethan,

6
@Ethan From man iptables: deve essere utilizzato solo con connessioni IP (dialup) assegnate dinamicamente: se si dispone di un indirizzo IP statico, è necessario utilizzare la destinazione SNAT. Il mascheramento equivale a specificare un mapping all'indirizzo IP dell'interfaccia in cui il pacchetto sta uscendo, ma ha anche l'effetto di dimenticare le connessioni quando l'interfaccia si interrompe. Hai ragione, ma dal momento che il mio IP non cambierebbe mai, ho deciso di usare SNAT per raccomandazione da parte della manpage.
Lekensteyn,

Penso che (sebbene non testato) l'ultimo passaggio (validazione della sorgente del percorso inverso) non sia necessario. È possibile semplicemente aggiungere un'altra regola alla PREROUTINGcatena all'indirizzo DNATdi origine corretto (in base al gateway predefinito).
Christian Wolf,

7

Ho risolto questo. Il problema era con le regole di routing nella tabella 11. La tabella 11 veniva colpita, ma le regole di routing lo rendono inoperabile. Questo script è quello che uso ora e sembra funzionare bene (anche se ovviamente è specifico per la mia configurazione). Inoltre, ho creato una nuova tabella 21 dedicata all'uplink principale (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

## MeanderingCode edit (perché non posso ancora commentare)

Grazie per questa risposta! Sembra che questo potrebbe diventare disordinato, dal momento che dovresti mantenere le informazioni sul percorso qui (possibilmente duplicando o rompendo altre cose che potrebbero voler impostare percorsi.

Potresti riscontrare "cose ​​strane" nella tua tabella di routing da OpenVPN perché il server è configurato per "spingere" le rotte, consentendo a tutto il traffico di instradare attraverso l'interfaccia di rete VPN, anziché Internet "nuda". O la tua configurazione OpenVPN o qualunque script / applicazione configuri sta impostando rotte.

Nel primo caso, è possibile modificare la configurazione di OpenVPN e inserire una riga contenente "route-nopull".
Nel secondo, controllare la configurazione di OpenVPN o qualsiasi wrapper (network-manager-openvpn, ad esempio su molte distribuzioni desktop Linux attuali)
In in entrambi i casi, l'eliminazione della configurazione di routing in cui viene impostata è più pulita e sicura rispetto allo svuotamento della tabella, a seconda di quando si esegue questo script e di cos'altro sta facendo il sistema.

Saluti!


2

Penso che tu voglia:

/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

Ma non ho testato quanto sopra.


Il primo comando restituisce "Errore:" a "è duplicato o" 10.32.0.49 "è un rifiuto."
Ethan,

Siamo spiacenti, ho dimenticato il via tra predefinito e IP.
mfarver,

L'ho provato. Sembra avere lo stesso effetto di lasciare la defaultparola chiave fuori.
Ethan,

Per eliminare le opzioni potresti provare a fare un'acquisizione di pacchetti su tun0 e vedere se i pacchetti stanno finendo su quell'interfaccia. tcpdump -i tun0 .. in alternativa, devi basarlo sull'ID utente? Potresti farlo in base all'indirizzo IP di destinazione (più semplice)? route aggiungi <host remoto> via 10.32.0.49
mfarver

Non posso basarmi se fuori dall'indirizzo IP di destinazione - ce ne sarebbero molti. Potrei anche teoricamente basarlo su pid, ma questo è ancora più difficile, perché non conoscerò il pid fino all'avvio del daemon.
Ethan,

0

Questo può essere fatto senza il comando iptables Esegue il comando ip semplice

Per uid 1002:

ip rule add uidrange 1002-1002 table 502

Aggiungi il percorso predefinito per la tabella 502 sull'interfaccia che vuoi dire

eth0 ip rule add default via a.b.c.d dev eth0

Ho testato quel comando, e non ha funzionato:Error: argument "uidrange" is wrong: Failed to parse rule type
Kasperd il

@kasperd devi aver sbagliato, perché funziona bene per me.
Horseyguy,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.