Friday, November 16, 2012

Extracting the firmware for Edimax IC-7110W IP Camera

I got an Edimax IC-7110W IP camera and I liked their firmware, but I was curious what was happening behind the curtains, so I decided to take a look.

Step 1: Get the firmware - I got the firmware update binary package from their site for version 1.7 - other versions are probably similar: http://www.edimax.com/en/support_detail.php?pd_id=415&pl1_id=8

Step 2: Prepare your environment - I am using Ubuntu Linux 12.04. You will need to download and install the following software:
Step 3: Install firmware-mod-kit and compile binwalk and unsquashfs:

adrianp@frost:~/temp$ mkdir -p edimax/1.7 edimax/fmk
adrianp@frost:~/temp$ cd edimax
adrianp@frost:~/temp/edimax$ svn checkout http://firmware-mod-kit.googlecode.com/svn/trunk/ fmk

... output omitted ...

adrianp@frost:~/temp/edimax$ cd fmk/src/binwalk-0.4.1/src
adrianp@frost:~/temp/edimax/fmk/src/binwalk-0.4.1/src$ ./configure

... output omitted ...

adrianp@frost:~/temp/edimax/fmk/src/binwalk-0.4.1/src$ make

... output omitted ...

adrianp@frost:~/temp/edimax/fmk/src/binwalk-0.4.1/src$ ls -l binwalk
-rwxrwxr-x 1 adrianp adrianp 358991 Nov 16 16:15 binwalk
 
adrianp@frost:~/temp/edimax/fmk/src/binwalk-0.4.1/src$ cd ../../squashfs-3.0/
adrianp@frost:~/temp/edimax/fmk/src/squashfs-3.0$ make

... output omitted ...adrianp@frost:~/temp/edimax/fmk/src/squashfs-3.0$ ls -l unsquashfs*
-rwxrwxr-x 1 adrianp adrianp  34292 Nov 16 16:18 unsquashfs
-rwxrwxr-x 1 adrianp adrianp 227552 Nov 16 16:18 unsquashfs-lzma

adrianp@frost:~/temp/edimax/fmk/src/squashfs-3.0$ cd ../../../  
adrianp@frost:~/temp/edimax$

Step 4: Unzip the firmware and extract the bin file:

adrianp@frost:~/temp/edimax$ cd 1.7
adrianp@frost:~/temp/edimax/1.7$ lsIC-7110_EDIMAX_CLOUD_v1.7_upg.zip
adrianp@frost:~/temp/edimax/1.7$ unzip IC-7110_EDIMAX_CLOUD_v1.7_upg.zip
Archive:  IC-7110_EDIMAX_CLOUD_v1.7_upg.zip
  inflating: IC-7110_EDIMAX_CLOUD_v1.7_upg.bin 
adrianp@frost:~/temp/edimax/1.7$ ls -l
total 7296
-rw-rw-r-- 1 adrianp adrianp 3751945 Apr 18  2012 IC-7110_EDIMAX_CLOUD_v1.7_upg.bin
-r-------- 1 adrianp adrianp 3709299 Nov 16 15:47 IC-7110_EDIMAX_CLOUD_v1.7_upg.zip

Step 5: Use binwalk to extract the root filesystem from the firmware (change the relative path to binwalk if needed) (note - analysing the firmware might take up to 5-10 minutes):

adrianp@frost:~/temp/edimax/1.7$ ../fmk/src/binwalk-0.4.1/src/binwalk -m ../fmk/src/binwalk-0.4.1/src/magic.binwalk  IC-7110_EDIMAX_CLOUD_v1.7_upg.bin

DECIMAL       HEX           DESCRIPTION
-------------------------------------------------------------------------------------------------------
11388         0x2C7C        gzip compressed data, from Unix, last modified: Wed Apr 18 05:12:23 2012, max compression
786440        0xC0008       Squashfs filesystem, little endian, version 3.0, size: 2961974 bytes, 221 inodes, blocksize: 65536 bytes, created: Wed Apr 18 05:12:31 2012

I am not sure what the first entry is - could be the kernel, but we are currently interested in the second one - the root file system.

 Step 6: Extract the root file system from the firmware file. Right now the root file system is embedded in the firmware file, starting from offset 0xC0008 (786440 bytes into the file). We need to make it a standalone file. The file size is 2961974 bytes. We will use dd for the job:


adrianp@frost:~/temp/edimax/1.7$ dd if=IC-7110_EDIMAX_CLOUD_v1.7_upg.bin skip=786440 bs=1 count=2961974 of=rootfs.squasfs
2961974+0 records in
2961974+0 records out
2961974 bytes (3.0 MB) copied, 8.89102 s, 333 kB/s
adrianp@frost:~/temp/edimax/1.7$ file rootfs.squasfs
rootfs.squasfs: Squashfs filesystem, little endian, version 3.0, 2961974 bytes, 221 inodes, blocksize: 65536 bytes, created: Wed Apr 18 05:12:31 2012
Step 7: Unsquash the squashfs file. This action decompresses the filesystem and recreates the folder structure it came from. The particular bit is you need to use the same unsquashfs version (3.0) it was created with. One more important detail is that squashfs usually uses gzip as a compressor, but in Edimax's case they used lzma, so you need to use the following command:

