- Mac-Adresse des Routers ändern
- Kabelmodem neustarten
Klingt eigentlich ganz einfach, dachte ich... Mein Kabelmodem ist ein Scientific Atlanta (Cisco) EPC2203, welches vor einer FritzBox 7570 steckt. Nach mehreren erfolglosen Google-Anfragen konnte ich keine passende Lösung für mein Problem finden, also beschloss ich mir selbst etwas zu schreiben.
Meine Voraussetzungen sind eigentlich ganz einfach:
- Skript zur Einbindung in unterschiedlichen Programmen, also kein Kompilat
- Skript muss größtenteils mit Standard-Linux-Befehlen funktionieren
- Keine modifizierte oder erweiterte Firmware der FritzBox
So weit so gut, der Befehl für das Neustarten des Modems war schnell im Netz gefunden:
curl http://192.168.100.1/goform/gscan -d SADownStartingFrequency=687000000
- enable_mac_override muss auf yes gesetzt werden, damit die Adresse überschrieben werden kann
- macdsl_override muss auf die neue MAC gesetzt werden
OK, den Telnet-Zugang zur Fritzbox aktiviert und verbunden:
telnet fritz.box
Da die ar7.cfg nicht direkt bearbeitet werden kann muss diese erst in das tmp-Verzeichnis der Box kopiert werden und wird dann später wieder zurückkopiert. Nach zahllosen Versuchen mit den begrenzten Befehlssatz der Box um meine Anforderungen zu erfüllen, kam ich dann letztendlich zu dieser Lösung:
cat /var/flash/ar7.cfg > /var/tmp/ar7.cfg sed -i '/enable_mac_override/cenable_mac_override = yes;' /var/tmp/ar7.cfg sed -i "s/\(macdsl_override = .*:\)\(.*\);$/\1$(cat /dev/urandom | tr -cd 'A-F 0-9' | head -c 2);/" /var/tmp/ar7.cfg cat /var/tmp/ar7.cfg > /var/flash/ar7.cfg exec /etc/init.d/rc.net reload
Zur zeilenweisen Erklärung :
Zeile 1:
Das vorher angesprochene Kopieren der Datei in den temporären Ordner
Zeile 2:
Es wird die Zeile mit enable_mac_override gesucht und - unabhängig von deren Inhalt wird diese mit enable_mac_override = yes; überschrieben.
Zeile 3 (die hat mit Abstand am längsten gedauert ;) ):
Es wird nach macdsl_override gesucht und der letzte Teil der MAC-Adresse ausgelesen. Dieser wird mit einer hexadezimalen Zufallszahl aus /dev/urandom ersetzt. Danch wird die ganze Zeile in die ar7.cfg zurückgeschrieben.
Zeile 4:
Die ar7.cfg wird wieder an ihren Ursprungsort kopiert
Zeile 5:
Damit die Einstellungen übernommen werden, wird nun noch die Netzwerkkonfiguration der FritzBox neu eingelesen.
Nachdem das nun funktioniert hat bleibt noch die Herausforderung das ganze per Skript auszuführen. Leider kommt man hier mit bash nicht wirklich weit und muss auf expect ausweichen. In den meisten Distributionen ist dies schon vorinstalliert. Hiermit ist es möglich interaktive Terminalsitzungen - wie bspw. telnet - auszulagern, Befehle abzusetzen und bestimmte Ausgaben zu überprüfen.
Das resultierende Skript sieht dann so aus:
#!/usr/bin/expect spawn telnet fritz.box expect "password: " send "MySecretPasswordReplaceWithYourOwn\n" expect "#" send "cat /var/flash/ar7.cfg > /var/tmp/ar7.cfg\n" expect "#" send "cat /var/tmp/ar7.cfg | grep overr\n" expect "#" send "sed -i '/enable_mac_override/c\enable_mac_override = yes;' /var/tmp/ar7.cfg\n" expect "#" send "sed -i \"s/\\(macdsl_override = .*:\\)\\(.*\\);$/\\1\$(cat /dev/urandom | tr -cd 'A-F0-9' | head -c 2);/\" /var/tmp/ar7.cfg\n" expect "#" send "cat /var/tmp/ar7.cfg > /var/flash/ar7.cfg\n" expect "#" send "cat /var/flash/ar7.cfg | grep overr\n" expect "#" send "exec /etc/init.d/rc.net reload\n" expect "#" send "exit" exit
Am Anfang wird die telnet-Verbindung herausgelöst (gespawned) und gewartet bis die Box eine Zeile mit dem Inhalt password: zurückgibt. Danach wird mein Passwort hingeschickt, da meine Box abgesichert ist. Es ist immer empfehlenswert die Oberfläche des Routers abzusichern, das gleiche Passwort wird auch bei Telnet benutzt. Wichtig ist nur das jede Send-Zeile mit \n beendet werden muss, dies bestätigt den Befehl und darf nicht gelöscht werden wenn ihr euer Passwort ersetzt.
Im Anschluss folgen die Befehle, die ich vorher schon einmal beschrieben habe. Diese sehen leicht verändert aus, da man im Skript bestimmte Zeichen maskieren muss. Die zwei zusätzlichen Zeilen, die grep beinhalten verändern nichts an der Funktion und geben lediglich die Vorher- und Nachherwerte der beiden geänderten Parameter aus. Diese Ausgabe kann bspw. für ein Logfile verwendet werden.
Das Schlimmste ist geschafft, nun muss nur noch das Skript zum Ändern der MAC und das zum Neustarten des Modems zusammengführt werden. Ich habe das expect-Skript als fritz.sh im selben Ordner abgelegt und rufe dieses über ein anderes Skript namens reconnect.sh auf:
#!/bin/bash DIR=$(cd $(dirname "$0"); pwd) LOG=$DIR/reconnect.log MACSCRIPT=$DIR/fritz.sh PASSWORD=MySecretPasswordReplaceWithYourOwn getIP() { curl http://ipecho.net/plain; echo } changeMAC() { $MACSCRIPT } restartModem() { curl http://192.168.100.1/goform/gscan -d SADownStartingFrequency=687000000 } waitUntilOnline() { while true do ping -c 1 ipecho.net >> $LOG if [[ $? == 0 ]]; then echo "Connection established. Waiting five more seconds." >> $LOG sleep 5 break; else echo "Waiting..." >> $LOG sleep 5 fi done } echo Old IP = $(getIP) > $LOG echo Restarting Modem++++++++++++++++ >> $LOG restartModem >> $LOG echo Changing FritzBox Mac ++++++++++++++++ >> $LOG changeMAC >> $LOG waitUntilOnline echo New IP = $(getIP) >> $LOG
Im Grunde ist das ganze ganz einfach. Zuerst wird die aktuelle IP ausgelesen und in eine Logdatei geschrieben. Anschließend wird das Modem neugestartet und die MAC der FritzBox geändert. waitUntilOnline prüft alle 5 Sekunden, ob die Internetverbindung schon wieder da ist um dann zum Schluss die neue IP ins Logfile zu schreiben.
Das war schon Alles ;) Das Skript kann man bestimmt noch etwas aufhübschen und etwas fehlertoleranter gestalten, es tut aber was es soll. Der Reconnect dauert zwischen 3 und 5 Minuten, da das Modem relativ träge ist bis es neu gestartet ist.
Falls ihr das Skript nachvollziehen wollt, muss ich vorher noch eine Warnung loswerden:
Die Skripte können im schlimmsten Fall die Box lahmlegen und es sollte vorher recherchiert werden, ob dies bei eurer FB genauso funktioniert. Ich kann und werde keine Garantie für kaputte Geräte übernehmen.
Ich konnte das Skript mit mehreren FritzBox-Modellen ausprobieren und es hat immer gut funktioniert. Im Zweifelsfall solltet ihr aber die einzelnen Teile der Telnet-Session einzeln ausprobieren, deshalb habe ich diese separat geschrieben. Ich konnte das Skript auch - mit leichten Anpassungen - unter Windows mit Hilfe von Cygwin laufen lassen. Folgendes musste ich dafür tun:
- expect und curl nachinstallieren (waren in der Standardinstallation nicht vorhanden)
- Der Ordner der Skripte durfte kein Leerzeichen beinhalten
- Alle Logausgaben entfernt (> $LOG), habe nicht näher recherchiert warum das nicht funktioniert
- Im expect-Skript die Zeile spawn telnet fritz.box durch spawn /usr/bin/telnet fritz.box ersetzt, da sonst das Win-Standard-Telnet benutzt wird.
Punkt 2 und 3 ist bestimmt auch anders lösbar, vielleicht will ja ein Windows-Nutzer seine Lösung posten.
Was ihr natürlich noch ändern müsst ist der Mechanismus zum Neustarten des Modems per URL, falls ihr ein anderes Modem habt. Dies sind aber im Netz relativ leicht zu finden.
Viel Spaß mit den beiden Skripten, ich freue mich auf eure Kommentare.