[Frage] Remote reboot

night4awk

Neuer User
Mitglied seit
25 Dez 2012
Beiträge
15
Punkte für Reaktionen
0
Punkte
0
Hallo,

ich habe eine FritzBox 7390 (v6.30).
Da ja seit einiger Zeit der Telnet-Zugriff abgeschaltet wurde, habe ich mich gefragt, ob es möglich ist die FritzBox über das lokale Netzwerk neu zu starten.
Gibt ein ein CLI-Kommando, mit dem man über eine Linux-Maschine im selben lokalen Netzwerk, einen Reboot-Befehl an die FritzBox schicken kann?
Oder geht so etwas eventuell auch per UPnP?

Danke
 
Moins


Eventuell geht es mit der Wählhilfe, die den Code wählt...
(Achtung: Wählhilfe muss mit einem Gerät assoziiert sein)
Code:
ONLY REBOOT
Neustart der FRITZ!Box ohne Einstellungen zu verändern
#990*15901590*
 
Zuletzt bearbeitet:
TR-064 - DeviceConfig

Funktion "Reboot" (wahlweise auch "FactoryReset", wenn der Neustart besonders nachhaltig sein soll ... Scherz, do not try this at home)
 
Pöh, Wählhilfe geht, da Webbasiert (AVM-Webinterface), auch über Fernzugang.

Aber auf meinem Desktop, seh ich grad, liegt was "fertiges" rum...
(Basierend auf UPnP/TR-064, siehe PeterPawn seinen Post)
fbreboot.php
PHP:
<?php
$fritzbox_Adresse = 'fritz.box';
$fritzbox_Username = 'Benutzer_mit_Konfigurationsrecht';
$fritzbox_Password = 'daslebenistharttristtrostloslangweiligfadeödeundunerotisch';

$client = new SoapClient(
    null,
    array(
        'location'   => 'http://'.$fritzbox_Adresse.':49000/upnp/control/deviceconfig',
        'uri'        => 'urn:dslforum-org:service:DeviceConfig:1',
        'noroot'     => True,
        'login'      => $fritzbox_Username,
        'password'   => $fritzbox_Password,
        'trace'      => True,
        'exceptions' => 0
    )
);

$action = 'Reboot';
$argument = 'NewSessionID';

$SID = '0000000000000000';
$direction_in_value = $SID;

//$result = $client->{$action}(new SoapParam($direction_in_value, $argument));
$result = $client->{$action}();

