Sie können den OpenVPN-Link innerhalb eines Namespace starten und dann jeden Befehl ausführen, den Sie verwenden möchten, um diesen OpenVPN-Link innerhalb des Namespace zu verwenden. Einzelheiten dazu finden Sie in Running an OpenVPN tunnel within a network namespace von Sebastian Thorarensen.
Ich habe es versucht und es funktioniert. Die Idee ist, ein benutzerdefiniertes Skript bereitzustellen, um die Up- und Routing-Phasen der OpenVPN-Verbindung innerhalb eines bestimmten Namespace statt des globalen auszuführen. Hier ist eine Antwort, die auf der obigen Quelle basiert, aber geändert wurde, um Google DNS zu resolv.conf
hinzuzufügen .
Erstellen Sie zuerst ein --up Skript für OpenVPN. Dieses Skript erstellt die VPN-Tunnelschnittstelle in einem Netzwerk-Namespace namens vpn , anstelle des Standard-Namespace.
$ 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
Starten Sie dann OpenVPN und weisen Sie es an, unser --up zu verwenden script anstatt ifconfig und route auszuführen.
openvpn --ifconfig-noexec --route-noexec --up netns-up --route-up netns-up --down netns-up
Nun können zu tunnelnde Programme wie folgt gestartet werden:
ip netns exec vpn command
Der einzige Haken ist, dass Sie root sein müssen, um ip netns exec ...
aufzurufen und vielleicht möchten Sie nicht, dass Ihre Anwendung als Root ausgeführt wird. Die Lösung ist einfach:
sudo ip netns exec vpn sudo -u $(whoami) command
Es stellt sich heraus, dass Sie können Setzen Sie eine Tunnelschnittstelle in einen Netzwerk-Namespace. Mein ganzes Problem war auf einen Fehler beim Aufrufen der Schnittstelle zurückzuführen:
ip addr add dev $tun_tundv \
local $ifconfig_local/$ifconfig_cidr \
broadcast $ifconfig_broadcast \
scope link
Das Problem ist "Scope Link", was ich falsch verstanden habe, da es nur das Routing betrifft. Es veranlasst den Kernel, die Quelladresse aller in den Tunnel gesendeten Pakete auf 0.0.0.0
zu setzen; vermutlich würde der OpenVPN-Server sie dann per RFC1122 als ungültig verwerfen; selbst wenn dies nicht der Fall wäre, wäre das Ziel offensichtlich nicht in der Lage zu antworten.
Ohne Netzwerk-Namespaces funktionierte alles korrekt, da das integrierte Netzwerkkonfigurationsskript von openvpn diesen Fehler nicht machte. Und ohne "Scope-Link" funktioniert mein ursprüngliches Skript auch.
(Wie habe ich das entdeckt, fragen Sie? Durch Ausführen von strace
Setzen Sie im openvpn-Prozess alles, was er aus dem Tunneldeskriptor liest, auf Hexdump und dekodieren Sie dann die Paketheader manuell.)
Der Fehler beim Versuch, die Veth-Geräte zu erstellen, wird durch eine Änderung der Vorgehensweise ip
verursacht interpretiert die Kommandozeilenargumente.
Der korrekte Aufruf von ip
ein Paar Veth-Geräte zu erstellen ist
ip link add name veth0 type veth peer name veth1
(name
statt dev
)
Wie bekommt man nun Traffic aus dem Namespace in den VPN-Tunnel? Da du nur Geräte zur Verfügung hast, muss der "Host" routen. Dh Erstellen Sie das Veth-Paar und fügen Sie eines in den Namensraum ein. Verbinden Sie den anderen per Routing mit dem Tunnel. Aktivieren Sie daher die Weiterleitung und fügen Sie dann die erforderlichen Routen hinzu.
Nehmen wir zum Beispiel an, dass eth0
ist Ihre Hauptschnittstelle, tun0
ist Ihre VPN-Tunnelschnittstelle und veth0
/veth1
das Schnittstellenpaar, von dem veth1
liegt im Namensraum. Innerhalb des Namensraums fügen Sie einfach eine Standardroute für veth1
hinzu .
Auf dem Host müssen Sie Policy-Routing verwenden, siehe zum Beispiel hier. Was Sie tun müssen:
Einen Eintrag hinzufügen/anhängen wie
1 vpn
bis /etc/iproute2/rt_tables
. Damit können Sie die (noch zu erstellende) Tabelle beim Namen nennen.
Verwenden Sie dann die folgenden Anweisungen:
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
Ich kann das hier nicht mit einem Setup wie Ihrem ausprobieren, aber das sollte genau das tun, was Sie wollen. Sie können dies durch Paketfilterregeln so ergänzen, dass weder das VPN- noch das "Gast"-Netz gestört werden.
Hinweis:Verschieben von tun0
in den Namensraum zu schreiben, sieht zunächst nach dem Richtigen aus. Aber wie du habe ich das nicht zum Laufen gebracht. Policy-Routing scheint das nächste Richtige zu sein. Die Lösung von Mahendra ist anwendbar, wenn Sie die Netzwerke hinter dem VPN und kennen alle anderen Anwendungen werden niemals auf diese Netzwerke zugreifen. Aber Ihre anfängliche Bedingung ("der gesamte Verkehr und nur der Datenverkehr zu/von bestimmten Prozessen geht durch das VPN") klingt, als ob letzteres nicht garantiert werden kann.