- pxe-nic-check: count 802.1X only from an authenticator (EAPOL type 0
with EAP Request/Success/Failure). iPXE sends EAPOL-Start on every NIC
open and Windows sends Start/Response, so a PXE-booting bay made the
verdict 'ge' and the watch stopped dnsmasq for the floor.
- pxe-nic-check: join the STP/PAE/LLDP/CDP/PVST+ multicast groups on
every capture socket, so CDP-only ports are heard on a plain NIC.
- pxe-nic-check --watch: if dnsmasq was (re)started inside the window,
re-check (~6 s) before stopping it; skip when already stopped.
New --state-cmd and --print-imaging.
- pxe-nic-carrier (+ pxe-nic-carrier.service): networkd-dispatcher hook
for the imaging NIC only. Carrier loss stops dnsmasq; carrier gain
restarts it through its guard if it was running or the hook stopped it.
- pxe-dhcp-hook.sh: clear only SMB (tcp 445/139) conntrack entries and
sockets, not all traffic for the client, which raced iPXE's first
HTTP fetch.
- GetPxeScript.aspx: every boot line has a failure branch (iPXE 2.0
accepts an unsigned EFI kernel and fails at boot under Secure Boot,
which aborted the script).
- Tests: client EAPOL, packet_mreq packing, watch race, shell helpers on
stub PATH, lab scenarios eapol-client, br-eapol-client, race, carrier.
- autoinstall: dead mirror + fallback offline-install, so the installed
base is exactly the ISO's; late-commands run offline-apt-install.sh on
CIDATA packages/ (local apt repo, one transaction, errors fail the
install, log /var/log/offline-apt-install.log); first boot no longer
runs dpkg -i; real archive sources written back at the end.
- download-packages.sh --iso: unpacks the ISO's default install source
into a docker image (pxe-iso-base:<version>) and downloads there: all
updates of the base, the explicit list (zip included) and the newest
pool packages with their closure; writes Packages + explicit.list and
checks the set offline in a fresh base container (--network none).
- offline-apt-install.sh: new; also used by that check (--simulate).
- build-usb.sh: ships Packages, explicit.list and the script; refuses a
set without them.
- tests/vm: pxetest-client-nosb (Secure Boot off, e1000e, SATA), one
client at a time.
- Copy the whole webapp/ tree (minus __pycache__) in build-usb.sh and
build-proxmox-iso.sh, so config, services/, views/ and
blancco_evidence_monthly.py reach the server.
- sfdisk --append failure now aborts; the CIDATA partition is the one
starting exactly at the computed sector, and nothing that starts
before it is ever formatted (the old fallback hit the ISO's EFI
partition).
- Volume id and El Torito load sizes come from the ISO
(xorriso -report_el_torito as_mkisofs); grub.cfg must contain
autoinstall after patching.
- --image FILE SIZE|auto builds the same layout in a file without root
(mkfs.vfat -C + mtools, sfdisk on the file). Plus --payload-root,
--skip-enrollment/-bios/-drivers/-boot-tools, --yes.
- tests/vm: libvirt harness (pxetest-server, pxetest-client, isolated
pxetest-imaging network) with fetch-iso/build-image/create/start/
status/stop/destroy.
pxe-nic-check classifies each NIC from what it hears: LLDP/CDP/802.1X
from managed switches, foreign DHCP offers and their domain (one
DHCPDISCOVER on the imaging NIC; the GE NIC's networkd lease is read
instead), STP and ARP hosts for information. A kernel BPF filter keeps
bulk SMB traffic out of the capture loop; bridge ports are listened on
too, since LLDP and EAPOL stop at the port.
- dnsmasq drop-in runs --guard as ExecStartPre: exit 1 on a ge or
foreign-dhcp imaging verdict, fail open (loudly) on bugs or no link
- pxe-nic-check.timer runs --watch every 5 min: stops dnsmasq on a bad
imaging verdict, never starts it
- /run/pxe-nic-status.json (0644, atomic) for the webapp
- playbook installs it all and writes /etc/pxe-server/nic.conf from
pxe_imaging_mac, pxe_ge_mac, pxe_corp_domain_suffixes,
pxe_nic_allowed_switches
- unit tests plus a no-root network-namespace lab (veth pairs, a raw
socket DHCP/LLDP peer and real dnsmasq); docs/pxe-nic-guard.md has the
operator notes and the two floor tests