Network PXE Boot iPXE System Rescue

From richud.com
Jump to: navigation, search


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.


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)

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

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

<SNIP>

  [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

<SNIP>

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;
 #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

#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)