2011-12-14

debian pxe boot installation with dhcp (dnsmasq) running on an openwrt router

background

I recently installed debian stable/squeeze on an old-ish laptop. The machine was already running squeeze, but I wanted to upgrade the hard drive from the original 80GB to a larger 250GB drive. I had an extra 250GB drive that came with my new laptop, but I replaced it with a 500GB drive as soon as I bought it.

The old laptop hard drive had an existing windows XP NTFS partition that I wanted to copy over to the 250GB drive before I installed debian. I didn't want to copy over the debian install from the 80GB drive. The fresh install on the old laptop was intended as a replacement machine for my wife's even-older laptop, which has started freezing frequently due to what I believe to be a failing motherboard. My wife doesn't want any of the developer stuff that I had on my old debian system. Instead, I was going to copy her data over from her laptop. Confusing enough?

complications

I downloaded a x86 debian squeeze net-install image and copied it to a USB pen drive, but I discovered that, incredibly, my old laptop BIOS would not boot from USB. Lame.

linux installation methods

I've installed various linux distros over the years. The most complicated one was probably a slackware installation onto a 486 laptop with no optical drive, USB, or ethernet. I started out by booting an installer bootstrap image from a 3.5" floppy disk and finished that installation by mounting the rest of the installation media over NFS using a Null-Printer parallel cable with PLIP networking.

I've also set up automated kickstart installs of centos guests on Xen servers, and I've installed SuSE servers located halfway across the USA remotely over an IPMI console. I've installed headless servers from standard boot media using a console provided by a serial null-modem cable. In addition, I've done the usual, simple installs from optical media or USB. However, I had never installed linux from a PXE boot.

Over the years, I've burned way too many linux installation CDRs that I've used once, put in a desk drawer, and then threw away a couple years later when they were obsolete by several versions. I hate wasting stuff, and I decided to finally get around to learning about PXE booting so I can stop throwing away CDRs after a single use. Caveat: I realize that, going forward, almost all computers will support booting from USB, and for 1-off installations, that's the easiest option when it is available. In any case, it was not available for my old laptop.

pxe boot setup

Preboot Execution Environment (PXE) booting uses DHCP to discover PXE boot images available on the network. On my home network, I use a wireless router that runs openwrt for DHCP. I also have a little fanless, low-power mini-itx x86 server that I use as a file/media server.

I wanted to configure my openwrt DHCP server to direct PXE clients to installation media on my mini-itx server (hostname == "pizza").

Here is what I had to do:

openwrt

Add this to /etc/config/dhcp:

#
#       Specify pxelinux.0 without a directory prefix
#       because we run tftpd in chroot (--secure) mode:
#
config boot
    option filename         'pxelinux.0'
    option serveraddress    '192.168.1.77'
    option servername       'pizza'

Restart dnsmasq:

/etc/init.d/dnsmasq restart

tftpd on pizza

I'm using openbsd-inetd as my inetd server and running tftpd from inetd since I do not need to run it all the time. I configured tftpd-hpa on a server named pizza on my LAN.

Install and prepare tftpd

sudo apt-get install tftpd-hpa
sudo mkdir -p /srv/tftp

Do not run as a standalone server:

/etc/init.d/tftpd-hpa stop
rm /etc/init.d/S03tftpd-hpa

Configure inetd to run tftpd. Add this to /etc/inetd.conf:

#
# We *might* want to change --timeout (default 900 or 15 minutes), which
# is the timeout before the server will run after a connection is received before
# it terminates.
#
# -s or --secure (chroot on startup)
#
# -u tftp is USER that the daemon will run as (default is nobody).
#       Installing the tftpd-hpa package creates a tftp user
#
tftp dgram udp wait root /usr/sbin/in.tftpd /usr/sbin/in.tftpd -u tftp --secure /srv/tftp

Restart inetd:

/etc/init.d/openbsd-inetd restart

Download the debian netboot image, and extract to /srv/tftp. We should see:

ls -1 /srv/tftp/

debian-installer
pxelinux.0
pxelinux.cfg
version.info

add options to boot SystemRescueCD with PXE

The debian installer netboot tarball variant does not include fdisk. I needed it. I also wanted to use ntfsclone to copy my NTFS partition. Therefore, I also downloaded SystemRescueCD to transfer my windows XP partition before proceeding with the debian installation.

NOTE: SystemRescueCD has become bloated. I've used it in the past, and years ago it used to be about 100MB. It now includes xorg and a bunch of GUI tools, and the size of the image is over 300MB. This is fine when booting from physical storage (USB drive or optical media), but it's slow to transfer an image this size over a LAN. I used SystemRescueCD to transfer the windows XP partition from my old hard drive to the new one during my installation, but next time I'll try the PLD rescue cd instead.

I downloaded it, copied the iso to my server, mounted it as a loopback, and copied the contents to /srv/tftp/system-rescue-cd/system-rescue-cd-2.4.0/:

