"Christmas - the time to fix the computers of your loved ones" « Lord Wyrm

Suche Script um FritzBox Reconnect durchzuführen

daisho 30.11.2023 - 15:04 5692 15
Posts

daisho

SHODAN
Avatar
Registered: Nov 2002
Location: 4C4
Posts: 19706
Wollte nur mal Fragen ob jemand sowas schon im Einsatz hat, wenn nicht dann nicht (Google bedienen kann ich selber auch :p).

Geht prinzipiell darum dass ich permanent/regelmäßig aus der LTE/5G Verbindung rausgeschmissen werde wenn ich viel Traffic verursache (Fullspeed-Download, ev. auch Upload), aber leider so dass die Verbindung zwischen Modem und Mast/Provider weiterbesteht, aber auf der Ebene darüber nichts mehr geht (keinerlei TCP Verbindung irgendwo hin möglich, die Provider-Seite läuft allerdings im Sausebraus :o).

Ich hatte das interessanterweise auch bei Magenta als Provider früher genauso :confused:

So oder so, ich brauche ein Script das optimalerweise auf meinem Windows Server (Linux geht theoretisch auch, Windows wäre mir lieber) läuft und regelmäßig Connectivity überprüft und im Problemfall auf die FritzBox geht (falls das über API geht wäre das natürlich besser als irgendein interaktives Script) und dort einen Reconnect auslöst.

spunz

Super Moderator
Super Moderator
Avatar
Registered: Aug 2000
Location: achse des bösen
Posts: 11259
nicht geprüft, aber das könnte funktionieren => https://gist.github.com/CarstenG2/1...9a1cc34fb88397b

Viper780

Er ist tot, Jim!
Avatar
Registered: Mar 2001
Location: Wien
Posts: 50035
Wie wärs mit automai?

Ich hab so ein reconnect Script früher für Jdownloader gehabt.
https://jdownloader.org/knowledge/w...m-fritzbox-upnp

daisho

SHODAN
Avatar
Registered: Nov 2002
Location: 4C4
Posts: 19706
Die meisten Skripte inklusive von JDownloader laufen scheinbar nicht mehr oder aus irgendeinem Grund nicht auf meiner Box.

Der Service und Action urn:schemas-upnp-org:service:WANIPConnection:1#ForceTermination findet man überall, liefert aber nur Fehler zurück, obwohl die auch so in der fritz.box/tr64desc.xml so gelistet sind.

Das Carsten Script nutzt jetzt eine andere URL und Service-Name:
http://fritz.box:49000/igd2upnp/control/WANIPConn1
urn:schemas-upnp-org:service:WANIPConnection:2#ForceTermination

