PXE on vanilla ASUSwrt firmware

As a previous dd-wrt user, I love the idea of adding services to my home router, but just lacked the time to commit to moving from ASUSwrt to merlin.

Since ASUSwrt uses dnsmasq for DNS and DHCP and offers telnet login by default, adding the necesary configurations for PXE was relatively simple, albeit it took some tinkering.

Most PXE-live implementations rely on read-write access to a filesystem via NFS – but I was after something that was truly read-only.

The setup:

  • DHCP server PXE options via dnsmasq
  • TFTP server via dnsmasq
  • tftp-root folder on a mounted USB-drive
  • Full ISOs (live-filesystems, etc.) via HTTP – on a separate server
  • lpxelinux.0 – for loading kernel/initrd via HTTP (/usr/lib/PXELINUX/lpxelinux.0)
  • syslinux64.efi – for x64 EFI boot support (/usr/lib/SYSLINUX.EFI/efi64/syslinux.efi)

OS’ supporting live-boot over PXE/HTTP

Debian was by far the most PXE-friendly OS to get running. Kali took some doing, but I got there eventually – thanks to this post and kali-linux-2017.1-amd64.iso!

I was also able to get debian working with using debian-live-9.3.0-amd64-lxde.iso

RAW-iso mode worked for getting Arch Linux (archlinux-2018.01.01-x86_64.iso @ 522MB) and TinyCore (Core-current.iso @ 12MB) booted (command-line only) – see the append arguments in ‘default’, below.

For some reason, even though Ubuntu, Lubuntu and Tails are all based on Debian, I was not able to get these to ‘fetch’ the filesystem over HTTP at all (vanilla iso); even trying to load the iso into memory ‘raw’ failed to find the live filesystem once the initramfs loaded…

I was also unsuccessful at getting Puppy Linux to boot from PXE (failed to find/mount the filesystem), despite following (similar) instructions from a few different places on how to rebuild the initrd to include the filesystem.

UEFI + PXE -friendly OS’ (13-Jan edit)

After a good while of tinkering, I found the following post in a discussion on the ArchLinux wiki:

The currently generated archiso file does not contain the required syslinux files for booting a PXE image. I have filed a bug for this at https://bugs.archlinux.org/task/50188


Custom dnsmasq options

Fortunately, customising the dnsmasq configuration is as easy as adding additional options (1 per line) to /etc/dnsmasq.conf  & restarting the service (killall dnsmasq && dnsmasq –log-async -C /etc/dnsmasq.conf). Lower down I share the script I built to apply (new) options and restart the service with one incantation.

The dnsmasq options I added were:

dhcp-boot=lpxelinux.0 default image
dhcp-option=vendor:PXEClient,6,2b “kill multicast”
tftp-no-blocksize (not sure if this is necessary)
log-dhcp outputs to /tmp/syslog.log
pxe-prompt=PXE-Booting,5 (not sure if this is necessary)
dhcp-match=set:bios-x86_64,option:client-arch,0 detect BIOS machines
dhcp-boot=tag:bios-x86_64,lpxelinux.0 assign bootfile for BIOS
dhcp-match=set:efi-x86_64,option:client-arch,7 detect EFI machines
dhcp-match=set:efi-x86_64,option:client-arch,9 detect EFI machines
dhcp-boot=tag:efi-x86_64,syslinux64.efi assign bootfile for EFI
pxe-service=X86PC,lpxelinux.0,lpxelinux.0 assign bootfile for BIOS
EDIT (13-Jan): Corrected the dnsmasq EFI-detection/assignemnt options based on this git project.
EDIT (20-Jan): Had to fall-back to BIOS-only to make sure everything works. (EFI line removed are struck-out, above)

minimal tftp-root filestructure:


With the upgrade to lpxelinux.0, I was able to eliminate all vmlinuz and initrd images from the TFTP server, instead pulling them from the HTTP server directly (read: much more quickly, too!). The kali vmlinuz/initrd entries are noted as an excercise for the reader.

Theoretically, one could also verify the checksum of the mounted .iso/squashfs to ensure no modifications had been injected, but I digress.

‘menu.msg’ contents

This text-file gets displayed by [l]pxelinux.0, and is meant to present the user with options provided by the PXE-server. Put in as little or as much as you want!

my pxelinux.cfg/menu.msg:

Local Boot options
 - local (boot from local storage)

PXE-BOOT Options
 > Tools
 - dos (dos 6.22)
 - dosnet (dos with networking support)
 - memtest (memtest86+ v5)
 - memtest-kali (memtest86+ v5)
> Live ISOs
 - kali (Kali in forensic-live mode)
 - debian (Debian in live-mode)

