aboutsummaryrefslogtreecommitdiff
path: root/dcs8000lh.md
diff options
context:
space:
mode:
Diffstat (limited to 'dcs8000lh.md')
-rw-r--r--dcs8000lh.md2043
1 files changed, 0 insertions, 2043 deletions
diff --git a/dcs8000lh.md b/dcs8000lh.md
deleted file mode 100644
index a680e6b..0000000
--- a/dcs8000lh.md
+++ /dev/null
@@ -1,2043 +0,0 @@
-# D-Link DCS-8000LH
-
-![D-Link DCS-8000LH](https://eu.dlink.com/uk/en/products/-/media/product-pages/dcs/8000lh/dcs_8000lh_front.png)
-
-These are random notes descibing how I changed my D-Link DCS-8000LH
-from a cloud camera to a locally managed IP camera, streaming H.264
-MPEG-TS over HTTP and HTTPS. Some of the tools and ideas might work
-for other cameras too, given some model specific adaptation.
-
-Complete defogging requires modifying one of the file systems in the
-camera. This implies a slight risk of ending up with a brick. You
-have now been warned...
-
-This is tested and developed on firmware versions v2.01.03 and
-v2.02.02 only. The final complete procedure has only been tested with
-v2.02.02. It should work fine with v2.01.03 and other versions, in
-theory, but could fail like anything untested. Please let me know if
-you have an original v2.01.03 firmware update from D-Link, or any
-other version for that matter, or know where firmware updates can be
-downloaded.
-
-The v2.02.02 update is available from
-https://mydlinkmpfw.auto.mydlink.com/DCS-8000LH/DCS-8000LH_Ax_v2.02.02_3014.bin
-at the time of writing. But I assume this link stops working as soon
-as there is a newer version available.
-
-
-## Changelog
-
-* v0.01 (20190515) - initial published version
-* v0.02 (20190515) - added RTSP support and information
-
-## Problem
-
-My D-Link DCS-8000LH came with firmware version 2.01.03 from factory.
-This firmware is locked to the [**mydlink**](https://www.mydlink.com)
-app/cloud service. It does not provide a local NIPCA compatible HTTP
-API or similar, and it does not stream video over HTTP, HTTPS or RTSP.
-
-Additionally, there is no way to downgrade the firmware. In fact,
-there is no documented way to install any firmware image at all,
-except trusting the "mydlink" cloud service to do it for you.
-
-
-## Solution
-
-#### Primary goals achieved:
-
-* configuration of network and admin password via Bluetooth LE, without
- registering with D-Link or using the [**mydlink**](https://www.mydlink.com) app at all
-* streaming MPEG-TS directly from camera over HTTP and HTTPS
-* direct RTSP streaming
-* NIPCA API configuration over HTTP and HTTPS, supporting settings
- like LED, nightmode, etc
-
-
-#### And some extra goodies which came for free
-
-* Firmware upgrades and downgrades via HTTP
-* telnet server with a root account (admin/PIN Code)
-* easy access to serial console, using the same root account
-* running arbitrary commands on the camera using Bluetooth
-
-Read on for all the gory details...
-
-
-### Requirements
-
- * a Linux PC with a Bluetooth controller
- * python3 with @IanHarvey's
- [**bluepy**](https://ianharvey.github.io/bluepy-doc/index.html)
- library
- * WiFi network with WPA2-PSK and a known password
- * mksquashfs from the squashfs-tools package
- * a tftp server or web server accepting file uploads (for backups)
- * guts :-)
-
-Most recent Linux distros will probably do. The bluepy library can be
-installed using pip if it is not available as a distro package. Other
-types of WiFi networks might work, but has not been tested with the
-provided tools. The squashfs-tools are only necessary if you want to
-rebuild the "mydlink" alternative file system. I assume you can even
-run the tools without installing Linux, by using a Linux "Live"
-CD/DVD/USB stick.
-
-This was developed and tested on Debian Buster.
-
-
-
-### Camera configuration using the Bluetooth LE GATT API
-
-The "mydlink" app uses Bluetooth LE for camera setup, authenticated by
-the camera pincode. This repo includes an alternative python script
-with a few extra goodies, but needing a better name:
-[**dcs8000lh-configure.py**](dcs8000lh-configure.py)
-
-(Why not an Android app? Because it would take me much more time to
-write. Should be fairly easy to do though, for anyone with enough
-interest. You can find all the necessary protocol details here and in
-the python code. Please let me know if you are interested)
-
-The script does not support scanning for the simple reason that this
-would require root access for not real gain. You have to provide the
-**PIN Code** from the camera label
-anyway. Reading the **MAC ID** as well is simple enough
-![camera label](https://www.mork.no/~bjorn/dcs8000lh/dcs8000lh-label.jpg)
-
-The **PIN Code** and **MAC** is also printed on the code card that
-came with the camera:
-![code card](https://www.mork.no/~bjorn/dcs8000lh/dcs8000lh-code-card.jpg)
-
-
-Note that the command line **address** paramenter must be formatted as
-**01:23:45:67:89:AB** instead of the **0123456789AB** format printed
-on the label.
-
-Current script help text at the time of writing shows what the script
-can do:
-
-```
-$ ./dcs8000lh-configure.py -h
-usage: dcs8000lh-configure.py [-h] [--essid ESSID] [--wifipw WIFIPW]
- [--survey] [--netconf] [--sysinfo]
- [--command COMMAND] [--telnetd] [--lighttpd]
- [--rtsp] [--unsignedfw] [--attrs] [-V]
- address pincode
-
-IPCam Bluetooth configuration tool.
-
-positional arguments:
- address IPCam Bluetooth MAC address (01:23:45:67:89:AB)
- pincode IPCam PIN Code (6 digits)
-
-optional arguments:
- -h, --help show this help message and exit
- --essid ESSID Connect to this WiFi network
- --wifipw WIFIPW Password for ESSID
- --survey List WiFi networks seen by the IPCam
- --netconf Print current network configuration
- --sysinfo Dump system configuration
- --command COMMAND Run command on IPCam
- --telnetd Start telnet server on IPCam
- --lighttpd Start web server on IPCam
- --rtsp Enable access to RTSP server on IPCam
- --unsignedfw Allow unsigned firmware
- --attrs Dump IPCam GATT characteristics
- -V, --version show program's version number and exit
-```
-
-
-#### Real session excample after a clean upgrade to firmware v2.02.02, followed by factory reset
-
-1. Start by making sure the camera can see our WiFi network. This
- also verifies that we can connect and authenticate against the
- Bluetooth LE IPCam service, without making any changes to any
- camera settings:
-
-```
-$ ./dcs8000lh-configure.py B0:C5:54:AA:BB:CC 123456 --survey
-Connecting to B0:C5:54:AA:BB:CC...
-Verifying IPCam service
-Connected to 'DCS-8000LH-BBCC'
-DCS-8000LH-BBCC is scanning for WiFi networks...
-{'I': 'AirLink126FD4', 'M': '0', 'C': '11', 'S': '4', 'E': '2', 'P': '47'}
-{'I': 'Antiboks', 'M': '0', 'C': '11', 'S': '4', 'E': '2', 'P': '73'}
-{'I': 'ASV17', 'M': '0', 'C': '11', 'S': '4', 'E': '2', 'P': '47'}
-{'I': 'ASV17-dlink', 'M': '0', 'C': '6', 'S': '4', 'E': '2', 'P': '57'}
-{'I': 'DIRECT-33-HP%20ENVY%205000%20series', 'M': '0', 'C': '1', 'S': '4', 'E': '2', 'P': '46'}
-{'I': 'fjorde123', 'M': '0', 'C': '1', 'S': '4', 'E': '2', 'P': '55'}
-{'I': 'JOJ', 'M': '0', 'C': '11', 'S': '4', 'E': '2', 'P': '48'}
-{'I': 'Kjellerbod', 'M': '0', 'C': '11', 'S': '4', 'E': '2', 'P': '75'}
-{'I': 'Landskap_24', 'M': '0', 'C': '11', 'S': '4', 'E': '2', 'P': '46'}
-{'I': 'mgmt', 'M': '0', 'C': '1', 'S': '4', 'E': '2', 'P': '72'}
-{'I': 'Rindedal', 'M': '0', 'C': '11', 'S': '4', 'E': '2', 'P': '68'}
-{'I': 'risikovirus', 'M': '0', 'C': '1', 'S': '4', 'E': '2', 'P': '45'}
-{'I': 'risikovirus%20WIFI', 'M': '0', 'C': '11', 'S': '4', 'E': '2', 'P': '45'}
-{'I': 'Stavik2014', 'M': '0', 'C': '6', 'S': '4', 'E': '2', 'P': '47'}
-{'I': 'TomterNett1', 'M': '0', 'C': '6', 'S': '4', 'E': '2', 'P': '44'}
-{'I': 'VIF', 'M': '0', 'C': '11', 'S': '4', 'E': '2', 'P': '47'}
-Done.
-```
-
-2. We're going to use the 'Kjellerbod' network, so that looks good.
- Select it and give the associated WiFi password to the camera:
-
-```
-$ ./dcs8000lh-configure.py B0:C5:54:AA:BB:CC 123456 --essid Kjellerbod --wifipw redacted
-Connecting to B0:C5:54:AA:BB:CC...
-Verifying IPCam service
-Connected to 'DCS-8000LH-BBCC'
-DCS-8000LH-BBCC is scanning for WiFi networks...
-Will configure: M=0;I=Kjellerbod;S=4;E=2;K=redacted
-Done.
-```
-
-3. Verify that the camera connected to the Wifi network and got an
- address. If not, go back and try again, making sure you are using
- the correct WiFi password:
-
-```
-$ ./dcs8000lh-configure.py B0:C5:54:AA:BB:CC 123456 --netconf
-Connecting to B0:C5:54:AA:BB:CC...
-Verifying IPCam service
-Connected to 'DCS-8000LH-BBCC'
-wifi link is Up
-wifi config: {'M': '0', 'I': 'Kjellerbod', 'S': '4', 'E': '2'}
-ip config: {'I': '192.168.2.37', 'N': '255.255.255.0', 'G': '192.168.2.1', 'D': '148.122.16.253'}
-Done.
-```
-
-
-**WARNING**: You must make a backup of your device at this point if
-you haven't done so already. See the [**Backup**](#Backup) section
-below. I only skipped it in this example because I already had a
-complete backup of my camera.
-
-
-
-4. We need HTTP NIPCA API for the remaining tasks, so temporarily
- start lighttpd on the camera:
-
-```
-$ ./dcs8000lh-configure.py B0:C5:54:AA:BB:CC 123456 --lighttpd
-Connecting to B0:C5:54:AA:BB:CC...
-Verifying IPCam service
-Connected to 'DCS-8000LH-BBCC'
-Attempting to run '[ $(tdb get HTTPServer Enable_byte) -eq 1 ] || tdb set HTTPServer Enable_byte=1' on DCS-8000LH-BBCC by abusing the 'set admin password' request
-Attempting to run '/etc/rc.d/init.d/extra_lighttpd.sh start' on DCS-8000LH-BBCC by abusing the 'set admin password' request
-Done.
-```
-
-Note that this implicitly changes a couple of settings which are
-stored in the ["db"](#Partitions) NVRAM partition, and therefore will persist until
-the next factory reset:
- * extra_lighttpd.sh will exit without doing anything unless
- **HTTPServer Enable** is set
- * the admin password is set both because we're abusing that BLE
- request, and because we need it for the HTTP API access. The
- script only supports setting the password to the **PIN Code**.
-
-*This password restriction is because I'm lazy - there is nothing in
-the camera or protocol preventing the password from being set to
-something else. But the script would then need the new password as
-an additional input parameter for most commands*
-
-
-5. Disable firmware signature verification. Only firmwares signed by
- D-Link are accepted by default. This feature can be disabled by
- changing a variable in the ["db"](#Partitions) NVRAM partition:
-
-```
-$ ./dcs8000lh-configure.py B0:C5:54:AA:BB:CC 123456 --unsignedfw
-Connecting to B0:C5:54:AA:BB:CC...
-Verifying IPCam service
-Connected to 'DCS-8000LH-BBCC'
-Attempting to run 'tdb set SecureFW _TrustLevel_byte=0' on DCS-8000LH-BBCC by abusing the 'set admin password' request
-Done.
-```
-
-6. The final step is the dangerous one. It replaces the file system
- on the [**userdata**](#Partitions) partition with our home cooked one. The D-Link
- firmware uses this partition exclusively for the "mydlink" cloud
- tools, which we don't need. The rest of the system is not touched
- by our firmware update. The camera will therefore run exactly the
- same kernel and rootfs as before the update, whatever version they
- were. I.e., the firmware version does not change - only the
- "mydlink" version.
-
-
-**NOTE**; You need to [build](#BuildFirmware) a **fw.tar** firmware
-update image first.
-
-```
-$ curl --http1.0 -u admin:123456 --form upload=@fw.tar http://192.168.2.37/config/firmwareupgrade.cgi
-upgrade=ok
-```
-
-See the section on [error handling](#Errors) if the upgrade request
-returned anything else.
-
-The camera will reboot automatically at this point, assuming the
-update was successful. From now both with telnetd and lighttpd
-running, and with external access to the RTSP server. All services
-will use the same **admin:PIN Code** account for authentication.
-
-So we now have access to direct [streaming](#Streaming) over HTTP,
-HTTPS and RTSP without ever having been in contact with the
-[**mydlink**](https://www.mydlink.com) service!
-
-
-
-### <a name="Streaming"></a>Streaming video locally
-
-Which was the whole point of all this... We can now stream directly
-from the camera using for example:
-
-
-#### HTTP or HTTPS
-```
-vlc https://192.168.2.37/video/mpegts.cgi
-vlc https://192.168.2.37/video/flv.cgi
-```
-
-Authenticate using the **admin** user with **PIN Code** as password
-
-AFAICS, this camera does not support MJPEG encoding. But you can
-always use ffmpeg to transcode the H.264 anyway. Looking closer at a
-stream sample:
-
-
-```
-$ curl --insecure -u admin:123456 https://192.168.2.37/video/mpegts.cgi>/tmp/stream
- % Total % Received % Xferd Average Speed Time Time Time Current
- Dload Upload Total Spent Left Speed
- 0 93.1G 0 438k 0 0 92872 0 12d 11h 0:00:04 12d 11h 92853^C
-
-$ mediainfo /tmp/stream
-General
-ID : 1 (0x1)
-Complete name : /tmp/stream
-Format : MPEG-TS
-File size : 500 KiB
-Duration : 5 s 433 ms
-Overall bit rate mode : Variable
-Overall bit rate : 752 kb/s
-
-Video
-ID : 257 (0x101)
-Menu ID : 1 (0x1)
-Format : AVC
-Format/Info : Advanced Video Codec
-Format profile : High@L4
-Format settings, CABAC : Yes
-Format settings, ReFrames : 1 frame
-Format settings, GOP : M=1, N=30
-Codec ID : 27
-Duration : 5 s 450 ms
-Width : 1 280 pixels
-Height : 720 pixels
-Display aspect ratio : 16:9
-Frame rate mode : Variable
-Color space : YUV
-Chroma subsampling : 4:2:0
-Bit depth : 8 bits
-Scan type : Progressive
-
-Audio
-ID : 256 (0x100)
-Menu ID : 1 (0x1)
-Format : AAC
-Format/Info : Advanced Audio Codec
-Format version : Version 2
-Format profile : LC
-Muxing mode : ADTS
-Codec ID : 15
-Duration : 3 s 456 ms
-Bit rate mode : Variable
-Channel(s) : 1 channel
-Channel positions : Front: C
-Sampling rate : 16.0 kHz
-Frame rate : 15.625 FPS (1024 spf)
-Compression mode : Lossy
-```
-
-
-#### RTSP
-
-Direct RTSP access is also supported, using the same **admin** user.
-
-The RTSP URLs are configurable, so the proper way to use RTSP is to
-first check the URL of the wanted profile using the NIPCA API:
-
-```
-$ curl -u admin:123456 --insecure 'https://192.168.2.37/config/rtspurl.cgi?profileid=1'
-profileid=1
-urlentry=live/profile.0
-video_codec=H264
-audio_codec=OPUS
-```
-
-and then connect to this RTSP URL:
-
-```
-$ vlc rtsp://192.168.2.37/live/profile.0
-```
-
-Note that persistent RTSP access can be enabled with original
-unmodified D-Link firmware, using the Bluetooth **--rtsp** option.
-This modifies the necessary settings. The **rtspd** service is
-already started by default in the original firmware.
-
-So there is no need to mess with the firmware at all if all you want
-is RTSP.
-
-
-#### <a name="Errors"></a>Errors during firmware update via HTTP
-
-The **firmwareupgrade.cgi** script running in the camera isn't much
-smarter than the rest of the system, so there are a few important
-things keep in mind. These are found by trial-and-error:
-
- * HTTP/1.1 might not work - the firmwareupgrade.cgi script does not support **100 Continue** AFAICS
- * The firmware update image should be provided as a **file** input field from a form
- * The field name must be **upload**.
-
-Use the exact curl command provided above, replacing only the PIN
-Code, IP address and firmware filename. This should work. Anything
-else might not.
-
-The camera must be manually rebooted by removing power or pressing
-reset if the firmware upgrade fails for any reason. The
-**firmwareupgrade.cgi** script stops most processes, inluding the
-Bluetooth handler, and fails to restart them on errors.
-
-There will be no permanent harm if the upload fails. But note that
-you have to repeat the **--lighttpd** step after rebooting the camera,
-before you can retry. It does not start automatically until we've
-installed our modified "mydlink" alternative.
-
-The contents of the fw.tar file must obviously be a valid, encrypted,
-firmware update intended for the specified hardware. It must also be
-signed. But the signing key can be unknown to the camera provided the
-previous **--unsignedfw** request above was successful.
-
-The [**Makefile**](Makefile) provided here shows how to [build](#BuildFirmware) a valid firmware
-update, but for the DCS-8000LH only! It does not support any other
-model. It will create a new throwaway signing key if it canæt find a
-real one, and include the associated public key in the archive in case
-you want to verify the signature manually.
-
-Note that the encryption key might be model specific. I do not know
-this as I have no other model to look at. Please let me know if you
-have any information on this topic.
-
-The encryption key is part ot the [**pib**](#Partitions) partition, and can be
-read from a shell using
-```
-pibinfo PriKey
-```
-
-Or you can simply look at your partition backup. The key is stored as
-a plain text *RSA PRIVATE KEY* PEM blob, so it is easy to spot. This
-repo includes a copy of my [key](keys/DCS-8000LH-PriKey.pem) as I see
-no point in attempting to keep a well known shared key like this one
-"secret"
-
-
-### <a name="Backup"></a>Backup
-
-Create a backup of everything *before* you mess up. Restoring will be
-hard anyway, so don't rely on that. But you can forget about
-restoring at all unless you have a backup, so make it anyway.
-
-Note that the [**pib**](#Partitions) partition contains data which are
-specific to **your** camera, and cannot be restored from any other
-source! This includes
- * model number
- * hardware revision
- * mac address
- * feature bits
- * private keys, pincode and passwords
-
-Well, OK, we can restore most of the [**pib**](#Partitions) using information from
-the [camera label](https://www.mork.no/~bjorn/dcs8000lh/dcs8000lh-label.jpg), but
-it's better to avoid having to do that...
-
-A backup is also useful for analyzing the file systems offline.
-
-Making a backup without networking is inconvenient, so setup
-networking first. In theory, you could dump the flash to the serial
-console. But this would be very time consuming and tiresome.
-
-The D-Link firmware provides a selection of network file transfer
-tools. Pick anyone you like:
- * tftp
- * wget
- * curl
- * ...and probably more
-
-I've been using tftp for my backups because it is simple. You'll
-obviously need a tftp server for this. Google for instructions on
-setting that up. You could alternatively set up a web server and use
-wget or curl to post the files there, but this is more complx to set
-up IMHO.
-
-Here is one example of how to enable temporary telnet access and
-copying all camera flash partitions to a tftp server:
-
-```
-$ ./dcs8000lh-configure.py B0:C5:54:AA:BB:CC 123456 --telnetd
-Connecting to B0:C5:54:AA:BB:CC...
-Verifying IPCam service
-Connected to 'DCS-8000LH-BBCC'
-Adding the 'admin' user as an alias for 'root'
-Attempting to run 'grep -Eq ^admin: /etc/passwd||echo admin:x:0:0::/:/bin/sh >>/etc/passwd' on DCS-8000LH-BBCC by abusing the 'set admin password' request
-Setting the 'admin' user password to '123456'
-Attempting to run 'grep -Eq ^admin:x: /etc/passwd&&echo admin:123456|chpasswd' on DCS-8000LH-BBCC by abusing the 'set admin password' request
-Starting telnetd
-Attempting to run 'pidof telnetd||telnetd' on DCS-8000LH-BBCC by abusing the 'set admin password' request
-
-
-Attempting to run '[ $(tdb get HTTPServer Enable_byte) -eq 1 ] || tdb set HTTPServer Enable_byte=1' on DCS-8000LH-BBCC by abusing the 'set admin password' request
-Attempting to run '/etc/rc.d/init.d/extra_lighttpd.sh start' on DCS-8000LH-BBCC by abusing the 'set admin password' request
-Done.
-
-
-$ telnet 192.168.2.37
-Trying 192.168.2.37...
-Connected to 192.168.2.37.
-Escape character is '^]'.
-localhost login: admin
-Password:
-
-
-BusyBox v1.22.1 (2019-02-14 17:06:35 CST) built-in shell (ash)
-Enter 'help' for a list of built-in commands.
-
-
-# for i in 0 1 2 3 4 5 6 7 8; do tftp -l /dev/mtd${i}ro -r mtd$i -p 192.168.2.1; done`
-```
-
-Change 192.168.2.37 to the address of your camera and 192.168.2.1 to
-the address of your tftp server. Note that most tftp servers require
-existing and writable destination files. Refer to your tftp server docs
-for details.
-
-
-
-## All the gory details
-
-
-### Restoring original D-Link firmware
-
-The D-Link firmware, including the mydlink tools in the
-[**userdata**](#Partitions) partition, can be restored by doing a
-manual firmware upgrade providing a firmware update from D-Link. Real
-example, going back to v2.02.02:
-
-```
-$ curl --http1.0 -u admin:123456 --form upload=@DCS-8000LH_Ax_v2.02.02_3014.bin http://192.168.2.37/config/firmwareupgrade.cgi
-curl: (52) Empty reply from server
-```
-
-I don't know why I got that **Empty reply** warning instead of the
-expected **upgrade=ok**, but update went fine so I guess it can safely
-be ignored. Might be a side effect of rewriting the root file system,
-which the firmwareupgrade.cgi script is running from.
-
-
-### Serial console
-
-Entirely optional. The defogging procedure does not require console
-access, but it can be very useful when debugging problems related to
-network configuration etc.
-
-There is a 4 hole female header with 2 mm spacing in the bottom of the
-camera. This header is easily accessible without opening the case at
-all. But you will need to remove the bottom label to find it:
-![label removed](https://www.mork.no/~bjorn/dcs8000lh/dcs8000lh-label-removed.jpg)
-
-Take a picure of the lable or save the information somewhere else
-first, in case you make the it unreadable in the process.
-
-Mate with a 3 (or 4) pin male 2 mm connector, or use sufficiently
-solid wires. The pins need to be 6-10 mm long. The pins will mess up the QR code, but the rest of the label can be left intact if you're careful:
-![header with pins](https://www.mork.no/~bjorn/dcs8000lh/dcs8000lh-label-with-serial-pins.jpg)
-
-The pinout seen from egde to center of camera is:
-
-
-| 1 | 2 | 3 | 4 |
-|------|----|----|-----|
-| 3.3V | TX | RX | GND |
-
-and the serial port parameters are 57600 8N1.
-
-
-You obviously need a 3.3V TTL adapter for this, Look at for example
-at the generic OpenWrt console instructions if you need guidance.
-![USB ttl adapter connected](https://www.mork.no/~bjorn/dcs8000lh/dcs8000lh-serial-connected.jpg)
-
-
-Do not connect the 3.3V pin. All USB TTL adapters are powered by the
-USB bus.
-
-
-
-### Opening the case
-
-Remove the top and bottom parts of the sylinder. I assume the two
-remaning halves of the sylinder are simple held together by clips, but
-I did not verify this after discovering the easily accessible console
-header.
-
-The top lid is clipped on:
-![top lid](https://www.mork.no/~bjorn/dcs8000lh/dcs8000lh-top-lid.jpg)
-
-The bottom cover is held in place by two screws under the label:
-![bottom cover](https://www.mork.no/~bjorn/dcs8000lh/dcs8000lh-label-removed.jpg)
-
-
-Removing the bottom cover reveals the reset button and the console header:
-![bottom removed](https://www.mork.no/~bjorn/dcs8000lh/dcs8000lh-bottom-without-cover.jpg)
-
-
-### U-Boot
-
-My DCS-8000LH came with this boot loader:
-
-`U-Boot 2014.01-rc2-V1.1 (Jun 06 2018 - 03:44:37)`
-
-But it is patched/configured to require a password for access to the
-U-Boot prompt. Fortunately, D-Link makes the password readily
-available in their GPL package :-) It is found in the file
-`DCS-8000LH-GPL/configs/gpl_defconfig`:
-
-`ALPHA_FEATURES_UBOOT_LOGIN_PASSWORD="alpha168"`
-
-Enter **alpha168** password when you see
-
-`Press ESC to abort autoboot in 3 seconds`
-
-and you'll get a `rlxboot#` prompt, with access to these U-Boot commands :
-
-```
-rlxboot# ?
-? - alias for 'help'
-base - print or set address offset
-bootm - boot application image from memory
-bootp - boot image via network using BOOTP/TFTP protocol
-cmp - memory compare
-coninfo - print console devices and information
-cp - memory copy
-crc32 - checksum calculation
-echo - echo args to console
-editenv - edit environment variable
-efuse - efuse readall | read addr
-env - environment handling commands
-fephy - fephy read/write
-go - start application at address 'addr'
-help - print command description/usage
-imxtract- extract a part of a multi-image
-loadb - load binary file over serial line (kermit mode)
-loadx - load binary file over serial line (xmodem mode)
-loady - load binary file over serial line (ymodem mode)
-loop - infinite loop on address range
-md - memory display
-mm - memory modify (auto-incrementing address)
-mw - memory write (fill)
-nm - memory modify (constant address)
-ping - send ICMP ECHO_REQUEST to network host
-printenv- print environment variables
-reset - Perform RESET of the CPU
-setenv - set environment variables
-setethaddr- set eth address
-setipaddr- set ip address
-sf - SPI flash sub-system
-source - run script from memory
-tftpboot- boot image via network using TFTP protocol
-tftpput - TFTP put command, for uploading files to a server
-tftpsrv - act as a TFTP server and boot the first received file
-update - update image
-version - print monitor, compiler and linker version
-```
-
-Using the boot loader for image manipulation will be hard though,
-since the camera has no ethernet, USB or removable flash and the boot
-loader has no WiFi driver. It is probably possible to load an image
-over serial, but I don't have the patience for that...
-
-The environment is fixed and pretty clean:
-```
-rlxboot# printenv
-=3
-addmisc=setenv bootargs ${bootargs}console=ttyS0,${baudrate}panic=1
-baudrate=57600
-bootaddr=(0xBC000000 + 0x1e0000)
-bootargs=console=ttyS1,57600 root=/dev/mtdblock8 rts_hconf.hconf_mtd_idx=0 mtdparts=m25p80:256k(boot),128k(pib),1024k(userdata),128k(db),128k(log),128k(dbbackup),128k(logbackup),3072k(kernel),11264k(rootfs)
-bootcmd=bootm 0xbc1e0000
-bootfile=/vmlinux.img
-ethact=r8168#0
-ethaddr=00:00:00:00:00:00
-load=tftp 80500000 ${u-boot}
-loadaddr=0x82000000
-stderr=serial
-stdin=serial
-stdout=serial
-
-Environment size: 533/131068 bytes
-```
-
-So we can get ourselves a root shell:
-
-
-```
-rlxboot# setenv bootargs ${bootargs} init=/bin/sh
-rlxboot# ${bootcmd}
-```
-
-Nothing is mounted or started since /sbin/init is skipped altogether
-in this case. Not even /sys and /proc. We can emulate a semi-normal
-system by running
-
-`/etc/rc.d/rcS`
-
-as the first command. And then run for example
-
-`telnetd -l /bin/sh`
-
-to enable temporary passwordless telnet into the camera instead of/in
-addition to the serial console. This is futile unless you have
-networking of course. I will not go into details on how to do that
-from the shell. Use the much simpler Bluetooth procedure described
-above. Or the "mydlink" app if you prefer.
-
-
-### OEM boot log
-
-```
-U-Boot 2014.01-rc2-V1.1 (Jun 06 2018 - 03:44:37)
-
-rx5281 prid=0xdc02
-DRAM: 64 MiB @ 800 MHz
-Skipping flash_init
-Flash: 0 Bytes
-flash status is 0, 2, 0
-SF: Detected W25Q128FV with page size 256 Bytes, erase size 64 KiB, total 16 MiB
-Using default environment
-
-In: serial
-Out: serial
-Err: serial
-Net: Realtek PCIe GBE Family Controller mcfg = 0024
-no hw config header
-new_ethaddr = 00:00:00:00:00:00
-r8168#0
-no hw config header
-Press ESC to abort autoboot in 3 seconds## Booting kernel from Legacy Image at bc1e0000 ...
-get header OKimage_get_kernel check hcrc
-image_get_kernel print contents
- Image Name: linux_3.10
- Created: 2018-06-05 19:44:27 UTC
- Image Type: MIPS Linux Kernel Image (uncompressed)
- Data Size: 1662157 Bytes = 1.6 MiB
- Load Address: 804d4960
- Entry Point: 804d4960
- Verifying Checksum ... OK
- Loading Kernel Image ... OK
-
-Starting kernel ...
-
-Linux version 3.10.27 (jenkins@DMdssdFW1) (gcc version 4.8.5 20150209 (prerelease) (Realtek RSDK-4.8.5p1 Build 2278) ) #1 PREEMPT Wed Jun 6 03:36:32 CST 2018
-prom cpufreq = 500000000
-prom memsize = 67108864
-hw_ver: 0x1, hw_rev: 0x2, isp_ver: 0x0
-bootconsole [early0] enabled
-CPU revision is: 0000dc02
-Determined physical RAM map:
- memory: 04000000 @ 00000000 (usable)
-Reserved contiguous memory at 0x4f3000
-Zone ranges:
- Normal [mem 0x00000000-0x03ffffff]
-Movable zone start for each node
-Early memory node ranges
- node 0: [mem 0x00000000-0x03ffffff]
-icache: 32kB/32B, dcache: 16kB/32B, scache: 0kB/0B
-Built 1 zonelists in Zone order, mobility grouping on. Total pages: 16256
-Kernel command line: console=ttyS1,57600 root=/dev/mtdblock8 rts_hconf.hconf_mtd_idx=0 mtdparts=m25p80:256k(boot),128k(pib),1024k(userdata),128k(db),128k(log),128k(dbbackup),128k(logbackup),3072k(kernel),11264k(rootfs)
-PID hash table entries: 256 (order: -2, 1024 bytes)
-Dentry cache hash table entries: 8192 (order: 3, 32768 bytes)
-Inode-cache hash table entries: 4096 (order: 2, 16384 bytes)
-Memory: 48600k/65536k available (3844k kernel code, 16936k reserved, 888k data, 192k init, 0k highmem)
-SLUB: HWalign=32, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
-Preemptible hierarchical RCU implementation.
-NR_IRQS:49
-Calibrating delay loop... 498.89 BogoMIPS (lpj=2494464)
-pid_max: default: 32768 minimum: 301
-Mount-cache hash table entries: 512
-pinctrl core: initialized pinctrl subsystem
-regulator-dummy: no parameters
-NET: Registered protocol family 16
-rtsxb2 registered with IRQs
-INFO: initializing USB host ...
-INFO: initializing spi host ...0
-spi platform id is 0
-INFO: initializing I2C master ...
-INFO: initializing DMA controller ...
-INFO: initializing SD controller ...
-INFO: initializing snd device ...
-snd resvd mem size : 1048576
-INFO: initializing pinctrl device ...
-pinctrl_platform pinctrl_platform: rtspc registered with IRQs
-INFO: initializing ethernet devices ...
-INFO: initializing dwc_otg devices ...
-INFO: initializing USB phy ...
-INFO: initializing ISP device ...
-isp resvd mem addr : 0x005f3000, size : 0xa00000
-ISP camera platform devices added
-INFO: initializing watchdog controller ...
-INFO: initializing PWM controller ...
-INFO: initializing crypto device ...
-INFO: initializing pmu device ...
-bio: create slab <bio-0> at 0
-rts_dmac rts_dmac: DesignWare DMA Controller, 1 channels
-INFO: realtek DMA engine inited
-SCSI subsystem initialized
-spic-platform spic-platform.0: master is unqueued, this is deprecated
-INFO:allocate spi master 0, 0
-usbcore: registered new interface driver usbfs
-usbcore: registered new interface driver hub
-usbcore: registered new device driver usb
-usbphy-platform usbphy-platform: Initialized Realtek IPCam USB Phy module
-Linux video capture interface: v2.00
-Advanced Linux Sound Architecture Driver Initialized.
-Bluetooth: Core ver 2.16
-NET: Registered protocol family 31
-Bluetooth: HCI device and connection manager initialized
-Bluetooth: HCI socket layer initialized
-Bluetooth: L2CAP socket layer initialized
-Bluetooth: SCO socket layer initialized
-NET: Registered protocol family 2
-TCP established hash table entries: 512 (order: 0, 4096 bytes)
-TCP bind hash table entries: 512 (order: -1, 2048 bytes)
-TCP: Hash tables configured (established 512 bind 512)
-TCP: reno registered
-UDP hash table entries: 256 (order: 0, 4096 bytes)
-UDP-Lite hash table entries: 256 (order: 0, 4096 bytes)
-NET: Registered protocol family 1
-RPC: Registered named UNIX socket transport module.
-RPC: Registered udp transport module.
-RPC: Registered tcp transport module.
-RPC: Registered tcp NFSv4.1 backchannel transport module.
-squashfs: version 4.0 (2009/01/31) Phillip Lougher
-NFS: Registering the id_resolver key type
-Key type id_resolver registered
-Key type id_legacy registered
-jffs2: version 2.2. (NAND) © 2001-2006 Red Hat, Inc.
-msgmni has been set to 94
-NET: Registered protocol family 38
-Block layer SCSI generic (bsg) driver version 0.4 loaded (major 253)
-io scheduler noop registered
-io scheduler deadline registered
-io scheduler cfq registered (default)
-Serial: 8250/16550 driver, 3 ports, IRQ sharing disabled
-serial8250: ttyS0 at MMIO 0x18810000 (irq = 6) is a 16550A
-console [ttyS1] enabled, bootconsole disabled
-console [ttyS1] enabled, bootconsole disabled
-serial8250: ttyS1 at MMIO 0x18810100 (irq = 6) is a 16550A
-serial8250: ttyS2 at MMIO 0x18810200 (irq = 6) is a 16550A
-dbg_iomem initialized!
-m25p80 spi0.0: unrecognized id mx25l12845e
-m25p80 spi0.0: found w25q128fv, expected m25p80
-m25p80 spi0.0: w25q128fv (16384 Kbytes)
-9 cmdlinepart partitions found on MTD device m25p80
-Creating 9 MTD partitions on "m25p80":
-0x000000000000-0x000000040000 : "boot"
-0x000000040000-0x000000060000 : "pib"
-0x000000060000-0x000000160000 : "userdata"
-0x000000160000-0x000000180000 : "db"
-0x000000180000-0x0000001a0000 : "log"
-0x0000001a0000-0x0000001c0000 : "dbbackup"
-0x0000001c0000-0x0000001e0000 : "logbackup"
-0x0000001e0000-0x0000004e0000 : "kernel"
-0x0000004e0000-0x000000fe0000 : "rootfs"
-invalid hconf_mtd_idx!
-hconf init failed
-rtl8168 Gigabit Ethernet driver 8.038.00-NAPI loaded
-rtl8168 rtl8168 (unregistered net_device): Get invalid MAC address from flash!
-eth%d: 0xb8400000, 00:00:00:00:00:00, IRQ 10
-PPP generic driver version 2.4.2
-PPP MPPE Compression module registered
-NET: Registered protocol family 24
-ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
-ehci-rts: ehci-rts platform driver
-ehci-platform ehci-platform: EHCI Host Controller
-ehci-platform ehci-platform: new USB bus registered, assigned bus number 1
-ehci-platform ehci-platform: irq 11, io mem 0x18100000
-ehci-platform ehci-platform: USB 2.0 started, EHCI 1.00
-usb usb1: New USB device found, idVendor=1d6b, idProduct=0002
-usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1
-usb usb1: Product: EHCI Host Controller
-usb usb1: Manufacturer: Linux 3.10.27 ehci_hcd
-usb usb1: SerialNumber: ehci-platform
-hub 1-0:1.0: USB hub found
-hub 1-0:1.0: 1 port detected
-ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
-ohci-platform ohci-platform: Generic Platform OHCI Controller
-ohci-platform ohci-platform: new USB bus registered, assigned bus number 2
-ohci-platform ohci-platform: irq 11, io mem 0x18180000
-usb usb2: New USB device found, idVendor=1d6b, idProduct=0001
-usb usb2: New USB device strings: Mfr=3, Product=2, SerialNumber=1
-usb usb2: Product: Generic Platform OHCI Controller
-usb usb2: Manufacturer: Linux 3.10.27 ohci_hcd
-usb usb2: SerialNumber: ohci-platform
-hub 2-0:1.0: USB hub found
-hub 2-0:1.0: 1 port detected
-dwc_otg: version 3.10b 20-MAY-2013
-Core Release: 3.10a
-Setting default values for core params
-WARN::dwc_otg_set_param_dev_tx_fifo_size:6354: Value is larger then power-on FIFO size
-
-WARN::dwc_otg_set_param_dev_tx_fifo_size:6354: Value is larger then power-on FIFO size
-
-Using Buffer DMA mode
-Periodic Transfer Interrupt Enhancement - disabled
-Multiprocessor Interrupt Enhancement - disabled
-OTG VER PARAM: 0, OTG VER FLAG: 0
-Shared Tx FIFO mode
-usbcore: registered new interface driver usb-storage
-g_mass_storage gadget: Mass Storage Function, version: 2009/09/11
-g_mass_storage gadget: Number of LUNs=1
- lun0: LUN: removable file: (no medium)
-g_mass_storage gadget: Mass Storage Gadget, version: 2009/09/11
-g_mass_storage gadget: g_mass_storage ready
-usb device pull 1
-i2c /dev entries driver
-Unable to read RTP_REG_CHIP_VERSION reg
-rtp_mfd 0-0030: pre_init() failed: -140
-rtp_mfd: probe of 0-0030 failed with error -140
-Stopped watchdog timer
-timer margin: 8 sec
-nf_conntrack version 0.5.0 (759 buckets, 3036 max)
-ip_tables: (C) 2000-2006 Netfilter Core Team
-TCP: cubic registered
-NET: Registered protocol family 17
-Bluetooth: RFCOMM TTY layer initialized
-Bluetooth: RFCOMM socket layer initialized
-usb 1-1: new high-speed USB device number 2 using ehci-platform
-Bluetooth: RFCOMM ver 1.11
-Bluetooth: BNEP (Ethernet Emulation) ver 1.3
-Bluetooth: BNEP filters: protocol multicast
-Bluetooth: BNEP socket layer initialized
-Key type dns_resolver registered
-ALSA device list:
- No soundcards found.
-VFS: Mounted root (squashfs filesystem) readonly on device 31:8.
-Freeing unused kernel memory: 192K (804b0000 - 804e0000)
-usb 1-1: New USB device found, idVendor=0bda, idProduct=b720
-usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
-usb 1-1: Product: 802.11n WLAN Adapter
-usb 1-1: Manufacturer: Realtek
-usb 1-1: SerialNumber: 00e04c000001
-init started: BusyBox v1.22.1 (2018-06-06 03:10:44 CST)
-starting pid 54, tty '': '/etc/rc.d/rcS start'
-mount: mounting none on /proc/bus/usb failed: No such file or directory
-rm: can't remove '/dev/mtd9': No such file or directory
-mknod: /dev/console: File exists
-soc-audio soc-audio.0: ASoC: machine RLX_INTERN_CARD should use snd_soc_register_card()
-soc-audio soc-audio.0: rlx-codec-digital <-> pcm-platform mapping ok
-soc-audio soc-audio.0: rlx-codec-analog <-> pcm-platform mapping ok
-pinctrl_platform pinctrl_platform: request() failed for pin 0
-pinctrl_platform pinctrl_platform: pin-0 (pinctrl-rts:0) status -16
-request GPIO failed
-sd-platform: probe of rts3901-sdhc failed with error -16
-rtscam:rtscam_soc_probe
-rtscam:rtscam_hx280_probe
-rtscam:hx280enc:HW at base <0x18060000> with ID <0x48314810>
-rtscam:rtscam_jpgenc_probe
-rtscam:rtstream_init
-rtscam:begin to load fw from isp.fw
-rtscam:Load firmware size : 131072.
-rtscam:Found ISP 1.006 device
-rtscam:video device <rts3901-isp> registered
-rtscam:rts3901-isp initialized
-Setup db... ok.
-Startting dbd... Password for 'root' changed
-ok.
-set the date to default:
-Wed Jun 6 00:00:00 UTC 2018
-No SD Device Path Exists.
-rc.sysinit start ok.
-============ normal mode ===============
-dbd(181) is already running.
-Startting tz_dst... ok.
-setsystz ok
-Startting watchDog... ok.
-Startting avcd...
-mic vol = 80
-avcd ok.
-starting create_certificate...get server.pem... ok.
-Startting dbus-daemon... ok.
-Startting bluetoothd... sendCmd : 0
-Open /tmp/ap_list fail: No such file or directory
-main[283] Fail to get channel of Kjellerbod network
-configure :
- Wireless : essid: Kjellerbod, encryp_method: AES, auth_method: WPA2PSK
- Network : dhcp_enable: 1, hostname: DCS-8000LH
-Open /proc/sys/net/ipv6/conf/wlan0/autoconf fail: No such file or directory
-killall: rtspd: no process killed
-killall: udhcpc: no process killed
-killall: wifiAutoReconnect: no process killed
-sendCmd : 0
-sendCmd : 0
-/bin/sh: dibbler-client: not found
-killall: orthrus: no process killed
-killall: orthrusipv6: no process killed
-killall: pppd: no process killed
-killall: zcip: no process killed
-wlan1 MAC [b2:c5:54:4c:cc:73]
-23186 wpa_supplicant -B -c /tmp/wpa_supplicant.conf -i wlan0 -P /tmp/wpa_supplicant.pid
-rfkill: Cannot open RFKILL control device
-ioctl[SIOCSIWAP]: Operation not permitted
-udhcpc (v1.22.1) started
-/sbin/udhcpc.sh: line 1: /etc/rc.d/init.d/zcip.sh: not found
-Sending discover...
-Sending discover...
-Sending select for 192.168.2.37...
-Lease of 192.168.2.37 obtained, lease time 432000
-ifdown: interface wlan1 not configured
-cat: can't open '/tmp/wifi-led.pid': No such file or directory
-sh: you need to specify whom to kill
-deleting routers
-route: ioctl 0x890c failed: No such process
-adding dns 148.122.16.253
-adding dns 148.122.164.253
-start network services, ...
-Startting mDNSResponder... ok.
-Starting rtspd... ok.
-Startting ntpd... disabled.
-Startting firewall...ok.
-/etc/rc.d/rcS: /etc/rc.d/rcS.d/S24network.sh: line 5: /etc/rc.d/init.d/network_services_ipv6.sh: not found
-Starting Apple Darwin Multicast DNS / DNS Service Discovery daemon: mdnsd.
-Jun 6 02:00:32 mDNSResponder: mDNSResponder (Engineering Build) (Jun 6 2018 03:55:36) starting
-Jun 6 02:00:32 mDNSResponder: mDNS_AddDNSServer: Lock not held! mDNS_busy (0) mDNS_reentrancy (0)
-Jun 6 02:00:32 mDNSResponder: mDNS_AddDNSServer: Lock not held! mDNS_busy (0) mDNS_reentrancy (0)
-Jun 6 02:00:32 mDNSResponder: WARNING: mdnsd continuing as root because user "nobody" does not exist
-Startting ntpd... disabled.
-Startting db_analysis... ok.
-Startting firewall...ok.
-rtspd(1011 878) is already running.
-Startting myDlinkEvent... ok.
-2018-06-06 02:00:37 | INFO | tcp_listen | 176| listening 127.0.0.1:7000
-2018-06-06 02:00:37 | INFO | http_listen | 40| waiting new connections ...
-rc.local start ok.
-starting pid 1157, tty '': '/bin/busybox getty -L ttyS1 57600 vt100'
-
-localhost login: May 6 22:34:35 mDNSResponder: mDNS_Execute: mDNSPlatformRawTime went backwards by 438780374 ticks; setting correction factor to -1542198966
-May 6 22:34:37 mDNSResponderPosix: mDNSCoreReceive: mDNSPlatformRawTime went backwards by 438777274 ticks; setting correction factor to 1206127822
-```
-
-
-### <a name="Partitions"></a>Partitions
-
-The D-Link DCS-8000LH partitions are:
-```
-# cat /proc/mtd
-dev: size erasesize name
-mtd0: 00040000 00010000 "boot"
-mtd1: 00020000 00010000 "pib"
-mtd2: 00100000 00010000 "userdata"
-mtd3: 00020000 00010000 "db"
-mtd4: 00020000 00010000 "log"
-mtd5: 00020000 00010000 "dbbackup"
-mtd6: 00020000 00010000 "logbackup"
-mtd7: 00300000 00010000 "kernel"
-mtd8: 00b00000 00010000 "rootfs"
-```
-Or as seen by the driver with start and end addresses:
-
-```
-9 cmdlinepart partitions found on MTD device m25p80
-Creating 9 MTD partitions on "m25p80":
-0x000000000000-0x000000040000 : "boot"
-0x000000040000-0x000000060000 : "pib"
-0x000000060000-0x000000160000 : "userdata"
-0x000000160000-0x000000180000 : "db"
-0x000000180000-0x0000001a0000 : "log"
-0x0000001a0000-0x0000001c0000 : "dbbackup"
-0x0000001c0000-0x0000001e0000 : "logbackup"
-0x0000001e0000-0x0000004e0000 : "kernel"
-0x0000004e0000-0x000000fe0000 : "rootfs"
-```
-
-Partition usage:
-
- | number | name | start | end | size | fstype | contents |
- | ------ | ----------- | -------- | -------- | -------- | -------- | --------------- |
- | 0 | "boot" | 0x000000 | 0x040000 | 0x40000 | boot | U-Boot |
- | 1 | "pib" | 0x040000 | 0x060000 | 0x20000 | raw | device info |
- | 2 | "userdata" | 0x060000 | 0x160000 | 0x100000 | squashfs | mydlink (/opt) |
- | 3 | "db" | 0x160000 | 0x180000 | 0x20000 | tar.gz | non-volatile data |
- | 4 | "log" | 0x180000 | 0x1a0000 | 0x20000 | raw? | empty |
- | 5 | "dbbackup" | 0x1a0000 | 0x1c0000 | 0x20000 | tar.gz | copy of "db" |
- | 6 | "logbackup" | 0x1c0000 | 0x1e0000 | 0x20000 | raw? | empty |
- | 7 | "kernel" | 0x1e0000 | 0x4e0000 | 0x300000 | uImage | Linux 3.10 |
- | 8 | "rootfs" | 0x4e0000 | 0xfe0000 | 0xb00000 | squashfs | rootfs (/) |
-
-
-The D-Link firmware updates I have looked at will replace the
-"userdata", "kernel" and "rootfs" partitions, but leave other
-partitions unchanged. I imagine that the "boot" partition might be
-upgraded too if deemed necessary by D-Link. But it was not touched
-when going from 2.01.03 to 2.02.02.
-
-The "log" and "logbackup" appear to be currently unused. But I am
-reluctant trusting this, given their names. I guess they could be
-cleaned and overwritten anytime. They are too small to be very useful
-anyway. You can't put any writable file system om them with only two
-erase blocks.
-
-
-### Backing up dynamic data
-
-This is not necessary for system operation as any non-volatile data is
-saved in the [**db**](#Partitions) partition anyway. But it can still be useful to
-have a copy of the system state for offline studying, so I also like
-to save a working copy of /tmp:
-```
-tar zcvf /tmp/tmp.tgz /tmp/
-tftp -l /tmp/tmp.tgz -r tmp.tgz -p 192.168.2.1
-```
-
-
-### Why can we run the NIPCA webserver before we modify the firmware?
-
-D-Link left all the webserver parts in the firmware, including all the
-NIPCA CGI tools. The only change they made was disabling the startup
-script.
-
-The webserver can be enabled and started manually from the shell by
-running:
-
-```
-tdb set HTTPServer Enable_byte=1
-/etc/rc.d/init.d/extra_lighttpd.sh start
-```
-
-This is precisely what our Bluetooth tool does when it is called with
-the **--lighttpd** option.
-
-The `HTTPServer Enable_byte` is persistent, so setting is only
-necessary once. Unless you do a factory reset.
-
-
-### What's the problem with the RTSP server in the unmodified firmware?
-
-The original D-Link firmware is already running **rtspd**, but it is only
-listening on the loopback address 127.0.0.1. It is probably intended
-as a backend server for the **mydlink** services.
-
-We can make rtspd listen on all addresses by clearing the **RTPServer
-RejectExtIP** setting. Both rtspd and the firewall need a restart for
-this to have an effect. Enabling **RTPServer Authenticate** is
-probably a good idea when doing this, to prevent the camera from
-streaming to anyone who can connect.
-
-```
-tdb set RTPServer RejectExtIP_byte=0
-tdb set RTPServer Authenticate_byte=1
-/etc/rc.d/init.d/firewall.sh reload
-/etc/rc.d/init.d/rtspd.sh restart
-```
-
-These settings are persistent as usual, so they only need to be
-modified after factory resets. Changing the settings and then
-rebooting the camera will therefore enable remote RTSP access, since
-both services are running by default in the D-Link firmware.
-
-
-### The "userdata" file system
-
-The [**userdata**](#Partitions) you backed up as **mtd2** contains a xz compressed
-squasfs file system, with most of the mydlink cloud tools. The file
-system can be unpacked on a Linux system using unsquashfs:
-```
-$ unsquashfs mtd2
-Parallel unsquashfs: Using 4 processors
-15 inodes (22 blocks) to write
-
-[=============================================================================================================================================================================================================|] 22/22 100%
-
-created 12 files
-created 1 directories
-created 3 symlinks
-created 0 devices
-created 0 fifos
-$ ls -la squashfs-root/
-total 1156
-drwxr-xr-x 2 bjorn bjorn 340 Feb 14 10:58 .
-drwxrwxrwt 41 root root 2280 May 13 15:13 ..
--rwxr-xr-x 1 bjorn bjorn 13184 Feb 14 10:58 ca-refresh
--rwxr-xr-x 1 bjorn bjorn 273692 Feb 14 10:58 cda
-lrwxrwxrwx 1 bjorn bjorn 9 May 13 15:13 cert -> /tmp/cert
--rwxr-xr-x 1 bjorn bjorn 5991 Feb 14 10:58 client-ca.crt.pem
-lrwxrwxrwx 1 bjorn bjorn 7 May 13 15:13 config -> /tmp/db
--rwxr-xr-x 1 bjorn bjorn 436428 Feb 14 10:58 da_adaptor
--rwxr-xr-x 1 bjorn bjorn 4 Feb 14 10:58 dcp_version
--rwxr-xr-x 1 bjorn bjorn 814 Feb 14 10:58 device.cfg
-lrwxrwxrwx 1 bjorn bjorn 17 May 13 15:13 lib -> /var/libevent/lib
--rwxr-xr-x 1 bjorn bjorn 5 Feb 14 10:58 m2m
--rwxr-xr-x 1 bjorn bjorn 6220 Feb 14 10:58 mydlink_watchdog.sh
--rwxr-xr-x 1 bjorn bjorn 1034 Feb 14 10:58 opt.local
--rwxr-xr-x 1 bjorn bjorn 171828 Feb 14 10:58 sa
--rwxr-xr-x 1 bjorn bjorn 242028 Feb 14 10:58 strmsvr
--rwxr-xr-x 1 bjorn bjorn 10 Feb 14 10:58 version
-```
-
-The primary entry point here is the **opt.local** init-script. This
-is also the only required file. The **version** file is read by the
-Bluetooth API, and reported as the mydlink version, which makes it
-useful for verifying a modified camera. Our alternate
-[**userdata**](#Partitions) file system contains only these two
-files. But one could imagine including a number of other useful tools,
-like tcpdump, a ssh server etc.
-
-It is also possible to keep all the D-Link files, if that's
-wanted. The original **opt.local** script can be modified to leave
-mydlink support running while still starting other features. We could
-even add our own non-volatile setting to choose one or the other, or
-both, and making it a configuration thing. Fantasy is the only
-limiting factor.
-
-Repacking the files into a camera compatible squashfs file system:
-```
-mksquashfs squashfs-root mtd2.new -all-root -comp xz
-```
-
-Note that **xz** compression is required. No other compression is
-supported AFAIK.
-
-There are simpler ways to write the new file system to the camera than
-creating a firmware update package, if you just want to test it. One
-example:
-
-```
-tftp -r mtd2.new -l /tmp/mtd2.new -g 192.168.2.1
-cat /tmp/mtd2.new >/dev/mtdblock2
-```
-
-But DON'T do that unless you both have a backup and know what you are
-doing...
-
-You should reboot the camera after doing this, unless you make sure
-you stop any process running from the previous /opt system and remount
-it properly.
-
-
-### <a name="NIPCA"></a>Using NIPCA to manage the camera
-
-The local web server provides a direct camera management API, but not
-a web GUI application. All API requests require authentication. We
-have added a single admin user, using the pincode from the camera
-label as passord. More users can be adding if necessary, even by
-using the API itself.
-
-Read the NIPCA reference spec for usage, or look at the script names
-under **/var/www** in the [**rootfs**](#Partitions) and simply try
-them out. Most API endpoints return a list of current settings. Some
-of the settings can be set by GET requests by providing the new values
-as URL parameters.
-
-A few NIPCA references of different age:
- * http://gurau-audibert.hd.free.fr/josdblog/wp-content/uploads/2013/09/CGI_2121.pdf
- * https://docplayer.net/33354138-Network-ip-camera-application-programming-interface-nipca.html
- * ftp://ftp.dlink.net.pl/dcs/dcs-2132L/documentation/DCS-2132L_NIPCA_support table_1-9-5_20131211.pdf
- * https://www.airlivecam.eu/data/IP%20Camera%20Open%20API.doc
-
-Google for more. Be aware that a most of these settings depend on the
-hardware. There is obviously no point in trying to manage an SD card
-slot of the DCS-8000LH...
-
-A few of examples, using curl to read and set configuration variables:
-```
-$ curl -u admin:123456 http://192.168.2.37/common/info.cgi
-model=DCS-8000LH
-product=Wireless Internet Camera
-brand=D-Link
-version=2.02
-build=02
-hw_version=A
-nipca=1.9.7
-name=DCS-8000LH
-location=
-macaddr=B0:C5:54:AA:BB:CC
-ipaddr=192.168.2.37
-netmask=255.255.255.0
-gateway=192.168.2.1
-wireless=yes
-inputs=0
-outputs=0
-speaker=no
-videoout=no
-pir=no
-icr=yes
-ir=yes
-mic=yes
-led=no
-td=no
-playing_music=no
-whitelightled=no
-
-$ curl -u admin:123456 'http://192.168.2.37/config/datetime.cgi'
-method=1
-timeserver=ntp1.dlink.com
-timezone=1
-utcdate=2019-05-09
-utctime=13:25:14
-date=2019-05-09
-time=15:25:14
-dstenable=yes
-dstauto=yes
-offset=01:00
-starttime=3.2.0/02:00:00
-stoptime=11.1.0/02:00:00
-
-$ curl -u admin:123456 http://192.168.2.37/config/led.cgi?led=off
-led=off
-```
-
-Most camera settings can be controlled using this API and e.g curl for
-the command line. There are also packages implementing API clients,
-like for example this nodejs one: https://www.npmjs.com/package/nipca
-
-
-
-### Bluetooth LE GATT API
-
-The Bluetooth service is in a "locked" mode by default. This is
-controlled by the "Ble Mode" persistent setting stored in the **db**
-partition. If true ("1"), then most of the Bluetooth commands are
-rejected. But changing the setting manually will not help much, since
-the system automatically enter lock mode 180 seconds after the last
-Bluetooth client disconnected.
-
-The challenge -> response unlock method described below is much more
-useful.
-
-
-#### Converting the PIN Code to a Bluetooth unlock key
-
-Most Bluetooth commands are rejected when locked. Access to the full
-Bluetooth API can be unlocked by using the PIN Code printed on the
-camera label. This code is not sent directly over the air
-though. Instead it is combined with a random challenge.
-
-Both the random challenge and the matching key are generated by the
-application `sbin/gen_bt_config` on the camera side. The key is
-calculated by taking the first 16 bytes of the base64 encoded md5
-digest of
-
- * model string + '-' four last mac digits (or Bluetooth device name?)
- * PIN Code
- * challenge.
-
-Note that this application depends on bluetooth libraries, which are
-not in /lib. So we have to set LD\_LIBRARY\_PATH to run it manually:
-
-```
-# LD_LIBRARY_PATH=/var/bluetooth/lib sbin/gen_bt_config update_key_only
-In main:182: modelStr = 'DCS-8000LH'
-In main:183: mac = 'b0:c5:54:ab:cd:ef'
-In update_ble_key:87: key data = 'DCS-8000LH-CDEF012345b2gaescrbldchnik'
-```
-
-I've slightly obfuscated my data here - the pincode in the above case
-is `012345`, and the dynamically generated challenge is
-`b2gaescrbldchnik`. The generated challenge and key are stored in
-`/tmp/db/db.xml` and can be read directly from there:
-```
-# grep Key /tmp/db/db.xml |tail -2
-<ChallengeKey type="3" content="b2gaescrbldchnik" />
-<Key type="5" content="jrtY6nONQ5rV+2Ph" />
-```
-
-Or you can read them using the same tools the Bluetooth system uses:
-```
-# tdb get Ble ChallengeKey_ss
-b2gaescrbldchnik
-# mdb get ble_key
-jrtY6nONQ5rV+2Ph
-```
-
-Yes, the D-Link code does actually use tdb for the first one and mdb
-for the second. I have absolutely no idea why,... It is possible to
-read the key using tdb too:
-
-```
-# tdb get Ble Key_ss
-jrtY6nONQ5rV+2Ph
-```
-
-Generating the same key by hand on a Linux system is simple:
-
-```
-$ echo -n 'DCS-8000LH-CDEF012345b2gaescrbldchnik' | md5sum | xxd -r -p | base64 | cut -c-16
-jrtY6nONQ5rV+2Ph
-```
-
-#### Characteristic UUIDs
-
-D-Link is using the GATT BlueZ example plugin, patching it to add
-their camera specific endpoints. This means that we can find all the
-API "documentation" in the
-`DCS-8000LH-GPL/package/bluez_utils/feature-patch/5.28/customized-mydlink.patch`
-file in the GPL archive.
-
-This defines a number of 16bit UUIDs with mostly nonsense names:
-```
-+#define IPCAM_UUID 0xD001
-+#define A000_UUID 0xA000
-+#define A001_UUID 0xA001
-+#define A100_UUID 0xA100
-+#define A101_UUID 0xA101
-+#define A102_UUID 0xA102
-+#define A103_UUID 0xA103
-+#define A104_UUID 0xA104
-+#define A200_UUID 0xA200
-+#define A201_UUID 0xA201
-+#define A300_UUID 0xA300
-+#define A301_UUID 0xA301
-+#define A302_UUID 0xA302
-+#define A303_UUID 0xA303
-+#define A304_UUID 0xA304
-```
-
-
-`IPCAM_UUID` is registered as the `GATT_PRIM_SVC_UUID`, which means
-that it shows up as a primary GATT service we can look for when
-looking for a supported camera.
-
-The rest of the UUIDs are characteristics of this primary service. The
-API is based on reading or writing these characteristics.
-
-
-#### Data formatting
-
-Both input and output parameters are sent as ascii strings using
-key=value pairs joined by `;`, with an exception for the nested KV
-pairs in the WiFi survey results. All keys are single upper case
-characters. Key names are somewhat reused, so the exact meaning depend
-on the characteristic.
-
-Values are either integers, including boolean 0/1, or some set of
-ascii text.
-
-Three real examples, read from 0xA001, 0xA200 and 0xA104:
-```
-M=1;C=b2gaescrbldchnik
-N=DCS-8000LH;P=1;T=1557349762;Z=CET-1CEST,M3.5.0,M10.5.0/3;F=2.01.03;H=A1;M=B0C554ABCDEF;V=3.0.0-b71
-I=192.168.2.37;N=255.255.255.0;G=192.168.2.1;D=148.122.16.253
-```
-
-#### Listing characteristics
-
-
-The **gattool** Linux command line tool is useful for exploring
-Bluetooth LE devices. You can look for primary services and list
-associated characteristics of a service:
-```
-[B0:C5:54:AA:BB:CC][LE]> primary
-attr handle: 0x0001, end grp handle: 0x0008 uuid: 00001800-0000-1000-8000-00805f9b34fb
-attr handle: 0x0010, end grp handle: 0x0010 uuid: 00001801-0000-1000-8000-00805f9b34fb
-attr handle: 0x0011, end grp handle: 0x002e uuid: 0000d001-0000-1000-8000-00805f9b34fb
-[B0:C5:54:AA:BB:CC][LE]> characteristics 0x0011
-handle: 0x0012, char properties: 0x12, char value handle: 0x0013, uuid: 0000a000-0000-1000-8000-00805f9b34fb
-handle: 0x0015, char properties: 0x0a, char value handle: 0x0016, uuid: 0000a001-0000-1000-8000-00805f9b34fb
-handle: 0x0017, char properties: 0x02, char value handle: 0x0018, uuid: 0000a100-0000-1000-8000-00805f9b34fb
-handle: 0x0019, char properties: 0x0a, char value handle: 0x001a, uuid: 0000a101-0000-1000-8000-00805f9b34fb
-handle: 0x001b, char properties: 0x08, char value handle: 0x001c, uuid: 0000a102-0000-1000-8000-00805f9b34fb
-handle: 0x001d, char properties: 0x02, char value handle: 0x001e, uuid: 0000a103-0000-1000-8000-00805f9b34fb
-handle: 0x001f, char properties: 0x02, char value handle: 0x0020, uuid: 0000a104-0000-1000-8000-00805f9b34fb
-handle: 0x0021, char properties: 0x0a, char value handle: 0x0022, uuid: 0000a200-0000-1000-8000-00805f9b34fb
-handle: 0x0023, char properties: 0x08, char value handle: 0x0024, uuid: 0000a201-0000-1000-8000-00805f9b34fb
-handle: 0x0025, char properties: 0x0a, char value handle: 0x0026, uuid: 0000a300-0000-1000-8000-00805f9b34fb
-handle: 0x0027, char properties: 0x02, char value handle: 0x0028, uuid: 0000a301-0000-1000-8000-00805f9b34fb
-handle: 0x0029, char properties: 0x08, char value handle: 0x002a, uuid: 0000a302-0000-1000-8000-00805f9b34fb
-handle: 0x002b, char properties: 0x08, char value handle: 0x002c, uuid: 0000a303-0000-1000-8000-00805f9b34fb
-handle: 0x002d, char properties: 0x02, char value handle: 0x002e, uuid: 0000a304-0000-1000-8000-00805f9b34fb
-```
-
-It is also possible to read and write characteristics using this tool,
-but this can be a bit cumbersome unless you are fluent in ASCII coding
-;-)
-
-
-
-#### The IPCam characteristics
-
-Guessed meanings of each characteristic, based on the source code and
-some trial and error. Not necessarily how D-Link would describe them:
-
-
-| UUID | op | description | format | keys |
-| ---- | ------ | --------------- | --------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
-| A000 | read | last status | C=%d;A=%d;R=%d | C: uuid, A: mode, R: state |
-| A000 | notify | last status | C=%d;A=%d;R=%d | C: uuid, A: mode, R: state |
-| A001 | read | challenge | M=%d;C=%s | M: opmode, C: challenge |
-| A001 | write | auth | M=%d;K=%s | M: opmode, K: key |
-| A100 | read | wifi survey | N=%d;P=%d;... | |
-| A101 | read | wifi config | M=%s;I=%s;S=%s;E=%s | M: opmode, I: essid, S: 4 , E: 2 |
-| A101 | write | wifi config | M=%s;I=%s;S=%s;E=%s;K=%s | M: opmode, I: essid, S: 4 , E: 2, K: password |
-| A102 | write | wifi connect | C=%d | C: connect (0/1) |
-| A103 | read | wifi status | S=%d | S: wifi link status (0,1,?) |
-| A104 | read | ip config | I=%s;N=%s;G=%s;D=%s | I: address, N: netmask, G: gateway, D: DNS-server |
-| A200 | read | system info | N=%s;P=%d;T=%d;Z=%s;F=%s;H=%s;M=%s;V=%s | N: devicename, P: haspin (0/1), T: time (unix epoch), Z: timezone, F: fwver, H: hwver, M: macaddr, V:mydlinkver |
-| A200 | write | name and time | N=%s;T=%d;Z=%s | N: devicename, T: time (unix epoch), Z: timezone |
-| A201 | write | admin password | P=%s;N=%s | P: current password, N: new password |
-| A300 | read | reg state | G=%d | G: registration state (0/1) |
-| A300 | write | reg state | G=%d | G: registration state (0/1) |
-| A301 | read | provisioning | N=%s;T=%s;U=%s | N: username, T: footprint, U: portal |
-| A302 | write | restart mydlink | C=%d | C: restart (0/1) |
-| A303 | write | register | S=%s;M=%s | S: , M: (written to /tmp/mydlink/reg_info, and then kill -USR1 `pidof da_adaptor`) |
-| A304 | read | register | S=%d;E=%d | S: , E: (cat /tmp/mydlink/reg_st) |
-
-
-The UUIDs from 0xA300 to 0xA304 are all related to the mydlink cloud
-service, and therefore not of much use to us. I haven't bothered
-trying to figure out exactly how they are used.
-
-We could in theory use the 0xA303 request which simply calls
-**/opt/opt.local restart**. But with the gaping 0xA201 hole,
-allowing **any** command, there isn't much need for this one...
-
-A few more details on the more complex characteristics:
-
-
-##### A000
-
-The only characteristic sent as notifications. But it can also be
-read directly for syncronous operations.
-
-The value is the state to the last Bluetooth action:
-
- "C=%d;A=%d;R=%d", last_action_status.uuid, last_action_status.mode, last_action_status.state
-
-
-##### A100
-
-The wifi survey scan results are split in 128 byte "pages", where each
-page starts with the total number of pages and the current page
-number. The characteristic value must be read as many times as the
-given total.
-
-For example, reading 3 pages:
-```
-[B0:C5:54:AA:BB:CC][LE]> char-read-hnd 0x0018
-Characteristic value/descriptor: 4e 3d 33 3b 50 3d 31 3b 4c 3d 49 3d 41 6e 74 69 62 6f 6b 73 2c 4d 3d 30 2c 43 3d 36 2c 53 3d 34 2c 45 3d 32 2c 50 3d 36 32 26 4c 3d 49 3d 41 53 56 31 37 2c 4d 3d 30 2c 43 3d 31 31 2c 53 3d 34 2c 45 3d 32 2c 50 3d 34 36 26 4c 3d 49 3d 41 53 56 31 37 2d 64 6c 69 6e 6b 2c 4d 3d 30 2c 43 3d 36 2c 53 3d 34 2c 45 3d 32 2c 50 3d 36 38 26 4c 3d 49 3d 66 6a 6f 72 64 65 31 32 33 2c 4d 3d 30
-[B0:C5:54:AA:BB:CC][LE]> char-read-hnd 0x0018
-Characteristic value/descriptor: 4e 3d 33 3b 50 3d 32 3b 2c 43 3d 31 2c 53 3d 34 2c 45 3d 32 2c 50 3d 35 38 26 4c 3d 49 3d 4a 4f 4a 2c 4d 3d 30 2c 43 3d 31 31 2c 53 3d 34 2c 45 3d 32 2c 50 3d 34 37 26 4c 3d 49 3d 4b 6a 65 6c 6c 65 72 62 6f 64 2c 4d 3d 30 2c 43 3d 36 2c 53 3d 34 2c 45 3d 32 2c 50 3d 36 32 26 4c 3d 49 3d 6d 67 6d 74 2c 4d 3d 30 2c 43 3d 31 2c 53 3d 34 2c 45 3d 32 2c 50 3d 37 34 26 4c 3d 49 3d 52 69
-[B0:C5:54:AA:BB:CC][LE]> char-read-hnd 0x0018
-Characteristic value/descriptor: 4e 3d 33 3b 50 3d 33 3b 6e 64 65 64 61 6c 2c 4d 3d 30 2c 43 3d 31 31 2c 53 3d 34 2c 45 3d 32 2c 50 3d 36 32
-```
-
-These strings are decoded as:
-```
-N=3;P=1;L=I=Antiboks,M=0,C=6,S=4,E=2,P=62&L=I=ASV17,M=0,C=11,S=4,E=2,P=46&L=I=ASV17-dlink,M=0,C=6,S=4,E=2,P=68&L=I=fjorde123,M=0
-N=3;P=2;,C=1,S=4,E=2,P=58&L=I=JOJ,M=0,C=11,S=4,E=2,P=47&L=I=Kjellerbod,M=0,C=6,S=4,E=2,P=62&L=I=mgmt,M=0,C=1,S=4,E=2,P=74&L=I=Ri
-N=3;P=3;ndedal,M=0,C=11,S=4,E=2,P=62
-```
-
-Which, when joined after removing the N/P paging info, becomes::
-```
-L=I=Antiboks,M=0,C=6,S=4,E=2,P=62&L=I=ASV17,M=0,C=11,S=4,E=2,P=46&L=I=ASV17-dlink,M=0,C=6,S=4,E=2,P=68&L=I=fjorde123,M=0,C=1,S=4,E=2,P=58&L=I=JOJ,M=0,C=11,S=4,E=2,P=47&L=I=Kjellerbod,M=0,C=6,S=4,E=2,P=62&L=I=mgmt,M=0,C=1,S=4,E=2,P=74&L=I=Rindedal,M=0,C=11,S=4,E=2,P=62
-```
-
-And after splitting this on & we get the final result:
-```
-L=I=Antiboks,M=0,C=6,S=4,E=2,P=62
-L=I=ASV17,M=0,C=11,S=4,E=2,P=46
-L=I=ASV17-dlink,M=0,C=6,S=4,E=2,P=68
-L=I=fjorde123,M=0,C=1,S=4,E=2,P=58
-L=I=JOJ,M=0,C=11,S=4,E=2,P=47
-L=I=Kjellerbod,M=0,C=6,S=4,E=2,P=62
-L=I=mgmt,M=0,C=1,S=4,E=2,P=74
-L=I=Rindedal,M=0,C=11,S=4,E=2,P=62
-```
-
-So each L entry is made up of the same set of keys:
-
- * I: essid
- * M: opmode? or authalg? (always 0 in the sample)
- * C: channel (2.4 GHz only)
- * S: key_mgmt/auth_alg/proto?
- * E: key_mgmt/auth_alg/proto?
- * P: relative signal. Higher is better. dBm + 100?
-
-Still need to figure out the mapping of the M,S,E keys to
-wpa_supplicant config settings. I assume they represent enums. But we
-can simply treat them as opaque values since we only use the survey
-data to help setup WiFi anyway. We copy these to the setup request,
-and do not need to know what they mean.
-
-
-FWIW, my example setting `M=0;I=Kjellerbod;S=4;E=2`
-is mapped to this wpa_supplicant configuration:
-```
-# cat /tmp/wpa_supplicant.conf
-ctrl_interface=/var/run/wpa_supplicant
-device_type=4-0050F204-3
-model_name=DCS-8000LH
-manufacturer=D-Link
-os_version=01020300
-config_methods=push_button virtual_push_button
-eapol_version=1
-network={
- scan_ssid=1
- ssid="Kjellerbod"
- key_mgmt=WPA-PSK
- auth_alg=OPEN
- proto=RSN
- psk="redeacted"
-}
-```
-
-##### A201
-
-This write request allows setting an admin password, used for example
-by the webserver. It takes the old and new passwords as unencoded
-input, verifies that the old password matches, and then change the
-admin password to the provided new one.
-
-The initial password is empty, which prevents webserver
-authentication. Simply provide an empty string for the old password in
-the first request: **P=;N=newpassword**
-
-But this request is much more useful in other ways.... The new passord
-(N_str) is processed like this (after slight compression of the
-interesting code lines):
-
-```C
- snprintf(cmd, sizeof(cmd), "mdb set admin_passwd %s", N_str);
- snprintf(cmdbuf, sizeof(cmdbuf), "%s > %s 2>&1", cmd, p_name);
- fp = popen(cmdbuf, "r");
-```
-
-You don't have to be a security expert to see the problem here. But
-one mans bug is another mans feature :-)
-
-
-##### A303
-
-The two strings S and M are url decoded and checked for special
-characters. Then the **orginal** url encoded strings are written to
-**/tmp/mydlink/reg_info** and SIGUSR1 is sent to the **da_adaptor**
-process. Presumably triggering it to reread the reg_info file.
-
-It is pretty safe to assume that this provides some registration info
-to the mydlink system, allowing it to connect to the cloud service.
-
-The set of allowed characters is rather interesting:
-```
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
-```
-
-Which initially made me think that this was an obvious security hole,
-since I missed the point that it's the url encoded strings that are
-used on the command line.
-
-But given the quality of the rest of the code here, I would be very
-surprised if there isn't an issue or ten in the da_adaptor code
-allowing this to be abused. It's just a bit harder to figure out
-without the source code.
-
-
-
-#### Manually restarting bluetoothd for debugging
-
-It can be useful to run bluetoothd in the foreground when debugging
-BLE interaction, or testing modified versions of bluetoothd. Log in
-using telnet or serial and simply stop and restart bluetoothd with the
--d and -n options:
-
-```
-# /etc/rc.d/init.d/bluetoothd.sh stop
-Stopping bluetoothd... ok.
-# LD_LIBRARY_PATH=/var/bluetooth/lib /var/bluetooth/bin/bluetoothd -d -n -E -p "gatt,gatt_example"
-bluetoothd[25020]: Bluetooth daemon 5.28
-bluetoothd[25020]: src/main.c:parse_config() parsing main.conf
-bluetoothd[25020]: src/main.c:parse_config() discovto=0
-bluetoothd[25020]: src/main.c:parse_config() pairto=0
-bluetoothd[25020]: src/main.c:parse_config() auto_to=3600
-bluetoothd[25020]: src/main.c:parse_config() name=DCS-8000LH-CDEF
-bluetoothd[25020]: src/main.c:parse_config() Key file does not have key 'Class'
-bluetoothd[25020]: src/main.c:parse_config() Key file does not have key 'DeviceID'
-bluetoothd[25020]: src/main.c:parse_config() Key file does not have key 'ReverseServiceDiscovery'
-bluetoothd[25020]: src/main.c:parse_config() ControllerMode=le
-bluetoothd[25020]: src/gatt.c:gatt_init() Starting GATT server
-bluetoothd[25020]: src/adapter.c:adapter_init() sending read version command
-bluetoothd[25020]: Starting SDP server
-bluetoothd[25020]: src/sdpd-service.c:register_device_id() Adding device id record for 0002:1d6b:0246:051c
-etc.
-```
-
-Note that the GATT GAP service will only pick up the device name
-whenever it is set. This causes an empty Device Name characteristic
-(0x2a00) after restarting bluetoothd.
-
-The name must therefore be changed and set again after every
-bluetoothd restart as a workaround:
-
-```
-/var/bluetooth/bin/hciconfig hci0 name foo
-/var/bluetooth/bin/hciconfig hci0 name DCS-8000LH-CDEF
-```
-
-
-### Firmware updates
-
-There are at least two shell scripts providing a firmware update
-service in the D-Link firmware:
-
- * /var/www/config/firmwareupgrade.cgi
- * /sbin/fwupdate
-
-They are both pretty similar and obviously come from the same source.
-The main difference is that firmwareupgrade.cgi provides the NIPCA
-firmwareupgrade service, while fwupdate is a command line tool.
-
-The web service is most interesting for us, providing both the upload
-and upgrade in one simple tool. The fwupdate tool is used by the
-mydlink cloud tool **da_adaptor** , via an fw_upgrade symlink.
-
-
-#### Downloading the latest OEM firmware
-
-The mydlink tools will set up two URLs in `/tmp/db/device.cf`:
-```
- "FirmwareDaemonURL": "http://mp-eu-fwd.auto.mydlink.com:80/fw-upgrade",
- "SecuredFirmwareDaemonURL": "https://mp-eu-fwd.auto.mydlink.com:443/fw-upgrade",
-```
-
-Calling either one of these with a model parameter will return a
-download URL for the latest firmware version. Examples:
-
-```
-$ curl -D - http://mp-eu-fwd.auto.mydlink.com:80/fw-upgrade?model=DCS-8000LH
-HTTP/1.1 200 OK
-Date: Sun, 27 Oct 2019 16:27:24 GMT
-Content-Length: 280
-Etag: "9a475c16361db8ba3ebfe679554680dbb6bf2c38"
-Content-Type: text/html; charset=UTF-8
-Server: TornadoServer/5.1.1
-
-{"code": 0, "fw_ver_type": "REGULAR", "process_time": 210, "main_board": {"url": "http://mydlinkmpfw.auto.mydlink.com/DCS-8000LH/DCS-8000LH_Ax_v2.03.02_3412.bin", "fw_version": "2.03.02", "md5": "3e26e96fcd8fcf711c1362a4cbfb2d48"}, "release_version": "3.2.7-b02", "device_id": ""}
-```
-
-
-```
-$ curl -D - 'https://mp-eu-fwd.auto.mydlink.com:443/fw-upgrade?model=DCS-8100LH'
-HTTP/1.1 200 OK
-Date: Sun, 27 Oct 2019 16:35:39 GMT
-Content-Length: 281
-Etag: "5714f3e62ca04e5c3465705cb4c7356f1d50e54f"
-Content-Type: text/html; charset=UTF-8
-Server: TornadoServer/5.1.1
-
-{"code": 0, "fw_ver_type": "REGULAR", "process_time": 210, "main_board": {"url": "https://mydlinkmpfw.auto.mydlink.com/DCS-8100LH/DCS-8100LH_Ax_v2.04.01_3619.bin", "fw_version": "2.04.01", "md5": "eb097a680754b94b81da6326b468121f"}, "release_version": "3.2.7-b03", "device_id": ""}
-```
-
-Download and verify the md5 sum:
-
-```
-$ curl -O https://mydlinkmpfw.auto.mydlink.com/DCS-8100LH/DCS-8100LH_Ax_v2.04.01_3619.bin
- % Total % Received % Xferd Average Speed Time Time Time Current
- Dload Upload Total Spent Left Speed
-100 19.5M 100 19.5M 0 0 2457k 0 0:00:08 0:00:08 --:--:-- 2727k
-
-$ md5sum DCS-8100LH_Ax_v2.04.01_3619.bin
-eb097a680754b94b81da6326b468121f DCS-8100LH_Ax_v2.04.01_3619.bin
-```
-
-
-#### Signed and encrypted
-
-Looking at the contents of a firmware update from D-Link can be
-demotivating at the beginning:
-
-```
-$ tar xvf DCS-8000LH_Ax_v2.02.02_3014.bin
-update.bin.aes
-update.aes
-aes.key.rsa
-certificate.info
-sign.sha1.rsa
-
-$ file *
-aes.key.rsa: data
-certificate.info: ASCII text
-sign.sha1.rsa: data
-update.aes: data
-update.bin.aes: data
-
-$ ls -l
-total 10956
--rw-r--r-- 1 bjorn bjorn 128 Feb 14 10:58 aes.key.rsa
--rw-r--r-- 1 bjorn bjorn 130 Feb 14 10:58 certificate.info
--rw-r--r-- 1 bjorn bjorn 128 Feb 14 10:58 sign.sha1.rsa
--rw-r--r-- 1 bjorn bjorn 10268368 Feb 14 10:58 update.aes
--rw-r--r-- 1 bjorn bjorn 936464 Feb 14 10:58 update.bin.aes
-```
-
-So all the interesting stuff is AES encrypted, and the AES key is RSA
-encrypted. The only directly readable file is this one, and it
-doesn't tell us much:
-
-```
-$ cat certificate.info
-Publisher:DMdssdFW1
-Supported Models:DCS-8000LH,DCS-8000LH
-Firmware Version:1.0.0
-Target:update.bin
-Build No:3014
-Contents:update
-```
-
-Not much we can do about this then. Or so it seems... Until we look
-at **firmwareupgrade.cgi**, or **fwupdate** which has almost the same
-code:
-
-```sh
-verifyFirmware() {
- result=uploadSign
- #tar tf "$UPLOADBIN" > /dev/null 2> /dev/null || return 1
- fw_sign_verify.sh "$UPLOADBIN" /etc/db/verify.key > /dev/null 2> /dev/null || return 1
- return 0
-}
-
-decryptFirmware() {
- result=uploadDecrypt
- pibinfo PriKey > $dir/decrypt.key 2> /dev/null
- fw_decrypt.sh $dir/decrypt.key $out > /dev/null 2> /dev/null || return 1
- return 0
-}
-```
-
-Can it be that simple? Yes, it is.
-
-Looking further at the **fw_sign_verify.sh** and **fw_decrypt.sh**,
-used by both update tools, confirms it. The firmware is verified by
-using the RSA public key in **/etc/db/verify.key** to decrypt the hash
-in **sign.sha1.rsa**. Then it is decrypted using a key from the
-factory data **pib** partition.
-
-
-
-#### Further unpacking the firmware update
-
-So we have the keys and the hashing algorithms we need to both verify
-and decrypt this firmware. We can run the commands found in
-**fw_decrypt.sh** to get the real contents (slightly adapted to modern
-openssl versions):
-
-```
-$ openssl rsautl -decrypt -in aes.key.rsa -inkey decrypt.key -out aes.key
-
-$ openssl aes-128-cbc -v -md md5 -kfile aes.key -nosalt -d -in update.bin.aes -out update.bin
-bufsize=8192
-*** WARNING : deprecated key derivation used.
-Using -iter or -pbkdf2 would be better.
-bytes read : 936464
-bytes written: 936454
-
-$ openssl aes-128-cbc -v -md md5 -kfile aes.key -nosalt -d -in update.aes -out update
-bufsize=8192
-*** WARNING : deprecated key derivation used.
-Using -iter or -pbkdf2 would be better.
-bytes read : 10268368
-bytes written: 10268355
-
-$ file update.bin update
-update.bin: POSIX shell script, ASCII text executable
-update: data
-```
-
-OK, the **update** file is still in an unknown format, but at least
-we have the tool used to write it to the system. And it is a shell
-script, so we have the source to look at too! But 936454 bytes is a
-hell of a shell script, and this is of course because most of it is an
-uuencoded binary. So we don't know exactly what that does. But it is
-named ddPack so a fair guess is that it is a tool for dd'ing multiple
-file systems or other images packed as a single file. That's really
-enough info.
-
-binwalk shows that the **update** file is just two squashfs systems
-and a kernel, with a 1024 header of some sort. The header presumably
-tells ddPack how it should apply these three images:
-
-```
-$ binwalk update
-
-DECIMAL HEXADECIMAL DESCRIPTION
---------------------------------------------------------------------------------
-1024 0x400 Squashfs filesystem, little endian, version 4.0, compression:xz, size: 338755 bytes, 16 inodes, blocksize: 131072 bytes, created: 2019-02-14 09:58:28
-340992 0x53400 uImage header, header size: 64 bytes, header CRC: 0x675F081D, created: 2019-02-14 09:31:53, image size: 1661571 bytes, Data Address: 0x804D4960, Entry Point: 0x804D4960, data CRC: 0x73083021, OS: Linux, CPU: MIPS, image type: OS Kernel Image, compression type: none, image name: "linux_3.10"
-2002627 0x1E8EC3 Squashfs filesystem, little endian, version 4.0, compression:xz, size: 8265620 bytes, 2145 inodes, blocksize: 131072 bytes, created: 2019-02-14 09:58:45
-```
-
-But we can easily guess that without knowing anything about the
-header. There is only one alternative:
- * The kernel goes into the **kernel** partition
- * The 8265620 bytes squasfs system goes into the **rootfs** partition
- * The remaining squasfs system goes into the **userdata** partition
-
-So there is no need to analyze ddPack. We have the necessary entry
-points for **fwupdate** or **firmwareupgrade.cgi** in the
-**update.bin** script, and that's what we needed to know for the next
-step:
-
-
-#### Creating our own firmware updates
-
-We do have shell access, so we can simply write the file systems we
-want to flash as shown earlier. We don't need to use the D-Link
-scripts. But where's the fun in that?
-
-There is one challenge here: The D-Link tools are expecting signed and
-encrypted firmware updates. They will run their verifyFirmware() and
-decryptFirmware() functions, and fail the update if any of the returns
-an error.
-
-But bailing out on verification errors is only the default setting, as
-illustrated by this code from **fwupdate** (there is code with similar
-functionality in **firmwareupgrade.cgi**):
-
-
-```sh
- TrustLevel=`tdb get SecureFW _TrustLevel_byte`
- verifyFirmware
- ret=$?
- case $ret in
- 2)
- sign="not_signed"
- ;;
- 0)
- sign="trust"
- ;;
- *)
- sign="untrust"
- ;;
- esac
- if [ "$do_up" = "1" -a "$ret" != "0" -a "$TrustLevel" = "1" ]; then
- echo "3"
- return 1
- fi
-```
-
-So we don't need to sign the firmware if we change the **SecureFW
-_TrustLevel** setting. Or we can even sign it with a key unknown to
-the camera if we like. Which can be useful if we ever replace the
-[**rootfs**]](#Partitions), since it will allow us to install our own verification
-key and use it with D-Links tools.
-
-But what about the encryption? This cannot be disabled. This gets
-even better: The decrypting key so graciously provided to us in the
-[**pib**](#Partitions) partition is an RSA private key. So not only can we decrypt
-the firmware with it, but we can also encrypt! Nice.
-
-
-The [**Makefile**](Makefile) in this repo has examples of how to use this to
-create firmware update images which are accepted by the **fwupdate**
-and **firmwareupgrade.cgi** tools. It uses an alternatative
-[**update.bin**](update.sh) made to modify only the [**userdata**](#Partitions) partition. This
-way we can install our own code in the camera, but still leave the
-D-Link camera OS unmodified.
-
-
-#### <a name="BuildFirmware"></a>Bulding the example firmware update in this repo
-
-Rebuilding the example is as easy as typing **make**. The Makefile is a
-noisy one, so you can see all that's going on:
-```
-$ make
-echo "WARNING: keys/DCS-8000LH-sign.pem is missing - using a new abitrary key instead"
-WARNING: keys/DCS-8000LH-sign.pem is missing - using a new abitrary key instead
-[ -f random-signkey.pem ] || openssl genrsa -out random-signkey.pem
-Generating RSA private key, 2048 bit long modulus (2 primes)
-...............................................................................................................................+++++
-........................................................................................................................................................+++++
-e is 65537 (0x010001)
-openssl rsa -pubout -in random-signkey.pem -out verify.key
-writing RSA key
-echo "Publisher:DMdssdFW1" >certificate.info
-echo "Supported Models:DCS-8000LH,DCS-8000LH" >>certificate.info
-echo "Firmware Version:1.0.0" >>certificate.info
-echo "Target:update.bin" >>certificate.info
-echo "Build No:9999" >>certificate.info
-echo "Contents:update" >>certificate.info
-openssl rand 16 > aes.key
-openssl rsautl -encrypt -in aes.key -inkey keys/DCS-8000LH-PriKey.pem -out aes.key.rsa
-sed -ne 's/"//g' -e 's/^VERSION *= *//p' dcs8000lh-configure.py >version
-mksquashfs version opt.local opt.squashfs -all-root -comp xz
-Parallel mksquashfs: Using 4 processors
-Creating 4.0 filesystem on opt.squashfs, block size 131072.
-[===============================================================================================================================================================================================================|] 2/2 100%
-
-Exportable Squashfs 4.0 filesystem, xz compressed, data block size 131072
- compressed data, compressed metadata, compressed fragments, compressed xattrs
- duplicates are removed
-Filesystem size 1.08 Kbytes (0.00 Mbytes)
- 60.69% of uncompressed filesystem size (1.79 Kbytes)
-Inode table size 98 bytes (0.10 Kbytes)
- 100.00% of uncompressed inode table size (98 bytes)
-Directory table size 46 bytes (0.04 Kbytes)
- 100.00% of uncompressed directory table size (46 bytes)
-Number of duplicate files found 0
-Number of inodes 3
-Number of files 2
-Number of fragments 1
-Number of symbolic links 0
-Number of device nodes 0
-Number of fifo nodes 0
-Number of socket nodes 0
-Number of directories 1
-Number of ids (unique uids + gids) 1
-Number of uids 1
- root (0)
-Number of gids 1
- root (0)
-openssl aes-128-cbc -md md5 -kfile aes.key -nosalt -e -out update.aes -in opt.squashfs
-*** WARNING : deprecated key derivation used.
-Using -iter or -pbkdf2 would be better.
-*** WARNING : deprecated key derivation used.
-Using -iter or -pbkdf2 would be better.
-sed -e "s/@@MODEL@@/\"DCS-8000LH\"/" -e "s/@@MD5SUM@@/\"f1a1d3952c1630e5adb53e7f93b59d5e\"/" -e "s/@@VERSION@@/\"1.0.0-9999\"/" update.sh >update.bin
-openssl aes-128-cbc -md md5 -kfile aes.key -nosalt -e -out update.bin.aes -in update.bin
-*** WARNING : deprecated key derivation used.
-Using -iter or -pbkdf2 would be better.
-openssl dgst -sha1 update.aes | cut -d' ' -f2 > update.sha1
-cat update.bin.aes aes.key.rsa certificate.info update.sha1 | openssl dgst -sha1 | cut -d' ' -f2 > sign.sha1
-openssl rsautl -sign -inkey random-signkey.pem -out sign.sha1.rsa -in sign.sha1
-tar cvf fw.tar certificate.info aes.key.rsa sign.sha1.rsa update.aes update.bin.aes verify.key
-certificate.info
-aes.key.rsa
-sign.sha1.rsa
-update.aes
-update.bin.aes
-verify.key
-
-```
-
-This will produce a new **fw.tar** firmware update image.
-
-
-## Contact
-
-
-Please contact me on bjorn@mork.no if you have questions, comments or
-just want to say hi.
-
-But please note that I won't be able to provide any support for this.
-I am making this information available for educational purposes. If
-you find it useful, then great! If you brick a camera, then I am
-truly sorry about that. But there isn't much I can do about it....