adrianp@frost:~/temp/edimax/1.7$ ../fmk/src/squashfs-3.0/unsquashfs-lzma rootfs.squasfs

created 66 files
created 27 directories
created 128 symlinks
created 0 devices
created 0 fifos
Step 8: Profit! Your firmware's root file system is now dumped in the folder squashfs-root:

adrianp@frost:~/temp/edimax/1.7$ cd squashfs-root/
adrianp@frost:~/temp/edimax/1.7/squashfs-root$ ls
bin  dev  etc  lib  linuxrc  mnt  proc  sbin  storage  tmp  usr  var

I will explore some of the hidden features of the firmware in a following blog post.

Thursday, November 15, 2012

RTSP streaming over dual nat with RTSP Interleaved mode

I have an IP Camera that supports RTSP streaming (most IP cameras seem to support it - Axis, Edimax, etc). This allows you to view mpeg4 or h264 live streams either by using a proprietary ActiveX control (via their web interface) or via a RTSP client.

If you are in the same LAN as the camera, you can easily connect to it by using VLC or even ffmpeg (to save or transcode the stream):

vlc rtsp://192.168.1.10/ipcamera_h264.sdp
ffmpeg -i rtsp://192.168.1.10/ipcamera_h264.sdp test.ts
ffmpeg -i rtsp://192.168.1.10/ipcamera_h264.sdp -f mpegts | vlc -



The problem is if you want to access that camera over the Internet. RTSP usually transports the data over UDP and negotiates the UDP ports over a control session on port 554 TCP. This gets difficult if you use NAT at either end or if you have firewalls you need to get through.

Let's consider this typical scenario:



The packets need to go through 2 NATs to travel between the source and destination. To make this happen, you have 3 possible solutions:

1. Using a session management protocol like ICE, but it needs to be supported by the client and server. Cheap IP cameras don't usually support it
2. Using a Layer 3 or Layer 2 VPN between RouterA and RouterB. With a VPN set in place (and with the appropriate firewall permits), the client can connect via RTSP to the server and it would communicate the same way it does in a LAN environment (no more NAT!). However, your routers need to be configured for site-to-site VPN - which might be challenging (especially if you don't have management access on either router)
3. Using RTSP Interleaved mode - a method I will describe next

According to Wikipedia:
Certain firewall designs and other circumstances may force a server to interleave RTSP methods and stream data. This interleaving should generally be avoided unless necessary since it complicates client and server operation and imposes additional overhead. Interleaved binary data SHOULD only be used if RTSP is carried over TCP.

So, instead of using UDP to transfer data, it uses TCP, and furthermore, it piggybacks the video data on top of the control session that is established on port 554. It may be less efficient in payload size and processing power, but it works with NAT and firewalls - which is what we want.

So, for the example above we have the following prerequisites for this to work:
  1.  The ability to port forward on RouterB
  2.  The IP Camera must have a fixed IP address (in order for port forwarding to work). This can be done either by assigning a static IP manually, or through DHCP.
  3.  Client and server must support RTSP Interleaved mode


Port forwarding setup

Depending on your router's firmware this can be done in different ways. I will not show a specific way to do it, just the concept. On RouterB you need to allow incoming TCP packets from source IP 11.11.11.11 (the NATed IP of the client) to go to your IP camera's IP (192.168.1.10) on the RTSP port (554 by default).

Since this is port forwarding you are actually forwarding a TCP port on your router (e.g. 22.22.22.22:1234) to an internal server in your network (192.168.1.10:554), so you will need to decide which external port you will be using (I used 1234 in my example).

If you have multiple IP Cameras behind RouterB, you can add multiple port forwarding rules - like this:

allow TCP from 11.11.11.11 to 192.168.1.10:554 on external port 1234
allow TCP from 11.11.11.11 to 192.168.1.11:554 on external port 5678
The port forwarding rule does not necessarily have to specify the source address - if it is missing it will allow access from any source address - but this is a security risk, so I advise against it.

RTSP Interleaved mode
Right now, you should be able to connect to the camera from the client computer, but if you try to use RTSP, you will notice that the control session is established, but the data never arrives because the NAT and firewall prevent the communication on the negotiated UDP ports.

You must convince the client software to try connecting in interleaved mode (this is why you came here for, right?).

VLC: Well, according to http://www.wowza.com/forums/content.php?64 you need to do the following configuration in VLC:

  1. Open VLC
  2. Select menu item Tools: Preferences
  3. Select the Input & Codecs section
  4. Select the Live555 stream transport option RTP over RTSP (TCP)
  5. Click Save button
You can now connect to your stream using the command:

vlc rtsp://22.22.22.22:1234/ipcamera_h264.sdp
For other cameras, change the destination port (e.g. 1234 -> 5678) in your command

FFMPEG: Their documentation states that you need to use the rtsp_transport flag:

ffmpeg -rtsp_transport tcp -i rtsp://22.22.22.22:1234/ipcamera_h264.sdp test.ts
ffmpeg -rtsp_transport tcp -i rtsp://22.22.22.22:1234/ipcamera_h264.sdp -f mpegts | vlc -
In case of problems, you should analyse a packet capture and see if Interleaved mode is supported by both end systems (it is negotiated in a RTSP OPTIONS request) - capture example below:


Have fun streaming!