Tinycore: proxyDHCP 







Setting up a proxyDHCP service for PXE booting


Some thin clients support network booting using the PXE protocol. This does provide an easy way of testing Linux out on them - especially if you are developing a custom kernel as it can cut out the interim step of copying the a test kernel to/from a USB drive to move it across from the development system to the target hardware. It was doing some work on a kernel for the Wyse Sx0 that provided the impetus for me to sort this out.

PXE booting is tied into the DHCP protocol. DHCP is the protocol the thin client (or whatever) uses to ask for an IP address and related stuff (Gateway address, DNS servers etc) to use on the network. In order to boot an operating system from the network it also needs to know the address of a TFTP server, and the name of the file to load from it.

For a lot of us (me included) the DHCP server we use is the one that's in the router that connects us to the internet. These are almost invariably basic DHCP servers and have no option for configuring or supplying PXE settings.

If you use Google to find a solution virtually all the hits you get tell you the only solution to the problem is to turn off the DHCP server in the router and to provide your own fully featured DHCP server. This requires you to have another PC that is always on (or at least always on when your router is on) and to me isn't an acceptable solution where I'm after an occasional PXE boot during testing. I'm glad to say that these people are wrong. The solution lies in setting up a proxyDHCP service.

How ProxyDHCP works

This describes how a proxyDHCP server works in conjunction with a DHCP server which has no PXE support.

  1. When a client boots up it sends a DHCP Discover broadcast on the network. This includes a list of information the client would like from the DHCP server, and, in some cases, some additional information identifying itself as a PXE capable device.
  2. A DHCP server responds with a DHCP Offer, which contains possible values for network settings requested by the client. Usually a possible IP address, subnet mask, router (gateway) address, dns domain name, etc. It ignores any PXE-capable indication.
  3. If the client identified itself as a PXEClient, the proxyDHCP server also responds with a DHCP Offer with the additional PXE-related information (TFTP server name and boot file name), but omits any IP address info. It leaves the IP address assigning to the regular DHCP server.
  4. The PXE Client responds to the DHCP Offer with a DHCP Request, where it officially requests the IP configuration information from the regular DHCP server.
  5. The regular DHCP server responds back with an ACK (acknowledgement), letting the client know it can use the IP configuration information it requested.
  6. The client now has its IP configuration information from the DHCP server, and the TFTP Server name and boot file name from the proxyDCHP server and it initiates a TFTP transaction to download the boot file.

Really quite neat.


I started out with my kernel development environment. It seemed the right hardware to pick on as my intention was to use PXE booting during kernel development work. If I wanted the capability online 24x7 I could install it on my (low power) Web Server mirror machine.

The development machine is currently running Tiny Core 4.7.6 and has persistent /opt and /home directories.

Using the App Browser I downloaded and installed dnsmasq. This is a small and neat DNS/DCHP/TFTP server that can be configured to act just as a proxyDHCP server.

For some of the PXE mechanics we'll be using syslinux, but that was already installed.


We need somewhere to serve our files from. I decided to use the directory /home/tftproot. We also need to think about what we're going to be putting there and how we want to organise things. I settled on a subdirectory images for the operating systems and beneath that tc for the standard Tiny Core kernel, and machine names (eg wyseSx0) for machine-specific kernels. So we start by creating these directories:

tc@box:~$ mkdir -p /home/tftpboot/images/tc
tc@box:~$ mkdir -p /home/tftpboot/images/wyseSx0

Next we set up some menus so that we can select the desired kernel. We do this using various files conveniently provided for us by syslinux. We also need to create a directory (/home/tftpboot/pxelinux.cfg) for our menu file (named default).

tc@box:~$ cp /usr/local/share/syslinux/menu.c32 /home/tftpboot/
tc@box:~$ cp /usr/local/share/syslinux/pxelinux.0 /home/tftpboot/
tc@box:~$ mkdir /home/tftpboot/pxelinux.cfg/

Copy over the standard Tiny Core kernel & initrd files for a basic 'does it run?' trial.

tc@box:~$ cp /mnt/sda1/tce/boot/vmlinuz /home/tftpboot/images/tc/
tc@box:~$ cp /mnt/sda1/tce/boot/core.gz /home/tftpboot/images/tc/

Now create the basic menu file named default that sits in the directory: /home/tftpboot/pxelinux.cfg. My initial file looked like this:

default menu.c32
prompt 0

menu title PXE Boot Menu

label tc476
    menu label Standard Tiny Core 4.7.6
    kernel images/tc/vmlinuz
    append initrd=images/tc/core.gz keymap=qwerty/uk

label tc476_wyse
    menu label Standard Tiny Core on Wyse Sx0
    kernel images/tc/vmlinuz
    append initrd=images/tc/core.gz keymap=qwerty/uk pci=nobios ignore_loglevel

label tc476_wyse_test
    menu label Tiny Core on Wyse Sx0 (Specific)
    kernel images/wyseSx0/vmlinuz
    append initrd=images/tc/core.gz keymap=qwerty/uk pci=nobios ignore_loglevel pata_cs5536.msr=1

