Leserartikel [How-To] Zugriff von außen hinter DoubleNAT / DSLite / Firewall mittels Reverse SSH Tunnel

memmex

Lt. Junior Grade
Dabei seit
Juni 2008
Beiträge
403
[How-To] Zugriff von außen hinter DoubleNAT / DS-Lite / Firewall mittels Reverse SSH Tunnel


1. Das Problem
Falls der Heimanschluss keine öffentliche IP hat, lässt sich aus dem Internet nicht auf Dienste im eigenen Heimnetz zugreifen oder eine VPN-Verbindung herstellen.
Dies ist beispielsweise der Fall, wenn

2. Die Lösungsidee
In den obig aufgezählten Beispielen ist jeweils von der Seite des Internets kein "Durchkommen" in das Heimnetzwerk. Wir können aber natürlich aus dem Heimnetzwerk auf beliebige Dienste im Internet zugreifen.
Der Trick eines SSH Reverse Tunnels ist es, vom Heimnetzwerk aus eine Verbindung zu einem Relayserver im Internet herzustellen und diese Verbindung immer offen zu halten. Sie fungiert als Tunnel (ähnlich einem VPN-Tunnel), durch den Traffic wieder in das Heimnetz geschickt werden kann. Der SSH Tunnel übernimmt ebenfalls die Transportverschlüsselung der Daten.

Netzwerkschema


Befindet man sich beispielsweise mit einem Laptop in einem öffentlichen Netzwerk und möchte auf die nextcloud-Instanz im Heimnetz zugreifen, dann öffnet man im Browser die Adresse 111.202.22.222:443. Die Anfrage wird durch den Tunnel an die lokale IP 10.10.0.100:443 weitergegeben und die Antwort auf gleichem Weg wieder zugestellt.

2.1. Achtung
Ihr betreibt bei dieser Vorgehensweise einen eigenen Server im Internet. Ihr seid alleine für die sichere Konfiguration und Wartung dessen verantwortlich. Informiert euch vorher über die rechtlichen Einschränkungen und mögliche Haftungsrisiken.
Desweiteren öffnet ihr Ports, die direkt in euer Heimnetzwerk führen. Die offenen Ports kann sich jeder mit einem Portscanner anzeigen lassen und jede Person im Internet kann sich mit diesen offenen Ports verbinden. Öffnet nur Ports in euer Heimnetz, wenn ihr genau wisst, was ihr macht.
Natürlich dürfen keine Ports in fremde Netze (Cafes, Hotels, Arbeitsplatz, ...) hinein durch SSH Tunnel geöffnen werden.

3. Was wird benötigt?
  • einen Localserver mit einem Linuxbetriebssystem (Raspberry Pi, Heimserver, NAS, ...)
  • einen Relayserver mit einem Linuxbetriebssystem, root Zugang und einer festen IP bzw. (optional) einem Domainnamen (vServer, dedizierter Server, ...)
  • grundlegende Linuxkenntnisse
Wir verwenden in diesem Tutorial auf beiden Serversystemen Debian 10 (buster). Es kann sein, dass sich mit späteren Debianversionen oder auf anderen Linuxdistributionen Dateipfade ändern oder Befehle abgewandelt werden müssen.

3.1. Welcher Server eignet sich als Relayserver?
Als Relayserver eignet sich jede Instanz im Internet, zu der ihr vollen Rootzugriff habt und der eine feste IP zugewiesen wurde.
Ich empfehle ein Relay mit Serverstandort Deutschland zu wählen. Dies verringert die Pingzeiten und gewährt deutsche Gesetze des Datenschutzes, da der gesamte getunnelte Datenverkehr über das Relay läuft.
Der Relayserver benötigt kaum CPU-Leistung, noch RAM und auch keinen Festplattenplatz. Einzig die Bandbreite des Relayservers sollte mindestens so schnell sein, wie eure Internetverbindung.
Ich empfehle den kleinsten Server bei Hetzner (CX11) für weniger als 3 € im Monat mit 20 TB High-Speed-Traffic.

4. Vorgehen
4.1 SSH Keys erstellen
Um einen Tunnel aufzubauen, muss der Localserver eine SSH Verbindung zum Relayserver aufbauen können.
Zur Authentifizierung verwenden wir SSH Keys. Dies erhöht die Sicherheit gegenüber Passwörtern erheblich und bietet auch Vorteile bei der späteren Automatisierung.
Alle folgenden Befehle in diesem Tutorial werden unter beiden Systemen als User root ausgeführt.
Wir benötigen sowohl auf dem Local- als auch auf dem Relayserver SSH Schlüssel und generieren sie jeweils mit ssh-keygen. Wir geben keine Passphrase an und der Speicherort wird ebenfalls nicht verändert.
Damit sich der Localserver beim Relayserver anmelden kann, muss der Public Key des Localservers als ein authorisierter Schlüssel im Relayserver hinterlegt werden: ssh-copy-id -i /root/.ssh/id_rsa.pub root@<relayip>.
Wir testen die Anmeldung ssh root@<relayip> und bestätigen die Serveridentität.

4.2 SSH Konfiguration anpassen
In der Standardeinstellung erlaubt der SSH Dienst keine Weiterleitungen, so dass wir dessen Config anpassen müssen: nano /etc/ssh/sshd_config.
Bash:
PermitRootLogin prohibit-password
PasswordAuthentication no
PubkeyAuthentication yes
AllowTcpForwarding yes
GatewayPorts yes
ClientAliveInterval 30
ClientAliveCountMax 4
  • Normalerweise empfehle ich, den SSH Zugang für root generell zu sperren. Wir befinden uns aber in der Situation, dass Ports <1024 nur von root abgefangen und weitergeleitet werden dürfen.
  • Zum sicheren Betrieb eines Servers sollte immer der Passwortzugang abgeschaltet und die Schlüsselauthentifizierung erlaubt werden.
  • AllowTcpForwarding und GatewayPorts sind notwendig, um einen SSH Reverse Tunnel aufzubauen und Daten durch ihn zu leiten.
  • ClientAliveInterval und ClientAliveCountMax bestimmen, wie häufig ein künstliches Paket durch den Tunnel gesendet wird, um ihn aufrecht zu erhalten. Mit den obigen Werten habe ich persönlich gute Erfahrungen gemacht.
Nun müssen wir den SSH Dienst oder gleich den ganzen Server neustarten: shutdown -r now.

4.3 Unser erster SSH Reverse Tunnel
Wir sind nun bereit, den ersten SSH Reverse Tunnel zu starten. Dies funktioniert mit dem Programm ssh und folgender Syntax:
Bash:
ssh -N -R <relayport>:<localip>:<localport> root@<relayip>
  • ssh öffnet normalerweise eine Shell auf dem Relayserver. Dieses Verhalten unterbinden wir mit -N.
  • Eine Portweiterleitung wird jeweils mit der Option -R eingeleitet.
  • Die genaue Funktion der verschiedenen Schalter ist in man ssh nachzulesen.

Testweise leiten wir jetzt die Ports 80 (HTTP) und 443 (HTTPS) weiter. Außerdem möchten wir uns auch per SSH (Port 22) mit unserem Localserver verbinden können.
Es ist wichtig, dass die Ports weder auf dem Local- noch auch auf dem Relayserver bereits belegt sind. In unserem Fall ist der Port 22 auf dem Relayserver bereits in Benutzung, da wir auf diesem Port unseren SSH Tunnel starten. Wir weichen auf dem Relayserver auf Port 22022 aus.
Bash:
ssh -N -R 80:127.0.0.1:80 -R 443:127.0.0.1:443 -R 22022:127.0.0.1:22 root@<relayip>
Bei den Platzhaltern <localip> und <relayip> können sowohl IP-Adressen als auch Domainnamen angegeben werden. Der Localserver kann außerdem den Traffic an jede weitere <localip> im Heimnetzwerk weiterreichen.

Wir können mit dem Befehl netstat -tulpen | grep -v 127.0.0.1 sehen, welche Ports auf dem Server momentan geöffnet sind. Auf dem Relayserver sehen wir den geöffneten Tunnel.
Anschließend schließen wir den Tunnel auf dem Localserver wieder mit CTRL+C.

4.4 SSH Reverse Tunnel automatisch starten und neu aufbauen
Wir möchten, dass sich der Tunnel zum Relayserver beim Start des Localservers automatisch aufbaut. Dies soll auch geschehen, falls eine Seite das Internet verliert und deshalb der Tunnel zusammenbricht.
Genau für diese Aufgabe wurde das Programm autossh geschrieben, das wir noch auf dem Localserver installieren müssen: apt -y install autossh.

Zur besseren Übersicht und Anpassbarkeit erstellen wir ein kleines Skript auf dem Localserver touch /opt/ssh_tunnel.sh und machen es ausführbar chmod +x /opt/ssh_tunnel.sh.
nano /opt/ssh_tunnel.sh:
Bash:
#!/bin/bash
#
echo "" && echo "" && echo ""
echo "-- start autossh --"
/usr/bin/autossh -M 0 -f -N -v -o "ServerAliveInterval 10" -o "ServerAliveCountMax 3" -o "ExitOnForwardFailure yes" -R 80:127.0.0.1:80 -R 443:127.0.0.1:443 -R 22022:127.0.0.1:22 root@<relayip>
#
echo "" && echo "" && echo ""
echo "use 'kill -9 \$(pidof autossh) && kill -9 \$(pidof /usr/bin/ssh)' to kill autossh"
#
echo "" && echo "" && echo ""
  • -N und -R sind die gleichen Schalter von ssh wie oben.
  • -M 0 deaktiviert die Monitorfunktion von autossh.
  • -f startet ssh im Hintergrund.
  • -v Verbose Mode.
  • ServerAliveInterval und ServerAliveCountMax erfüllen eine analoge Funktion auf der Serverseite wie ClientAliveInterval und ClientAliveCountMax.
  • ExitOnForwardFailure bewirkt, dass der Tunnelaufbau fehlschlägt, falls die angeforderten Ports belegt sind.

Das Skript führen wir bei jedem Neustart mittels crontab aus.
crontab -e:
Bash:
@reboot /bin/bash /opt/ssh_tunnel.sh >> /tmp/cron.log

Nach einem Neustart des Localservers shutdown -r now sehen wir auf beiden Servern mit netstat -tulpen | grep -v 127.0.0.1 die offenen Ports und auch die Programme autossh und ssh in der Prozessorliste htop des Localservers.

5. Abschließende Worte
Vielen Dank für das Lesen meines Guides. Ich hoffe, dass ich euch helfen konnte!
Abschließend möchte ich noch einmal darauf hinweisen, dass dies eine mögliche Lösung ist, um dem DS-Lite / DoubleNAT Problem zu begegnen. Sie ist aber sicherlich nicht für jeden Anwender geeignet.
Für weitere Anmerkungen und Korrekturen gerne im Thread kommentieren.

Viele Grüße
memmex


Versionsverlauf:
  • 2019.07.20: Veröffentlichung
  • 2019.07.21: kleine Korrekturen
 
Zuletzt bearbeitet:

till69

Captain
Dabei seit
Jan. 2010
Beiträge
3.738
Sehr guter Beitrag :)

Interessant wäre ein Perfomance-Vergleich zwischen verschiedenen Tunneln wie z.B. OpenVPN, Wireguard, SSH und strongSwan.
strongSwan bietet den Vorteil, dass kein LocalServer nötig ist, das VPN einer Fritzbox reicht.

Und wer nur ein DSLite-Problem hat, kann mit "socat" ganz ohne einen Tunnel IPv4 Ports auf eine IPv6 Freigabe im Heimnetz mappen. Problem dabei ist evtl. ein wechselndes IPv6 Präfix.
 

memmex

Lt. Junior Grade
Ersteller dieses Themas
Dabei seit
Juni 2008
Beiträge
403
Vielen Dank @till69

Ich habe leider nicht den Aufbau, um diese Tests durchzuführen und leider auch keine Muße dazu :freak:
Interessieren würde es mich aber auch. Vielleicht traut sich jemand anderes dran.


P.S. Generell sollte ein SSH Tunnel für die meisten Anwendungen potent genug sein.
Es würde wahrscheinlich noch mehr gehen, aber man sieht, dass der Relayserver ziemlich genau (1 Gbit/s)/2 schafft, was genau der Geschwindigkeit des LAN-Anschluss entspricht. Es ist also noch Luft nach oben.

802154
 
Top