Einstiegsscript, Port 80 freigeben

fiveyears

Neuer User
Mitglied seit
25 Mai 2010
Beiträge
15
Punkte für Reaktionen
0
Punkte
1
Hallo,

ich suche einen Einstieg, um an meine Portfreigaben per script heranzukommen. Ich möchte per php oder curl (web-interface) die Port-80-Freigabe für ein Gerät im Netz aktivieren und dann wieder deaktivieren (LetsEncrypt braucht einen offenen port 80). Jedesmal auf die Weboberfläche der Fritz!Box zu gehen ist umständlich und nicht zu Skripten.

Wo kann ich ansetzen, gibt es Beispiele ähnlicher Ansetze.

Danke und viele Grüße,


five years
 
Port 80 kann problematisch sein, da die Box den ggf. selber benutzt. Früher konnte man Port 80 nicht forwarden.

Ansonsten gibt es ja einige Scriptsammlungen für TR-064 für die Fritzbox. fritzsoap und fritzconnection z.B. oder die fbtools. Ist da nichts dabei?
 
  • Like
Reaktionen: Black Senator
Bei meiner 7590AX geht das, ich mache den Port kurz auf, update die Certs und wieder zu. FB_Tools dauert zu lange, da muss ich erst die Konfiguration Exporten, patschen und Importen, dann startet die Box neu. fritzconnection muss ich mal schauen. Danke für den Hinweis,

VG fiveyears
 
@fiveyears

An dem Coding würde ich mich gerne beteiligen. Ich hatte schon vor Jahren mich mal in die Richtung versucht, es aber nie weiter verfolgt.

@Kruemelino

wanipconnection1 ...

XML:
    <service name="wanipconnection1" origin="tr64desc.xml">
        <serviceType>urn:dslforum-org:service:WANIPConnection:1</serviceType>
        <controlURL>/upnp/control/wanipconnection1</controlURL>
        <actions>
            <action>GetInfo</action>
            <action>GetConnectionTypeInfo</action>
            <action>SetConnectionType</action>
            <action>GetStatusInfo</action>
            <action>GetNATRSIPStatus</action>
            <action>SetConnectionTrigger</action>
            <action>ForceTermination</action>
            <action>RequestConnection</action>
            <action>GetGenericPortMappingEntry</action>
            <action>GetSpecificPortMappingEntry</action>
            <action>AddPortMapping</action>
            <action>DeletePortMapping</action>
            <action>GetExternalIPAddress</action>
            <action>X_GetDNSServers</action>
            <action>GetPortMappingNumberOfEntries</action>
            <action>SetRouteProtocolRx</action>
            <action>SetIdleDisconnectTime</action>
        </actions>
    </service>

scheint ja die AVM-spezifische Aufbohrung von WANIPCON1 (igd bzw. igd2) zu sein:

XML:
    <service name="WANIPConn1" origin="igddesc.xml">
        <serviceType>urn:schemas-upnp-org:service:WANIPConnection:1</serviceType>
        <controlURL>/igdupnp/control/WANIPConn1</controlURL>
        <actions>
            <action>SetConnectionType</action>
            <action>GetConnectionTypeInfo</action>
            <action>GetAutoDisconnectTime</action>
            <action>GetIdleDisconnectTime</action>
            <action>RequestConnection</action>
            <action>RequestTermination</action>
            <action>ForceTermination</action>
            <action>GetStatusInfo</action>
            <action>GetNATRSIPStatus</action>
            <action>GetGenericPortMappingEntry</action>
            <action>GetSpecificPortMappingEntry</action>
            <action>AddPortMapping</action>
            <action>DeletePortMapping</action>
            <action>GetExternalIPAddress</action>
            <action>X_AVM_DE_GetExternalIPv6Address</action>
            <action>X_AVM_DE_GetIPv6Prefix</action>
            <action>X_AVM_DE_GetDNSServer</action>
            <action>X_AVM_DE_GetIPv6DNSServer</action>
        </actions>
    </service>
    <service name="WANIPConn1" origin="igd2desc.xml">
        <serviceType>urn:schemas-upnp-org:service:WANIPConnection:2</serviceType>
        <controlURL>/igd2upnp/control/WANIPConn1</controlURL>
        <actions>
            <action>SetConnectionType</action>
            <action>GetConnectionTypeInfo</action>
            <action>RequestConnection</action>
            <action>RequestTermination</action>
            <action>ForceTermination</action>
            <action>SetAutoDisconnectTime</action>
            <action>SetIdleDisconnectTime</action>
            <action>SetWarnDisconnectDelay</action>
            <action>GetStatusInfo</action>
            <action>GetAutoDisconnectTime</action>
            <action>GetIdleDisconnectTime</action>
            <action>GetWarnDisconnectDelay</action>
            <action>GetNATRSIPStatus</action>
            <action>GetGenericPortMappingEntry</action>
            <action>GetSpecificPortMappingEntry</action>
            <action>AddPortMapping</action>
            <action>DeletePortMapping</action>
            <action>GetExternalIPAddress</action>
            <action>X_AVM_DE_GetExternalIPv6Address</action>
            <action>X_AVM_DE_GetIPv6Prefix</action>
            <action>X_AVM_DE_GetDNSServer</action>
            <action>X_AVM_DE_GetIPv6DNSServer</action>
            <action>DeletePortMappingRange</action>
            <action>GetListOfPortMappings</action>
            <action>AddAnyPortMapping</action>
        </actions>
    </service>

