Telekom Speedport Hybrid: Logging mit rrdtool

Als internetsüchtiges Landei greift man ja jedem Strohhalm, den man zu fassen bekommt. Ich hatte vor gut zwei Jahren zusätzlich zu unserem „normalen“ DSL-Anschluss der (je nach Tagesform) 10-14MBit/s bring noch einen LTE-Anschluss geklickt.

Das Problem an der Sache: bei zwei Uplinks man muss den Traffic intelligent routen. Eigentlich soll alles über LTE abgewickelt werden, aber man definiert dann unzählige Ausnahmen um möglichst keinen teuren LTE-Traffic zu vergeuden. Manche Dienste lassen sich auch schwer anhand von IPs und Ports in Filter gießen. Selbst mit viel Gefummel und Gehirnschmalz reichen dann 30GB für zwei Werktätige im Homeoffice eigentlich nicht aus.

Zum LTE-Vertragende wurden Hybrid-Anschlüsse bundesweit verfügbar. Das ist genau was ich eigentlich will: höhere Geschwindigkeit ohne Volumenlimit und mehr Redundanz, das alles ohne Fummelorgie in pf bzw. iptables. Einzig der Rant von Clemens in der Freakshow hat mich davon abgehalten sofort zuzuschlagen. Sein Fazit: das Produkt ist gut, aber der Router ist scheiße.

Nun habe ich einen Speedport Hybrid im Haus und kann diese Meinung vollumfänglich bestätigen. Das Webinterface des Routers ist eine Beleidigung. Javascript-Foo ohne Ende, es nervt mit unwichtigen Dingen wie Telefonie und diversen „Sicherheitsfeatures“. Man kann zeitgesteuert WLAN und Internet abschalten (ein sehr deutsches Feature), dafür kommt man aber an wichtige Informationen wie verbrauchter Traffic oder CRC-Fehler nicht ran. Das Webinterface warnt den User, wenn von einem weiteren Client darauf zugegriffen wird und ist auch sonst in jeder Hinsicht ein Usability-Verbrechen.

Her mit Deinen Daten!

Es gibt ein verstecktes „Engineer“-Menü, das viele Daten bereitstellt, die ich gerne hätte: Paket-Zähler der Interfaces; Dämpfung, SNR, CRC-Fehler und Bitrate auf der DSL-Leitung, Empfangsqualität des LTE-Signals ect.

Telekom Speedport Engineer Menu

Diese Daten wollte ich haben und mit rrdtool visualisieren. Dann hätte ich einen „DSL-Wetterbericht“ und weiß, wie es meinem Anschluss geht. Leider muss man sich jedes Mal auf dem Webinterface einloggen und dann die Engineer-URL in den Browser pasten.

Das ganze kann man schlecht automatisieren, solche Trümmer wie Selenium wollte ich nicht gleich auffahren. Ich habe mir deswegen zwei Sachen näher angeschaut:

  1. Die Firmware. Vielleicht gibt es noch einen einfachen Weg: es könnten durchaus Klartextscripte (lua?) in der Router-Firmware zu finden sein, die Rückschlüsse auf die Datenquellen zulassen.
  2. Die Kommunikation beim Login und das involvierte Javascript.

Die Firmware des Routers gibt es bei der Telekom zum Download. Mit Tools wie dem Firmware Modification Kit und binwalk kann man in das Image reinschauen und findet folgendes vor:

Target File: Firmware_Speedport_Hybrid_v050124.01.00.057.bin
MD5 Checksum: 086f589676e2cf108e755c2f0ad34649

DECIMAL HEX DESCRIPTION
----------------------------------------------------
132615 0x20607 JFFS2 filesystem, big endian
31098175 0x1DA853F PNG image, 488 x 2, 8-bit colormap, non-interlaced
31098375 0x1DA8607 JFFS2 filesystem, big endian
45205479 0x2B1C7E7 gzip compressed data
53720703 0x333B67F gzip compressed data
56458441 0x35D7CC9 gzip compressed data
56493219 0x35E04A3 gzip compressed data
66090195 0x3F074D3 gzip compressed data

Interessant: das Image enthält mehrere Firmware-Images: neben der für den „normalen“ Router gibt es noch ein vxworks-Image für den LTE-Teil des Routers. Die anderen Images konnte ich nicht genauer zuordnen, „mein“ Image ist mit 30MB das größte und lässt sich einfach mit dd rauskratzen. Das Image ist ein JFFS2 Image und ich konnte es auch mit viel googeln und fluchen nicht mounten. An der Stelle musste ich erstmal aufgeben und einen anderen Weg suchen.

