Einrichtung eines Gateway mit SSH
Eine Kombination aus Remote und Local Port Weiterleitung zur Einrichtung eines Gateways mit SSH
Mit Hilfe einer Kombination aus Remote und Local Port Weiterleitung ist es möglich, Verbindungen zwischen Rechnern herzustellen, die auf direktem Weg untereinander nicht erreichbar sind. Dazu ist kein "offenes" Gateway erforderlich.
In einem anderen Artikel dieses Blog wurde beschrieben, wie man mit einer Remote Port Weiterleitung Dienste im Heimnetzwerk für den Zugriff aus dem Internet verfügbar machen kann. Dazu wird ein Zugang per SSH auf einem Rechner im Internet benötigt, den man im Prinzip über jeden VPS (Virtual Private Server) erhält.
Das Problem dabei ist, dass der SSH-Server als offenes Gateway arbeiten muss, was in der Standardkonfiguration eines SSH-Servers normalerweise deaktiviert ist.
Dieser Artikel zeigt nun, wie man mit einer Kombination aus Remote und Local Port Weiterleitung die Einrichtung eines offenen SSH-Gateways umgehen kann.
Die hier beschriebene Lösung funktioniert jedoch nur für Anwender, die einen SSH-Zugang zum Server haben. Eine Lösung, die den Zugriff für jederman verfügbar macht und dennoch auf die EInrichtung eines offenen Gateways verzichtet, wird in diesem Artikel vorgestellt.
Beispiel: Zugriff auf die interne Website eines Pi-hole
In einem Heimnetzwerk soll auf einem Raspberry Pi das Pogramm Pi-hole laufen. Pi-hole blockt jegliche Art von Internetwerbung im Heimnetzwerk, indem es DNS-Anfragen auflöst und bekannte Domainnamen von Werbeanbietern einfach ignoriert. Dieser Raspberry Pi soll im folgenden den Namen Cadamosto haben.
Das Programm Pi-hole beinhaltet eine Weboberfläche, über die das Programm konfiguriert werden kann und die gleichzeitig Statistiken und Logs in ansprechender und übersichtlicher Form in einem Dashboard darstellt. Dafür wird bei der Installation des Pi-hole zusätzlich ein lighttpd
Webserver installiert, der auf dem Port 80
Anfragen entgegennimmt.
Die nachfolgende Abbildung zeigt das Dashboard des Pi-hole, das mit http://localhost/admin/
auf dem Raspberry Pi aufgerufen werden kann:
Ziel ist es, dieses Dashboard auch von außerhalb des Heimnetzwerks aufrufen zu können, z.B. wenn man mal unterwegs ist. Die Lösung besteht in der Einrichtung einer Remote Port Weiterleitung auf dem Raspberry Pi und einer Local Port Weiterleitung auf dem Rechner, mit dem man sich außerhalb des Heimnetzwerkes befindet.
Damit diese Kombination aus Remote und Local Port Weiterleitung überhaupt möglich ist, wird ein Rechner im Internet benötigt – zum Beispiel ein VPS eines beliebigen Anbieters – auf dem man sich per SSH anmelden kann. Dieser Rechner soll Cayenne heißen.
Einrichtung der Remote Port Weiterleitung
Die erste Aufgabe ist die Einrichtung einer Remote Port Weiterleitung von Cadamosto zu Cayenne:
uwe@cadamosto:~ $ ssh -fN -o ExitOnForwardFailure=yes -R 8080:localhost:80 Cayenne
Cayenne
ist in diesem Befehl ein Alias für den vollständigen Hostnamen des Rechners Cayenne.
Der Befehl richtet eine Port Weiterleitung als Hintergrundprozess vom Port 8080
auf Cayenne zum Port 80
auf Cadamosto ein. Da die Weiterleitung von Cadamosto aus eingerichtet wird, aber von Cayenne zurück zu Cadamosto führt, heißt sie Remote Port Weiterleitung oder auch manchmal Reverse Port Weiterleitung.
Für den Beginn der Port Weiterleitung muss auf Cayenne ein freier Port gewählt werden. Im hier verwendeten Beispiel wird davon ausgegangen, dass auf Cayenne bereits ein Webserver auf dem Port 80
läuft, daher wird der Port 8080
gewählt.
Die Weiterleitung ist auf Cadamosto (Raspberry Pi) zu sehen, wenn man sich alle Prozesse mit dem Befehl ps
ausgeben lässt:
uwe@cadamosto:~ $ ps -x -o pid,cmd
PID CMD
4585 sshd: uwe@pts/2
4588 -bash
7855 ps -x -o pid,cmd
14072 /lib/systemd/systemd --user
14075 (sd-pam)
14871 ssh -fN -o ExitOnForwardFailure=yes -R 8080:localhost:80 Cayenne
uwe@cadamosto:~ $
Um die Weiterleitung zu beenden würde man ein SIGTERM an die PID schicken, z.B. mit kill 14871
.
Es wäre natürlich von Vorteil, das Starten und Beenden der Weiterleitung mit einem einzigen Befehl durchführen zu können, am besten noch mit der Möglichkeit, den aktuellen Status abzufragen. Dies kann mit dem nachfolgenden Bash-Skript ReverseTunnel
erreicht werden:
#!/bin/bash
# Script to start or stop remote port forwarding (rpf)
# Exit code is 1 if rpf is established, 0 if not
#
# Usage: ReverseTunnel (start|stop|status)
RHOST="server.example.com" # Remote Host (Cayenne)
RPORT="8080" # Remote Port on Remote Host
RUSER="$USER" # Remote User (here: same as local)
LHOST="localhost" # Local Host (Cadamosto)
LPORT="80" # Local Port on Local Host
SSHOPT="-fN -o ExitOnForwardFailure=yes" # Options for ssh
# Define the command to establish rpf
CMD="$(which ssh) $SSHOPT -R $RPORT:$LHOST:$LPORT $RUSER@$RHOST"
# Define a function to get the PID for a specific command
function getPID {
pid=$(ps x -o user,pid,cmd | grep "$1" | grep -v "grep" | tr -s " " | cut -d" " -f2)
[[ $pid ]] && echo $pid
}
# Get PID of $CMD (will be empty if rpf is not established)
PID=$(getPID "$CMD")
case $1 in
start) # If parameter start is given
# If PID exists then a rpf is already established
if [ $PID ];then
echo "Reverse tunnel already established!"
echo "PID $PID ($RHOST:$RPORT -> $LHOST:$LPORT)"
exit 1
fi
# Otherwise we can establish it
$CMD > /dev/null 2>&1
RETURNCODE=$?
# Check the returncode and inform about new status
if [ $RETURNCODE == 0 ];then
PID=$(getPID "$CMD")
echo "Reverse tunnel from $RHOST:$RPORT -> $LHOST:$LPORT established"
echo "PID $PID"
exit 1
else
echo "Reverse tunnel could not be established!"
echo "Return code $RETURNCODE"
exit $RETURNCODE
fi
;;
stop) # If parameter stop is given
# If PID does not exist then a rpf is not established
if [ -z $PID ];then
echo "Reverse tunnel not established!"
exit 0
fi
# Otherwise we can stop it by sending the SIGTERM to its PID
kill $PID
RETURNCODE=$?
# Check the return code and inform about status
if [ $RETURNCODE == 0 ];then
echo "Reverse tunnel from $RHOST:$RPORT -> $LHOST:$LPORT terminated"
exit 0
else
echo "Reverse tunnel could not be terminated!"
echo "Return code $RETURNCODE"
exit $RETURNCODE
fi
;;
status) # If parameter status is given
# If PID exists then a rpf is already established
if [ $PID ];then
echo -n "Reverse tunnel already established with PID $PID"
echo " from $RHOST:$RPORT -> $LHOST:$LPORT"
exit 1
fi
# If PID does not exist then a rpf is not established
if [ -z $PID ];then
echo "Reverse tunnel not already established"
exit 0
fi
;;
*) # If none or any other parameter is given, print usage info and exit
echo "Usage: $(basename $0) (start|stop|status)" && exit 125
;;
esac
Mit dem Befehl ReverseTunnel start
kann man die Remote Port Weiterleitung aktivieren und mit ReverseTunnel stop
wieder deaktivieren. Mit ReverseTunnel status
lässt sich der aktuelle Status der Port Weiterleitung abfragen.
Auf dem VPS Cayenne kann man anhand der Liste der offenen Ports sehen, dass es diese Weiterleitung gibt – allerdings leider nicht, wohin diese führt bzw. von wo aus sie eingerichtet wurde:
uwe@cayenne:~$ sudo netstat -ltpn | grep 8080
tcp 0 0 127.0.0.1:8080 0.0.0.0:* LISTEN 25789/sshd: uwe
tcp6 0 0 ::1:8080 :::* LISTEN 25789/sshd: uwe
uwe@cayenne:~$
Der Befehl netstat
wird hier mit sudo
aufgerufen, da sonst nicht alle Details angezeigt werden.
Wie man sieht, wird nur der lokal erreichbare Port 8080
von Cayenne weitergeleitet. Von außerhalb des Rechners Cayenne ist die Nutzung der Port Weiterleitung nicht möglich. Das ist der Nachteil (oder, unter Sicherheitsaspekten: Vorteil) der beschriebenen Standardeinstellung, dass der SSH-Server kein offenes Gateway bildet.
Das würde allerdings auch nicht dem Ziel entsprechen, dass die Website von unterwegs erreichbar sein soll.
Man könnte natürlich jetzt von unterwegs in einem Terminal eine SSH-Verbindung zu Cayenne herstellen, aber in einem Terminal könnte man die Website nicht aufrufen und wenn doch - z.B. mit lynx
- würde diese nicht richtig angezeigt werden. Ziel ist es weiterhin, das Dashboard mit einem normalen Browser auf dem Rechner, mit dem man gerade arbeitet, aufzurufen.
Einrichtung der Local Port Weiterleitung
Dafür muss nun auf dem Rechner mit dem die Website aufgerufen werden soll eine Local Port Weiterleitung zu Cayenne eingerichtet werden. Im folgenden geschieht dies auf einem Laptop, das auf den Namen Caboto hört. Da auch auf Caboto bereits ein Webserver läuft und den Port 80
belegt, wird für die Port Weiterleitung der Port 8008
verwendet:
uwe@Caboto:~$ ssh -fN -o ExitOnForwardFailure=yes -L 8008:localhost:8080 Cayenne
Der Befehl richtet eine Port Weiterleitung als Hintergrundprozess vom Port 8008
auf Caboto zum Port 8080
auf Cayenne ein. Da die Einrichtung von Caboto aus erfolgt und von Caboto zu Cayenne führt, nennt diese sich Local Port Weiterleitung.
Auch auf Caboto kann man den Hintergrundprozess mit Hilfe von ps
sehen und mit einem SIGTERM an die PID bei Bedarf beenden. Es könnte natürlich hier auch wieder ein Skript erstellt werden, dass beide Aufgaben erfüllt.
Der offene Port ist diesmal nicht auf Cayenne sondern auf Caboto zu sehen und wie man sieht, ist auch hier die Port Weiterleitung nur über die lokale Schnittstelle erreichbar:
uwe@Caboto:~$ sudo netstat -ltpn | grep 8008
tcp 0 0 127.0.0.1:8008 0.0.0.0:* LISTEN 5813/ssh
tcp6 0 0 ::1:8008 :::* LISTEN 5813/ssh
uwe@Caboto:~$
Jetzt kann man in einem Browser auf Caboto die Adresse http://localhost:8008/admin/
eingeben und das Dashboard des Pi-hole auf Cadamosto sehen:
Wie man sieht, müsste man sich hier erst erneut anmelden, um das vollständige Dashboard zu sehen, was übrigens trotz der vermeintlich unverschlüsselten Verbindung (http://…
) kein Problem ist. Denn der Aufruf von localhost:8008
auf Caboto bewirkt ja eine unmittelbare Weiterleitung durch die bestehende SSH-Verbindung zu Cayenne. Dort wird die Anfrage an den lokalen Port 8080
gerichtet und wiederum unmittelbar durch die bestehende SSH-Verbindung zu Cadamosto weitergeleitet, wo sie auf dem lokalen Port 80
landet.
Mit anderen Worten ist die Verbindung auf dem ganzen Weg verschlüsselt und es besteht keine Notwendigkeit, die Website zusätzlich per Zertifikat zu sichern.
Die nachfolgende Abbildung zeigt noch einmal die ganze Konstruktion schematisch:
Vom Raspberry Pi Cadamosto im Heimnetz wird eine Remote Port Weiterleitung zum VPS Cayenne eingerichtet, die Anfragen auf den Port 8080
auf Cayenne durch den Router hindurch zu Cadamosto auf Port 80
weiterleitet.
Vom Laptop Caboto wird unterwegs dann eine Local Port Weiterleitung zu Cayenne eingerichtet, die Anfragen auf den Port 8008
auf Caboto zu Cayenne auf Port 8080
weiterleitet - wo diese dann unmittelbar zu Cadamosto weitergeleitet werden.
Somit kann man nun unterwegs auf Caboto in einem Browser die Adresse http://localhost:8008/
eingeben und sieht das Dashboard des Pi-hole im Heimnetzwerk.
Weitere Möglichkeiten
Natürlich ist die Anwendung dieser kombinierten Port Weiterleitung nicht auf eine Website oder Websites im allgemeinen beschränkt. So könnte man zum Beispiel auch den SSH-Zugriff auf den Raspberry Pi nach außen freigeben, wenn man im Skript ReverseTunnel
den lokalen Port 80
durch 22
und den entfernten Port 8080
durch 2222
ersetzt – letzteres, weil auf dem VPS Cayenne ja bereits ein SSH-Server auf Port 22
hört.
Mit einer entsprechend angepassten Local Port Weiterleitung hätte man dann von überall direkten Zugriff auf eine Konsole auf dem Heimnetzrechner Cadamosto.