Open-Source Firmware for the D-Link DIR-652 Wlan Router
I recently got my new, shiny, fast internet connection from Kabel Deutschland. Along with it came a new home router, the DIR-652, which does Wlan b, g, n, and probably other letters, which means it can move more bits in less time. Cool.
When I opened the box, the first thing I saw was a "WRITTEN OFFER FOR GPL AND LGPL SOURCE CODE". They really printed the whole GPL on paper :) And there was a download link to the firmware code. Cool!
Downloading
After enabling JavaScript, you have to click an "I Agree"-Button on a page displaying some information about the GPL, EULA-Style, which felt kind of weird. After typing in the product name (and closing a "Register your Product" popup) the file for the DIR-652 firmware is easily found. The server only gave me about 50 kilobytes per second and didn't support parallel downloads, so the 780MB download went rather slow. (I later found out that you can also get the code from a (slightly) faster server.)
Using the source
Building the firmware image is rather straightforward. The GPL/README file includes instructions on how to do it. Basically, it's the usual "make menuconfig", which presents you with menus for the Ubicom configuration first, and then runs the menu config for the distribution you select. There are 2 options for the distribution: uClinux is the default, which I used, but apparently you can also choose OpenWRT. After configuring, you run "make".
Uploading
If everything worked, you will get the firmware image in SRC/ubicom-distro/bin/DIR-652_upgrade.bin, which is ready for uploading with the router's web interface, or the Ubicom Dongle if you have such a thing. I don't have the dongle (and I didn't want to open the case to see if I could use the serial interface), so I used the web interface. Click on Tools -> Firmware, choose the firmware file, click Upload. You can actually still use the net connection most of the time while the upload/flashing is running. After a while, the router will reboot.
Everything Works... Almost
After first configuring & uploading, everything seemed to work, so I was happy I hadn't bricked the thing. :-) The web interface came up, net connection worked too. Including wireless... After a while, I noticed the wireless network was open, although it was configured to use 'WPA2 Only' (which I double-checked). There was no error message, nothing to see in the logs, the network just wasn't encrypted.
I didn't want to run an open wireless network, so I figured I could log into the router via SSH and try to fix it from there, or at least find out what was wrong. (And I wanted SSH built in anyway.)
Enabling SSH support
To configure userland applications, you have to check [*] Run distro menuconfig in the Ubicom Distro Configuration. In the uClinux Distro config, enable Kernel/Library/Defaults Selection ---> [*] Customize Application/Library Settings. Don't choose Customize Module Settings as that doesn't seem to work.
The uClinux distro includes two SSH servers. There is sshd, which as described in the help text "is the openssh variant and supports ssh v1 and ssh v2", and adds about 580k binary size. I opted for dropbear, which is a smaller variant and only adds about 100k. Both can be selected in the uClinux distro config in the Network Applications submenu.
After saving your config, you just run "make", and your image including your new applications gets built. Or so I thought. Actually, parts of the distribution you get, such as the embedded C library uClibc, are rather old. As a result, many optional things will not build out of the box. In the case of dropbear, a header file "utmpx.h" was missing from uClibc, which seems to have been a known bug/omission some years ago. I pulled the missing file from a newer version of the uClibc repository and dropped it into SRC/ubicom-distro/uClinux/uClibc/include. After that, dropbear built fine.
To run properly, dropbear also needs a Host Key which identifies the host to its clients. The install script wants the key files in dropbear's source directory. To generate the keys and place them there, the 'dropbearkey' tool has to be used:
~/src/DIR652A1_FW100b33_GPL/SRC/ubicom-distro$ dropbearkey -t dss -f dropbear_dss_host_key
Will output 1024 bit dss secret key to 'dropbear_dss_host_key'
Generating key, this may take a while...
Public key portion is:
[...]
~/src/DIR652A1_FW100b33_GPL/SRC/ubicom-distro$ dropbearkey -t rsa -f dropbear_rsa_host_key
[...]
~/src/DIR652A1_FW100b33_GPL/SRC/ubicom-distro$ cp dropbear_* uClinux/user/dropbear/
Dropbear also supports key-based authentication. I wanted to be able to log in without having to type a password, so I placed my public SSH keys in SRC/ubicom-distro/uClinux/romfs/root/.ssh/authorized_keys. (The distro might support users other than root but I didn't bother adding any. If I log into the router, I mostly will want to do stuff that needs superuser rights anyway.)
Logging In
After rebuilding&uploading, the dropbear daemon greeted me with a nice, company-branded ASCII art screen. :-)
$ ssh root@router
The authenticity of host 'router (192.168.0.1)' can't be established.
RSA key fingerprint is xxxxxx.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'router,192.168.0.1' (RSA) to the list of known hosts.
Welcome to
_____ _ _
/ ___| |_|
_ _| | | |_ ____ _ _ _ _
| | | | | | | | _ \| | | |\ \/ /
| |_| | |___| | | | | | |_| | ) (
| ___\_____|_|_|_| |_|\____|/_/\_\
| |
|_|
by
_ _ _ _
| | | | | |_|
| | | | |__ _ ___ ___ __ __
| | | | _ \| |/ __|/ _ \| \/ \
| |_| | |_| | | |__( |_| ) |\/| |
\_____/\___/|_|\___|\___/|_| |_|
For further information check:
http://linux.ubicom.com/
BusyBox v1.14.1 (2011-05-03 18:13:15 CEST) hush - the humble shell
Enter 'help' for a list of built-in commands.
~ #
Still, secure wireless didn't work of course. After fumbling around on the commandline for a bit, I found something called 'wpatalk'. Which wouldn't run.
# /sbin/wpatalk
/sbin/wpatalk: can't load library 'libwpa_common.so'
I did not find any reference to libwpa_common.so in the source archive, it was obviously missing. A quick web search for the file name didn't turn up anything interesting either. WPA does work with the 'official' binary image, so I guessed the files had to be somewhere in there.
Extraction
After reading the different parts of the build scripts and makefiles for a while to find out the format of the image, I figured out it would probably be easier to figure it out from the binary file itself. According to the file tool, it is a u-boot image, or uImage:
$ file DIR652A1_FW100B33.bin
DIR652A1_FW100B33.bin: u-boot/PPCBoot image
There's a script which claims it can extract such images. It extracts something, but getting at the romfs files needs some more work.
The format used for compression is the widely-used gzip. The format description tells us that at the start of a gzip file, we can expect a byte string of 1f 8b 08 (1f8b=gzip signature, 08=deflate compression). Using beye aka biew, I found that there was something which looked like a gzip signature somewhere in the middle of the extracted, unzipped image file. Extracting that with 'dd' and unpacking it with gzip yields an archive file:
$ file Image-2-unzipped
Image-2-unzipped: ASCII cpio archive (SVR4 with no CRC)
Looks good!! Now using a hex editor for searching the file is somewhat user-unfriendly, so I wanted to automate this somehow.
Enter bgrep
So I need a tool which does one of the most basic tasks one can do with files: look for something and print its offset. This tool is called bgrep, and of course, it's included in all the major Linux distributions.
Actually, it isn't. The tool was only recently written and is not included in any distributions that I know of. It is about 200 lines of C code, has a repo at github, and uses one of the coolest installation methods invented yet.
Using bgrep, I could then write a script which would extract the root fs:
# now extract the root fs
file ${TMPFILE}
(cat ${TMPFILE} | gunzip > ${TMPFILE}-unzipped)
SHITOFFSET=$(printf "%d\n" 0x$(bgrep 1f8b08????????????03 ${TMPFILE}-unzipped | sed "s/^.*: //"))
dd if=${TMPFILE}-unzipped ibs=1 obs=1024 skip=$SHITOFFSET of=${TMPFILE}-2
file ${TMPFILE}-2
cat ${TMPFILE}-2 | gunzip > ${TMPFILE}-2-unzipped
file ${TMPFILE}-2-unzipped
(mkdir rootfs && cd rootfs && cpio -idu --no-absolute-filenames < ../${TMPFILE}-2-unzipped)
Together with extract_uImage, the complete script extracts the files into the "rootfs" subdirectory. Use: extract_uImage_romfs.sh DIR652A1_FW100B33.bin
Lost and Found
Surprise!, the missing files libwpa_common.so and libwpa_ctrl.so are found in /lib. After placing them into SRC/ubicom-distro/uClinux/romfs/lib and rebuilding, WPA/WPA2 works fine!
Conclusion
I think it's nice that D-Link uses GPL firmware for their newer routers. They don't make make a big fuss about it, they don't advertise their gracious 'openness' or anything, they just seem to be doing it as a business decision, which I think makes it even nicer.
That the image built from their source code silently leaves networks open is not so nice however. The libraries seem to have simply been forgotten. This and the fact that much of the optional stuff in the distribution does not compile without fixes indicates that they do not test their firmware very thoroughly.
I did not find any source code to wpatalk or the libwpa_* libraries. I'm not sure about the legal implications, but I'm certain that omitting parts of the source code for an open source distribution goes against the spirit, if not the wording, of the GPL.
Also, they could update their uClibc code from time to time.
[ view entry ] ( 1775 views ) | [ 0 trackbacks ] | related link