OpenVPN selektiv #4: IPv6

Sollzustand, wenn ich über meinen Server einen Tunnel aufbaue:


Dort soll nun Dante, ein SOCKS5-Proxy, eine OpenVPN-Verbindung nach Deutschland teilen.
Also dann statt
ssh -D 1080 myhost.tld

das hier
ssh -L 1080:localhost:1080 myhost.tld

Ein geringfügiger Mehraufwand.

Alles der Reihe nach. Was bisher geschah:
SSH Portweiterleitungen
OpenVPN selektiv #1 auf 'nem Server
OpenVPN selektiv #2 Leak schließen
OpenVPN selektiv #3 Teilen über SOCKS

Neuer VPN-Anbieter. IPv6. Da bin ich leider mit meinem alten Post nicht mehr klar gekommen.

Zuerst einmal gilt es herauszufinden, was OpenVPN überhaupt macht.
Dafür hab' ich die Stock OpenVPN Client Konfigurationsdatei mit strace vorne dran ausgeführt. Das Ganze in eine Datei gedumpt.
Hierbei sollte ich anmerken, dass sich der Server nach herstellen der OpenVPN Verbindung komplett aus dem Internet verabschiedet, weil alles nur noch per Tunneladapter geroutet wird. Ergibt ja auch Sinn, für den Endnutzer.

Exakt dieses Verhalten möchte ich jedoch unterbinden. Die VPN-Verbindung soll einzig und alleine vom Dante SOCKS-Proxy genutzt werden.
Bedeutet,
curl -4 icanhazip.com
curl -6 icanhazip.com

geben immer die echte IP des Servers zurück. Erst, wenn ich zusätzlich --interface tun0 angebe, wie in der SOCKS Konfiguration, soll die Tunnelverbindung genutzt werden.

1 root@lxc ~ # grep /sbin/ip strace                                                                                                                          
Tue Oct 4 17:43:54 2016 /sbin/ip link set dev tun0 up mtu 1500
Tue Oct 4 17:43:54 2016 /sbin/ip addr add dev tun0 172.17.13.37/20 broadcast 172.17.13.255
Tue Oct 4 17:43:54 2016 /sbin/ip -6 addr add fd10:beef:beef:beef:coff:eeco:ffee:coff/64 dev tun0
Tue Oct 4 17:43:54 2016 /sbin/ip route add 8.9.10.11/32 via 172.17.0.1
Tue Oct 4 17:43:54 2016 /sbin/ip route add 0.0.0.0/1 via 172.17.48.1
Tue Oct 4 17:43:54 2016 /sbin/ip route add 128.0.0.0/1 via 172.17.48.1
Tue Oct 4 17:43:54 2016 /sbin/ip -6 route add fd10:beef:beef:beef::/64 dev tun0
Tue Oct 4 17:43:54 2016 /sbin/ip -6 route add 2000::/3 dev tun0
Tue Oct 4 17:43:57 2016 /sbin/ip route del 8.9.10.11/32
Tue Oct 4 17:43:57 2016 /sbin/ip route del 0.0.0.0/1
Tue Oct 4 17:43:57 2016 /sbin/ip route del 128.0.0.0/1
Tue Oct 4 17:43:57 2016 /sbin/ip -6 route del 2000::/3 dev tun0
Tue Oct 4 17:43:57 2016 /sbin/ip -6 route del fd10:beef:beef:beef::/64 dev tun0
Tue Oct 4 17:43:57 2016 /sbin/ip addr del dev tun0 172.17.13.37/20


Was auch noch von Nutzen sein könnte, als OpenVPN-UP Script einfach mal
export > /tmp/export

auszuführen. Die ganzen Routing-Details sind nämlich eigentlich in Environment-Variablen verfügbar. So könnte man die Routen dynamisch setzen.

Hiernach wissen wir, welche Routen gesetzt werden.
--script-security 2
--route-nopull

in die Config, dass keine Routen mehr automatisch gesetzt werden.

IPv4 ist einfach. Habe einfach im up-Skript die globale 0.0.0.0/1 Route gelöscht. Einzig IPv6 machte Probleme.
Die 2000::/3 Regel routet alles über tun. Lösche ich sie, geht IPv6 technisch rein gar nichts mehr über den Tunnel.

Zwischenstand

Weiterhin ganz normaler SSHD Socks über den Server. Selbstredend soll IPv6 nicht per default über den Tunnel (Deutschland) geroutet werden, da der Server ansonsten nicht mehr von außen per IPv6 erreichbar ist.


Beim Server handelt es sich um einen LXC-Container, der eine NAT-IPv4 /32 (Gateway: 172.17.0.1), sowie public /128 IPv6 bekommt. Mit der Magie von radvd kein Problem.
root@lxc ~ # ip route show
default via 172.17.0.1 dev eth0
172.17.0.0/24 dev eth0 proto kernel scope link src 172.17.0.4
172.17.48.0/20 dev tun0 proto kernel scope link src 172.17.13.37