### Do all this stuff as root
mkdir -p /mnt/tmp
mkdir -p /srv/tftp/system-rescue-cd/system-rescue-cd-2.4.0
cd /srv/tftp/system-rescue-cd
ln -s system-rescue-cd-2.4.0 current
cd current
mount -o loop -tiso9660 /dev/shm/systemrescuecd-x86-2.4.0.iso /mnt/tmp
cp -a /mnt/tmp/* .

Then I made an entry for systemrescuecd in my PXE boot configuration, which I put in /srv/tftp/sysrescue32.cfg:

label sysrescue32
        menu label ^sysrescue32
        kernel system-rescue-cd/current/isolinux/rescuecd
        append vga=788 initrd=system-rescue-cd/current/isolinux/initram.igz

Then I added a line for that config file to /srv/tftp/pxelinux.cfg/default:

# D-I config version 2.0
include debian-installer/i386/boot-screens/menu.cfg

### This is the line I added to the default config:
include sysrescue32.cfg

default debian-installer/i386/boot-screens/vesamenu.c32
prompt 0
timeout 0

imaging and installation

I'm not going to cover the actual debian installation in detail. Once I had openwrt's dnsmasq DHCP set up to point to the tftpd running via inetd on pizza, all I had to do to PXE boot was hit F12 when I booted the old laptop to select PXE as the boot option.

Then I was greeted with a debian splash screen, from which I could select either one of the debian boot options or my sysrescue32 SystemRescueCD boot option.

To complete my installation, I did (roughly):

  • booted into SystemRescueCD, mounted my old hard drive with a USB enclosure,
  • created a single NTFS partition on the new drive with fdisk
  • imaged the old NTFS partition over the new partition with ntfsclone
  • created a single VFAT (FAT32 LBA type 0x0C) partition with fdisk to use for shared data between windows XP and linux
  • rebooted into the debian installer and installed debian (installing GRUB2 to the MBR)

2011-12-13

readthedocs.org

I just discovered readthedocs.org today, and it's awesome! The organization behind the site will build and host documentation for any open source project. It works with any projects that use sphinx/reStructuredText for their documentation.

I'm a fan of reST (reStructuredText). Its semantic processing of whitespace can be confusing when you're first starting out, and the format used for tables can be cumbersome if your tables are complex, but you get used to it.

I write these blog posts in reST, I write notes in reST, and recently I started using reST + sphinx to document an open source project.

I considered using github's wiki feature for project documentation, but after reading about it, I decided not to use it. As of this writing, it does not support auto-building documentation in HTML format from markup formats defined in your main project source tree. You can use git for your project wiki/docs, but github will create a separate git repo for the documentation.

With sphinx, you can take your reST sources and build documentation in multiple formats. readthedocs.org supports html, epub, and pdf out of the box!

readthedocs.org uses a build system that scans your project source tree to find the conf.py at the root of your sphinx documentation. My project had the sphinx docs rooted in src/site/sphinx, with the conf.py in the source subdirectory, and ReadTheDocs was able to find this and build my documentation without requiring me to specify the paths. All I had to do was:

  • sign up for an account on readthedocs.org
  • configure a new project on ReadTheDocs and specify the read-only-access url of my github project in the ReadTheDocs project configuration form.

And that was it! ReadTheDocs checked out my project source, built the documentation in html format, and published it here.

If you customize your sphinx layout, you have to contact the ReadTheDocs team to whitelist your custom configuration (this may be automated in the future). Otherwise, ReadTheDocs will build your documentation with a some default sphinx settings.

ReadTheDocs also provides a unique web service endpoint that you can call to rebuild your documentation. Github provides a custom post-commit hook for ReadTheDocs that can be configured on your github project page by navigating to:

admin -> service hooks -> ReadTheDocs

Once you do that, your documentation will be rebuilt automatically every time you push code to master. Otherwise, by default, the documentation will be rebuilt nightly.

2011-12-06

anyremote j2me client

I purchased a couple low-cost, used j2me-capable phones on eBay recently for a j2me development project. While watching a movie with my wife on our desktop computer the other day (we do not have a TV) and getting up repeatedly from the couch to walk over to the desktop to adjust the volume, I got the idea to write a simple j2me MIDlet that could use a phone's bluetooth interface to function as a remote control for the desktop.

It turns out that there is already an open source project for that called anyRemote. There are packages for it in debian stable:

1
sudo apt-get install anyremote

I know that one of my phones, a Nokia 5130-c2 with T-Mobile firmware, will throw a SecurityException if an unsigned MIDlet tries to access any APIs that require permissions (including bluetooth). The GNU autotools-based build for anyremote-j2me-client does not include options to sign your MIDlet. Since I already wrote a portable ant-based build system for another j2me MIDlet that includes a step to sign a jad and also ensures that jar MANIFEST and jad metadata are consistent, I ported my build scripts to the anyremote j2me client.

I published my build of the anyremote-j2me-client on github.

If you will be running the anyremote j2me client on a Nokia and need to sign your MIDlet, check out my previous blog post on installing self-signed code-signing certificates on nokia s40 handsets.

It took a little trial and error to get the client working with VLC. I'm pasting my notes below.

vlc with anyremote

I tried the ganyremote gtk client for anyremote, but I didn't have any luck with it. Having said that, I spent no more than a minute trying to get it to work with VLC, and I did not RTFM at all.

I figured out how to use the console-based anyremote server after a quick scan of the manpage, and that's what I document below.

First we need to configure VLC to play a media file, and run an embedded HTTP server on host:port localhost:8080 to accept commands from remote clients:

1
vlc -I http --http-host localhost:8080 mymovie.avi

Then we need to configure the anyremote server to listen on our bluetooth interface, using a configuration customized for remote VLC control. In the following example, the anyremote server listens on bluetooth channel 19:

1
anyremote -s bluetooth:19 -f /usr/share/anyremote/cfg-data/Server-mode/vlc.cfg

To find a list of cfg files installed with anyremote, run:

1
dpkg -L anyremote-data |grep cfg

Down the road, I will play around with customizing the config file and store my modified file in some subdirectory of $HOME.

As root, we need to make our bluetooth adapter visible to external bluetooth client scans:

1
sudo hciconfig hci0 piscan

Once the anyremote server is running and our hci0 interface allows remote clients to scan the channels, the anyremote-j2me-client can search for peers, find the anyremote server, and then connect to the service.

Then the remote control interface will be launched on the client, and we can pause, stop, fast forward, rewind, and adjust volume.

anyremote-j2me-client build for nokia 5130c2

My Nokia 5130 has a 240x320 resolution. The default vlc configuration for anyremote uses 4-rows of buttons. I found that the 48-pixel icon set is the best size for the nokia screen. I'm guessing that, for any given j2me device, you should calculate:

icon_size_max = vertical_resolution / 6

And then choose the larges available icon size that is < icon_size_max. For me that is 48-pixels, which means that I built my anyremote-j2me-client using:

1
ant -Dicon.size=48 -Dsign.app=true clean package

2011-12-02

installing code signing certificates on j2me phones

Recently, I got a couple j2me-capable phones on ebay as test devices for some development work that I'm doing for an NGO based in West Africa. I'm developing a literacy-education tool that is intended to be deployed on low-cost j2me devices because this is the technology platform with the greatest market penetration in the area. Most people in the region do not have laptops, desktops, OLPCs, tablets, android phones or iPhones. Many people do have low-cost j2me-capable phones manufactured by nokia, samsung, LG, etc.

To test my j2me code on real hardware (not just emulators), I purchased a couple second-hand mobile phones on eBay.

I do not use this type of device day to day. I have a much fancier android phone that operates on a CDMA network. My test devices are gsm.

One is a samsung C3050 and the other is a nokia 5130 XM. Both are relatively cheap devices. My C3050 isn't totally locked-down/crippled because it does not have a T-Mobile firmware. The guy who sold it to me on eBay shipped it from NY, and he left an old T-Mobile USA SIM card in the phone, but the firmware version code indicates that it was originally sold by "China Mobile Communications Corporation".

The nokia came with a T-Mobile USA firmware. On nokia s40 phones (and maybe other j2me phones), T-Mobile modifies the core manufacturer firmwares to disallow running apps that would otherwise run in the "trusted third party" j2me security domain. The phone contains Thawte and VeriSign root x509 certificates, but T-Mo does not allow you to run apps signed with code-signing certs. I learned this from developer.nokia.com.

In any case, (many? some?) nokia s40 phones do not allow you to install your own certificates for code signing. If you do a web search, you will find several other blogs lamenting the developer-unfriendly "security model" (in scare quotes because it has more to do with securing revenue than with device security) on j2me mobile devices.

It took way too much binary diffing, staring at hex dumps, and trial + error, but I reverse engineered enough of the file format of nokia's internal binary cert DB file to figure out how to install a self signed cert that runs in what I believe is the operator protection domain. The partial analysis of the nokia ext_info.sys file on this page by Thomas Zell helped a lot.

I created a github project called dustbowl to alter ext_info.sys files.

I also posted this analysis of the ext_info.sys file format.

Here are some really great tools that enabled my analysis:
gammu:
This is a fantastic project that implements the nokia FBUS protocol to support accessing the filesystem on supported nokia phones.
vbindiff:
This is a nice, lightweight console-based binary diff program
hexdump:
a good tool for a quick traditional hex-editor formatted view of a binary file.

update

Since I wrote this, I found an open source project called nokicert that also supports installing code-signing certificates on nokia s40 phones. I was able to build and run it, but I haven't tried to use it to install certs on my own phone. I confirmed that the feature to read the cert DB on my phone works fine.

Nokicert installs certs to your phone's auth certificate DB not to the user certificate DB. On my firmware/device (T-Mobile USA/nokia 5130c2), it is sufficient to install certs to the user certificate DB, and doing so incurs less risk of possibly bricking your phone.

I reached out to Francois Kooman, the developer of nokicert, and he graciously shared his notes on reverse engineering the security model of nokia phones. He managed to figure out several things about the security model that I had not figured out from my tinkering.