Category Archives: Networking

Allwinner H2+/H3 Ethernet with Linux 4.9-rc8

The Orange Pi PC is not a new single board computer. It’s been released for over a year now, but has mostly been stuck on a heavily patched 3.4 release kernel.

There have been ongoing efforts since the release to have support for the Allwinner H3 in the mainline kernel. In the past weeks there have been new patches released which enable support for the Ethernet MAC on the H3 (and H2+).

Unfortunately this support is not in mainline yet, and won’t make it in the upcoming 4.9 release. However, that doesn’t stop you from taking the patches and applying them against 4.9 yourself.

I wrote a script to compile the kernel from source, applying the necessary patches to the kernel and using a minimal .config file which compiles the sun8i_emac support as a module. You can download the build script from GitHub.

It does try to be somewhat smart: verifying the integrity of the downloaded files, and will bail out if there are errors in patching the source code. But, it doesn’t do toolchain dependency checking because that’s just too complicated. Since the emac support will end up in mainline soon, I doubt it’s worth the time to improve the build script. However if anyone is interested in improving it, the script is released as GPLv2.

The result? If you are patient enough to wait for the kernel to compile, you get a uImage and modules for Linux 4.9-rc8 with Ethernet support:

Allwinner H3 emac performance:

[email protected]:~$ iperf -n 1024M -c 192.168.1.150
————————————————————
Client connecting to 192.168.1.150, TCP port 5001
TCP window size: 43.8 KByte (default)
————————————————————
[ 3] local 192.168.1.206 port 42572 connected with 192.168.1.150 port 5001
[ ID] Interval Transfer Bandwidth
[ 3] 0.0-100.6 sec 1.00 GBytes 85.4 Mbits/sec

Orange Pi Zero (Allwinner H2+):

I’ve also just received my Orange Pi Zero and confirmed that the same kernel works on the Orange Pi Zero, so you can run Linux 4.9 on the Orange Pi PC (Allwinner H3) or Orange Pi Zero (Allwinner H2+) with Ethernet support.

Allwinner H2+ emac performance:

[email protected]:~$ iperf -n 1024M -c 192.168.1.150
————————————————————
Client connecting to 192.168.1.150, TCP port 5001
TCP window size: 43.8 KByte (default)
————————————————————
[ 3] local 172.16.4.206 port 54762 connected with 192.168.1.150 port 5001
[ ID] Interval Transfer Bandwidth
[ 3] 0.0-95.9 sec 1.00 GBytes 89.5 Mbits/sec

Download:
If you want to skip compiling the kernel yourself, I’m providing the kernel uImage and modules here.

I am using u-boot v2016.11 from denx.

Note: HDMI isn’t working on my Orange Pi PC, and since I run it headless I’m not interested in investigating why. If you’re using your Orange Pi PC with HDMI output, you may need to modify the kernel .config file to fix HDMI.

D-Link DAP-1520 hacking: Part 2

In Part 1 we looked at the hardware of the DAP-1520 and did some investigation into the stock D-Link firmware that runs on the device.

We found that there were two firmware images on the device, the main firmware (Image 1) and the recovery OS (Image 2) which is used when Image 1 fails verification.

Despite D-Link’s reputation for buggy firmwares, my infosec skills are still basic, and I wasn’t able to get telnetd running on the DAP-1520 to investigate the firmware more. Sure, we already have a dump of the firmware thanks to an SPI reader (and the update, available from D-Link’s website), but this only tells us what’s in the firmware, it doesn’t actually let us poke around at the hardware. Since my stated goal is to get OpenWrt running on the device, poking around at the hardware with a working OS is pretty important.

To accomplish this, I needed to build the firmware from the GPL source code published by D-Link. You can download the GPL source code for their routers from their Taiwanese website.

DAP-1520 GPL source code

DAP-1520 GPL source code

GPL source code for each firmware release

GPL source code for each firmware release

If you’re wondering why there’s a huge difference in the size of the source code between firmware versions, don’t. Firmware 1.05, despite the file extension, is just a tar file and is 185MB. Firmware 1.06 is a gzip compressed tar file and is 186MB. These inconsistencies are just the start of our wonderful journey with the D-Link source 😉

I’m building firmware 1.06, since newer is always better. I’ve just noticed that D-Link have published a file for firmware 1.07 on their Australian website. Hopefully they will release the GPL source for this firmware soon, I’m excited to see what vulnerabilities have been addressed in the web configurator!

Anyway, when you download the GPL source code, you will find that D-Link has included a README file, which describes how to build the firmware. This surprised me, I wasn’t expecting anything more than the source code, so some minor kudos go to D-Link for at least providing instructions.

Install & Build
===============
Environment: 
    1. Download Ubuntu 10.04.4 LTS from http://releases.ubuntu.com/lucid/
        http://releases.ubuntu.com/lucid/ubuntu-10.04.4-server-i386.iso
    2. Install Ubuntu 10.04.4 LTS server in your computer.
    3. Make sure your Ubuntu is 10.04.4 LTS(Lucid Lynx).
    4. Building image with ROOT privileges.	
	
Install:
    1.  Please update the list of available packages:
       ~#apt-get update
	   ~#apt-get install gcc build-essential zlib1g-dev bison flex subversion sharutils libncurses5-dev gawk help2man intltool pkg-config libglib2.0-dev	  
    2. Create a folder in root directory 
       ~#mkdir /tftpboot/
    3. Install the toolchain:
		~#cd /DAP-1520_A1_106b04_FOSS/toolchain
		A.	GCC
				1.	cp buildroot-gcc342.tar.bz2 /opt
				2.	tar jxvf buildroot-gcc342.tar.bz2
		B.	LZMA
			    1.  cp lzma-4.32.7.tar.gz /home/
			    2.  tar -xvf lzma-4.32.7.tar.gz
				3.  cd lzma-4.32.7
				4.	./configure
				5.	make
				6.	make install
			    7.  ldconfig	
		C.	XZ
				1.	cp xz-5.0.3.tar.bz2 /home/
				2.	tar jxvf xz-5.0.3.tar.bz2
				3.  cd xz-5.0.3
				4.	./configure
				5.	make
				6.	make install
		D.	mksquashfs
				1.  cp squashfs4.2.tar.bz2 /home/
				2.	tar jxvf squashfs4.2.tar.bz2
				3.	cd squashfs4.2/squashfs-tools
				4.	make
				5.	cp mksquashfs /opt/buildroot-gcc342/bin/mksquashfs_lzma-4.2
	4. Building the image & loader.
		(1). Please make sure the gcc-version is greater than 4.2.4
			 (You can type "~#gcc -v " to check the gcc-version)
		(2). Copy the DAP1520A1_GPL106b04.tar into /home/ directory
		     use following commands.
			~#tar -xvf DAP1520A1_GPL106b04.tar
		(3). You will get "AthSDK" directory.
			~#cd /home/AthSDK	
		(4). Into the AthSDK directory,and run following commands.
			(4-1). If you want to build normal image
			~#make clean
			~#make kernel_clean
			~#make 
			After make successfully, under "AthSDK/image/", you will get the normal image file "DAP1520A1_FW106B04.bin".
			(4-2). If you want to build backup image
			~#make -f Makefile.backup clean
			~#make kernel_clean
			~#make -f Makefile.backup 
			After make successfully, under "AthSDK/image/", you will get the backup image file "DAP1520A1_FW100B03.bin".
			(4-3). If you want to build loader
			~#make loader_clean
			~#make mtk_loader
			After make successfully, under "AthSDK/image/", you will get the loader file "DAP1520A1_FW100.boot".
	5. Update the new firmware by web interface provided by device.
	6. Congratulations! You got your specific image now.

Install Ubuntu 10.04? Thanks, I think I will pass. Ubuntu 10.04 isn't supported anymore, so good luck installing all the packages you need to support the build environment. So, instead I decided to build the firmware on my laptop, which runs a reasonably current version of Arch Linux. On Arch Linux /tmp is a ramdisk, so I just do all my work there and make symlinks when necessary. I wouldn't recommend using /tmp for work unless you have >8GB of RAM as the /tmp filesystem is by default 50% of your RAM, and the compiled source code is somewhere around 2GB give or take.

The first step is to decompress the toolchain and create a symlink from DAP-1520_A1_106b04_FOSS/toolchain/ to /opt/buildroot-gcc342 because a bunch of their makefiles are hard coded to look in this place for the toolchain.

$ cd $(mktemp -d)
$ tar -zxvf ~/Downloads/DAP-1520\ A1_ver1.06b04_FOSS.tar.gz
$ cd DAP-1520_A1_106b04_FOSS/toolchain
$ tar -jxf buildroot-gcc342.tar.bz2
$ tar -zxf lzma-4.32.7.tar.gz
$ tar -jxf squashfs4.2.tar.bz2
$ ln -s $(pwd)/buildroot-gcc342 /opt/buildroot-gcc342

Then you'll need to compile the versions of lzma and squashfs provided, for reasons which I will get into in a bit. Copy the lzma and mksquashfs_lzma-4.2 binaries into the bin folder of your toolchain. I don't recommend running make install as they do in the instructions, just run make and manually copy the binaries to the toolchain/bin directory.

$ cd lzma-4.32.7
$ ./configure
$ make
$ cp src/lzma/lzma ../buildroot-gcc342/bin/
$ cd ../squashfs4.2/squashfs-tools
$ make
$ cp mksquashfs ../../buildroot-gcc342/bin/mksquashfs_lzma-4.2

The copy of mksquashfs_lzma-4.2 included in the toolchain links against an ancient version of liblzma.so which has long since not existed in Arch Linux. Hence, it's easier just to compile the version from the source code included. Just install xz from your package manager, I didn't need to compile their specific version.

Now that we have "installed" the toolchain, we need to decompress the actual source code for the router firmware and "install" it in /home/AthSDK:

$ cd ../../../src/
$ tar -zxf DAP1520A1_GPL106b04.tar.gz
$ sudo ln -s $(pwd)/AthSDK /home/AthSDK

Now we are all set to start building it as per the D-Link instructions above:

$ cd AthSDK
$ make clean
$ make kernel_clean

At this point, we need to fix some of the source files or the compilation will fail. You will need to download and run the next few patches in the AthSDK directory or compilation will fail with errors.

$ wget https://watchmysys.com/blog/wp-content/uploads/2016/03/timeconst.patch
$ wget https://watchmysys.com/blog/wp-content/uploads/2016/03/busybox_makefile.patch
$ wget https://watchmysys.com/blog/wp-content/uploads/2016/03/busybox_features.patch
$ wget https://watchmysys.com/blog/wp-content/uploads/2016/03/timer_makefile.patch
$ wget https://watchmysys.com/blog/wp-content/uploads/2016/03/telnetd.patch
$ wget https://watchmysys.com/blog/wp-content/uploads/2016/03/nc.patch

