fritzconnection icon indicating copy to clipboard operation
fritzconnection copied to clipboard

UPnPError: errorCode: 600 errorDescription: Argument Value Invalid

Open mfeske opened this issue 4 months ago • 0 comments

Hello everyone. Thank you very much for this great project. My plan is to use a script to create/activate/deactivate port forwarding on a timer. The reason for this is that port 80 is required for LE extension on one NAS and then also on another, and I don't always want to have port 80 open permanently. I am using a Fritz Box 7590 and two Synology NAS devices. Ideally, I would also like to be able to control the call from an external web server, but if I understand correctly, the call must be made internally. What works is: Connect to the Fritz Box List the services List the port forwarding.

However, setting and deleting one does not work. I am using FRITZ!OS: 8.03 and Python 3.13.

I haven't found any relevant documentation either, so I don't know whether a parameter is missing or in the wrong format or something similar.

log:

2025-08-08 13:43:58,385 - INFO - ✅ Verbindung zur Fritzbox erfolgreich hergestellt. 2025-08-08 13:43:58,386 - INFO - Verfügbare Dienste: ['any1', 'WANCommonIFC1', 'WANDSLLinkC1', 'WANIPConn1', 'WANIPv6Firewall1', 'DeviceInfo1', 'DeviceConfig1', 'Layer3Forwarding1', 'LANConfigSecurity1', 'ManagementServer1', 'Time1', 'UserInterface1', 'X_AVM-DE_Storage1', 'X_AVM-DE_WebDAVClient1', 'X_AVM-DE_UPnP1', 'X_AVM-DE_Speedtest1', 'X_AVM-DE_RemoteAccess1', 'X_AVM-DE_MyFritz1', 'X_VoIP1', 'X_AVM-DE_OnTel1', 'X_AVM-DE_Dect1', 'X_AVM-DE_TAM1', 'X_AVM-DE_AppSetup1', 'X_AVM-DE_Homeauto1', 'X_AVM-DE_Homeplug1', 'X_AVM-DE_Filelinks1', 'X_AVM-DE_Auth1', 'X_AVM-DE_HostFilter1', 'X_AVM-DE_USPController1', 'WLANConfiguration1', 'WLANConfiguration2', 'WLANConfiguration3', 'Hosts1', 'LANEthernetInterfaceConfig1', 'LANHostConfigManagement1', 'WANCommonInterfaceConfig1', 'WANDSLInterfaceConfig1', 'X_AVM-DE_WANMobileConnection1', 'WANDSLLinkConfig1', 'WANEthernetLinkConfig1', 'WANPPPConnection1', 'WANIPConnection1'] 2025-08-08 13:43:58,459 - INFO - Mapping 0: {'NewRemoteHost': '0.0.0.0', 'NewExternalPort': 8080, 'NewProtocol': 'TCP', 'NewInternalPort': 8080, 'NewInternalClient': '192.168.115.33', 'NewEnabled': True, 'NewPortMappingDescription': 'HTTP-Server', 'NewLeaseDuration': 0} 2025-08-08 13:43:58,522 - INFO - Mapping 1: {'NewRemoteHost': '0.0.0.0', 'NewExternalPort': '8083-8088', 'NewProtocol': 'TCP', 'NewInternalPort': 8083, 'NewInternalClient': '192.168.115.72', 'NewEnabled': True, 'NewPortMappingDescription': 'HTTP-Server', 'NewLeaseDuration': 0} 2025-08-08 13:43:58,592 - INFO - Mapping 2: {'NewRemoteHost': '0.0.0.0', 'NewExternalPort': 5002, 'NewProtocol': 'TCP', 'NewInternalPort': 5001, 'NewInternalClient': '192.168.115.112', 'NewEnabled': True, 'NewPortMappingDescription': 'HTTPS-Server', 'NewLeaseDuration': 0} 2025-08-08 13:43:58,661 - INFO - Mapping 3: {'NewRemoteHost': '0.0.0.0', 'NewExternalPort': 5001, 'NewProtocol': 'TCP', 'NewInternalPort': 5001, 'NewInternalClient': '192.168.115.155', 'NewEnabled': True, 'NewPortMappingDescription': 'HTTPS-Server', 'NewLeaseDuration': 0} 2025-08-08 13:43:58,734 - INFO - Mapping 4: {'NewRemoteHost': '0.0.0.0', 'NewExternalPort': 445, 'NewProtocol': 'TCP', 'NewInternalPort': 445, 'NewInternalClient': '192.168.115.155', 'NewEnabled': False, 'NewPortMappingDescription': 'smb', 'NewLeaseDuration': 0} 2025-08-08 13:43:58,807 - INFO - Mapping 5: {'NewRemoteHost': '0.0.0.0', 'NewExternalPort': 80, 'NewProtocol': 'TCP', 'NewInternalPort': 5000, 'NewInternalClient': '192.168.115.155', 'NewEnabled': True, 'NewPortMappingDescription': 'NAS_192_168_115_155', 'NewLeaseDuration': 0} 2025-08-08 13:43:58,856 - INFO - Keine weiteren Mappings. 2025-08-08 13:43:59,451 - ERROR - ❌ Fehler beim Setzen der Portweiterleitung: UPnPError: errorCode: 600 errorDescription: Argument Value Invalid

