Wiki:packages/rudi-shell/tips

Tips & Tricks

Sicherer Zugriff via HTTPS

/!\ Achtung: Diese Anleitung wurde geschrieben bevor AVM eine eigene Fernzugrifffunktion integriert hat, weshalb die hier auch nicht erwähnt wird.

Jetzt haben wir endlich eine Shell, die über ein reines Web-Interface läuft, sind also unabhängig von Telnet, SSH & Co. Was jetzt noch schön wäre: sicherer Zugriff auf die Rudi-Shell oder am besten gleich die ganze Freetz-Konfiguration von außen über eine SSL-gesicherte Verbindung. Wir könnten dann aus dem Büro oder von jedem Internet-Café der Welt aus unseren Router konfigurieren, ohne auf Proxies oder Portbeschränkungen Rücksicht nehmen zu müssen. Port 443 für HTTPS ist bei 99% aller Proxies freigeschaltet. Wir bräuchten keinen SSH-Client und hätten trotzdem eine sicher verschlüsselte Verbindung vom Browser zum Router.

Genau das konfigurieren wir uns jetzt! Zunächst brauchen wir eine Firmware mit dem Paket stunnel. Das Paket aktiviert übrigens automatisch die beiden Shared Libraries für OpenSSL, nämlich libcrypto.so und libssl.so. Außerdem wird die zlib (libz.so) benötigt. Weitere Tips und Infos hierzu:

  • Der Platzbedarf dieser Pakete ist nicht zu unterschätzen, somit nichts für kleine Boxen: 90 KB für stunnel, 70 KB für die zlib und sage und schreibe 1.150 KB für OpenSSL. Das sind fast 1,3 MB und somit eine Menge. Aber wenn die Box es verkraftet (meine 7170 tut es), werden wir gleich noch viel Spaß haben.
  • Wer eine Firmware mit OpenSSL-Bibliotheken von AVM einsetzt, z.B. die aktuelle 29.04.59 für die 7170, muß aufpassen, daß er in /var/flash/tr069.cfg - so vorhanden - die Option enabled = no setzt, bevor die Firmware mit den eigenen Bibliotheken installiert wird (oder aber beim Erstellen des Images gleich den ganzen TR-069 Kram rauspatchen lassen). Ansonsten würde es mit Boxen von 1&1 Probleme beim Aufrufen der durch Freetz ersetzten OpenSSL-Bibliotheken geben. Einige Provider wie z.B. 1&1 verlangen bei Support-Anfragen, dass TR-069 in der Box aktiviert ist!

Als nächstes brauchen wir für den HTTPS-Server ein Serverzertifikat und ein Schlüsselpaar. Das bauen wir uns selbst mit OpenSSL. Das geht unter Linux prinzipiell genauso wie unter Windows, man sollte nur vorsichtshalber darauf achten, daß die Schlüsseldatei, welche am Ende auf der Box landet, UNIX-Zeilenenden hat. Ich erkläre im Folgenden, wie die Generierung eines Self-Signed Key unter Linux abläuft. Es genügt, folgendes Skript auszuführen:

#!/bin/bash

# Paßwortgeschützten Server Key erzeugen
openssl genrsa -des3 -out server.key 1024

# Ungeschützte Version extrahieren (der SSL-Server kann ja nicht
# vor der Benutzung selbst ein Paßwort eingeben)
openssl rsa -in server.key -out server.key.unsecure

# Certificate Signing Request (CSR) mit persönlichen Daten erzeugen
openssl req -new -key server.key -out server.csr

# Ein Jahr gültiges, selbst signiertes Zertifikat anfordern
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

# CSR wird nicht mehr benötigt
rm server.csr

# Schlüssel + Zertifikat (in dieser Reihenfolge!)


# in einer Datei zusammenführen
cat server.key.unsecure server.crt > stunnel-key.pem

# Nachschauen, ob auch alles da ist
ls -l

Der gesamte Vorgang erfordert zwischendurch die Eingabe einer Passphrase für den Serverschlüssel sowie von persönlichen Daten für das Zertifikat. Das sieht dann inkl. Ein- und Ausgaben beispielsweise so aus:

$ openssl genrsa -des3 -out server.key 1024
Generating RSA private key, 1024 bit long modulus
..................++++++
.......++++++
e is 65537 (0x10001)
Enter pass phrase for server.key:
Verifying - Enter pass phrase for server.key:

$ openssl rsa -in server.key -out server.key.unsecure
Enter pass phrase for server.key:
writing RSA key