if(is_soap_fault($result))
{
 print(" Fehlercode: $result->faultcode | Fehlerstring:
         $result->faultstring");
}
else
{
 print "$result\n";
}

var_dump ($result);

?>
EDIT: Aufruf, nach dem editieren und eintragen von $fritzbox_Adresse und $fritzbox_Username ...
Code:
php fbreboot.php
Rückgabewert: NULL (Bei Erfolg)
Geht auch unter Windows, sofern PHP installiert (im PATH).

Es steht leider kein Autor im Header.
Möge er mir verzeihen.

...oder war ichs etwa selbst :?: Nein! :silly:

@PeterPawn: Was ist denn nun besser/richtiger ?
'http://'.$fritzbox_Adresse.':49000/upnp/control/deviceconfig'
...oder doch vorsichtigerweise...
'https://'.$fritzbox_Adresse.':49000/upnp/control/deviceconfig'

Mein "altes" PHP (von XAMPP) auf Windows meldet bei HTTPS...
"SSL support is not available in this build"
 
Zuletzt bearbeitet:
Pöh, Wählhilfe geht, da Webbasiert (AVM-Webinterface), auch über Fernzugang.
Ist zwar jetzt mal nicht getestet, aber das sollte für die TR-064-Funktion auch gelten ... zumindest das mit "über den Fernzugang", webbasiert ist die eher nicht.

Aber auf meinem Desktop, seh ich grad, liegt was "fertiges" rum...
Na ja, das ist ja nun genau das Benutzen dieses Interfaces ... wobei ich mich mit so "etwas kleinem" wie einer PHP-Installation als Basis nicht zufrieden geben würde ... für solche "komplexen Aufgaben" sollte es schon eine virtuelle Maschine sein, auf der ein vollwertiges Serversystem inkl. SMTP-, SSH-Service (und was weiß ich sonst noch) laufen sollte, wozu dann auch ein kleiner Apache2-Server gehört, auf den man dann wieder mit einem 3D-fähigen Browser zugreifen kann und der die PHP-Seite hostet, die am Ende den Request zur FRITZ!Box auslöst.

So schnöde Sachen wie ein einfaches Shell-Skript, was das dann über wget (oder sogar über nc/socat) macht, sind eher nichts für den täglichen Gebrauch ... sie brauchen einfach nicht genug Ressourcen und dann bricht der PC-Markt am Ende noch weiter ein ... und das alles nur, weil man an die Stelle der graphischen Oberfläche mit Client-Server-Modell aus lauter Faulheit ein paar wenige Textzeilen setzen wollte.

BTW ... da bei diesem Interface gar keine Authentifizierung über eine SID gebraucht wird, sind natürlich auch die entsprechenden Variablen im PHP-Code überflüssig (das Zusammenbauen des Parameters ist ja ohnehin auskommentiert).

Wobei es tatsächlich sein könnte (auch das teste ich jetzt mal nicht), daß der Zugriffsversuch über den unverschlüsselten Zugang scheitert ... normalerweise liest man zuerst den "SecurityPort" (unverschlüsselt und ohne Authentifizierung) aus und verwendet dann eine TLS-Verbindung zu diesem Port. Ob neuere Firmware tatsächlich noch die (unsichere) "basic auth" im unverschlüsselten Modus zuläßt (und die SOAP-URL sieht so aus), müßte man erst einmal prüfen ... ich wäre zwar wieder entsetzt, aber auch nicht allzu überrascht.
 
Zuletzt bearbeitet:
:crazy:
ich wäre zwar wieder entsetzt, aber auch nicht allzu überrascht
Nagut, dann muss ich wohl betonen: Auf meiner 7360SL mit 6.30, geht das so.
...aber da gibts nen Fehler wenn ich HTTPS benutzen will: "Could not connect to host"
Egal ob fritz.box oder 192.168.178.1 erst wenn ich es auf HTTP ändere, klappt es.
 
@koy:
Schau Dir mal einige andere Beispiele an ... u.a. auch die FRITZ!Box-Skripte in PowerShell aus der c't (ist schon eine Weile her).

Der HTTPS-Port ist natürlich nicht 49000 ... daher kann man die notwendige Port-Nummer tatsächlich ohne vorherige Authentifizierung abfragen und dann sollte man anschließend HTTPS mit diesem Port verwenden. Wobei ich bisher noch keine Box gesehen habe, wo der interne Port dann nicht 49443 gewesen wäre ... man könnte also auch gleich mit diesem Port starten, aber das andere ist der "saubere Weg".

Wenn bei der Authentifizierung bei "purem HTTP" nicht seitens der FRITZ!Box auf "digest auth" bestanden werden sollte (dann muß der erste Versuch mit einem Fehler scheitern, da erst bei diesem Fehler der "nonce"-Wert für die Berechnung des MD5-Hashes gesendet wird), dann wäre der TR-064-Zugriff sogar wieder unsicherer als eine Anmeldung im GUI, weil so eine "basic auth"-Anmeldung natürlich nur notdürftig mit "base64"-Kodierung den Benutzernamen und das Kennwort verschleiert, während das GUI wenigstens diese Angaben nur in Hash-Form überträgt und man da mindestens auf das Stehlen der SID und das Spoofen der dazu gehörenden IP-Adresse setzen müßte.

Das kriegst Du ja mit einem Mitschnitt auf der FRITZ!Box leicht heraus, was da im Hintergrund seitens PHP passiert ... es kann auch sein, daß da tatsächlich der erste Zugriffsversuch ohne Benutzer/Kennwort erfolgt und anschließend der von der Box geforderte Mechanismus verwendet wird, der im Header der HTTP-Antwort enthalten ist (bei "digest auth" dann inkl. nonce-Value).

Wenn Deine PHP-Installation kein HTTPS unterstützt, fehlt ja vielleicht nur die passende libssl oder libcrypto ... ich kann mir kaum vorstellen, daß eine "ausgewachsene" PHP-Installation heutzutage ohne SSL-Support daherkommt, aber PHP ist definitiv nicht mein Fokus.
 
Gibt es auch eine Möglichkeit die Box per Shell-Skript und CURL neuzustarten?
 
Worüber reden wir denn sonst hier in diesem Thread? Es muß auch nicht "curl" sein ... es sollte so ziemlich jedes Programm funktionieren, welches einen HTTP(S)-Request an die FRITZ!Box (mit "custom body and headers") absetzen kann. Das ist im Extremfall die "bash" selbst, wenn es eine passende Version ist, die die "/dev/tcp"-Syntax kennt.

PS: Für die TLS-Verschlüsselung bräuchte es neben der "bash" dann natürlich noch einen passenden TLS-Stack ... aber auch der sollte heutzutage auf jedem System existieren.
 
Zuletzt bearbeitet:
Ich kenne mich leider nicht so gut aus, als das ich das selbst programmieren könnte.
Ich habe sonst auch kein funktionsfähiges Skript finden können.

Zum Beispiel bei dem folgenden:
Code:
#!/bin/bash
_BOXURL="http://fritz.box"
_USERNAME=""
_PASSWORD="GEHEIM"
_CHALLENGE=$(curl -s "${_BOXURL}/login_sid.lua?username=${_USERNAME}" | grep -Po '(?<=<Challenge>).*(?=</Challenge>)')
echo "Challenge: $_CHALLENGE"
_MD5=$(echo -n ${_CHALLENGE}"-"${_PASSWORD} | iconv -f ISO8859-1 -t UTF-16LE | md5sum -b | awk '{print substr($0,1,32)}')
echo "MD5: $_MD5"
_RESPONSE="${_CHALLENGE}-${_MD5}"
echo "RESPONSE: $_RESPONSE"
_SID=$(curl -i -s -k -d "response=${_RESPONSE}&username=${_USERNAME}" "${_BOXURL}" | grep -Po -m 1 '(?<=sid=)[a-f\d]+')
echo "SID: $_SID"

# Box rebooten
echo 'Reboot in progress ... please allow up to 2 minutes for the box to come up!'
curl -s "${_BOXURL}/reboot.lua?sid=${_SID}&extern_reboot=1&ajax=1"

kommt folgender Output:
Code:
Challenge: 5929abf8
MD5: d41d8cd98f00b204e9800998ecf8427e
RESPONSE: 5929abf8-d41d8cd98f00b204e9800998ecf8427e
SID:

Die Challenge mit MD5 funktioniert, aber die SID kann nicht ausgelesen werden.

Hat jemand ein funktionierendes Shell-Skript?
 
Ich habe keine Lust, mich durch das Skript zu graben ... die Anmeldung über die "login_sid.lua" funktioniert jedenfalls auch in neuer Firmware noch, wie ich gerade mit meinem eigenen Skript getestet habe.

Ich tippe hier eher auf falsche Benutzernamen und/oder Kennwörter und dann kann auch an und für sich funktionierender Skript-Code wenig machen.

Wenn das mit dem gezeigten Ausschnitt trotz passender Credentials nicht funktioniert, ging es vermutlich vorher auch schon nicht (mich irritiert die Verwendung von ISO-8859-1 als Zeichensatz, das muß schon recht alter Code sein oder ein sehr spezieller Host, auf dem das ausgeführt wird - die meisten verwenden nun mal inzwischen UTF-8 und auch das grep-Kommando nach dem curl-Aufruf sieht auf den ersten Blick für mich falsch aus, die Antwort ist XML-formatiert und enthält einen Node "<SID>" mit der richtigen Session-ID, aber keine "sid="-Angabe und damit würde ich da eher so etwas wie "(?<=SID>)[a-f\d]+(?=</SID>)" als RegEx verwenden (wenn es schon Perl-Syntax sein soll, was ich auch nicht nachvollziehen kann)) und dann benutzt dieser Weg natürlich eher das GUI der Box als die "offiziellen" TR-064-Schnittstellen.
 
Kram, wühl, ein Beispiel wie der Safeport (eigentlich eh immer gleich) ermittelt werden kann...
fbsafeport.sh
Code:
#!/bin/sh
curl 'http://fritz.box:49000/upnp/control/deviceinfo' -H 'Content-Type: text/xml; charset="utf-8"' -H 'SoapAction: urn:dslforum-org:service:DeviceInfo:1#GetSecurityPort' -d '<?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:GetSecurityPort xmlns:u="urn:dslforum-org:service:DeviceInfo:1"> </u:GetSecurityPort> </s:Body> </s:Envelope>'
...und hier hab ich noch Eins gefunden, welches bei dynamischer IP-Vergabe vom Provider mit Glück eine Neue anfordert durch ein Reconnect...
reconnect.sh
Code:
#!/bin/sh
curl "http://fritz.box:49000/igdupnp/control/WANIPConn1" \
-H "Content-Type: text/xml; charset="utf-8"" \
-H "SoapAction:urn:schemas-upnp-org:service:WANIPConnection:1#ForceTermination" \
-d "<?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:ForceTermination xmlns:u='urn:schemas-upnp-org:service:WANIPConnection:1' /> \
</s:Body> \
</s:Envelope>"
#EOF
...das kommt einen Reboot schon ziemlich nahe.
 
Zuletzt bearbeitet:
ich habe eine FritzBox 7390 (v6.30).
...
Gibt ein ein CLI-Kommando, mit dem man über eine Linux-Maschine im selben lokalen Netzwerk, einen Reboot-Befehl an die FritzBox schicken kann?

Hallo night4awk,
das Problem mit der fehlenden SID bei Skript #10 läßt sich wie folgt fixen;

Code:
Zeile 2 ändern:
[FONT=courier new]_USERNAME="admin"[/FONT]

Zeile 11 ändern:
[FONT=courier new]_SID=$(curl -s "$_BOXURL/login_sid.lua?username=$[/FONT]_USERNAME[FONT=courier new][/FONT][FONT=courier new]&response=$_RESPONSE" | sed -n '/.*<SID>\([^<]*\)<.*/s//\1/p')[/FONT]

bei mir wird dann bei FB7490 FW 06.51 die SID richtig ermittelt;

habe keine FB7390 FW 06.30 zur Hand, daher kann ich keine Aussage zum weiteren Skriptverlauf bei Dir machen;

generell sind diese Skripte, die HTTP-POST nutzen, stark von der FW abhängig; im Bedarfsfall muß man sich die URLs aus HTTP-Traffic bei Browser-Zugriff auf die entsprechenden Seiten ermitteln; ggf. hilft auch ein Blick in den LUA-Code.

LG Riverhopper
 
Zuletzt bearbeitet:
Kleiner Nachtrag meinerseits ... das mit dem Benutzernamen sollte natürlich zur eigenen Box passen - da ohnehin nur die Einstellung "Benutzername und Kennwort" wirklich zu empfehlen ist, gehört da neben dem eigenen Kennwort auch der eigene Benutzername in das Skript.

Daß das Parsen der SID so nicht funktionieren wird, hatte ich schon versucht zu verdeutlichen ... hier war es eben auch nicht nur ein Problem der Groß- oder Kleinschreibung (die man am ehesten umgehen kann, wenn man entweder normalisiert (also entsprechend selbst alles in ausschließlich eine einheitliche Schreibweise umwandelt) oder solche Vergleiche mit entsprechenden Einstellungen (Schreibweise ignorieren) ausführt), sondern gleich ein richtiges Problem, weil noch nach einem "="-Zeichen gesucht wurde.

Wenn man ohnehin die "bash" als Shell verwendet, kann man auf "sed" oder "grep" auch komplett verzichten und gleich (nach Setzen von "nocasematch") mit dem RegEx-Operator der "bash" arbeiten ... die "richtige Umsetzung" wäre trotzdem wieder die Verwendung von "xmllint" zum Ermitteln des Wertes der SID, dann ist auch gleich sichergestellt, daß der Rest der Antwort "well-formed" ist.

Also ... wenn man es mit der "bash" mit so wenig Abhängigkeiten wie möglich machen will, nimmt man deren RegEx-Operator (schon die Verwendung von "curl" steht aber im Widerspruch zu "so wenig Abhängigkeiten wie möglich") und wenn das keine Rolle spielt, wäre die Verwendung von "xmllint" zum Auslesen von Werten aus einer XML-Struktur dringendst zu empfehlen.

Der von @Riverhopper gezeigte Weg mittels "sed" funktioniert (genauso wie die Verwendung von "grep") nämlich auch nur solange, bis da nach dem "SID"-Tag noch ein Zeilenumbruch steht, was bei "well-formed XML" absolut ebenfalls erlaubt wäre.

Code:
<SID>[COLOR="#FF0000"]\n[/COLOR]
[COLOR="#FF0000"]\t[/COLOR]0123456789abcdef[COLOR="#FF0000"]\n[/COLOR]
</SID>

Wenn man das also mittels "sed" so gestalten will, daß man garantiert den Treffer landet, sollte man vorher noch alle Zeilenumbrüche (und Tabulatoren, ggf. sogar alles, was "whitespace" ist) in der Datei entfernen. Es wird sicherlich auch so funktionieren (nicht daß man das mißversteht), aber es gäbe eben auch eine (gültige) Antwort seitens der Box, bei der dieser Weg nicht paßt und dazu reicht praktisch jeder der beiden oben gezeigten Zeilenumbrüche auch einzeln - wenn mich mein Auge/Hirn nicht trügt, erwartet die Suche das alles in einer einzelnen Zeile (und auch die Trennung in "locate" (bzw. "/.../") und "s"-Kommando erschwert das Lesen nur).
 
Hallo,
gemäß Vorschlag von PeterPawn habe ich den "Whitespace-Eliminator" eingebaut:
Code:
Zeile 11 ändern:
_SID=$(curl -s "$_BOXURL/login_sid.lua?username=$_USERNAME&response=$_RESPONSE" | sed -e "s/^[ \t]*//" | sed -e ':x;$!N;s/\n//;tx;s|.*<SID>\([^\<]*\)</SID>.*|\1|')

so dass "all well-formed XML" Output mit "SID"-Tag gehandelt werden kann.

@night4awk: #10 Bitte bei Fremdskripten immer Quellen beilegen:
http://www.administrator.de/wissen/...are-versionen-6-x-274710.html#comment-1095021
Hier gibt es auch ein Powershell-Skript "Reboot Fritz!Box über SOAP-UPNP-Request" mit XML-Parser; dies ist jedoch eher für Win-PC als LINUX Rechner gedacht.

LG Riverhopper

UPDATE: Korrektur der sed-Befehle aus PeterPawns Posting aus #15 eingepflegt, Danke an PeterPawn
 
Zuletzt bearbeitet:
Ist das getestet? Normalerweise würde ein
Code:
s/^M//g
nur in jeder Zeile, die mit einem großem "M" beginnt, dieses erste Zeichen löschen.

Das "Zusammenziehen" von Zeilen mittels "sed" funktioniert etwas anders, eine Möglichkeit wäre z.B. diese:
Code:
echo -n -e "1\n2\n3\n4\n\t5\n6\n" | sed -e ':x;$!N;s/[\n\t]//;tx'
Das sieht auf den ersten Blick etwas wild aus, ist aber aufgeschlüsselt auch wieder recht einfach. Man sollte dazu aber die (bzw. eine) "sed"-Dokumentation zumindest mal "angelesen" haben: https://www.gnu.org/software/sed/manual/sed.txt

Man muß eigentlich nur wissen, daß "sed" ansonsten "stream-orientiert" arbeitet und die angegebenen Kommandos (die können auf der Kommandozeile angegeben werden - meist nach der Option "-e" - oder auch in einer gesonderten Datei stehen, mehrere aufeinanderfolgende Kommandos werden durch Semikolon getrennt bzw. in einer Kommandodatei durch eigene Zeilen) der Reihe nach auf jede einzelne Zeile der Eingabedatei angewendet werden ... daher findet eben so ein "Suchausdruck" keine passenden Daten, wenn sie sich über mehr als eine einzelne Zeile erstrecken.

Ist die "Kommandofolge" für eine einzelne Zeile abgearbeitet, wird die nächste Zeile der Eingabedatei gelesen und das Spiel beginnt von vorne. Als Besonderheit gibt es aber auch in so einer Kommandofolge die Möglichkeit, zu einer vorher festgelegten Marke zu springen, damit werden die Befehle in einer Schleife ausgeführt und solange es nicht bis zum Ende der Kommandofolge geht, wird auch nicht die nächste Zeile der Datei gelesen (jedenfalls nicht auf "normalem Weg").

Genau so funktioniert dieser Weg des "join lines":
Code:
:x    - definiert so ein "label" (mit dem Wert "x", das eigentliche Kommando ist der Doppelpunkt), zu dem man springen kann
$     - bezeichnet beim "sed" die letzte Zeile der Eingabedatei, solange es als "Adresse" verwendet wird
!     - negiert eine Adresse, die sich vor diesem Zeichen befindet ... "$!" steht also für "alle Zeilen der Eingabedatei, außer der letzten" 
N     - dieses Kommando fügt an die aktuelle Zeile einen Zeilenumbruch an und liest dann die nächste Zeile aus der Datei direkt hinter diesen "virtuellen Zeilenumbruch" in den sogenannten "pattern space" (das ist der "Arbeitsbereich", auf den sich die Kommandos beziehen)
Wenn wir jetzt erst einmal das Label "x" außer acht lassen, haben wir also ein Kommando, das bei allen Zeilen - außer bei der letzten in der Datei - die jeweils nächste Zeile mit einem dazwischenliegenden "newline" in den "pattern space" liest, was dann natürlich automatisch dazu führt, daß die gesamte Kommandofolge nur noch auf die Hälfte der "Durchläufe" kommt, weil ja immer zwei Zeilen zu einer einzelnen zusammengezogen werden im "pattern space".

Modifiziert man die Kommandofolge etwas, sieht man das ganz gut:
Code:
# echo -n -e "1\n2\n3\n4\n\t5\n6\n" | sed -e '$!N;s/\n/{NeueZeile}/'
1{NeueZeile}2
3{NeueZeile}4
        5{NeueZeile}6
Solange man natürlich das "newline"-Zeichen, welches vom "N"-Kommando an die aktuelle Zeile angefügt wird, in seiner "ursprünglichen Form" bestehen läßt, sieht man in der Ausgabe den Effekt des "N"-Kommandos nicht, weil ja einfach wieder die Zeilen getrennt angezeigt würden.

Ersetzen wir das aber durch die Zeichenkette "{NeueZeile}", sieht man auch ganz gut, daß tatsächlich jetzt aus den 6 Zeilen der Eingabe nur noch 3 Zeilen in der Ausgabe werden, weil jeweils zwei Zeilen zu einer einzelnen zusammengefaßt wurden.

Das "N"-Kommando dürfen wir dabei nicht auf die letzte Zeile der Datei anwenden, weil die Dokumentation für dieses Kommando besagt:
man sed schrieb:
`N' - Add a newline to the pattern space, then append the next line of input to the pattern space. If there is no more input then `sed' exits without processing any more commands.

Auch das können wir leicht überprüfen, indem wir einfach mal 7 Zeilen Eingabe verarbeiten (bei gerader Anzahl von Zeilen spielt das keine Rolle, weil das "N" ja nur auf die vorletzte Zeile angewendet würde) und das "N"-Kommando auch auf diese letzte Zeile loslassen:
Code:
# echo -n -e "1\n2\n3\n4\n\t5\n6\n7" | sed -e 'N;s/\n/{NeueZeile}/;a====='
1{NeueZeile}2
=====
3{NeueZeile}4
=====
        5{NeueZeile}6
=====
7
Das "a"-Kommando zum Hinzufügen der "====="-Folge als letzte Aktion, bevor zur nächsten Eingabezeile weiter gegangen wird, kommt nach der letzten Zeile also nicht mehr zur Ausführung, weil das "N"-Kommando mangels weiterer Zeilen in der Eingabedatei die Kommandofolge direkt abbricht ... im Gegenteil zu diesem Aufruf:
Code:
# echo -n -e "1\n2\n3\n4\n\t5\n6\n7" | sed -e '$!N;s/\n/{NeueZeile}/;a====='
1{NeueZeile}2
=====
3{NeueZeile}4
=====
        5{NeueZeile}6
=====
7
=====
Hier wird also das "N"-Kommando für die letzte Zeile der Datei gar nicht erst ausgeführt (wegen "$!") und damit kommt das "a"-Kommando noch zum Zuge (das "s"-Kommando dazwischen findet halt nichts zum Ersetzen und bleibt wirkungslos). Das war zwar nur ein kleiner (hier eigentlich sogar nebensächlicher) Ausflug in die Verwendung von "N", aber es ist einer der beliebtesten Fehler, wenn man das "N"-Kommando in anderem Zusammenhang verwendet.

Zurück zum ursprünglichen Kommando ... die Abarbeitung für die erste Zeile ergibt also nach ":x;$!N" folgenden Inhalt des "pattern space":
Code:
1[COLOR="#FF0000"]\n[/COLOR]2
Jetzt wird mittels "s/\n//" das eingesetzte "newline"-Zeichen entfernt und damit ergibt sich folgender Inhalt des "pattern space":
Code:
12
Wäre hier jetzt die Kommandofolge beendet, würde die nächste Zeile aus der Eingabe gelesen (das wäre die mit der "3") und es ergäbe sich das oben gezeigte Bild der jeweils "paarig" zusammengezogenen Zeilen. Aber in der gezeigten Kommandofolge steht jetzt eben ein "t"-Kommando und das bedeutet: "Springe zur nachfolgend angegebenen Marke, wenn seit dem letzten Lesen einer Zeile der Datei irgendeine Ersetzung stattgefunden hat." ... genau das ist aber hier der Fall, denn das "newline"-Zeichen wurde ja durch "nichts" ersetzt. Damit springt also die Abarbeitung der Kommandofolge wieder zur Marke "x" und die besagt: "Solange das nicht die letzte Zeile der Datei ist, ziehe sie mit der nächsten zusammen." - das wäre hier jetzt die dritte Zeile.

Das setzt sich jetzt bis zur letzten Zeile so fort und am Ende erhält man eben eine Datei, die nur aus einer einzelnen Zeile besteht.

Wenn man dieses Vorgehen "visualisieren" möchte, fügt man einfach noch ein "p"-Kommando (das gibt den aktuellen Inhalt des "pattern space" aus, wenn es an der Reihe ist) in die Abarbeitung mit ein:
Code:
 # echo -n -e "1\n2\n3\n4\n\t5\n6\n7" | sed -e ':x;$!N;s/\n/{NeueZeile}/;[COLOR="#FF0000"]p[/COLOR];tx'
1{NeueZeile}2
1{NeueZeile}2{NeueZeile}3
1{NeueZeile}2{NeueZeile}3{NeueZeile}4
1{NeueZeile}2{NeueZeile}3{NeueZeile}4{NeueZeile}        5
1{NeueZeile}2{NeueZeile}3{NeueZeile}4{NeueZeile}        5{NeueZeile}6
1{NeueZeile}2{NeueZeile}3{NeueZeile}4{NeueZeile}        5{NeueZeile}6{NeueZeile}7
1{NeueZeile}2{NeueZeile}3{NeueZeile}4{NeueZeile}        5{NeueZeile}6{NeueZeile}7
1{NeueZeile}2{NeueZeile}3{NeueZeile}4{NeueZeile}        5{NeueZeile}6{NeueZeile}7
Da wir ja auch eventuell vorhandene Tabulatoren entfernen wollen, ist das ursprüngliche "s"-Kommando eben "s/[\n\t]//", was jedes "newline"- oder "tab"-Zeichen entfernt. Wenn man ganz sicher gehen wollte, müßte man wohl die Tabulatoren und event. führende Leerzeichen in einem gesonderten Durchlauf entfernen (weil man eben nicht jedes beliebige Leerzeichen ersetzen will), was dann in etwa so aussehen würde:
Code:
... | sed -e "s/^[ \t]*//" | sed -e ':x;$!N;s/\n//;tx'
Dabei ist die zweifache Verwendung von "sed" genauso entscheidend wie die einfachen Hochkommata um die Kommandofolge des zweiten Aufrufs, weil bei der Verwendung von Anführungszeichen (wie beim ersten Aufruf) zusätzliche Maskierungen von Sonderzeichen mit spezieller Bedeutung in Shell-Kommandos erfolgen müßten.

An dieser Stelle ziemlich umsonst ist hingegen die Beschränkung des "N"-Kommandos auf alle Zeilen außer der letzten, da streng genommen ohnehin nur die allererste Zeile "normal" gelesen wird und alle nachfolgenden Zeilen vom "N"-Kommando in den "pattern space" transferiert werden.

Solange man jetzt mit dieser "einzelnen Zeile" als Ergebnis nichts weiter mehr machen will, spielt es auch keine Rolle, wenn das letzte "N"-Kommando dann fehlschlägt und die Abarbeitung der Kommandofolge beendet wird ... damit ist also in diesem konkreten Fall ":x;N;s/\n//;tx" vom Ergebnis her mit der Variante mit dem zusätzlichen "$!" identisch.

Erst wenn hinter dem "t"-Kommando (das ist ja ein "conditional branch", der nur dann ausgeführt wird, wenn es eine Substitution zuvor gab) noch weitere Kommandos folgen (die werden ja dann erst ausgeführt, wenn die einzelne Zeile komplett zusammengezogen wurde und es keine Ersetzung mehr gab - weil es kein "newline" im "pattern space" gibt, solange das "N" nicht ausgeführt wurde), erst dann macht es einen gewaltigen Unterschied, ob man die letzte Zeile mit einbezieht oder nicht. Gewöhnt man sich für das "N"-Kommando gleich an, daß man es besser nicht auf die letzte Zeile losläßt, spart man sich u.U. viel Zeit bei der Fehlersuche.

Man könnte ja das Auslesen der SID auch gleich mit dem Zusammenziehen zu einer Zeile in einem Kommando zusammenfassen (der erste "sed"-Aufruf entfernt nur führende Leerzeichen und Tabulatoren, das könnte man auch nachträglich erst machen):
Code:
sed -e "s/^[ \t]*//" | sed -e ':x;$!N;s/\n//;tx;s|.*<SID>\(.*\)</SID>.*|\1|'
Wenn man dieses Kommando mit und ohne "$!" testet, stellt man den Unterschied fest:
Code:
# echo -n -e "1\n2\n3\n  4<SID>\n\t5\n</SID>6\n7\n" | sed -e "s/^[ \t]*//" | sed -e ':x;$!N;s/\n//;tx;s|.*<SID>\([^\<]*\)</SID>.*|\1|'
5
# echo -n -e "1\n2\n3\n  4<SID>\n\t5\n</SID>6\n7\n" | sed -e "s/^[ \t]*//" | sed -e ':x;N;s/\n//;tx;s|.*<SID>\([^\<]*\)</SID>.*|\1|'
1234<SID>5</SID>67
Im zweiten Falle kommt also das letzte "s"-Kommando gar nicht mehr zur Ausführung, weil der Fehler beim "N" die gesamte Kommandofolge abbricht. Da das Zusammenziehen auch so lange fortgesetzt wird, bis praktisch alles in Zeile 1 steht, spielt hier die Frage, ob die Eingabe nun eine gerade oder eine ungerade Anzahl von Zeilen enthält, keine wirkliche Rolle mehr.

Das hatte zwar mit dem "reboot" an sich jetzt alles nichts mehr zu tun, aber so einfach wie mit den beiden gezeigten "s"-Kommandos von @Riverhopper dürfte das auch wieder nicht funktionieren ... und für den Fall, daß spätere Leser dann auf das gezeigte Kommando zurückgreifen wollen und dabei nicht das erwartete Ergebnis erzielen, konnte ich mir diesem Nachtrag auch wieder nicht verkneifen.
 
@PeterPawn,
Danke für Korrektur und Erklärungen bzgl. sed-Befehle;
hab's in #15 mit Autorenhinweis eingepflegt.

habe mal einen Blick in die AVM-Doku zu TR-064 Schnittstelle geworfen;
sieht interessant aus, insbesondere hätte man eine saubere Schnittstelle und könnte dadurch eine FW-Unabhängigkeit erreichen.

Frage: Gibt es hier eine Perl oder Python-Toolbox mit den SOAP-Funktionen zum Zugriff und Steuerung von Fritzboxen, inkl. reboot ?

LG Riverhopper
 
Ich mag normalerweise nicht sowas alte Sachen auszugraben... Aber da bis auf eine Box mittlerweile nix mehr mit Freetz im Einsatz ist (und daher auch keine Cronjobs mehr gibt) wollte ich mich mal damit beschäftigen wie ich die diversen Fritz Sachen per script rebooten kann. Sichern der Configs funktioniert für alle 06.xx Versionen die ich habe (von 7270v2 mit 06.06(? mein ich jedenfalls) bis zu 06.83) inkl Login und allem. Das Reboot per lua scheitert allerdings scheinbar an einem Parameter der neben den "alten" Parametern mitgegeben wird. Gerade mit der 06.51 auf einem 1750E mit Wireshark mitgeschnitten:

Code:
GET /reboot.lua?sid={SID}&ajax=1&no_sidrenew=1&xhr=1&t1492164829447=nocache

Der Teil mit dem t vorne verändert sich andauernd und ich finde im Traffic auf Anhieb keinen Hinweis wie der Parameter irgendwie erzeugt werden könnte per Script. Da ein Teil der Boxen nur per HTTPS aus dem Internet erreichbar ist (bei meinen Eltern zu Hause z.B.) fällt ein lokales UPNP als Alternative leider raus. Vielleicht hat ja jemand eine Idee?
 
1. Das TR-064-Interface ist - mit passender URL - auch von extern zu erreichen: https://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/AVM_TR-064_remote.pdf ... das "remote" reicht als Argument gegen die dokumentierten Schnittstellen alleine also nicht aus.

2. Der fragliche "t[nnn]"-Parameter in so einem XHR (XmlHttpRequest) enthält nur die aktuelle Uhrzeit als Linux-Timestamp im "nnn"-Teil und wird (vermutlich, aber ich teste das jetzt nicht selbst, weil ich keine Box wirklich neu starten will) eher nicht benötigt. Wenn man wirklich so einen Request absetzen will, sollte bereits "sid" und "ajax" (wobei ich bei letzterem schon wieder nachsehen würde in den Lua-Dateien von AVM, ob der wirklich gebraucht wird) ausreichen, um das Ziel zu erreichen.

Aber ich würde trotzdem eher auf 1. oben setzen ... wer bereits einem "handgemachten SOAP-Request" für die interne Verwendung hat, braucht bloß noch die passende URL von extern zu verwenden und erzielt dasselbe Ergebnis - die Wahrscheinlichkeit, daß AVM da die Schnittstelle ändert, ist zumindest auch mal geringer und wie sich solche GUI-Abrufe i.V.m. 2FA in der Zukunft entwickeln werden, weiß man auch noch nicht "abschließend".
 
Wenn man wirklich so einen Request absetzen will, sollte bereits "sid" und "ajax" (wobei ich bei letzterem schon wieder nachsehen würde in den Lua-Dateien von AVM, ob der wirklich gebraucht wird) ausreichen, um das Ziel zu erreichen.

Im Gegensatz zum sichern der Config (also Login und SID funktionieren ja) wird es nur mit sid oder mit sid und ajax quittiert, dass der Neustart nicht durchgeführt worden ist da keine Rechte dazu vorhanden sind. Daran kann es aber nicht liegen - auf dem Test-Repeater gibt es keinen Nutzer der dazu keine Rechte hätte...

Ich werd mir dann mal deinen Link anschauen bzgl. TR-064 von extern. Danke!

Edit:
Ohne Ajax kommt nix, mit Ajax bekomme ich dann aber den Output, dass es verweigert worden ist. So war es
 
Zuletzt bearbeitet:

Neueste Beiträge

Statistik des Forums

Themen
244,858
Beiträge
2,219,654
Mitglieder
371,572
Neuestes Mitglied
#Kuddel#
Holen Sie sich 3CX - völlig kostenlos!
Verbinden Sie Ihr Team und Ihre Kunden Telefonie Livechat Videokonferenzen

Gehostet oder selbst-verwaltet. Für bis zu 10 Nutzer dauerhaft kostenlos. Keine Kreditkartendetails erforderlich. Ohne Risiko testen.

3CX
Für diese E-Mail-Adresse besteht bereits ein 3CX-Konto. Sie werden zum Kundenportal weitergeleitet, wo Sie sich anmelden oder Ihr Passwort zurücksetzen können, falls Sie dieses vergessen haben.