Statusanfragen per UPnP

From Fritz!Box
Jump to: navigation, search

AVM Wiki >> Tipps+Tricks >> Statusanfragen per UPnP @ whmf   -   IRC-Chat   -   hu nl it English
Community Modelle Zubehör Environment Konfiguration Shell-Befehle Software Freetz Lexikon Tipps+Tricks Bilder

Hardware-Tipps System-Tipps Netzwerk-Tipps Telefonie-Tipps Software-Tipps Sonstige Tipps Todo

Statusanfragen per UPnP

Über Skripte wie das folgende können verschiedene Parameter der Fritz!Box per UPnP/SOAP ausgelesen werden. Hier wird der momentane Durchsatz abgefragt (Bytes in/out), bzw. mit der Option "-ip" erscheint die aktuelle externe IP-Adresse. Die Option "-a" gibt alle Informationen über die DSL-Schnittstelle aus.

#!/bin/bash

NETCAT=`which netcat`
[ -z "$NETCAT" ] && NETCAT=`which nc`
[ -z "$NETCAT" ] && exit 1

INTERFACE_NS="urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1"
WANIP_NS="urn:schemas-upnp-org:service:WANIPConnection:1"

if [ "$1" = "-ip" ]; then
        NS="$WANIP_NS"
        REQUEST="GetExternalIPAddress"
        SED='/^<NewExternalIP/ s,</\?NewExternalIPAddress>,,gp'
else
        NS="$INTERFACE_NS"
        REQUEST="GetAddonInfos"
        if [ "$1" = "-a" ]; then
                SED='s,<New,<, ; /^<[a-zA-Z]*[ >]/ s,^<\([^> ]*\) *>\([^<]*\)</.*,\1\t\2,p'
        else
                SED='s/Send/OUT/ ; s/Receive/IN/ ; /^<NewByte/ s,^<NewByte\([^>]*\)Rate>\([^<]*\)<.*,\1\t\2,gp'
        fi
fi

( $NETCAT 192.168.178.1 49000 | sed -ne "$SED" ) <<EOF
POST /upnp/control/WANCommonIFC1 HTTP/1.1
Content-Type: text/xml; charset="utf-8"
HOST: 192.168.178.1:49000
Content-Length: 0
SOAPACTION: "$NS#$REQUEST"

<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
        <s:Body><u:$REQUEST xmlns:u=$NS /></s:Body>
</s:Envelope>
EOF

Das Skript ist übrigens im Wesentlichen eine Zusammenfassung der Arbeit anderer Wiki-Teilnehmer. Vielen Dank!

Das oben aufgeführte Script funktioniert nicht mehr mit neueren Firmwareversionen, da diese das "Content-Lenght" Feld auswerten. Das folgende modifizierte Skript läuft auf neueren Frimwareversionen (getestet 29.04.40), auf älteren hingegen nicht. Diese scheinen den xml content nicht richtig zu interpretieren.

#!/bin/bash

FRITZ_IP=192.168.178.1

NETCAT=`which netcat`
[ -z "$NETCAT" ] && NETCAT=`which nc`
[ -z "$NETCAT" ] && exit 1

( [ -n "$FRITZ_IP" ] && $NETCAT -z $FRITZ_IP 49000 ) || exit 1;

INTERFACE_NS="urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1"
WANIP_NS="urn:schemas-upnp-org:service:WANIPConnection:1"

if [ "$1" = "-ip" ]; then
        NS="$WANIP_NS"
        REQUEST="GetExternalIPAddress"
        SED='/^<NewExternalIP/ s,</\?NewExternalIPAddress>,,gp'
else
        NS="$INTERFACE_NS"
        REQUEST="GetAddonInfos"
        if [ "$1" = "-a" ]; then
                SED='s,<New,<, ; /^<[a-zA-Z]*[ >]/ s,^<\([^> ]*\) *>\([^<]*\)</.
*,\1\t\2,p'
        else
                SED='s/Send/OUT/ ; s/Receive/IN/ ; /^<NewByte/ s,^<NewByte\([^>]
*\)Rate>\([^<]*\)<.*,\1\t\2,gp'
        fi
fi

body="<?xml version=\"1.0\" encoding=\"utf-8\"?> \
<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" \
   s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\
        <s:Body><u:$REQUEST xmlns:u=$NS /></s:Body>\
</s:Envelope>"

( $NETCAT $FRITZ_IP 49000 | sed -ne "$SED"  ) <<EOF
POST /upnp/control/WANCommonIFC1 HTTP/1.1
Content-Type: text/xml; charset="utf-8"
HOST: $FRITZ_IP:49000
Content-Length: ${#body}
SOAPACTION: "$NS#$REQUEST"

$body
EOF

UPnP-Anfrage aus Python heraus

Unter Verwendung einer High-Level-Skriptsprache und Rückgriff auf eine SOAP-Bibliothek geht es auch kompakter:

#!/usr/bin/env python
from SOAPpy import SOAPProxy
print SOAPProxy(proxy='http://192.168.178.1:49000/upnp/control/WANCommonIFC1',
                namespace='urn:schemas-upnp-org:service:WANIPConnection:1',
                soapaction='urn:schemas-upnp-org:service:WANIPConnection:1#GetExternalIPAddress',
                noroot=True).GetExternalIPAddress()

Getestet gegen eine FRITZ!Box 2170.

Anzumerken ist noch, dass die FRITZ!Box recht eigenwillige Vorstellungen von XML hat: ein entsprechendes Perl-Skript mit der Bibliothek SOAP::Lite bekommt immer eine Fehlermeldung der FRITZ!Box zurück, da es im Envelope-Element der XML-Nachricht neben dem soap-Namespace "http://schemas.xmlsoap.org/soap/envelope/" weitere Namespaces definiert (xsi, xsd) und diese Attribute vor das soap-Attribut stellt. Das mag die FRITZ!Box gar nicht; bearbeitet man eine SOAP::Lite-Nachricht manuell derart, dass das soap-Namespace-Attribut vor den anderen erscheint, klappt es...

Mögliche UPnP-Anfragen

Mögliche UPnP-Anfragen sind in verschachtelten XML-Beschreibungsdateien definiert, die einander baumartig referieren. Mehr dazu im UPnP-Artikel. Das folgende Beispiel zeigt wie sich die für IGD zuständigen Dateien abrufen lassen, ist aber ansonsten ein schlechtes Beispiel, da es die Baumstruktur ignoriert und blind davon ausgeht dass diese Dateien vorhanden sind.

for i in igddesc.xml igdconnSCPD.xml igdicfgSCPD.xml igddslSCPD.xml ; do
  wget http://fritz.box:49000/$i
done

Mehr als eine Fehlermeldung kann dabei nicht passieren, besser wäre jedoch zuerst igddesc.xml anzufordern, und die darin referierten Dateien entsprechend ihrer Funktion auszufiltern, da Pfade sich immer ändern können und Funktionen je nach Modell und Firmware garnicht vorhanden oder deaktiviert sein können.

Die Grundidee von UPnP ist es die Funktionsblöcke eines Geräts im LAN bekannzugeben, mit URLs zu ihrer jeweiligen XML-Beschreibungsdatei. Ein interessierter Client filtert dabei die gewünschte Basisfunktion heraus (zb IGD) und ruft die annoncierte XML-Beschreibungsdatei ab. Diese Methode ist enorm zukunftssicher, nahezu unendlich erweiterbar und es sind keinerlei Annahmen über Port, Protokoll, Host und Pfad zum XML-Dokument notwendig. Dies erfordert allerdings den Empfang der (selten gesendeten) UPnP Broadcasts und das Interpretieren des XML, beides Aufgaben die mit Standard Shell-Befehlen kaum elegant zu lösen sind.