Einstiegsscript, Port 80 freigeben

  • Like
Reaktionen: Kruemelino
Hm jetzt bin ich frustriert. Ich hatte angenommen, dass die SCPD-Dateinamen eineindeutig sind. Pustekuchen! igddslSCPD und igdicfgSCPD werden sowohl in IGD1 und IGD2 genutzt, jedoch mit unterschiedlichen URLs (controlURL bzw. eventSubURL). Toll. Da muss ich meine Schnittstelle umstellen, sonnst kann ich die nicht erfassen.

BTW: IGD1 und IGD2 enthalten die selben Informationen zu igd2ipv6fwcSCPD
 
Hallo nochmal,

meine Fritz!Box hängt am Glasfaser, d. h. bei mir funktioniert WANPPPConnection1, nicht aber WANIPConn1 oder WANIPConnection1, was geht ist "WANIPConn1", "X_AVM_DE_GetIPv6Prefix", den Präfix erhalte ich.
Port80 öffnen geht problemlos, den Sinn dahinter schreibe ich noch mal auf. Die IPv6-Pinholes zu bekommen war für mich mehr 'ne Spielerei, dies brauche ich eigentlich nicht. Vielleicht ist einfach die InternalClient-Adresse falsch, deshalb der Anmelde-Fehler. Bei IPv4 geht auch nur die IP-Adresse des Rechners, nicht die eines anderen Clients.
Gruß fiveyears
 
So, weil es von Interesse ist, das ganze Script:
renewCerts.sh:
Bash:
#!/bin/bash
# when sourced by zsh or bash
dir=$(cd "$(dirname "${BASH_SOURCE[0]:-${(%):-%x}}")" && pwd) && cd "$dir"
# 
# get own IP on macos
# 
IP=$(ipconfig getifaddr en0)
# 
# Fritzbox is router -> last 1
# 
FB="$(echo $IP | cut -d '.' -f 1,2,3).1"
# 
# userdata
# 
US=***
# 
# set environment pw or hardcode it
# 
PW="$FRITZ_PASSWORD"
"$dir/port80delete.py" "$FB" "$US" "$PW"
# 
# fritzbox needs some rest
# 
sleep 10
# 
# open port 80 for this machine
# 
echo "Try to create portmappings port 80 to $IP ..."
ret=$("$dir/port80open.py" "$FB" "$US" "$PW" "$IP")
err=$( echo "$ret" | grep "errorCode")
while [ -n "$err" ]; do
    echo "   $ret"
    echo "   sleep some time ..."
    sleep 10
    ret=$("$dir/port80open.py" "$FB" "$US" "$PW" "$IP")
    err=$( echo "$ret" | grep "errorCode")
done
echo "Portmappings port 80 to $IP created."
# 
# certbots renewal
# 
certbot renew
# 
# close port 80
# 
"$dir/port80delete.py" "$FB" "$US" "$PW"
#
port80delete.py:
Code:
#!/usr/bin/env python3
import sys, os, datetime, time
from fritzconnection import FritzConnection
# 
# get environment
# 
user = os.getenv('FRITZ_USERNAME')
pw = os.getenv('FRITZ_PASSWORD')
ip = os.getenv('FRITZ_IP')
# 
# get commandline parameter
# 
for i in range(len(sys.argv)):
    match i:
        case 1:
             ip = sys.argv[i]
        case 2:
             user = sys.argv[i]
        case 3:
             pw = sys.argv[i]
# 
# test parameter
# 
if pw is None or user is None or ip is None:
    print ("Not all parameter set!")
    print (f"Usage: > {os.path.basename(sys.argv[0])} ip user password [internal_ip]")
    print ("  or set environmental variables FRITZ_USERNAME FRITZ_PASSWORD FRITZ_IP INTERN_IP")
    exit()
# 
# establish connection and test
# 
fc = FritzConnection(address=ip, user=user, password=pw, use_cache=True)
# state = fc.call_action("WLANConfiguration1", "GetInfo") # kein Fehler
# print(state)  # print router model information
# 
# get all IPv4 portmappings
# 
maxID = fc.call_action("WANPPPConnection1", "GetPortMappingNumberOfEntries") 
PortMappingNumberOfEntries = maxID["NewPortMappingNumberOfEntries"]
port_count = 0
for x in range(PortMappingNumberOfEntries):
    state = fc.call_action("WANPPPConnection1", "GetGenericPortMappingEntry", NewPortMappingIndex=x)
    if state["NewExternalPort"] == 80:
        if port_count == 0:
            port_count = 1
            print ("Portmappings port 80!")
        print (f'   Internal IP: {state["NewInternalClient"]} Enabled: {state["NewEnabled"]}')
# 
# delete all port 80 mappings, because there can be only one
# 
if port_count == 1:
    print ("Delete all portmappings port 80!")
    state = fc.call_action("WANPPPConnection1", "DeletePortMapping", \
        NewRemoteHost="0.0.0.0", \
        NewExternalPort=80, \
        NewProtocol="TCP")
    time.sleep(5)
else:
    print ("No portmappings found!")
port80open.py:
Code:
#!/usr/bin/env python3
import sys, os, datetime, time
from fritzconnection import FritzConnection
# 
# get environment
# 
user = os.getenv('FRITZ_USERNAME')
pw = os.getenv('FRITZ_PASSWORD')
ip = os.getenv('FRITZ_IP')
intern_ip = os.getenv('INTERN_IP')
# 
# get commandline parameter
# 
for i in range(len(sys.argv)):
    match i:
        case 1:
             ip = sys.argv[i]
        case 2:
             user = sys.argv[i]
        case 3:
             pw = sys.argv[i]
        case 4:
             intern_ip = sys.argv[i]