root@lxc ~ # route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 172.17.0.1 0.0.0.0 UG 0 0 0 eth0
172.17.0.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
172.17.48.0 0.0.0.0 255.255.240.0 U 0 0 0 tun0

root@lxc ~ # route -6 -n
Kernel IPv6 routing table
Destination Next Hop Flag Met Ref Use If
::/0 :: !n -1 1 47830 lo
2001:bc8:226a:101::/64 :: U 256 0 0 eth0
fd10:beef:beef:beef::/64 :: U 256 0 0 tun0
fe80::/64 :: U 256 0 0 eth0
::/0 fe80::649b:c9ff:fe4a:be50 UGDAe 1024 2 0 eth0
::/0 :: !n -1 1 47830 lo
::1/128 :: Un 0 1 1280 lo
2001:bc8:226a:101::1/128 :: Un 0 2 35969 lo
fd10:beef:beef:beef:coff:eeco:ffee:coff/128 :: Un 0 1 429 lo
fe80::216:3eff:fe3b:7125/128 :: Un 0 1 2319 lo
ff00::/8 :: U 256 1 0 eth0
ff00::/8 :: U 256 1 0 tun0
::/0 :: !n -1 1 47830 lo

Jawoll. Das wird spaßig.


An einer zusätzlichen Routingtabelle führt kein Weg vorbei:
echo 2 tunnel >> /etc/iproute2/rt_tables


Wenn wir uns die Routen eines Linuxsystems anschauen,
root@lxc ~ # ip rule show                     
0:    from all lookup local
32766:    from all lookup main
32767:    from all lookup default


gibt es drei Tabellen. Je niedriger die Zahl, desto höher die Priorität. man ip rule hilft.
Die default Tabelle macht nichts.
Stattdessen füge ich hier die neue Routingtabelle tunnel ein.
root@lxc ~ # ip -6 rule add table tunnel prio 32767
root@lxc ~ # ip rule add table tunnel prio 32767

Ergibt
root@lxc ~ # ip -6 rule show 
0:    from all lookup local
32766:    from all lookup main
32767:    from all lookup tunnel

VPN sollte insofern nie erreicht werden.

Anschießend werden die Regeln speziell für die Tabelle tunnel gesetzt:
ip link set dev tun0 up mtu 1500
ip addr add dev tun0 172.17.13.37/20 broadcast 172.17.13.255
ip -6 addr add fd10:beef:beef:beef:coff:eeco:ffee:coff/64 dev tun0
ip route add table tunnel 8.9.10.11/32 via 172.17.0.1
ip route add table tunnel 0.0.0.0/1 via 172.17.48.1
ip route add table tunnel 128.0.0.0/1 via 172.17.48.1
ip -6 route add table tunnel fd10:beef:beef:beef::/64 dev tun0
ip -6 route add table tunnel 2000::/3 dev tun0

Ein simples Ersetzen von route add durch route add table tunnel führt zum Ziel. Ich kann einfach alle Routen setzen - inklusive privater Netzwerke, globaler Regeln, etc. Zumal diese nicht automatisch genutzt werden.

Manuelles Löschen der Regeln:
ip route flush table tunnel
ip -6 route flush table tunnel

Beim Beenden von OpenVPN wurden bei mir alle Regeln gelöscht.

IP Rule Priority überdauern einen Neustart nicht.

Zu guter Letzt bleibt zu sagen,
falls man einen VPN-Anbieter gewählt hat, der bei jedem Verbinden eine neue public IP zuweist, so sollte man sich lieber mit dem OpenVPN-Up-Skript beschäftigen.
An dieser Lösung gefällt mir, dass ich wirklich sicher gehen kann, dass alles 1:1 funktioniert, wie normalerweise. Mit Nutzung nach Bedarf.

Update 14.10.2016
Curl geht, Dante möchte noch nicht. Weil die Regeln noch nicht komplett sind, es fehlen die Regeln, wenn Traffic vom Tunnelinterface zurück kommt:
ip rule add from 172.17.13.37/20 table tunnel
ip -6 rule add from fd10:beef:beef:beef::/64 table tunnel


Testbar mit
curl icanhazip.com --proxy socks5://localhost:1080 -v -4
curl icanhazip.com --proxy socks5://localhost:1080 -v -6


Update 10.01.2017
Man sollte für OpenVPN nicht die default-Routingtabelle überschreiben, da dort auch Pakete, die nirgends dazu passen, durchwandern.
which order is the route table analyzed in? - Unix & Linux Stack Exchange

Quellen
http://lartc.org/howto/lartc.rpdb.multiple-links.html
https://www.thomas-krenn.com/en/wiki/Two_Default_Gateways_on_One_System
http://www.rjsystems.nl/en/2100-adv-routing.php