$ openssl req -new -key server.key -out server.csr
Enter pass phrase for server.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:DE
State or Province Name (full name) [Some-State]:Bavaria
Locality Name (eg, city) []:Munich
Organization Name (eg, company) [Internet Widgits Pty Ltd]:ACME Ltd.
Organizational Unit Name (eg, section) []:
Common Name (eg, YOUR name) []:Manni Muster
Email Address []:manni@acme.de

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

$ openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
Signature ok
subject=/C=DE/ST=Bavaria/L=Munich/O=ACME Ltd./CN=Manni Muster/emailAddress=manni@acme.de
Getting Private key
Enter pass phrase for server.key:

$ rm server.csr

$ cat server.key.unsecure server.crt > stunnel-key.pem

$ ls -l
insgesamt 16
-rw-r--r-- 1 ubuntu ubuntu  895 2007-02-26 21:50 server.crt
-rw-r--r-- 1 ubuntu ubuntu  963 2007-02-26 21:41 server.key
-rw-r--r-- 1 ubuntu ubuntu  887 2007-02-26 21:42 server.key.unsecure
-rw-r--r-- 1 ubuntu ubuntu 1782 2007-02-26 22:00 stunnel-key.pem

Anschließend haben wir in Form der Datei stunnel-key.pem, was wir wollten: ein selbst signiertes Schlüsselpaar für unseren HTTPS-Server. Das muß jetzt nur noch irgendwie auf die Box. Dafür gibt es zwei Wege:

  • Einbau in die Firmware: Einfach an den gewünschten Ort unter <Mod-Verzeichnis>/root kopieren, z.B. nach /usr/share/stunnel-key.pem.
  • Einbau in /var/flash/debug.cfg oder /tmp/flash/rc.custom in der üblichen Form eines Hier-Dokuments, welchen beim Booten der Box entpackt wird, z.B. nach /tmp/stunnel-key.pem oder nach /mod/usr/share/stunnel-key.pem. Das Here-Dokument kann so aussehen:
    cat << EOF_CERT > /tmp/stunnel-key.pem
    -----BEGIN RSA PRIVATE KEY-----
    # Server-Schlüssel ...
    -----END RSA PRIVATE KEY-----
    -----BEGIN CERTIFICATE-----
    # Zertifikat ...
    -----END CERTIFICATE-----
    EOF_CERT
    

Wo auch immer die Schlüsseldatei liegt, wir müssen uns in der stunnel-Konfiguration lediglich auf den richtigen Ablageort beziehen. Weiter geht's:

Über die Freetz-Oberfläche sorgen wir dafür, daß stunnel als Dienst automatisch gestartet wird und geben unter Einstellungen → stunnel services folgende Konfiguration ein, um eben diese Web-Oberfläche, in der wir uns gerade aufhalten, zukünftig HTTPS-gesichert verfügbar zu machen:

[freetz_web]
cert = /tmp/stunnel-key.pem
client = no
accept = 443
connect = 81

D.h. nichts anderes, als daß wir einen von uns Freetz getauften Service verfügbar machen, welcher eingehende SSL-Verbindungen auf dem HTTPS-Port 443 akzeptiert und diese nach dem Entschlüsseln an den Port 81 des Freetz-Webservers weiterleitet. Wichtig: Das Ganze läuft nicht im Client-, sondern im Server-Modus.

Das war's schon! Jetzt können wir ausprobieren, was passiert, wenn wir https://fritz.box aufrufen. Es sollten zunächst der Passwort-Dialog von Freetz und anschließend die Web-Oberfläche erscheinen.

Wenn wir jetzt noch Services für Port 80 (AVM-Oberfläche) und/oder Port 82 (WoL?-Oberfläche) haben wollen, fügen wir einfach entsprechende Abschnitte in die Konfiguration ein nach obigem Muster.

/!\ Achtung: Um den oder die HTTPS-Ports nach außen verfügbar zu machen, müssen entweder die üblichen Einstellungen in /var/flash/ar7.cfg vorgenommen werden, also z.B. folgender Abschnitt unter forwardrules

        "tcp 0.0.0.0:443 0.0.0.0:443",

oder aber über die AVM-Oberfläche ein entsprechendes Port Forwarding auf ein virtuelles Interface konfiguriert werden. Das Ganze benötigen wir pro Service, d.h. wir müssen uns entscheiden, welcher Service den "Premium Port" 443 bekommt, der von überall her erreichbar sein sollte. Ich schlage vor, der Freetz-Oberfläche diesen Port zu geben, denn dadurch gelangen wir an die Rudi-Shell und können somit alles mit der Box anstellen, was wir wollen.

