ng-upnp2mrtg



If you're looking at this page, you most like use a modem that ng-upnp2mrtg does not (yet) support.

The following paragraphs describe the UPnP protocol(s) to an extent that will enable you to retrieve the missing information.

Discovery

Discovery is the process of determining how to query the UPnP server.

On the most basic level you need:

  • the IP address of the modem/router, and the

  • port number on which the UPnP server is listening.

Usually three values are being retrieved from the UPnP device:

  • number of bytes received

  • number of bytes sent, and

  • the uptime. 

As you will see shortly, 4 short strings for each of them are all you need to get the information you want:

  • the URI within the UPnP server,

  • the so called 'service' and a corresponding 'action',

  • and the name of the tag that holds the value in the reply from the server.

In nearly all cases, the IP address is the one you use to open its web interface.  The port number is usually located in the 49000 range; the FritzBox uses 49000, the NetCologne Premium Modem uses 49300.

SSDP Notify

A reliable way to find the missing information is to monitor the network for SSDP notify packets sent by the UPnP devices (SSDP = Simple Service Discovery Protocol).  These are multicast UDP packets sent to 239.255.255.250 port 1900.  You can use a packet sniffer like Wireshark to capture those.

When using Wireshark you might want to filter the packets, showing only those originating from your router: 'ip.addr == a.b.c.d'

wireshark screenshot

Be patient – it could take a few minutes for the first SSDP packets to appear.  There will be different SSDP packets which will be repeated after a while.  The content of a typical SSDP packet looks like this:

NOTIFY * HTTP/1.1
HOST: 239.255.255.250:1900
LOCATION: http://192.168.0.99:49000/igddesc.xml
SERVER: mynet UPnP/1.0 AVM FRITZ!Box WLAN 3170 49.04.57
CACHE-CONTROL: max-age=1800
NT: urn:schemas-upnp-org:device:InternetGatewayDevice:1
NTS: ssdp:alive
USN: uuid:75802409-bccb-40e7-8e6c-001C4A50656D::urn:schemas-upnp-org:device:InternetGatewayDevice:1

This looks like a HTTP message – and it is:

  • a methode (NOTIFY),

  • an URI (*) (well...),

  • and the protocol version (HTTP/1.1),

  • followed by a few headers containing UPnP related information.


Those are:

  • LOCATION: 
    This URL contains the IP number and the port address of the UPnP server.  If you enter this URL into your browser you get an XML file describing various services (see below).  Even if this URL does not end in .xml, try it anyway.

  • NT: the “service type”

  • NTS: ssdp:alive = unit present; ssdp:byebye = unit will cease operation shortly

  • USN:  a unique identifier for this service (needed if you want to keep track of this particular service in a caching subroutine, for example).

The values for NT and the information stored in the description XML files will become important later.  First, let's have a look at an actual query to see what we are looking for.

A UPnP query


After establishing a TCP connection to the IP and port number mentioned in the SSDP packet under LOCATION the client sends a query to the UPnP server.  This query is text based and formatted according to the HTTP protocol.  The body includes XML and is a SOAP message.

Here is a typical example:

POST /WANCommonInterfaceConfigService/control HTTP/1.0
HOST: 192.168.0.1:49300
CONTENT-LENGTH: 340
CONTENT-TYPE: text/xml; charset="utf-8"
SOAPACTION: "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1#GetTotalBytesReceived"

<?xml version="1.0"?>
    <s:Envelope
        xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
        s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
    <s:Body>
       <u:GetTotalBytesReceived xmlns:u="urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1">
       </u:GetTotalBytesReceived>
    </s:Body>
</s:Envelope>

The interesting parts are underlined and printed in italic. Let's have a look:

POST is an HTTP method followed by an URI (in this example /WANCommonInterfaceConfigService/control ).  This is one piece of information we need.

HOST: IP and port number of the UPnP server.  We just got this information from the SSDP packet.

CONTENT-LENGTH: length of the body

CONTENT-TYPE: character encoding of the body

SOAPACTION: The part in front of the #-sign describes the service, the part behind an action.  More on that later.

After a blank line (due to the HTTP standard) we find the message body, a SOAP request, i.e. an XML message.  Most of it is boilerplate – and the variable parts we know already from the headers.

The UPnP server will answer in the same connection with a message like this one:

HTTP/1.1 200 OK
EXT:
CONTENT-TYPE: text/xml; charset="utf-8"
SERVER: IAD, UPnP/1.0, MicroStack v1.0.2777

<?xml version="1.0" encoding="utf-8"?>
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"       xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
   <u:GetStatusInfoResponse xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1">
       <NewConnectionStatus>Connected</NewConnectionStatus>
       <NewLastConnectionError>ERROR_NONE</NewLastConnectionError>
       <NewUptime>30864</NewUptime>
   </u:GetStatusInfoResponse>
</s:Body></s:Envelope>

The first line is a standard HTTP response code (200 means OK), followed by header lines, followed by an empty line, followed by an XML message.  Most of it is SOAP boilerplate, some of the variable parts we know from the query.  The info we seek is encapsulated in tags <tag>...</tag>, like the uptime value in <NewUptime>...</NewUptime>.

To recap.

To query a specific item of information we need (example values in brackets):

  • the IP address (192.168.0.1) and the port number (49300) of the UPnP server

  • the URI within that server (/WANCommonInterfaceConfigService/control)

  • a service (urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1)

  • an action for that service (GetTotalBytesReceived)

  • the tag in the response which holds the information we want (NewUptime)

SSDP revisited

Now that we know what we are looking for, let's look again at the SSDP packet.  Each SSDP packet has a LOCATION header:

LOCATION: http://192.168.0.99:49000/igddesc.xml

There will be most likely different values for LOCATION in the different SSDP packets.  The URI may contain the name of an XML file or it may not.  In either case, enter this URI into your browser.

If you use Firefox, you will get a nicely formatted XML tree.  Look for entries starting with <serviceList>. There may be more than one on different levels of the XML tree.

Example:
...
<serviceList>
    <service>
        <serviceType>urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1</serviceType>
        <serviceId>urn:upnp-org:serviceId:WANCommonIFC1</serviceId>
        <SCPDURL>WANCommonInterfaceConfigService/scpd.xml</SCPDURL>
        <controlURL>WANCommonInterfaceConfigService/control</controlURL>
 ...
    </service>
...
</serviceList>

Within a <serviceList> there are one or more <service> listed.

  • The <serviceType> is the “service” we need in the UPnP query.

  • The <controlURL> is the URI needed in the query (add a backslash in front of it).

  • <SCPDURL> gets you another XML file listing the available actions. 


Enter  http://<ip-address>:<port>/<value_of_SCPDURL>  into your browser.  The resulting XML file looks like this:

<scpd>
...
    <actionList>
        <action>
            <name>action_name</name>
            <argumentList>
                <argument>
                    <name>argument_name_1</name>
                    <direction>in</direction>
                </argument>
               <argument>
                    <name>argument_name_2</name>
                    <direction>out</direction>
                </argument>
...
            </argumentList>
        </action>
...
    </actionList>
</scpd>

Most of the tags are self-explanatory. Here are the important ones:

  • action_name is the parameter action of our UPnP query

  • argument_name is the name of the tag in the UPnP reply

  • you can only query information which has the direction set to “out”.


The information we are looking for is usually labelled: “GetTotalBytesReceived”“ and „NewTotalBytesReceived“.  For the uptime, look for  „NewUpTime“.