Ich habe mit diesen Services keine weitergehenden Erfahrungen gemacht (also bisher nix programmiert) und die Codings in allen drei Klassen in fritzsoap sind daher noch generisch (was aber im wesentlichen unproblematisch ist).

Wenn ich den Service wanipconnection1 mit beliebigen "get"-Actions aufrufe bekomme ich SOAP-Errors, nicht jedoch bei den Pendents aus WANIPConn1! Da dies bisher das erste Mal ist, dass ein Service die "Zusammenarbeit" verweigert bin ich doch etwas erstaunt.

Könntest Du einmal testen, ob dass mit deiner FBoxAPI sich genauso verhält?

Black Senator
 
Zuletzt bearbeitet:
BTW:
Bei meiner 7590AX geht das,
Und auch bei allen anderen Fritzboxen die ich bisher in den Händen hatte, von der 7050 angefangen. Es war imo nie ein Problem bspw. einen Webserver auf Port 80 (extern) freizugeben.
 
Ich habe gerade probiert:
#!/usr/bin/env python3 from fritzconnection import FritzConnection fc = FritzConnection(address="192.168.2.1", user="***", password="***", use_cache=True) state = fc.call_action("WLANConfiguration1", "GetInfo") # kein Fehler print(state) # print router model information state = fc.call_action("WANIPConn1", "GetStatusInfo") # kein Fehler print(state) # print router model information state = fc.call_action("wanipconnection1", "GetInfo") # Fehler !!!! print(state) # print router model information

Also es kommen Fehler:

fritzconnection.core.exceptions.FritzActionError: UPnPError:
errorCode: 401
errorDescription: Invalid Action

Ich habe aber Soap nicht probiert und mit FritzConnection habe ich noch nicht gefunden, wo ich an die Port-Weiterleitung rankomme
 
Okay, danke! Dann liegt es offenbar nicht an meiner Box oder dem Coding in der Klasse.

Hmmm, sollte ich vielleicht einen Hinweis an Herrn Töpel senden ...

Soap ..., wo ich an die Port-Weiterleitung rankomme
Wie ich geschrieben habe, habe ich selbst mit den Actions in diesen Services nocht "nicht rumgemacht", hätte aber nach Methode-scharfen-ansehens angenommen, dass mit
  • GetPortMappingNumberOfEntries
  • AddPortMapping
  • DeletePortMapping
etwas anzufangen wäre.
 
Hier Ende ich zur Zeit:

state = fc.call_action("WANPPPConnection1", "GetSpecificPortMappingEntry", "NewInternalClient") # Fehler
print(state) # print router model information

Wie kann ich jetzt z. B. einen speziellen Entry auslesen, mit dem Parameter-Format komme ich noch nicht klar.

state = fc.call_action("WANPPPConnection1", "GetSpecificPortMappingEntry", ?????) # Fehler
 
state = fc.call_action("WANPPPConnection1", "GetSpecificPortMappingEntry", ?????) # Fehler
Na, das Action braucht halt drei Eingabe Parameter:
  • in: NewRemoteHost (string)
  • in: NewExternalPort (ui2)
  • in: NewProtocol (string)
sonst gehts eben auf die Bretter ;)
 
Achso, ich dachte, ich lese erst einmal einen existierenden Eintrag aus
 
Dann fang doch erst einmal klein an ... mit getGenericPortMappingEntry()

Bei mir führt

PHP:
<?PHP

require_once './vendor/autoload.php';

use blacksenator\fritzsoap\wanpppconn1;

$fritzbox = new wanpppconn1('fritz.box', 'yourTR064user', 'yourPW');

print_r($fritzbox->getGenericPortMappingEntry(0));

zu recht zu Error: 713 (SpecifiedArrayIndexInvalid)!, weil ich keine Portweiterleitungen eingetragen habe.

Aber, wenn Du dort was hast, dann sollte was kommen:
  • out: NewRemoteHost (string)
  • out: NewExternalPort (ui2)
  • out: NewProtocol (string)
  • out: NewInternalPort (ui2)
  • out: NewInternalClient (string)
  • out: NewEnabled (boolean)
  • out: NewPortMappingDescription (string)
  • out: NewLeaseDuration (ui4)
 
Zuletzt bearbeitet:
Danke, ich habe es gefressen:
PHP:
#!/usr/bin/env php
<?php
require_once './vendor/autoload.php';

use blacksenator\fritzsoap\wanpppconn1;

$fritzbox = new wanpppconn1('***', '***', '***');
$maxID = $fritzbox->GetPortMappingNumberOfEntries();
for ($i = 0; $i <= $maxID; $i++) {
    print_r($fritzbox->getGenericPortMappingEntry($i));
}
?>

oder

Python:
#!/usr/bin/env python3

from fritzconnection import FritzConnection

fc = FritzConnection(address="***", user="***", password="***", use_cache=True)
maxID = fc.call_action("WANPPPConnection1", "GetPortMappingNumberOfEntries")
for x in range(maxID["NewPortMappingNumberOfEntries"]):
    state = fc.call_action("WANPPPConnection1", "GetGenericPortMappingEntry", NewPortMappingIndex=x)
    print(f'Host: {x+1}')
    print(state)
 
Zuletzt bearbeitet:
jetzt habe ich in python den script, in php muss ich noch schauen, wie die benannten Parameter übergeben werden:

Python:
#!/usr/bin/env python3

from fritzconnection import FritzConnection
fc = FritzConnection(address="192.168.2.1", user="***", password="***", use_cache=True)
# state = fc.call_action("WLANConfiguration1", "GetInfo")
# print(state)  # print router model information
maxID = fc.call_action("WANPPPConnection1", "GetPortMappingNumberOfEntries")
port_count = 0
for x in range(maxID["NewPortMappingNumberOfEntries"]):
    state = fc.call_action("WANPPPConnection1", "GetGenericPortMappingEntry", NewPortMappingIndex=x) 
    if state["NewExternalPort"] == 80:
        port_count = 1
        print (state)
        print (f'Internal IP: {state["NewInternalClient"]} Enabled: {state["NewEnabled"]}')
if port_count == 1:
    # delete all port 80 Weiterleitungen
    state = fc.call_action("WANPPPConnection1", "DeletePortMapping", \
        NewRemoteHost="0.0.0.0", \
        NewExternalPort=80, \
        NewProtocol="TCP")

# create port 80 Weiterleitung
state = fc.call_action("WANPPPConnection1", "AddPortMapping", \
    NewRemoteHost="0.0.0.0", \
    NewExternalPort=80, \
    NewProtocol="TCP", \
    NewInternalPort=80, \
    NewInternalClient="192.168.2.80", \
    NewEnabled=True, \
    NewPortMappingDescription="per Terminal", \
    NewLeaseDuration=0)
 
Hallo,