‘default’ contents

These instruct [l]pxelinux.0 which kernel/initrd/etc. files should be pulled (and from where), based on user-input (or lack thereof).

All paths are relative to <tftp-root> – ‘http://‘ paths (for kernel and initrd) are only supported with lpxelinux.0 (not pxelinux.0)

The ‘fetch’ option tells the initrd to download the filesystem from the provided path. if ‘httpfs’ is used with the same path

my ‘default’:

serial 0 115200
default local
timeout 150
prompt 1
display pxelinux.cfg/menu.msg

label local
  localboot 0

## Tools
label dos
  kernel bootimage/memdisk
  append initrd=bootimage/dos622.img
label dosnet
  kernel bootimage/memdisk
  append initrd=bootimage/dosnet.img
label memtest
  kernel bootimage/memdisk append initrd=bootimage/memtest86p-5.01.bin
label memtest-kali
  kernel bootimage/memtest-kali

## Live ISOs
label kali
  kernel bootimage/vmlinuz-kali
  append initrd=bootimage/initrd-kali.img edd=off boot=live noconfig=sudo username=root hostname=klive device=eth0 noswap components fetch=http://<HTTP-server IP>/pxe/kali/live/filesystem.squashfs
label debian
  #kernel bootimage/vmlinuz-debian
  kernel http://<HTTP-server IP>/pxe/debian/live/vmlinuz-4.9.0-4-amd64
  append initrd=http://<HTTP-server IP>/pxe/debian/live/initrd.img-4.9.0-4-amd64 boot=live components fetch=http://<HTTP-server IP>/pxe/debian/live/filesystem.squashfs

## Direct ISO
label tc
  kernel bootimage/memdisk
  append initrd= iso raw
label arch
  kernel bootimage/memdisk
  append initrd= iso raw

The notice how the kali entries instruct lpxelinux.0 to pull vmlinuz/initrd via TFTP, while the debian ones pull directly from the HTTP server.

ISOLINUX ‘append’ options – as a reference (from their respective iso’s .cfg files):

Debian (isolinux.cfg)
#LABEL English (en)
  linux /live/vmlinuz-4.9.0-4-amd64
  APPEND initrd=/live/initrd.img-4.9.0-4-amd64 boot=live components locales=en_US.UTF-8
Kali (live.cfg)
#label live-forensic
  append boot=live noconfig=sudo username=root hostname=kali noswap
#label live-persistence
  append boot=live noconfig=sudo username=root hostname=kali persistence

HTTP-server files:

The HTTP server basically has a mount folder for each ISO: Kali and Debian, serving all files (including vmlinuz, initrd and filesystem.squashfs)

When using lpxelinux.0 (or gpxelinux.0) vmlinuz and initrd can also be loaded via HTTP, which is much quicker than doing so via TFTP.

Pulling it all together

IMHO, the key advantages of merlin over ASUSwrt would (could) have been HTTP-server hosted on the router and reboot-resilience; As things stand, if my router reboots (it’s on a UPS, so a very rare occurrence), I need to reapply the settings to /etc/dnsmasq.conf and resart the service. Fortunately, I am the only one using PXE at home, so connecting via telnet and running the script is a trivial operation.

The script itself is rather straightforward (for anyone with a little BASH experience) – and there are probably some inefficiencies, but I can take constructive criticism 🙂




usb_mount_str="/dev/sda1 on /tmp/mnt/sda1 type vfat"

# Check USB is mounted
if $(mount | grep -qi "$usb_mount_str"); then
        cd ${usb_mountpoint}/tftpboot
        echo "Error: USB not mounted - exiting(1)"
        exit 1

# check/apply dnsmaq config
dnsmasq_ps=$(ps w | grep dnsmasq | grep -v grep)
dnsmasq_args=$(echo "$dnsmasq_ps" | sed 's/^.*dnsmasq //g')
if ! $(echo "$dnsmasq_args" | grep -qi ".conf"); then
        echo "no .conf specified: \"$dnsmasq_args\" (assuming \"/etc/dnsmasq.conf\")"
        setopt shwordsplit
        for word in $dnsmasq_args; do
                if echo "$word" | grep -qi ".conf"; then
                        unsetopt shwordsplit
        unsetopt shwordsplit
        if [ "$dnsmasq_conf_file" == "" ]; then
                echo "error parsing .conf filename from \"$dnsmasq_args\" - exiting(1)"
                exit 1

for cmd in $local_pxe_options; do
        #echo "testing $cmd"
        if ! grep -qi $cmd $dnsmasq_conf_file; then
                # command not found
                echo "adding: $cmd"
                echo $cmd >> $dnsmasq_conf_file

