import os import json from collections import OrderedDict from aioupnp.fault import UPnPError from tests import AsyncioTestCase, mock_tcp_and_udp from aioupnp.gateway import Gateway, get_action_list from aioupnp.serialization.ssdp import SSDPDatagram from aioupnp.serialization.soap import serialize_soap_post from aioupnp.upnp import UPnP def gen_get_bytes(location: str, host: str) -> bytes: return ( 'GET %s HTTP/1.1\r\nAccept-Encoding: gzip\r\nHost: %s\r\nConnection: Close\r\n\r\n' % (location, host) ).encode() class TestParseActionList(AsyncioTestCase): test_action_list = {'actionList': { 'action': [OrderedDict([('name', 'SetConnectionType'), ('argumentList', OrderedDict([('argument', OrderedDict( [('name', 'NewConnectionType'), ('direction', 'in'), ('relatedStateVariable', 'ConnectionType')]))]))]), OrderedDict([('name', 'GetConnectionTypeInfo'), ('argumentList', OrderedDict([('argument', [ OrderedDict([('name', 'NewConnectionType'), ('direction', 'out'), ('relatedStateVariable', 'ConnectionType')]), OrderedDict( [('name', 'NewPossibleConnectionTypes'), ('direction', 'out'), ('relatedStateVariable', 'PossibleConnectionTypes')])])]))]), OrderedDict([('name', 'RequestConnection')]), OrderedDict([('name', 'ForceTermination')]), OrderedDict([('name', 'GetStatusInfo'), ('argumentList', OrderedDict([('argument', [OrderedDict( [('name', 'NewConnectionStatus'), ('direction', 'out'), ('relatedStateVariable', 'ConnectionStatus')]), OrderedDict( [('name', 'NewLastConnectionError'), ('direction', 'out'), ('relatedStateVariable', 'LastConnectionError')]), OrderedDict( [('name', 'NewUptime'), ('direction', 'out'), ('relatedStateVariable', 'Uptime')])])]))]), OrderedDict([('name', 'GetNATRSIPStatus'), ('argumentList', OrderedDict([('argument', [OrderedDict( [('name', 'NewRSIPAvailable'), ('direction', 'out'), ('relatedStateVariable', 'RSIPAvailable')]), OrderedDict( [('name', 'NewNATEnabled'), ('direction', 'out'), ('relatedStateVariable', 'NATEnabled')])])]))]), OrderedDict( [('name', 'GetGenericPortMappingEntry'), ('argumentList', OrderedDict([('argument', [OrderedDict( [('name', 'NewPortMappingIndex'), ('direction', 'in'), ('relatedStateVariable', 'PortMappingNumberOfEntries')]), OrderedDict( [('name', 'NewRemoteHost'), ('direction', 'out'), ('relatedStateVariable', 'RemoteHost')]), OrderedDict( [('name', 'NewExternalPort'), ('direction', 'out'), ('relatedStateVariable', 'ExternalPort')]), OrderedDict( [('name', 'NewProtocol'), ('direction', 'out'), ('relatedStateVariable', 'PortMappingProtocol')]), OrderedDict([('name', 'NewInternalPort'), ('direction', 'out'), ( 'relatedStateVariable', 'InternalPort')]), OrderedDict([('name', 'NewInternalClient'), ('direction', 'out'), ( 'relatedStateVariable', 'InternalClient')]), OrderedDict([('name', 'NewEnabled'), ('direction', 'out'), ( 'relatedStateVariable', 'PortMappingEnabled')]), OrderedDict([('name', 'NewPortMappingDescription'), ('direction', 'out'), ( 'relatedStateVariable', 'PortMappingDescription')]), OrderedDict([('name', 'NewLeaseDuration'), ('direction', 'out'), ( 'relatedStateVariable', 'PortMappingLeaseDuration')])])]))]), OrderedDict([('name', 'GetSpecificPortMappingEntry'), ('argumentList', OrderedDict([('argument', [ OrderedDict( [('name', 'NewRemoteHost'), ('direction', 'in'), ('relatedStateVariable', 'RemoteHost')]), OrderedDict([('name', 'NewExternalPort'), ('direction', 'in'), ('relatedStateVariable', 'ExternalPort')]), OrderedDict( [('name', 'NewProtocol'), ('direction', 'in'), ('relatedStateVariable', 'PortMappingProtocol')]), OrderedDict( [('name', 'NewInternalPort'), ('direction', 'out'), ('relatedStateVariable', 'InternalPort')]), OrderedDict( [('name', 'NewInternalClient'), ('direction', 'out'), ('relatedStateVariable', 'InternalClient')]), OrderedDict( [('name', 'NewEnabled'), ('direction', 'out'), ('relatedStateVariable', 'PortMappingEnabled')]), OrderedDict( [('name', 'NewPortMappingDescription'), ('direction', 'out'), ('relatedStateVariable', 'PortMappingDescription')]), OrderedDict( [('name', 'NewLeaseDuration'), ('direction', 'out'), ('relatedStateVariable', 'PortMappingLeaseDuration')])])]))]), OrderedDict( [('name', 'AddPortMapping'), ('argumentList', OrderedDict([('argument', [ OrderedDict( [('name', 'NewRemoteHost'), ('direction', 'in'), ('relatedStateVariable', 'RemoteHost')]), OrderedDict( [('name', 'NewExternalPort'), ('direction', 'in'), ('relatedStateVariable', 'ExternalPort')]), OrderedDict( [('name', 'NewProtocol'), ('direction', 'in'), ('relatedStateVariable', 'PortMappingProtocol')]), OrderedDict( [('name', 'NewInternalPort'), ('direction', 'in'), ('relatedStateVariable', 'InternalPort')]), OrderedDict( [('name', 'NewInternalClient'), ('direction', 'in'), ('relatedStateVariable', 'InternalClient')]), OrderedDict( [('name', 'NewEnabled'), ('direction', 'in'), ('relatedStateVariable', 'PortMappingEnabled')]), OrderedDict([('name', 'NewPortMappingDescription'), ('direction', 'in'), ('relatedStateVariable', 'PortMappingDescription')]), OrderedDict( [('name', 'NewLeaseDuration'), ('direction', 'in'), ('relatedStateVariable', 'PortMappingLeaseDuration')])])]))]), OrderedDict( [('name', 'DeletePortMapping'), ('argumentList', OrderedDict([('argument', [ OrderedDict( [('name', 'NewRemoteHost'), ('direction', 'in'), ('relatedStateVariable', 'RemoteHost')]), OrderedDict( [('name', 'NewExternalPort'), ('direction', 'in'), ('relatedStateVariable', 'ExternalPort')]), OrderedDict( [('name', 'NewProtocol'), ('direction', 'in'), ('relatedStateVariable', 'PortMappingProtocol')])])]))]), OrderedDict([('name', 'GetExternalIPAddress'), ('argumentList', OrderedDict( [('argument', OrderedDict([('name', 'NewExternalIPAddress'), ('direction', 'out'), ('relatedStateVariable', 'ExternalIPAddress')]))]))])]}} def test_parse_expected_action_list(self): expected = [('SetConnectionType', ['NewConnectionType'], []), ('GetConnectionTypeInfo', [], ['NewConnectionType', 'NewPossibleConnectionTypes']), ('RequestConnection', [], []), ('ForceTermination', [], []), ('GetStatusInfo', [], ['NewConnectionStatus', 'NewLastConnectionError', 'NewUptime']), ('GetNATRSIPStatus', [], ['NewRSIPAvailable', 'NewNATEnabled']), ( 'GetGenericPortMappingEntry', ['NewPortMappingIndex'], ['NewRemoteHost', 'NewExternalPort', 'NewProtocol', 'NewInternalPort', 'NewInternalClient', 'NewEnabled', 'NewPortMappingDescription', 'NewLeaseDuration']), ( 'GetSpecificPortMappingEntry', ['NewRemoteHost', 'NewExternalPort', 'NewProtocol'], ['NewInternalPort', 'NewInternalClient', 'NewEnabled', 'NewPortMappingDescription', 'NewLeaseDuration']), ('AddPortMapping', ['NewRemoteHost', 'NewExternalPort', 'NewProtocol', 'NewInternalPort', 'NewInternalClient', 'NewEnabled', 'NewPortMappingDescription', 'NewLeaseDuration'], []), ('DeletePortMapping', ['NewRemoteHost', 'NewExternalPort', 'NewProtocol'], []), ('GetExternalIPAddress', [], ['NewExternalIPAddress'])] self.assertEqual(expected, get_action_list(self.test_action_list)) class TestDiscoverDLinkDIR890L(AsyncioTestCase): gateway_info = \ {'manufacturer_string': 'D-Link DIR-890L', 'gateway_address': '10.0.0.1', 'server': 'Linux, UPnP/1.0, DIR-890L Ver 1.20', 'urlBase': 'http://10.0.0.1:49152', 'location': 'http://10.0.0.1:49152/InternetGatewayDevice.xml', 'specVersion': {'major': '1', 'minor': '0'}, 'usn': 'uuid:11111111-2222-3333-4444-555555555555::urn:schemas-upnp-org:device:WANDevice:1', 'urn': 'urn:schemas-upnp-org:device:WANDevice:1', 'gateway_xml': 'HTTP/1.1 200 OK\r\nServer: WebServer\r\nDate: Thu, 11 Oct 2018 22:16:16 GMT\r\nContent-Type: text/xml\r\nContent-Length: 3921\r\nLast-Modified: Thu, 09 Aug 2018 12:41:07 GMT\r\nConnection: close\r\n\r\n\n\n\t\n\t\t1\n\t\t0\n\t\n\thttp://10.0.0.1:49152\n\t\n\t\turn:schemas-upnp-org:device:InternetGatewayDevice:1\n\t\tWireless Broadband Router\n\t\tD-Link Corporation\n\t\thttp://www.dlink.com\n\t\tD-Link Router\n\t\tD-Link Router\n\t\tDIR-890L\n\t\thttp://www.dlink.com\n\t\t120\n\t\tuuid:11111111-2222-3333-4444-555555555555\n\t\t\n\t\t\t\n\t\t\t\timage/gif\n\t\t\t\t118\n\t\t\t\t119\n\t\t\t\t8\n\t\t\t\t/ligd.gif\n\t\t\t\n\t\t\n\t\t\n\t\t\t\n\t\t\t\turn:schemas-microsoft-com:service:OSInfo:1\n\t\t\t\turn:microsoft-com:serviceId:OSInfo1\n\t\t\t\t/soap.cgi?service=OSInfo1\n\t\t\t\t/gena.cgi?service=OSInfo1\n\t\t\t\t/OSInfo.xml\n\t\t\t\n\t\t\t\n\t\t\t\turn:schemas-upnp-org:service:Layer3Forwarding:1\n\t\t\t\turn:upnp-org:serviceId:L3Forwarding1\n\t\t\t\t/soap.cgi?service=L3Forwarding1\n\t\t\t\t/gena.cgi?service=L3Forwarding1\n\t\t\t\t/Layer3Forwarding.xml\n\t\t\t\n\t\t\n\t\t\n\t\t\t\n\t\t\t\turn:schemas-upnp-org:device:WANDevice:1\n\t\t\t\tWANDevice\n\t\t\t\tD-Link\n\t\t\t\thttp://www.dlink.com\n\t\t\t\tWANDevice\n\t\t\t\tDIR-890L\n\t\t\t\t1\n\t\t\t\thttp://www.dlink.com\n\t\t\t\t120\n\t\t\t\tuuid:11111111-2222-3333-4444-555555555555\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\turn:schemas-upnp-org:service:WANCommonInterfaceConfig:1\n\t\t\t\t\t\turn:upnp-org:serviceId:WANCommonIFC1\n\t\t\t\t\t\t/soap.cgi?service=WANCommonIFC1\n\t\t\t\t\t\t/gena.cgi?service=WANCommonIFC1\n\t\t\t\t\t\t/WANCommonInterfaceConfig.xml\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\turn:schemas-upnp-org:device:WANConnectionDevice:1\n\t\t\t\t\t\tWANConnectionDevice\n\t\t\t\t\t\tD-Link\n\t\t\t\t\t\thttp://www.dlink.com\n\t\t\t\t\t\tWanConnectionDevice\n\t\t\t\t\t\tDIR-890L\n\t\t\t\t\t\t1\n\t\t\t\t\t\thttp://www.dlink.com\n\t\t\t\t\t\t120\n\t\t\t\t\t\tuuid:11111111-2222-3333-4444-555555555555\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\turn:schemas-upnp-org:service:WANEthernetLinkConfig:1\n\t\t\t\t\t\t\t\turn:upnp-org:serviceId:WANEthLinkC1\n\t\t\t\t\t\t\t\t/soap.cgi?service=WANEthLinkC1\n\t\t\t\t\t\t\t\t/gena.cgi?service=WANEthLinkC1\n\t\t\t\t\t\t\t\t/WANEthernetLinkConfig.xml\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\turn:schemas-upnp-org:service:WANIPConnection:1\n\t\t\t\t\t\t\t\turn:upnp-org:serviceId:WANIPConn1\n\t\t\t\t\t\t\t\t/soap.cgi?service=WANIPConn1\n\t\t\t\t\t\t\t\t/gena.cgi?service=WANIPConn1\n\t\t\t\t\t\t\t\t/WANIPConnection.xml\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\n\t\thttp://10.0.0.1\n\t\n\n', 'services_xml': { '/OSInfo.xml': 'HTTP/1.1 200 OK\r\nServer: WebServer\r\nDate: Thu, 11 Oct 2018 22:16:16 GMT\r\nContent-Type: text/xml\r\nContent-Length: 219\r\nLast-Modified: Thu, 09 Aug 2018 12:41:07 GMT\r\nConnection: close\r\n\r\n\n\n\t\n\t\t1\n\t\t0\n\t\n\t\n\t\n\t\n\t\n\n', '/Layer3Forwarding.xml': 'HTTP/1.1 200 OK\r\nServer: WebServer\r\nDate: Thu, 11 Oct 2018 22:16:16 GMT\r\nContent-Type: text/xml\r\nContent-Length: 920\r\nLast-Modified: Thu, 09 Aug 2018 12:41:07 GMT\r\nConnection: close\r\n\r\n\n\n\t\n\t\t1\n\t\t0\n\t\n\t\n\t\t\n\t\t\tGetDefaultConnectionService\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tNewDefaultConnectionService\n\t\t\t\t\tout\n\t\t\t\t\tDefaultConnectionService\n\t\t\t\t\n\t\t\t\n\t\t\n\t\t\n\t\t\tSetDefaultConnectionService\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tNewDefaultConnectionService\n\t\t\t\t\tin\n\t\t\t\t\tDefaultConnectionService\n\t\t\t\t\n\t\t\t\n\t\t\n\t\n\t\n\t\t\n\t\t\tDefaultConnectionService\n\t\t\tstring\n\t\t\n\t\n\n', '/WANCommonInterfaceConfig.xml': 'HTTP/1.1 200 OK\r\nServer: WebServer\r\nDate: Thu, 11 Oct 2018 22:16:16 GMT\r\nContent-Type: text/xml\r\nContent-Length: 5343\r\nLast-Modified: Thu, 09 Aug 2018 12:41:07 GMT\r\nConnection: close\r\n\r\n\r\n\r\n\t\r\n\t\t1\r\n\t\t0\r\n\t\r\n\t\r\n\t\t\r\n\t\t\tGetCommonLinkProperties\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewWANAccessType\r\n\t\t\t\t\tout\r\n\t\t\t\t\tWANAccessType\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewLayer1UpstreamMaxBitRate\r\n\t\t\t\t\tout\r\n\t\t\t\t\tLayer1UpstreamMaxBitRate\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewLayer1DownstreamMaxBitRate\r\n\t\t\t\t\tout\r\n\t\t\t\t\tLayer1DownstreamMaxBitRate\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewPhysicalLinkStatus\r\n\t\t\t\t\tout\r\n\t\t\t\t\tPhysicalLinkStatus\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\tGetTotalBytesSent\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewTotalBytesSent\r\n\t\t\t\t\tout\r\n\t\t\t\t\tTotalBytesSent\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\tGetTotalBytesReceived\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewTotalBytesReceived\r\n\t\t\t\t\tout\r\n\t\t\t\t\tTotalBytesReceived\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\tGetTotalPacketsSent\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewTotalPacketsSent\r\n\t\t\t\t\tout\r\n\t\t\t\t\tTotalPacketsSent\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\tGetTotalPacketsReceived\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewTotalPacketsReceived\r\n\t\t\t\t\tout\r\n\t\t\t\t\tTotalPacketsReceived\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\tX_GetICSStatistics\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tTotalBytesSent\r\n\t\t\t\t\tout\r\n\t\t\t\t\tTotalBytesSent\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tTotalBytesReceived\r\n\t\t\t\t\tout\r\n\t\t\t\t\tTotalBytesReceived\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tTotalPacketsSent\r\n\t\t\t\t\tout\r\n\t\t\t\t\tTotalPacketsSent\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tTotalPacketsReceived\r\n\t\t\t\t\tout\r\n\t\t\t\t\tTotalPacketsReceived\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tLayer1DownstreamMaxBitRate\r\n\t\t\t\t\tout\r\n\t\t\t\t\tLayer1DownstreamMaxBitRate\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tUptime\r\n\t\t\t\t\tout\r\n\t\t\t\t\tX_Uptime\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\t\tWANAccessType\r\n\t\t\tstring\r\n\t\t\t\r\n\t\t\t\tDSL\r\n\t\t\t\tPOTS\r\n\t\t\t\tCable\r\n\t\t\t\tEthernet\r\n\t\t\t\tOther\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\tLayer1UpstreamMaxBitRate\r\n\t\t\tui4\r\n\t\t\r\n\t\t\r\n\t\t\tLayer1DownstreamMaxBitRate\r\n\t\t\tui4\r\n\t\t\r\n\t\t\r\n\t\t\tPhysicalLinkStatus\r\n\t\t\tstring\r\n\t\t\t\r\n\t\t\t\tUp\r\n\t\t\t\tDown\r\n\t\t\t\tInitializing\r\n\t\t\t\tUnavailable\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\tWANAccessProvider\r\n\t\t\tstring\r\n\t\t\r\n\t\t\r\n\t\t\tMaximumActiveConnections\r\n\t\t\tui2\r\n\t\t\t\r\n\t\t\t\t1\r\n\t\t\t\t\r\n\t\t\t\t1\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\tTotalBytesSent\r\n\t\t\tui4\r\n\t\t\r\n\t\t\r\n\t\t\tTotalBytesReceived\r\n\t\t\tui4\r\n\t\t\r\n\t\t\r\n\t\t\tTotalPacketsSent\r\n\t\t\tui4\r\n\t\t\r\n\t\t\r\n\t\t\tTotalPacketsReceived\r\n\t\t\tui4\r\n\t\t\r\n\t\t\r\n\t\t\tX_PersonalFirewallEnabled\r\n\t\t\tboolean\r\n\t\t\r\n\t\t\r\n\t\t\tX_Uptime\r\n\t\t\tui4\r\n\t\t\r\n\t\r\n\r\n', '/WANEthernetLinkConfig.xml': 'HTTP/1.1 200 OK\r\nServer: WebServer\r\nDate: Thu, 11 Oct 2018 22:16:16 GMT\r\nContent-Type: text/xml\r\nContent-Length: 773\r\nLast-Modified: Thu, 09 Aug 2018 12:41:07 GMT\r\nConnection: close\r\n\r\n\n\n\t\n\t\t1\n\t\t0\n\t\n\t\n\t\t\n\t\t\tGetEthernetLinkStatus\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tNewEthernetLinkStatus\n\t\t\t\t\tout\n\t\t\t\t\tEthernetLinkStatus\n\t\t\t\t\n\t\t\t\n\t\t\n\t\n\t\n\t\t\n\t\t\tEthernetLinkStatus\n\t\t\tstring\n\t\t\t\n\t\t\t\tUp\n\t\t\t\tDown\n\t\t\t\tUnavailable\n\t\t\t\n\t\t\n\t\n\n', '/WANIPConnection.xml': 'HTTP/1.1 200 OK\r\nServer: WebServer\r\nDate: Thu, 11 Oct 2018 22:16:16 GMT\r\nContent-Type: text/xml\r\nContent-Length: 12078\r\nLast-Modified: Thu, 09 Aug 2018 12:41:07 GMT\r\nConnection: close\r\n\r\n\r\n\r\n\t\r\n\t\t1\r\n\t\t0\r\n\t\r\n\t\r\n\t\t\r\n\t\t\tSetConnectionType\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewConnectionType\r\n\t\t\t\t\tin\r\n\t\t\t\t\tConnectionType\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t \r\n\t\t\r\n\t\t\tGetConnectionTypeInfo\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewConnectionType\r\n\t\t\t\t\tout\r\n\t\t\t\t\tConnectionType\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewPossibleConnectionTypes\r\n\t\t\t\t\tout\r\n\t\t\t\t\tPossibleConnectionTypes\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\tRequestConnection\r\n\t\t\r\n\t\t\r\n\t\t\tForceTermination\r\n\t\t\r\n\t\t\r\n\t\t\tGetStatusInfo\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewConnectionStatus\r\n\t\t\t\t\tout\r\n\t\t\t\t\tConnectionStatus\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewLastConnectionError\r\n\t\t\t\t\tout\r\n\t\t\t\t\tLastConnectionError\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewUptime\r\n\t\t\t\t\tout\r\n\t\t\t\t\tUptime\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\tGetNATRSIPStatus\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewRSIPAvailable\r\n\t\t\t\t\tout\r\n\t\t\t\t\tRSIPAvailable\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewNATEnabled\r\n\t\t\t\t\tout\r\n\t\t\t\t\tNATEnabled\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\tGetGenericPortMappingEntry\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewPortMappingIndex\r\n\t\t\t\t\tin\r\n\t\t\t\t\tPortMappingNumberOfEntries\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewRemoteHost\r\n\t\t\t\t\tout\r\n\t\t\t\t\tRemoteHost\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewExternalPort\r\n\t\t\t\t\tout\r\n\t\t\t\t\tExternalPort\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewProtocol\r\n\t\t\t\t\tout\r\n\t\t\t\t\tPortMappingProtocol\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewInternalPort\r\n\t\t\t\t\tout\r\n\t\t\t\t\tInternalPort\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewInternalClient\r\n\t\t\t\t\tout\r\n\t\t\t\t\tInternalClient\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewEnabled\r\n\t\t\t\t\tout\r\n\t\t\t\t\tPortMappingEnabled\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewPortMappingDescription\r\n\t\t\t\t\tout\r\n\t\t\t\t\tPortMappingDescription\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewLeaseDuration\r\n\t\t\t\t\tout\r\n\t\t\t\t\tPortMappingLeaseDuration\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\tGetSpecificPortMappingEntry\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewRemoteHost\r\n\t\t\t\t\tin\r\n\t\t\t\t\tRemoteHost\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewExternalPort\r\n\t\t\t\t\tin\r\n\t\t\t\t\tExternalPort\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewProtocol\r\n\t\t\t\t\tin\r\n\t\t\t\t\tPortMappingProtocol\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewInternalPort\r\n\t\t\t\t\tout\r\n\t\t\t\t\tInternalPort\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewInternalClient\r\n\t\t\t\t\tout\r\n\t\t\t\t\tInternalClient\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewEnabled\r\n\t\t\t\t\tout\r\n\t\t\t\t\tPortMappingEnabled\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewPortMappingDescription\r\n\t\t\t\t\tout\r\n\t\t\t\t\tPortMappingDescription\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewLeaseDuration\r\n\t\t\t\t\tout\r\n\t\t\t\t\tPortMappingLeaseDuration\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\tAddPortMapping\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewRemoteHost\r\n\t\t\t\t\tin\r\n\t\t\t\t\tRemoteHost\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewExternalPort\r\n\t\t\t\t\tin\r\n\t\t\t\t\tExternalPort\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewProtocol\r\n\t\t\t\t\tin\r\n\t\t\t\t\tPortMappingProtocol\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewInternalPort\r\n\t\t\t\t\tin\r\n\t\t\t\t\tInternalPort\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewInternalClient\r\n\t\t\t\t\tin\r\n\t\t\t\t\tInternalClient\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewEnabled\r\n\t\t\t\t\tin\r\n\t\t\t\t\tPortMappingEnabled\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewPortMappingDescription\r\n\t\t\t\t\tin\r\n\t\t\t\t\tPortMappingDescription\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewLeaseDuration\r\n\t\t\t\t\tin\r\n\t\t\t\t\tPortMappingLeaseDuration\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\tDeletePortMapping\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewRemoteHost\r\n\t\t\t\t\tin\r\n\t\t\t\t\tRemoteHost\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewExternalPort\r\n\t\t\t\t\tin\r\n\t\t\t\t\tExternalPort\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewProtocol\r\n\t\t\t\t\tin\r\n\t\t\t\t\tPortMappingProtocol\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\tGetExternalIPAddress\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\tNewExternalIPAddress\r\n\t\t\t\t\tout\r\n\t\t\t\t\tExternalIPAddress\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\t\tConnectionType\r\n\t\t\tstring\r\n\t\t\tUnconfigured\r\n\t\t\r\n\t\t\r\n\t\t\tPossibleConnectionTypes\r\n\t\t\tstring\r\n\t\t\t\r\n\t\t\t\tUnconfigured\r\n\t\t\t\tIP_Routed\r\n\t\t\t\tIP_Bridged\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\tConnectionStatus\r\n\t\t\tstring\r\n\t\t\tUnconfigured\r\n\t\t\t\r\n\t\t\t\tUnconfigured\r\n\t\t\t\tConnecting\r\n\t\t\t\tAuthenticating\r\n\t\t\t\tPendingDisconnect\r\n\t\t\t\tDisconnecting\r\n\t\t\t\tDisconnected\r\n\t\t\t\tConnected\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\tUptime\r\n\t\t\tui4\r\n\t\t\t0\r\n\t\t\t\r\n\t\t\t\t0\r\n\t\t\t\t\r\n\t\t\t\t1\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\tRSIPAvailable\r\n\t\tboolean\r\n\t\t\t0\r\n\t\t\r\n\t\t\r\n\t\t\tNATEnabled\r\n\t\t\tboolean\r\n\t\t\t1\r\n\t\t \r\n\t\t\r\n\t\t\tX_Name\r\n\t\t\tstring\r\n\t\t\r\n\t\t\r\n\t\t\tLastConnectionError\r\n\t\t\tstring\r\n\t\t\tERROR_NONE\r\n\t\t\t\r\n\t\t\t\tERROR_NONE\r\n\t\t\t\tERROR_ISP_TIME_OUT\r\n\t\t\t\tERROR_COMMAND_ABORTED\r\n\t\t\t\tERROR_NOT_ENABLED_FOR_INTERNET\r\n\t\t\t\tERROR_BAD_PHONE_NUMBER\r\n\t\t\t\tERROR_USER_DISCONNECT\r\n\t\t\t\tERROR_ISP_DISCONNECT\r\n\t\t\t\tERROR_IDLE_DISCONNECT\r\n\t\t\t\tERROR_FORCED_DISCONNECT\r\n\t\t\t\tERROR_SERVER_OUT_OF_RESOURCES\r\n\t\t\t\tERROR_RESTRICTED_LOGON_HOURS\r\n\t\t\t\tERROR_ACCOUNT_DISABLED\r\n\t\t\t\tERROR_ACCOUNT_EXPIRED\r\n\t\t\t\tERROR_PASSWORD_EXPIRED\r\n\t\t\t\tERROR_AUTHENTICATION_FAILURE\r\n\t\t\t\tERROR_NO_DIALTONE\r\n\t\t\t\tERROR_NO_CARRIER\r\n\t\t\t\tERROR_NO_ANSWER\r\n\t\t\t\tERROR_LINE_BUSY\r\n\t\t\t\tERROR_UNSUPPORTED_BITSPERSECOND\r\n\t\t\t\tERROR_TOO_MANY_LINE_ERRORS\r\n\t\t\t\tERROR_IP_CONFIGURATION\r\n\t\t\t\tERROR_UNKNOWN\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\tExternalIPAddress\r\n\t\t\tstring\r\n\t\t\r\n\t\t\r\n\t\t\tRemoteHost\r\n\t\t\tstring\r\n\t\t\r\n\t\t\r\n\t\t\tExternalPort\r\n\t\t\tui2\r\n\t\t\r\n\t\t\r\n\t\t\tInternalPort\r\n\t\t\tui2\r\n\t\t\r\n\t\t\r\n\t\t\tPortMappingProtocol\r\n\t\t\tstring\r\n\t\t\t\r\n\t\t\t\tTCP\r\n\t\t\t\tUDP\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\tInternalClient\r\n\t\t\tstring\r\n\t\t\r\n\t\t\r\n\t\t\tPortMappingDescription\r\n\t\t\tstring\r\n\t\t\r\n\t\t\r\n\t\t\tPortMappingEnabled\r\n\t\t\tboolean\r\n\t\t\r\n\t\t\r\n\t\t\tPortMappingLeaseDuration\r\n\t\t\tui4\r\n\t\t\r\n\t\t\r\n\t\t\tPortMappingNumberOfEntries\r\n\t\t\tui2\r\n\t\t\r\n\t\r\n\r\n'}, 'services': {'/OSInfo.xml': OrderedDict([('serviceType', 'urn:schemas-microsoft-com:service:OSInfo:1'), ('serviceId', 'urn:microsoft-com:serviceId:OSInfo1'), ('controlURL', '/soap.cgi?service=OSInfo1'), ('eventSubURL', '/gena.cgi?service=OSInfo1'), ('SCPDURL', '/OSInfo.xml')]), '/Layer3Forwarding.xml': OrderedDict( [('serviceType', 'urn:schemas-upnp-org:service:Layer3Forwarding:1'), ('serviceId', 'urn:upnp-org:serviceId:L3Forwarding1'), ('controlURL', '/soap.cgi?service=L3Forwarding1'), ('eventSubURL', '/gena.cgi?service=L3Forwarding1'), ('SCPDURL', '/Layer3Forwarding.xml')]), '/WANCommonInterfaceConfig.xml': OrderedDict( [('serviceType', 'urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1'), ('serviceId', 'urn:upnp-org:serviceId:WANCommonIFC1'), ('controlURL', '/soap.cgi?service=WANCommonIFC1'), ('eventSubURL', '/gena.cgi?service=WANCommonIFC1'), ('SCPDURL', '/WANCommonInterfaceConfig.xml')]), '/WANEthernetLinkConfig.xml': OrderedDict( [('serviceType', 'urn:schemas-upnp-org:service:WANEthernetLinkConfig:1'), ('serviceId', 'urn:upnp-org:serviceId:WANEthLinkC1'), ('controlURL', '/soap.cgi?service=WANEthLinkC1'), ('eventSubURL', '/gena.cgi?service=WANEthLinkC1'), ('SCPDURL', '/WANEthernetLinkConfig.xml')]), '/WANIPConnection.xml': OrderedDict( [('serviceType', 'urn:schemas-upnp-org:service:WANIPConnection:1'), ('serviceId', 'urn:upnp-org:serviceId:WANIPConn1'), ('controlURL', '/soap.cgi?service=WANIPConn1'), ('eventSubURL', '/gena.cgi?service=WANIPConn1'), ('SCPDURL', '/WANIPConnection.xml')])}, 'reply': OrderedDict( [('CACHE_CONTROL', 'max-age=1800'), ('LOCATION', 'http://10.0.0.1:49152/InternetGatewayDevice.xml'), ('SERVER', 'Linux, UPnP/1.0, DIR-890L Ver 1.20'), ('ST', 'urn:schemas-upnp-org:device:WANDevice:1'), ('USN', 'uuid:11111111-2222-3333-4444-555555555555::urn:schemas-upnp-org:device:WANDevice:1')]), 'soap_port': 49152, 'registered_soap_commands': {'GetGenericPortMappingEntry': 'urn:schemas-upnp-org:service:WANIPConnection:1', 'GetSpecificPortMappingEntry': 'urn:schemas-upnp-org:service:WANIPConnection:1', 'AddPortMapping': 'urn:schemas-upnp-org:service:WANIPConnection:1', 'DeletePortMapping': 'urn:schemas-upnp-org:service:WANIPConnection:1', 'GetExternalIPAddress': 'urn:schemas-upnp-org:service:WANIPConnection:1'}, 'unsupported_soap_commands': { 'urn:schemas-upnp-org:service:Layer3Forwarding:1': ['GetDefaultConnectionService', 'SetDefaultConnectionService'], 'urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1': ['GetCommonLinkProperties', 'GetTotalBytesSent', 'GetTotalBytesReceived', 'GetTotalPacketsSent', 'GetTotalPacketsReceived', 'X_GetICSStatistics'], 'urn:schemas-upnp-org:service:WANEthernetLinkConfig:1': ['GetEthernetLinkStatus'], 'urn:schemas-upnp-org:service:WANIPConnection:1': ['SetConnectionType', 'GetConnectionTypeInfo', 'RequestConnection', 'ForceTermination', 'GetStatusInfo', 'GetNATRSIPStatus']}, 'soap_requests': []} client_address = "10.0.0.2" def setUp(self) -> None: self.replies = { ( f"GET {path} HTTP/1.1\r\n" f"Accept-Encoding: gzip\r\n" f"Host: {self.gateway_info['gateway_address']}\r\n" f"Connection: Close\r\n" f"\r\n" ).encode(): xml_bytes.encode() for path, xml_bytes in self.gateway_info['services_xml'].items() } self.replies.update({ ( f"GET /{self.gateway_info['location'].lstrip(self.gateway_info['urlBase'])} HTTP/1.1\r\n" f"Accept-Encoding: gzip\r\n" f"Host: {self.gateway_info['gateway_address']}\r\n" f"Connection: Close\r\n" f"\r\n" ).encode(): self.gateway_info['gateway_xml'].encode() }) super().setUp() async def test_discover_gateway(self): with self.assertRaises(UPnPError) as e1: with mock_tcp_and_udp(self.loop): await Gateway.discover_gateway(self.client_address, self.gateway_info['gateway_address'], 2, loop=self.loop) with self.assertRaises(UPnPError) as e2: with mock_tcp_and_udp(self.loop): await Gateway.discover_gateway(self.client_address, self.gateway_info['gateway_address'], 2, loop=self.loop) self.assertEqual(str(e1.exception), f"M-SEARCH for {self.gateway_info['gateway_address']}:1900 timed out") self.assertEqual(str(e2.exception), f"M-SEARCH for {self.gateway_info['gateway_address']}:1900 timed out") async def test_discover_commands(self): with mock_tcp_and_udp(self.loop, tcp_replies=self.replies): gateway = Gateway( SSDPDatagram("OK", self.gateway_info['reply']), self.client_address, self.gateway_info['gateway_address'], loop=self.loop ) await gateway.discover_commands() self.assertDictEqual(self.gateway_info['registered_soap_commands'], gateway._registered_commands) self.assertDictEqual(gateway.debug_gateway(), self.gateway_info) class TestDiscoverNetgearNighthawkAC2350(TestDiscoverDLinkDIR890L): gateway_info = {'manufacturer_string': 'NETGEAR NETGEAR Nighthawk X4 AC2350 Smart WiFi Router', 'gateway_address': '192.168.0.1', 'server': 'R7500v2 UPnP/1.0 miniupnpd/1.0', 'urlBase': 'http://192.168.0.1:5555', 'location': 'http://192.168.0.1:5555/rootDesc.xml', 'specVersion': {'major': '1', 'minor': '0'}, 'usn': 'uuid:11111111-2222-3333-4444-555555555555::upnp:rootdevice', 'urn': 'upnp:rootdevice', 'gateway_xml': 'HTTP/1.1 200 OK\r\nContent-Type: text/xml; charset="utf-8"\r\nConnection: close\r\nContent-Length: 3720\r\nServer: R7500v2 UPnP/1.0 miniupnpd/1.0\r\nExt: \r\nContent-Language: en-US\r\n\r\n\n10http://192.168.0.1:5555VEN_01f2&DEV_0018&REV_02 VEN_01f2&DEV_8000&SUBSYS_01&REV_01 VEN_01f2&DEV_8000&REV_01 VEN_0033&DEV_0008&REV_01urn:schemas-upnp-org:device:InternetGatewayDevice:1NetworkInfrastructure.RouterNetwork.Router.Wirelessurn:schemas-upnp-org:device:InternetGatewayDevice:1R7500v2 (Gateway)NETGEAR, Inc.http://www.netgear.comNETGEAR R7500v2 NETGEAR Nighthawk X4 AC2350 Smart WiFi RouterNETGEAR Nighthawk X4 AC2350 Smart WiFi RouterR7500v2http://www.netgear.com/home/products/wirelessroutersv1uuid:11111111-2222-3333-4444-555555555555606449084528urn:schemas-upnp-org:service:Layer3Forwarding:1urn:upnp-org:serviceId:L3Forwarding1/ctl/L3Forwarding/evt/L3Forwarding/Layer3F.xmlurn:schemas-upnp-org:device:WANDevice:1WAN DeviceNETGEARhttp://www.netgear.comWAN Device on NETGEAR R7500v2 Wireless RouterNETGEAR Nighthawk X4 AC2350 Smart WiFi RouterR7500v2http://www.netgear.comv1uuid:11111111-2222-3333-4444-5555555555551234567890aburn:schemas-upnp-org:service:WANCommonInterfaceConfig:1urn:upnp-org:serviceId:WANCommonIFC1/ctl/CommonIfCfg/evt/CommonIfCfg/WANCfg.xmlurn:schemas-upnp-org:device:WANConnectionDevice:1WAN Connection DeviceNETGEARhttp://www.netgear.comWANConnectionDevice on NETGEAR R7500v2 Wireless RouterNETGEAR Nighthawk X4 AC2350 Smart WiFi RouterR7500v2http://www.netgear.comv1uuid:4d696e69-444c-164e-9d44-b0b98a4cd3c31234567890aburn:schemas-upnp-org:service:WANEthernetLinkConfig:1urn:upnp-org:serviceId:WANEthLinkC1/ctl/WanEth/evt/WanEth/WanEth.xmlurn:schemas-upnp-org:service:WANIPConnection:1urn:upnp-org:serviceId:WANIPConn1/ctl/IPConn/evt/IPConn/WANIPCn.xmlhttp://www.routerlogin.net', 'services_xml': { '/Layer3F.xml': 'HTTP/1.1 200 OK\r\nContent-Type: text/xml; charset="utf-8"\r\nConnection: close\r\nContent-Length: 794\r\nServer: R7500v2 UPnP/1.0 miniupnpd/1.0\r\nExt: \r\nContent-Language: en-US\r\n\r\n\n10SetDefaultConnectionServiceNewDefaultConnectionServiceinDefaultConnectionServiceGetDefaultConnectionServiceNewDefaultConnectionServiceoutDefaultConnectionServiceDefaultConnectionServicestring', '/WANCfg.xml': 'HTTP/1.1 200 OK\r\nContent-Type: text/xml; charset="utf-8"\r\nConnection: close\r\nContent-Length: 2942\r\nServer: R7500v2 UPnP/1.0 miniupnpd/1.0\r\nExt: \r\nContent-Language: en-US\r\n\r\n\n10GetCommonLinkPropertiesNewWANAccessTypeoutWANAccessTypeNewLayer1UpstreamMaxBitRateoutLayer1UpstreamMaxBitRateNewLayer1DownstreamMaxBitRateoutLayer1DownstreamMaxBitRateNewPhysicalLinkStatusoutPhysicalLinkStatusGetTotalBytesSentNewTotalBytesSentoutTotalBytesSentGetTotalBytesReceivedNewTotalBytesReceivedoutTotalBytesReceivedGetTotalPacketsSentNewTotalPacketsSentoutTotalPacketsSentGetTotalPacketsReceivedNewTotalPacketsReceivedoutTotalPacketsReceivedWANAccessTypestringDSLPOTSCableEthernetLayer1UpstreamMaxBitRateui4Layer1DownstreamMaxBitRateui4PhysicalLinkStatusstringUpDownInitializingUnavailableTotalBytesSentui4TotalBytesReceivedui4TotalPacketsSentui4TotalPacketsReceivedui4', '/WanEth.xml': 'HTTP/1.1 200 OK\r\nContent-Type: text/xml; charset="utf-8"\r\nConnection: close\r\nContent-Length: 711\r\nServer: R7500v2 UPnP/1.0 miniupnpd/1.0\r\nExt: \r\nContent-Language: en-US\r\n\r\n\n10GetEthernetLinkStatusNewEthernetLinkStatusoutEthernetLinkStatusEthernetLinkStatusstringUpDownInitializingUnavailable', '/WANIPCn.xml': 'HTTP/1.1 200 OK\r\nContent-Type: text/xml; charset="utf-8"\r\nConnection: close\r\nContent-Length: 8400\r\nServer: R7500v2 UPnP/1.0 miniupnpd/1.0\r\nExt: \r\nContent-Language: en-US\r\n\r\n\n10AddPortMappingNewRemoteHostinRemoteHostNewExternalPortinExternalPortNewProtocolinPortMappingProtocolNewInternalPortinInternalPortNewInternalClientinInternalClientNewEnabledinPortMappingEnabledNewPortMappingDescriptioninPortMappingDescriptionNewLeaseDurationinPortMappingLeaseDurationGetExternalIPAddressNewExternalIPAddressoutExternalIPAddressDeletePortMappingNewRemoteHostinRemoteHostNewExternalPortinExternalPortNewProtocolinPortMappingProtocolSetConnectionTypeNewConnectionTypeinConnectionTypeGetConnectionTypeInfoNewConnectionTypeoutConnectionTypeNewPossibleConnectionTypesoutPossibleConnectionTypesRequestConnectionForceTerminationGetStatusInfoNewConnectionStatusoutConnectionStatusNewLastConnectionErroroutLastConnectionErrorNewUptimeoutUptimeGetNATRSIPStatusNewRSIPAvailableoutRSIPAvailableNewNATEnabledoutNATEnabledGetGenericPortMappingEntryNewPortMappingIndexinPortMappingNumberOfEntriesNewRemoteHostoutRemoteHostNewExternalPortoutExternalPortNewProtocoloutPortMappingProtocolNewInternalPortoutInternalPortNewInternalClientoutInternalClientNewEnabledoutPortMappingEnabledNewPortMappingDescriptionoutPortMappingDescriptionNewLeaseDurationoutPortMappingLeaseDurationGetSpecificPortMappingEntryNewRemoteHostinRemoteHostNewExternalPortinExternalPortNewProtocolinPortMappingProtocolNewInternalPortoutInternalPortNewInternalClientoutInternalClientNewEnabledoutPortMappingEnabledNewPortMappingDescriptionoutPortMappingDescriptionNewLeaseDurationoutPortMappingLeaseDurationConnectionTypestringPossibleConnectionTypesstringUnconfiguredIP_RoutedIP_BridgedConnectionStatusstringUnconfiguredConnectingConnectedPendingDisconnectDisconnectingDisconnectedUptimeui4LastConnectionErrorstringERROR_NONERSIPAvailablebooleanNATEnabledbooleanExternalIPAddressstringPortMappingNumberOfEntriesui2PortMappingEnabledbooleanPortMappingLeaseDurationui4RemoteHoststringExternalPortui2InternalPortui2PortMappingProtocolstringTCPUDPInternalClientstringPortMappingDescriptionstring'}, 'services': {'/Layer3F.xml': OrderedDict( [('serviceType', 'urn:schemas-upnp-org:service:Layer3Forwarding:1'), ('serviceId', 'urn:upnp-org:serviceId:L3Forwarding1'), ('controlURL', '/ctl/L3Forwarding'), ('eventSubURL', '/evt/L3Forwarding'), ('SCPDURL', '/Layer3F.xml')]), '/WANCfg.xml': OrderedDict( [('serviceType', 'urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1'), ('serviceId', 'urn:upnp-org:serviceId:WANCommonIFC1'), ('controlURL', '/ctl/CommonIfCfg'), ('eventSubURL', '/evt/CommonIfCfg'), ('SCPDURL', '/WANCfg.xml')]), '/WanEth.xml': OrderedDict( [('serviceType', 'urn:schemas-upnp-org:service:WANEthernetLinkConfig:1'), ('serviceId', 'urn:upnp-org:serviceId:WANEthLinkC1'), ('controlURL', '/ctl/WanEth'), ('eventSubURL', '/evt/WanEth'), ('SCPDURL', '/WanEth.xml')]), '/WANIPCn.xml': OrderedDict( [('serviceType', 'urn:schemas-upnp-org:service:WANIPConnection:1'), ('serviceId', 'urn:upnp-org:serviceId:WANIPConn1'), ('controlURL', '/ctl/IPConn'), ('eventSubURL', '/evt/IPConn'), ('SCPDURL', '/WANIPCn.xml')])}, 'reply': OrderedDict( [('CACHE_CONTROL', 'max-age=1800'), ('ST', 'upnp:rootdevice'), ('USN', 'uuid:11111111-2222-3333-4444-555555555555::upnp:rootdevice'), ('Server', 'R7500v2 UPnP/1.0 miniupnpd/1.0'), ('Location', 'http://192.168.0.1:5555/rootDesc.xml')]), 'soap_port': 5555, 'registered_soap_commands': {'AddPortMapping': 'urn:schemas-upnp-org:service:WANIPConnection:1', 'GetExternalIPAddress': 'urn:schemas-upnp-org:service:WANIPConnection:1', 'DeletePortMapping': 'urn:schemas-upnp-org:service:WANIPConnection:1', 'GetGenericPortMappingEntry': 'urn:schemas-upnp-org:service:WANIPConnection:1', 'GetSpecificPortMappingEntry': 'urn:schemas-upnp-org:service:WANIPConnection:1'}, 'unsupported_soap_commands': { 'urn:schemas-upnp-org:service:Layer3Forwarding:1': ['SetDefaultConnectionService', 'GetDefaultConnectionService'], 'urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1': ['GetCommonLinkProperties', 'GetTotalBytesSent', 'GetTotalBytesReceived', 'GetTotalPacketsSent', 'GetTotalPacketsReceived'], 'urn:schemas-upnp-org:service:WANEthernetLinkConfig:1': ['GetEthernetLinkStatus'], 'urn:schemas-upnp-org:service:WANIPConnection:1': ['SetConnectionType', 'GetConnectionTypeInfo', 'RequestConnection', 'ForceTermination', 'GetStatusInfo', 'GetNATRSIPStatus']}, 'soap_requests': []} class TestActiontec(AsyncioTestCase): name = "Actiontec GT784WN" _location_key = 'Location' @property def data_path(self): return os.path.join(os.path.dirname(os.path.abspath(__file__)), "replays", self.name) def _get_location(self): # return self.gateway_info['reply']['Location'].split(self.gateway_address)[-1] return self.gateway_info['reply'][self._location_key].split(f"{self.gateway_address}:{self.gateway_info['soap_port']}")[-1] def setUp(self) -> None: with open(self.data_path, 'r') as f: data = json.loads(f.read()) self.gateway_info = data['gateway'] self.client_address = data['client_address'] self.gateway_address = self.gateway_info['gateway_address'] self.udp_replies = { (SSDPDatagram('M-SEARCH', self.gateway_info['m_search_args']).encode().encode(), ("239.255.255.250", 1900)): SSDPDatagram("OK", self.gateway_info['reply']).encode().encode() } self.tcp_replies = { ( f"GET {path} HTTP/1.1\r\n" f"Accept-Encoding: gzip\r\n" f"Host: {self.gateway_info['gateway_address']}\r\n" f"Connection: Close\r\n" f"\r\n" ).encode(): xml_bytes.encode() for path, xml_bytes in self.gateway_info['service_descriptors'].items() } self.tcp_replies.update({ ( f"GET {self._get_location()} HTTP/1.1\r\n" f"Accept-Encoding: gzip\r\n" f"Host: {self.gateway_info['gateway_address']}\r\n" f"Connection: Close\r\n" f"\r\n" ).encode(): self.gateway_info['gateway_xml'].encode() }) self.registered_soap_commands = self.gateway_info['registered_soap_commands'] super().setUp() async def setup_request_replay(self, u: UPnP): for method, reqs in self.gateway_info['soap_requests'].items(): if not reqs: continue self.tcp_replies.update({ serialize_soap_post( method, list(args.keys()), self.registered_soap_commands[method].encode(), self.gateway_address.encode(), u.gateway.services[self.registered_soap_commands[method]].controlURL.encode() ): response.encode() for args, response in reqs }) async def replay(self, u: UPnP): self.assertEqual('11.222.33.111', await u.get_external_ip()) async def test_replay(self): with mock_tcp_and_udp(self.loop, udp_replies=self.udp_replies, tcp_replies=self.tcp_replies, udp_expected_addr=self.gateway_address, tcp_chunk_size=1450): u = await UPnP.discover(lan_address=self.client_address, gateway_address=self.gateway_address, loop=self.loop) await self.setup_request_replay(u) await self.replay(u) class TestNewMediaNet(TestActiontec): name = "NewMedia-NET GmbH Generic X86" async def replay(self, u: UPnP): self.assertEqual('11.222.33.111', await u.get_external_ip()) await u.get_redirects() # print(await u.get_next_mapping(4567, 'UDP', 'aioupnp test mapping'))