foxthefox / ioBroker.fritzdect

Fritzbox DECT adapter for ioBroker
MIT License
40 stars 12 forks source link

Keine Kommunikation mehr mit Fritzbox nach Wechsel von raspberry pi 4 zu Docker #377

Open Reddingo opened 1 year ago

Reddingo commented 1 year ago

Hallo,

ich habe den Fritz Dect Adapter 2.2.6 auf einen raspberry pi 4 erfolgreich installiert und mit der Fritzbox verbunden. Da die RPi zu schwach wurde habe ich die komplette Installation in ein Docker Contrainer unter Windows 11 umgezogen. Seit dem läuft der Fritz Dect Adapter nicht mehr. Zu Testzwecken habe ich den Raspi gestartet und dort klappt alles sofort. Ich kann also ausschließen, dass die Credentials falsch sind, bzw dass der Benutzer unzureichend in der Fritzbox eingerichtet ist.

Infos: Fritzbox 6591 mit FritzOS 07.29 Auf dem RasPi erfolgreich mit 2.2.6 installiert und Geräte abgerufen Extra Benutzer (der auf dem RasPi immer noch läuft) Docker läuft unter Windows 11 (alle anderen Adapter laufen ohne Probleme) Adapter Versionen 2.2.0, 2.2.6 und 2.3.0 in dem Docker getestet. Alle Firewalls sind aus

Wenn ich in den Instance-Einstellungen das ganze von http auf https stelle, hört er nach "fritzdect user USER: iobroker" wieder auf.

Gibt es noch Tips was ich machen könnte? Benutzt der Adapter irgendwelche IP-Multicasts, Broadcasts oder sonst eine Unicast Kommunikation die von der Fritzbox initieriert wird? (mir gehen echt die Ideen aus)

Ein Screenshot der Logfiles im Anhang.

Logausgabe

foxthefox commented 1 year ago

Der Adapter kommuniziert direkt mit der IP der FB, die im config angegeben wurde. Der Adapter initiert die Kommunikation um Daten anzufragen. Wenn es im container ist, ist denn die FB auch erreichbar bzw. wird das Antwortelegram auch richtig durchgereicht?

Hab da keine Erfahrung mit Docker unter Win11, aber wenn die Dockerinstallation keine eigene IP im Heimnetz hat, sondern eine interne, dann könnte das ggf. etwas sein, wonach man suchen kann. Ich hab den Adapter unter proxmox laufen und da geht es.

Unabhängig davon, könnte ich noch irgendwie den Fall abfangen, damit der Adapter nicht abstürzt. Das ändert aber nichts an der Tatsache, daß die Kommunikation nicht läuft. Laut log wird versucht sich einzuloggen, was aber nicht funktioniert.

Reddingo commented 1 year ago

Ich habe einmal Wireshark angeschmissen und das ganze aufgezeichnet. Verbindungsausbau (SYN;SYN-ACK;ACK) klappt ohne Probleme und ich bekomme dann die folgenden 2 Pakete (Request und Response):

HTTP-Request:

Hypertext Transfer Protocol
    GET http://192.168.1.1/login_sid.lua?version=2 HTTP/1.1\r\n
    Host: 192.168.1.1\r\n
    User-Agent: Go-http-client/1.1\r\n
    Connection: close\r\n
    Content-Type: application/x-www-form-urlencoded\r\n
    \r\n
    [Full request URI: http://192.168.1.1/login_sid.lua?version=2]
    [HTTP request 1/1]
    [Response in frame: 300]

HTTP-Response:

Transmission Control Protocol, Src Port: 80, Dst Port: 49446, Seq: 117, Ack: 179, Len: 194
[2 Reassembled TCP Segments (310 bytes): #279(116), #300(194)]
Hypertext Transfer Protocol
    HTTP/1.1 503 Service Unavailable\r\n
    Connection: close\r\n
    Content-Length: 194\r\n
    Content-Type: text/html; charset=utf-8\r\n
    \r\n
    [HTTP response 1/1]
    [Time since request: 0.049398000 seconds]
    [Request in frame: 277]
    [Request URI: http://192.168.1.1/login_sid.lua?version=2]
    File Data: 194 bytes
Line-based text data: text/html (1 lines)
    <HTML><HEAD><TITLE>503 Service Unavailable (ERR_FORBIDDEN)</TITLE></HEAD><BODY><H1>503 Service Unavailable</H1><BR>ERR_FORBIDDEN<HR><B>Webserver</B> Sun, 22 Jan 2023 21:05:30 GMT</BODY></HTML>\r\n

Hilft das weiter?

foxthefox commented 1 year ago

so weit runter in den Netzwerkverkehr hab ich mich noch nicht bewegt. Aber es sieht so aus, daß der login aufgerufen wird und die FB mit Error Forbidden 503 Service Unavailable antwortet.

Folgendes wäre ne Idee:

Bin gespannt was im FB-log steht

Reddingo commented 1 year ago

Ich hab noch einiges getestet gestern Nacht.

Im Logfile von der FB finde ich gar nichts, liegt auch daran, dass mit dem ersten Aufruf nach meinem Verständnis nach noch keine Credentials ausgetauscht werden. Mit dem Aufruf (vom Browser) sieht man dass hier nur der letzte Login zurück kommt und man eine Session-ID bekommt.

Die anderen Vorschläge hatte/habe ich alle getestet.

Ich habe nun aber einmal den Verkehr auf dem RasPi mitgeschnitten und verglichen.

HTTP-Request vom RasPi:

Transmission Control Protocol, Src Port: 45442, Dst Port: 80, Seq: 1, Ack: 1, Len: 128
Hypertext Transfer Protocol
    GET /login_sid.lua?version=2 HTTP/1.1\r\n
    Content-Type: application/x-www-form-urlencoded\r\n
    Host: 192.168.1.1\r\n
    Connection: close\r\n
    \r\n
    [Full request URI: http://192.168.1.1/login_sid.lua?version=2]
    [HTTP request 1/1]
    [Response in frame: 326]

mit der HTTP-Response an den RasPi:

2 Reassembled TCP Segments (1023 bytes): #324(1023), #326(0)]
Hypertext Transfer Protocol
    HTTP/1.1 200 OK\r\n
    Cache-Control: no-cache\r\n
    Connection: close\r\n
    Content-Type: text/xml\r\n
    Date: Mon, 23 Jan 2023 08:21:21 GMT\r\n
    Expires: -1\r\n
    Pragma: no-cache\r\n
    X-Frame-Options: SAMEORIGIN\r\n
    X-XSS-Protection: 1; mode=block\r\n
    X-Content-Type-Options: nosniff\r\n
     [truncated]Content-Security-Policy: default-src 'none'; connect-src 'self'; font-src 'self'; frame-src https://service.avm.de https://help.avm.de https://www.avm.de https://avm.de https://assets.avm.de https://clickonce.avm.de http://cli
    \r\n
    [HTTP response 1/1]
    [Time since request: 0.072247707 seconds]
    [Request in frame: 321]
    [Request URI: http://192.168.1.1/login_sid.lua?version=2]
    File Data: 272 bytes
eXtensible Markup Language
    <?xml
(...)

Der einzige Unterschied beim Request ist hier, dass aus dem Docker heraus der User-Agent: Go-http-client/1.1 geschickt wird und beim RasPi nicht. Ich will nicht ausschließen dass dieser User-Agent von der Fritzbox blockiert wird? Weiß hier jemand mehr? Und kann man den User-Agent in der benützen Lib irgendwie ändern?

Nachtrag:

Ich habe einmal nach den User-Agent gesucht und der wird wohl von Google für deren Robots verwendet. Aus meiner Sicht macht es seitens FB schon Sinn den zu blocken wenn die FB aus dem Internet erreichbar ist. Ob nun aber auch auf dem internen Interface Sinn macht lass ich mal so stehen, aber ein paar Suchen haben ergeben dass dieser spezielle User-Agent wohl öfters Probleme macht. Eine Lösung wäre nun, dass man den User-Agent in deiner Lib (wenn möglich) entfernt so dass es läuft wie bisher, oder aber auf etwas setzt was niemanden mehr stört (geht hier 'iobroker/1.0' ? oder statt der 1.0 die Version deines Adapters).

Ich werde heute Abend noch ein paar mehr Tests machen wenn ich wieder zu Hause bin. Ich versuche dann herausfinden wie ich das zum Testen ggf. patchen kann.

foxthefox commented 1 year ago

mal eine kurze Zwischenmeldung, ich verwende in der library den nativen http aus nodej, also nichts außergewöhnliches und da macht die lib keinen Unterschied wo sie installiert ist

Reddingo commented 1 year ago

meinst du node.js?

Also auf dem RasPi habe ich es geschafft in irgendeiner Datei (hab nur nach LOGIN_SID_ROUTE gesucht) das wie folgt zu ändern:

const options = {
                hostname: hostname,
                port: port || defaultport,
                path: LOGIN_SID_ROUTE,
                method: 'GET',
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded',
                    'User-Agent': 'iobroker.fritzdect/2.2.6'
                },
                rejectUnauthorized: false
            };

Danach wurde der user-agent im Request angepasst. Gut möglich dass er für den default, wenn man nichts explizit angibt, eben den Go-http-client/1.1 nimmt. Ich habe das auch bei einem anderen Adapter (homepilot.20) im Wireshark gesehen dass dort auch der user-agent gesetzt wurde.

Ich kämpfe aktuell damit im Docker die Datei ebenso zu patchen, da aber dort kein vi und keingarnichts installiert ist, gestalltet sich das Ganze sehr schwierig...

foxthefox commented 1 year ago

ja, nodejs

was du auch noch probieren könntest ist ein connection test in der library dazu in /opt/iobroker/node_modules/fritzdect-aha-nodejs gehen und dann in das Verzeichnis /lib/conn_test

dort gibt es ein fritz.py und fritz.js

beides kann man mit den parametern http://IP user pw aufrufen, um die Verbindung zu testen

foxthefox commented 1 year ago

meinst du node.js?

Also auf dem RasPi habe ich es geschafft in irgendeiner Datei (hab nur nach LOGIN_SID_ROUTE gesucht) das wie folgt zu ändern

Sollte im fritzdect-aha-nodejs/lib/fritz_ahaapi.js gewesen sein Grundsätzlich kann ich das ändern, weil es auch mein eigenes Repo ist, ich mag aber noch nicht so dran glauben, daß dies die Ursache ist, Woher soll denn der geänderte User_agent kommen, strange

Reddingo commented 1 year ago

Okay. Ich habe das mit dem Patchen des User-Agents im Docker geschafft und musste feststellen, dass das nicht das Problem ist. ABER, was ich übersehen habe in den beiden Wireshark Aufzeichnungen:

RasPi: GET /login_sid.lua?version=2 HTTP/1.1\r\n

Docker: GET http://192.168.1.1/login_sid.lua?version=2 HTTP/1.1\r\n

Bei dem Docker hat das "http://192.168.1.1" überhaupt nichts zu suchen. Und ich habe keine Ahnung woher das kommt.

Zur Info: Auf dem Docker und dem RasPi laufen beide Node.js: v16.19.0 und NPM: v8.19.3

foxthefox commented 1 year ago

yepp, das sieht komisch aus. wüsste nicht wo in der library der Pfad noch um die IP erweitert würde, das sind zwei verschiedene Dinge Wie schon vorher mal geschrieben in einem proxmox lxc container läuft iobroker bei mir sauber, mit exakt gleicher Version Node.js: v16.19.0 und NPM: v8.19.3

foxthefox commented 1 year ago

hab grad gesehen, das aber keine Auswirkung auf den vollen Aufruf hat, man hätte vermiten können, daß hier 2mal die IP auftaucht, wenn es Teil des Pfades wäre.

    GET http://192.168.1.1/login_sid.lua?version=2 HTTP/1.1\r\n
    [Full request URI: http://192.168.1.1/login_sid.lua?version=2]

Full request ist in beiden Fällen gleich, löst da wireshark anders auf?

Ich bin eher wieder an der 503-Forbidden Antwort die die FB loslässt, gibt es parallel zur Dockerinstanz noch andere Instanzen oder Adapter oder Apps die gleichzeitig mit der FB kommunizieren? Wundert mich, daß hier nicht die FB etwas mitloggt.

Reddingo commented 1 year ago

Ich habe zum Testen eben einen eigenen Java-HTTP-Client gebaut und konnte das Problem nun final eingrenzen: Sobald ich mit dem Client das hier schicke:

GET http://192.168.1.1/login_sid.lua?version=2 HTTP/1.1\r\n (...) bekomme ich genau die gleiche Fehlermeldung von der Fritzbox:

HTTP/1.1 503 Service Unavailable\r\n

lasse ich den http-Kladderadatsch weg und schicke nur /login_sid.lua?version=2 HTTP/1.1\r\n, kommt die richtige Antwort.

Wie finde ich heraus welche nodejs lib Datei für den HTTP-Request in dem Docker verwendet wird?

foxthefox commented 1 year ago

was meinst du? die 2.3.0 verwendet das npm-Paket fritzdect-aha-nodejs und dort unter wird mit der /lib/fritz_ahaapi.js die Kommunikation erledigt. in fritz_ahaapi.js selbst hat keine externen Abhängigkeiten, sie verwendet das http-Paket, welches im node.js enthalten ist

also der Aufruf an die FB ist http://192.168.1.1/login_sid.lua?version=2, dies verpackt das http-Paket in die Telegrammstruktur. http://192.168.1.1/http://192.168.1.1/login_sid.lua?version=2 wäre da falsch, weil die IP nochmal Teil des Pfades ist. mich wundert, daß "Full request" in beiden Fällen gleich ist, obwohl im GET Unterschiede sind. musstest du im Java-client für den Fehler die IP nochmal als Pfad angeben?

Reddingo commented 1 year ago

Was ich gemacht habe ist ein Lowlevel Client der den HTTP-Request als puren Header-String zur FB schickt. Mehr macht ein HTTP-Client ja nicht, er bastelt ja primär auch nur den Header zusammen ;-)

  InetAddress adr = InetAddress.getByName("192.168.1.1");
  sock = new Socket(adr, 80);

  OutputStream out = sock.getOutputStream();
  BufferedReader in = new BufferedReader(new InputStreamReader(sock.getInputStream()));

  String s = "GET /login_sid.lua?version=2 HTTP/1.1\r\n" + 
          "Host: 192.168.1.1\r\n" + 
          "User-Agent: iobroker/1.1\r\n" + 
          "Connection: close\r\n" + 
          "Content-Type: application/x-www-form-urlencoded\r\n" + 
          "\r\n";

  out.write(s.getBytes());

  String line = in.readLine();
  while (line != null) 
  {
     System.out.println(line);
     line = in.readLine();
  }

Wenn ich das so mache bekomme ich eben die identische 503-Fehlermeldung wie aktuell bei dir.

(...)

  String s = "GET http://192.168.1.1/login_sid.lua?version=2 HTTP/1.1\r\n" + 
          "Host: 192.168.1.1\r\n" + 
          "User-Agent: iobroker/1.1\r\n" + 
          "Connection: close\r\n" + 
          "Content-Type: application/x-www-form-urlencoded\r\n" + 
          "\r\n";
(...)

Meine Frage nach der nodejs-lib bezog sich auf die Frage wo normalerweise die lib liegt. Ich habe einmal nach der Datei node.js, http.js und request.js gesucht und einen ganzen Zoo von Dateien gefunden in den unterschiedlichsten Ordnern. Daher war die Frage ob man irgendwie herausfinden kann welche der Libs genau verwendet werden bzw wo diese liegen.

Ich versuche die Lib zu finden und mir dort die Stelle rauszusuchen wo das Ganze zusammengebaut und an den Server verschickt wird. Du machst ja in deinem Code nichts anderes als dass du die ganzen Infos für den Header an den request übergibst und der baut dass dann im Hintergrund für dich irgendwie zusammen und schickt es ab. Und diese Stelle versuche ich zu analysieren. Da ich keinen Debugger habe hilft nur code-reading :-)

PS: Ich bin mal mit der fritzdect Version wieder auf 2.2.6 gegangen welche die letztgültige im iobroker repository ist und auf dem gleichen Stand zu sein wie der RasPi.

foxthefox commented 1 year ago

also im code mach eine request auf die native http Bibliothek. Ich bin mir nicht sicher ob dazu überhaupt ein node_module Verzeichnis notwendig ist, oder es direkt im node.js drin ist.

Reddingo commented 1 year ago

So langsam habe ich das Gefühl, dass der Docker ausgehende HTTP-Pakete manipuliert!

Ich habe ein JS gemacht welches exakt den gleichen Inhalt wie mein Java Programm gestern an die FB verschickt, nämlich HTTP-Rohdaten . Im Ausgehenden Stream im Wireshark sehe ich aber wieder, dass er vor das er die ersten Zeichen wieder manipuliert zu GET http://192.168.1.1/login_sid.lua?version

Das Script:

var net = require('net');

var client = net.connect({host: '192.168.1.1', port: 80}, function () {

    var s = 'GET /login_sid.lua?version=2 HTTP/1.1\r\n' + 
            'Host: 192.168.1.1\r\n' + 
            'User-Agent: iobroker/1.1\r\n' + 
            'Connection: close\r\n' + 
            'Content-Type: application/x-www-form-urlencoded\r\n' + 
            '\r\n';

    client.write(s);
});

client.on('data', function (data) {
    console.log(data.toString());
    client.end();
});

client.on('end', function () {
    console.log('disconnected from server');
});

client.on('error', function (error) {
    console.error(`Did not get an OK from the server. Code: ${res.statusCode}`);
});

Kannst du das Script mal aus deinem iobroker heraus starten und gucken ob du die erwartete Antwort bekommst oder auch das hier: javascript.0 (176) script.js.common.Skript1: <HTML><HEAD><TITLE>503 Service Unavailable (ERR_FORBIDDEN)</TITLE></HEAD><BODY><H1>503 Service Unavailable</H1><BR>ERR_FORBIDDEN<HR><B>Webserver</B> Wed, 25 Jan 2023 21:33:15 GMT</BODY></HTML>

foxthefox commented 1 year ago

hab den JS Adapter in iobroker installiert und deinen code laufen lassen das kam raus:

javascript.0 (2280) script.js.Skript_1: HTTP/1.1 200 OK Cache-Control: no-cache Connection: close Content-Type: text/xml Date: Wed, 25 Jan 2023 22:04:42 GMT Expires: -1 Pragma: no-cache X-Frame-Options: SAMEORIGIN X-XSS-Protection: 1; mode=block X-Content-Type-Options: nosniff Content-Security-Policy: default-src 'none'; connect-src 'self'; font-src 'self'; frame-src https://service.avm.de https://help.avm.de https://www.avm.de https://avm.de https://assets.avm.de https://clickonce.avm.de http://clickonce.avm.de http://download.avm.de https://download.avm.de 'self'; img-src 'self' https://tv.avm.de https://help.avm.de/images/ http://help.avm.de/images/ data:; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; frame-ancestors 'self'; media-src 'self' <?xml version="1.0" encoding="utf-8"?><SessionInfo><SID>0000000000000000</SID><Challenge>2$60000$09006aebfc0c45a3b006e59c914407ef$6000$7637bb32c346bd41f8c1cbc9a92debb7</Challenge><BlockTime>0</BlockTime></SessionInfo>

Edit: Vergaß zu erwähnen, daß das die erwartete Antwort ist, unabhängig das es schon Status 200 ist.

Reddingo commented 1 year ago

Vielen Dank, sieht aus wie gewollt. Das bestätigt was ich mitlerweile befürchtet habe, dass Docker die ausgehenden Header der HTTP-Requsts wohl irgendwie verpfuscht.

rsc-90 commented 1 year ago

Hallo zusammen,

ich hatte bis eben das gleiche Problem.

Iobroker läuft unter Windows (Docker Desktop + WSL, jeweils aktuelle Version). Die Fehlermeldung ließ sich aus dem Docker-Container (aus anderen auch) auch über curl -X GET http://<Fritzbox-IP> reproduzieren.

Auf einem anderen PC mit gleicher Konfiguration hatte ich das Problem nicht. Ich habe festgestellt, dass Docker Desktop auf letzterem PC unter einer älteren Version (4.2.0) läuft, also habe ich Docker Desktop von dem Gerät, auf dem ich Iobroker betreiben will, gelöscht und die alte Docker Dekstop Version installiert.

Ich kann mir nicht erklären warum, aber damit läuft es.

Reddingo commented 1 year ago

Ich hab das Thema mal ins Docker-Forum getragen, wenn ich dort eine Lösung finde lass ich es euch hier wissen.

foxthefox commented 1 year ago

Danke