if [[ $modified -ne "0" ]]; then
        echo "Restarting dnsmasq"
        killall dnsmasq
elif [ "$(ps w | grep dnsmasq | grep -v grep)" == "" ]; then
        echo "Starting dnsmasq"
        echo "All pxe-related options are already present ($dnsmasq_conf_file)"

if [ "$dnsmasq_conf_file" != "$default_conf" ]; then
        /usr/sbin/dnsmasq --log-async -C "$dnsmasq_conf_file"
        /usr/sbin/dnsmasq --log-async

Next steps:

Diskless thin client(s) with NFS-root? Maybe Clonezilla to quickly restore a family member’s PC when they bungle it up? Only time will tell 🙂


Baby Tools/Methods: Hits & Misses

So for first time parents, there is often LOTS of guesswork. Here’s some of our hits and misses to hopefully make life a little easier for other first-time parents 🙂

1) Tools

Video baby monitor + WiFi

So I have a bit of a paranoid streak in my technology use, so I’ve never used the WiFi features (The unit was a gift).

The Video is a BIG win. The ability to quickly tell if that yell was only a dream, or if they are sitting/standing up without the risk of being seen/heard checking in (PLUS NIGHT VISION!) is purely awesome.

Baby Carriage & Car-seat

Winter Clothing

“Petit Coulou” Carseat-cover
BIG WIN; forget dressing the kid in a suit, into the carseat and just cover the whole thing! No need to risk waking them up by forcing little limbs in or out of sleeves/legs

Thumb-less gloves with forearm and wrist elastics+toggles
WIN: Thumbs on childrens’ gloves are totally over-rated, even at 18mo…

Winter boots (with side-zippers)
WIN: much quicker than laces, and hold on pretty decently


WIN @ 1yo. Spill-RESISTANT cups: if they drop it, you get a splatter instead of an empty cup and a puddle. With the right expectations, they’re pretty sweet.

2) Methods

Baby Sign-language

We only used a sub-set of signs, but definitely a WIN.

Past month ~3 of using this (with the BLW) it take SO MUCH guesswork out of what your kid wants. They won’t be able to talk for another 6mo-1year, but them being able to communicate basic things like ‘more’, ‘finished’ and ‘drink’ make mealtimes so much easier!

There is a plethora of sites that explain the different signs; I’d recommend looking at a few and try regularly integrating 2-3 signs (in-context, of course) at a time, until the kid understands and starts repeating them. With each sign they get, you can add a new one to the rotation.

We started with ‘more’ and ‘finished’. Later brought in ‘bath’ and others, though they were more or less useful in the end. Your kid will understand what you’re saying rather quickly – it’s nice to give them some basic way to give you a better hint of what they’re after 🙂

Baby-Led Weaning (BLW/DME)

tl;dr: This was a WIN! If you are a foodie and/or enjoy cooking, definitely check this out! (@ jessicacoll.com or just google BLW)

I think the french name for this idea/process more accurately describes what happens: “Diversification Menée par l’Enfant” or ‘DME’ – Baby-led diversification – since nothing stop the mother from breastfeeding once the kid starts eating solids.

The basic idea is to capitalise when your kid starts putting everything in their mouth (@ ~6mo) to put APPROPRIATE (in nature, and size) foods in their hands so they can explore tastes, textures and control how much and how fast they eat.

  • APPROPRIATE SIZE means (roughly) pieces the size of your thumb (for starters). They wil begin by biting of small bits and chewing that
  • APPROPRIATE NATURE means soft stuff; think bananas, avocado, carrots boiled until soft, etc. You’ll also want to peel most things. Later you can start ripe fruits and tomatoes (cut in wedges), etc.
  • AVOID!: anything that is A) ROUND (grapes are the BIGGEST NO-NO), B) that can’t be easily be squished between your index and middle finger (on the same hand) and/or C) contains added sugar and/or salt

It will be messy, food may be thrown around but in 2-3 months, you should be able to give your kid a few pieces on their tray and have some peace for 15-20 mins as they work their way though the selection.

We went to a 4-hr seminar with Jessica Coll, who is a nutritionist-dietician, and learned the ins and outs of BLW. I’d highly recommend attending such a seminar, if you are interested in trying this technique. She also offers an online-course style section of her site with recipes, message boards and videos; we signed up but didn’t actually use it.

I LOVED the example she gave in the class: “Imagine going to a fancy restaurant and ordering a nice steak. Next imagine the waiter bringing it to your table, having run it through the blender with your potatoes and vegetables, and proceeding to shovel the amalgamated slop into your face with a spoon, leaving you hardly any time to breathe, let alone take note of the flavour of what you’re eating”

