Instradare il traffico su un'interfaccia specifica per un processo in Linux


20

È possibile instradare il traffico utilizzato da un processo su un'interfaccia specifica?

Ad esempio, il traffico di rete per applicazione di download dovrebbe sempre utilizzare l'interfaccia wlan0mentre tutte le altre applicazioni sulla macchina dovrebbero usare eth0.

È possibile avere questo tipo di regola in Linux?

Risposte:


22

Può essere fatto usando gli spazi dei nomi di rete Linux.

Ecco un articolo che spiega come. Fondamentalmente si crea uno spazio dei nomi di rete con una route predefinita diversa e si eseguono i processi che ne hanno bisogno lì. Connetti lo spazio dei nomi di rete appena creato all'adattatore fisico con un bridge (ma ovviamente sono possibili altre soluzioni).

Aggiornamento: dal kernel 3.14 è ancora più facile usare i gruppi di controllo, come descritto in questo articolo . Devi:

1) definire un gruppo di controllo net_cls per annotare i pacchetti da un determinato processo con un classid (o un gruppo di processi, si noti che non deve esserci alcuna relazione genitore-figlio tra di loro)

2) utilizzare il modulo cgroup iptables (aggiunto in Linux 3.14) per contrassegnare i pacchetti

3) utilizzare il routing dei criteri (regola ip aggiungere fwmark ....) per creare una nuova tabella di routing per i pacchetti contrassegnati

Il vantaggio è che non dobbiamo fare il ponte e tutto è molto più dinamico grazie ai cgroups.


14

Ho davvero lottato con questo, quindi ecco una soluzione COMPLETA. È testato su Ubuntu 15 e 16. Puoi usarlo in particolare con OpenVPN per indirizzare determinate app al di fuori dell'interfaccia del tunnel VPN.

La soluzione completa "cgroup"

Come funziona?

  • Il kernel Linux inserirà l'app in un gruppo di controllo . Il traffico di rete dalle app in questo cgroup verrà identificato dall'ID classe a livello del controller di rete.
  • iptables segnerà questo traffico e lo costringerà ad uscire con l'IP giusto
  • ip route elaborerà il traffico contrassegnato in una tabella di routing diversa, con una route predefinita a qualsiasi IP gateway desiderato.

Script automatizzato

Ho creato uno script novpn.sh per automatizzare l'installazione e l'esecuzione delle dipendenze. Testato su Ubuntu.

Avvia prima la tua VPN.

wget https://gist.githubusercontent.com/kriswebdev/a8d291936fe4299fb17d3744497b1170/raw/cf8b37fbe6c3f50a0be825eb77cafa3e0134946f/novpn.sh
# If you don't use eth0, edit the script setting.
sudo chmod +x novpn.sh
./novpn.sh traceroute www.google.com
./novpn.sh --help

Manuale HowTo

Innanzitutto, installa il supporto e gli strumenti di cgroup:

sudo apt-get install cgroup-lite cgmanager cgroup-tools

Riavvia (potrebbe non essere necessario).

Hai bisogno di iptables 1.6 .0+. Ottieni il sorgente di rilascio iptables 1.6.0 , estrailo, quindi esegui questo ( --disable-nftablesflag eviterà errori) dalla directory dei sorgenti di iptables:

sudo apt-get install dh-autoreconf bison flex
./configure --prefix=/usr      \
            --sbindir=/sbin    \
            --disable-nftables \
            --enable-libipq    \
            --with-xtlibdir=/lib/xtables
make
sudo make install
iptables --version

Ora, la vera configurazione. Definire un gruppo di controllo denominato novpn. I processi in questo cgroup avranno un classid di 0x00110011(11:11).

sudo su
mkdir /sys/fs/cgroup/net_cls/novpn
cd /sys/fs/cgroup/net_cls/novpn
echo 0x00110011 > net_cls.classid

Ora supponiamo che l'interfaccia che desideri utilizzare per l'app specifica abbia eth0un IP gateway di 10.0.0.1. Sostituiscili con ciò che vuoi veramente (ottieni le informazioni da ip route). Esegui ancora come root:

# Add mark 11 on packets of classid 0x00110011
iptables -t mangle -A OUTPUT -m cgroup --cgroup 0x00110011 -j MARK --set-mark 11

# Force the packets to exit through eth0 with NAT
iptables -t nat -A POSTROUTING -m cgroup --cgroup 0x00110011 -o eth0 -j MASQUERADE

# Define a new "novpn" routing table
# DO THIS JUST ONCE !
echo 11 novpn >> /etc/iproute2/rt_tables

# Packets with mark 11 will use novpn
ip rule add fwmark 11 table novpn

# Novpn has a default gateway to the interface you want to use
ip route add default via 10.0.0.1 table novpn

