Files
OpenPXE/scripts/fetch-ipxe.sh
T
Miles WardandClaude Opus 4.8 4f193cac05 v0.6.1: latest iPXE + automatic NIC driver fallback (more devices, zero toggle)
Mirrors the worthwhile device-support wins from iVentoy 1.0.24→1.0.35 onto our
(very different) proxy-DHCP + iPXE-chainload architecture. iVentoy's other
changes are inapplicable (arm64-server / distro-display fixes live in its
injected Linux, which we don't have), niche (iSCSI), or closed-source
(Matrix Boot).

iPXE refreshed (mirrors 1.0.35 "Update iPXE")
- Pin the from-source build to ipxe/ipxe master @ 2026-06-09
  (95ffbf4745553e8a207922389929e1943c0237c0) — newer NIC drivers + EFI fixes.
  The pin also busts the cached ipxe-build Docker layer so the release
  actually recompiles iPXE; build-ipxe.sh now shallow-fetches an exact SHA.

Automatic NIC driver fallback (mirrors 1.0.34 "driver/boot-file mode" — but
no operator toggle, per request)
- New DriverMode {Firmware, Builtin} in core; ClientArch::ipxe_bootfile_mode
  maps each arch to either the firmware-net build (snponly/undionly, default)
  or the all-drivers build (ipxe.efi/ipxe.pxe/ipxe-i386.efi/ipxe-arm64.efi).
- The DHCP proxy serves Firmware by default — byte-for-byte unchanged, so
  hardware that boots today never regresses. A new DriverEscalation state
  machine watches for the tell-tale failure: a MAC re-PXE-boots (fresh
  firmware DISCOVER) without ever completing the iPXE-user-class handoff that
  proves the firmware NIC stack worked. That MAC is automatically escalated to
  iPXE's own NIC drivers, and the choice is sticky after a confirmed handoff
  (debounced for the :67/:4011 same-boot pair, TTL-pruned, capped). It just
  works — no settings, no UI.
- All-drivers binaries fetched per arch (ipxe.pxe + i386/arm64 native EFI;
  x86_64 ipxe.efi already built from source with PNG); ipxe-assets embeds
  *.pxe and logs availability per (arch, mode).

Core principles intact: DHCP-proxy-only, container-first, Rust-focused (the
logic is all Rust; only the iPXE fetch/build stays shell), Windows hard-rules
untouched (this never goes near Windows boot).

Validation: clippy clean; full workspace test suite green (core 99 incl. new
DriverMode tests, dhcp-proxy +4 escalation tests, http-api 31+68, iso-store
61, tftp 6, bin 2); fmt-clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-09 11:18:07 -04:00

92 lines
3.4 KiB
Bash
Executable File

#!/usr/bin/env bash
# Fetch prebuilt iPXE binaries from the official distribution at
# https://boot.ipxe.org/ and place them under assets/ipxe/ with the filenames
# OpenPXE's arch mapping expects.
#
# Why not build from source?
# - Building iPXE requires the toolchain + several megabytes of source, and
# the official binaries are rebuilt nightly from upstream master with the
# standard driver set. For Phase 1 we use those. A later iteration can
# add an optional Dockerfile build stage that compiles iPXE with custom
# driver or scripting patches if needed.
#
# Safety:
# - Upstream (boot.ipxe.org) serves over HTTPS.
# - We do NOT pin by sha256 because upstream is a nightly rolling build;
# pinning would mean stale binaries with known CVEs. If you need
# deterministic builds, mirror these to your own artifact store and
# point the Dockerfile there instead.
# - Each binary is boot firmware the client executes. Only fetch from
# upstream or a mirror you trust; never from random sources.
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
DEST="$ROOT/assets/ipxe"
mkdir -p "$DEST"
# Map: local filename <- upstream path on boot.ipxe.org
# Upstream uses arch-scoped subdirectories; we flatten to the names our
# ClientArch::ipxe_bootfile() expects.
declare -a MAP=(
# DriverMode::Firmware (default) — reuse the firmware UNDI/SNP NIC stack.
"undionly.kpxe=undionly.kpxe"
"snponly.efi=x86_64-efi/snponly.efi"
"snponly-i386.efi=i386-efi/snponly.efi"
"snponly-arm64.efi=arm64-efi/snponly.efi"
# DriverMode::Builtin (v0.6.1 automatic fallback) — iPXE's own all-drivers
# builds, advertised by the DHCP proxy to a MAC whose firmware NIC stack
# failed to chainload. (x86_64 ipxe.efi is rebuilt from source with PNG in
# build-ipxe.sh and overlaid on top of this fetched baseline.)
"ipxe.efi=x86_64-efi/ipxe.efi"
"ipxe.pxe=ipxe.pxe"
"ipxe-i386.efi=i386-efi/ipxe.efi"
"ipxe-arm64.efi=arm64-efi/ipxe.efi"
)
BASE="https://boot.ipxe.org"
# wimboot lives in its own GitHub release. Fetching it enables the Windows
# toggle in the WebUI. Safe to leave disabled — the binary is vendor-signed
# for iPXE's own use; we never modify it and it only runs inside iPXE's
# memory space, never the target OS.
WIMBOOT_URL="https://github.com/ipxe/wimboot/releases/latest/download/wimboot"
fetched=0
for entry in "${MAP[@]}"; do
local_name="${entry%%=*}"
upstream_name="${entry#*=}"
url="$BASE/$upstream_name"
out="$DEST/$local_name"
echo ">> fetching $url -> $out"
if ! curl --fail --silent --show-error --location --output "$out.tmp" "$url"; then
echo " skip: upstream not available ($url)"
rm -f "$out.tmp"
continue
fi
mv "$out.tmp" "$out"
fetched=$((fetched+1))
done
if [ "$fetched" -eq 0 ]; then
echo
echo "ERROR: zero iPXE binaries were downloaded. The container would build"
echo " but no PXE client could boot. Check your network egress to"
echo " $BASE and re-run this script. Aborting."
exit 2
fi
echo
echo ">> fetching wimboot (optional, enables Windows ISO support)"
if curl --fail --silent --show-error --location --output "$DEST/wimboot.tmp" "$WIMBOOT_URL"; then
mv "$DEST/wimboot.tmp" "$DEST/wimboot"
echo " wimboot installed"
else
echo " skip: wimboot unreachable — Windows toggle will stay disabled in the WebUI"
rm -f "$DEST/wimboot.tmp"
fi
echo
echo "iPXE assets now in $DEST:"
ls -lh "$DEST" | tail -n +2