wenn man einfach mal verstanden hat, wie die Parameterübergabe funktioniert, ist es ganz einfach. Ich habe die beiden Skripte in der endgültigen Version angehangen. Beide Skripte erwarten die IP der Fritz!Box, username, password als Commandozeilenparameter oder als Env-Variable. Es werden die aktuellen mappings von port 80 angezeigt und dann gleich gelöscht.
Ist noch der Parameter intern_ip angegeben, wird ein neues mapping für port 80 angelegt.
Jetzt kann ich per script den port 80 für einen Rechner im Netzwerk öffnen, letsencrypt "certbot renew" starten und danach den port 80 gleich wieder schließen. Das ganze kann man auch per cron etc. machen lassen, ohne permanent port 80 offen zu lassen, und an verschiedenen Rechnern im Netzwerk nacheinander. (php oder python je nach Vorliebe)

Gruß fiveyears
 

Anhänge

  • port80.zip
    2.7 KB · Aufrufe: 9
[...]

@Kruemelino

wanipconnection1 ...

[...]

Wenn ich den Service wanipconnection1 mit beliebigen "get"-Actions aufrufe bekomme ich SOAP-Errors, nicht jedoch bei den Pendents aus WANIPConn1! Da dies bisher das erste Mal ist, dass ein Service die "Zusammenarbeit" verweigert bin ich doch etwas erstaunt.

Könntest Du einmal testen, ob dass mit deiner FBoxAPI sich genauso verhält?
Hallo @Black Senator,

ich hab soeben einen Test gemacht. Lief ohne Probleme durch. Ich hab jetzt nur GetPortMappingNumberOfEntries und GetGenericPortMappingEntry getestet. Da ich keine Portweiterleitungen habe, waren die gemeldeten Daten plausibel. Es kam zumindest nicht zu Fehlermeldungen.
 
Was mir nicht gelingt, sind IPv6-Portmappings zu lesen, geschweige denn zu manipulieren. Sicher ist hier WANIPv6Firewall1 gefragt, aber ich komme nicht an die UniqueIDs ran.
 
aber ich komme nicht an die UniqueIDs ran.
Wenn ich es richtig verstehe, dann ist die UniqueID, was Du u.a. (nur) durch AddPinHole zurückbekommst (2.3 Abs. 1.):
Das korrospondiert auch mit den Parametern des Action:
Code:
in: RemoteHost (string)
in: RemotePort (ui2)
in: InternalClient (string)
in: InternalPort (ui2)
in: Protocol (ui2)
in: LeaseTime (ui4)
out: UniqueID (ui2)
 
Ja wenn ich AddPinHole mache, bekomme ich eine UniqueID, aber für die bereits vorhandenen habe ich die ja nicht. Ich könnte jetzt alle löschen und neu anlegen, weiß aber auch nicht, wie ich an den internalClient rankomme, außer auf der Web-Oberfläche nachzusehen - was ich ja nicht will.

-- Zusammenführung Doppelpost gemäß Boardregeln https://www.ip-phone-forum.de/threads/ip-phone-forum-regeln.297224/ by stoney

Hallo nochmal,
ich habe es nicht hinbekommen, mit AddPinHole 'ne UniqueID zu bekommen. Es kommt Fehler 606, was wohl ein Anmeldefehler ist. Da ich auch nirgendwo eine ordentliche Erklärung finde, gebe ich bei IPv6 erstmal auf.

-- Zusammenführung Doppelpost gemäß Boardregeln https://www.ip-phone-forum.de/threads/ip-phone-forum-regeln.297224/ by stoney

Code:
state = fc.call_action("WANIPv6Firewall1", "GetFirewallStatus")
print (state)
state: {'FirewallEnabled': True, 'InboundPinholeAllowed': True}
Code:
state = fc.call_action("WANIPv6Firewall1", "AddPinhole", \
    RemoteHost="::", \
    RemotePort=443, \
    InternalClient="xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx", \
    InternalPort=443, \
    Protocol=6, \
    LeaseTime=0, \
) 
print (state)
state: ...
fritzconnection.core.exceptions.FritzSecurityError: UPnPError:
errorCode: 606
errorDescription: Unknown Error Code

Mein Mac hat 2 ipv6-Adressen, beide probiert, die Fritz!Box vergibt eine weitere, auch probiert, "::1" ging auch nicht
 
Zuletzt bearbeitet von einem Moderator:
@fiveyears

6.1 Actions and User Rights:
If a user is authenticated but has not the needed rights, 606 (“Action not authorized”) will be returned.