We can see later how to build customised menus.

Having got that straight we move to configuring dnsmasq. Whilst we find an example file dnsmasq.conf.example in the directory /usr/local/etc/, the dnsmasq application actually looks for the file /etc/dnsmasq.conf. (This caught me out for a while!). Here's my configuration file:

# Configuration for dnsmasq to function as a proxyDHCP server, enabling
# thin clients to boot when an external, unmodifiable DHCP server is present.

# Don't function as a DNS server:

# Log lots of extra information about DHCP transactions.
# (Useful to start with, could drop later)

# We'll use its built-in TFTP server

# Set the root directory for files available via FTP.

# The boot filename.

# kill multicast

# Disable re-use of the DHCP servername and filename fields as extra
# option space. That's to avoid confusing some old or broken DHCP clients.

# PXE menu
pxe-prompt="Press F8 for boot menu", 3
pxe-service=X86PC, "Boot from network", pxelinux

# A boot service type of 0 is special, and will abort the
# net boot procedure and continue booting from local media.
pxe-service=X86PC, "Boot from local hard disk", 0

# This sets the DSHP server to run in proxy mode.  For the ip address
# any address in the subnet will do, so just put the server NIC ip here.

# That's it

To check you've got things right it's worth running a few checks. Firstly check the syntax of your configuration file:

root@box~# dnsmasq --test
dnsmasq: syntax check OK.

However I should point out you'll also get this message if there is NO configuration file!

When we start dnsmasq it will try and create a lease file /var/lib/misc/dnsmasq.leases. As we are not acting as the main DCHP server we have no requirement to keep track of leases so we use the command line switch of -9 to suppress the use of the lease database file.

Next startup dnsmasq in the foreground. You should get a few messages:

root@box:~# dnsmasq -9 -d
dnsmasq: started, version 2.55 DNS disabled
dnsmasq: compile time options: IPv6 GNU-getopt no-DBus no-I18N DHCP TFTP
dnsmasq-dhcp: DHCP, proxy on subnet:
dnsmasq-dhcp: TFTP root is /home/tftproot

Here you can see that it has started the DHCP proxy and the FTFP server. If you don't see these messages then either you've got the configuration completely wrong or you have mispelled/misplaced the conf file.

Next fire up your network client and you should end up with the PXE Boot Menu screen on it and a number of messages in the dnsmasq log file...

Save it

The final step is to ensure that we save our changes. We're running with a persistent /home so that only leaves the file /etc/dnsmasq.conf to worry about. We also want dnsmasq to start up when our system boots.

root@box:~# echo etc/dnsmasq.conf >>/opt/.filetool.lst
root@box:~# echo dnsmasq -9 >>/opt/
root@box:~# -b
Backing up files to /mnt/sda1/tce/mydata.tgzDone


When you start up a client it searches for a number of configuration files before finally setting on the default menu we created earlier. Here's an excerpt from the log file when I fired up a Wyse S10 with a MAC address of 00:80:64:71:AB:0A which was assigned an IP address of

dnsmasq-tftp: file /home/tftpboot/pxelinux.cfg/597c5400-922f-11db-9fff-008064667faa not found
dnsmasq-tftp: file /home/tftpboot/pxelinux.cfg/01-00-80-64-71-ab-0a not found
dnsmasq-tftp: file /home/tftpboot/pxelinux.cfg/C0A80A15 not found
dnsmasq-tftp: file /home/tftpboot/pxelinux.cfg/C0A80A1 not found
dnsmasq-tftp: file /home/tftpboot/pxelinux.cfg/C0A80A not found
dnsmasq-tftp: file /home/tftpboot/pxelinux.cfg/C0A80 not found
dnsmasq-tftp: file /home/tftpboot/pxelinux.cfg/C0A8 not found
dnsmasq-tftp: file /home/tftpboot/pxelinux.cfg/C0A not found
dnsmasq-tftp: file /home/tftpboot/pxelinux.cfg/C0 not found
dnsmasq-tftp: file /home/tftpboot/pxelinux.cfg/C not found
dnsmasq-tftp: sent /home/tftpboot/pxelinux.cfg/default to

From the pxelinux wiki:

Because more than one system may be booted from the same server, the configuration file name depends on the IP address of the booting machine. PXELINUX will search for its config file on the boot server in the following way:

First, it will search for the config file using the hardware type (using its ARP type code) and address, all in lower case hexadecimal with dash separators; for example, for an Ethernet (ARP type 1) with address 88:99:AA:BB:CC:DD it would search for the filename 01-88-99-aa-bb-cc-dd.

Next, it will search for the config file using its own IP address in upper case hexadecimal, e.g. -> C000025B (you can use the included program gethostip to compute the hexadecimal IP address for any host). If that file is not found, it will remove one hex digit and try again. Ultimately, it will try looking for a file named default (in lower case).



Any comments? email me.    Last update June 2013