Schneller Reconnect der FRITZ!Box in Python

Python Logo

Wer hätte nicht gerne eine Möglichkeit mal eben schnell die FRITZ!Box per Shellskript zu einem Reconnect zu überreden? Ganz am Anfang (Jahr 2000 oder so?) gab es ja nur so eine “dubiose” Binary für Windows, welche per UPNP ulra schnell die FRITZ!Box reconnecten konnte.(2 Sekunden ca.)

Heute machen wir das ein bisschen schöner(nicht nur für Linux!) in Python (Version 2.x):

#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2011  Geekparadise.de
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# Contact: http://geekparadise.de/contact/
# Usage: ./reconnect.py
# Version: 1.0
# Only for Python 2.x!

import re
import pycurl
import StringIO
import sys

def post_data(data):
        encoded_data = ["Content-Type: text/xml", \
        "charset: utf-8", "SoapAction: urn:schemas-upnp-org:service:WANIPConnection:1#"+data]
        encoded_data2=("""<?xml version="1.0" encoding="utf-8"?>
        <s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
        xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
        <s:Body>
        <u:"""+data+"""s xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1" />
        </s:Body>
        </s:Envelope>""")
        try:
                b = StringIO.StringIO()
                curl = pycurl.Curl()
                curl.setopt(pycurl.POSTFIELDS, encoded_data2)
                curl.setopt(pycurl.HTTPHEADER,encoded_data)
                curl.setopt(pycurl.TIMEOUT,10)
                curl.setopt(pycurl.CONNECTTIMEOUT,10)
                curl.setopt(pycurl.URL, "http://fritz.box:49000/upnp/control/WANIPConn1")
                curl.setopt(pycurl.WRITEFUNCTION, b.write)
                curl.perform()
                return b.getvalue()
        except:
                print "Error: connection problems."
                exit(-1)

# Query actual IP and show it
ip = re.split(r"<NewExternalIPAddress>",post_data("GetExternalIPAddress"))
if len(ip) > 1:
        ip = re.split(r"</NewExternalIPAddress>",ip[1])
else:
        print "Error: IP query failed."
        exit(-1)
print "Actual IP: "+ip[0]

# start reconnect
sys.stdout.write("Reconnect...")
sys.stdout.flush()
post_data("ForceTermination")
print "done."

# Query actual IP
ip2 = re.split(r"<NewExternalIPAddress>",post_data("GetExternalIPAddress"))
if len(ip2) > 1:
        ip2 = re.split(r"</NewExternalIPAddress>",ip2[1])
else:
        print "Error: IP query failed."
        exit(-1)

# Check if IP has changed: True -> show new IP; False -> show error.
if ip[0] != ip2[0]:
        print "New IP: "+ip2[0]
        exit(0)
else:
        print "Error: IP did not change."
        exit(-1)

Für Distributionen mit Python 3 als Standard sollte man die erste Zeile in

#!/usr/bin/python2

ändern.

Das ganze in reconnect.py (oder wie ihr es nennen wollt..) packen und mit chmod +x reconnect.py ausführbar machen.

Weiterhin muss der UPNP Kram in der Fritz!Box aktiviert sein.(Bei mir ist das irgendwo bei “Netzwerkeinstellungen” und dort muss ” Statusinformationen über UPnP übertragen (empfohlen)” und “Änderungen der Sicherheitseinstellungen über UPnP gestatten” aktiviert sein.)

Übrigens: Der reconnect selbst geht extrem schnell (~1-2 Sekunden) nur die Abfrage der neuen IP braucht einige Sekunden, in der Weboberfläche ist sie viel schneller sichtbar.

Getestet hab ich das auf einer FRITZ!Box SL Wlan, ob das bei neueren Modellen auch noch geht, weiß ich nicht.

Die Idee stammt übrigens nicht von mir, ursprl. kommt sie glaube ich aus einem Reconnect Binary für Windows,
blog.Jbbr.net hat dann eine Curlvariante für Linux dazu geschrieben. Details zur Fritz!Box UPNP Geschichte hab ich dann bei OpenShots gefunden. Danke dafür!

Falls ihr sagt “Wow, WTF ist eine FRITZ!Box?”, FRITZ!Box ist ein DSL-Router der Firma AVM. Falls ihr auch einen schnellen Reconnect wollt: Kauft euch eine FRITZ!Box, AVM freut sich ;)

Update(18.03.2012):
Aufgrund einer Nachfrage hier noch die “verbesserte” Version, ich weiß gar nicht mehr genau was ich geändert habe, jedenfalls versucht diese Version 3 Mal die IP zu wechseln. Zusätzlich habe ich ein paar Kleinigkeiten geändert, weil es bei der älteren manchmal etwas Probleme gab .. wie auch immer, jedenfalls klappt diese Version ganz gut, ich nutze sie schon länger…
Noch eine Änderung gab es: Es wird nun checkip.dyndns.org genutzt um die eigene IP abzufragen, weil das bisherige da eher unzuverlässig war.

#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2012  Geekparadise.de
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# Contact: http://geekparadise.de/contact/
# Usage: ./reconnect.py
# Version: 1.1
# Only for Python 2.x!

import re
import pycurl  
import StringIO 
import sys
import time

def getIP():
        b = StringIO.StringIO()
        curl = pycurl.Curl()
        curl.setopt(pycurl.TIMEOUT,10)
        curl.setopt(pycurl.CONNECTTIMEOUT,10)
        curl.setopt(pycurl.URL, "http://checkip.dyndns.org")
        curl.setopt(pycurl.WRITEFUNCTION, b.write)
        curl.perform()
        ip = re.search(r'\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b',b.getvalue())
        if ip:
                return ip.group(0)
        else:
                return false	


def post_data(data):
        encoded_data = ["Content-Type: text/xml", \
        "charset: utf-8", "SoapAction: urn:schemas-upnp-org:service:WANIPConnection:1#"+data]
        encoded_data2=("""<?xml version="1.0" encoding="utf-8"?>
        <s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
        xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
        <s:Body>
        <u:"""+data+"""s xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1" />
        </s:Body>
        </s:Envelope>""")
        try:
                b = StringIO.StringIO()
                curl = pycurl.Curl()
                curl.setopt(pycurl.POSTFIELDS, encoded_data2)
                curl.setopt(pycurl.HTTPHEADER,encoded_data)
                curl.setopt(pycurl.TIMEOUT,10)
                curl.setopt(pycurl.CONNECTTIMEOUT,10)
                curl.setopt(pycurl.URL, "http://fritz.box:49000/upnp/control/WANIPConn1")
                curl.setopt(pycurl.WRITEFUNCTION, b.write)
                curl.perform()
                return b.getvalue()
        except:
                print "Error: connection problems."
                exit(-1)
                
def reconnect():
        # Query actual IP and show it
        ip = re.split(r"<NewExternalIPAddress>",post_data("GetExternalIPAddress"))
        if len(ip) > 1:
                ip = re.split(r"</NewExternalIPAddress>",ip[1])
        else:
                print "Error: IP query failed."
                exit(-1)
        print "Actual IP: "+ip[0]
        # Start reconnect
        sys.stdout.write("Reconnect...")
        sys.stdout.flush()
        post_data("ForceTermination")
        print "done."
        # Query actual IP
        ip2 = getIP()
        if ip2 == False:
                print "Error: IP query failed."
                exit(-1)
        if ip[0] != ip2:
                print "New IP: "+ip2
                return True
        else:
                return False
        
counter = 0
bool = reconnect()
while not bool and counter < 3:
        print "Error: IP did not change."
        time.sleep(2)
        print "Trying again...."
        bool = reconnect()
        counter = counter + 1 

if counter >= 3:
        print "Error: 3 failed attempts...abborting."
        exit(-1)        
exit(0)

Comments (5)

  1. 20:20, August 3, 2011Rookee  / Reply

    Es gibt für Firefox-User auch das praktische Plugin Fox!Box. Bei mir dauert ein Reconnect damit auch so 1~ 2 Sekunden. (Womit ich natürlich keinen davon abhalten möchte, das geniale Python mal auszuprobieren.)

  2. 15:51, September 24, 2011dark...  / Reply

    Verwende doch “#! /usr/bin/env python” statt den hartkod. Pythonpfad

  3. 15:53, September 24, 2011Andreas  / Reply

    Danke für den Tipp!

    Kannte ich gar nicht ;)

    Hab von dem Skript hier eh eine verbesserte Variante, werde ich demnächst mal updaten!

  4. 18:28, May 15, 2012fly  / Reply

    Gibts da auch ne Möglichkeit, einen VoIP-Check mit einzubauen?

  5. 18:17, November 27, 2014Daniel  / Reply

    Hi Andreas,

    danke für das neue Skript. Allerdings war noch ein Fehler drin beim ersten Abfragen der IP und die neuen Fritzboxen verwenden eine andere URL. Wenn du magst kann ich dir die angepasste Version schicken.

Leave a Reply

Allowed Tags - You may use these HTML tags and attributes in your comment.

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Pingbacks (0)

› No pingbacks yet.