Network PXE Boot iPXE System Rescue

How to use iPXE as a cheap emergency system rescue system!

Firstly you will need to find and check out you can flash a suitable network card. Examples are of the two most common ones you may have laying around.


 * a standard PCI 3COM 3C905C
 * a standard PCI Intel Pro 100

Basic Principal

 * Suitable network card (or onboard LAN) is flashed with an iPXE rom with inbuilt script
 * Inbuilt script tells it to get its config file from a remote site (www or ftp) passing some variables over specific to the server, e.g. MAC address e.g. www.yoursite/rescue.php?mac={mac}
 * Set the BIOS to boot this LAN card first
 * System boots from NIC and the result of rescue.php determines if it drops to next boot device, or your rescue system!

So in a normal situation, the server boots from LAN ,checks out result from rescue.php, which normally drops it to second boot device. (LAN down will also cause this as it will timeout) In an emergency the best you can usually hope for is someone to power server on and off. However, now you can alter rescue.php to tell the server to boot from your little rescue system instead or dropping to next boot device. This will probably be a linux kernel/initrd running some utils and a SSH server so you can get in and fix your server, or at least see whats wrong!

Embed script for EEPROM
This is saved as "script" (name doesn't matter). you can add as many variables here so long as you dont break the HTTP_GET string length limit (which could be anything) - remember everything is URL encoded so it may end up longer than you think.

MAC would be minimal to identify the machine, but the more you add the harder it would be for someone to try and spoof it etc. ( add things like dns=${dns}&gateway=${gateway} - or you could hardcode them)

dhcp chain http://www.richud.com/rescue.php?mac=${mac}&ip=${ip}
 * 1) !ipxe

Create rom
The rom is then created in ipxe, embedding the script (called "script" above), in this example for the Intel NIC.

$ make ARCH=i386 CC="gcc -m32" CXX="g++ -m32" EMBED=script bin/80861229.rom



[ZINFO] bin/80861229.rom.zinfo [ZBIN] bin/80861229.rom.zbin [FINISH] bin/80861229.rom rm bin/80861229.rom.zbin bin/80861229.rom.bin bin/80861229.rom.zinfo

Write rom to card
Created pad file, writes rom into it and then flash the Intel NIC
 * Note flashrom can determine correct card without specifying bus, if it is the only card in system 'nicintel' recognises

$ dd if=/dev/zero of=test.rom bs=1 count=65536 $ dd if=bin/80861229.rom of=test.rom conv=notrunc $ sudo flashrom -p nicintel -w test.rom



Mapping Intel NIC control/status reg at 0xfdaff000, unaligned size 0x10. Found Atmel flash chip "AT49BV512" (64 kB, Parallel) on nicintel. Reading old flash chip contents... done. Erasing and writing flash chip... Erase/write done. Verifying flash... VERIFIED.

rescue.php
The embedded ROM script tries to chainload this from your rescue server - this will determine what it does next.

"foreach" loop sets all arguments passed to become variables of the same name.

Variables passed can therefore be used to determine what to dish out next in iPXE script.

"switch" can be used for multiple MACs or can stick to basic if/else if you prefer!

Can match HTTP header info to returned variables to make sure it is who it says it is, e.g. checking IP is matched

In this example my rescue kernel (and appended parameters) is : "kernel bzImage loglevel=3 vga=788" and rescue initrd is "initrd initramfs.cp.lzma"

<?PHP echo "#!ipxe\n";

foreach($_GET as $k=>$v){ $$k=$v; }
 * 1) echo "echo $k=$v\n"; #uncomment to debug

$sip=$_SERVER["REMOTE_ADDR"];

switch ($mac) { case "00:02:b3:9d:94:8c": break; #comment out to enable rescue mode for this MAC if ( $ip == $sip ) { echo " kernel bzImage loglevel=3 vga=788                                initrd initramfs.cp.lzma                                boot"; } else { echo "echo IP Failed Match"; }       break; default: echo "echo No rescue mode requested, exiting"; } ?>

The above script is currently disabled (normal passthrough mode), to ENABLE rescue mode, change break; #comment out to enable rescue mode for this MAC to
 * 1) break; #comment out to enable rescue mode for this MAC

Security Risks
I think the benefits greatly outweigh the risks, but for the paranoid!


 * Your domain could get taken over so config file is elsewhere. (Could hardcode IP instead)
 * Someone where your server is hosted could spoof the DHCP gateway etc when its getting its address via DHCP, (Could hardcode all network settings in the script file instead)