Ich für meinen Teil kenne mich in diesem Bereich der SOAP Services nicht aus (keine Erfahrungen gesammelt) und - ja, leider - ist die Dokumentation von AVM im allgemeinen ziemlich beschissen.
  1. Wenn Du doch die ursprüngliche Herausforderung, die temporäre Portfreigabe für IPv4 gelöst hast, warum das ganze noch einmal für IPv6?
  2. Noch eine Ebene höher: mich würde das Gesamtproblem bzw. der verfolgte/gefundene Lösungsansatz interessieren:
    Sowie ich es in deinem ersten Post verstanden habe, willst Du wiederkehrend LetsEncrypt Zertifikate in die FRITZ!Box laden, dafür den Port 80 öffnen, Zertifikat laden und dann den Port wieder dicht machen - richtig?
    In dem veröffentlichen Script lese ich nur das Teilproblem Port öffnen und schließen - mich würde aber die gesamte Strecke interessieren. vielleicht kannst Du das teilen (gerne auch PM und auch nur in Pseudo-Code )
  3. Manchmal hilft es so eine Detailfrage, wie z.B. zu den Attributwerten spezifischer Actions direkt an den AVM Entwicklersupport zu senden (#7). Wenn man nett zu ihren veröffentlichten SST fragt, dann bekommt man dort auch i.d.R. eine Antwort.

@Kruemelino
Komisch - ich habe es noch einmal probiert, bekomme aber bei wannipconnetion1 unverändert den 401 Error. Davon abgesehen ist mir nicht ganz klar, worin der Unterschied zu den IGD1 und IGD2 basierten Services WANIPConn1 ist ... ich muss mir wohl mal eine Matrix anlegen, um besser zu überblicken welche gleichnamigen/-artigen(!) Actions wo drinn stecken.
FunFact: mein Generatorprogramm zieht aus den DESC-Files und SCPD-Files auch Actions die offenbar nur in der XML-Definition existieren. Diese Actions finden sich nicht in den IGD-Dokumentationen beschrieben und liefern beim Aufruf einen Fehler 403 (Not available Action).
Beispiele: GetPinholePackets oder CheckPinholeWorking:

XML:
    <service name="WANIPv6Firewall1" origin="igddesc.xml">
        <serviceType>urn:schemas-upnp-org:service:WANIPv6FirewallControl:1</serviceType>
        <controlURL>/igd2upnp/control/WANIPv6Firewall1</controlURL>
        <actions>
            <action>GetFirewallStatus</action>
            <action>GetOutboundPinholeTimeout</action>
            <action>AddPinhole</action>
            <action>UpdatePinhole</action>
            <action>DeletePinhole</action>
            <action>GetPinholePackets</action>
            <action>CheckPinholeWorking</action>
        </actions>
    </service>
    <service name="WANIPv6Firewall1" origin="igd2desc.xml">
        <serviceType>urn:schemas-upnp-org:service:WANIPv6FirewallControl:1</serviceType>
        <controlURL>/igd2upnp/control/WANIPv6Firewall1</controlURL>
        <actions>
            <action>GetFirewallStatus</action>
            <action>GetOutboundPinholeTimeout</action>
            <action>AddPinhole</action>
            <action>UpdatePinhole</action>
            <action>DeletePinhole</action>
            <action>GetPinholePackets</action>
            <action>CheckPinholeWorking</action>
        </actions>
    </service>


Black Senator
 
Ich gebe ehrlich zu, dass ich mich um IGD1 und IGD2 noch nicht gekümmert habe, was ich mal nachholen muss.
Wenn ich es richtig sehe wird die WANCommonInterfaceConfig:1 (IGD1) nicht vollständig unterstützt.

Action in IGD1AVM Implementation
SetEnabledForInternetnein
GetEnabledForInternetnein
GetCommonLinkPropertiesja
GetWANAccessProvidernein
GetMaximumActiveConnectionsnein
GetTotalBytesSentja
GetTotalBytesReceivedja
GetTotalPacketsSentja
GetTotalPacketsReceivedja
GetActiveConnectionnein
GetAddonInfos
X_AVM_DE_GetDsliteStatus
X_AVM_DE_GetIPTVInfos

Wir sollten die IGD bzw. TR-064 Diskussion vielleicht in einem separaten Thread weiterführen.
 
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.