Digging into UPnP by searching a Sonos API

Boris Djurdjevic
Jul 26, 2017 · 3 min read

A discussion about connection possibilities of a Sonos speaker led to an short analysis on how it communicates with other systems. As an exercise I would like to control the volume.

At first I thought Sonos uses a proprietary API because after a quick search on the internet I couldn’t find anything useful. However, after searching for some minutes it turned out that there are open protocols in use.

Search for protocols

nmap found the IP address of my Sonos Play:5 and I searched for open TCP ports on this device:

# nmap -p1–65535 192.168.0.24Starting Nmap 7.50 ( https://nmap.org ) at 2017–07–24 11:48 CEST
Nmap scan report for 192.168.0.24
Host is up (0.020s latency).
Not shown: 65532 closed ports
PORT STATE SERVICE
1400/tcp open cadkey-tablet
1410/tcp open hiq
1443/tcp open ies-lm
MAC Address: B8:E9:XX:XX:XX:XX (Sonos)
Nmap done: 1 IP address (1 host up) scanned in 40.32 seconds

TCP ports 1400, 1410 and 1443 are open. Using curl it was clear that 1400 and 1443 are the same or similar services with the difference that 1443 uses TLS.

$ curl -v 192.168.0.24:1400/
* Trying 192.168.0.24...
* TCP_NODELAY set
* Connected to 192.168.0.24 (192.168.0.24) port 1400 (#0)
> GET / HTTP/1.1
> Host: 192.168.0.24:1400
> User-Agent: curl/7.54.1
> Accept: */*
>
< HTTP/1.1 403 Forbidden
< Cache-Control: no-cache
< Content-type: text/html
< Server: Linux UPnP/1.0 Sonos/36.4-42130 (ZPS5)
< Connection: close
<
* Closing connection 0
<HTML><HEAD><TITLE>Error 403</TITLE></HEAD><BODY><H1>Error 403</H1><P>Forbidden</P></BODY></HTML>

Ok, that’s interesting. The Server string contains UPnP in it what looks like this device has some UPnP capability. Searching the internet I found that UPnP uses SSDP for discovery so I installed the gssdp-device-sniffer on my Linux system. One of the responses which were caught look like this:

CACHE-CONTROL: max-age = 1800
EXT:
LOCATION: http://192.168.0.24:1400/xml/device_description.xml
Server: Linux UPnP/1.0 Sonos/36.4-42130 (ZPS5)
ST: urn:schemas-upnp-org:service:MusicServices:1
USN: uuid:RINCON_B8E9XXXXXXXXXXXXX::urn:schemas-upnp-org:service:MusicServices:1
X-RINCON-HOUSEHOLD: Sonos_xxxxxxxxxxxxxxxxxxxxx
X-RINCON-BOOTSEQ: 162
X-RINCON-WIFIMODE: 1
X-RINCON-VARIANT: 0

Remark: The port 1410 did also respond to a HTTP request with an UPnP Server string but I couldn’t find any description document URI.

Understanding UPnP

At this point we know this device uses UPnP and a special URI was discovered which seems like a step forward. But first I had to learn something about UPnP. On https://openconnectivity.org/developer/specifications/upnp-resources/upnp you can find very helpful specifications. As an introduction http://upnp.org/specs/arch/UPnP-arch-DeviceArchitecture-v2.0.pdf is enough as it explains UPnP basics down to a common protocol layer. Following steps are defined, namely Addressing, Discovery, Description, Control, Eventing, Presentation.

The discovery step we already have above, where I caught the SSDP message. It provided us with an URI which is specified in the description step. Looking at the data from http://192.168.0.24:1400/xml/device_description.xml shows a list of all so called services where the following definition looks interesting:

<service>
<serviceType>urn:schemas-upnp-org:service:RenderingControl:1</serviceType>
<serviceId>urn:upnp-org:serviceId:RenderingControl</serviceId>
<controlURL>/MediaRenderer/RenderingControl/Control</controlURL>
<eventSubURL>/MediaRenderer/RenderingControl/Event</eventSubURL>
<SCPDURL>/xml/RenderingControl1.xml</SCPDURL>
</service>

Going to http://192.168.0.24:1400/xml/RenderingControl.xml it reveals several actions like GetVolume and SetVolume which are described with its parameters like this example shows (stripped relatedStateVariable for readability away):

<action>
<name>GetVolume</name>
<argumentList>
<argument>
<name>InstanceID</name>
<direction>in</direction>
</argument>
<argument>
<name>Channel</name>
<direction>in</direction>
</argument>
<argument>
<name>CurrentVolume</name>
<direction>out</direction>
</argument>
</argumentList>
</action>

Now we are in the step/chapter Control. Explanations can be found in the UPnP-av-RenderingControl-v1-Service document.

Sending a request

It’s time to send a request. UPnP-arch-DeviceArchitecture explains on page 78 an Action Invocation which I used as template for the SOAP request to get the actual volume level.

echo '
<?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:GetVolume xmlns:u="urn:schemas-upnp-org:service:RenderingControl:1">
<InstanceID>0</InstanceID>
<Channel>Master</Channel>
</u:GetVolume>
</s:Body>
</s:Envelope>
' | curl -v -d @- \
-H 'SOAPAction: "urn:schemas-upnp-org:service:RenderingControl:1#GetVolume"' \
-H 'content-type: text/xml; charset="utf-8"' \
http://192.168.0.24:1400/MediaRenderer/RenderingControl/Control

Invoking this command it responds with the volume level 22:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:GetVolumeResponse xmlns:u="urn:schemas-upnp-org:service:RenderingControl:1">
<CurrentVolume>22</CurrentVolume>
</u:GetVolumeResponse>
</s:Body>
</s:Envelope>

Now my goal is reached, I established some basic communication with the Sonos device and all other controls are straight forward.

Learnings

  • The UPnP specification is easy understandable and the device and service description format is human readable
  • UPnP uses different (well known) protocols and is very powerful as it covers a wide application spectrum
  • The error code 402 (Invalid Args) occurred a few times, always without a pointer to the error. This can be nasty
  • It looks like the Sonos device is more open as many know

Boris Djurdjevic

Written by

Linux, Go, Container, PostgreSQL, Bitcoin, Infosec

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade