Puoi avviare il collegamento OpenVPN all'interno di uno spazio dei nomi e quindi eseguire tutti i comandi che desideri utilizzare quel collegamento OpenVPN all'interno dello spazio dei nomi. I dettagli su come farlo sono presentati in Esecuzione di un tunnel OpenVPN all'interno di uno spazio dei nomi di rete, di Sebastian Thorarensen.
L'ho provato e funziona. L'idea è quella di fornire uno script personalizzato per eseguire le fasi di up e route-up della connessione OpenVPN all'interno di uno spazio dei nomi specifico invece che globale. Ecco una risposta basata sulla fonte sopra, ma modificata per aggiungere Google DNS a resolv.conf
.
Per prima cosa crea un --up script per OpenVPN. Questo script creerà l'interfaccia del tunnel VPN all'interno di uno spazio dei nomi di rete chiamato vpn , invece dello spazio dei nomi predefinito.
$ cat > netns-up << 'EOF' #!/bin/sh case $script_type in up) ip netns add vpn ip netns exec vpn ip link set dev lo up mkdir -p /etc/netns/vpn echo "nameserver 8.8.8.8" > /etc/netns/vpn/resolv.conf ip link set dev "$1" up netns vpn mtu "$2" ip netns exec vpn ip addr add dev "$1" \ "$4/${ifconfig_netmask:-30}" \ ${ifconfig_broadcast:+broadcast "$ifconfig_broadcast"} test -n "$ifconfig_ipv6_local" && \ ip netns exec vpn ip addr add dev "$1" \ "$ifconfig_ipv6_local"/112 ;; route-up) ip netns exec vpn ip route add default via "$route_vpn_gateway" test -n "$ifconfig_ipv6_remote" && \ ip netns exec vpn ip route add default via \ "$ifconfig_ipv6_remote" ;; down) ip netns delete vpn ;; esac EOF
Quindi avvia OpenVPN e digli di utilizzare il nostro --up script invece di eseguire ifconfig e route.
openvpn --ifconfig-noexec --route-noexec --up netns-up --route-up netns-up --down netns-up
Ora puoi avviare i programmi da incanalare in questo modo:
ip netns exec vpn command
L'unico problema è che devi essere root per invocare ip netns exec ...
e forse non vuoi che la tua applicazione venga eseguita come root. La soluzione è semplice:
sudo ip netns exec vpn sudo -u $(whoami) command
Si scopre che puoi inserire un'interfaccia tunnel in uno spazio dei nomi di rete. Tutto il mio problema era dovuto a un errore nel richiamare l'interfaccia:
ip addr add dev $tun_tundv \
local $ifconfig_local/$ifconfig_cidr \
broadcast $ifconfig_broadcast \
scope link
Il problema è "collegamento ambito", che ho frainteso in quanto riguarda solo il routing. Fa sì che il kernel imposti l'indirizzo di origine di tutti i pacchetti inviati nel tunnel a 0.0.0.0
; presumibilmente il server OpenVPN li eliminerebbe quindi come non validi per RFC1122; anche se così non fosse, la destinazione ovviamente non sarebbe in grado di rispondere.
Tutto ha funzionato correttamente in assenza di spazi dei nomi di rete perché lo script di configurazione di rete integrato di openvpn non ha commesso questo errore. E senza "scope link", anche il mio script originale funziona.
(Come l'ho scoperto, chiedi? Eseguendo strace
sul processo openvpn, imposta su hexdump tutto ciò che legge dal descrittore del tunnel, quindi decodifica manualmente le intestazioni del pacchetto.)
L'errore nel tentativo di creare i dispositivi veth è causato da un cambiamento di come ip
interpreta gli argomenti della riga di comando.
La corretta invocazione di ip
creare una coppia di dispositivi veth è
ip link add name veth0 type veth peer name veth1
(name
invece di dev
)
Ora, come far uscire il traffico dallo spazio dei nomi al tunnel VPN? Poiché hai a disposizione solo dispositivi tun, l'"host" deve instradare. Cioè. creare la coppia veth e inserirne una nello spazio dei nomi. Connetti l'altro tramite routing al tunnel. Pertanto, abilita l'inoltro e quindi aggiungi i percorsi necessari.
Per esempio supponiamo che eth0
è la tua interfaccia principale, tun0
è la tua interfaccia del tunnel VPN e veth0
/veth1
la coppia di interfacce di cui veth1
è nello spazio dei nomi. All'interno dello spazio dei nomi aggiungi solo un percorso predefinito per veth1
.
Sull'host è necessario utilizzare l'instradamento dei criteri, ad esempio vedere qui. Cosa devi fare:
Aggiungi/aggiungi una voce come
1 vpn
a /etc/iproute2/rt_tables
. Con questo puoi chiamare la tabella (ancora da creare) per nome.
Quindi utilizzare le seguenti istruzioni:
ip rule add iif veth0 priority 1000 table vpn
ip rule add iif tun0 priority 1001 table vpn
ip route add default via <ip-addr-of-tun0> table vpn
ip route add <ns-network> via <ip-addr-of-veth0> table vpn
Non posso provarlo qui con una configurazione come la tua, ma questo dovrebbe fare esattamente quello che vuoi. Puoi aumentarlo con regole di filtro dei pacchetti tali che né la VPN né la rete "ospite" siano disturbate.
N.B. Spostamento di tun0
nello spazio dei nomi in primo luogo sembra la cosa giusta da fare. Ma come te non l'ho fatto funzionare. Il policy routing sembra la prossima cosa giusta da fare. La soluzione di Mahendra è applicabile se conosci le reti dietro la VPN e tutte le altre applicazioni non accederanno mai a tali reti. Ma la tua condizione iniziale ("tutto il traffico e solo il traffico, verso/da specifici processi passa attraverso la VPN") sembra che quest'ultima non possa essere garantita.