- 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.
68 lines
2.3 KiB
Bash
Executable File
68 lines
2.3 KiB
Bash
Executable File
#!/bin/bash
|
|
#
|
|
# pxe-dhcp-hook.sh - dnsmasq dhcp-script hook.
|
|
#
|
|
# Runs every time a PXE client gets/changes/releases a DHCP lease on
|
|
# 172.16.9.0/24. Flushes that client's SMB (TCP 445 and 139) conntrack
|
|
# entries and drops its lingering SMB sockets. Prevents stale server-side
|
|
# state from causing "System error 53 - network path not found" when a
|
|
# WinPE client re-images the same machine without a clean SMB session
|
|
# teardown.
|
|
#
|
|
# SMB only, on purpose: the lease that fires this hook is iPXE's, and its
|
|
# first HTTP fetch of the boot menu is racing this script. Killing every
|
|
# socket or conntrack entry for the client IP broke that fetch.
|
|
#
|
|
# dnsmasq calls this with argv:
|
|
# $1 = action (add | old | del)
|
|
# $2 = mac address
|
|
# $3 = client IP
|
|
# $4 = hostname (may be empty)
|
|
#
|
|
# A re-image usually comes back to the SAME lease (same MAC, same IP), which
|
|
# dnsmasq reports as "old", not "add" - and only at all because dnsmasq.conf
|
|
# sets script-on-renewal. "old" also fires when a running Windows PC renews
|
|
# its lease, so on "old" we only clear state when the request came from PXE
|
|
# firmware or iPXE (vendor class PXEClient...): that machine has just
|
|
# rebooted into a network boot, so any server-side session for its IP is
|
|
# dead. A renewal from Windows (vendor class "MSFT 5.0") is left alone.
|
|
#
|
|
# Must exit quickly; dnsmasq waits for it. Logs to syslog via logger.
|
|
|
|
set +e
|
|
|
|
# dnsmasq's environment may lack sbin; keep any PATH it gave us first.
|
|
PATH="${PATH:+$PATH:}/usr/sbin:/usr/bin:/sbin:/bin"
|
|
|
|
action="$1"
|
|
mac="$2"
|
|
ip="$3"
|
|
host="${4:-}"
|
|
|
|
[ -z "$ip" ] && exit 0
|
|
|
|
clear_state() {
|
|
local port
|
|
for port in 445 139; do
|
|
# client -> our share, and anything the other way round
|
|
conntrack -D -p tcp -s "$ip" --dport "$port" >/dev/null 2>&1
|
|
conntrack -D -p tcp -d "$ip" --sport "$port" >/dev/null 2>&1
|
|
done
|
|
# our SMB sockets (local port 445/139) whose peer is this client
|
|
ss -K -t "( sport = :445 or sport = :139 ) and dst = $ip" >/dev/null 2>&1
|
|
logger -t pxe-dhcp-hook "cleared stale SMB state for $1 $ip ($mac${host:+ $host})"
|
|
}
|
|
|
|
case "$action" in
|
|
add|del)
|
|
clear_state "$action"
|
|
;;
|
|
old)
|
|
case "${DNSMASQ_VENDOR_CLASS:-}" in
|
|
PXEClient*) clear_state "old (network boot, ${DNSMASQ_VENDOR_CLASS%%:UNDI*})" ;;
|
|
esac
|
|
;;
|
|
esac
|
|
|
|
exit 0
|