well … SECURITY!

Zwischen Router und Browser wird http gesprochen, man kann also einfach mit Charles oder Wireshark den Traffic analysieren. Früher hatten andere Speedport Router ein HTTPS-Webinterface. Das hatte aber nicht nur Vorteile:

Es spricht viel dafür, dass das HTTP-only Webinterface ein Resultat der oben geschilderten Probleme ist.

Ab in das JavaScript-Schlammbad!

Also Augen zu und durch! Der interessante Code steckt in http://speedport.ip/js/pages/login.js. Als Beifang springen zwei Dinge sofort ins Auge:

Offenbar gibt es ein Standardpasswort für Servicezwecke. Entweder ist das Passwort statisch oder es lässt sich aus der Telekom verfügbaren Daten ableitet (IMEI oder Seriennummer …).

[Update] Ich habe in einem meiner vielen Telefonate mit der Telekom Störungsstelle einem Mitarbeiter die Information abgerungen, dass es nur ein hart codiertes Engineer-Password gibt … 🙁 [/Update]

Die Statusseite unter http://speedport.ip/html/login/status.html?lang=de ist ohne Login zugänglich und könnte den notwendigen Input liefern.
Insgesamt ist das schon gruselig, dass mein Provider meinen Router umkonfigurieren kann und ich nicht in der Lage bin es zu verhindern.

Ein weiteres interessantes Fundstück findet sich hier:

Offensichtlich findet beim Hersteller der Firmware kein Code-Review statt.

Die Speedport Login Prozedur

Damit trotzdem niemand das Router-Passwort mitlesen kann, unternimmt das Webinterface einen unglaublichen Eiertanz. Das Vorgehen ist vermutlich aus einem Crypto-Playbook, so ähnlich funktioniert auch der Login bei einigen Musikstreamingdiensten.

Zuerst sendet der Browser das hier zum Router:

Mit diesem Request wird challengev angefordert, der Router liefert darauf hin 52 zufällige Bytes zurück:

challengev muss im weiteren Verlauf der Sitzung immer als Cookie mitgesendet werden. Das eigentliche Passwort wird dann mit challengev in eine Hashfunktion geworfen und das Resultat daraus in sjcl.codec.hex.fromBits().

Sendet man das richtige Passwort…

… bekommt man in der Antwort eine Session-ID:

Die Speedport-Firmware macht sich dann noch die Mühe mit den ersten 16 Zeichen von challengev sowie dem Passwort einen symmetrischen Schlüssel mittels PBKDF2 abzuleiten. Das alleine dauert in einer V8 Engine mehr als eine Sekunde und ist der Hauptgrund für die Verzögerung beim Login:

Mit den insgesamt nur drei Cookies kann man dem Speedport endlich seine Daten abringen:

Wie ich später bemerkt habe, ist derivedk für die Abfrage der JSON Statusdaten aus dem Engineer-Menu nicht notwendig.

l33tport

Ich habe das ganze in node.js nachgebaut und als „l33tport“ veröffentlicht. Das Script führt den Login durch und lädt die Statusdaten als JSON runter. Damit bin ich erstmal am Ziel: ich kann die Rohdaten selbst verarbeiten. Erstes Ergebnis ist der oben erwähnte „DSL-Wetterbericht“:

DSL Wetterbericht

Mit dem Script als Basis sind natürlich noch ganz andere Dinge vorstellbar: ein alternatives, benutzbares Web-UI für den Router, integration des Routers in Hausautomation, eine „richtige“ App… Wie immer sind der Phantasie keine Grenzen gesetzt.

Update (24.05.2015): rrdtool Beispiele

Das Github-Projekt enthält jetzt ein paar Beispiele, wie man die rrdtool-Datenbanken erstellt, dort via cron Daten reinpumpt und wie man daraus bunte Graphen erstellt.

