经常用到内网穿透,对UPNP也有所了解,但是具体的报文每次都去抓显然浪费时间。因此记录在下面。
报文是开启BitComet时抓取的,前面的python代码是自己用来获取NOTIFY消息的代码。
连接到组播地址接收NOTIFY消息
import socket
import re
ANY = "0.0.0.0"
DES_IP = "239.255.255.250"
PORT = 1900
# xml_str = b'<?xml version="1.0" encoding="utf-8"?><Probe><Uuid>B2D5D4D2-808C-40F6-87CD-694C05C2B274</Uuid><Types>inquiry</Types></Probe> '
# xml_str = b'<?xml version="1.0" encoding="utf-8"?><Probe><Uuid>CB09F608-E016-4EE8-869A-CA186852F12E</Uuid><Types>inquiry</Types></Probe> '
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)
接收到的NOTIFY报文
NOTIFY * HTTP/1.1
HOST: 239.255.255.250:1900
CACHE-CONTROL: max-age=100
LOCATION: http://192.168.1.1:1900/igd.xml
NT: upnp:rootdevice
NTS: ssdp:alive
SERVER: Mercury Router MR808, UPnP/1.0
USN: uuid:upnp-InternetGatewayDevice-192168115678900001::upnp:rootdevice
NOTIFY * HTTP/1.1
HOST: 239.255.255.250:1900
CACHE-CONTROL: max-age=100
LOCATION: http://192.168.1.1:1900/igd.xml
NT: uuid:upnp-InternetGatewayDevice-192168115678900001
NTS: ssdp:alive
SERVER: Mercury Router MR808, UPnP/1.0
USN: uuid:upnp-InternetGatewayDevice-192168115678900001
NOTIFY * HTTP/1.1
HOST: 239.255.255.250:1900
CACHE-CONTROL: max-age=100
LOCATION: http://192.168.1.1:1900/igd.xml
NT: urn:schemas-upnp-org:device:InternetGatewayDevice:1
NTS: ssdp:alive
SERVER: Mercury Router MR808, UPnP/1.0
USN: uuid:upnp-InternetGatewayDevice-192168115678900001::urn:schemas-upnp-org:device:InternetGatewayDevice:1
NOTIFY * HTTP/1.1
HOST: 239.255.255.250:1900
CACHE-CONTROL: max-age=100
LOCATION: http://192.168.1.1:1900/igd.xml
NT: urn:schemas-upnp-org:service:Layer3Forwarding:1
NTS: ssdp:alive
SERVER: Mercury Router MR808, UPnP/1.0
USN: uuid:upnp-InternetGatewayDevice-192168115678900001::urn:schemas-upnp-org:service:Layer3Forwarding:1
NOTIFY * HTTP/1.1
HOST: 239.255.255.250:1900
CACHE-CONTROL: max-age=100
LOCATION: http://192.168.1.1:1900/igd.xml
NT: uuid:upnp-WANDevice-192168115678900001
NTS: ssdp:alive
SERVER: Mercury Router MR808, UPnP/1.0
USN: uuid:upnp-WANDevice-192168115678900001
NOTIFY * HTTP/1.1
HOST: 239.255.255.250:1900
CACHE-CONTROL: max-age=100
LOCATION: http://192.168.1.1:1900/igd.xml
NT: urn:schemas-upnp-org:device:WANDevice:1
NTS: ssdp:alive
SERVER: Mercury Router MR808, UPnP/1.0
USN: uuid:upnp-WANDevice-192168115678900001::urn:schemas-upnp-org:device:WANDevice:1
NOTIFY * HTTP/1.1
HOST: 239.255.255.250:1900
CACHE-CONTROL: max-age=100
LOCATION: http://192.168.1.1:1900/igd.xml
NT: urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1
NTS: ssdp:alive
SERVER: Mercury Router MR808, UPnP/1.0
USN: uuid:upnp-WANDevice-192168115678900001::urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1
NOTIFY * HTTP/1.1
HOST: 239.255.255.250:1900
CACHE-CONTROL: max-age=100
LOCATION: http://192.168.1.1:1900/igd.xml
NT: uuid:upnp-WANConnectionDevice-192168115678900001
NTS: ssdp:alive
SERVER: Mercury Router MR808, UPnP/1.0
USN: uuid:upnp-WANConnectionDevice-192168115678900001
NOTIFY * HTTP/1.1
HOST: 239.255.255.250:1900
CACHE-CONTROL: max-age=100
LOCATION: http://192.168.1.1:1900/igd.xml
NT: urn:schemas-upnp-org:device:WANConnectionDevice:1
NTS: ssdp:alive
SERVER: Mercury Router MR808, UPnP/1.0
USN: uuid:upnp-WANConnectionDevice-192168115678900001::urn:schemas-upnp-org:device:WANConnectionDevice:1
NOTIFY * HTTP/1.1
HOST: 239.255.255.250:1900
CACHE-CONTROL: max-age=100
LOCATION: http://192.168.1.1:1900/igd.xml
NT: urn:schemas-upnp-org:service:WANIPConnection:1
NTS: ssdp:alive
SERVER: Mercury Router MR808, UPnP/1.0
USN: uuid:upnp-WANConnectionDevice-192168115678900001::urn:schemas-upnp-org:service:WANIPConnection:1
请求igd.xml
GET /igd.xml HTTP/1.1
Cache-Control: no-cache
Connection: Close
Pragma: no-cache
Accept: text/xml, application/xml
Host: 192.168.1.1:1900
User-Agent: Microsoft-Windows/10.0 UPnP/1.0
HTTP/1.1 200 OK
CONTENT-LENGTH: 2746
CONTENT-TYPE: text/xml
DATE: Thu, 07 Jan 2021 02:03:00 GMT
LAST-MODIFIED: Tue, 28 Oct 2003 08:46:08 GMT
SERVER: Mercury Router MR808, UPnP/1.0
CONNECTION: close
<?xml version="1.0"?>
<root xmlns="urn:schemas-upnp-org:device-1-0">
......
</root>
igd.xml的详细内容如下
<?xml version="1.0"?>
<root xmlns="urn:schemas-upnp-org:device-1-0">
<specVersion>
<major>1</major>
<minor>0</minor>
</specVersion>
<URLBase></URLBase>
<device>
<deviceType>urn:schemas-upnp-org:device:InternetGatewayDevice:1</deviceType>
<presentationURL>http://192.168.1.1:80 </presentationURL>
<friendlyName >Mercury Router MR808</friendlyName>
<manufacturer >Mercury</manufacturer>
<manufacturerURL >http://www.mercurycom.com.cn</manufacturerURL>
<modelDescription >MR808 2.0</modelDescription>
<modelName >MR808</modelName>
<modelNumber >2.0</modelNumber>
<UDN>uuid:upnp-InternetGatewayDevice-192168115678900001</UDN>
<UPC>123456789001</UPC>
<serviceList>
<service>
<serviceType>urn:schemas-upnp-org:service:Layer3Forwarding:1</serviceType>
<serviceId>urn:upnp-org:serviceId:L3Forwarding1</serviceId>
<controlURL>/l3f</controlURL>
<eventSubURL>/l3f</eventSubURL>
<SCPDURL>/l3f.xml</SCPDURL>
</service>
</serviceList>
<deviceList>
<device>
<deviceType>urn:schemas-upnp-org:device:WANDevice:1</deviceType>
<friendlyName>WAN Device</friendlyName>
<manufacturer >Mercury</manufacturer>
<manufacturerURL >http://www.mercurycom.com.cn</manufacturerURL>
<modelDescription>WAN Device</modelDescription>
<modelName>WAN Device</modelName>
<modelNumber>1</modelNumber>
<modelURL></modelURL>
<serialNumber>12345678900001</serialNumber>
<UDN>uuid:upnp-WANDevice-192168115678900001</UDN>
<UPC>123456789001</UPC>
<serviceList>
<service>
<serviceType>urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1</serviceType>
<serviceId>urn:upnp-org:serviceId:WANCommonInterfaceConfig</serviceId>
<controlURL>/ifc</controlURL>
<eventSubURL>/ifc</eventSubURL>
<SCPDURL>/ifc.xml</SCPDURL>
</service>
</serviceList>
<deviceList>
<device>
<deviceType>urn:schemas-upnp-org:device:WANConnectionDevice:1</deviceType>
<friendlyName>WAN Connection Device</friendlyName>
<manufacturer >Mercury</manufacturer>
<manufacturerURL >http://www.mercurycom.com.cn</manufacturerURL>
<modelDescription>WAN Connection Device</modelDescription>
<modelName>WAN Connection Device</modelName>
<modelNumber>1</modelNumber>
<modelURL></modelURL>
<serialNumber>12345678900001</serialNumber>
<UDN>uuid:upnp-WANConnectionDevice-192168115678900001</UDN>
<UPC>123456789001</UPC>
<serviceList>
<service>
<serviceType>urn:schemas-upnp-org:service:WANIPConnection:1</serviceType>
<serviceId>urn:upnp-org:serviceId:WANIPConnection</serviceId>
<controlURL>/ipc</controlURL>
<eventSubURL>/ipc</eventSubURL>
<SCPDURL>/ipc.xml</SCPDURL>
</service>
</serviceList>
</device>
</deviceList>
</device>
</deviceList>
</device>
</root>
请求ipc.xml的报文
GET /ipc.xml HTTP/1.1
Cache-Control: no-cache
Connection: Close
Pragma: no-cache
Accept: text/xml, application/xml
User-Agent: Microsoft-Windows/10.0 UPnP/1.0
Host: 192.168.1.1:1900
HTTP/1.1 200 OK
CONTENT-LENGTH: 8689
CONTENT-TYPE: text/xml
DATE: Thu, 07 Jan 2021 02:03:00 GMT
LAST-MODIFIED: Sat, 25 Oct 2003 03:22:56 GMT
SERVER: Mercury Router MR808, UPnP/1.0
CONNECTION: close
<?xml version="1.0"?>
<scpd xmlns="urn:schemas-upnp-org:service-1-0">
......
</scpd>
IPC返回的是以xml方式呈现的接口详情,整理之后如下:
SetConnectionType
SetConnectionType
|--param:NewConnectionType
|--param:NewConnectionType
GetConnectionTypeInfo
GetConnectionTypeInfo
|--param:NewConnectionType
|--param:NewConnectionType
|--param:NewPossibleConnectionTypes
|--param:NewPossibleConnectionTypes
ForceTermination
ForceTermination
RequestConnection
RequestConnection
GetStatusInfo
GetStatusInfo
|--param:NewConnectionStatus
|--param:NewConnectionStatus
|--param:NewLastConnectionError
|--param:NewLastConnectionError
|--param:NewUptime
|--param:NewUptime
GetNATRSIPStatus
GetNATRSIPStatus
|--param:NewRSIPAvailable
|--param:NewRSIPAvailable
|--param:NewNATEnabled
|--param:NewNATEnabled
GetGenericPortMappingEntry
GetGenericPortMappingEntry
|--param:NewPortMappingIndex
|--param:NewPortMappingIndex
|--param:NewRemoteHost
|--param:NewRemoteHost
|--param:NewExternalPort
|--param:NewExternalPort
|--param:NewProtocol
|--param:NewProtocol
|--param:NewInternalPort
|--param:NewInternalPort
|--param:NewInternalClient
|--param:NewInternalClient
|--param:NewEnabled
|--param:NewEnabled
|--param:NewPortMappingDescription
|--param:NewPortMappingDescription
|--param:NewLeaseDuration
|--param:NewLeaseDuration
GetSpecificPortMappingEntry
GetSpecificPortMappingEntry
|--param:NewRemoteHost
|--param:NewRemoteHost
|--param:NewExternalPort
|--param:NewExternalPort
|--param:NewProtocol
|--param:NewProtocol
|--param:NewInternalPort
|--param:NewInternalPort
|--param:NewInternalClient
|--param:NewInternalClient
|--param:NewEnabled
|--param:NewEnabled
|--param:NewPortMappingDescription
|--param:NewPortMappingDescription
|--param:NewLeaseDuration
|--param:NewLeaseDuration
AddPortMapping
AddPortMapping
DeletePortMapping
DeletePortMapping
GetExternalIPAddress
GetExternalIPAddress
|--param:NewExternalIPAddress
|--param:NewExternalIPAddress
ConnectionType
ConnectionType
PossibleConnectionTypes
PossibleConnectionTypes
ConnectionStatus
ConnectionStatus
Uptime
Uptime
LastConnectionError
LastConnectionError
RSIPAvailable
RSIPAvailable
NATEnabled
NATEnabled
ExternalIPAddress
ExternalIPAddress
PortMappingNumberOfEntries
PortMappingNumberOfEntries
PortMappingEnabled
PortMappingEnabled
PortMappingLeaseDuration
PortMappingLeaseDuration
RemoteHost
RemoteHost
ExternalPort
ExternalPort
InternalPort
InternalPort
PortMappingProtocol
PortMappingProtocol
InternalClient
InternalClient
PortMappingDescription
PortMappingDescription
调用ipc的接口报文
POST /ipc HTTP/1.1
Cache-Control: no-cache
Connection: Close
Pragma: no-cache
Content-Type: text/xml; charset="utf-8"
User-Agent: Microsoft-Windows/10.0 UPnP/1.0
SOAPAction: "urn:schemas-upnp-org:service:WANIPConnection:1#AddPortMapping"
Content-Length: 1127
Host: 192.168.1.1:1900
<?xml version="1.0"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><m:AddPortMapping xmlns:m="urn:schemas-upnp-org:service:WANIPConnection:1"><NewRemoteHost xmlns:dt="urn:schemas-microsoft-com:datatypes" dt:dt="string"></NewRemoteHost><NewExternalPort xmlns:dt="urn:schemas-microsoft-com:datatypes" dt:dt="ui2">16849</NewExternalPort><NewProtocol xmlns:dt="urn:schemas-microsoft-com:datatypes" dt:dt="string">UDP</NewProtocol><NewInternalPort xmlns:dt="urn:schemas-microsoft-com:datatypes" dt:dt="ui2">16849</NewInternalPort><NewInternalClient xmlns:dt="urn:schemas-microsoft-com:datatypes" dt:dt="string">192.168.1.100</NewInternalClient><NewEnabled xmlns:dt="urn:schemas-microsoft-com:datatypes" dt:dt="boolean">1</NewEnabled><NewPortMappingDescription xmlns:dt="urn:schemas-microsoft-com:datatypes" dt:dt="string">BitComet UDP</NewPortMappingDescription><NewLeaseDuration xmlns:dt="urn:schemas-microsoft-com:datatypes" dt:dt="ui4">0</NewLeaseDuration></m:AddPortMapping></SOAP-ENV:Body></SOAP-ENV:Envelope>
HTTP/1.1 200 OK
CONNECTION: close
SERVER: Mercury Router MR808, UPnP/1.0
CONTENT-LENGTH: 332
CONTENT-TYPE: text/xml; charset="utf-8"
<?xml version="1.0"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<u:AddPortMappingResponse xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1"></u:AddPortMappingResponse></SOAP-ENV:Body>
</SOAP-ENV:Envelope>
调用的ipc的接口和接口顺序如下
调用ipc接口之后的结果
结论
添加映射的主要操作是POST的方式调用AddPortMapping接口。
显然libtorrent在这之前要先通过M-SEARCH和NOTIFY的UDP报文找到路由器,通过igd找ipc,通过ipc接口操作删除或添加映射。
添加完映射要用GetExternalIPAddress获取外网地址,这样就能把地址传给别人让别人找到你。
参考网址
www.upnp.org已经面目全非了,只能借助weiki的存档才能看见
https://web.archive.org/web/20050708020002/http://www.upnp.org/
https://web.archive.org/web/20051104061236if_/http://www.upnp.org:80/standardizeddcps/upnpresource20050517.zip
upnpresource20050517/documents/UPnP_Vendor_Implementation_Guide_Jan2001.htm
upnpresource20050517/documents/UPnPDA10_20000613.htm
https://github.com/jupnp/jupnp
https://github.com/hubing8658/UPnP-DLNA-Demo