# 
# test parameter
# 
if pw is None or user is None or ip is None:
    print ("Not all parameter set!")
    print (f"Usage: > {os.path.basename(sys.argv[0])} ip user password [internal_ip]")
    print ("  or set environmental variables FRITZ_USERNAME FRITZ_PASSWORD FRITZ_IP INTERN_IP")
    exit()
# 
# no intern ip, just exit after deleting
# 
if intern_ip is None:
    print("No IP is given!\nExit")
    exit()
# 
# establish connection and test
# 
fc = FritzConnection(address=ip, user=user, password=pw)
# 
# create port 80 mappimg
# 
aDate=datetime.datetime.today().strftime('%Y-%m-%d_%H-%M-%S')
try:
    state = fc.call_action("WANPPPConnection1", "AddPortMapping", \
        NewRemoteHost="0.0.0.0", \
        NewExternalPort=80, \
        NewProtocol="TCP", \
        NewInternalPort=80, \
        NewInternalClient=intern_ip, \
        NewEnabled=True, \
        NewPortMappingDescription=f"{aDate}", \
        NewLeaseDuration=0)
except Exception as inst:
    print (inst)
Ich habe gemerkt, die Fritz!Box (meine ist 7590X) ist sehr langsam und sensible. Der gleiche Code macht manchmal 402-Errors (falsche Argumente), wenn es zu schnell geht. Einmal musste ich die FB neu starten, weil gar nichts mehr geht. Muss man ausprobieren, ob man die sleep braucht, ich definitiv ja.
 
Da muss ich meine Schnittstelle umstellen, sonnst kann ich die nicht erfassen.
Moin,

ich habe jetzt doch mal eine Übersicht erstellt (Basis sind die XML-Files meiner 7590er): PDF im Anhang.

Wenn ich mich nicht irgendwo vertan habe, dann wird deutlich, dass der Service WANIPConn1 auf Basis IGD1 eigentlich obsolet ist, weil alle Actions in der IGD2-Version enthalten sind (was ja auch irgendwie Sinn ergibt).
Warum AVM dann in letztere eigene Actions implementiert, und on top aber dann noch mit wanipconnection1 und wanpppconn1 zwei seperate Services (als Add-On) mit Überschneidungen definiert, erschließt sich mir nicht.
Ich sehe aber, dass wieder genauso alle Actions von wanipconnection1 vollständig in wanpppconn1 enthalten sind. Auf wanpppconn1 kann ich zugreifen (obwohl ich nicht am Cable hänge!), wanipconnection1 liefert mir, wie gesagt, nur 403er Fehler.

BTW: IGD1 und IGD2 enthalten die selben Informationen zu igd2ipv6fwcSCPD
Ja, mir war auch schon länger aufgefallen, dass meine Generator-Program hier eine eindeutige Doublette erzeugt. Habe das aber bisher ignoriert, weil es nicht wehtut... Ich vermute mal, das die IGD1 Spezifikation schon deutlich vor der IPv6-Spezifikation kam und AVM dann einfach später den Link in beide Dokus hineingeschustert hat - und das auch so in den XML abgebildet hat.

Black Senator
 

Anhänge

  • Overview WAN.pdf
    398 KB · Aufrufe: 7
  • Like
Reaktionen: Kruemelino
[...]
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:

Die sind bei mir auch vorhanden. Ich vermute, dass sie für eine vollständige Unterstützung der WANIPv6FirewallControl implantiert werden müssen. Gemäß Tabelle 2-6 (Actions) ist GetPinholePackets mit Status R (REQUIRED) aufgeführt. (Demgegenüber CheckPinholeWorking mit O (OPTIONAL). Vielleicht hat AVM einfach die komplette SCPD gemäß Kapitel 4 hier genutzt.)

Aber ich erhalte auch einen 403-Fehler.
 
Zuletzt bearbeitet:
WANIPv6FirewallControl:
Before processing the action request, the device MUST apply the chosen security policy, and authenticate and authorize the control point as required by the security policy. If the control point does not have the necessary permission to perform the action with the requested parameters, the device MUST return the 606 Action not authorized error code (defined in [DEVICE]).

Ja wie macht man das (mit FritzConnection oder php). Ich dachte, die Connection ist schon autorisiert?
 
Zuletzt bearbeitet:
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
Hey und danke für dein Code Snippet,

kannst du mir mal bitte bei dem debugging helfen, ich wollte dein Script ausprobieren, doch leider bekomme ich folgende Fehlermeldung:


Bash:
amnesia@yoga:~/Downloads$ python3 port80.py 192.168.10.1 user pass  192.168.10.103
No portmappings found!
Create portmappings port 80 to 192.168.10.103 ...
Traceback (most recent call last):
  File "/home/amnesia/Downloads/port80.py", line 49, in <module>
    state = fc.call_action("WANPPPConnection1", "AddPortMapping", \
  File "/home/amnesia/.local/lib/python3.10/site-packages/fritzconnection/core/fritzconnection.py", line 441, in call_action
    return self.soaper.execute(service, action_name, arguments)
  File "/home/amnesia/.local/lib/python3.10/site-packages/fritzconnection/core/soaper.py", line 286, in execute
    return handle_response(response)
  File "/home/amnesia/.local/lib/python3.10/site-packages/fritzconnection/core/soaper.py", line 268, in handle_response
    raise_fritzconnection_error(response)
  File "/home/amnesia/.local/lib/python3.10/site-packages/fritzconnection/core/soaper.py", line 191, in raise_fritzconnection_error
    raise exception(message)
fritzconnection.core.exceptions.FritzArgumentValueError: UPnPError:
errorCode: 600
errorDescription: Argument Value Invalid

Danke schonmal !
 
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.