/!\ Wichtig: Es muß wohl nicht weiter erklärt werden, weshalb bei diesem Szenario einem sicheren Passwort für die Web-Oberfläche besondere Bedeutung zukommt…

HTTPS-Zugriff reloaded & improved

Die Aussicht auf ein Paket von (bei mir) 1.310 KB für die oben beschriebene Lösung ist natürlich ein K.O.-Kriterium für kleine Boxen, die sowieso schon mit dem Speicherplatz für einen Firmware-Mod haushalten müssen. Wer sowieso OpenSSL auf der Box für etwas anderes braucht, dem werden die 160 KB für stunnel + zlib zusätzlich nicht mehr viel ausmachen. Aber wer SSL nur für den HTTPS-Server benötigt, würde sich sicher über eine schlankere Variante freuen. Das Schöne ist: es gibt eine.

Es gibt eine für Embedded-Systeme optimierte Open-Source-SSL-Bibliothek Namens matrixssl. Außerdem hat jemand für OpenWRT den kleinen Wrapper matrixtunnel geschrieben, welcher unsere Alternative zu stunnel sein wird. Und es gibt das Ganze auch bereits als Paket für Freetz. Es handelt sich um ein Paket und eine Bibliothek mit der Gesamtgröße von 110 KB(!). Das entspricht einer Platzersparnis von ca. 92% gegenüber der ersten Lösung und funktioniert genauso gut nach meinen bisherigen Erfahrungen. So schnell wie ohne Verschlüsselung ist das Browsen subjektiv mit beiden HTTPS-Varianten nicht, aber absolut in Ordnung zum Arbeiten.

Inzwischen wurde auch xrelayd der Nachfolger von matrixtunnel in Freetz aufgenommen. Hier wird xyssl (inzwischen polarssl) als Crypt-Lib eingesetzt.

Der Aufruf, den man am besten in einer der beim Start ausgeführten Dateien (siehe Beschreibung der stunnel-Variante) unterbringt, sieht beispielhaft so aus:

matrixtunnel -A cert.pem  -p server_key.pem -d 443 -r 81 -P /tmp/matrixssl.pid

Ich verwende übrigens für -A und -p denselben Dateinamen und dieselbe kombinierte Datei mit Serverschlüssel und Zertifikat wie für stunnel (Bauanleitung s.o.). Gibt man zusätzlich -f an, startet der Server im Vordergrund und man kann die Ausgaben beobachten. Einen Debug-Schalter gibt es auch - einfach mal mit -? aufrufen und schauen.

Übrigens: matrixtunnel kann auch für jede Schnitstelle (IP-Adresse) eine andere Regel nutzen. Einfach die IP-Addresse vor dem Port (ip:port) angeben wie z.B.

# ds_mod web über SSL auf LAN
matrixtunnel -A mycert.pem -p mycert.pem -d 192.168.1.1:443 -r 192.168.1.1:81 -P /tmp/matrixssl.pid
# eigene Internetseite über SSL auf Virtual IP für externen Zugang
matrixtunnel -A mycert.pem -p mycert.pem -d 192.168.1.253:443 -r 192.168.1.253:82 -P /tmp/matrixssl.pid

Firmware remote flashen

Auch das geht mit Rudi wunderbar, wie ich seit längerer Zeit in einem Beitrag im Forum beschrieben habe. Hier nochmals der Code, den man in der Rudi-Shell auf einmal ausführen kann. Vorher stoppen wir am besten noch einige Freetz-Dienste, welche dem im Code aufgerufenen AVM-Skript nicht bekannt sind und die deshalb weiter laufen und Speicher verbrauchen würden.

# Bevor wir anfangen, ein Hintergrundbefehl: notfalls in 10 min die Box
# zwangsweise neu starten, das müßte für Download + FW-Update reichen.
{ sleep 600 ; reboot -f; } &

{
# Unnötige Dienste stoppen, aber websrv und dsld weiter laufen lassen
prepare_fwupgrade start_from_internet
# FW-Image herunterladen und direkt nach "/" entpacken
wget -q -O - http://mein.server.xy/mein.image 2> /dev/null | tar -C / -x
# Restliche Dienste stoppen
prepare_fwupgrade end
# Installation vorbereiten
/var/install
# Installation initialisieren
/var/post_install
# Box neu starten
reboot
}

Dieser Code funktioniert übrigens nicht nur in der Rudi-Shell, sondern grundsätzlich auch innerhalb einer Telnet- oder SSH-Sitzung.