CAVEAT EMPTOR: this method WILL be completely weird/alien to your parents; be ready to respond to “what do you mean you don’t give baby mush-mush!?”.

3) Baby-proofing

Magnetic Latches

THESE. ARE. AWESOME! Hover a magnet over the right spot and the cupboard opens! Don’t and it stays locked. Kid not interested in the cupboards/etc. yet? Turn them ‘off’ (Yes, they have an ‘off’ switch!)

The installation instructions didn’t make any sense (I’m an P.Engineer) but I was able to figure our how to place/space everything just right on the first try 3 cupboards out of 5 (2nd and 3rd try on the last 2, respectively).

If a toddler gets a hold of the handle and really pulls, the 2-sided adhesive may give, but if only trying to pull from the edge of the door, it should last.


Cabinet Latches

These require 2 opposite cupboard doors to have handles in-range (<~6″ apart) to work. We have knobs on the cupboards, so just slip the gizmo on and off to get into the cupboards! YMMV depending on the type/spacing of your cupboard handles. Probably no good for drawers.


Outlet Covers

Only 1$ for a pack of ~30, these are a must have before baby starts crawling. Apparently HydroQuebec (electrical utility) will send you somefor free if you ask.


Plastic corner-covers

These seemed like a great idea, but work best in the following cases:

  • you plan to install them on perfectly square (cubed) corners
  • you don’t mind it being held in place by 2-sided tape
  • your kids doesn’t take an interest in trying to remove them

The 2-sided tape is no match for a determined child (or mine, in any case). I put one on the corner of the fireplace mantle – it didn’t last long. Added some clear boxing tape on top and it’s still attached many months later.


Foam glass-edge covers

This is larger (~1″ deep) than we expected form the photos, but also a better cushion. Installation takes some imagination as the 2-sided tape provided comes in a roll (not pre-attached to the inside of the foam). If you’re aesthetically demanding, try something else, as they arrived rolled, so had a ‘wrinkly’ look to them, and the sides of the roll of tape also leave funny marks on any parts of the foam it touches.

Would not buy again (and didn’t install it on the second coffee table either).


Bonding eth0 and wlan0

So since I’m using my Pi for some network functions, I figured it’d be nice to have a single IP to consistently reach the device, regardless of whether a cable is handy or not.

Since my router is smart enough to disallow pre-configuring the DHCP server to assign the same IP to multiple MACs (and no one likes IP address conflicts), I went with bonding.

My starting point was debian’s wiki: https://wiki.debian.org/Bonding

In Raspbian, a new package is needed:

# apt-get install ifenslave

Don’t forget to tell the kernel to start the bonding module at each boot-up:

# echo 'bonding' >> /etc/modules 

So I got the lion’s share of my setup from there (with some adjustments) – here is the final version:

# Define slaves   
auto eth0
iface eth0 inet manual
    bond-master bond0
    bond-primary eth0
    bond-mode active-backup
auto wlan0
iface wlan0 inet manual
    wpa-conf /etc/network/wpa.conf
    bond-master bond0
    bond-primary eth0
    bond-mode active-backup

# Define master
auto bond0
iface bond0 inet dhcp
    slaves         eth0 wlan0
    bond_mode      active-backup
    bond_miimon    100
    bond_downdelay 200
    bond_updelay   200

Thanks to a forum post I’ve lost track of, I also figured out that I had to comment out the line I had previously added to address an issue getting dhcp addresses:

# iface default inet dhcp

The current delay is 5min 11sec from reboot to ping(out).

When plugging-unpluging the Eth cable, one can clearly see the difference in ping-times (~5ms vs. ~0.5ms), but no requests/replies get dropped!



I reproduced this on a brand-new minimal-install of Raspbian (4.4.50-v7+) and folowed my own steps.

BUT, for some reason, when booting with eth0 connected, eth0 would grab the IP (instead of bond0 doing so) and I was unable to ping my router(!?).

Disconnecting eth0, the IP would toggele over to bond0 and everything worked well (pinging over wlan0), so I reconnected the cable and it still worked (pinging over eth0)… or 5 seconds, after which, the IP switched back to eth0 and ping connectivity was lost!?

The only other changes I made before it started workign again were:

  • disable “alsa-utils” sound driver/service (update-rc.d alsa-utils disable)
  • comment out the plaintext ‘key’ line in /etc/wpa-supplicant/wpasupplicant.conf

… Wierd, right??



Auto-launch application on (Raspbian-xfce desktop) login

So I do most of my tinkering in the terminal, through much googling and log the changes (ahem, improvements) I make.

