协议-upnp
upnp访问过程
#随笔
udp访问239.255.255.250的1900端口,ssdp协议
import socket
import re
ANY = "0.0.0.0"
DES_IP = "239.255.255.250"
PORT = 1900
xml_str = b'M-SEARCH * HTTP/1.1\r\n' \
\+ b'HOST: 239.255.255.250:1900\r\n' \
\+ b'MAN: "ssdp:discover"\r\n' \
\+ b'MX: 1\r\n' \
\+ b'ST: urn:dial-multiscreen-org:service:dial:1\r\n' \
\+ b'USER-AGENT: Google Chrome/87.0.4280.88 Windows\r\n\r\n\r\n'
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM,socket.IPPROTO_UDP)
s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
s.bind((ANY,PORT))
s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 255)
s.setsockopt(
socket.IPPROTO_IP,
socket.IP_ADD_MEMBERSHIP,
socket.inet_aton(DES_IP) + socket.inet_aton(ANY)
)
s.setblocking(False)
s.sendto(xml_str,(DES_IP,PORT))
while True:
try:
data, address = s.recvfrom(2048)
except Exception as e:
pass
else:
print(address)
print(data)
通过这种方式可以获取到同网下的其他upnp设备信息
('10.0.0.1', 35150)
b'NOTIFY * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nCACHE-CONTROL: max-age=3600\r\nLOCATION: http://10.0.0.1:56688/rootDesc.xml\r\nSERVER: OpenWRT/OpenWrt UPnP/1.1 MiniUPnPd/2.0\r\nNT: upnp:rootdevice\r\nUSN: uuid:97fd7581-d522-415d-bfae-a51ac69e4b55::upnp:rootdevice\r\nNTS: ssdp:alive\r\nOPT: "http://schemas.upnp.org/upnp/1/0/"; ns=01\r\n01-NLS: 1693189369\r\nBOOTID.UPNP.ORG: 1693189369\r\nCONFIGID.UPNP.ORG: 1337\r\n\r\n'
('10.0.0.1', 60956)
b'NOTIFY * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nCACHE-CONTROL: max-age=1801\r\nNTS: ssdp:alive\r\nLOCATION: http://10.0.0.1:49153/wps_device.xml\r\nSERVER: Unspecified, UPnP/1.0, Unspecified\r\nNT: urn:schemas-wifialliance-org:service:WFAWLANConfig:1\r\nUSN: uuid:dd20a05f-a846-47cf-b976-047083022a1d::urn:schemas-wifialliance-org:service:WFAWLANConfig:1\r\n\r\n'
现在是以10.0.0.1做演示
信息中能发现LOCATION
http://10.0.0.1:49153/wps_device.xml
http://10.0.0.1:56688/rootDesc.xml
rootDesc.xml文件
This XML file does not appear to have any style information associated with it. The document tree is shown below.
<root xmlns="urn:schemas-upnp-org:device-1-0" configId="1337">
<specVersion>
<major>1</major>
<minor>1</minor>
</specVersion>
<device>
<deviceType>urn:schemas-upnp-org:device:InternetGatewayDevice:1</deviceType>
<friendlyName>RAX40 (Gateway)</friendlyName>
<manufacturer>Netgear, Inc.</manufacturer>
<manufacturerURL>http://www.NETGEAR.com</manufacturerURL>
<modelDescription>OpenWRT router</modelDescription>
<modelName>RAX40</modelName>
<modelNumber>RAX40</modelNumber>
<modelURL>http://www.netgear.com/home</modelURL>
<serialNumber>5UP299WPA0C55</serialNumber>
<UDN>uuid:97fd7581-d522-415d-bfae-a51ac69e4b55</UDN>
<serviceList>
<service>
<serviceType>urn:schemas-upnp-org:service:Layer3Forwarding:1</serviceType>
<serviceId>urn:upnp-org:serviceId:L3Forwarding1</serviceId>
<SCPDURL>/L3F.xml</SCPDURL>
<controlURL>/ctl/L3F</controlURL>
<eventSubURL>/evt/L3F</eventSubURL>
</service>
</serviceList>
<deviceList>
<device>
<deviceType>urn:schemas-upnp-org:device:WANDevice:1</deviceType>
<friendlyName>WANDevice</friendlyName>
<manufacturer>MiniUPnP</manufacturer>
<manufacturerURL>http://miniupnp.free.fr/</manufacturerURL>
<modelDescription>WAN Device</modelDescription>
<modelName>WAN Device</modelName>
<modelNumber>20220318</modelNumber>
<modelURL>http://miniupnp.free.fr/</modelURL>
<serialNumber>5UP299WPA0C55</serialNumber>
<UDN>uuid:97fd7581-d522-415d-bfae-a51ac69e4b56</UDN>
<UPC>000000000000</UPC>
<serviceList>
<service>
<serviceType>urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1</serviceType>
<serviceId>urn:upnp-org:serviceId:WANCommonIFC1</serviceId>
<SCPDURL>/WANCfg.xml</SCPDURL>
<controlURL>/ctl/CmnIfCfg</controlURL>
<eventSubURL>/evt/CmnIfCfg</eventSubURL>
</service>
</serviceList>
<deviceList>
<device>
<deviceType>urn:schemas-upnp-org:device:WANConnectionDevice:1</deviceType>
<friendlyName>WANConnectionDevice</friendlyName>
<manufacturer>MiniUPnP</manufacturer>
<manufacturerURL>http://miniupnp.free.fr/</manufacturerURL>
<modelDescription>MiniUPnP daemon</modelDescription>
<modelName>MiniUPnPd</modelName>
<modelNumber>20220318</modelNumber>
<modelURL>http://miniupnp.free.fr/</modelURL>
<serialNumber>5UP299WPA0C55</serialNumber>
<UDN>uuid:97fd7581-d522-415d-bfae-a51ac69e4b57</UDN>
<UPC>000000000000</UPC>
<serviceList>
<service>
<serviceType>urn:schemas-upnp-org:service:WANIPConnection:1</serviceType>
<serviceId>urn:upnp-org:serviceId:WANIPConn1</serviceId>
<SCPDURL>/WANIPCn.xml</SCPDURL>
<controlURL>/ctl/IPConn</controlURL>
<eventSubURL>/evt/IPConn</eventSubURL>
</service>
</serviceList>
</device>
</deviceList>
</device>
</deviceList>
<presentationURL>http://www.routerlogin.net</presentationURL>
</device>
</root>
其中可以获取设备名称制造商各种服务等信息
L3Forwarding1
<service>
<serviceType>urn:schemas-upnp-org:service:Layer3Forwarding:1</serviceType>
<serviceId>urn:upnp-org:serviceId:L3Forwarding1</serviceId>
<SCPDURL>/L3F.xml</SCPDURL>
<controlURL>/ctl/L3F</controlURL>
<eventSubURL>/evt/L3F</eventSubURL>
</service>
WANCommonIFC1
<service>
<serviceType>urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1</serviceType>
<serviceId>urn:upnp-org:serviceId:WANCommonIFC1</serviceId>
<SCPDURL>/WANCfg.xml</SCPDURL>
<controlURL>/ctl/CmnIfCfg</controlURL>
<eventSubURL>/evt/CmnIfCfg</eventSubURL>
</service>
WANIPConn1
<service>
<serviceType>urn:schemas-upnp-org:service:WANIPConnection:1</serviceType>
<serviceId>urn:upnp-org:serviceId:WANIPConn1</serviceId>
<SCPDURL>/WANIPCn.xml</SCPDURL>
<controlURL>/ctl/IPConn</controlURL>
<eventSubURL>/evt/IPConn</eventSubURL>
</service>
通过访问SCPDURL可以获取服务的具体行为,以WANIPConn1为例
访问http://10.0.0.1:56688/WANIPCn.xml
This XML file does not appear to have any style information associated with it. The document tree is
shown below.
<scpd xmlns="urn:schemas-upnp-org:service-1-0">
<specVersion>
<major>1</major>
<minor>1</minor>
</specVersion>
<actionList>
<action>
<name>SetConnectionType</name>
<argumentList>
<argument>
<name>NewConnectionType</name>
<direction>in</direction>
<relatedStateVariable>ConnectionType</relatedStateVariable>
</argument>
</argumentList>
</action>
<action>
<name>GetConnectionTypeInfo</name>
<argumentList>
<argument>
<name>NewConnectionType</name>
<direction>out</direction>
<relatedStateVariable>ConnectionType</relatedStateVariable>
</argument>
<argument>
<name>NewPossibleConnectionTypes</name>
<direction>out</direction>
<relatedStateVariable>PossibleConnectionTypes</relatedStateVariable>
</argument>
</argumentList>
</action>
<action>
<name>RequestConnection</name>
</action>
<action>
<name>ForceTermination</name>
</action>
<action>
<name>GetStatusInfo</name>
<argumentList>
<argument>
<name>NewConnectionStatus</name>
<direction>out</direction>
<relatedStateVariable>ConnectionStatus</relatedStateVariable>
</argument>
<argument>
<name>NewLastConnectionError</name>
<direction>out</direction>
<relatedStateVariable>LastConnectionError</relatedStateVariable>
</argument>
<argument>
<name>NewUptime</name>
<direction>out</direction>
<relatedStateVariable>Uptime</relatedStateVariable>
</argument>
</argumentList>
</action>
<action>
<name>GetNATRSIPStatus</name>
<argumentList>
<argument>
<name>NewRSIPAvailable</name>
<direction>out</direction>
<relatedStateVariable>RSIPAvailable</relatedStateVariable>
</argument>
<argument>
<name>NewNATEnabled</name>
<direction>out</direction>
<relatedStateVariable>NATEnabled</relatedStateVariable>
</argument>
</argumentList>
</action>
<action>
<name>GetGenericPortMappingEntry</name>
<argumentList>
<argument>
<name>NewPortMappingIndex</name>
<direction>in</direction>
<relatedStateVariable>PortMappingNumberOfEntries</relatedStateVariable>
</argument>
<argument>
<name>NewRemoteHost</name>
<direction>out</direction>
<relatedStateVariable>RemoteHost</relatedStateVariable>
</argument>
<argument>
<name>NewExternalPort</name>
<direction>out</direction>
<relatedStateVariable>ExternalPort</relatedStateVariable>
</argument>
<argument>
<name>NewProtocol</name>
<direction>out</direction>
<relatedStateVariable>PortMappingProtocol</relatedStateVariable>
</argument>
<argument>
<name>NewInternalPort</name>
<direction>out</direction>
<relatedStateVariable>InternalPort</relatedStateVariable>
</argument>
<argument>
<name>NewInternalClient</name>
<direction>out</direction>
<relatedStateVariable>InternalClient</relatedStateVariable>
</argument>
<argument>
<name>NewEnabled</name>
<direction>out</direction>
<relatedStateVariable>PortMappingEnabled</relatedStateVariable>
</argument
<argument>
<name>NewPortMappingDescription</name>
<direction>out</direction>
<relatedStateVariable>PortMappingDescription</relatedStateVariable>
</argument>
<argument>
<name>NewLeaseDuration</name>
<direction>out</direction>
<relatedStateVariable>PortMappingLeaseDuration</relatedStateVariable>
</argument>
</argumentList>
</action>
<action>
<name>GetSpecificPortMappingEntry</name>
<argumentList>
<argument>
<name>NewRemoteHost</name>
<direction>in</direction
<relatedStateVariable>RemoteHost</relatedStateVariable>
</argument>
<argument>
<name>NewExternalPort</name>
<direction>in</direction>
<relatedStateVariable>ExternalPort</relatedStateVariable>
</argument>
<argument>
<name>NewProtocol</name>
<direction>in</direction>
<relatedStateVariable>PortMappingProtocol</relatedStateVariable>
</argument>
<argument>
<name>NewInternalPort</name>
<direction>out</direction>
<relatedStateVariable>InternalPort</relatedStateVariable>
</argument>
<argument>
<name>NewInternalClient</name>
<direction>out</direction>
<relatedStateVariable>InternalClient</relatedStateVariable>
</argument>
<argument>
<name>NewEnabled</name>
<direction>out</direction>
<relatedStateVariable>PortMappingEnabled</relatedStateVariable>
</argument>
<argument>
<name>NewPortMappingDescription</name>
<direction>out</direction>
<relatedStateVariable>PortMappingDescription</relatedStateVariable>
</argument>
<argument>
<name>NewLeaseDuration</name>
<direction>out</direction>
<relatedStateVariable>PortMappingLeaseDuration</relatedStateVariable>
</argument>
</argumentList>
</action>
<action>
<name>AddPortMapping</name>
<argumentList>
<argument>
<name>NewRemoteHost</name>
<direction>in</direction>
<relatedStateVariable>RemoteHost</relatedStateVariable>
</argument>
<argument>
<name>NewExternalPort</name>
<direction>in</direction>
<relatedStateVariable>ExternalPort</relatedStateVariable>
</argument>
<argument>
<name>NewProtocol</name>
<direction>in</direction>
<relatedStateVariable>PortMappingProtocol</relatedStateVariable>
</argument>
<argument>
<name>NewInternalPort</name>
<direction>in</direction>
<relatedStateVariable>InternalPort</relatedStateVariable>
</argument>
<argument>
<name>NewInternalClient</name>
<direction>in</direction>
<relatedStateVariable>InternalClient</relatedStateVariable>
</argument>
<argument>
<name>NewEnabled</name>
<direction>in</direction>
<relatedStateVariable>PortMappingEnabled</relatedStateVariable>
</argument>
<argument>
<name>NewPortMappingDescription</name>
<direction>in</direction>
<relatedStateVariable>PortMappingDescription</relatedStateVariable>
</argument>
<argument>
<name>NewLeaseDuration</name>
<direction>in</direction>
<relatedStateVariable>PortMappingLeaseDuration</relatedStateVariable>
</argument>
</argumentList>
</action>
<action>
<name>DeletePortMapping</name>
<argumentList>
<argument>
<name>NewRemoteHost</name>
<direction>in</direction>
<relatedStateVariable>RemoteHost</relatedStateVariable>
</argument>
<argument>
<name>NewExternalPort</name>
<direction>in</direction>
<relatedStateVariable>ExternalPort</relatedStateVariable>
</argument>
<argument>
<name>NewProtocol</name>
<direction>in</direction>
<relatedStateVariable>PortMappingProtocol</relatedStateVariable>
</argument>
</argumentList>
</action>
<action>
<name>GetExternalIPAddress</name>
<argumentList>
<argument>
<name>NewExternalIPAddress</name>
<direction>out</direction>
<relatedStateVariable>ExternalIPAddress</relatedStateVariable>
</argument>
</argumentList>
</action>
</actionList>
<serviceStateTable>
<stateVariable sendEvents="no">
<name>ConnectionType</name>
<dataType>string</dataType>
<defaultValue>IP_Routed</defaultValue>
</stateVariable>
<stateVariable sendEvents="yes"
<name>PossibleConnectionTypes</name>
<dataType>string</dataType>
<allowedValueList>
<allowedValue>Unconfigured</allowedValue>
<allowedValue>IP_Routed</allowedValue>
<allowedValue>IP_Bridged</allowedValue>
</allowedValueList>
</stateVariable>
<stateVariable sendEvents="yes">
<name>ConnectionStatus</name>
<dataType>string</dataType>
<defaultValue>Unconfigured</defaultValue>
<allowedValueList>
<allowedValue>Unconfigured</allowedValue>
<allowedValue>Connecting</allowedValue>
<allowedValue>Connected</allowedValue>
<allowedValue>PendingDisconnect</allowedValue>
<allowedValue>Disconnecting</allowedValue>
<allowedValue>Disconnected</allowedValue>
</allowedValueList>
</stateVariable>
<stateVariable sendEvents="no">
<name>Uptime</name>
<dataType>ui4</dataType>
</stateVariable>
<stateVariable sendEvents="no">
<name>LastConnectionError</name>
<dataType>string</dataType>
<defaultValue>ERROR_NONE</defaultValue>
<allowedValueList>
<allowedValue>ERROR_NONE</allowedValue>
</allowedValueList>
</stateVariable>
<stateVariable sendEvents="no">
<name>RSIPAvailable</name>
<dataType>boolean</dataType>
<defaultValue>0</defaultValue>
</stateVariable>
<stateVariable sendEvents="no">
<name>NATEnabled</name>
<dataType>boolean</dataType>
<defaultValue>1</defaultValue>
</stateVariable>
<stateVariable sendEvents="yes">
<name>ExternalIPAddress</name>
<dataType>string</dataType>
</stateVariable>
<stateVariable sendEvents="yes">
<name>PortMappingNumberOfEntries</name>
<dataType>ui2</dataType>
</stateVariable>
<stateVariable sendEvents="no">
<name>PortMappingEnabled</name>
<dataType>boolean</dataType>
</stateVariable>
<stateVariable sendEvents="no">
<name>PortMappingLeaseDuration</name>
<dataType>ui4</dataType>
<defaultValue>3600</defaultValue>
<allowedValueRange>
<minimum>0</minimum>
<maximum>604800</maximum>
</allowedValueRange>
</stateVariable>
<stateVariable sendEvents="no">
<name>RemoteHost</name>
<dataType>string</dataType>
</stateVariable>
<stateVariable sendEvents="no">
<name>ExternalPort</name>
<dataType>ui2</dataType>
</stateVariable>
<stateVariable sendEvents="no">
<name>InternalPort</name>
<dataType>ui2</dataType>
<allowedValueRange>
<minimum>1</minimum>
<maximum>65535</maximum>
</allowedValueRange>
</stateVariable>
<stateVariable sendEvents="no">
<name>PortMappingProtocol</name>
<dataType>string</dataType>
<allowedValueList>
<allowedValue>TCP</allowedValue>
<allowedValue>UDP</allowedValue>
</allowedValueList>
</stateVariable>
<stateVariable sendEvents="no">
<name>InternalClient</name>
<dataType>string</dataType>
</stateVariable>
<stateVariable sendEvents="no">
<name>PortMappingDescription</name>
<dataType>string</dataType>
</stateVariable>
</serviceStateTable>
</scpd>
分类统计有以下几种:
SetConnectionType,GetConnectionTypeInfo,RequestConnection,ForceTermination,GetStatusInfo,GetNATRSIPStatus,GetGenericPortMappingEntry,GetSpecificPortMappingEntry,AddPortMapping,DeletePortMapping,GetExternalIPAddress
通过构造POST请求,访问controlURL:http://10.0.0.1:56688/ctl/IPConn
POST /ctl/IPConn HTTP/1.1
Host: 10.0.0.1:56688
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 Edg/116.0.1938.62
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
SOAPAction: "urn:schemas-upnp-org:service:WANIPConnection:1#GetExternalIPAddress"
Connection: close
Content-Length: 260
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:GetExternalIPAddress xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1">
</u:GetExternalIPAddress>
</s:Body>
</s:Envelope>
重要的有head中的SOAPAction,构造方式为serviceType#action即:urn:schemas-upnp-org:service:WANIPConnection:1#GetExternalIPAddress
post参数来源action中的direction为in的参数,如果只有out参数,即可不用构造post参数,直接获取。
in参数的数据类型在serviceStateTable中可以获取
POST /ctl/IPConn HTTP/1.1
Accept-Encoding: identity
User-Agent: Python-urllib/3.11
Host: 10.0.0.1:56688
Content-Length: 358
Content-Type: text/xml; charset="utf-8"
Soapaction: "urn:schemas-upnp-org:service:WANIPConnection:1#DeletePortMapping"
Connection: close
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:DeletePortMapping xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1">
<NewRemoteHost>AAAA</NewRemoteHost>
<NewExternalPort>AAAA</NewExternalPort>
<NewProtocol>TCP</NewProtocol>
</u:DeletePortMapping>
</s:Body>
</s:Envelope>
通过gdb调试可以发现,可以获取到
python中又个upnpy库,可以很方便的执行上述步骤。
python3 -m pip install upnpy
使用方式
import upnpy
\#获取upnp
upnp = upnpy.UPnP()
\#扫描,返回一个设备列表
devices = upnp.discover()
\#确定设备,两种方式都可以
devide = devices[0]
device = upnp.get_igd()
\#获取服务列表
services = device.get_services()
\#确定服务,同两种方式均可
service = services[0]
service = device['WANPPPConnection.1'] #service id
\#获取服务的actions,返回一个action列表
service.get_actions()
\#通过service.action['name']()可以执行
service.GetExternalIPAddress() #{'NewExternalIPAddress': '10.100.40.182'}
\#通过service.action['name'].get_input_arguments()可以获取参数
service.DeletePortMapping.get_input_arguments()
\#[{'name': 'NewRemoteHost', 'data_type': 'string', 'allowed_value_list': []}, {'name': 'NewExternalPort', 'data_type': 'ui2', 'allowed_value_list': []}, {'name': 'NewProtocol', 'data_type': 'string', 'allowed_value_list': ['TCP', 'UDP']}]
\#发送服务
service.AddPortMapping(
NewRemoteHost='',
NewExternalPort=80,
NewProtocol='TCP',
NewInternalPort=8000,
NewInternalClient='192.168.1.3',
NewEnabled=1,
NewPortMappingDescription='Test port mapping entry from UPnPy.',
NewLeaseDuration=0
)