NIC guard: ignore client EAPOL, re-check on carrier change, SMB-only lease cleanup
- 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.
This commit is contained in:
@@ -22,6 +22,9 @@ The NIC guard catches those.
|
||||
| `/etc/pxe-server/nic.conf` | which NIC is which |
|
||||
| `/etc/systemd/system/dnsmasq.service.d/nic-guard.conf` | guard before every dnsmasq start|
|
||||
| `/etc/systemd/system/pxe-nic-check.{service,timer}` | watch every 5 min |
|
||||
| `/usr/local/sbin/pxe-nic-carrier` | re-check on imaging cable moves |
|
||||
| `/etc/networkd-dispatcher/<state>.d/50-pxe-nic-carrier` | calls it on link changes |
|
||||
| `/etc/systemd/system/pxe-nic-carrier.service` | the re-check after carrier gain |
|
||||
| `/run/pxe-nic-status.json` | last result, read by the webapp |
|
||||
|
||||
Sources: `playbook/pxe-server-helpers/`, installed by `pxe_server_setup.yml`
|
||||
@@ -33,11 +36,18 @@ from the first two). The same MACs pin the NICs in netplan
|
||||
|
||||
## How it decides
|
||||
|
||||
It listens on each NIC (raw socket, sends nothing) for:
|
||||
It listens on each NIC (raw socket, sends nothing; it joins the STP,
|
||||
802.1X, LLDP, CDP and PVST+ multicast groups so a NIC that is not
|
||||
promiscuous still hears them) for:
|
||||
|
||||
- LLDP and CDP: managed switches announce themselves. GE switches do; the
|
||||
unmanaged imaging switch does not.
|
||||
- 802.1X EAPOL: GE ports ask for port authentication.
|
||||
- 802.1X EAPOL from an authenticator: GE ports ask for port
|
||||
authentication (EAP Request, Success or Failure). EAPOL that clients
|
||||
send is ignored: iPXE sends three EAPOL-Starts every time it opens a
|
||||
NIC and Windows sends Starts and EAP Responses, so a bay PXE-booting on
|
||||
the imaging switch is not mistaken for a GE port. Those frames show up
|
||||
only as "N client EAPOL frames ignored".
|
||||
- DHCP OFFER/ACK from any other server.
|
||||
- STP and the count of distinct ARP hosts: reported, never decisive.
|
||||
|
||||
@@ -70,7 +80,19 @@ never allowed.
|
||||
about 6 s. Exit 1 = do not serve: dnsmasq does not start. A bug or no
|
||||
link exits 0 (fail open) with an error line in the journal.
|
||||
- `pxe-nic-check --watch` - the timer. On a bad imaging verdict it runs
|
||||
`systemctl stop dnsmasq` and logs CRIT. It never starts dnsmasq.
|
||||
`systemctl stop dnsmasq` and logs CRIT. It never starts dnsmasq. If
|
||||
dnsmasq was (re)started during the 60 s window (an operator, or the
|
||||
carrier hook, restarted it and its guard passed), the watch re-checks
|
||||
for about 6 s and stops dnsmasq only if that still says blocked; if
|
||||
dnsmasq is already stopped it only logs.
|
||||
- `pxe-nic-carrier` - the networkd-dispatcher hook. Only the imaging NIC
|
||||
(or its bridge ports) counts; GE NIC events are ignored. Carrier lost:
|
||||
dnsmasq is stopped at once if it was running. Carrier back: after 2 s,
|
||||
`pxe-nic-carrier.service` restarts dnsmasq if it was running or the hook
|
||||
stopped it, so the guard checks the new network before dnsmasq serves
|
||||
again; dnsmasq that an operator or the watch stopped stays stopped.
|
||||
A bridge with several ports stops dnsmasq when any one of them loses
|
||||
carrier. Log: `journalctl -t pxe-nic-carrier`.
|
||||
|
||||
Every start or restart of dnsmasq runs the guard, so `systemctl restart
|
||||
dnsmasq` and the `@reboot` cron restart take about 6 s longer than before.
|
||||
@@ -81,6 +103,7 @@ dnsmasq` and the `@reboot` cron restart take about 6 s longer than before.
|
||||
cat /run/pxe-nic-status.json # last guard/watch result
|
||||
journalctl -u dnsmasq -b | grep pxe-nic-check
|
||||
journalctl -u pxe-nic-check -b
|
||||
journalctl -t pxe-nic-carrier -b # cable unplug / replug
|
||||
|
||||
## dnsmasq will not start
|
||||
|
||||
@@ -94,7 +117,7 @@ dnsmasq` and the `@reboot` cron restart take about 6 s longer than before.
|
||||
|
||||
## Floor tests (run with the floor idle)
|
||||
|
||||
Both tests stop imaging for a few minutes. Have console or GE-side SSH
|
||||
All three tests stop imaging for a few minutes. Have console or GE-side SSH
|
||||
access to the server; do not rely on the imaging network for the session.
|
||||
|
||||
### (a) Rogue DHCP on the imaging switch: expect the alarm
|
||||
@@ -126,6 +149,10 @@ dnsmasq must be stopped BEFORE the cable moves, so it never serves on GE.
|
||||
dnsmasq; the guard would still block it, but do not test that way).
|
||||
2. Move the IMAGING NIC's cable from the imaging switch into a live GE
|
||||
network port. Wait for link: `ip -br link` shows the imaging NIC `UP`.
|
||||
The carrier hook sees the link come up and runs the guard once (one
|
||||
DHCPDISCOVER) to refresh the status file; with dnsmasq stopped it does
|
||||
not start it. `journalctl -t pxe-nic-carrier -n 5` shows `dnsmasq was
|
||||
not running, left stopped`.
|
||||
3. Run the guard by hand first:
|
||||
`sudo pxe-nic-check --guard; echo "exit $?"`
|
||||
Expect `exit 1` and a `REFUSING to start dnsmasq` line naming LLDP/CDP,
|
||||
@@ -142,6 +169,17 @@ dnsmasq must be stopped BEFORE the cable moves, so it never serves on GE.
|
||||
shows the imaging NIC `isolated`. `sudo systemctl start dnsmasq`
|
||||
starts. PXE-boot one client to confirm.
|
||||
|
||||
### (c) Imaging cable unplugged and replugged: expect stop, re-check, start
|
||||
|
||||
1. dnsmasq running, imaging NIC `isolated`.
|
||||
2. Unplug the imaging NIC's cable. Within a second
|
||||
`journalctl -t pxe-nic-carrier -n 5` shows `carrier lost on imaging NIC
|
||||
... stopped dnsmasq` and `systemctl is-active dnsmasq` is `inactive`.
|
||||
3. Plug it back into the imaging switch. About 10 s later the journal
|
||||
shows `guard passed, dnsmasq (re)started` and dnsmasq is `active`.
|
||||
Had it gone into a GE port instead, the guard refuses: the journal
|
||||
shows `dnsmasq NOT started` and dnsmasq stays down.
|
||||
|
||||
## Status file
|
||||
|
||||
`/run/pxe-nic-status.json`, mode 0644, replaced atomically:
|
||||
|
||||
Reference in New Issue
Block a user