script: `import logging import os import sys from fritzconnection import FritzConnection from dotenv import load_dotenv

load_dotenv('config.env') NewRemoteHost = '' FRITZ_HOST = os.getenv('FRITZ_HOST') FRITZ_USER = os.getenv('FRITZ_USER') FRITZ_PASSWORD = os.getenv('FRITZ_PASSWORD') NAS_IP = sys.argv[2] if len(sys.argv) > 2 else '192.168.115.155' NAS_NAME = f"LE_NAS_{NAS_IP.replace('.', '_')}" ENABLE = sys.argv[1].lower() == 'on' # "on" oder "off" external_port = 80 internal_port = 5001

Logging konfigurieren

logging.basicConfig( filename='fritz_portmapping.log', filemode='a', format='%(asctime)s - %(levelname)s - %(message)s', level=logging.INFO )

Verbindungsaufbau

try: fc = FritzConnection(address=FRITZ_HOST, user=FRITZ_USER, password=FRITZ_PASSWORD) logging.info("✅ Verbindung zur Fritzbox erfolgreich hergestellt.") print("✅ Verbindung zur Fritzbox erfolgreich hergestellt.") except Exception as e: logging.error(f"❌ Verbindung zur Fritzbox fehlgeschlagen: {e}") print(f"❌ Verbindung zur Fritzbox fehlgeschlagen: {e}") sys.exit(1)

Dienste ausgeben und loggen

logging.info(f"Verfügbare Dienste: {list(fc.services.keys())}") print(f"Verfügbare Dienste: {list(fc.services.keys())}")

service_name = 'WANIPConnection1' service = fc.services.get(service_name) if not service: logging.error(f"❌ Service {service_name} nicht gefunden.") print(f"❌ Service {service_name} nicht gefunden.") sys.exit(1)

Aktuelle Port-Mappings ausgeben und loggen

index = 0 while True: try: mapping = fc.call_action(service_name, 'GetGenericPortMappingEntry', NewPortMappingIndex=index) logging.info(f"Mapping {index}: {mapping}") print(f"Mapping {index}: {mapping}") index += 1 except Exception: logging.info("Keine weiteren Mappings.") print("Keine weiteren Mappings.") break

Alte Mappings für NAS entfernen

num_rules = int(fc.call_action(service_name, 'GetPortMappingNumberOfEntries')['NewPortMappingNumberOfEntries']) for i in range(num_rules): try: data = fc.call_action(service_name, 'GetGenericPortMappingEntry', NewPortMappingIndex=i)

    if data['NewPortMappingDescription'] == NAS_NAME:

        remote_host = data.get('NewRemoteHost', '')
        ext_port = int(data.get('NewExternalPort'))
        protocol = data.get('NewProtocol')
        logging.info(f"🛠️ Lösche Mapping mit: Host={remote_host}, Port={ext_port}, Protocol={protocol}")
        print(f"🛠️ Lösche Mapping mit: Host={remote_host}, Port={ext_port}, Protocol={protocol}")

        logging.info(f"🗑️ Versuche Portweiterleitung zu löschen: "
                     f"{data['NewExternalPort']} {data['NewProtocol']} "
                     f"{data['NewRemoteHost']} ({data['NewPortMappingDescription']})")

        remote_host = data['NewRemoteHost']
        if remote_host == '0.0.0.0':
            remote_host = ''  # Fritzbox erwartet leeren String ?
        fc.call_action(service_name, 'DeletePortMapping',
                       NewRemoteHost=remote_host,
                       NewExternalPort=int(data['NewExternalPort']),
                       NewProtocol=data['NewProtocol']
                       )

        logging.info(f"🗑️ Alte Portweiterleitung {NAS_NAME} auf Port {data['NewExternalPort']} gelöscht.")
        print(f"🗑️ Alte Portweiterleitung {NAS_NAME} auf Port {data['NewExternalPort']} gelöscht.")
except Exception as e:
    logging.error(f"❌ Fehler beim Löschen der Portweiterleitung {NAS_NAME}: {e}")
    print(f"❌ Fehler beim Löschen der Portweiterleitung {NAS_NAME}: {e}")

def port_mapping_exists(fc, external_port, protocol='TCP'): index = 0 while True: try: mapping = fc.call_action('WANIPConnection1', 'GetGenericPortMappingEntry', NewPortMappingIndex=index) if (int(mapping['NewExternalPort']) == external_port and mapping['NewProtocol'] == protocol): return True index += 1 except Exception: return False

if ENABLE: if not port_mapping_exists(fc, external_port): try: print(f"Setze Portweiterleitung: Extern {external_port} -> Intern {NAS_IP}:{internal_port}") fc.call_action(service_name, 'AddPortMapping', NewRemoteHost='', NewExternalPort=int(external_port), NewProtocol='TCP', NewInternalPort=int(internal_port), NewInternalClient=NAS_IP, NewEnabled=1, NewPortMappingDescription=NAS_NAME, NewLeaseDuration=0) logging.info(f"✅ Port {external_port} wurde auf {NAS_IP}:{internal_port} weitergeleitet.") print(f"✅ Port {external_port} wurde auf {NAS_IP}:{internal_port} weitergeleitet.") except Exception as e: logging.error(f"❌ Fehler beim Setzen der Portweiterleitung: {e}") print(f"❌ Fehler beim Setzen der Portweiterleitung: {e}") else: logging.info("ℹ️ Mapping existiert bereits.") print("Mapping existiert bereits.") else: # Portweiterleitung entfernen try: fc.call_action(service_name, 'DeletePortMapping', NewRemoteHost='', NewExternalPort=int(external_port), NewProtocol='TCP') logging.info(f"🛑 Portweiterleitung zu {NAS_IP} wurde entfernt.") print(f"🛑 Portweiterleitung zu {NAS_IP} wurde entfernt.") except Exception as e: logging.error(f"❌ Fehler beim Entfernen der Portweiterleitung: {e}") print(f"❌ Fehler beim Entfernen der Portweiterleitung: {e}")`

mfeske avatar Aug 08 '25 11:08 mfeske