Das "funktioniert" interessanterweise (unter Anführungszeichen, komme später dazu).
Es gibt auch ein PIP Package FritzConnection welches sehr angenehm zu benutzen ist (https://fritzconnection.readthedocs...ng_started.html), Initialisierung dauert allerdings etwas lang (liest da die komplette Box aus denke ich) deswegen ist das Carsten Script einfach performanter.

Mein Problem hat sich dadurch leider nicht gelöst. Im Event Log der Box sehe ich zwar:
Code:
03.12.23	23:59:16	Internet connection established successfully. IP address: 11.222.333.444, DNS server: 22.33.44.55 and 22.33.44.55, gateway: -
03.12.23	23:59:16	Internet connection cleared.
Aber das passiert quasi "instant" (ohne Unterbrechung bei regelmäßigen Pings z.B.) und ändert nichts an einer Problemsituation.
Es löst bei mir nicht die Mobile LTE/5G Connection und sucht neu, was bei einem Druck auf den "Reconnect" Button in der UI passiert.
Dann sieht das üblicherweise so aus:
Code:
04.12.23	07:21:32	Internet connection established successfully. IP address: 11.222.333.444, DNS server: 22.33.44.55 and 22.33.44.55, gateway: -
04.12.23	07:21:32	Mobile network connection established (75000/75000 kbit/s).
04.12.23	07:21:32	Connecting to mobile network...
04.12.23	07:21:32	Mobile network found.
04.12.23	07:21:31	Search for mobile networks in range.
04.12.23	07:20:59	Internet connection cleared.
04.12.23	07:20:51	Login to the FRITZ!Box user interface from the IP address X.X.X.X.

Werde mal den Entwicklungssupport bei AVM anschreiben ob die mir helfen können, hier in den API Beschreibungen habe ich leider keine Funktion gesehen die mich Mobile Provider neu suchen lässt o.Ä. (dafür kann ich PIN/PUK setzen o.Ä.).

daisho

SHODAN
Avatar
Registered: Nov 2002
Location: 4C4
Posts: 19706
Schade :(
Zitat
Der TR064 Service WANIPConnection1 ist nur für DSL-Verbindungen funktional.
WANIPConnection2 ist hingegen ein UPNP Service. Dieser nutzt einen anderen Mechanismus für den Disconnect.
Der TR064 Service X_AVM-DE_WANMobileConnection1 hat bisher keine Möglichkeit der Zwangstrennung. Dieses Enhancement ist aktuell auch nicht auf der Roadmap.

Wir hoffen, dass Sie mit dieser Info weiterkommen und wünschen viel Erfolg bei Ihrem Entwicklungsprojekt.
Geht dann wohl echt nur über interaktives Skript.

Drei hat mir außerdem versichert dass das so bleiben wird weil es ein Sprach-SIM-Tarif ist und kein Home-Internet-Datentarif :o

mr.nice.

differential image maker
Avatar
Registered: Jun 2004
Location: Wien
Posts: 6472
Es gibt Steckerleisten, die in regelmäßigen Abständen IPs pingen können und wenn etwas nicht erreichbar ist, gewisse Steckdosen aus- und einschalten können. Ich denke das würde in deinem Fall auch eine Möglichkeit sein.

Viper780

Er ist tot, Jim!
Avatar
Registered: Mar 2001
Location: Wien
Posts: 50035
Zitat aus einem Post von mr.nice.
Es gibt Steckerleisten, die in regelmäßigen Abständen IPs pingen können und wenn etwas nicht erreichbar ist, gewisse Steckdosen aus- und einschalten können. Ich denke das würde in deinem Fall auch eine Möglichkeit sein.

Ein nettes SmartHome Projekt mit einem Shelly ;)

daisho

SHODAN
Avatar
Registered: Nov 2002
Location: 4C4
Posts: 19706
Das stimmt, wäre sogar super einfach zu machen (via URL Aufruf dass dann eine Aktion ausführt).
Sauberer für die Uptime wäre wohl der Weg über das UI, vermute dass der Bootvorgang der Box doch etwas länger dauert als einfach nur ein Reconnect (das ist innerhalb von ein paar Sekunden wieder da). Aber AutoHotKey oder so mit Image Recognition im Skript ... bäh :p

COLOSSUS

Administrator
GNUltra
Avatar
Registered: Dec 2000
Location: ~
Posts: 12075
Exponiert das FRITZ!Box-Webinterface denn eine solche Funktion, die du per Browser ausloesen kannst? (Die die Verbindung zum APN wiederherstellt, oder das LTE-Modem rebootet?) Wenn ja, dann kann man das auch Headless scripten - die Frage ist lediglich, wie muehsam es (auch je nach Wahl des Toolings) wird.

Vielleicht hat man im Dunstkreis von Freetz(-NG) auch eine Loesung fuer dein Problem parat -> https://freetz-ng.github.io/freetz-ng/

Ich wuerde jedenfalls davon ausgehen, dass auch die Embedded-FW auf deiner Fritzbox entweder via Hayes/AT Command Set und/oder QMI mit dem LTE-Modem spricht, und man, das Wissen um das richtige Kommando vorausgesetzt, das mit Shell-Zugriff bzw. RCE ausloesen wird koennen, auch wenn es von keiner offiziellen API exponiert wird.

daisho

SHODAN
Avatar
Registered: Nov 2002
Location: 4C4
Posts: 19706
Custom Firmware wollte ich eigentlich nicht drauf spielen, Shell Access gibt es in der Default Firmware scheinbar mittlerweile auch nicht mehr.

Die XHR Requests sind nicht so schwer zu finden:
Code:
"response=4272944f63b22f0c91a4604ae4d6266c%2311e844957f2ed0c3f579ec7436ab972aafd86ad43368e981aab014e7017c1d7c&lp=&loginView=simple&username=fritz1234",
"xhr=1&sid=840a0cc9d330f675&lang=en&page=netMoni&xhrId=reconnect&disconnect=true&useajax=1&no_sidrenew=",
"xhr=1&sid=840a0cc9d330f675&logout=1&no_sidrenew=",

Natürlich: wtf ist die "response". Dr. Google fand eine Technical Note (AVM Technical Note - Session ID_EN - Nov2020.pdf) zum Login und das enthält netterweise auch ein Python Example inklusive des Handlings der Challenge-Response Authentication für ein Login.
Funktioniert auch soweit und eine SID kann geholt werden. Absetzen des Reconnect Commands wird damit wohl kein Problem mehr sein.

Example:
Code:
#!/usr/bin/env python3
# vim: expandtab sw=4 ts=4

"""
FRITZ!OS WebGUI Login

Get a sid (session ID) via PBKDF2 based challenge response algorithm.
Fallback to MD5 if FRITZ!OS has no PBKDF2 support.
AVM 2020-09-25
"""

import sys
import hashlib
import time
import urllib.request
import urllib.parse
import xml.etree.ElementTree as ET

LOGIN_SID_ROUTE = "/login_sid.lua?version=2"


class LoginState:
    def __init__(self, challenge: str, blocktime: int):
        self.challenge = challenge
        self.blocktime = blocktime
        self.is_pbkdf2 = challenge.startswith("2$")


def get_sid(box_url: str, username: str, password: str) -> str:
    """ Get a sid by solving the PBKDF2 (or MD5) challenge-response process. """
    try:
        state = get_login_state(box_url)
    except Exception as ex:
        raise Exception("failed to get challenge") from ex

    if state.is_pbkdf2:
        print("PBKDF2 supported")
        challenge_response = calculate_pbkdf2_response(state.challenge, password)
    else:
        print("Falling back to MD5")
        challenge_response = calculate_md5_response(state.challenge, password)

    if state.blocktime > 0:
        print(f"Waiting for {state.blocktime} seconds...")
        time.sleep(state.blocktime)

    try:
        sid = send_response(box_url, username, challenge_response)
    except Exception as ex:
        raise Exception("failed to login") from ex
    if sid == "0000000000000000":
        raise Exception("wrong username or password")
    return sid

def get_login_state(box_url: str) -> LoginState:
    """ Get login state from FRITZ!Box using login_sid.lua?version=2 """
    url = box_url + LOGIN_SID_ROUTE
    http_response = urllib.request.urlopen(url)
    xml = ET.fromstring(http_response.read())
    # print(f"xml: {xml}")
    challenge = xml.find("Challenge").text
    blocktime = int(xml.find("BlockTime").text)
    return LoginState(challenge, blocktime)

def calculate_pbkdf2_response(challenge: str, password: str) -> str:
    """ Calculate the response for a given challenge via PBKDF2 """
    challenge_parts = challenge.split("$")
    # Extract all necessary values encoded into the challenge
    iter1 = int(challenge_parts[1])
    salt1 = bytes.fromhex(challenge_parts[2])
    iter2 = int(challenge_parts[3])
    salt2 = bytes.fromhex(challenge_parts[4])
    # Hash twice, once with static salt...
    hash1 = hashlib.pbkdf2_hmac("sha256", password.encode(), salt1, iter1)
    # Once with dynamic salt.
    hash2 = hashlib.pbkdf2_hmac("sha256", hash1, salt2, iter2)
    return f"{challenge_parts[4]}${hash2.hex()}"

def calculate_md5_response(challenge: str, password: str) -> str:
    """ Calculate the response for a challenge using legacy MD5 """
    response = challenge + "-" + password
    # the legacy response needs utf_16_le encoding
    response = response.encode("utf_16_le")
    md5_sum = hashlib.md5()
    md5_sum.update(response)
    response = challenge + "-" + md5_sum.hexdigest()
    return response

def send_response(box_url: str, username: str, challenge_response: str) -> str:
    """ Send the response and return the parsed sid. raises an Exception on error """
    # Build response params
    post_data_dict = {"username": username, "response": challenge_response}
    post_data = urllib.parse.urlencode(post_data_dict).encode()
    headers = {"Content-Type": "application/x-www-form-urlencoded"}
    url = box_url + LOGIN_SID_ROUTE
    # Send response
    http_request = urllib.request.Request(url, post_data, headers)
    http_response = urllib.request.urlopen(http_request)
    # Parse SID from resulting XML.
    xml = ET.fromstring(http_response.read())
    return xml.find("SID").text

def main():
    if len(sys.argv) < 4:
        print(
            f"Usage: {sys.argv[0]} [url]http://fritz.box[/url] user pass"
        )
        exit(1)
    
    url = sys.argv[1]
    username = sys.argv[2]
    password = sys.argv[3]

    sid = get_sid(url, username, password)
    print(f"Successful login for user: {username}")
    print(f"sid: {sid}")

if __name__ == "__main__":
    main()

spunz

Super Moderator
Super Moderator
Avatar
Registered: Aug 2000
Location: achse des bösen
Posts: 11259
Ggf mal diverse Smarthome Adapter zwecks Beispielcode prüfen. tr064 Support für Callmonitore, Wlan Steuerung oder Reboot haben ja praktisch alle:

https://github.com/iobroker-communi...ioBroker.tr-064

Viper780

Er ist tot, Jim!
Avatar
Registered: Mar 2001
Location: Wien
Posts: 50035
TR064 ist aber nur für DSL nicht für 5G

spunz

Super Moderator
Super Moderator
Avatar
Registered: Aug 2000
Location: achse des bösen
Posts: 11259
Zitat aus einem Post von Viper780
TR064 ist aber nur für DSL nicht für 5G

Das hindert AVM nicht daran auch weitere Funktionen einzubauen. Von der Zigbee Lampe, Wlan Konfig, Anrufbeantworter bis zum NAS Server ist ja alles mit dabei. Man hat es schlicht und einfach nicht auf der Roadmap, siehe auch dem Kommentar von AVM weiter oben.

daisho

SHODAN
Avatar
Registered: Nov 2002
Location: 4C4
Posts: 19706
Keine Tragödie. Problem ist auf meiner Seite quasi solved.
Hab es mit Postman gerade getestet, mit dem Skript oben einfach SID holen und mit Postman dann einen einfachen POST Request absetzen:

Code:
http://fritz.box/data.lua
Parameter:
  xhr = 1
  sid = {{sid}}
  lang = en
  page = netMoni
  xhrId = reconnect
  disconnect = true
  useajax = 1
  no_sidrenew =
Fetzt 1A

Muss das jetzt nur noch ins Python-Skript einbauen, davor einen Ping-Check auf Google.at o.Ä. setzen damit das Skript weiß wann es die Connection killen soll voila.
Mal schauen ob ich am Wochenende dazu komme, jetzt um Weihnachten hat das nicht so hohe Priorität :p

RoboByte

Bloody Newbie
Registered: Dec 2023
Location: Wien
Posts: 1
@daisho hast du den Python-Script schon fertig?

Ich suche auch so einen Reconnect-Script.
Würde den gern automatisch jeden Tag über mein NAS starten (z.B. Linux/Cronjobs).
Kontakt | Unser Forum | Über overclockers.at | Impressum | Datenschutz