Some explanation is in order:

  • Compiling the kernel will fail because Arch has a reasonably new verison of Perl, and the syntax in Perl >5.22 has changed since 2.6.36. You will need to apply the patch timeconst.patch to fix this.
  • Compiling busybox will fail because the syntax in the makefile is deprecated. You will need to apply the patch busybox_makefile.patch to fix this.
  • We want to have telnetd and nc in the image we create, for backdoors and stuff. You will need to apply the patch busybox_features.patch to enable these features.
  • D-Link includes an application called timer which expects an object file to compile, except this object file is never created. Removing the line fixes the error and as far as I know timer still works as intended. You will need to apply the patch timer_makefile.patch to fix this.
  • We need to create sysconfig scripts to start the telnetd and nc daemons on boot. The telnetd and nc patches create the sysconfig scripts in the rootfs folder of the D-Link OS
  • $ patch -p1 < timeconst.patch 
    patching file platform/MT7620/kernels/mips-linux-2.6.36.x/kernel/timeconst.pl
    $ patch -p1 < busybox_makefile.patch 
    patching file apps/busybox-1.6.1/Makefile
    $ patch -p1 < busybox_features.patch 
    patching file apps/busybox-1.6.1/.config
    $ patch -p1 < timer_makefile.patch   
    patching file apps/timer/Makefile
    $ sudo patch -p1 < telnetd.patch  
    patching file rootfs/target/etc/sysconfig/S3telnetd.sh
    $ sudo patch -p1 < nc.patch      
    patching file rootfs/target/etc/sysconfig/S4nc.sh
    $ chmod 755 rootfs/target/etc/sysconfig/*sh
    $ install -d rootfs/target/bin
    $ ln -s busybox_161 rootfs/target/bin/nc
    

    Now we can run the next command with sudo, as tar will attempt to create some files for the firmware which are owned by root. This will fail if not run as sudo:

    $ sudo make

    A long time later:

    
    =================== installing wireless ===================
    make -C wireless install || exit 1
    make[1]: Entering directory '/tmp/tmp.41xjcpqbrX/DAP-1520_A1_106b04_FOSS/src/AthSDK/wireless'
    make[1]: Leaving directory '/tmp/tmp.41xjcpqbrX/DAP-1520_A1_106b04_FOSS/src/AthSDK/wireless'
    =================== installing rootfs ===================
    make -C rootfs install || exit 1
    make[1]: Entering directory '/tmp/tmp.41xjcpqbrX/DAP-1520_A1_106b04_FOSS/src/AthSDK/rootfs'
    install -d /home/AthSDK/image
    rm -rf /home/AthSDK/rootfs/target/man/ /home/AthSDK/rootfs/target/lib/*.a
    Strip all .so
    find /home/AthSDK/rootfs/target/lib/ -name "*.so*" -exec mipsel-linux-uclibc-strip '{}' ';'
    cp -f /opt/buildroot-gcc342/lib/libdl* /home/AthSDK/rootfs/target/lib/
    mipsel-linux-uclibc-strip target/lib/libdl-0.9.30.so
    mipsel-linux-uclibc-strip: 'target/lib/libdl-0.9.30.so': No such file
    Strip all exec
    find /home/AthSDK/rootfs/target -type f -perm -u+x -exec mipsel-linux-uclibc-strip '{}' ';'
    mipsel-linux-uclibc-strip: /home/AthSDK/rootfs/target/www/widget.cgi: File format not recognized
    mipsel-linux-uclibc-strip: /home/AthSDK/rootfs/target/www/tr069.cgi: File format not recognized
    mipsel-linux-uclibc-strip: /home/AthSDK/rootfs/target/www/save_configure.cgi: File format not recognized
    mipsel-linux-uclibc-strip: /home/AthSDK/rootfs/target/www/hnap.cgi: File format not recognized
    mipsel-linux-uclibc-strip: /home/AthSDK/rootfs/target/www/apply.cgi: File format not recognized
    mipsel-linux-uclibc-strip: /home/AthSDK/rootfs/target/www/library/test/success.html: File format not recognized
    mipsel-linux-uclibc-strip: /home/AthSDK/rootfs/target/usr/share/udhcpc/default.script: File format not recognized
    mipsel-linux-uclibc-strip: /home/AthSDK/rootfs/target/usr/share/udhcpc/default.bound-nodns: File format not recognized
    mipsel-linux-uclibc-strip: /home/AthSDK/rootfs/target/usr/share/udhcpc/default.bound-dns: File format not recognized
    mipsel-linux-uclibc-strip: /home/AthSDK/rootfs/target/lib/libavahi-core.la: File format not recognized
    mipsel-linux-uclibc-strip: /home/AthSDK/rootfs/target/lib/libavahi-common.la: File format not recognized
    mipsel-linux-uclibc-strip: /home/AthSDK/rootfs/target/lib/libexpat.la: File format not recognized
    mipsel-linux-uclibc-strip: /home/AthSDK/rootfs/target/lib/libdaemon.la: File format not recognized
    mipsel-linux-uclibc-strip: /home/AthSDK/rootfs/target/etc/rdnssd-script: File format not recognized
    mipsel-linux-uclibc-strip: /home/AthSDK/rootfs/target/etc/dhcp6c-script: File format not recognized
    mipsel-linux-uclibc-strip: /home/AthSDK/rootfs/target/etc/host.conf: File format not recognized
    mipsel-linux-uclibc-strip: /home/AthSDK/rootfs/target/etc/inittab: File format not recognized
    mipsel-linux-uclibc-strip: /home/AthSDK/rootfs/target/etc/services: File format not recognized
    mipsel-linux-uclibc-strip: /home/AthSDK/rootfs/target/etc/shadow: File format not recognized
    mipsel-linux-uclibc-strip: /home/AthSDK/rootfs/target/etc/rdnssd/merge-hook: File format not recognized
    mipsel-linux-uclibc-strip: /home/AthSDK/rootfs/target/etc/passwd: File format not recognized
    mipsel-linux-uclibc-strip: /home/AthSDK/rootfs/target/etc/sysinfo: File format not recognized
    mipsel-linux-uclibc-strip: /home/AthSDK/rootfs/target/etc/icon.ico: File format not recognized
    mipsel-linux-uclibc-strip: /home/AthSDK/rootfs/target/etc/nvram.default: File format not recognized
    mipsel-linux-uclibc-strip: /home/AthSDK/rootfs/target/etc/sysconfig/S2gpio.sh: File format not recognized
    mipsel-linux-uclibc-strip: /home/AthSDK/rootfs/target/etc/issue: File format not recognized
    mipsel-linux-uclibc-strip: /home/AthSDK/rootfs/target/etc/group: File format not recognized
    mipsel-linux-uclibc-strip: /home/AthSDK/rootfs/target/etc/fstab: File format not recognized
    mipsel-linux-uclibc-strip: /home/AthSDK/rootfs/target/etc/securetty: File format not recognized
    mipsel-linux-uclibc-strip: /home/AthSDK/rootfs/target/etc/rc.d/rcS: File format not recognized
    mipsel-linux-uclibc-strip: /home/AthSDK/rootfs/target/bin/gpio_event: File format not recognized
    Strip Atheros's *.ko
    find /home/AthSDK/rootfs/target/lib/modules/2.6.36.x -name "*.ko" -type f \
    	-exec mipsel-linux-uclibc-strip -g -S -d \
    	--strip-unneeded \
    	--remove-section=__kcrctab \
    	--remove-section=__kcrctab_gpl \
    	--remove-section=__param \
    	--remove-section=__ex_table \
    	--remove-section=__obsparm \
    	--remove-section=__versions \
    	--remove-section=.pdr \
    	--remove-section=.mdebug.abi32 \
    	--remove-section=.comment \
    	--remove-section=__ksymtab_gpl_future \
    	--remove-section=__kcrctab_gpl_future \
    	--remove-section=__ksymtab_unused \
    	--remove-section=__kcrctab_unused \
    	--remove-section=__ksymtab_unused_gpl \
    	--remove-section=__kcrctab_unused_gpl \
    	--remove-section=.ctors \
    	--remove-section=__markers \
    	--remove-section=__tracepoints \
    	--remove-section=_ftrace_events \
    	--remove-section=__mcount_loc \
    	-x '{}' ';'
    Strip Cameo's *.ko
    Remove unneeded files
    rm -f /home/AthSDK/rootfs/target/lib/modules/2.6.36.x/build
    rm -f /home/AthSDK/rootfs/target/lib/modules/2.6.36.x/modules.order
    rm -f /home/AthSDK/rootfs/target/lib/modules/2.6.36.x/source
    rm -rf /home/AthSDK/rootfs/target/include
    rm -rf /home/AthSDK/rootfs/target/lib/avahi
    rm -rf /home/AthSDK/rootfs/target/lib/pkgconfig
    rm -rf /home/AthSDK/rootfs/target/root
    rm -f /home/AthSDK/rootfs/target/lib/modules/2.6.36.x/net/ath_pktlog.ko
    cp /home/AthSDK/platform/MT7620/kernels/mips-linux-2.6.36.x/arch/mips/boot/vmlinux.* /home/AthSDK/image/ || exit 1;
    /home/AthSDK/tools/release_scripts/mkuImage.sh
    + case $BOARD_TYPE in
    + LDADDR=0x80000000
    ++ readelf -a /home/AthSDK/platform/MT7620/kernels/mips-linux-2.6.36.x/vmlinux
    ++ grep Entry
    ++ head -1
    ++ cut -d: -f 2
    + ENTRY='               0x8000c310'
    + /home/AthSDK/tools/release_scripts/mkimage -A mips -O linux -T kernel -C lzma -a 0x80000000 -e 0x8000c310 -n 'Linux Kernel Image' -d /home/AthSDK/image/vmlinux.lzma /home/AthSDK/image/vmlinux.lzma.ub
    Image Name:   Linux Kernel Image
    Created:      Sun Mar  6 23:20:20 2016
    Image Type:   MIPS Linux Kernel Image (lzma compressed)
    Data Size:    908125 Bytes = 886.84 kB = 0.87 MB
    Load Address: 0x80000000
    Entry Point:  0x8000C310
    /home/AthSDK/tools/release_scripts/release_rootfs.sh
    =================== Create SQUASHFS for DAP-1520 ===================
    Parallel mksquashfs: Using 4 processors
    Creating 4.0 filesystem on /home/AthSDK/image/MT7620-squash, block size 65536.
    [===========================================================================================\] 524/524 100%
    Exportable Squashfs 4.0 filesystem, xz compressed, data block size 65536
    	compressed data, compressed metadata, compressed fragments, compressed xattrs
    	duplicates are removed
    Filesystem size 3370.39 Kbytes (3.29 Mbytes)
    	28.91% of uncompressed filesystem size (11656.43 Kbytes)
    Inode table size 5286 bytes (5.16 Kbytes)
    	24.23% of uncompressed inode table size (21816 bytes)
    Directory table size 5948 bytes (5.81 Kbytes)
    	46.62% of uncompressed directory table size (12759 bytes)
    Number of duplicate files found 46
    Number of inodes 650
    Number of files 419
    Number of fragments 56
    Number of symbolic links  125
    Number of device nodes 53
    Number of fifo nodes 0
    Number of socket nodes 0
    Number of directories 53
    Number of ids (unique uids + gids) 1
    Number of uids 1
    	root (0)
    Number of gids 1
    	root (0)
    =================== MAX_ROOTFS_IMG_SIZE=3801062 Bytes =================== 
    0+1 records in
    1+0 records out
    3801062 bytes (3.8 MB) copied, 0.00318195 s, 1.2 GB/s
    =================== MT7620 Squashfs created for 8 MB FLASH ===================
    /home/AthSDK/tools/release_scripts/release_image.sh
    0+1 records in
    1+0 records out
    983040 bytes (983 kB) copied, 0.00105716 s, 930 MB/s
    make[1]: Leaving directory '/tmp/tmp.41xjcpqbrX/DAP-1520_A1_106b04_FOSS/src/AthSDK/rootfs'
    =================== Finish ===================
    

    We need to verify that the file produced matches the official firmware update available from D-Link. It really wouldn't do to flash an XZ compressed kernel when the bootloader expects an LZMA compressed kernel!

    $ binwalk image/DAP1520A1_FW106B04.bin 
    
    DECIMAL       HEXADECIMAL     DESCRIPTION
    --------------------------------------------------------------------------------
    0             0x0             uImage header, header size: 64 bytes, header CRC: 0x9D3D95E7, created: 2016-03-07 19:18:42, image size: 909160 bytes, Data Address: 0x80000000, Entry Point: 0x8000C310, data CRC: 0x77D76472, OS: Linux, CPU: MIPS, image type: OS Kernel Image, compression type: lzma, image name: "Linux Kernel Image"
    64            0x40            LZMA compressed data, properties: 0x5D, dictionary size: 33554432 bytes, uncompressed size: 2798288 bytes
    983040        0xF0000         Squashfs filesystem, little endian, version 4.0, compression:xz, size: 3451228 bytes, 650 inodes, blocksize: 65536 bytes, created: 2016-03-07 19:18:45

    Good, this matches the D-Link provided firmware update, so we should be all good to flash it to the router and see if we can login.

    Gotchas
    mksquashfs
    I had originally installed mksquashfs from pacman, because why would you want to use the old version included in the D-Link source?

    Hilariously, the version of mksquashfs_lzma-4.2 included in the D-Link source doesn't actually support LZMA compression at all, instead using xz compression by default!

    
    SYNTAX:/opt/buildroot-gcc342/bin/mksquashfs_lzma-4.2 source1 source2 ...  dest [options] [-e list of exclude
    dirs/files]
    
    Filesystem build options:
    -comp 		select  compression
    			Compressors available:
    				gzip
    				xz (default)
    
    (other options omitted)
    
    Compressors available and compressor specific options:
    	gzip (no options)
    	xz (default)
    	  -Xbcj filter1,filter2,...,filterN
    		Compress using filter1,filter2,...,filterN in turn
    		(in addition to no filter), and choose the best compression.
    		Available filters: x86, arm, armthumb, powerpc, sparc, ia64
    	  -Xdict-size 
    		Use  as the XZ dictionary size.  The dictionary size
    		can be specified as a percentage of the block size, or as an
    		absolute value.  The dictionary size must be less than or equal
    		to the block size and 8192 bytes or larger.  It must also be
    		storable in the xz header as either 2^n or as 2^n+2^(n+1).
    		Example dict-sizes are 75%, 50%, 37.5%, 25%, or 32K, 16K, 8K
    		etc.
    

    This differs from mksquashfs included in Arch Linux, which uses gzip by default! If you just go ahead and build the image using mksquashfs provided by your package manager, you will end up with a filesystem which is too large, and the build process will fail!

    
    $ mksquashfs -h
    SYNTAX:mksquashfs source1 source2 ...  dest [options] [-e list of exclude
    dirs/files]
    
    Filesystem build options:
    -comp 		select  compression
    			Compressors available:
    				gzip (default)
    
    (other options omitted)
    
    Compressors available and compressor specific options:
    	gzip (default)
    	  -Xcompression-level 
    		 should be 1 .. 9 (default 9)
    	  -Xwindow-size 
    		 should be 8 .. 15 (default 15)
    	  -Xstrategy strategy1,strategy2,...,strategyN
    		Compress using strategy1,strategy2,...,strategyN in turn
    		and choose the best compression.
    		Available strategies: default, filtered, huffman_only,
    		run_length_encoded and fixed
    	lzma (no options)
    	lzo
    	  -Xalgorithm 
    		Where  is one of:
    			lzo1x_1
    			lzo1x_1_11
    			lzo1x_1_12
    			lzo1x_1_15
    			lzo1x_999 (default)
    	  -Xcompression-level 
    		 should be 1 .. 9 (default 8)
    		Only applies to lzo1x_999 algorithm
    	lz4
    	  -Xhc
    		Compress using LZ4 High Compression
    	xz
    	  -Xbcj filter1,filter2,...,filterN
    		Compress using filter1,filter2,...,filterN in turn
    		(in addition to no filter), and choose the best compression.
    		Available filters: x86, arm, armthumb, powerpc, sparc, ia64
    	  -Xdict-size 
    		Use  as the XZ dictionary size.  The dictionary size
    		can be specified as a percentage of the block size, or as an
    		absolute value.  The dictionary size must be less than or equal
    		to the block size and 8192 bytes or larger.  It must also be
    		storable in the xz header as either 2^n or as 2^n+2^(n+1).
    		Example dict-sizes are 75%, 50%, 37.5%, 25%, or 32K, 16K, 8K
    		etc.
    

    At least the build process will fail and tell you the image is too large, instead of making an image which will brick your router...

    lzma
    Again I was wondering, why should I use the old version of LZMA included in the D-Link source, when Arch Linux ships which a much newer (and thus better) version of LZMA? It might occur to you, that I haven't learned my lesson yet from the previous experience with mksquashfs...

    The lzma included in D-Link's source:

    $ /opt/buildroot-gcc342/bin/lzma -h
    
    lzma 4.32.7 Copyright (C) 2005 Ville Koskinen
    Based on LZMA SDK 4.32 Copyright (C) 1999-2005 Igor Pavlov
    
    Usage: /opt/buildroot-gcc342/bin/lzma [flags and input files in any order]
      -c --stdout       output to standard output
      -d --decompress   force decompression
      -z --compress     force compression
      -k --keep         keep (don't delete) input files
      -f --force        force overwrite of output file and compress links
      -t --test         test compressed file integrity
      -S .suf  --suffix .suf   use suffix .suf on compressed files
      -q --quiet        suppress error messages
      -v --verbose      be verbose
      -h --help         print this message
      -L --license      display the license information
      -V --version      display version numbers of LZMA SDK and lzma
      -1 .. -2          fast compression
      -3 .. -9          good to excellent compression. -7 is the default.
         --fast         alias for -1
         --best         alias for -9 (usually *not* what you want)
    
      Memory usage depends a lot on the chosen compression mode -1 .. -9.
      See the man page lzma(1) for details.
    

    And lzma from Arch Linux:

    $ lzma -h
    Usage: lzma [OPTION]... [FILE]...
    Compress or decompress FILEs in the .xz format.
    
      -z, --compress      force compression
      -d, --decompress    force decompression
      -t, --test          test compressed file integrity
      -l, --list          list information about .xz files
      -k, --keep          keep (don't delete) input files
      -f, --force         force overwrite of output file and (de)compress links
      -c, --stdout        write to standard output and don't delete input files
      -0 ... -9           compression preset; default is 6; take compressor *and*
                          decompressor memory usage into account before using 7-9!
      -e, --extreme       try to improve compression ratio by using more CPU time;
                          does not affect decompressor memory requirements
      -T, --threads=NUM   use at most NUM threads; the default is 1; set to 0
                          to use as many threads as there are processor cores
      -q, --quiet         suppress warnings; specify twice to suppress errors too
      -v, --verbose       be verbose; specify twice for even more verbose
      -h, --help          display this short help and exit
      -H, --long-help     display the long help (lists also the advanced options)
      -V, --version       display the version number and exit
    
    With no FILE, or when FILE is -, read standard input.
    
    Report bugs to  (in English or Finnish).
    XZ Utils home page: 
    

    So, apart from the newer output looking much more like a standard GNU utility, you might have noticed that the older copy of lzma compresses with a default compression of -7 while the newer version compresses with a default compression of -6.

    If you think this doesn't make a difference, let me just tell you now, it does. A big one. The difference between -6 and -7 is the difference between a kernel that boots, and one that doesn't.

    This firmware was built with the D-Link SDK version of lzma and will boot:

    $ binwalk image/DAP1520A1_FW106B04.bin 
    
    DECIMAL       HEXADECIMAL     DESCRIPTION
    --------------------------------------------------------------------------------
    0             0x0             uImage header, header size: 64 bytes, header CRC: 0x46768407, created: 2016-03-05 22:33:15, image size: 909272 bytes, Data Address: 0x80000000, Entry Point: 0x8000C310, data CRC: 0x4993B2D9, OS: Linux, CPU: MIPS, image type: OS Kernel Image, compression type: lzma, image name: "Linux Kernel Image"
    64            0x40            LZMA compressed data, properties: 0x5D, dictionary size: 33554432 bytes, uncompressed size: 2798288 bytes
    983040        0xF0000         Squashfs filesystem, little endian, version 4.0, compression:xz, size: 3445784 bytes, 655 inodes, blocksize: 65536 bytes, created: 2016-03-05 22:33:20
    

    This firmware was built with the Arch Linux version of lzma and won't boot:

    $ binwalk image/DAP1520A1_FW106B04.bin 
    
    DECIMAL       HEXADECIMAL     DESCRIPTION
    --------------------------------------------------------------------------------
    0             0x0             uImage header, header size: 64 bytes, header CRC: 0x7A57558F, created: 2016-03-07 20:41:46, image size: 908147 bytes, Data Address: 0x80000000, Entry Point: 0x8000C310, data CRC: 0x8E0F6C03, OS: Linux, CPU: MIPS, image type: OS Kernel Image, compression type: lzma, image name: "Linux Kernel Image"
    983040        0xF0000         Squashfs filesystem, little endian, version 4.0, compression:xz, size: 3451428 bytes, 653 inodes, blocksize: 65536 bytes, created: 2016-03-07 20:41:49
    

    So, what exactly happens when you flash this image to the device? Does it do some verification before flashing and stop you? Does it flash the image, and then when Image 1 fails to boot it boots the linux4b image and start rootfsb so you can recover the device?

    Not quite...

    Image1 Try Counter --> 0
    
    Image1: OK Image2: OK
    Both images are OK!!!
    
    =================================================
    
    Please choose the operation: 
       1: Load system code to SDRAM via TFTP. 
       2: Load system code then write to Flash via TFTP. 
       3: Boot system code via Flash (default).
       4: Entr boot command line interface.
       7: Load Boot Loader code then write to Flash via Serial. 
       9: Load Boot Loader code then write to Flash via TFTP. 
     1  0 
       
    3: System Boot system code via Flash.
    ## Booting image at bc050000 ...
    raspi_read: from:50000 len:40 
       Image Name:   Linux Kernel Image
       Image Type:   MIPS Linux Kernel Image (lzma compressed)
       Data Size:    908132 Bytes = 886.8 kB
       Load Address: 80000000
       Entry Point:  8000c310
    raspi_read: from:50040 len:ddb64 
       Verifying Checksum ... OK
       Uncompressing Kernel Image ... LZMA ERROR 1 - must RESET board to recover
    

    So, no. No verification of the validity of the kernel in the update before flashing. And no, it won't boot from Image 2. You will just see this error, over and over, while the device resets. You might think that Image1 Try Counter would increment, and after a threshold it would boot into the recovery environment, but no. Congratulations, you are now the proud owner of a brick. Get out your SPI flashing tool, because there's no other way around this disaster.

    This does beg the question, how do you get the device to boot into Image 2? Well, after the LZMA compression snafu on the kernel, I thought I would save some time and just flash the vmlinuz.ub file created by the build script to flash and be done with it... nope!

    
    Check image validation:
    Image1 Header Magic Number --> OK
    Image2 Header Magic Number --> OK
    Image1 Header Checksum --> OK
    Image2 Header Checksum --> OK
    Image1 Data Checksum --> raspi_read: from:50040 len:de000 
    Failed
    Image2 Data Checksum --> raspi_read: from:4f0040 len:ca8f4 
    OK
    Image1 Stable Flag --> Not stable
    Image1 Try Counter --> 0
    
    Image1: Broken Image2: OK
    Only Image1 is borken!!
    
    =================================================
    
    Please choose the operation: 
       1: Load system code to SDRAM via TFTP. 
       2: Load system code then write to Flash via TFTP. 
       3: Boot system code via Flash (default).
       4: Entr boot command line interface.
       7: Load Boot Loader code then write to Flash via Serial. 
       9: Load Boot Loader code then write to Flash via TFTP. 
     1  0 
       
    3: System Boot system code via Flash.
    ## Booting image at bc4f0000 ...
    raspi_read: from:4f0000 len:40 
       Image Name:   Linux Kernel Image
       Image Type:   MIPS Linux Kernel Image (lzma compressed)
       Data Size:    829684 Bytes = 810.2 kB
       Load Address: 80000000
       Entry Point:  8000c310
    raspi_read: from:4f0040 len:ca8f4 
       Verifying Checksum ... OK
       Uncompressing Kernel Image ... OK
    No initrd
    ## Transferring control to Linux (at address 8000c310) ...
    ## Giving linux memsize in MB, 64
    
    Starting kernel ...
    
    
    LINUX started...
    
     THIS IS ASIC
    Linux version 2.6.36.x ([email protected]kwork-desktop) (gcc version 3.4.2) #1 Thu Sep 26 16:47:12 CST 2013
    

    Couple of things to note here:

    1. Only Image1 is borken!!
    2. The kernel in Image 2 is much older, and was built on a different host, than the kernel in Image 1 from D-Link

    When you do flash a working firmware back onto the router, you get a surprise when it boots. Because Image1 is borken!! the device rewrites all the nvram variables to their defaults.

    
    init NVRAM_SPACE from mtdblock size
    init nvram memory map size: 0x10000 order of pages: 0x4
    nvram module init:
    	/dev/nvram major number 225 glues to mtd: "nvram" size: 0x00010000
    	nvram_space: 0x00010000 mapped via mmap(2)
    openfile :/etc/sysinfo
    openfile :/etc/nvram.default
    nvram_sanity_check: restore key: uplink_set_by_user="0"
    nvram_sanity_check: restore key: language="default"
    nvram_sanity_check: restore key: ap_ipv6_wan_specify_dns="0"
    nvram_sanity_check: restore key: ap_ipv6_autoconfig_secondary_dns=""
    nvram_sanity_check: restore key: ap_ipv6_autoconfig_primary_dns=""
    nvram_sanity_check: restore key: ap_ipv6_autoconfig_dns_enable="0"
    nvram_sanity_check: restore key: ap_ipv6_static_secondary_dns=""
    nvram_sanity_check: restore key: ap_ipv6_static_primary_dns=""
    nvram_sanity_check: restore key: ap_ipv6_static_default_gw=""
    nvram_sanity_check: restore key: ap_ipv6_static_prefix_length=""
    nvram_sanity_check: restore key: ap_ipv6_static_lan_ip=""
    nvram_sanity_check: restore key: ap_ipv6_wan_proto="ipv6_autoconfig"
    nvram_sanity_check: restore key: pure_support_url="http://support.dlink.com/products/view.asp?productid=DAP-1520"
    nvram_sanity_check: restore key: pure_reboot_page="reboot.htm"
    nvram_sanity_check: restore key: pure_parental_url=""
    nvram_sanity_check: restore key: pure_block_url=""
    nvram_sanity_check: restore key: pure_wireless_url_new="/Wireless.htm"
    nvram_sanity_check: restore key: pure_wireless_url="/wireless.htm"
    nvram_sanity_check: restore key: pure_presentation_url="/Device_Info.htm"
    nvram_sanity_check: restore key: pure_model_description="Wireless Repeater"
    nvram_sanity_check: restore key: pure_vendor_name="D-Link"
    nvram_sanity_check: restore key: pure_device_name="D-Link Systems DAP-1520"
    nvram_sanity_check: restore key: pure_type_new="WiFiAccessPoint"
    nvram_sanity_check: restore key: pure_type="Repeater"
    nvram_sanity_check: restore key: default_downlink_ssid="1"
    nvram_sanity_check: restore key: wlan1_wps_wizard="0"
    nvram_sanity_check: restore key: setup_wizard_ap="1"
    nvram_sanity_check: restore key: log_response_type="system|debug|attack|dropped|notice"
    nvram_sanity_check: restore key: log_current_page="0"
    nvram_sanity_check: restore key: log_total_page="0"
    nvram_sanity_check: restore key: log_per_page="10"
    nvram_sanity_check: restore key: log_notice="1"
    nvram_sanity_check: restore key: log_dropped_packets="0"
    nvram_sanity_check: restore key: log_attacks="1"
    nvram_sanity_check: restore key: log_debug_information="0"
    nvram_sanity_check: restore key: log_system_activity="1"
    nvram_sanity_check: restore key: syslog_server="0/0.0.0.0"
    nvram_sanity_check: restore key: time_daylight_offset="3600"
    nvram_sanity_check: restore key: time_daylight_saving_end_time="1"
    nvram_sanity_check: restore key: time_daylight_saving_end_day_of_week="1"
    nvram_sanity_check: restore key: time_daylight_saving_end_week="2"
    nvram_sanity_check: restore key: time_daylight_saving_end_month="11"
    nvram_sanity_check: restore key: time_daylight_saving_start_time="1"
    nvram_sanity_check: restore key: time_daylight_saving_start_day_of_week="1"
    nvram_sanity_check: restore key: time_daylight_saving_start_week="3"
    nvram_sanity_check: restore key: time_daylight_saving_start_month="3"
    nvram_sanity_check: restore key: time_daylight_saving_enable="0"
    nvram_sanity_check: restore key: ntp_sync_interval="168"
    nvram_sanity_check: restore key: ntp_default_server="ntp1.dlink.com,ntp.dlink.com.tw"
    nvram_sanity_check: restore key: ntp_server=""
    nvram_sanity_check: restore key: time_zone_area="4"
    nvram_sanity_check: restore key: time_zone="-128"
    nvram_sanity_check: restore key: ntp_client_enable="0"
    nvram_sanity_check: restore key: session_timeout="180"
    nvram_sanity_check: restore key: graph_enable="none"
    nvram_sanity_check: restore key: system_time="2011/01/01/00/00/00"
    nvram_sanity_check: restore key: serial_number="none"
    nvram_sanity_check: restore key: model_url="http://support.dlink.com"
    nvram_sanity_check: restore key: model_name="D-Link Repeater"
    nvram_sanity_check: restore key: manufacturer_url="http://www.dlink.com"
    nvram_sanity_check: restore key: manufacturer="D-Link"
    nvram_sanity_check: restore key: friendlyname="DAP-1520"
    nvram_sanity_check: restore key: model_number="DAP-1520"
    nvram_sanity_check: restore key: hostname="DAP-1520"
    nvram_sanity_check: restore key: wlan1_11n_protection="auto"
    nvram_sanity_check: restore key: wlan1_wps_enable="1"
    nvram_sanity_check: restore key: wlan1_psk_pass_phrase="1234567890"
    nvram_sanity_check: restore key: wlan1_psk_cipher_type="both"
    nvram_sanity_check: restore key: wlan1_wep_display="hex"
    nvram_sanity_check: restore key: wlan1_wep128_key="00000000000000000000000000"
    nvram_sanity_check: restore key: wlan1_wep64_key="0000000000"
    nvram_sanity_check: restore key: wlan1_security="disable"
    nvram_sanity_check: restore key: wlan1_ssid=""
    nvram_sanity_check: restore key: wlan_repeater_mode="1"
    nvram_sanity_check: restore key: wlan0_disable_wps_pin="1"
    nvram_sanity_check: restore key: wlan0_wps_configured_mode="5"
    nvram_sanity_check: restore key: wlan0_wps_enable="1"
    nvram_sanity_check: restore key: wlan0_disablecoext="0"
    nvram_sanity_check: restore key: wlan0_rxchainmask="3"
    nvram_sanity_check: restore key: wlan0_txchainmask="3"
    nvram_sanity_check: restore key: wlan0_gkey_rekey_time="3600"
    nvram_sanity_check: restore key: wlan0_11n_protection="auto"
    nvram_sanity_check: restore key: wlan0_wmm_enable="1"
    nvram_sanity_check: restore key: wlan0_short_gi="1"
    nvram_sanity_check: restore key: wlan0_partition="0"
    nvram_sanity_check: restore key: wlan0_dtim="1"
    nvram_sanity_check: restore key: wlan0_fragmentation="2346"
    nvram_sanity_check: Raeth v3.0 (reTaskletst,SkbRecycleo)
    nvram_sanity_check: restore key: wlan0_beacon_interval="100"
    nvram_sanity_check: restore key: wlan0_txpower="100"
    nvram_sanity_check: restore key: wlan0_psk_cipher_type="both"
    nvram_sanity_check: restore key: wlan0_wep_display="hex"
    nvram_sanity_check: restore key: wlan0_wep128_key="00000000000000000000000000"
    nvram_sanity_check: restore key: wlan0_wep64_key="0000000000"
    nvram_sanity_check: restore key: wlan0_ssid_broadcast="1"
    nvram_sanity_check: restore key: wlan0_dot11_mode="11bgn"
    nvram_sanity_check: restore key: wlan0_auto_channel_enable="1"
    nvram_sanity_check: restore key: wlan0_channel="6"
    nvram_sanity_check: restore key: wlan0_enable="1"
    nvram_sanity_check: restore key: wlan0_5g_fragmentation="2346"
    nvram_sanity_check: restore key: wlan0_5g_rts_threshold="2347"
    nvram_sanity_check: restore key: wlan0_5g_dfs_enable="0"
    nvram_sanity_check: restore key: wlan0_5g_11n_protection="adevice eth2 entered promiscuous mode
    uto"
    nvram_sanity_check: restore key: wlan0_5g_wep128_key="00000000000000000000000000"
    nvram_sanity_check: restore key: wlan0_5g_wep64_key="0000000000"
    nvram_sanity_check: restore key: wlan0_5g_psk_cipher_type="both"
    nvram_sanity_check: restore key: wlan0_5g_wep_display="hex"
    nvram_sanity_check: restore key: wlan0_5g_wmm_enable="1"
    nvram_sanity_check: restore key: wlan0_5g_txpower="100"
    nvram_sanity_check: restore key: wlan0_5g_dtim="1"
    nvram_sanity_check: restore key: wlan0_5g_beacon_interval="100"
    nvram_sanity_check: restore key: wlan0_5g_auto_channel_enable="1"
    nvram_sanity_check: restore key: wlan0_5g_channel="36"
    nvram_sanity_check: restore key: wlan0_5g_dot11_mode="11anac"
    nvram_sanity_check: restore key: dhcpc_enable="1"
    nvram_sanity_check: restore key: ap_device_name="dlinkap"
    nvram_sanity_check: restore key: ap_secondary_dns="0.0.0.0"
    nvram_sanity_check: restore key: ap_primary_dns="0.0.0.0"
    nvram_sanity_check: restore key: ap_gateway="0.0.0.0"
    nvram_sanity_check: restore key: ap_netmask="255.255.255.0"
    nvram_sanity_check: restore key: ap_ipaddr="192.168.0.50"
    nvram_sanity_check: restore key: lan_bridge="br0"
    nvram_sanity_check: restore key: lan_eth="eth2"
    nvram_sanity_check: restore key: admin_password=""
    nvram_sanity_check: restore key: admin_username="admin"
    

    Solid defaults there, D-Link. I think this is the first device I've ever encountered where the admin password was actually blank. I setup the device initially, and then it rebooted and asked me for a password to login. Even working in IT, I never thought to try an empty password. I mean, who does that?! D-Link does that.

    And just while writing this I realized that I can look at the nvram defaults any time I want to in /etc/nvram.defaults. This is why you use the 15 minute rule, people.

    Below is a firmware with nc running on port 8023 if you have a DAP-1520 and you want to poke around the D-Link firmware. Telnet asks for a username and password, and none of the combinations I could think of let me login.

    nc 192.168.0.50 8023

    Enjoy your root shell!

    Firmware DAP1520A1_FW106B04.bin (gzip compressed) with nc backdoor.
    md5sum: 31397369d0631183c3823d9933bede5f
    sha1sum: 2951f4e36b05014cbc327acf5c9d6e860ac2f0a5
    sha256sum: 6dd416c6f26e17f059dcc531e2a882a64e3af0594bd3720da669af631c34e50b

    D-Link DAP-1520 hacking: Part 1

    What do you do with a device you never would have bought for yourself, but received for free? Say welcome the D-Link DAP-1520, a “WiFi Extender” that was given to me by O2 as a bonus for signing up with them. Hopefully they aren’t expecting it back in one piece…

    So, what is the DAP-1520? Executive summary:

  • Supports 2.4GHz at 300MBps and 5GHz at 433MBps (thanks to SmallNetBuilder for demystifying this)
  • Repeats the packets from your existing WiFi network for extending range
  • Will also turn a 2.4GHz network into 5GHz through the repeating process (or vice versa)
  • No Ethernet ports because Ethernet is so 2014
  • Right, now that we’ve got the useless D-Link page out of the way, let’s talk about what’s actually in the DAP-1520:

  • MediaTek MT7260A SoC running at 580MHz (includes 2.4GHz radio)
  • 64MB RAM (Winbond W9751G6KB-25 64471X600ZY2)
  • 8MB Flash (MXIC MX 25L640GE)
  • MediaTek MT7610EN (5GHz radio)
  • Skyworks 5GHz Frontend module (datasheet [PDF])
  • This all sounds great, but what do we actually have here? I will preface this post by saying that I started out wanting to port OpenWrt to this device, and I still do, but I got side tracked in my investigation and you’ll have to wait for a follow up post if I ever succeed to port OpenWrt.

    PCB front

    PCB front

    PCB Rear

    PCB Rear

    The UART runs at 57600 8N1.

    No pictures of the power supply because it’s just a boring 5V power source.

    Okay, so now that we know the UART pinout, what does the device say when it boots?

    Boot log:

    U-Boot 1.1.3 (Aug  8 2013 - 10:32:46)
    
    Board: Ralink APSoC DRAM:  64 MB
    relocate_code Pointer at: 83fb0000
    enable ephy clock...done. rf reg 29 = 5
    SSC disabled.
    spi_wait_nsec: 29 
    spi device id: c2 20 17 c2 20 (2017c220)
    find flash: MX25L6405D
    raspi_read: from:30000 len:1000 
    *** Warning - bad CRC, using default environment
    
    ============================================ 
    Ralink UBoot Version: 4.1.1.0
    -------------------------------------------- 
    ASIC 7620_MP (Port5None)
    DRAM component: 512 Mbits DDR, width 16
    DRAM bus: 16 bit
    Total memory: 64 MBytes
    Flash component: SPI Flash
    Date:Aug  8 2013  Time:10:32:46
    Cameo Version: v1.00 Build:01
    Module Name: D-Link DAP-1520A1
    ============================================ 
    icache: sets:512, ways:4, linesz:32 ,total:65536
    dcache: sets:256, ways:4, linesz:32 ,total:32768 
    
     ##### The CPU freq = 580 MHZ #### 
     estimate memory size =64 Mbytes
    raspi_read: from:50000 len:40 
    raspi_read: from:4f0000 len:40 
    
    =================================================
    Check image validation:
    Image1 Header Magic Number --> OK
    Image2 Header Magic Number --> OK
    Image1 Header Checksum --> OK
    Image2 Header Checksum --> OK
    Image1 Data Checksum --> raspi_read: from:50040 len:ddf98 
    OK
    Image2 Data Checksum --> raspi_read: from:4f0040 len:ca8f4 
    OK
    Image1 Stable Flag --> Not stable
    Image1 Try Counter --> 0
    
    Image1: OK Image2: OK
    Both images are OK!!!
    
    =================================================
    
    Please choose the operation: 
       1: Load system code to SDRAM via TFTP. 
       2: Load system code then write to Flash via TFTP. 
       3: Boot system code via Flash (default).
       4: Entr boot command line interface.
       7: Load Boot Loader code then write to Flash via Serial. 
       9: Load Boot Loader code then write to Flash via TFTP. 
     1  0 
       
    3: System Boot system code via Flash.
    ## Booting image at bc050000 ...
    raspi_read: from:50000 len:40 
       Image Name:   Linux Kernel Image
       Image Type:   MIPS Linux Kernel Image (lzma compressed)
       Data Size:    909208 Bytes = 887.9 kB
       Load Address: 80000000
       Entry Point:  8000c310
    raspi_read: from:50040 len:ddf98 
       Verifying Checksum ... OK
       Uncompressing Kernel Image ... OK
    No initrd
    ## Transferring control to Linux (at address 8000c310) ...
    ## Giving linux memsize in MB, 64
    
    Starting kernel ...
    
    
    LINUX started...
    
     THIS IS ASIC
    Linux version 2.6.36.x ([email protected]) (gcc version 3.4.2) #1 Fri Aug 22 16:26:27 CST 2014
    
     The CPU feqenuce set to 580 MHz
    
     MIPS CPU sleep mode enabled.
     PCIE: bypass PCIe DLL.
     PCIE: Elastic buffer control: Addr:0x68 -> 0xB4
     disable all power about PCIe
    CPU revision is: 00019650 (MIPS 24Kc)
    Determined physical RAM map:
     memory: 04000000 @ 00000000 (usable)
    Zone PFN ranges:
      Normal   0x00000000 -> 0x00004000
    Movable zone start PFN for each node
    early_node_map[1] active PFN ranges
        0: 0x00000000 -> 0x00004000
    Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 16256
    Kernel command line: console=ttyS1,57600n8 root=/dev/mtdblock5 console=ttyS0,57600 root=31:05 rootfstype=squashfs init=/sbin/init
    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)
    Primary instruction cache 64kB, VIPT, 4-way, linesize 32 bytes.
    Primary data cache 32kB, 4-way, PIPT, no aliases, linesize 32 bytes
    Writing ErrCtl register=0007efde
    Readback ErrCtl register=0007efde
    Memory: 62028k/65536k available (2225k kernel code, 3508k reserved, 338k data, 168k init, 0k highmem)
    NR_IRQS:128
    MTK/Ralink System Tick Counter init... cd:80271d98, m:214748, s:32
    console [ttyS1] enabled
    Calibrating delay loop... 386.04 BogoMIPS (lpj=772096)
    pid_max: default: 32768 minimum: 301
    Mount-cache hash table entries: 512
    NET: Registered protocol family 16
    RALINK_GPIOMODE = 1a311d
    RALINK_GPIOMODE = 18311d
    PPLL_CFG1=0xe90000
    MT7620 PPLL lock
    PPLL_DRV =0x80080504
    start PCIe register access
    RALINK_PCI_PCICFG_ADDR = 1000f0
    
    *************** MT7620 PCIe RC mode *************
    bio: create slab  at 0
    vgaarb: loaded
    pci 0000:00:00.0: BAR 8: assigned [mem 0x20000000-0x201fffff]
    pci 0000:00:00.0: BAR 1: assigned [mem 0x20200000-0x2020ffff]
    pci 0000:00:00.0: BAR 1: set to [mem 0x20200000-0x2020ffff] (PCI address [0x20200000-0x2020ffff]
    pci 0000:01:00.0: BAR 0: assigned [mem 0x20000000-0x200fffff]
    pci 0000:01:00.0: BAR 0: set to [mem 0x20000000-0x200fffff] (PCI address [0x20000000-0x200fffff]
    pci 0000:01:00.1: BAR 0: assigned [mem 0x20100000-0x201fffff]
    pci 0000:01:00.1: BAR 0: set to [mem 0x20100000-0x201fffff] (PCI address [0x20100000-0x201fffff]
    pci 0000:00:00.0: PCI bridge to [bus 01-01]
    pci 0000:00:00.0:   bridge window [io  disabled]
    pci 0000:00:00.0:   bridge window [mem 0x20000000-0x201fffff]
    pci 0000:00:00.0:   bridge window [mem pref disabled]
    BAR0 at slot 0 = 0
    bus=0x0, slot = 0x0
    res[0]->start = 0
    res[0]->end = 0
    res[1]->start = 20200000
    res[1]->end = 2020ffff
    res[2]->start = 0
    res[2]->end = 0
    res[3]->start = 0
    res[3]->end = 0
    res[4]->start = 0
    res[4]->end = 0
    res[5]->start = 0
    res[5]->end = 0
    bus=0x1, slot = 0x0
    res[0]->start = 20000000
    res[0]->end = 200fffff
    res[1]->start = 0
    res[1]->end = 0
    res[2]->start = 0
    res[2]->end = 0
    res[3]->start = 0
    res[3]->end = 0
    res[4]->start = 0
    res[4]->end = 0
    res[5]->start = 0
    res[5]->end = 0
    bus=0x1, slot = 0x0
    res[0]->start = 20100000
    res[0]->end = 201fffff
    res[1]->start = 0
    res[1]->end = 0
    res[2]->start = 0
    res[2]->end = 0
    res[3]->start = 0
    res[3]->end = 0
    res[4]->start = 0
    res[4]->end = 0
    res[5]->start = 0
    res[5]->end = 0
    Switching to clocksource Ralink external timer
    NET: Registered protocol family 2
    IP route cache hash table entries: 1024 (order: 0, 4096 bytes)
    TCP established hash table entries: 2048 (order: 2, 16384 bytes)
    TCP bind hash table entries: 2048 (order: 1, 8192 bytes)
    TCP: Hash tables configured (established 2048 bind 2048)
    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
    squashfs: version 4.0 (2009/01/31) Phillip Lougher
    msgmni has been set to 121
    Block layer SCSI generic (bsg) driver version 0.4 loaded (major 254)
    io scheduler noop registered (default)
    Ralink gpio driver initialized
    Serial: 8250/16550 driver, 2 ports, IRQ sharing disabled
    serial8250: ttyS0 at MMIO 0x10000500 (irq = 37) is a 16550A
    serial8250: ttyS1 at MMIO 0x10000c00 (irq = 12) is a 16550A
    brd: module loaded
    deice id : c2 20 17 c2 20 (2017c220)
    MX25L6405D(c2 2017c220) (8192 Kbytes)
    mtd .name = raspi, .size = 0x00800000 (0M) .erasesize = 0x00000008 (0K) .numeraseregions = 65536
    Creating 9 MTD partitions on "raspi":
    0x000000000000-0x000000800000 : "ALL"
    0x000000000000-0x000000030000 : "u-boot"
    0x000000030000-0x000000040000 : "nvram"
    0x000000040000-0x000000050000 : "Factory"
    0x000000050000-0x000000140000 : "linux4"
    0x000000140000-0x0000004e0000 : "rootfs"
    0x0000004e0000-0x0000004f0000 : "LANG"
    0x0000004f0000-0x0000005c0000 : "linux4b"
    0x0000005c0000-0x000000800000 : "rootfsb"
    rdm_major = 253
    SMACCR1 -- : 0x0000000c
    SMACCR0 -- : 0x43762077
    Ralink APSoC Ethernet Driver Initilization. v3.0  256 rx/tx descriptors allocated, mtu = 1500!
    SMACCR1 -- : 0x0000000c
    SMACCR0 -- : 0x43762077
    PROC INIT OK!
    TCP cubic registered
    NET: Registered protocol family 10
    IPv6 over IPv4 tunneling driver
    NET: Registered protocol family 17
    VFS: Mounted root (squashfs filesystem) readonly on device 31:5.
    Freeing unused kernel memory: 168k freed
    init started:  BusyBox v1.01 (2014.08.22-08:26+0000) multi-call binary
    Algorithmics/MIPS FPU Emulator v1.5
    devpts: called with bogus options
    init NVRAM_SPACE from mtdblock size
    init nvram memory map size: 0x10000 order of pages: 0x4
    nvram module init:
        /dev/nvram major number 225 glues to mtd: "nvram" size: 0x00010000
        nvram_space: 0x00010000 mapped via mmap(2)
    openfile :/etc/sysinfo
    openfile :/etc/nvram.default
    
    
    BusyBox v1.01 (2014.08.22-08:26+0000) Built-in shell (ash)
    Enter 'help' for a list of built-in commands.
    
    / # rm: cannot remove `/var/wizard_lang.js': No such file or directory
    umount: cannot umount /tmp/lang_pack: No such file or directory
    eth2: Cannot assign requested address
    Raeth v3.0 (Tasklet,SkbRecycle)
    
    phy_tx_ring = 0x03f4b000, tx_ring = 0xa3f4b000
    
    phy_rx_ring0 = 0x03f4c000, rx_ring0 = 0xa3f4c000
    SMACCR1 -- : 0x000054b8
    SMACCR0 -- : 0x0a7d19a6
    CDMA_CSG_CFG = 81000000
    GDMA1_FWD_CFG = 20710000
    umount: cannot umount /tmp/lang_pack: No such file or directory
    mount: mounting /dev/mtdblock6 on /tmp/lang_pack failed
    eth2: Cannot assign requested address
    device eth2 entered promiscuous mode
    TFTP main
    standard_tftp_server launched on port 69.
    killall: syslogd: no process killed
    killall: klogd: no process killed
    Sat Jan  1 00:00:00 UTC 2011
    /tmp/password has been created
    br0: port 1(eth2) entering forwarding state
    br0: port 1(eth2) entering forwarding state
    Set: phy[0].reg[0] = 3900
    Set: phy[1].reg[0] = 3900
    Set: phy[2].reg[0] = 3900
    Set: phy[3].reg[0] = 3900
    Set: phy[4].reg[0] = 3900
    Set: phy[0].reg[0] = 3100
    2011-01-01 00:00:00: (network.c.247) warning: please use server.use-ipv6 only for hostnames, not without server.bind / empty address; your config will break if the kernel default for IPV6_V6ONLY changes 
    rt2860v2_ap: module license 'unspecified' taints kernel.
    Disabling lock debugging due to kernel taint
    
    
    === pAd = c04cd000, size = 1278080 ===
    
    <-- RTMPAllocTxRxRingMemory, Status=0
    <-- RTMPAllocAdapterBlock, Status=0
    AP Driver version-2.7.1.6_edcca_monitor_20131222
    
    
    === pAd = c0b02000, size = 2010752 ===
    
    <-- RTMPAllocTxRxRingMemory, Status=0
    MT76x0_WLAN_ChipOnOff(): OnOff:1, pAd->WlanFunCtrl:0x0, Reg-WlanFunCtrl=0xff000002
    MACVersion = 0x76502000
    RX DESC a3672000  size = 2048
    RTMP_TimerListAdd: add timer obj c05a1e20!
    RTMP_TimerListAdd: add timer obj c053b694!
    RTMP_TimerListAdd: add timer obj c053f78c!
    RTMP_TimerListAdd: add timer obj c053f84c!
    RTMP_TimerListAdd: add timer obj c053f90c!
    RTMP_TimerListAdd: add timer obj c053f9cc!
    RTMP_TimerListAdd: add timer obj c053fa8c!
    RTMP_TimerListAdd: add timer obj c053fb4c!
    RTMP_TimerListAdd: add timer obj c053fc0c!
    RTMP_TimerListAdd: add timer obj c053fccc!
    RTMP_TimerListAdd: add timer obj c053fd8c!
    RTMP_TimerListAdd: add timer obj c053fe4c!
    RTMP_TimerListAdd: add timer obj c053ff0c!
    RTMP_TimerListAdd: add timer obj c053ffcc!
    RTMP_TimerListAdd: add timer obj c054008c!
    RTMP_TimerListAdd: add timer obj c054014c!
    RTMP_TimerListAdd: add timer obj c054020c!
    RTMP_TimerListAdd: add timer obj c05402cc!
    RTMP_TimerListAdd: add timer obj c0569e9c!
    RTMP_TimerListAdd: add timer obj c056df94!
    RTMP_TimerListAdd: add timer obj c056e054!
    RTMP_TimerListAdd: add timer obj c056e114!
    RTMP_TimerListAdd: add timer obj c056e1d4!
    RTMP_TimerListAdd: add timer obj c056e294!
    RTMP_TimerListAdd: add timer obj c056e354!
    RTMP_TimerListAdd: add timer obj c056e414!
    RTMP_TimerListAdd: add timer obj c056e4d4!
    RTMP_TimerListAdd: add timer obj c056e594!
    RTMP_TimerListAdd: add timer obj c056e654!
    RTMP_TimerListAdd: add timer obj c056e714!
    RTMP_TimerListAdd: add timer obj c056e7d4!
    RTMP_TimerListAdd: add timer obj c056e894!
    RTMP_TimerListAdd: add timer obj c056e954!
    RTMP_TimerListAdd: add timer obj c056ea14!
    RTMP_TimerListAdd: add timer obj c056ead4!
    RTMP_TimerListAdd: add timer obj c053b668!
    RTMP_TimerListAdd: add timer obj c053b6c0!
    RTMP_TimerListAdd: add timer obj c053f760!
    RTMP_TimerListAdd: add timer obj c053f820!
    RTMP_TimerListAdd: add timer obj c053f8e0!
    RTMP_TimerListAdd: add timer obj c053f9a0!
    RTMP_TimerListAdd: add timer obj c053fa60!
    RTMP_TimerListAdd: add timer obj c053fb20!
    RTMP_TimerListAdd: add timer obj c053fbe0!
    RTMP_TimerListAdd: add timer obj c053fca0!
    RTMP_TimerListAdd: add timer obj c053fd60!
    RTMP_TimerListAdd: add timer obj c053fe20!
    RTMP_TimerListAdd: add timer obj c053fee0!
    RTMP_TimerListAdd: add timer obj c053ffa0!
    RTMP_TimerListAdd: add timer obj c0540060!
    RTMP_TimerListAdd: add timer obj c0540120!
    RTMP_TimerListAdd: add timer obj c05401e0!
    RTMP_TimerListAdd: add timer obj c05402a0!
    RTMP_TimerListAdd: add timer obj c0569e70!
    RTMP_TimerListAdd: add timer obj c0569ec8!
    RTMP_TimerListAdd: add timer obj c056df68!
    RTMP_TimerListAdd: add timer obj c056e028!
    RTMP_TimerListAdd: add timer obj c056e0e8!
    RTMP_TimerListAdd: add timer obj c056e1a8!
    RTMP_TimerListAdd: add timer obj c056e268!
    RTMP_TimerListAdd: add timer obj c056e328!
    RTMP_TimerListAdd: add timer obj c056e3e8!
    RTMP_TimerListAdd: add timer obj c056e4a8!
    RTMP_TimerListAdd: add timer obj c056e568!
    RTMP_TimerListAdd: add timer obj c056e628!
    RTMP_TimerListAdd: add timer obj c056e6e8!
    RTMP_TimerListAdd: add timer obj c056e7a8!
    RTMP_TimerListAdd: add timer obj c056e868!
    RTMP_TimerListAdd: add timer obj c056e928!
    RTMP_TimerListAdd: add timer obj c056e9e8!
    RTMP_TimerListAdd: add timer obj c056eaa8!
    RTMP_TimerListAdd: add timer obj c053b63c!
    RTMP_TimerListAdd: add timer obj c0569e44!
    RTMP_TimerListAdd: add timer obj c053f7b8!
    RTMP_TimerListAdd: add timer obj c053f878!
    RTMP_TimerListAdd: add timer obj c053f938!
    RTMP_TimerListAdd: add timer obj c053f9f8!
    RTMP_TimerListAdd: add timer obj c053fab8!
    RTMP_TimerListAdd: add timer obj c053fb78!
    RTMP_TimerListAdd: add timer obj c053fc38!
    RTMP_TimerListAdd: add timer obj c053fcf8!
    RTMP_TimerListAdd: add timer obj c053fdb8!
    RTMP_TimerListAdd: add timer obj c053fe78!
    RTMP_TimerListAdd: add timer obj c053ff38!
    RTMP_TimerListAdd: add timer obj c053fff8!
    RTMP_TimerListAdd: add timer obj c05400b8!
    RTMP_TimerListAdd: add timer obj c0540178!
    RTMP_TimerListAdd: add timer obj c0540238!
    RTMP_TimerListAdd: add timer obj c05402f8!
    RTMP_TimerListAdd: add timer obj c053b710!
    RTMP_TimerListAdd: add timer obj c053b73c!
    RTMP_TimerListAdd: add timer obj c053b768!
    RTMP_TimerListAdd: add timer obj c056dfc0!
    RTMP_TimerListAdd: add timer obj c056e080!
    RTMP_TimerListAdd: add timer obj c056e140!
    RTMP_TimerListAdd: add timer obj c056e200!
    RTMP_TimerListAdd: add timer obj c056e2c0!
    RTMP_TimerListAdd: add timer obj c056e380!
    RTMP_TimerListAdd: add timer obj c056e440!
    RTMP_TimerListAdd: add timer obj c056e500!
    RTMP_TimerListAdd: add timer obj c056e5c0!
    RTMP_TimerListAdd: add timer obj c056e680!
    RTMP_TimerListAdd: add timer obj c056e740!
    RTMP_TimerListAdd: add timer obj c056e800!
    RTMP_TimerListAdd: add timer obj c056e8c0!
    RTMP_TimerListAdd: add timer obj c056e980!
    RTMP_TimerListAdd: add timer obj c056ea40!
    RTMP_TimerListAdd: add timer obj c056eb00!
    RTMP_TimerListAdd: add timer obj c0569f18!
    RTMP_TimerListAdd: add timer obj c0569f44!
    RTMP_TimerListAdd: add timer obj c0569f70!
    RTMP_TimerListAdd: add timer obj c04d5014!
    RTMP_TimerListAdd: add timer obj c04d4bf8!
    RTMP_TimerListAdd: add timer obj c04d4fe4!
    RTMP_TimerListAdd: add timer obj c04d5320!
    RTMP_TimerListAdd: add timer obj c04d5260!
    RTMP_TimerListAdd: add timer obj c04d5290!
    RTMP_TimerListAdd: add timer obj c04d8fbc!
    RTMP_TimerListAdd: add timer obj c04d8ba0!
    RTMP_TimerListAdd: add timer obj c04d8f8c!
    RTMP_TimerListAdd: add timer obj c04d92c8!
    RTMP_TimerListAdd: add timer obj c04d9208!
    RTMP_TimerListAdd: add timer obj c04d9238!
    RTMP_TimerListAdd: add timer obj c04dcf64!
    RTMP_TimerListAdd: add timer obj c04dcb48!
    RTMP_TimerListAdd: add timer obj c04dcf34!
    RTMP_TimerListAdd: add timer obj c04dd270!
    RTMP_TimerListAdd: add timer obj c04dd1b0!
    RTMP_TimerListAdd: add timer obj c04dd1e0!
    RTMP_TimerListAdd: add timer obj c04e0f0c!
    RTMP_TimerListAdd: add timer obj c04e0af0!
    RTMP_TimerListAdd: add timer obj c04e0edc!
    RTMP_TimerListAdd: add timer obj c04e1218!
    RTMP_TimerListAdd: add timer obj c04e1158!
    RTMP_TimerListAdd: add timer obj c04e1188!
    RTMP_TimerListAdd: add timer obj c04e4eb4!
    RTMP_TimerListAdd: add timer obj c04e4a98!
    RTMP_TimerListAdd: add timer obj c04e4e84!
    RTMP_TimerListAdd: add timer obj c04e51c0!
    RTMP_TimerListAdd: add timer obj c04e5100!
    RTMP_TimerListAdd: add timer obj c04e5130!
    RTMP_TimerListAdd: add timer obj c04e8e5c!
    RTMP_TimerListAdd: add timer obj c04e8a40!
    RTMP_TimerListAdd: add timer obj c04e8e2c!
    RTMP_TimerListAdd: add timer obj c04e9168!
    RTMP_TimerListAdd: add timer obj c04e90a8!
    RTMP_TimerListAdd: add timer obj c04e90d8!
    RTMP_TimerListAdd: add timer obj c04ece04!
    RTMP_TimerListAdd: add timer obj c04ec9e8!
    RTMP_TimerListAdd: add timer obj c04ecdd4!
    RTMP_TimerListAdd: add timer obj c04ed110!
    RTMP_TimerListAdd: add timer obj c04ed050!
    RTMP_TimerListAdd: add timer obj c04ed080!
    RTMP_TimerListAdd: add timer obj c04f0dac!
    RTMP_TimerListAdd: add timer obj c04f0990!
    RTMP_TimerListAdd: add timer obj c04f0d7c!
    RTMP_TimerListAdd: add timer obj c04f10b8!
    RTMP_TimerListAdd: add timer obj c04f0ff8!
    RTMP_TimerListAdd: add timer obj c04f1028!
    RTMP_TimerListAdd: add timer obj c053e5ec!
    RTMP_TimerListAdd: add timer obj c053e1d0!
    RTMP_TimerListAdd: add timer obj c053e5bc!
    RTMP_TimerListAdd: add timer obj c053e8f8!
    RTMP_TimerListAdd: add timer obj c053e61c!
    RTMP_TimerListAdd: add timer obj c053e64c!
    RTMP_TimerListAdd: add timer obj c053e67c!
    RTMP_TimerListAdd: add timer obj c056cdf4!
    RTMP_TimerListAdd: add timer obj c056c9d8!
    RTMP_TimerListAdd: add timer obj c056cdc4!
    RTMP_TimerListAdd: add timer obj c056d100!
    RTMP_TimerListAdd: add timer obj c056ce24!
    RTMP_TimerListAdd: add timer obj c056ce54!
    RTMP_TimerListAdd: add timer obj c056ce84!
    RTMP_TimerListAdd: add timer obj c057878c!
    RTMP_TimerListAdd: add timer obj c05788a8!
    RTMP_TimerListAdd: add timer obj c05787b8!
    RTMP_TimerListAdd: add timer obj c056fcc4!
    RTMP_TimerListAdd: add timer obj c04d24c4!
    RTMP_TimerListAdd: add timer obj c04d646c!
    RTMP_TimerListAdd: add timer obj c04da414!
    RTMP_TimerListAdd: add timer obj c04de3bc!
    RTMP_TimerListAdd: add timer obj c04e2364!
    RTMP_TimerListAdd: add timer obj c04e630c!
    RTMP_TimerListAdd: add timer obj c04ea2b4!
    RTMP_TimerListAdd: add timer obj c04ee25c!
    RTMP_TimerListAdd: add timer obj c056f9d0!
    APSDCapable[0]=0
    APSDCapable[1]=0
    APSDCapable[2]=0
    APSDCapable[3]=0
    APSDCapable[4]=0
    APSDCapable[5]=0
    APSDCapable[6]=0
    APSDCapable[7]=0
    APSDCapable[8]=0
    APSDCapable[9]=0
    APSDCapable[10]=0
    APSDCapable[11]=0
    APSDCapable[12]=0
    APSDCapable[13]=0
    APSDCapable[14]=0
    APSDCapable[15]=0
    default ApCliAPSDCapable[0]=0
    default ApCliAPSDCapable[1]=0
    start ch = 1, ch->num = 2
    30 30 30 30 
    30 30 30 30 30 30 30 30 
    26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
    start ch = 3, ch->num = 9
    30 30 30 30 
    30 30 30 30 30 30 30 30 
    26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 
    26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 
    start ch = 12, ch->num = 2
    30 30 30 30 
    30 30 30 30 30 30 30 30 
    26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
    start ch = 14, ch->num = 1
    30 30 30 30 
    0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
    1. Phy Mode = 9
    2. Phy Mode = 9
    E2PROM: D0 target power=0xff20 
    E2PROM: 40 MW Power Delta= 0 
    3. Phy Mode = 9
    AntCfgInit: primary/secondary ant 0/1
    Initialize RF Central Registers for E2 !!!
    Initialize RF Central Registers for E3 !!!
    Initialize RF Channel Registers for E2 !!!
    Initialize RF Channel Registers for E3 !!!
    Initialize RF DCCal Registers for E2 !!!
    Initialize RF DCCal Registers for E3 !!!
    D1 = -1, D2 = 16, CalCode = 40 !!!
    RT6352_Temperature_Init : BBPR49 = 0xffffffff
    RT6352_Temperature_Init : TemperatureRef25C = 0xfffffff5
    Current Temperature from BBP_R49=0xffffffec
    RT6352_TemperatureCalibration:: CurrentTemper 
    @@@ ed_monitor_init : <===
    Main bssid = 54:b8:0a:7d:19:a6
    
    @@@ ed_monitor_init : num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 38, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 40, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 42, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 44, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 46, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 48, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 52, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 54, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 56, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 58, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 60, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 62, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 64, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 100, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 102, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 104, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 106, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 108, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 110, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 112, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 116, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 118, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 120, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 122, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 124, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 126, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 128, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 132, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 134, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 136, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 140, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 149, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 151, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 153, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 155, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 157, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 159, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 161, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 165, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 169, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    start ch = 173, ch->num = 1
    0 0 0 0 
    38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    38 38 38 38 36 36 32 32 38 38 38 38 36 36 32 32 
    32 32 32 32 32 32 32 32 26 26 
    1. Phy Mode = 49
    2. Phy Mode = 49
    ext_pa_current_setting = 1
    3. Phy Mode = 49
    AntCfgInit: primary/secondary ant 0/1
    ChipStructAssign(): RALINK6590 hook !
    MCS Set = ff 00 00 00 01
    MT76x0_ChipBBPAdjust():rf_bw=2, ext_ch=1, PrimCh=36, HT-CentCh=38, VHT-CentCh=42
    MT76x0_ChipSwitchChannel: DefaultTargetPwr = 30
    APStartUp(): AP Set CentralFreq at 42(Prim=36, HT-CentCh=38, VHT-CentCh=42, BBP_BW=2)
    Main bssid = 54:b8:0a:7d:19:a8
    <==== rt28xx_init, Status=0
    MT76x0_ChipSwitchChannel: DefaultTargetPwr = 30
    MT76x0_ChipSwitchChannel: DefaultTargetPwr = 30
    MT76x0_ChipSwitchChannel: DefaultTargetPwr = 30
    MT76x0_ChipSwitchChannel: DefaultTargetPwr = 30
    MT76x0_ChipSwitchChannel: DefaultTargetPwr = 30
    MT76x0_ChipSwitchChannel: DefaultTargetPwr = 30
    MT76x0_ChipSwitchChannel: DefaultTargetPwr = 30
    MT76x0_ChipSwitchChannel: DefaultTargetPwr = 30
    MT76x0_ChipSwitchChannel: DefaultTargetPwr = 30
    MT76x0_ChipSwitchChannel: DefaultTargetPwr = 30
    MT76x0_ChipSwitchChannel: DefaultTargetPwr = 30
    MT76x0_ChipSwitchChannel: DefaultTargetPwr = 30
    MT76x0_ChipSwitchChannel: DefaultTargetPwr = 30
    RT6352_TemperatureCalibration:: CurrentTemper < 20 
    MT76x0_ChipSwitchChannel: DefaultTargetPwr = 30
    MT76x0_ChipSwitchChannel: DefaultTargetPwr = 30
    MT76x0_ChipSwitchChannel: DefaultTargetPwr = 30
    MT76x0_ChipSwitchChannel: DefaultTargetPwr = 30
    MT76x0_ChipSwitchChannel: DefaultTargetPwr = 30
    MT76x0_ChipSwitchChannel: DefaultTargetPwr = 30
    MT76x0_ChipSwitchChannel: DefaultTargetPwr = 30
    MT76x0_ChipSwitchChannel: DefaultTargetPwr = 30
    MT76x0_ChipSwitchChannel: DefaultTargetPwr = 30
    MT76x0_ChipSwitchChannel: DefaultTargetPwr = 30
    MT76x0_ChipBBPAdjust():rf_bw=2, ext_ch=1, PrimCh=44, HT-CentCh=46, VHT-CentCh=42
    MT76x0_ChipSwitchChannel: DefaultTargetPwr = 30
    APStartUp(): AP Set CentralFreq at 42(Prim=44, HT-CentCh=46, VHT-CentCh=42, BBP_BW=2)
    0x1300 = 00064380
    RTMPDrvOpen(1):Check if PDMA is idle!
    RTMPDrvOpen(2):Check if PDMA is idle!
    device rai0 entered promiscuous mode
    br0: port 4(rai0) entering forwarding state
    br0: port 4(rai0) entering forwarding state
    device apclii0 entered promiscuous mode
    br0: port 5(apclii0) entering forwarding state
    br0: port 5(apclii0) entering forwarding state
    Interface doesn't accept private ioctl...
    set (8BE2): Invalid argument
    killall: udhcpc: no process killed
    SIOCSIFFLAGS: Cannot assign requested address
    rm: cannot remove `/var/tmp/previous_dn': No such file or directory
    rm: cannot remove `/var/tmp/previous_dns': No such file or directory
    rm: cannot remove `/var/tmp/m_flag': No such file or directory
    rm: cannot remove `/var/tmp/o_flag': No such file or directory
    RTNETLINK answers: No such file or directory
    cat: /var/etc/resolv.conf: No such file or directory
    sh: cannot create /proc/sys/net/ipv6/conf/br0/disable_ipv6: Directory nonexistent
    Start IPv6 dhclient
    Sat Jan  1 00:00:00 UTC 2011
    rdnssd is already active !
    RT6352_TemperatureCalibration:: CurrentTemper < 20 
    Start IPv6 dhclient
    DHCP server start.
    device_lan_ip=192.168.0.50 , device_lan_subnet_mask=255.255.255.0
    max_leases value (254) not sane, setting to 20 instead
    Unable to open /var/misc/udhcpd.leases for reading
    llmnr: have no available linklocal address. wait count=0
    /tmp/password has been created
    2011-01-01 00:00:00: (network.c.247) warning: please use server.use-ipv6 only for hostnames, not without server.bind / empty address; your config will break if the kernel default for IPV6_V6ONLY changes 
    Failed to kill daemon: No such file or directory
    Daemon already running on PID 315
    RT6352_TemperatureCalibration:: CurrentTemper < 20 
    RT6352_TemperatureCalibration:: CurrentTemper < 20 
    RT6352_TemperatureCalibration:: CurrentTemper < 20
    

    Warning: Do not attempt to modify the firmware of this device if you do not have hardware to rewrite the firmware to the SPI flash. Before I even powered up the device the first time, I took a dump of the SPI flash in case I ended up “bricking” the device (which I did, many times).

    You can build your own SPI flash reader/writer with a Teensy and a chip clip. I am using the work of Trammell Hudson who gave an awesome talk at 31C3 on manipulating UEFI on MacBook Pros for fun and profit.

    You can find a copy of the SPI dump of my device (firmware 1.05) here. You cannot flash this image without hardware tools as described above. If you flash this dump, your device will have the same MAC address as mine. This dump should be used only as an option of last resort.

    Poking around the D-Link firmware for vulnerabilities

    I would love to say that I’m an infosec god, and that I can hack anything that moves. Really though, I’m not. I tried to find exploits for D-Link, and it doesn’t seem that there is any shortage of HNAP exploits and other nasty things, but I was unable to get the device to do any interesting things for me, like start a telnet server.

    Disassembling the firmware to learn more about installed software

    Since my Google-fu is weak, I couldn’t find the firmware images for this device on D-Link’s website at first, so I just disassembled the firmware I dumped from the MXIC.

    $ binwalk dlink-dap1520.bin 
    
    DECIMAL       HEXADECIMAL     DESCRIPTION
    --------------------------------------------------------------------------------
    99968         0x18680         U-Boot version string, "U-Boot 1.1.3 (Aug  8 2013 - 10:32:46)"
    100732        0x1897C         HTML document header
    101832        0x18DC8         HTML document footer
    101954        0x18E42         HTML document header
    102754        0x19162         HTML document footer
    102878        0x191DE         HTML document header
    105248        0x19B20         HTML document footer
    105367        0x19B97         HTML document header
    106050        0x19E42         HTML document footer
    106174        0x19EBE         HTML document header
    106255        0x19F0F         HTML document footer
    196962        0x30162         Unix path: /01/01/00/00/00
    327680        0x50000         uImage header, header size: 64 bytes, header CRC: 0xC9616E23, created: 2014-08-22 08:41:24, image size: 909208 bytes, Data Address: 0x80000000, Entry Point: 0x8000C310, data CRC: 0x895D3AE, OS: Linux, CPU: MIPS, image type: OS Kernel Image, compression type: lzma, image name: "Linux Kernel Image"
    327744        0x50040         LZMA compressed data, properties: 0x5D, dictionary size: 33554432 bytes, uncompressed size: 2798288 bytes
    1310720       0x140000        Squashfs filesystem, little endian, version 4.0, compression:xz, size: 3459080 bytes, 649 inodes, blocksize: 65536 bytes, created: 2014-08-22 08:41:35
    5177344       0x4F0000        uImage header, header size: 64 bytes, header CRC: 0x225D8E97, created: 2013-09-26 08:58:51, image size: 829684 bytes, Data Address: 0x80000000, Entry Point: 0x8000C310, data CRC: 0xA98529B2, OS: Linux, CPU: MIPS, image type: OS Kernel Image, compression type: lzma, image name: "Linux Kernel Image"
    5177408       0x4F0040        LZMA compressed data, properties: 0x5D, dictionary size: 33554432 bytes, uncompressed size: 2544052 bytes
    6029312       0x5C0000        Squashfs filesystem, little endian, version 4.0, compression:xz, size: 2192260 bytes, 345 inodes, blocksize: 65536 bytes, created: 2013-09-26 08:59:04
    

    Something interesting, there are two Squashfs filesystems on this device. This makes some sense, given what we saw earlier in the uboot logs:

    Check image validation:
    Image1 Header Magic Number --> OK
    Image2 Header Magic Number --> OK
    Image1 Header Checksum --> OK
    Image2 Header Checksum --> OK
    Image1 Data Checksum --> raspi_read: from:50040 len:ddf98 
    OK
    Image2 Data Checksum --> raspi_read: from:4f0040 len:ca8f4 
    OK
    Image1 Stable Flag --> Not stable
    Image1 Try Counter --> 0
    
    Image1: OK Image2: OK
    Both images are OK!!!

    Using dd, we can extract both Squashfs images from the firmware file. I used my dump, but actually I would recommend you just head over to D-Link's website and download the 1.06 firmware image [ZIP] and dump that instead. However, D-Link's firmware is missing the second Squashfs filesystem.

    Squashfs #1

    $ dd if=dlink-dap1520.bin of=squashfs1.bin bs=1 skip=1310720

    Squashfs #2

    $ dd if=dlink-dap1520.bin of=squashfs2.bin bs=1 skip=6029312

    Run the 'ol unsquashfs on squashfs1.bin and squashfs2.bin, and you'll have the extracted filesystems of the squashfs images in my dump the firmware. Remember to rename the directory squashfs-root between runs, or specify unsquashfs -d with a different directory name to decompress the images into respective directories.

    If you're using the D-Link firmware from their website, the dd command is a bit different due to offsets and all:

    $ binwalk DAP1520A1_FW106B04.bin
    
    DECIMAL       HEXADECIMAL     DESCRIPTION
    --------------------------------------------------------------------------------
    0             0x0             uImage header, header size: 64 bytes, header CRC: 0xBA3B64BA, created: 2015-01-22 03:48:48, image size: 909200 bytes, Data Address: 0x80000000, Entry Point: 0x8000C310, data CRC: 0x310BA125, OS: Linux, CPU: MIPS, image type: OS Kernel Image, compression type: lzma, image name: "Linux Kernel Image"
    64            0x40            LZMA compressed data, properties: 0x5D, dictionary size: 33554432 bytes, uncompressed size: 2798288 bytes
    983040        0xF0000         Squashfs filesystem, little endian, version 4.0, compression:xz, size: 3460300 bytes, 649 inodes, blocksize: 65536 bytes, created: 2015-01-22 03:48:54
    $ dd if=DAP1520A1_FW106B04.bin of=dlink106.bin bs=1 skip=983040

    Now unsquashfs that, and you'll have firmware 1.06 from D-Link.

    I'm going to leave investigation of the individual files in the firmware to the reader, but I'd like to state some facts I learned while investigating the firmware:

  • There are two copies of busybox on the firmware, versions 1.01 and 1.6.1. Some programs in /bin are linked to 1.01 and others to 1.6.1. I have no idea why D-Link would do this.
  • Pretty much everything on the device is run from /bin/cli and /bin/ssi. Other people on the web have analyzed these binaries and can tell you what they do (and how insecure they are).
  • The second squashfs image is the D-Link recovery OS. This OS will boot if the first kernel fails the integrity check performed in uboot. Hilariously, it won't boot into the recovery environment if you flash a bad kernel to the device in Image 1 as I found out.

    You might have noticed the flash layout from the binwalk of the firmware dump I made, but here is the actual firmware layout as reported by Linux:

    0x000000000000-0x000000800000 : "ALL"
    0x000000000000-0x000000030000 : "u-boot"
    0x000000030000-0x000000040000 : "nvram"
    0x000000040000-0x000000050000 : "Factory"
    0x000000050000-0x000000140000 : "linux4"
    0x000000140000-0x0000004e0000 : "rootfs"
    0x0000004e0000-0x0000004f0000 : "LANG"
    0x0000004f0000-0x0000005c0000 : "linux4b"
    0x0000005c0000-0x000000800000 : "rootfsb"

    To summarize:
    ALL: This spans from 0x000000 to 0x800000 which is the entire 8MB of the MXIC chip
    u-boot: u-boot loader
    nvram: Storage space for configuration variables. More on this in part 2
    Factory: No idea.
    linux4: This is the primary kernel on the device, and the one that will boot if your device has a valid Image 1. This is the firmware that you download from D-Link's website. Despite the label, it is not Linux 4.x, but 2.6.36.
    rootfs: Squashfs compressed filesystem of the primary OS (Image 1)
    LANG: No idea.
    linux4b: Recovery kernel. This kernel will be booted if Image 1 kernel fails verification.
    rootfsb: Squashfs compressed recovery filesystem. This, along with linux4b boot if Image 1 is corrupt and allow you to flash a firmware through the web interface to restore the device.

    I must say that the inclusion of a recovery OS is an interesting move on D-Link's part. Since I don't buy their products normally, I'm not sure if other D-Link devices also have this recovery OS on them. It seems like a good idea to include on this device, since if a firmware update fails, since there are no Ethernet ports on the device it's not possible to recover via TFTP, as it would be on a normal router. The firmware update from D-Link's website only updates Image 1 squashfs and kernel. Image 2 on my device is firmware version 1.00, and the squashfs filesystem is smaller than the Image 1 OS.

    If you do some maths on the mtd blocks, you will see that with the stock D-Link layout, the Image 1 kernel can only be 983040 bytes (0xF0000) large. Any larger, and the kernel will not fit in flash. The recovery kernel has to be even smaller, maximum 851968 bytes (0xD0000).

    Since this device lacks Ethernet ports, it doesn't include some of the features one would consider necessary on a home router, such as port forwarding, firewall configuration, and the like. I suspect that not needing to include these features gave D-Link the space on flash to store a recovery OS. As you can see though, they did have to make some compromises in the allocation of flash to fit the main and recovery OS within 8MB. The device does not function as a WiFi repeater in the recovery OS, only allowing you to reflash a firmware.

    As much as I would love to cram all of what I did into one post, this is getting long already.

    Stay tuned for part 2 where I compile the D-Link GPL firmware from source and backdoor the device to allow shell access without a login (infosec is hard). If you've heard horror stories about GPL firmwares before, they're all true...

    Come back soon!

    Arch Linux and SDIO WiFi on a Bay Trail tablet

    tl;dr If you just came to download the bootable USB stick filesystem to boot your tablet, click here.

    You will need to format a USB key (minimum 1GB) with a VFAT/FAT32 filesystem with the label ARCH_201512, unzip the contents of the file to the USB key, and read the section marked Grub near the bottom of this post to boot! It shouldn’t require Linux to set up the USB key.

    I highly recommend you make a backup of the tablet before you proceed to install Linux. The easiest/fastest/laziest way I have found is to use dd and pigz to make a block for block backup of the internal EMMC onto an ext4 formatted microSD card (as the archive will exceed the 4GB limit of VFAT).


    So, you have a Bay Trail based tablet, in my case a Dell Venue 8 Pro (model 3845), and you want to install Linux on it. Chances are pretty good that your tablet will use SDIO for WiFi, and this means that you will start the installer and quickly realize you have no WiFi. Bummer. Hope you’ve got a USB to Ethernet adapter with you, and a USB OTG hub with 3 ports.

    Or, you could compile a custom kernel with patches for the SDIO WiFi chipset, put it into the Arch Linux installer, and then have glorious WiFi for your installation.

    I chose the second option, because USB ethernet adapters are slow. And now I will tell you how I did it, so you too can do it too.

    First: you need to have a computer which can build a normal Linux kernel. I run Arch Linux also on my laptop, so just install the development tools and you can start:

    $ sudo pacman -S base-devel arch-install-scripts squashfs-tools
    

    Go download the latest stable Linux kernel from kernel.org, I used the following: https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.3.2.tar.xz

    Then you need to download the source code for the rtl8723bs WiFi chipset module (it is not in mainline yet):
    https://github.com/hadess/rtl8723bs

    Decompress the Linux source you downloaded earlier:

    $ tar -xf linux-4.3.2.tar.xz
    

    And decompress the rtl8723bs driver you downloaded earlier:

    $ unzip rtl8723bs-master.zip
    

    Don’t forget to apply the patches from the rtl8723bs driver:

    $ cd linux-4.3.2
    linux-4.3.2 ~$ patch -p1 < ../rtl8723bs-master/patches/0001-PM-QoS-Add-pm_qos_cancel_request_lazy-that-doesn-t-s.patch 
    patching file include/linux/pm_qos.h
    patching file kernel/power/qos.c
    linux-4.3.2 ~$ patch -p1 < ../rtl8723bs-master/patches/0001-mmc-sdhci-get-runtime-pm-when-sdio-irq-is-enabled.patch    
    patching file drivers/mmc/host/sdhci.c
    Hunk #1 succeeded at 1731 (offset -13 lines).
    Hunk #2 succeeded at 1743 (offset -13 lines).
    linux-4.3.2 ~$ patch -p1 < ../rtl8723bs-master/patches/0002-mmc-sdhci-Support-maximum-DMA-latency-request-via-PM.patch 
    patching file drivers/mmc/host/sdhci.c
    Hunk #2 succeeded at 1402 (offset 2 lines).
    Hunk #3 succeeded at 1427 (offset 2 lines).
    Hunk #4 succeeded at 2206 (offset 2 lines).
    Hunk #5 succeeded at 2279 (offset 2 lines).
    Hunk #6 succeeded at 2911 (offset 2 lines).
    Hunk #7 succeeded at 3407 (offset 2 lines).
    Hunk #8 succeeded at 3472 (offset 2 lines).
    Hunk #9 succeeded at 3529 (offset 2 lines).
    patching file drivers/mmc/host/sdhci.h
    Hunk #2 succeeded at 428 (offset 5 lines).
    linux-4.3.2 ~$ patch -p1 < ../rtl8723bs-master/patches/0003-mmc-sdhci-acpi-Fix-device-hang-on-Intel-BayTrail.patch     
    patching file drivers/mmc/host/sdhci-acpi.c
    linux-4.3.2 ~$ patch -p1 < ../rtl8723bs-master/patches/0004-mmc-sdhci-pci-Fix-device-hang-on-Intel-BayTrail.patch  
    patching file drivers/mmc/host/sdhci-pci.c
    

    If any of the patches fail to apply, do not proceed with building the kernel, you will not build a working kernel with SDIO WiFi support.

    Moving right along, I stole the stock Arch Linux configuration from the 2015.12 installer ISO and ran make oldconfig to bring it up to date on Linux 4.3.2.

    Here is a copy of the .config which you will want to use. The .config is inside the zip file, just move the zip file to the linux-4.3.2 directory and unzip.

    Verify that everything is cool with the .config file you decompressed (if you use a newer kernel this will prompt you to answer questions about new features supported which are not in the config file):

    linux-4.3.2 ~$ make oldconfig
    scripts/kconfig/conf  --oldconfig Kconfig
    #
    # configuration written to .config
    #
    linux-4.3.2 ~$ make -j 9
    

    Now wait a really long time. I will never understand why Arch Linux includes kernel modules for USB webcams in their text-only installer media…

    Now, while this is happening, download the latest Arch Linux live installation media, because we’re going to open it up and replace the kernel and squashfs:
    https://www.archlinux.org/download/

    I followed the excellent Arch Wiki instructions to remaster the install ISO:
    https://wiki.archlinux.org/index.php/Remastering_the_Install_ISO

    Mount the ISO somewhere:

    $ mkdir /tmp/archlinux-iso
    $ sudo mount -o loop archlinux-2015.12.01-dual.iso /tmp/archlinux-iso
    

    Since I have 16GB of RAM, I just do everything in /tmp because it’s a ramdisk and faster than an SSD:

    $ cp /tmp/archlinux-iso/arch/x86_64/airootfs.sfs /tmp/
    $ cd /tmp/
    $ unsquashfs airootfs.sfs
    

    Now, hopefully by now your kernel has finished building and we can install it to the recently unsquashed install ISO:

    linux-4.3.2 ~$ sudo make INSTALL_MOD_PATH=/tmp/squashfs-root modules_install
    linux-4.3.2 ~$ sudo cp arch/x86/boot/bzImage /tmp/squashfs-root/boot/vmlinuz
    

    This will install our kernel modules to the squashfs-root folder. Feel free to delete the modules from the previous kernel version if you want to save space (for me this was 4.2.5-1-ARCH):

    $ sudo rm -rf /tmp/squashfs-root/lib/modules/4.2.5-1-ARCH/
    

    Now, we need to build the rtl8723bs module:

    $ cd rtl8723bs-master
    rtl8723bs-master ~$ make KSRC=~/linux-4.3.2 KVER=4.3.2-ARCH
      (output omitted for brevity)
      Building modules, stage 2.
      MODPOST 1 modules
      CC      /home/hmartin/rtl8723bs-master/r8723bs.mod.o
      LD [M]  /home/hmartin/rtl8723bs-master/r8723bs.ko
    make[1]: Leaving directory '/home/hmartin/linux-4.3.2'
    rtl8723bs-master ~$ sudo cp r8723bs.ko /tmp/squashfs-root/lib/modules/4.3.2-ARCH/kernel/drivers/net/wireless/
    rtl8723bs-master ~$ sudo chmod 0644 /tmp/squashfs-root/lib/modules/4.3.2-ARCH/kernel/drivers/net/wireless/r8723bs.ko
    rtl8723bs-master ~$ sudo cp -n rtl8723bs_nic.bin /tmp/squashfs-root/lib/firmware/rtlwifi/rtl8723bs_nic.bin
    rtl8723bs-master ~$ sudo cp -n rtl8723bs_wowlan.bin /tmp/squashfs-root/lib/firmware/rtlwifi/rtl8723bs_wowlan.bin
    

    Okay, now we need to chroot into the decompressed squashfs filesystem to create an initrd. We need to modify /etc/mkinitcpio.conf in the squashfs root so we can generate an initrd with the correct modules and options, otherwise your tablet won’t boot with the new kernel:

    $ sudo arch-chroot /tmp/squashfs-root
    (chroot) $ depmod -a 4.3.2-ARCH
    (chroot) $ vi /etc/mkinitcpio.conf
    - MODULES=""
    + MODULES="r8723bs"
    - HOOKS="base udev autodetect modconf block filesystems keyboard fsck"
    + HOOKS="base udev memdisk archiso_shutdown archiso archiso_loop_mnt archiso_pxe_common archiso_pxe_nbd archiso_pxe_http archiso_pxe_nfs archiso_k
    ms block pcmcia filesystems keyboard"
    - #COMPRESSION="xz"
    + COMPRESSION="xz"
    

    Earlier we installed the 4.3.2-ARCH kernel modules, and also copied the kernel to /boot/ within the decompressed squashfs filesystem. Now we are going to use the modules, the vmlinuz kernel in /tmp/squashfs-root/boot/, and the above modifications to the /etc/mkinitcpio.conf file to generate a new initrd which we will call archiso.img:

    (chroot) $ mkinitcpio -k /boot/vmlinuz -c /etc/mkinitcpio.conf -g /boot/archiso.img -k 4.3.2-ARCH
    ==> Starting build: 4.3.2-ARCH
      -> Running build hook: [base]
      -> Running build hook: [udev]
      -> Running build hook: [memdisk]
      -> Running build hook: [archiso_shutdown]
      -> Running build hook: [archiso]
      -> Running build hook: [archiso_loop_mnt]
      -> Running build hook: [archiso_pxe_common]
    ==> WARNING: Possibly missing firmware for module: liquidio
      -> Running build hook: [archiso_pxe_nbd]
      -> Running build hook: [archiso_pxe_http]
      -> Running build hook: [archiso_pxe_nfs]
      -> Running build hook: [archiso_kms]
      -> Running build hook: [block]
    ==> WARNING: Possibly missing firmware for module: wd719x
    ==> WARNING: Possibly missing firmware for module: aic94xx
      -> Running build hook: [pcmcia]
      -> Running build hook: [filesystems]
      -> Running build hook: [keyboard]
    ==> Generating module dependencies
    ==> Creating xz-compressed initcpio image: /boot/archiso.img
    ==> Image generation successful
    

    Pack the contents of squashfs-root back into a squashfs image:

    /tmp ~$ mksquashfs squashfs-root airootfs.sfs
    

    Okay, now it’s time to create the USB boot media. You will need at least a 1GB USB key for this, and you will lose all the data current on the USB key.

    If your stick was previously formatted with a FAT32 partition, skip this step:

    $ sudo fdisk /dev/sdX
    
    Welcome to fdisk (util-linux 2.27.1).
    Changes will remain in memory only, until you decide to write them.
    Be careful before using the write command.
    
    Device does not contain a recognized partition table.
    Created a new DOS disklabel with disk identifier 0xfa02f14c.
    
    Command (m for help): o
    Created a new DOS disklabel with disk identifier 0xf1b89f31.
    
    Command (m for help): n
    Partition type
       p   primary (0 primary, 0 extended, 4 free)
       e   extended (container for logical partitions)
    Select (default p): p
    Partition number (1-4, default 1): 1
    First sector (2048-2097151, default 2048): 
    Last sector, +sectors or +size{K,M,G,T,P} (2048-2097151, default 2097151): 
    
    Created a new partition 1 of type 'Linux' and of size 1023 MiB.
    
    Command (m for help): t
    Selected partition 1
    Partition type (type L to list all types): c
    Changed type of partition 'Linux' to 'W95 FAT32 (LBA)'.
    
    Command (m for help): w
    The partition table has been altered.
    Calling ioctl() to re-read partition table.
    

    Now format and mount the USB key, this will erase all data on the USB key:

    $ sudo mkfs.vfat -n ARCH_201512 /dev/sdX1
    $ mkdir /tmp/archlinux-usb
    $ sudo mount /dev/sdX1 /tmp/archlinux-usb
    

    Copy the contents of the Arch installation ISO you mounted earlier to the USB key:

    $ sudo cp -R /tmp/archlinux-iso/* /tmp/archlinux-usb/
    

    Now, we need to replace the kernel, initrd, and squashfs filesystem on the USB key with the ones we made:

    $ sudo cp /tmp/squashfs-root/boot/vmlinuz /tmp/archlinux-usb/arch/boot/x86_64/vmlinuz
    $ sudo cp /tmp/squashfs-root/boot/archiso.img /tmp/archlinux-usb/arch/boot/x86_64/archiso.img
    $ sudo cp /tmp/airootfs.sfs /tmp/archlinux-usb/arch/x86_64/airootfs.sfs
    $ cd /tmp
    /tmp ~$ echo $(md5sum airootfs.sfs) | sudo tee /tmp/archlinux-usb/arch/x86_64/airootfs.md5
    

    Feel free to delete the i686 squashfs, since we did not compile an i686 kernel:

    $ sudo rm /tmp/archlinux-usb/arch/i686/airootfs.*
    

    If you’re building the boot media yourself, you will also need to put bootia32.efi in /tmp/archlinux-usb/EFI/boot/bootia32.efi since Bay Trail tablets only have 32-bit UEFI (the CPU is 64-bit). Download bootia32.efi here.


    In summary:

    1. We downloaded Linux kernel from kernel.org
    2. We downloaded the rtl8723bs driver from GitHub
    3. We applied the patches required for SDIO from rtl8723bs to the kernel source
    4. We compiled the kernel and modules using the default Arch Linux .config file
    5. We decompressed the squashfs filesystem present on the Arch Linux ISO
    6. We installed the kernel modules compiled earlier
    7. We compiled and installed the r8723bs kernel module in the decompressed squashfs filesystem
    8. We used chroot to run depmod and generate a new initrd using mkinitcpio inside the decompressed squashfs filesystem
    9. (optional) We deleted old kernel modules from the decompressed squashfs filesystem
    10. We recompressed the squashfs filesystem
    11. We formatted our USB installation media
    12. We copied the unmodified Arch Linux ISO contents to the USB installation media
    13. We replaced vmlinuz, initrd (archiso.img). and the x86_64 compressed squashfs filesystem on the USB installation media
    14. We installed bootia32.efi on the USB installation media

    Grub

    There is an issue with the install media which I haven’t bothered to diagnose. Grub will not display the normal boot menu, so you have to type in the commands manually. You need a keyboard anyway to configure WiFi and start SSH, so you might as well get one out now…

    set root=hd0,msdos1
    linux /arch/boot/x86_64/vmlinuz archisobasedir=arch archisolabel=ARCH_201512 nomodeset
    initrd /arch/boot/x86_64/archiso.img
    boot
    

    Wireless

    If all goes well, you will have a booted tablet with a wlan0 device. Follow the Arch instructions to configure wireless.

    Or, create /etc/wpa_supplicant/MyNetwork.conf with your network details:

    ctrl_interface=/var/run/wpa_supplicant
    update_config=1
    country=US
    
    network={
      ssid="MyNetwork"
      psk="Staple Horse Battery XKCD"
    }
    

    Up the interface with wpa_supplicant:

    $ wpa_supplicant -Dnl80211 -iwlan0 -c/etc/wpa_supplicant/MyNetwork.conf
    

    If all goes well, wpa_supplicant will find and connect to your network, but you still won’t have an IP address, so switch to another TTY (e.g. ctrl+alt+F2) and run dhclient to get an IP address:

    $ dhclient wlan0
    

    Set a root password and start SSH:

    $ passwd
    $ systemctl start sshd
    

    Find the IP address of your tablet:

    $ ip addr
    

    Now you should be able to SSH to your tablet from another computer, and complete the installation (I have censored my MAC addresses):
    venue_8_pro_archiso_wlan-clean


    Notes: I haven’t actually installed Arch Linux on my Dell Venue 8 Pro (3845) yet. I need to use it over the holidays and want it to work. I will try to post a follow up in the next few months about my experience installing and using Arch Linux on it.

    Also, I did this and wrote the post in one afternoon. Usually when I post something here, I work on it for several days and then sit on the draft in case there are any mistakes. However, since I am leaving for Christmas vacation shortly, I wanted to get this out quickly so people could read it over the holidays. There may be errors or omissions in the article which prevent it from working exactly as written. If I discover any errors, I will update the article to correct them.

    Unitymedia is blocking VPN connections

    unitymedia is a German ISP, and I made the unfortunate choice of using them as my internet service provider.

    Unfortunately, they’re not a very good ISP, because they are using deep packet inspection (DPI) to throttle or block VPN connections. I would expect this sort of behaviour from certain countries (a full list of countries engaging in internet censorship can be found here) but never in Germany.

    Obviously this claim cannot be made lightly. There must be some sort of proof to back up anyone who is claiming that a German ISP is filtering customer’s internet connectivity.

    Could this be a mistake?
    Possibly. Unitymedia does not have enough IPv4 addresses to give each customer a global IPv4 address. They are instead using something called DS-Lite in which each customer has a unique IPv6 address, and IPv4 connections are tunneled over IPv6 (4in6) to the carrier where customers then must go through carrier-grade nat (CGN) before reaching the internet.

    Other people have written about frequent TCP disconnections and poor connectivity on unitymedia (DE, English version here), but I believe they are going farther.

    The evidence
    I had a strong suspicion from my regular use that unitymedia was filtering connections, but I needed a good way to prove it.

    Since the most common use for a VPN is to get around region restrictions (honourable mention to YouTube DE and GEMA) or to download copyrighted content illegally, I thought torrenting Ubuntu 14.04 would be a good example use case.

    I installed Transmission and configured it to require encrypted connections. This will ensure that any network connections to peers will be encrypted UDP. I should also note that IPv6 was disabled on the computer, so only IPv4 connections are possible.

    So, for the first test, I downloaded the torrent for Ubuntu 14.04 LTS AMD64, and started downloading.

    encrypted_udp_torrent_novpn

    Everything is still working, good.

    Now I paused the torrent and logged in to a paid OpenVPN service on UDP port 1194. To prove that the connection is working, I will run a ping test to Google’s public DNS. This is what happened next:

    encrypted_udp_torrent_udpvpn

    Okay, so we are still downloading, but much slower than before. Unitymedia would not be the first ISP in the history of the uncensored world to throttle VPN connections.

    However, we cannot browse to websites. Chrome and Firefox just sit forever waiting for data from the remote server. To test my VPN connection, I tethered my phone to my PC and logged in to the VPN. Websites load perfectly.

    But, what if we tried a TCP-based OpenVPN connection? Let’s connect to an OpenVPN endpoint using TCP on port 443. In the upper right xterm I have logged into my router and I am filtering for TCP RST packets on my upstream WLAN connection (to the unitymedia router). We can see that the ping is still running, although we have not started to download anything yet.

    encrypted_udp_torrent_tcpvpn-working

    I resume the torrent and all of a sudden I receive 2 TCP RST packets and the connection is dead.

    encrypted_udp_torrent_tcpvpn-blocked

    This is absolutely unacceptable. Under no circumstances should an ISP ever be inserting TCP RST packets into a user’s connections. Here is the PCAP file with the TCP RST packets that ended my connection.

    ISPs inserting TCP RST packets to disrupt user connections is sadly not new. Comcast in the United States has been known to forge TCP RST packets for users who are using bittorrent, calling it “Network Management.” The EFF even compiled a report on Comcast’s shady behaviour. There is a Wikipedia article on the TCP reset attack if you want to know more about how it works.

    An ISP is providing a service to paying customers, and at no point should they ever interfere or attack a customer’s connections. Sadly these days the terms of service (ToS) are usually in favour of the service provider, and not the customer.

    I find it ironic that in Germany, which has spied on its citizens in the past, I cannot use such privacy enhancing technology as VPNs.

    There are many legitimate uses for a VPN such as: encrypting your internet traffic from your ISP, anonymizing yourself to avoid higher prices in online shopping, or getting cheaper plane tickets for your holiday.

    I have confirmed that this issue is not isolated to my Unitymedia connection. I have a friend living in another large German city, and their connection faces the same hostile behaviour from Unitymedia.

    Unitymedia’s filtering is also not limited to commercial VPN services. My work requires I use a VPN connection to access internal services, and I frequently experience disconnections, dropped packets, extreme throttling, and corrupted packets while trying to work.

    So, why am I writing this? I live in a free country, I can vote with my wallet and move to a different ISP. This is true, but if I did that, people who do not have the technical knowledge to diagnose connection problems would never know that Unitymedia is censoring their internet. Unitymedia would just be blasted for their DS-Lite implementation, and things would never improve.

    In conclusion:

    linus-torvalds-220612

    Unitymedia is sending forged TCP RST packets to disrupt TCP VPN connections. They are throttling, and I suspect also filtering, UDP VPN connections to a severe extent.

    thatwouldbegreat

    libvirt remote access with TLS and SASL

    In this post, we’re going to discuss how you can configure the libvirt daemon to use TLS and SASL so that remote connections are encrypted. Please ensure that you have the appropriate packages for libvirt and gnutls installed before proceeding. certtool is part of the gnutls-bin package in Debian.

    First we need to generate a CA certificate and key that will later be used to sign the server and client keys. If you already have a CA set up you can skip this step:

    $ certtool --generate-privkey --sec-param=high > cakey.pem
    Generating a 3072 bit RSA private key...
    $ cat ca.info
    cn = mydomain.co
    ca
    cert_signing_key
    $ certtool --generate-self-signed --sec-param=high --load-privkey cakey.pem
    --template ca.info --outfile cacert.pem
    certtool --generate-self-signed --sec-param=high --load-privkey cakey.pem --template ca.info --outfile cacert.pem
    Generating a self signed certificate...
    X.509 Certificate Information:
    	Version: 3
    	Serial Number (hex): 544bafeb011c172fe279cd4b
    	Validity:
    		Not Before: Sat Oct 25 14:12:59 UTC 2014
    		Not After: Sun Oct 25 14:12:59 UTC 2015
    	Subject: CN=example.com
    	Subject Public Key Algorithm: RSA
    	Algorithm Security Level: High (3072 bits)
    		Modulus (bits 3072):
    			00:c0:72:2b:64:26:c4:76:dd:ab:b1:f7:67:67:22:f1
    			ff:31:03:b8:9d:9f:9e:c0:01:b9:db:de:50:f0:61:ff
    			0d:f5:ae:8a:96:e4:e6:75:a3:56:4d:41:7c:49:4c:6d
    			25:7f:de:b8:77:87:9d:c1:8b:4b:36:70:d4:a9:d9:c7
    			93:cb:a9:39:b1:73:29:b5:d9:5b:01:e2:60:57:f1:4b
    			42:a5:15:e8:e8:77:2b:3e:ec:4c:2a:0e:0f:0c:61:68
    			84:1e:09:9b:9d:7d:0a:87:97:24:07:a2:3d:06:c9:fa
    			91:cb:72:f1:61:01:a6:8b:6d:93:1f:dd:33:d9:1b:e9
    			3c:23:39:36:c2:a4:df:3c:44:d2:8e:b4:e4:20:37:11
    			36:7f:b7:9f:14:cd:d5:df:dc:16:fd:a8:a5:09:fa:ad
    			cf:32:62:7e:0d:e2:af:80:f3:7a:bb:e9:d8:93:1d:6c
    			f6:e2:4b:dd:2f:da:46:ce:fd:c7:41:95:9c:55:ee:66
    			a7:03:81:f9:8b:db:3b:03:a1:67:24:47:9a:25:3a:ba
    			30:77:34:4e:62:87:54:91:a6:09:09:a6:84:e4:93:76
    			09:b8:d3:5d:03:1b:2e:ea:aa:4a:6f:c3:99:1f:35:7d
    			74:0d:37:0f:a1:ae:82:6d:fc:5b:4f:b3:6d:5b:d3:f2
    			9f:65:fa:88:24:f9:2c:40:2a:88:72:23:80:7c:83:cb
    			95:2e:61:f2:38:3f:33:f9:08:4b:5f:72:ae:da:18:50
    			ed:d3:fd:22:9a:3e:3a:7d:f2:7e:c3:ea:f9:92:d0:62
    			3d:5c:15:98:a0:a8:96:0f:75:66:ed:72:48:56:42:46
    			c7:de:39:e3:9e:11:84:3d:bb:98:78:a1:33:c8:02:1d
    			d3:c3:2e:93:fc:b9:16:bb:de:3d:3a:37:ee:1b:c6:7b
    			09:04:6e:5b:9d:2b:22:0e:ba:c4:b6:d2:29:f7:e1:fc
    			80:a3:ec:fb:ab:44:d9:fe:d4:4c:4c:cd:19:76:fc:4e
    			2f
    		Exponent (bits 24):
    			01:00:01
    	Extensions:
    		Basic Constraints (critical):
    			Certificate Authority (CA): TRUE
    		Key Usage (critical):
    			Certificate signing.
    		Subject Key Identifier (not critical):
    			51768ae1aea87f9bf1c60b103bc74db7b8b4480a
    Other Information:
    	Public Key ID:
    		51768ae1aea87f9bf1c60b103bc74db7b8b4480a
    	Public key's random art:
    		+--[ RSA 3072]----+
    		|        . o .    |
    		|       . = o     |
    		|    .   = o      |
    		|     + + + .     |
    		|  E + + S .      |
    		|   . B + o       |
    		|    o =.o        |
    		|   .  .=o        |
    		|  ....ooo.       |
    		+-----------------+
    
    
    
    Signing certificate...
    # inspect the CA cert to ensure it was generated properly
    $ certtool -i --infile cacert.pem
    X.509 Certificate Information:
    	Version: 3
    	Serial Number (hex): 544bafeb011c172fe279cd4b
    	Issuer: CN=example.com
    	Validity:
    		Not Before: Sat Oct 25 14:12:59 UTC 2014
    		Not After: Sun Oct 25 14:12:59 UTC 2015
    	Subject: CN=example.com
    	Subject Public Key Algorithm: RSA
    	Algorithm Security Level: High (3072 bits)
    		Modulus (bits 3072):
    			00:c0:72:2b:64:26:c4:76:dd:ab:b1:f7:67:67:22:f1
    			ff:31:03:b8:9d:9f:9e:c0:01:b9:db:de:50:f0:61:ff
    			0d:f5:ae:8a:96:e4:e6:75:a3:56:4d:41:7c:49:4c:6d
    			25:7f:de:b8:77:87:9d:c1:8b:4b:36:70:d4:a9:d9:c7
    			93:cb:a9:39:b1:73:29:b5:d9:5b:01:e2:60:57:f1:4b
    			42:a5:15:e8:e8:77:2b:3e:ec:4c:2a:0e:0f:0c:61:68
    			84:1e:09:9b:9d:7d:0a:87:97:24:07:a2:3d:06:c9:fa
    			91:cb:72:f1:61:01:a6:8b:6d:93:1f:dd:33:d9:1b:e9
    			3c:23:39:36:c2:a4:df:3c:44:d2:8e:b4:e4:20:37:11
    			36:7f:b7:9f:14:cd:d5:df:dc:16:fd:a8:a5:09:fa:ad
    			cf:32:62:7e:0d:e2:af:80:f3:7a:bb:e9:d8:93:1d:6c
    			f6:e2:4b:dd:2f:da:46:ce:fd:c7:41:95:9c:55:ee:66
    			a7:03:81:f9:8b:db:3b:03:a1:67:24:47:9a:25:3a:ba
    			30:77:34:4e:62:87:54:91:a6:09:09:a6:84:e4:93:76
    			09:b8:d3:5d:03:1b:2e:ea:aa:4a:6f:c3:99:1f:35:7d
    			74:0d:37:0f:a1:ae:82:6d:fc:5b:4f:b3:6d:5b:d3:f2
    			9f:65:fa:88:24:f9:2c:40:2a:88:72:23:80:7c:83:cb
    			95:2e:61:f2:38:3f:33:f9:08:4b:5f:72:ae:da:18:50
    			ed:d3:fd:22:9a:3e:3a:7d:f2:7e:c3:ea:f9:92:d0:62
    			3d:5c:15:98:a0:a8:96:0f:75:66:ed:72:48:56:42:46
    			c7:de:39:e3:9e:11:84:3d:bb:98:78:a1:33:c8:02:1d
    			d3:c3:2e:93:fc:b9:16:bb:de:3d:3a:37:ee:1b:c6:7b
    			09:04:6e:5b:9d:2b:22:0e:ba:c4:b6:d2:29:f7:e1:fc
    			80:a3:ec:fb:ab:44:d9:fe:d4:4c:4c:cd:19:76:fc:4e
    			2f
    		Exponent (bits 24):
    			01:00:01
    	Extensions:
    		Basic Constraints (critical):
    			Certificate Authority (CA): TRUE
    		Key Usage (critical):
    			Certificate signing.
    		Subject Key Identifier (not critical):
    			51768ae1aea87f9bf1c60b103bc74db7b8b4480a
    	Signature Algorithm: RSA-SHA256
    	Signature:
    		7f:f2:41:4a:1b:23:34:48:f0:1d:03:1d:ee:94:51:86
    		8f:5c:ff:c6:69:db:f3:8e:9a:be:5d:82:47:a3:e0:c2
    		1f:e4:eb:1d:3c:9f:63:a2:40:b4:6a:cd:dd:48:74:d1
    		03:67:b2:04:c5:27:30:04:75:5b:32:7f:ec:cb:c3:cc
    		3d:f8:d2:60:64:62:20:d5:29:a9:67:70:76:d4:34:a0
    		a1:fe:34:97:f4:42:7e:bc:67:0a:35:c8:c9:53:35:13
    		65:d2:4f:10:d3:ed:cd:6c:2f:3e:a9:0a:56:0f:48:5f
    		17:1c:4c:14:2b:c8:c5:77:01:d1:73:6c:08:45:d3:1c
    		e2:24:46:53:f9:2a:7b:dd:fe:19:6c:8d:b0:17:ad:c3
    		f1:56:3c:dd:e7:da:02:57:3c:56:42:c8:1a:d7:59:e0
    		38:fb:f6:7a:ed:88:7b:e6:86:66:58:2c:ce:6a:d9:00
    		a8:2e:6b:f4:c1:61:a1:19:d2:d6:46:92:1c:84:2a:c6
    		85:34:56:c8:22:d9:cd:23:98:3f:33:7e:2a:f0:f4:e9
    		9a:f4:bf:dd:83:52:38:5f:cc:d3:5e:4b:c8:9f:61:7a
    		c9:28:8b:39:b3:10:84:08:75:6b:1f:82:74:7f:b2:a8
    		7b:7c:50:0f:59:54:fc:b9:9e:f8:62:07:2d:1d:3d:9b
    		16:39:95:6e:4a:fb:c0:2b:a2:2e:7d:f1:fa:11:95:66
    		81:57:9c:33:be:19:e4:41:1b:31:39:1e:5f:e8:28:41
    		ef:0c:99:bc:e1:7a:6f:78:65:b2:c0:86:d2:2f:a7:81
    		85:58:ca:41:df:b3:b4:de:a2:fe:6f:ed:3e:6b:ad:b8
    		db:9c:f9:39:c1:e7:9e:c9:1e:47:11:b6:e7:f5:57:ae
    		25:eb:8d:ae:53:7d:9d:48:f5:a3:3a:7d:1b:7b:58:a1
    		32:ae:7e:bb:04:56:ca:e5:c6:40:c3:7d:cb:e0:be:cd
    		c9:7f:10:66:bc:75:87:82:2c:c8:db:a4:11:c6:e3:24
    Other Information:
    	SHA1 fingerprint:
    		58ecea66161b1fdd4b292c83a631be8f870ceebd
    	SHA256 fingerprint:
    		779ed901764da3ef9f6a4326dfb3067617e0d9c75ccadd3ea542a2e7c7ed8be6
    	Public Key ID:
    		51768ae1aea87f9bf1c60b103bc74db7b8b4480a
    	Public key's random art:
    		+--[ RSA 3072]----+
    		|        . o .    |
    		|       . = o     |
    		|    .   = o      |
    		|     + + + .     |
    		|  E + + S .      |
    		|   . B + o       |
    		|    o =.o        |
    		|   .  .=o        |
    		|  ....ooo.       |
    		+-----------------+
    
    -----BEGIN CERTIFICATE-----
    MIID+TCCAmGgAwIBAgIMVEuv6wEcFy/iec1LMA0GCSqGSIb3DQEBCwUAMBYxFDAS
    BgNVBAMTC2V4YW1wbGUuY29tMCIYDzIwMTQxMDI1MTQxMjU5WhgPMjAxNTEwMjUx
    NDEyNTlaMBYxFDASBgNVBAMTC2V4YW1wbGUuY29tMIIBojANBgkqhkiG9w0BAQEF
    AAOCAY8AMIIBigKCAYEAwHIrZCbEdt2rsfdnZyLx/zEDuJ2fnsABudveUPBh/w31
    roqW5OZ1o1ZNQXxJTG0lf964d4edwYtLNnDUqdnHk8upObFzKbXZWwHiYFfxS0Kl
    Fejodys+7EwqDg8MYWiEHgmbnX0Kh5ckB6I9Bsn6kcty8WEBpottkx/dM9kb6Twj
    OTbCpN88RNKOtOQgNxE2f7efFM3V39wW/ailCfqtzzJifg3ir4Dzervp2JMdbPbi
    S90v2kbO/cdBlZxV7manA4H5i9s7A6FnJEeaJTq6MHc0TmKHVJGmCQmmhOSTdgm4
    010DGy7qqkpvw5kfNX10DTcPoa6CbfxbT7NtW9Pyn2X6iCT5LEAqiHIjgHyDy5Uu
    YfI4PzP5CEtfcq7aGFDt0/0imj46ffJ+w+r5ktBiPVwVmKColg91Zu1ySFZCRsfe
    OeOeEYQ9u5h4oTPIAh3Twy6T/LkWu949OjfuG8Z7CQRuW50rIg66xLbSKffh/ICj
    7PurRNn+1ExMzRl2/E4vAgMBAAGjQzBBMA8GA1UdEwEB/wQFMAMBAf8wDwYDVR0P
    AQH/BAUDAwcEADAdBgNVHQ4EFgQUUXaK4a6of5vxxgsQO8dNt7i0SAowDQYJKoZI
    hvcNAQELBQADggGBAH/yQUobIzRI8B0DHe6UUYaPXP/Gadvzjpq+XYJHo+DCH+Tr
    HTyfY6JAtGrN3Uh00QNnsgTFJzAEdVsyf+zLw8w9+NJgZGIg1SmpZ3B21DSgof40
    l/RCfrxnCjXIyVM1E2XSTxDT7c1sLz6pClYPSF8XHEwUK8jFdwHRc2wIRdMc4iRG
    U/kqe93+GWyNsBetw/FWPN3n2gJXPFZCyBrXWeA4+/Z67Yh75oZmWCzOatkAqC5r
    9MFhoRnS1kaSHIQqxoU0Vsgi2c0jmD8zfirw9Oma9L/dg1I4X8zTXkvIn2F6ySiL
    ObMQhAh1ax+CdH+yqHt8UA9ZVPy5nvhiBy0dPZsWOZVuSvvAK6IuffH6EZVmgVec
    M74Z5EEbMTkeX+goQe8Mmbzhem94ZbLAhtIvp4GFWMpB37O03qL+b+0+a62425z5
    OcHnnskeRxG25/VXriXrja5TfZ1I9aM6fRt7WKEyrn67BFbK5cZAw33L4L7NyX8Q
    Zrx1h4IsyNukEcbjJA==
    -----END CERTIFICATE-----
    

    Now that we have a CA certificate and signing key we need to generate a server key for the libvirt host:

    $ certtool --generate-privkey --sec-param=high > serverkey.pem
    Generating a 3072 bit RSA private key...
    $ cat libvirt_server.info 
    organization = example.com
    cn = libvirt.example.com
    tls_www_server
    encryption_key
    signing_key
    $ certtool --generate-certificate --sec-param=high --load-privkey serverkey.pem --load-ca-certificate cacert.pem --load-ca-privkey cakey.pem --template libvirt_server.info --outfile servercert.pem
    Generating a signed certificate...
    X.509 Certificate Information:
    	Version: 3
    	Serial Number (hex): 544bb10a049f2eaca4b04d94
    	Validity:
    		Not Before: Sat Oct 25 14:17:46 UTC 2014
    		Not After: Sun Oct 25 14:17:46 UTC 2015
    	Subject: CN=libvirt.example.com,O=example.com
    	Subject Public Key Algorithm: RSA
    	Algorithm Security Level: High (3072 bits)
    		Modulus (bits 3072):
    			00:eb:77:a6:12:6f:a5:a6:b1:aa:9b:b2:fa:aa:38:48
    			52:9c:4f:5b:ae:0b:2f:08:71:6e:6e:25:21:88:d2:3a
    			eb:16:08:98:70:ee:30:2b:bb:11:42:c8:c7:e8:f9:eb
    			f3:c6:1e:b5:76:2b:dd:c3:5f:63:10:87:33:45:bd:f3
    			ac:7b:a0:da:bd:05:8e:fa:75:0f:de:27:b8:1a:23:d4
    			86:ba:0a:52:11:8a:55:83:e1:6c:68:2e:b5:74:10:1d
    			21:35:14:d8:6f:11:14:67:59:f9:b3:db:fc:9a:5b:3c
    			5d:91:bb:d2:30:74:a6:45:99:e1:a2:f4:5d:e9:a1:bd
    			68:fc:ba:63:3c:91:95:cd:5d:99:f0:75:8c:ac:26:9a
    			70:44:47:ae:e7:70:95:b8:25:b2:fd:42:99:bf:74:a1
    			54:e4:4f:14:ae:05:3b:d7:5d:85:c6:d8:5a:72:aa:28
    			8c:a4:c5:0d:bb:86:44:d2:b0:9c:c8:c9:c9:a5:ab:c2
    			1b:dd:b9:73:dd:ac:f7:9e:d0:4a:9a:fa:c0:ea:bb:8c
    			07:93:80:64:12:08:78:ff:50:37:3b:3f:e1:ee:5b:89
    			c6:47:fd:f6:7d:80:6f:e4:1a:7c:5e:62:c0:36:dc:eb
    			6c:66:85:50:3d:f7:1b:e0:9f:5f:9b:62:a3:d7:1a:4c
    			8f:3b:b1:4f:a7:f0:9f:95:ef:ac:ac:58:aa:db:e1:fb
    			75:64:7a:77:c3:59:61:56:65:9d:d7:c6:51:be:70:48
    			ae:b3:c1:98:b5:7e:12:b7:59:8e:76:90:e1:de:48:b7
    			ce:1f:15:82:cc:85:1e:08:ba:66:4b:14:ce:f4:bd:a8
    			60:21:f0:21:66:a1:6d:a9:38:ec:8e:a4:67:43:ef:a5
    			64:8d:14:7d:93:8f:28:85:6a:41:b2:e1:b6:62:19:1b
    			1f:5a:b1:6a:85:bf:b7:1a:31:3c:c7:25:a8:43:ee:6f
    			94:0c:43:0c:9b:a8:81:7d:77:50:0a:d5:fb:f0:52:b4
    			fd
    		Exponent (bits 24):
    			01:00:01
    	Extensions:
    		Basic Constraints (critical):
    			Certificate Authority (CA): FALSE
    		Key Purpose (not critical):
    			TLS WWW Server.
    		Key Usage (critical):
    			Digital signature.
    			Key encipherment.
    		Subject Key Identifier (not critical):
    			83d19f1391ea516d2d499f7c94ac1c9703b44cd7
    		Authority Key Identifier (not critical):
    			51768ae1aea87f9bf1c60b103bc74db7b8b4480a
    Other Information:
    	Public Key ID:
    		83d19f1391ea516d2d499f7c94ac1c9703b44cd7
    	Public key's random art:
    		+--[ RSA 3072]----+
    		|          .+o*o.=|
    		|       .  o.B++OE|
    		|      . .o...+B o|
    		|       oo. o o . |
    		|      ..S.+      |
    		|        .. .     |
    		|                 |
    		|                 |
    		|                 |
    		+-----------------+
    
    
    
    Signing certificate...
    $ certtool --generate-privkey --sec-param=high > clientkey.pem
    Generating a 3072 bit RSA private key...
    $ cat client1.info
    country = DE
    organization = example.com
    cn = client1.example.com
    tls_www_client
    encryption_key
    signing_key
    $ certtool --generate-certificate --sec-param=high --load-privkey clientkey.pem  --load-ca-certificate cacert.pem --load-ca-privkey cakey.pem   --template client1.info --outfile client1cert.pem
    Generating a signed certificate...
    X.509 Certificate Information:
    	Version: 3
    	Serial Number (hex): 544bb184075bcf2e62d42003
    	Validity:
    		Not Before: Sat Oct 25 14:19:48 UTC 2014
    		Not After: Sun Oct 25 14:19:48 UTC 2015
    	Subject: CN=client1.example.com,O=example.com,C=DE
    	Subject Public Key Algorithm: RSA
    	Algorithm Security Level: High (3072 bits)
    		Modulus (bits 3072):
    			00:bb:c4:26:e1:ab:bf:ea:bc:db:b2:88:c0:6e:9a:d4
    			a6:97:fc:cc:3a:8e:ae:49:69:80:35:86:0f:2d:a6:36
    			e9:ac:8e:7a:04:bd:d9:4c:0f:85:d7:80:bf:5e:26:37
    			38:40:20:03:9a:c2:49:ed:a1:4f:42:9e:be:28:12:a8
    			00:42:6c:6e:7d:08:0d:b8:bf:72:ef:2b:2e:a6:68:40
    			df:ec:97:00:75:48:f6:96:03:a9:46:71:2b:db:99:3a
    			ab:28:00:01:09:60:be:7d:a3:cd:0c:44:b9:99:35:91
    			04:3d:96:48:9b:26:06:ca:4f:3f:18:84:37:84:8b:8a
    			b1:fd:9b:5f:00:b7:89:b6:f7:32:75:1b:cb:33:12:cc
    			b0:ff:b6:05:58:08:df:54:24:da:73:4e:fd:6f:e7:2b
    			59:16:5e:a7:7b:1b:86:ee:38:02:73:09:bd:a8:73:60
    			eb:7f:87:12:c6:fe:b8:c4:c3:e4:ea:85:c4:43:94:5c
    			dc:a3:ca:73:4a:08:0d:0a:8a:de:51:c7:c1:bf:f3:39
    			91:54:cc:44:00:9c:a8:bc:0a:de:e3:20:63:04:dc:e8
    			c3:52:0c:0e:34:43:8a:00:0a:19:07:d0:63:cf:c4:a3
    			4e:01:52:7f:33:89:24:47:9d:e1:3d:75:5c:76:2f:f0
    			91:21:ce:cd:9a:97:64:03:2e:6b:4f:31:27:cf:d2:8c
    			83:83:83:82:5b:76:a4:b7:7a:43:da:d7:40:32:69:aa
    			04:27:1b:40:91:04:df:ce:35:b2:d7:f6:24:9f:3b:3c
    			f4:c6:f8:33:80:e3:43:c7:b0:dc:d5:42:f9:fb:0c:df
    			d7:04:44:24:47:49:ca:d2:13:19:91:fa:48:31:92:4f
    			5a:73:86:02:78:3c:25:75:32:f3:24:7d:e3:c6:57:68
    			62:f2:a9:76:d5:81:5b:50:64:27:42:a2:6d:1e:e7:b6
    			79:85:f9:31:18:33:74:08:78:91:90:e2:fe:9d:97:42
    			73
    		Exponent (bits 24):
    			01:00:01
    	Extensions:
    		Basic Constraints (critical):
    			Certificate Authority (CA): FALSE
    		Key Purpose (not critical):
    			TLS WWW Client.
    		Key Usage (critical):
    			Digital signature.
    			Key encipherment.
    		Subject Key Identifier (not critical):
    			77f16cb983bae8ee1e205e5f60340bb5793af951
    		Authority Key Identifier (not critical):
    			51768ae1aea87f9bf1c60b103bc74db7b8b4480a
    Other Information:
    	Public Key ID:
    		77f16cb983bae8ee1e205e5f60340bb5793af951
    	Public key's random art:
    		+--[ RSA 3072]----+
    		|      ..+        |
    		|       o =       |
    		|        * . E    |
    		|       . = . + . |
    		|    . o S + . =  |
    		|   . o o = o o . |
    		|    .   o . . o  |
    		|         o .   . |
    		|       =* o.     |
    		+-----------------+
    
    
    
    Signing certificate...
    

    We’ve just created a CA certificate and signing key, a certificate and key for the libvirt server, and a client certificate/key pair for a client (e.g. a laptop).

    Now we need to install the certificates in the appropriate places:

    $ sudo mkdir -p /etc/pki/CA /etc/pki/libvirt/private
    $ sudo cp cacert.pem /etc/pki/CA/cacert.pem
    $ sudo chmod 0644 /etc/pki/CA/cacert.pem
    $ sudo cp servercert.pem /etc/pki/libvirt/servercert.pem
    $ sudo chmod 0644 /etc/pki/libvirt/servercert.pem
    $ sudo cp serverkey.pem /etc/pki/libvirt/private/serverkey.pem
    $ sudo chmod 0600 /etc/pki/libvirt/private/serverkey.pem
    

    Edit the libvirt configuration to listen for TLS connections and use SASL for authentication:

    $ sudo vi /etc/libvirt/libvirtd.conf
    # Override the default configuration which binds to all network
    # interfaces. This can be a numeric IPv4/6 address, or hostname
    #
    listen_addr = "10.0.0.10"
    auth_tls = "sasl"
    

    On Debian you need to edit the libvirt daemon configuration to enable listening, otherwise libvirt will only accept local connection attempts:

    $ sudo vi /etc/default/libvirt-bin
    # options passed to libvirtd, add "-l" to listen on tcp
    libvirtd_opts="-l"
    

    Configure SASL to handle the authentication for libvirt:

    $ sudo cat /etc/sasl2/libvirt.conf
    # If you want to use the non-TLS socket, then you *must* include
    # the GSSAPI or DIGEST-MD5 mechanisms, because they are the only
    # ones that can offer session encryption as well as authentication.
    #
    # If you're only using TLS, then you can turn on any mechanisms
    # you like for authentication, because TLS provides the encryption
    #
    # Default to a simple username+password mechanism
    mech_list: digest-md5
    
    # Before you can use GSSAPI, you need a service principle on the
    # KDC server for libvirt, and that to be exported to the keytab
    # file listed below
    #mech_list: gssapi
    #
    # You can also list many mechanisms at once, then the user can choose
    # by adding  '?auth=sasl.gssapi' to their libvirt URI, eg
    #   qemu+tcp://hostname/system?auth=sasl.gssapi
    #mech_list: digest-md5 gssapi
    
    # Some older builds of MIT kerberos on Linux ignore this option &
    # instead need KRB5_KTNAME env var.
    # For modern Linux, and other OS, this should be sufficient
    #
    # There is no default value here, uncomment if you need this
    #keytab: /etc/libvirt/krb5.tab
    
    # If using digest-md5 for username/passwds, then this is the file
    # containing the passwds. Use 'saslpasswd2 -a libvirt [username]'
    # to add entries, and 'sasldblistusers2 -f [sasldb_path]' to browse it
    sasldb_path: /etc/libvirt/passwd.db
    

    Now add the users you want to authenticate with libvirt to the SASL database for the libvirt daemon:

    $ sudo saslpasswd2 -a libvirt hmartin
    Password:
    Again (for verification):
    $ sudo sasldblistusers2 -f /etc/libvirt/passwd.db
    [email protected]: userPassword
    

    Now restart the libvirt daemon to apply the changes:

    $ sudo service libvirt-bin restart
    

    Verify that libvirt is listening for incoming connections:

    $ sudo netstat -anp | grep libvirt
    tcp        0      0 10.0.0.10:16509       0.0.0.0:*               LISTEN      12565/libvirtd      
    tcp        0      0 10.0.0.10:16514       0.0.0.0:*               LISTEN      12565/libvirtd
    

    Copy the CA certificate, client certificate, and client key to the computer you’ll be using to connect to libvirt, and then install them similar to how we installed the certificates and key on the server:

    $ scp cacert.pem client1cert.pem clientkey.pem client1.example.com:
    client1 $ sudo mkdir -p /etc/pki/CA /etc/pki/libvirt/private
    client1 $ cp cacert.pem /etc/pki/CA/cacert.pem
    client1 $ sudo chmod 0644 /etc/pki/CA/cacert.pem
    client1 $ cp client1cert.pem /etc/pki/libvirt/clientcert.pem
    client1 $ sudo chmod 0644 /etc/pki/libvirt/client1cert.pem
    client1 $ cp clientkey.pem /etc/pki/libvirt/private/clientkey.pem
    client1 $ sudo chmod 0600 /etc/pki/libvirt/private/clientkey.pem
    

    Inside virt-manager you need to add a new connection. Select “Connect to remote host” with the method “SSL/TLS with certificates”

    Leave the username blank, and specify the FQDN of your server running libvirt (e.g. “libvirt.example.com”) and click “Connect”

    If virt-manager can successfully communicate with the libvirt daemon on the remote host, a dialog prompting you for your SASL username and password will appear:

    virt-manager user authentication window

    Enter your [email protected], for me this is “[email protected]”, and your user password in the credentials window that appears.

    If you get an error when trying to connect to the remote host then I suggest reviewing the syslog and auth log on the remote host. Googling the python error from virt-manager can also help to determine what the issue is.

    If you connected successfully to the libvirt host then you are now communicating with the libvirt daemon over a secure connection.

    virt-manager

    Not every interaction with your guests is encrypted with this configuration. The guest console is still unencrypted. If you are concerned about people eavesdropping on the console session you can restrict access by interface in the guest definition file, or configure TLS for the guest’s spice server, but I won’t cover those right now.

    Direct wifi traffic through a VPN with openwrt

    I think we probably all know someone who’s received a copyright violation notice. Usually these notices list the user’s IP address, date, and copyrighted file that was shared while demanding some payment or the content owner will take the user to court.

    Today we will explore how to setup a wireless access point that automatically tunnels traffic through a VPN, so that you don’t have to worry about the activities of your guests on your network.

    Note: If your VPN provider does not push the “redirect-gateway” option then DNS queries from clients will still go through your normal internet connection. This means that activities on the guest wifi are not completely anonymous!

    For this I will be using the following:

    • TP-Link WR703N running OpenWRT 12.09 (Attitude Adjustment)
    • 1GB USB key
    • a subscription-based VPN provider

    I chose the WR703N mainly because I had one and it is small, has low power consumption, and is quite inexpensive.

    There are many instructions for how to install OpenWRT on the WR703N, so I’m not going to discuss that here. Also the choice of VPN providers differs based on your needs and price range. I recommend reading the TorrentFreak articles on VPN providers to find out which one is best for you.

    A 1GB USB key is required as the flash on the WR703N is not large enough to hold an OpenWRT installation with luci and openvpn installed. First we need to move the OpenWRT OS from the internal flash to the USB key, this will allow us to install the additional packages required, namely openvpn. I followed these instructions for how to transfer the OS from internal flash to USB. I’ll provide a tl;dr:

    • Partition the USB key with a DOS partition table, make at least one partition of type 82 (Linux)
    • Format this partition as ext4
    • Install block-mount, kmod-usb-core, kmod-usb-ohci, kmod-usb-storage, kmod-usb2, kmod-scsi-core, kmod-scsi-generic, kmod-fs-ext4, libblkid

    Plug in the USB key. Check dmesg on the router and you should see that it recognizes the USB key as a block device. Create two temporary folders, one to mount the USB key at, and the other to bind mount /

    mount /dev/sda1 /tmp/usb
    mount --bind / /tmp/flash
    tar -C /tmp/flash -cvf - . | tar -C /tmp/usb -xf -
    umount /tmp/flash
    umount /tmp/usb

    Now that we’ve moved the OpenWRT installation to the USB key we have to configure the router to boot from the USB key instead of internal flash. Edit /etc/config/fstab and change the following:

    config mount
         option device /dev/sda1
         option target /home
         option enabled 0
    

    to:

    config mount
         option device /dev/sda1
         option target /
         option enabled 1
    

    Now reboot the router, it should boot off the USB key now.

    Now there is lots of available space

    Now there is lots of available space

    I followed this post for most of the following openvpn configuration. Now go ahead and install the openvpn package:

    opkg install openvpn

    scp all the crt, ovpn and other openvpn configuration files to /etc/openvpn on the router.

    You can test openvpn by ssh’ing into the router and running:

    openvpn --config myconfig.ovpn

    from /etc/openvpn. Assuming that works, now open the luci interface on the router to create a new interface:

    1. Go to the Network tab, click on Interfaces
    2. Create a new interface, I called mine “VPN” and set the protocol to “unmanaged”
    3. Specify tun0 as the network interface for the VPN interface
    4. Under “Advanced Settings” click the “Bring up on boot” checkbox

    Now you have a choice, you can either:

    1. add the VPN interface we are in the process of creating above to the WAN zone, in which case a route with the prefix 0.0.0.0/1 will be added, which will supersede the WAN route of 0.0.0.0/0 through longest prefix matching, or
    2. create a firewall zone in luci to ensure that any traffic from LAN is automatically forwarded directly to the VPN, never going to the WAN. This is based on an openwrt wiki example

    If you choose the second, then you need to do some additional work in luci:

    1. Go to the Network tab, click on Firewall
    2. Add a new Zone, I called mine “vpn” set it to Input:accept, Output:accept, Forward:accept
    3. Forward all traffic from the LAN to the vpn zone and visa versa, remove the WAN zone from the forwarding from the LAN zone.

    Your zones should look like this now:

    Firewall Zones

    Firewall Zones

    Go back to the Interface page and edit the VPN interface. Under the “Firewall Settings” tab change the zone from “wan” to “vpn”. The interface should look like this now:

    VPN Interface Firewall Zone Settings

    VPN Interface > Firewall Settings > Assign Firewall Zone “vpn”

    There is an airvpn thread full of information on how to ensure that traffic goes from the LAN through the VPN. The above achieves something similar to the iptables rule mentioned in the airvpn thread.

    Now that we have the routing all configured, you can go back to openvpn. If the ovpn file has “auth-user-pass” in it, you can create a text file which contains your VPN username on the first line, and your password on the second, and change the ovpn file to have “auth-user-pass credentials.txt” so openvpn will not prompt you for them when it connects.

    Next we need to configure openvpn to start a boot:

    1. Go to the System tab, click on Startup
    2. At the bottom in the text box, add the following above “exit 0”
    /usr/sbin/openvpn --cd /etc/openvpn --daemon --config /etc/openvpn/myvpn.ovpn &

    Now we want to secure the router more. You might have some technically savvy guests who may try to break into the admin interface of your router to reconfigure it.

    Before we block access to the management ports from the “bad” (guest-facing) side, we need to ensure that we don’t lock ourselves out of the router. Go to the Network tab, click on Firewall, click on “Port Forwards” add new rules to forward SSH (TCP 22), HTTP (TCP 80), and HTTPS (TCP 443) from WAN to the IP address of your router, in my case this is 192.168.1.1. Make absolutely sure you can access these ports from the WAN interface (your home LAN) before you do the following!

    Now, go to the Network tab, click on Firewall, click on “Custom Rules” and add these rules in the space provided:

    iptables -I zone_lan_ACCEPT 1 -p tcp -i wlan0 --dport 22 -j DROP
    iptables -I zone_lan_ACCEPT 1 -p tcp -i wlan0 --dport 80 -j DROP
    iptables -I zone_lan_ACCEPT 1 -p tcp -i wlan0 --dport 443 -j DROP

    This blocks your wireless clients from accessing ports 22, 80, and 443 on the router, which means if they try to go to the luci interface or SSH into the router from the wireless side, they can’t! You need to restart the firewall for these changes to take effect.

    The performance appears to be quite good. I am not sure precisely what the speed of my internet connection here is, but I was able to get over 6MBit/s down using the VPN and the speedof.me speed testing service, which seems very good.

    That’s it. I recommend rebooting the router to make sure everything you did will survive a power cycle. IANAL but this solution should allow you to avoid any legal ramifications for the activities of guests on your IP address since they’ll be using a VPN and have a different termination IP address.

    So, in summary:

    1. All traffic from wireless clients will be directed through the VPN, if the VPN is down wireless clients will not have internet, nor will they have access to your network
    2. Wireless clients are considered hostile, and as such are blocked from accessing ports 22, 80, and 443 on the router to prevent break-in attempts.

     

    Setting up IPSec/L2TP on Amazon EC2

    I wanted to figure out how to setup an IPSec/L2TP VPN, since it seems to be a pretty useful thing to have. Since I didn’t have a VPS to stage this on, I signed up for Amazon’s AWS service using their free tier.

    The AWS sign-up process is pretty easy. Amazon will want your credit card details so they can easily up-sell you. You have to provide them with a phone number, which they will call you and ask you to enter the PIN you see on the screen to verify your contact information. Once this is finished your Amazon Web Services account will be created and you can spin up an instance. There are still a few things you need to watch out for:

    • When creating an instance, the wizard will default to the small tier, which has a charge associated with it (IIRC they quoted me ~$43/mo). You’ll need to change this to the micro instance if you don’t want to pay.
    • The free tier is only available for the first year after signing up for AWS, after which they will charge you. At US Eastern prices, it will cost me around $14/mo for the micro instance, which is quite a bit more expensive than what other hosting providers are offering.
    • You need the private key you generated when you signed up to SSH into your server. The username is “admin” and has no-password sudo privileges.
    • “Terminate” in Amazon lingo means “Turn off and permanently delete” which unless you’re finished with your instance I do not recommend you select. For some reason I thought terminate meant “force shutdown,” which it really didn’t. Suffice to say configuring IPSec was much faster the second time around.
    • Amazon uses 1-to-1 NAT for EC2 instances, so when you’re configuring services you need to change the Group Security settings applied to your instance to allow the ports through. Group Security settings are under “Networking & Security” -> Security Groups” in the AWS dashboard. Also, this probably goes without saying, the public IP you SSH to is not the IP of your instance, so if you’re configuring things you need to specify the interface IP address of your instance, not the public IP address.
    • Amazon won’t discuss the bandwidth your instance will get in concrete terms, but it’s pretty poor. I thought I would try to watch South Park via my VPN, but I didn’t even get past the ads before waiting for buffering killed all desire to watch episodes the legitimate way.

    tl;dr – You get 750 hours per month of usage for the first year on Amazon AWS. You can use this to create micro instances of any of the free-tier operating systems they offer. From my poking around, micro instances appear to offer you 8GB of disk space and 613MB of RAM. The free tier gives you 15GB of bandwidth shared across all your AWS services.

    At current US Eastern pricing, which seems to be the least expensive, the micro tier will cost you about $15/mo. So unless you find yourself needing Amazon’s infrastructure for some purpose, or plan to increase your computing requirements significantly in the near future, plan on using AWS micro instances for the first year and then migrating to another hosting provider that better suits your needs.

    I plan on using my micro instance as a staging area for services I want to eventually deploy to my production server, but have not finished testing yet.

    On to setting up IPSec/L2TP. For the most part I followed this guide available on elastichosts.

    This being the first time I’ve ever setup IPSec and L2TP, I ran into some issues. One was that xl2tpd wouldn’t start. This is the output from when I tried to start it in daemon mode:

    [email protected]:~# xl2tpd -D
    xl2tpd[6164]: Enabling IPsec SAref processing for L2TP transport mode SAs
    xl2tpd[6164]: IPsec SAref does not work with L2TP kernel mode yet, enabling forceuserspace=yes
    xl2tpd[6164]: init_network: Unable to bind socket: Cannot assign requested address. Terminating.

    This is because AWS uses 1-to-1 NAT and I put the public IP address instead of the IP address of the instance into /etc/xl2tpd/xl2tpd.conf

    After that, I headed over to System Preferences in OS X to configure my shiny new VPN. Except I kept getting cryptic error messages in Console like this one:

    14-03-05 7:18:33 PM pppd[7612] pppd 2.4.2 (Apple version 412.5.70) started by devops, uid 502
    14-03-05 7:18:33 PM pppd[7612] L2TP connecting to server 'xx.xx.xx.xxx' (xx.xx.xx.xxx)...
    14-03-05 7:18:33 PM pppd[7612] IPSec connection started
    14-03-05 7:18:33 PM racoon[7613] Connecting.
    14-03-05 7:18:33 PM racoon[7613] IKE Packet: transmit success. (Initiator, Main-Mode message 1).
    14-03-05 7:18:36 PM racoon[7613] IKE Packet: transmit success. (Phase1 Retransmit).
    14-03-05 7:18:39 PM racoon[7613] IKE Packet: transmit success. (Phase1 Retransmit).
    14-03-05 7:18:42 PM racoon[7613] IKE Packet: transmit success. (Phase1 Retransmit).
    14-03-05 7:18:43 PM pppd[7612] IPSec connection failed

    And Google was not helpful at all. So, over to the server logs:

    pluto[3627]: packet from xxx.xxx.xxx.xxx:439: received Vendor ID payload [RFC 3947] method set to=109
    pluto[3627]: packet from xxx.xxx.xxx.xxx:439: received Vendor ID payload [draft-ietf-ipsec-nat-t-ike] method set to=110
    pluto[3627]: packet from xxx.xxx.xxx.xxx:439: ignoring unknown Vendor ID payload [8f8d83826d246b6fc7a8a6a428c11de8]
    pluto[3627]: packet from xxx.xxx.xxx.xxx:439: ignoring unknown Vendor ID payload [439b59f8ba676c4c7737ae22eab8f582]
    pluto[3627]: packet from xxx.xxx.xxx.xxx:439: ignoring unknown Vendor ID payload [4d1e0e136deafa34c4f3ea9f02ec7285]
    pluto[3627]: packet from xxx.xxx.xxx.xxx:439: ignoring unknown Vendor ID payload [80d0bb3def54565ee84645d4c85ce3ee]
    pluto[3627]: packet from xxx.xxx.xxx.xxx:439: ignoring unknown Vendor ID payload [9909b64eed937c6573de52ace952fa6b]
    pluto[3627]: packet from xxx.xxx.xxx.xxx:439: received Vendor ID payload [draft-ietf-ipsec-nat-t-ike-03] meth=108, but already using method 110
    pluto[3627]: packet from xxx.xxx.xxx.xxx:439: received Vendor ID payload [draft-ietf-ipsec-nat-t-ike-02] meth=107, but already using method 110
    pluto[3627]: packet from xxx.xxx.xxx.xxx:439: received Vendor ID payload [draft-ietf-ipsec-nat-t-ike-02_n] meth=106, but already using method 110
    pluto[3627]: packet from xxx.xxx.xxx.xxx:439: received Vendor ID payload [Dead Peer Detection]
    pluto[3627]: packet from xxx.xxx.xxx.xxx:439: initial Main Mode message received on 172.xx.xx.xxx:500 but no connection has been authorized with policy=PSK

    Mmhm. Yeah. Mmhm. Oh, yeah yeah yeah. I know some of these words.

    Turns out, again, the problem is that I’ve foolishly specified the public (NAT) IP address instead of the IP address of my instance in /etc/ipsec.conf

    Fixing that leads to a VPN that can connect! I’d say that was an afternoon well spent.

    Find server port on HP ProCurve switches the lazy way

    This is a useful trick for VLAN configuration, or just figuring out which switch port a server is on.

    Note: This requires that your server not be in production, or that your server has been tested and confirmed to have a correct redundant network connection.

    ssh [email protected]
    $ enable
    # config
    (config) # debug event
    (config) # debug destination session

    Then run ‘ifconfig <eth> down’ on the server, or unplug the network cable. Watch the session on the switch and you will see which port has its link status change.

    This isn’t a replacement for proper labels, since it involves downing an active network interface, which could cause connectivity issues in a live environment. A better alternative would be to use LLDP to identify which port a server is connected to, but as the title says, this is the lazy way.