# Unset reverse path filtering for all interfaces, or at least for "eth0" and "all"
for i in /proc/sys/net/ipv4/conf/*/rp_filter; do echo 0 > $i; done

Infine, esegui la tua app sull'interfaccia specifica:

exit
sudo cgcreate -t $USER:$USER -a $USER:$USER -g net_cls:novpn
cgexec -g net_cls:novpn traceroute www.google.com
# Close all Firefox windows first
cgexec -g net_cls:novpn firefox

O se vuoi spostare un processo già in esecuzione nel cgroup, beh ... non puoi! Ciò sembra essere dovuto alla funzione NAT (mascherata): iptables -nvL -t natnon corrisponde quando il cgroup viene cambiato, ma iptables -nvL -t manglecorrisponde.

# Get PID of the process (we'll then suppose it's 1234)
pidof firefox
# Add to cgroup - THIS DOESN'T WORK! Silently fails to produce the final result.
sudo echo 1234 > /sys/fs/cgroup/net_cls/novpn/tasks
# Remove - but this works...
sudo echo 1234 > /sys/fs/cgroup/net_cls

Riconoscimenti: nessuna risposta funzionava come previsto, ma un mix di loro ha funzionato: risposta chripell articolo evolware Per routing di processo prendere 2: utilizzo di cgroups, iptables e routing di criteri , come faccio a fare in modo che un processo specifico NON passi attraverso una connessione OpenVPN? , Uccidi l'interruttore per OpenVPN sulla base di iptables


Grazie per l'ottima risposta, come faccio a farlo funzionare con Apache? Ho provato cgexec -g net_cls:novpn apache2e mi ha dato un intero elenco di errori variabili indefiniti!
razzak,

2
Otterrai gli stessi errori eseguendo apache2direttamente dal terminale. Questo perché apache2viene normalmente lanciato come servizio, con systemctl start apache2. Tuttavia, non funzionerà con cgexec. Il programma chiamato deve essere un genitore del apache2processo desiderato ( ) per la propagazione del cgroup net_cls. Quindi è necessario trovare lo script di avvio. In questo caso, lo è sudo cgexec -g net_cls:novpn /usr/sbin/apache2ctl start. Verificare con ./novpn.sh --list.
KrisWebDev,

Non funziona più in Ubuntu 16.04!
razzak,

2
Lo sto usando su Ubuntu 16.04 e funziona benissimo. I nomi delle interfacce sono cambiati in Ubuntu 16, potrebbe essere necessario sostituirli eth0con qualcosa di simile enp7s0. Ottieni le informazioni dal ifconfigcomando.
KrisWebDev,

Grazie. Ma non funziona su Ubuntu 18.04 perché cpmanager è stato rimosso a causa di un conflitto con systemd
skonsoft il


3

Combinando le eccellenti risposte di mariusmatutiae e KrisWebDev ho creato una versione ampiamente modificata dell'eccellente novpn.shscript di KrisWebDev . Mentre lo script di KrisWebDev è progettato per eliminare un prurito più specifico (esecuzione e spostamento di processi all'interno / all'esterno di una VPN), la mia versione ti consente di eseguire praticamente qualsiasi comando in un ambiente di rete specificato. Puoi specificare l'interfaccia a cui associare, la route predefinita, specificare le tue regole iptables, route statiche, specificare un "test" per confermare che tutto funzioni come desideri prima di eseguire il comando ... ecc.). Ti consente di utilizzare più file di configurazione in modo da poter definire un numero qualsiasi di specifici ambienti di rete in cui è possibile eseguire comandi / processi all'interno.

L'ho pubblicato come una sintesi qui: https://gist.github.com/level323/54a921216f0baaa163127d960bfebbf0

In seguito può persino ripulire le tabelle cgroup / iptables / routing!

Feedback di benvenuto.

PS - È progettato per Debian 8 (Jessie)


Ciao @allnatural, vorrei usare il tuo script altnetworking.sh, ma cosa dovrei inserire nel file di configurazione?
Cris70,

0

Non per applicazione, no. Puoi farlo per porta o per indirizzo IP ecc. Oppure un'applicazione stessa può associarsi (e utilizzare) una scheda di rete specifica.

Tuttavia, non puoi impostare una regola per farlo.


Ho un'applicazione Java, è possibile associare tale app a un'interfaccia?
Suresh,

Un'applicazione Java per cui hai il codice sorgente e puoi riprogrammare gli interni?
Majenko,

Ho un codice sorgente dell'applicazione Java che utilizza la libreria http di Apache.
Suresh,

Quindi vorrei andare su StackOverflow.com e chiedere ai programmatori lì come modificare il programma. Non ho mai programmato in Java.
Majenko,
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.