From Brandon's Tinkerings
Revision as of 02:04, 17 October 2012 by Bpenglase (talk | contribs) (Added under construction)
Jump to: navigation, search
This is under construction and may not be complete

Heading text

Intro

PXE (Preboot Execution Environment) Booting, or just Network booting in general is very interesting, at least to me, and a few others. As I believe it was Marty Connor in this awesome video "gPXE: Modern FOSS Network Booting" said that some people get really excited over booting machines over networks (including the Internet!) while others... not so much.

Well, I'm one of those people who gets really excited over the idea of booting machines over a network, and I can't really put my finger on why, it's just awesome to me.

So, I wanted to document the netboot setups that I use at my home, and my work. This entry consists of my work setup. My home setup is detailed here

Now, network booting isn't for everyone, and it doesn't fit every situation, so your mileage will vary greatly.

My work setup consists of iPXE, ASP Scripting, Syslinux, and different separate utilities. All of this is detailed below... so lets begin!

What does this page assume?

  • You have a working network
  • You control your DHCP Server
  • You have control of your DNS server
  • You have a working webserver
  • Basic understanding of ASP
  • Have a basic understand of whats involved with PXE Booting, even if it's skimming over the Wikipedia page
  • Have a machine that is capable of picking the network card to boot from, via PXE (On most Dell systems, you need to go into the BIOS, Integrated Peripherals, and mark the NIC as "On W/ PXE", not just "On", or "On W/ ImageServer"

My Environment

  • Windows Server 2008 R2
  • IIS 7
  • Classic ASP Scripting
  • tftpd32 v4.00 (Service)
  • iPXE (current GIT master)
  • Syslinux 4.06_Pre11
  • Misc Utilities like Drive Fitness Test, SeaTools, Memtest, etc.

The Basic Process

-- My Setup

  1. Computer powers on, and selects the NIC to boot from, either via interaction, or it being the first device
  2. The native PXE Stack (iPXE (flashed onto the ROM/BIOS), Intel, Broadom, Realtek, etc) brings up the network card, does a DHCP Request, while also requesting, at least, options 66 and 67
  3. DHCP Server responds with an IP, and the two options
  4. The PXE Stack then tried to contact the server provided in option 66, to retrieve the file specified in option 67, which in this case is iPXE (for non-iPXE clients), over TFTP
  5. iPXE then unloads the native PXE stack (to a degree), and takes over, issuing it's own DHCP Request, again requesting, among other options, 66 and 67
  6. The DHCP Server responds with (typically) the same IP address, but now detects that the client is iPXE, and passes a different option 67.
  7. iPXE then boots to the URL passed in option 67 this time (via HTTP), and that script then directs it what to do.

Files

IIS Config

<Place holder for the time being>

TFTPD32 Config

<Place holder for the time being>

preboot.asp

<% 
response.contenttype="text/plain" 
dim mac
dim plembed
dim clientip
dim code
dim code1

' Set code
code = "onereallylongcodethatsrandomlygenerated"

' Set Code1
code1 = "secondreallylongcodethatsrandomlygenerated"

' Set IP Subnets that do not get prompted for login
dim nologinips(1)
nologinips(0) = "10.80.18" ' Subnet for NetApps
nologinips(1) = "10.80.38" ' Subnet in Technicians Office

' Get the client's IP Address
clientip = request.servervariables("REMOTE_ADDR")

' Check to see if the PXE boot thats hitting us is authorized, the boot will embed two random codes
' this is also used to try and hide the user/pass on the command since it's shown in plain text in the URL
' Check Code0
if not request.querystring("code").count = 0 then
	if request.querystring("code") = code then
		' Check Code1		
		if not isEmpty(request.querystring("code1")) then
			if not request.querystring("code1") = code1 then
				' Fail to boot, don't offer login screen again
				response.write("#!ipxe" & vbcrlf & "echo Boot Error Code: Error 001 - This PXEBoot is not authorized." & vbcrlf & "exit 1")
				response.end
			end if
		end if
	else
		' Fail to boot, don't offer login screen again
		response.write("#!ipxe" & vbcrlf & "echo Boot Error Code: Error 002 - This PXEBoot is not authorized."& vbcrlf & "exit 1")
		response.end
	end if
else
		' Fail to boot, don't offer login screen again
		response.write("#!ipxe" & vbcrlf & "echo Boot Error Code: Error 003 - This PXEBoot is not authorized."& vbcrlf & "exit 1")
		response.end
end if

'Get MAC Address into a variable
' This should always be handed over to this script.
If not isEmpty(request.querystring("MAC")) Then
	mac = request.querystring("MAC")
else
	' If no MAC found, it's most likely a bad script, or unauthorized netboot that has somehow gotten this far
	response.write("#!ipxe" & vbcrlf & "echo Boot Error Code: Error 009 - MAC Not listed."& vbcrlf & "exit 1")
	response.end
End If

' Find out of Pxelinux is embedded or not
If not isEmpty(request.querystring("plembed")) Then
	plembed = request.querystring("plembed")
else
	plembed = 0
End If

' Compare the current client IP to IPs we shouldn't prompt for login for
for i=0 to ubound(nologinips)
	if instr(clientip, nologinips(i)) then
		'Perform functions for clients that don't need to be prompted for login
		response.write("#!ipxe"&vbcrlf)
		response.write("echo On IP "&clientip&" -- Bypassing Login, Autologging in as CS."&vbcrlf)
		response.write("chain -ar http://netboot.example.com/boot.asp?MAC="&mac&"&code="&code&"&user=cs&pass=a12345B&plembed="&plembed&"&code1="&code1&vbcrlf)
		response.end
	end if
next
response.write("#!ipxe"&vbcrlf)
response.write("echo On IP "&clientip&" -- Forcing Login."&vbcrlf)
response.write("login"&vbcrlf)
response.write("chain -ar http://netboot.example.com/boot.asp?MAC="&mac&"&code="&code&"&user=${username:uristring}&pass=${password:uristring}&plembed="&plembed&"&code1="&code1&vbcrlf)
response.end

%>

boot.asp

<% 
response.contenttype="text/plain" 
dim mac
dim user
dim pass
dim plembed
dim testing

'Check to see if the PXE boot thats hitting us is authorized, the boot will embed two random codes
'this is also used to try and hide the user/pass on the command since it's shown in plain text
' Check Code0
if not request.querystring("code").count = 0 then
	if request.querystring("code") = "onereallylongcodethatsrandomlygenerated" then
		' Check Code1		
		if not isEmpty(request.querystring("code1")) then
			if not request.querystring("code1") = "secondreallylongcodethatsrandomlygenerated" then
				' Fail to boot, don't offer login screen again
				response.write("#!ipxe" & vbcrlf & "echo Boot Error Code: Error 001 - This PXEBoot is not authorized." & vbcrlf & "exit 1")
				response.end
			end if
		end if
	else
		' Fail to boot, don't offer login screen again
		response.write("#!ipxe" & vbcrlf & "echo Boot Error Code: Error 002 - This PXEBoot is not authorized."& vbcrlf & "exit 1")
		response.end
	end if
else
		' Fail to boot, don't offer login screen again
		response.write("#!ipxe" & vbcrlf & "echo Boot Error Code: Error 003 - This PXEBoot is not authorized."& vbcrlf & "exit 1")
		response.end
end if

'Check to see if user is set, and not empty, if it is, then do the same with the password.
'If set, copy the results to variables
'Otherwise fail over with an error code. 
if not request.querystring("user").count = 0 and not isEmpty(request.querystring("user")) then
	user = request.querystring("user")
	if not request.querystring("pass").count = 0 and not isEmpty(request.querystring("pass")) then
		pass = request.querystring("pass")
	else
		' If no password is set, fail (either blank, or login command was not issued)
		response.write("#!ipxe" & vbcrlf & "echo Boot Error Code: Error 004 - No Password Set."& vbcrlf & "exit 1")
		response.end	
	end if	
else
		' If the username is blank, fail (either left blank, or login command was not issued)
		response.write("#!ipxe" & vbcrlf & "echo Boot Error Code: Error 005 - No Username Set."& vbcrlf & "exit 1")
		response.end	
end if

'Verify user/pass combination
'Other users can be added here, following the same code (can use the cs or shd variables if returning the same menu
'Otherwise new variables can be added for more functionality)
'First is user 'cs' - Computing Services
if user = "cs" then
	' If the password needs to change, change it here
	if not pass = "a12345B" then
		response.write("#!ipxe" & vbcrlf & "echo Boot Error Code: Error 006 - Wrong Password." & vbcrlf & "exit 1")
		response.end
	else
		' Set the proper code for which menu (or other functions) should be returned to the user
		cs = 1
		shd = 0
	end if
'Next user is 'shd' - Student HelpDesk
elseif user = "shd" then
	' If the password needs to change, change it here
	if not pass = "B54321a" then
		response.write("#!ipxe" & vbcrlf & "echo Boot Error Code: Error 007 - Wrong Password." & vbcrlf & "exit 1")
		response.end
	else
		' Set the proper code for which menu (or other functions) should be returned to the user
		cs = 0
		shd = 1
	end if
else
		response.write("#!ipxe" & vbcrlf & "echo Boot Error Code: Error 008 - Invalid Username." & vbcrlf & "exit 1")
		response.end
end if
		
'Get MAC Address into a variable
' This should always be handed over to this script.
If not isEmpty(request.querystring("MAC")) Then
	mac = request.querystring("MAC")
else
	' If no MAC found, it's most likely a bad script, or unauthorized netboot that has somehow gotten this far
	response.write("#!ipxe" & vbcrlf & "echo Boot Error Code: Error 009 - MAC Not listed."& vbcrlf & "exit 1")
	response.end
End If

' Find out of Pxelinux is embedded or not
If not isEmpty(request.querystring("plembed")) Then
	plembed = request.querystring("plembed")
else
	plembed = 0
End If

' Check the MAC, this is where we can specify certain PCs get certain things
' This was changed to #!ipxe on 5/7/12, if gPXE is still in use, it may fail, however most builds are now ipxe
response.write("#!ipxe" & vbCrLF)
Select Case mac
	Case "00:0c:29:xx:xx:xx" ' This is a VM for testing the netboot with.
		ipxemenu
	Case "84:2b:2b:xx:xx:xx" ' Dell 980 
		ipxemenu
	Case Else
		' Fall back and set the pxelinux variables and what variables should work with what menus
		' Variable here (current) set based on username provided
		response.write("set 210:string http://netboot.example.com/" & vbcrlf)
		If cs = 1 Then
			response.write("set 209:string mainmenu.ipxe" & vbcrlf)
		ElseIf shd = 1 Then
			response.write("set 209:string mainmenu-shd.ipxe" & vbcrlf)
		End If

		' If pxelinux is embedded, load it from the embedded image, otherwise pull it from the server
		If plembed = 1 Then
			response.write("imgload pxelinux.0" & vbcrlf)
			response.write("imgexec pxelinux.0" & vbcrlf)
		Else
			response.write("chain ${210:string}pxelinux.0" & vbcrlf)
		End If
End Select

sub ipxemenu()
	response.write(":mainmenu" & vbcrlf)
	response.write("menu Work Netboot" & vbcrlf)
	response.write("item --gap --		----------- Ghost Boots -----------" & vbcrlf)
	response.write("item --key w wimboot	Symantec Ghost PE via WIMBoot" & vbcrlf)
	response.write("item --gap --   	------ Hardware Diagnostics -------" & vbcrlf)
	response.write("item --key m memtest	Memtest" & vbcrlf)
	response.write("item --key d dft	Drive Fitness Test v4.16" & vbcrlf)
	response.write("item --key l wddld	WD Data Lifegaurd Diagnostics v5.04f" & vbcrlf)
	response.write("item --key s seatools	Seagate Seatools for DOS v2.23" & vbcrlf)
	response.write("item --gap -- 		--------- Disk Utilities ----------" & vbcrlf)
	response.write("item --key q qwipe	Quick Wipe (Default Disk: 0)" & vbcrlf)
	response.write("item --key a dban	Darik's Boot and Nuke (DBAN) v2.2.6" & vbcrlf)
	response.write("item --key h shdd	Salvation HDD Scan and Restore v3.0" & vbcrlf)
	response.write("item --key p pmagic	Parted Magic" & vbcrlf)
	response.write("item --key g gparted	GParted (Gnome Partition Editor)" & vbcrlf)
	response.write("item --gap --		---------- Other Options ----------" & vbcrlf)
	response.write("item --key o nboot	Other Netboot Systems Menu" & vbcrlf)
	response.write("item --key i installers	Installers Submenu" & vbcrlf)
	response.write("item --key x shell	iPXE Shell" & vbcrlf)
	response.write("item default	Default VesaMenu" & vbcrlf)
	response.write("choose label && goto ${label}" & vbcrlf)

	response.write(":dft" & vbcrlf)
	response.write("sanboot --drive=0x00 dft32_v416_b00_install.IMG" & vbcrlf)
	response.write("goto mainmenu" & vbcrlf)

	response.write(":wddld" & vbcrlf)
	response.write("sanboot --drive=0xa0 Diag504fCD.iso" & vbcrlf)
	response.write("goto mainmenu" & vbcrlf)

	response.write(":nboot" & vbcrlf)
	response.write("menu Work Netboot - Other Netboot Systems" & vbcrlf)
	response.write("item --key c citrix	Citrix Provisioning Service (Citrix-DP)" & vbcrlf)
	response.write("item --key t tstation	Thinstation" & vbcrlf)
	response.write("item --key r mainmenu	Return to Main Menu" & vbcrlf)
	response.write("choose label && goto ${label}" & vbcrlf)

	response.write(":installers" & vbcrlf)
	response.write("menu Work Netboot - Installers Menu" & vbcrlf)
	response.write("item --key 3 7x32	Windows 7 32bit Installer" & vbcrlf)
	response.write("item --key 6 7x64	Windows 7 64bit Installer" & vbcrlf)
	response.write("item --key p esxi51sl	ESXi 5.1 Installer via PXELinux" & vbcrlf)
	response.write("item --key i esxi51	ESXi 5.1 Installer native iPXE" & vbcrlf)
	response.write("item --key r mainmenu	Return to Main Menu" & vbcrlf)
	response.write("choose label && goto ${label}" & vbcrlf)

	response.write(":memtest" & vbcrlf)
	response.write("chain memtest.0" & vbcrlf)
	response.write("goto mainmenu" & vbcrlf)

	response.write(":esxi51sl" & vbcrlf)
	response.write("set 210:string http://netboot.example.com/" & vbcrlf)
	response.write("set 209:string esxi51/esxi.cfg" & vbcrlf)
	If plembed = 1 Then
		response.write("imgload pxelinux.0" & vbcrlf)
		response.write("imgexec pxelinux.0" & vbcrlf)
	Else
		response.write("chain ${210:string}pxelinux.0" & vbcrlf)
	End If
	response.write("goto end" & vbcrlf)

	response.write(":esxi51" & vbcrlf)
	response.write("chain http://netboot.example.com/esxi51/esxi51.ipxe" & vbcrlf)
	response.write("goto end" & vbcrlf)

	response.write(":wimboot" & vbcrlf)
	response.write("imgfree" & vbcrlf)
	response.write("kernel wimboot" & vbcrlf)
	response.write("initrd ghostpe/bootmgr.exe bootmgr.exe" & vbcrlf)
	response.write("initrd ghostpe/BCD BCD" & vbcrlf)
	response.write("initrd ghostpe/fonts/chs_boot.ttf chs_boot.ttf" & vbcrlf)
	response.write("initrd ghostpe/fonts/cht_boot.ttf cht_boot.ttf" & vbcrlf)
	response.write("initrd ghostpe/fonts/kor_boot.ttf kor_boot.ttf" & vbcrlf)
	response.write("initrd ghostpe/fonts/jpn_boot.ttf jpn_boot.ttf" & vbcrlf)
	response.write("initrd ghostpe/fonts/wgl4_boot.ttf wgl4_boot.ttf"& vbcrlf)
	response.write("initrd ghostpe/boot.sdi boot.sdi" & vbcrlf)
	response.write("initrd ghostpe/boot.wim boot.wim" & vbcrlf)
	response.write("boot" & vbcrlf)

	response.write(":7x64" & vbcrlf)
	response.write("sanboot --drive 0xA0 --no-describe http://netboot.example.com/sysinstalls/W7ENTx64.iso" & vbcrlf)

	response.write(":7x32" & vbcrlf)
	response.write("sanboot --drive 0x81 --no-describe http://netboot.example.com/sysinstalls/W7ENTx32.iso" & vbcrlf)

	response.write(":default" & vbcrlf)
	response.write("set 210:string http://netboot.example.com/" & vbcrlf)
	If cs = 1 Then
		response.write("set 209:string mainmenu.ipxe" & vbcrlf)
	ElseIf shd = 1 Then
		response.write("set 209:string mainmenu-shd.ipxe" & vbcrlf)
	End If
	If plembed = 1 Then
		response.write("imgload pxelinux.0" & vbcrlf)
		response.write("imgexec pxelinux.0" & vbcrlf)
	Else
		response.write("chain ${210:string}pxelinux.0" & vbcrlf)
	End If
	response.write(":end" & vbcrlf)
end sub

%>