I played with UPnP lately, and think it may be worth to share the experiences.
The wikipedia entry is pretty general, and does not cover the large scale of problems, apart from missing authentication and a lack of standard for the HTTPMU protocoll.
I'll focus on a specific use of UPnP, a hardware router from linksys (WRT54GS) with UPnP enabled, this is a 'servicepoint', and a controllpoint, a nepenthes module which will add portforwarding rules on the gateway using upnp.
So what happens on the wire, the servicepoint has the address 192.168.1.1, the controlpoint 192.168.3.1 (I refomatted the messages)
The servicepoint sends a a bunch of udp multicasts to its subnet.
UDP 192.168.1.1:1900 → 239.255.255.0:1900
NOTIFY * HTTP/1.1
HOST: 239.255.255.250:1900
CACHE-CONTROL: max-age=180
Location: http:/ /192.168.1.1:5431/dyndev/uuid:00 13-1007-eefc0000eddc
NT: urn:schemas-upnp-org:service:WANPPPConnection:
NTS: ssdp:alive
SERVER: LINUX/2.4 UPnP/1.0 BRCM400/1.0
USN: uuid:0013-1007-eefc0200eddc::urn:schemas-upnp-org:service:WANPPPConnection:1
This kind of message is called HTTPMU and is not standarized, the ietf draft expired in 2001.
The control point searches for service points which offer the service he can control.
UDP 192.168.1.3:38246 → 239.255.255.0:1900
M-SEARCH * HTTP/1.1
HOST: 239.255.255.250:1900
MAN: "ssdp: discover"
MX: 5
ST: urn:schema s-upnp-org:device:InternetGatewayDevice:1
The servicepoint answers, and offers a URL where the control point can download a service description.
UDP 192.168.1.1:1900 → 192.168.1.3:38246
HTTP/1.1 200 OK
ST: urn:sche mas-upnp-org:device:InternetGatewayDevice:1
USN :uuid:0013-1007-eefc0000eddc::urn:schemas-upnp-org:device:Intern etGatewayDevice:1
Location: http://192.168.1.1:5431/dyndev/uuid:0013-1007-eefc0000eddc
Server: Custom/1.0 UPnP /1.0 Proc/Ver
EXT:
Cache-Control:max-age=180
DATE: Sun, 02 Ju l 2006 04:55:30 GMT
the servicepoints service description contains the required informations which subservices the service offers, as well as which url to use to controll them.
Please note the http protocol, as well as the xml format
GET /dyndev/uuid:0013-1007-eefc0000eddc HTTP/1.1
HOST: 192.168.1.1:5431
DATE: Sun, 02 Jul 2006 11:56:29 GMT
CONNECTION: close
USER-AGENT: Linux/2.6.14.4, UPnP/1.0, Portable SDK for UPnP devices/1.4.0
HTTP/1.0 200 OK
SERVER: LINUX/2.4 UPnP/1.0 BRCM400/1.0
DATE: Sun, 02 Jul 2006 04:55:30 GMT
CONTENT-TYPE: application/octet-stream
Cache-Control: max-age=1
PRAGMA: no-cache
Connection: Close
<?xml version="1.0"?>
<root xmlns="urn:schemas-upnp-org:device-1-0">
<specVersion>
<major>1</major>
<minor>0</minor>
</specVersion>
<device>
<deviceType>urn:schemas-upnp-org:device:InternetGatewayDevice:1</deviceType>
<friendlyName>Residential Gateway Device</friendlyName>
<manufacturer>Linksys Inc.</manufacturer>
<manufacturerURL>http://www.linksys.com/</manufacturerURL>
<modelDescription>Internet Access Server</modelDescription>
<modelName>WRT54GS</modelName>
<modelNumber>v4.71.0</modelNumber>
<modelURL>http://www.linksys.com/</modelURL>
<UDN>uuid:0013-1007-eefc0000eddc</UDN>
<serviceList>
<service>
<serviceType>urn:schemas-upnp-org:service:Layer3Forwarding:1</serviceType>
<serviceId>urn:upnp-org:serviceId:Layer3Forwarding:11</serviceId>
<controlURL>/uuid:0013-1007-eefc0000eddc/Layer3Forwarding:1</controlURL>
<eventSubURL>/uuid:0013-1007-eefc0000eddc/Layer3Forwarding:1</eventSubURL>
<SCPDURL>/dynsvc/Layer3Forwarding:1.xml</SCPDURL>
</service>
</serviceList>
<deviceList>
<device>
<deviceType>urn:schemas-upnp-org:device:WANDevice:1</deviceType>
<friendlyName>urn:schemas-upnp-org:device:WANDevice:1</friendlyName>
<manufacturer>Linksys Inc.</manufacturer>
<manufacturerURL>http://www.linksys.com/</manufacturerURL>
<modelDescription>Internet Access Server</modelDescription>
<modelName>WRT54GS</modelName>
<modelNumber>v4.71.0</modelNumber>
<modelURL>http://www.linksys.com/</modelURL>
<UDN>uuid:0013-1007-eefc0100eddc</UDN>
<serviceList>
<service>
<serviceType>urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1</serviceType>
<serviceId>urn:upnp-org:serviceId:WANCommonIFC1</serviceId>
<controlURL>/uuid:0013-1007-eefc0100eddc/WANCommonInterfaceConfig:1</controlURL>
<eventSubURL>/uuid:0013-1007-eefc0100eddc/WANCommonInterfaceConfig:1</eventSubURL>
<SCPDURL>/dynsvc/WANCommonInterfaceConfig:1.xml</SCPDURL>
</service>
</serviceList>
<deviceList>
<device>
<deviceType>urn:schemas-upnp-org:device:WANConnectionDevice:1</deviceType>
<friendlyName>urn:schemas-upnp-org:device:WANConnectionDevice:1</friendlyName>
<manufacturer>Linksys Inc.</manufacturer>
<manufacturerURL>http://www.linksys.com/</manufacturerURL>
<modelDescription>Internet Access Server</modelDescription>
<modelName>WRT54GS</modelName>
<modelNumber>v4.71.0</modelNumber>
<modelURL>http://www.linksys.com/</modelURL>
<UDN>uuid:0013-1007-eefc0200eddc</UDN>
<serviceList>
<service>
<serviceType>urn:schemas-upnp-org:service:WANIPConnection:1</serviceType>
<serviceId>urn:upnp-org:serviceId:WANIPConn1</serviceId>
<controlURL>/uuid:0013-1007-eefc0200eddc/WANIPConnection:1</controlURL>
<eventSubURL>/uuid:0013-1007-eefc0200eddc/WANIPConnection:1</eventSubURL>
<SCPDURL>/dynsvc/WANIPConnection:1.xml</SCPDURL>
</service>
<service>
<serviceType>urn:schemas-upnp-org:service:WANPPPConnection:1</serviceType>
<serviceId>urn:upnp-org:serviceId:WANPPPConn1</serviceId>
<controlURL>/uuid:0013-1007-eefc0200eddc/WANPPPConnection:1</controlURL>
<eventSubURL>/uuid:0013-1007-eefc0200eddc/WANPPPConnection:1</eventSubURL>
<SCPDURL>/dynsvc/WANPPPConnection:1.xml</SCPDURL>
</service>
</serviceList>
</device>
</deviceList>
</device>
</deviceList>
</device>
</root>
TCP 192.168.3.1: → 192.168.1.1:5431
When subscribing to a subservice, the controll point has to provide a callback url, where the service point can post http messages in the G Event Notification Architecture (which is based upon xml).
Please note that this means, your controlpoint runs a http server too, which allows the servicepoint to send you GENA messages
SUBSCRIBE /uuid:0013-1007-eefc0100eddc/WANCommonInterfaceConfig:1 HTTP/1.1
HOST: 192.168.1.1:5431
CALLBACK: <http://192.168.1.3:49152/>
NT: upnp:event
TIMEOUT: Second-1801
HTTP/1.1 200 OK
Server: LINUX/2.4 UPnP/1.0 BRCM400/1.0
SID: uuid:0013-1007-eefc03f0a4b3
TIMEOUT: Second-1801
SUBSCRIBE /uuid:0013-1007-eefc0000eddc/Layer3Forwarding:1 HTTP/1.1
HOST: 192.168.1.1:5431
CALLBACK: <http://192.168.1.3:49152/>
NT: upnp:event
TIMEOUT: Second-1801
HTTP/1.1 200 OK
Server: LINUX/2.4 UPnP/1.0 BRCM400/1.0
SID: uuid:0013-1007-eefc04f09cab
TIMEOUT: Second-1801
SUBSCRIBE /uuid:0013-1007-eefc0200eddc/WANIPConnection:1 HTTP/1.1
HOST: 192.168.1.1:5431
CALLBACK: <http://192.168.1.3:49152/>
NT: upnp:event
TIMEOUT: Second-0
HTTP/1.1 200 OK
Server: LINUX/2.4 UPnP/1.0 BRCM400/1.0
SID: uuid:0013-1007-eefc05f09ba7
TIMEOUT: Second-0
SUBSCRIBE /uuid:0013-1007-eefc0200eddc/WANPPPConnection:1 HTTP/1.1
HOST: 192.168.1.1:5431
CALLBACK: <http://192.168.1.3:49152/>
NT: upnp:event
TIMEOUT: Second-0
HTTP/1.1 200 OK
Server: LINUX/2.4 UPnP/1.0 BRCM400/1.0
SID: uuid:0013-1007-eefc06f09ca8
TIMEOUT: Second-0
Please make sure to notice the service point POSTS these messages to a webserver on our controll point.
Please note this is SOAP formatted
TCP 192.168.1.1:any → 192.168.1.3:49152
NOTIFY / HTTP/1.1
HOST: 192.168.1.3:49152
CONTENT-TYPE: text/xml
CONTENT-LENGTH: 153
NT: upnp:event
NTS: upnp:propchange
SID: uuid:0013-1007-eefc04f09cab
SEQ: 0
<e:propertyset xmlns:e="urn:schemas-upnp-org:event-1-0">
<e:property>
<DefaultConnectionService></DefaultConnectionService>
</e:property>
</e:propertyset>
HTTP/1.1 200 OK
SERVER: Linux/2.6.14.4, UPnP/1.0, Portable SDK for UPnP devices/1.4.0
CONNECTION: close
CONTENT-LENGTH: 41
CONTENT-TYPE: text/html
<html>
<body>
<h1>200 OK</h1>
</body>
</html>
NOTIFY / HTTP/1.1
HOST: 192.168.1.3:49152
CONTENT-TYPE: text/xml
CONTENT-LENGTH: 211
NT: upnp:event
NTS: upnp:propchange
SID: uuid:0013-1007-eefc03f0a4b3
SEQ: 0
<e:propertyset xmlns:e="urn:schemas-upnp-org:event-1-0">
<e:property>
<PhysicalLinkStatus>Up</PhysicalLinkStatus>
</e:property>
<e:property>
<EnabledForInternet>1</EnabledForInternet>
</e:property>
</e:propertyset>
HTTP/1.1 200 OK
SERVER: Linux/2.6.14.4, UPnP/1.0, Portable SDK for UPnP devices/1.4.0
CONNECTION: close
CONTENT-LENGTH: 41
CONTENT-TYPE: text/html
<html>
<body>
<h1>200 OK</h1>
</body>
</html>
NOTIFY / HTTP/1.1
HOST: 192.168.1.3:49152
CONTENT-TYPE: text/xml
CONTENT-LENGTH: 420
NT: upnp:event
NTS: upnp:propchange
SID: uuid:0013-1007-eefc08f09baa
SEQ: 0
<e:propertyset xmlns:e="urn:schemas-upnp-org:event-1-0">
<e:property>
<PossibleConnectionTypes>Unconfigured,IP_Routed,IP_Bridged</PossibleConnectionTypes>
</e:property>
<e:property>
<ConnectionStatus>Connected</ConnectionStatus>
</e:property>
<e:property>
<ExternalIPAddress>192.168.53.223</ExternalIPAddress>
</e:property>
<e:property>
<PortMappingNumberOfEntries>18</PortMappingNumberOfEntries>
</e:property>
</e:propertyset>
HTTP/1.1 200 OK
SERVER: Linux/2.6.14.4, UPnP/1.0, Portable SDK for UPnP devices/1.4.0
CONNECTION: close
CONTENT-LENGTH: 41
CONTENT-TYPE: text/html
<html>
<body>
<h1>200 OK</h1>
</body>
</html>
NOTIFY / HTTP/1.1
HOST: 192.168.1.3:49152
CONTENT-TYPE: text/xml
CONTENT-LENGTH: 420
NT: upnp:event
NTS: upnp:propchange
SID: uuid:0013-1007-eefc05f09ba7
SEQ: 0
<e:propertyset xmlns:e="urn:schemas-upnp-org:event-1-0">
<e:property>
<PossibleConnectionTypes>Unconfigured,IP_Routed,IP_Bridged</PossibleConnectionTypes>
</e:property>
<e:property>
<ConnectionStatus>Connected</ConnectionStatus>
</e:property>
<e:property>
<ExternalIPAddress>192.168.53.223</ExternalIPAddress>
</e:property>
<e:property>
<PortMappingNumberOfEntries>18</PortMappingNumberOfEntries>
</e:property>
</e:propertyset>
HTTP/1.1 412 Precondition Failed
SERVER: Linux/2.6.14.4, UPnP/1.0, Portable SDK for UPnP devices/1.4.0
CONNECTION: close
CONTENT-LENGTH: 58
CONTENT-TYPE: text/html
<html>
<body>
<h1>412 Precondition Failed</h1>
</body>
</html>
NOTIFY / HTTP/1.1
HOST: 192.168.1.3:49152
CONTENT-TYPE: text/xml
CONTENT-LENGTH: 470
NT: upnp:event
NTS: upnp:propchange
SID: uuid:0013-1007-eefc07f09cab
SEQ: 0
<e:propertyset xmlns:e="urn:schemas-upnp-org:event-1-0">
<e:property>
<PossibleConnectionTypes>Unconfigured,IP_Routed,DHCP_Spoofed,PPPOE_Bridged,PPTP_Relay,L2TP_Relay,PPOE_Relay</PossibleConnectionTypes>
</e:property>
<e:property>
<ConnectionStatus>Unconfigured</ConnectionStatus>
</e:property>
<e:property>
<ExternalIPAddress>192.168.53.223</ExternalIPAddress>
</e:property>
<e:property>
<PortMappingNumberOfEntries></PortMappingNumberOfEntries>
</e:property>
</e:propertyset>
HTTP/1.1 200 OK
SERVER: Linux/2.6.14.4, UPnP/1.0, Portable SDK for UPnP devices/1.4.0
CONNECTION: close
CONTENT-LENGTH: 41
CONTENT-TYPE: text/html
<html>
<body>
<h1>200 OK</h1>
</body>
</html>
Now, finally we can add a portmapping …
POST /uuid:0013-1007-eefc0200eddc/WANIPConnection:1 HTTP/1.1
HOST: 192.168.1.1:5431
CONTENT-LENGTH: 590
CONTENT-TYPE: text/xml; charset="utf-8"
SOAPACTION: "urn:schemas-upnp-org:service:WANIPConnection:1#AddPortMapping"
USER-AGENT: Linux/2.6.14.4, UPnP/1.0, Portable SDK for UPnP devices/1.4.0
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:AddPortMapping xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1">
<NewRemoteHost></NewRemoteHost>
<NewExternalPort>443</NewExternalPort>
<NewProtocol>tcp</NewProtocol>
<NewInternalPort>443</NewInternalPort>
<NewInternalClient>192.168.1.3</NewInternalClient>
<NewEnabled>1</NewEnabled>
<NewPortMappingDescription>Nepenthes PFW (tcp) 443</NewPortMappingDescription>
<NewLeaseDuration>0</NewLeaseDuration>
</u:AddPortMapping>
</s:Body>
</s:Envelope>
HTTP/1.1 200 OK
DATE: Sun, 02 Jul 2006 04:55:44 GMT
Connection: Keep-Alive
Server: LINUX/2.4 UPnP/1.0 BRCM400/1.0
Content-Length: 289
Content-Type: text/xml; charset="utf-8"
EXT:
<?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<m:AddPortMappingResponse xmlns:m="urn:schemas-upnp-org:service:WANIPConnection:1"></m:AddPortMappingResponse>
</s:Body>
</s:Envelope>
I hope this little excerpt was able to show:
UPnP relies on
for service and control points.
as well as
UPnP
From my own experience implementing the clientside http protocol is non trivial, I never tried doing it serverside.
XML and SOAP, the majors when talking about enterprise software, define bloat in most usecases.
The library I used to write the controlpoint, libupnp (written by intel years ago and unmaintained), comes with:
And as you may expect it, it did not work, I had to tweak it for very trivial things, the content type the servicepoint replied for its content was “application/octet-stream” where the lib would only accept “text/xml”.
The library tries to hides every dirty detail about its internal threading to run the webserver and get/post content from/to the servicepoint 'asynchronous', one has to provide threading safe callbacks, and lock mutexes for shared informations.
Inadequate complexity for the actual use.
What you could not see, after adding 18 rules via upnp, I used Windows XP networking *whatever* to list the enabled UPnP forwardings, it took like 2 minutes to download all forwardings rules as the router was pretty loaded with requests.
Bad performance.
For now, even if its working, we won't include the nepenthes module which would allow creating port forwards on upnp enabled devides, as the upnp library needs to be patched, and UPnP is nothing we want to support.
Some links about UPnP: