Hi @efbCREED — a couple of things are going on here, and the good news is the behavior you’re seeing may not be broken at all.
First, your capture is filtering out where the boot filename actually lives.
Because you’re using pxe-service= menu entries in proxy mode, dnsmasq does the handoff in two steps:
The initial ProxyDHCP offer on port 67 carries the PXE menu (in the vendor-encapsulated options) and a boot-server list — it deliberately does not include the boot filename (option 67). That’s exactly the “four handshake-y parameters” you’re seeing. The client then sends a Boot Server Discover and the actual filename comes back on UDP port 4011.Your filter was port 67 or 68, so it never captured 4011 — which is very likely where the file is (or should be) going. Re-run with:
tcpdump -i eno1 -v port 67 or port 68 or port 4011
That will tell us whether the filename is being served on 4011 and the client just isn’t completing the exchange, or whether it never gets there.
Second, I’d simplify the config. Your file mixes two different handoff mechanisms (dhcp-boot and pxe-service), and the four dhcp-vendorclass lines you defined are never actually referenced — the pxe-service lines use dnsmasq’s built-in arch keywords instead, so those vendorclass lines aren’t doing anything.
The config we recommend for proxyDHCP drops the menu approach and matches on architecture directly. This puts the correct filename right in the port-67 offer (so it’s trivial to verify with the tcpdump you’re already running) and chains iPXE → FOG’s boot.php once iPXE is loaded:
# /etc/dnsmasq.d/ltsp.conf (adjust <server-ip> throughout) port=0 log-dhcp tftp-root=/tftpboot dhcp-range=<server-ip>,proxy dhcp-no-override # Detect the client's PXE architecture (DHCP option 93) dhcp-match=set:bios,option:client-arch,0 dhcp-match=set:efi32,option:client-arch,6 dhcp-match=set:efibc,option:client-arch,7 dhcp-match=set:efi64,option:client-arch,9 # Detect when iPXE itself is asking (DHCP option 175) dhcp-match=set:ipxe,175 # Serve the right network boot program per architecture dhcp-boot=tag:bios,undionly.kpxe,,<server-ip> dhcp-boot=tag:efi32,ipxe.efi,,<server-ip> dhcp-boot=tag:efibc,ipxe.efi,,<server-ip> dhcp-boot=tag:efi64,ipxe.efi,,<server-ip> # Once iPXE is running, hand off to FOG dhcp-boot=tag:ipxe,http://<server-ip>/fog/service/ipxe/boot.phpA few notes:
Use undionly.kpxe for BIOS, not .kkpxe. The kk variant is only needed on the handful of older NICs that need the UNDI stack kept resident — undionly.kpxe is the right default. The tag:ipxe line must come after the per-arch lines. dnsmasq applies the later match, so this ensures a machine that’s already running iPXE gets sent to boot.php instead of being handed the .efi again (which would loop). Make sure those files actually exist under /tftpboot (undionly.kpxe, ipxe.efi) — they ship with FOG, but worth confirming.After you drop this in, restart dnsmasq and PXE-boot a client with the tcpdump above running. You should now see the filename land in the port-67 offer for the client’s architecture. If you still get nothing, paste that full capture (67/68/4011) here and we’ll take it from there.
Which firmware is the client — legacy BIOS or UEFI? That narrows down which line above should be firing.