So I wanted to have these 3 apps (terminal, changes.txt & iceweasel) opened automatically on login.

The Good:

Since I had previously switched from LXDE to XFCE, the solution was quick and GUI-based, adding some entries in Settings > Session and Startup : Application Autostart.

  • xfce4-terminal
  • iceweasel
  • leafpad /home/pi/Documents/changes.txt

Though for some (unknown) reason, the abbreviated path ~/Documents/changes.txt initially failed ot open the correct file – the full path from ‘/’ worked just fine.

This post by alez put me on this track.

The Bad:

Unfortunately, I initially tried adding these at the end of .bashrc with a ‘&’ appended so they will launch in the background (and .bashrc would not wait forthemto complete/exit before exiting itself) – BIG MISTAKE.

The Ugly:

Basically an infinite loop somehow arose opening multiple instances of these 3 applications until everything ground to a halt! 😦

Fortunately I had just received my second Pi and was able to quicly download NOOBS, install raspbian, slave my original microSD card and comment out the evil.

Webmin on Raspbian

Webmin is a neat little tool that puts a GUI front-end on a whole lot of (pretty much everything??) stuff that can be configured in Linux.

I followed the instructable below which was basically flawless (so much better than some of the help-files I’ve been working with lately that have so many knowledge gaps you’ve liable to fall in and just give up before getting the first thing running…). Kudos to steve.m.graves for a thoroughly well-done job!

The main advantage I’m looking for is saving configuration of various services/etc. without having to manually ferret out relevant config files, save those (and their relative paths) and cross my fingers I didn’t miss some important piece of the puzzle.

Is my geek-pride injured for taking the GUI (read: non-console) way out? A little. but in contrast with the potential time-savings, the compromise is a no-brainer.

The Raspbian GUI vs. the evil ‘startx’

So it all started with the best intentions: Let’s try to open up a Windows machine with RDP!

The straw…

So somewhere I found how to install rdesktop and that led me to install some other packages & type ‘startx’ to get it all going… and it was all downhill from there! 😦

No matter what I did, I couldn’t get the old GUI to come up the way it used to!

Stuff I tried, but that ultimately didn’t pan out

I tried restoring the ‘.old’ .Xauthority file. I tried changing the .Xauthority file’s user:group back to pi:pi (from root:root). I tried deleting the .Xauthority file altogether. Hell, I even though it plausible that Raspbian’s default partitioning of my 32GB SD card somehow let me clog the FS – but nope; not one partition with >15% utilization.

Update: OH! I also added a “startx; sleep 10” to the end of my  .profile at some point that caused xface to not start until I logged in via ssh and killed the bugging-out xServer process… :@

Update 2: Great! Now I get the same blank/black desktop again!? Running ‘startx’ will bring up xface, but this is still a manual SSH step required to get my GUI up and running! Poking around I removed the instigating ‘rdesktop’ package and based on the post below, installed slim to replace lightdm, which only seems to want to drop me into the black-screen GUI with a right-click menu to open a terminal emulator and other applications.


The (lesser-evil) downside is that the login-prompt is back, but at least it is accepting the same user/pass that SSH has been all along 🙂 (raspi-config was of no help here, contrary o some forum posts)

The final solution

In the end, I said my goodbyes to lxde and uninstalled it and moved to xface, at the cost of a few hundred MBs of SD space. I followed the instructions below without any difficulties whatsoever:


I had some doubts (read: “Oh shit, did I really make things worse!?”-moments) at a few points during the reboot process, but xface ultimately came up with its (somewhat obnoxiously coloured) desktop background

I’ve done a first-pass in the settings tweaking certain things, but time will tell if xface will pass the ‘good enough’ test.

Once thing worth noting is that xface seems to take much longer to shutdown once given the ‘reboot’ command, but this may simply be my mind playing tricks on me… This seems to have been related to the “startx; sleep 10” that I had added to my .profile… and removed – see the Update above.

…but why use a GUI in the first place!?

Being quite accustomed to working through a console, using vi, etc. I still like to be able to use the Pi, connected to my monitor in complete SILENCE 🙂

Adding to that the amount of googling I do in the course of my hackling, a web browser and text-editor were natural additions.


I probably could have tried something from the Raspbian recovery menu (hold SHIFT at boot-up)… only though of this after xface’s obligatory post-install reboot. Oh well.

Update2: Maybe I should have looked further into lightdm’s config for the issue…

Lessons (I really should have) learned

Oh how nice it would be to have a full backup of the SD card to revert back to in case of similar catastrophes… but unfortunately I may have to end up screwing the pooch much harder than this to actually put the effort into deuplicating and storing SD cards…