32 Antworten auf „Telekom Speedport Hybrid: Logging mit rrdtool“

  1. Hallo Melle,

    vielen Dank für Deinen super ausführlichen Artikel über den Speedport Hybrid. Ich habe das mal in einem Bashscript zusammengefasst:

    Schöne Grüße aus Duderstadt!
    Olli

  2. Hallo Melle,
    danke für den Artikel. Musste noch ein wenig probieren, bis ich es auf ubuntu zum Laufen bekommen habe, aber nur sehe ich initial erste Werte mal mit Historie und kann es ausbauen.

  3. Hallo Melle,

    ich versuche das ganze unter Windows (.Net) nachzubauen
    Leider scheitere ich am Aufruf der Enigneering-Seite, hier wird mir ein leeres Gerüst übergeben (kein fehlerhafter Login, sondern einfach keine Values). Eine Idee, was ich hier falsch mache?

    Weiter:
    Nachdem ich den challengev-Cookie/Value habe, wie berechne ich daraus (+ Loginpasswort), das Übergabevalue?

    Vielen Dank!

  4. Me again mit einer weiteren Frage.
    Ich habe mir ein Lubuntu installiert ob dein Script zu testen. Nun muss ich hinzufügen, dass ich von Linux keine Ahnung habe.

    Führe ich nun das Script von dir aus (getestet mit ‚./l33tport.js -f dsl“ und auch ’node ./l33tport.js -f dsl‘) gibt keine Rückmeldung/Ausgabe.
    Springt in die nächste Zeile, dass wars. Wird da eine Datei erzeugt und irgendwo angelegt, wo ich nicht nachsehe, oder sollte hier eine Rückgabe auf dem Terminal erfolgen?

    Danke und ratlosen Gruß

  5. @Grimoire

    „Challengev“ + „:“ + „passwort“ steckst du in sha256 rein. Das Resultat wird in sjcl.codec.hex.fromBits() gesteckt um es in Hex auszudrücken. Siehe auch das Script von Oliver oben.

    Unter Linux musst Du auf jeden Fall nodejs und die abhängigkeiten installieren. Also etwa so:

    aptitude install nodejs
    npm install sjcl
    npm install commander

    Ich habe unter OS X entwickelt, kann sein, dass das binary unter Linux node oder nodejs heisst. Du kannst dann auch das Script mit „node l33tport.js -f dsl“ aufrufen (in der ersten Zeile steht der Interpreter, kann sein, dass der bei Dir woanders liegt).

    Die Ausgabe von l33tport erfolgt immer auf der Konsole.

  6. Hallo Welle,
    vielen Dank für das Script.
    Ich möchte gerne die aktuelle Datentransfer-Rate und das Datenvolumen darstellen. Ich vermute, dass sich das durch Auslesen von „Interfaces“ und Werten „Out_Frames“ und „IN_Frames“ machen lässt. Ich habe gegoogled, konnte aber nicht zur Einheit der „In_Frames“ bzw. „Out_Frames“ finden.
    Weißt Du, in welcher Einheit die „In_Frames“ bzw. „Out_Frames“ dargestellt werden?

    Danke
    Martin

  7. Das ist die Zahl der Ethernet-Frames. Ein Frame kann maximal 1492 Bytes groß sein. Das Problem ist, dass ein Frame auch kürzer sein kann. Eine genaue Messung des Traffics ist damit also nicht möglich, kleinere Pakete (z.B. DNS / VoIP) zählen genau so viel wie “große” Pakete, die die MTU voll ausnutzen.

    Man kann mit den Werten sicherlich Graphen zeichnen für einen ungefähren Anhaltspunkt, für einen richtigen “Traffic-Tacho” taugt der Wert leider nicht.

  8. Danke für die Erklärung. Damit müsste sich ein Maximalwert des aktuellen Durchsatzes ermitteln lassen, unter der idealen Annahme, dass alle Frames 1.500 Bytes groß sind.
    Ich habe daraufhin die Werte eine zeitlang ausgelesen, komme aber auf keine plausiblen Werte. Vielleicht habe ich irgendwo noch einen Denk-/Rechenfehler?
    Was ich mache ist:
    1) Ich lese alle 10s die Werte „Out_Frames“ und „In_Frames“ des br0 Interface aus
    2) Ich berechne jeweils:
    (Out_Frames2 – Out_Frames1) * 1500 / 10 / 1024
    (In_Frames2 – In_Frames1) * 1500 / 10 / 1024
    Erläuterung:
    1.500 zur Umrechnung von Frames in Bytes
    10, weil ich ja nur alle 10 Sekunden abfrage
    1024, zur Umrechnung von Bytes in Kilobytes

    Damit müsste ich eigentlich die Datentransferrate in KB/s bekommen.
    Tatsächlich erhalte ich aber viel zu kleine Werte, z.B. 20, obwohl ich parallel mit mindestens 180 KB/s einen Download habe.

    Hast Du dafür eine Erklärung. Ist den br0 das richtige Interface? Ich bin davon ausgegangen, dass br0 genau die Bridge ins WAN ist.

  9. Hallo Melle,

    ich bin auf diesen Blogeintrag gestoßen, als ich nach einer Lösung zu einem weiteren Problem im Zusammenhang mit einem Speedport gesucht habe.
    Ich habe den Speedport W724V, der zeitgesteuert das Wlan deaktivert, bzw deaktivieren sollte.
    Das macht er leider nur wenn zum Zeitpunkt des Deaktivierens kein Gerät verbunden ist. Da dass aber so gut wie nie der Fall ist, ist die Zeitschaltung komplett unbrauchbar. In den Telekom Foren findet man dazu etliche Beiträge, und das schon seit Jahren.
    Da die Telekom, bzw deren Zulieferer aber anscheinend zu ignorant ist um das zu verbessern, habe ich mich selbst daran gemacht. Ob dus glaubst oder nicht, aber für mich war das durchaus ein ganzes Stück Arbeit.
    Herausgekommen ist ein python-Skript, dass über die Komandozeile verschiedene Parameter entgegen nimmt um so die einzelnen WLAN-Module an und auszuschalten. Auf einem Raspberry Pi mit cron Job verrichtet dieses nun zuverlässig seinen Dienst.
    Bekommen kann man das ganze unter:
    https://github.com/stenub/wlan_switcher
    Vielleicht hilft es jemandem der sich genauso über diese „vermurkste“ Funktion ärgert wie ich! 🙂

  10. Moin Melle!

    Erstmal danke für das Script und die ausführliche Beschreibung hier!

    Mit libCurl & libOpenSSL lies es sich dadurch auch recht leicht in C/C++ umsetzen.

    Ich war auch auf der Suche nach einem ‚Tacho‘ für die Verbindung und habe deshalb ein wenig mit deinem Script auf der Kommandozeile ‚gespielt‘.
    Dachte mir, daß die In-/OutOctetts des GRE-Tunnels da interessant sein könnten – aber damit kommt dein Script nicht klar 😉
    Mit ‚./l33tport -f bonding_tunnel‘ bekomme ich erst ein paar Daten und dann:

    Unexpected token ]
    SyntaxError: Unexpected token ]
    at Object.parse (native)
    at safeParse (/home/emkay/Entwicklung/SpeedportHybrid/l33tport:282:21)
    at /home/emkay/Entwicklung/SpeedportHybrid/l33tport:322:18
    at IncomingMessage. (/home/emkay/Entwicklung/SpeedportHybrid/l33tport:240:9)
    at IncomingMessage.emit (events.js:129:20)
    at _stream_readable.js:908:16
    at process._tickCallback (node.js:355:11)
    null

    Da scheint es zu einem Parsing-Fehler zu kommen.
    Dachte mir, ich sag‘ mal Bescheid.

    mfg, marcus

  11. @emkay der Speerport spuckt teilweise ungültiges JSON aus. Das müsste man von Hand reparieren, bevor es in den Parser geht. Es gibt ein issue auf Github dazu, pull requests werden gerne angenommen.

  12. Moin @Melle!

    Dachte ja erst, ich wär‘ da keine große Hilfe… Javascript umgehe ich normalerweise, wenn’s nich unbedingt sein muß.

    Mit GitHub kenn‘ ich mich auch nich sonderlich aus 😉

    Aber folgende Zeile eingefügt am Anfang des Try-Blocks in ’safeParse‘ wirkt wahre Wunder:
    ///
    input = input.replace(/}\s*,\s*]/g, „}]“);
    /// (wann immer ein alleiniges ‚,‘ zwischen ‚}‘ und ‚]‘ auftaucht, ersetze die Gruppe gegen ‚}]‘

    Um es einheitlich zu haben, habe ich das Gleiche dann bei mir auch in ’sendPassword‘ gemacht:
    Aus
    ‚var statusJSON = chunk;‘
    wurde
    ‚var statusJSON = chunk.replace(/}\s*,\s*]/g, „}]“);‘
    dafür kann dann dein Workaround entfallen 😉

    Mein C++-Code hatte die Probleme nicht, weil ich das ganze als RegEx-Training für C++11-RegEx genutzt hatte und deshalb ohne JSON-Parser gearbeitet habe. (wollte auch die Abhängigkeiten gering halten.) Dadurch habe ich diese Fallstricke wohl ’nebenbei‘ umgangen…

    mfg, emkay

  13. @melle: keine Ursache 😉
    RegEx is für mich (als C++ler) noch recht neu – aber ist als Tool schon ziemlich mächtig.
    Werd‘ mir dann mal deine neue Version anschauen, die neuen Daten-Felder scheinen interessant zu sein 😉

    mfg, emkay

  14. Moin melle!

    Wollte nur mal zurückmelden, das es auf der Kommandozeile des SPHs auch ‚xdslcmd‘ & ‚atcmd‘ gibt – falls Du schönere Messwerte des Routers haben möchtest… (wir haben mittlerweile Telnet, Root, etc… => stricted.net/forum/ oder einfach googlen 😉 )

    mfg, emkay

  15. Hallo Melle,
    bin gerade auf deinen sehr interessanten Blog gestoßen.
    Eine Frage.
    Ist dir beim durchstöbern des Engineer Menü auch eine Möglichkeit aufgefallen NAT Loopback einzurichten?
    Leider besteht ja auf normalen Weg keine Möglichkeit dazu, was äußerst nervig ist, wenn man eine Owncloud auf dem eigenen Server einrichten möchte und nicht auch noch zusätzlich einen eigenen DNS Server betreiben will.
    VG
    Silvio

  16. Hallo Melle, sagenhaft, ein kleiner wrapper in Perl um Dein Script drumrumgewickelt und ich habe ein Prima Check-Script für Icinga2 (was letztlich ebenfalls in rrd landet). Eines stößt mir aber auf (und ich bin kein JSON-Fachmann:

    Wenn ich „./l33tport.js -f PhoneCalls“ aufrufe, kommt eine Menge Hexdaten, mit denen ich so aus dem Stand nichts anfangen kann. Hast Du eine Idee?

    Grüße aus Mainz

  17. @Thomas Manche Felder sind nochmal verschlüsselt. Ich habe bisher noch keine Lust gehabt mich daran zu versuchen. Da die Daten letztendlich im Browser im Klartext angezeigt werden, sollte es auch möglich sein, die Entschlüsselung nachzuvollziehen, aber ich hatte noch keine Lust und Zeit dafür 🙂

  18. In den verlinkungen (stricted.net) ist ja nur vom Speedport Hybrid die Rede. Weis denn jemand wie man die Config und auch Telnet bei einem W724V hinbekommt, sind das die gleichen Methoden nur mit anderem Key und IV?

  19. Hallo Melle,

    Wäre es möglich, auch die PhoneCalls mit auszulesen.
    Am sinnvollsten wahrscheinlich als String, also ohne Json.

  20. Sorry eben vergessen: Wenn man erst mal eingeloggt ist, dann kann man die Anrufliste auch als Textdatei herunter laden, der Link ist nur veränderlich und ich bekomme ihn nicht raus aber im Script ist das vermutlich für jemanden, der sich auskennt keine große Sache mehr oder? 🙂

  21. Hallo Melle,
    ich habe dein Script heute gefunden und bekomme es leider nicht ans Laufen.
    Egal, was ich eingebe, nach einer Weile bekomme ich immer ein „Error: socket hang up“
    Selbst ein
    ./l33tport.js -f Status
    was ja kein Login braucht endet auf diese Weise
    Ich habe leider keine Idee, wie man node.js Scripte debuggt.

    Hast Du vielleicht eine Idee dazu?

    Hier nochmal die gesamte Meldung eines Aufrufs:

    $ ./l33tport.js -f Status
    events.js:160
    throw er; // Unhandled ‚error‘ event
    ^
    Error: socket hang up
    at createHangUpError (_http_client.js:254:15)
    at Socket.socketOnEnd (_http_client.js:346:23)
    at emitNone (events.js:91:20)
    at Socket.emit (events.js:185:7)
    at endReadableNT (_stream_readable.js:974:12)
    at _combinedTickCallback (internal/process/next_tick.js:80:11)
    at process._tickCallback (internal/process/next_tick.js:104:9)

  22. Hallo das scrip von Oliver hat bis vor etwa einen halben Jahr getan. seit dem scheint im login etwas verändert worden zu sein, die IP adressen werden nicht mehr ausgegeben.

  23. Hi, könntest du das Ding auch für netdata anpassen?
    Da braucht du dich um die visualisierung nicht zu kümmern , sondern nur die datenliefern.

  24. Hallo Melle,

    ich habe seit 19.12.2017 einen Speedport Hybrid mit der aktuellen Firmeware 050124.03.07.001
    Unter Windows 7 (64-bit) erhalte ich beim Aufruf
    node ./l33tport.js -f Status
    events.js:137
    throw er; // Unhandled ‚error‘ event
    ^

    Error: socket hang up
    at createHangUpError (_http_client.js:330:15)
    at Socket.socketOnEnd (_http_client.js:423:23)
    at Socket.emit (events.js:165:20)
    at endReadableNT (_stream_readable.js:1101:12)
    at process._tickCallback (internal/process/next_tick.js:152:19)

    Gibt bzw. wird an einer Lösung gearbeitet? 🙂

  25. Tier Down Telekom Speedport Hybrid.

    EngineerPassword=“huaweiDt_eng“

    Sometimes its too simple…

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.