Path: blob/main/dns/dnsmasq/files/patch-src_dhcp.c
42641 views
commit 84415a87be571a6da82c910c1b87b194e5f547271Author: Clayton O'Neill <[email protected]>2Date: Thu Feb 5 15:38:27 2026 +000034Fix PXE boot server (PXEBS) responses broken in 2.9256I think I've found a regression in dnsmasq 2.92 that breaks PXE boot server7(PXEBS) responses when running in proxy DHCP mode. Fair warning: I'm not8familiar with the dnsmasq codebase and used AI tooling to help trace through9the source and identify the issue, so please take the analysis below with10appropriate skepticism. PXE boot works fine on 2.9111but fails on 2.92 — the client gets the initial proxy DHCPOFFER, but the PXEBS12ACK on port 4011 never reaches it.1314My setup is dnsmasq in proxy DHCP mode serving iPXE to Proxmox VMs via their15virtio-net ROM. Here's a stripped-down version of my config:1617port=018enable-tftp19tftp-root=/tftpboot20dhcp-range=172.19.74.0,proxy,255.255.255.021interface=eno122bind-interfaces23dhcp-match=set:ipxe,17524pxe-service=tag:ipxe,x86PC,"Network Boot",http://server:8081/boot.ipxe25pxe-service=tag:!ipxe,x86PC,"Network Boot",undionly.kpxe26log-dhcp2728The issue seems to be in src/dhcp.c in the response routing logic after29dhcp_reply() returns. In 2.91, the destination selection was an if/else-if30chain:3132if (pxe_fd)33{ ... }34else if (mess->giaddr.s_addr && !is_relay_reply)35{ ... }36else if (mess->ciaddr.s_addr)37{ ... }38else39{ ... broadcast to 255.255.255.255:68 ... }4041In 2.92, the else between the pxe_fd block and the giaddr/relay check was42removed in commit 4fbe1ad ("Implement RFC-4388 DHCPv4 leasequery") to43accommodate the new is_relay_use_source logic:4445if (pxe_fd)46{ ... }47if ((is_relay_use_source || mess->giaddr.s_addr) && !is_relay_reply)48{ ... }49else if (mess->ciaddr.s_addr)50{ ... }51else52{ ... broadcast to 255.255.255.255:68 ... }5354For PXEBS responses, dhcp_reply() in rfc2131.c (around line 924-925) does:5556mess->yiaddr = mess->ciaddr;57mess->ciaddr.s_addr = 0;5859So after dhcp_reply() returns for a PXEBS request, ciaddr is 0, giaddr is 060(no relay), and is_relay_use_source is 0. In 2.91, the pxe_fd block runs and61the rest of the chain is skipped — dest stays as received from recvmsg, and the62response goes back to the client correctly. In 2.92, the pxe_fd block runs but63then falls through to the standalone if, which is false, so the else block runs64and sets dest to 255.255.255.255 port 68. The client is listening on port 401165and ignores it.6667Here are the relevant dnsmasq logs. With 2.91 (working), I see normal proxy68DHCP and PXE boot server exchanges:6970dnsmasq-dhcp: DHCPDISCOVER(eno1) bc:24:11:59:85:9071dnsmasq-dhcp: DHCPOFFER(eno1) 172.19.74.60 bc:24:11:59:85:9072dnsmasq-dhcp: DHCPREQUEST(eno1) 172.19.74.60 bc:24:11:59:85:9073dnsmasq-dhcp: DHCPACK(eno1) 172.19.74.60 bc:24:11:59:85:9074dnsmasq-dhcp: PXE(eno1) bc:24:11:59:85:90 proxy75dnsmasq-dhcp: PXE(eno1) bc:24:11:59:85:90 proxy76dnsmasq-dhcp: PXEBS(eno1) bc:24:11:59:85:90 undionly.kpxe77dnsmasq-dhcp: PXE(eno1) bc:24:11:59:85:90 proxy78dnsmasq-dhcp: PXEBS(eno1) bc:24:11:59:85:90 http://infra1.oneill.net:8081/boot.ipxe7980With 2.92 (broken), the DHCPDISCOVER/OFFER/REQUEST/ACK cycle and the proxy81PXE response work, but the PXEBS response never reaches the client — it times82out after repeated attempts. The dnsmasq side shows it sending the response,83but the client keeps retrying:8485dnsmasq-dhcp: PXE(eno1) bc:24:11:59:85:90 proxy86dnsmasq-dhcp: PXE(eno1) bc:24:11:59:85:90 proxy87dnsmasq-dhcp: PXEBS(eno1) bc:24:11:59:85:90 undionly.kpxe88dnsmasq-dhcp: PXEBS(eno1) bc:24:11:59:85:90 undionly.kpxe89dnsmasq-dhcp: PXEBS(eno1) bc:24:11:59:85:90 undionly.kpxe90dnsmasq-dhcp: PXEBS(eno1) bc:24:11:59:85:90 undionly.kpxe9192I tested by restoring the else keyword and the fix appears to work — 2.92 with93the patch below PXE boots successfully. I believe this change preserves the94leasequery behavior since that path only applies when pxe_fd is false (normal95DHCP handling, not port 4011).9697diff --git a/src/dhcp.c b/src/dhcp.c98index 6775fb6..efda023 10064499--- src/dhcp.c~100+++ src/dhcp.c101@@ -399,7 +399,7 @@ void dhcp_packet(time_t now, int pxe_fd)102if (mess->ciaddr.s_addr != 0)103dest.sin_addr = mess->ciaddr;104}105- if ((is_relay_use_source || mess->giaddr.s_addr) && !is_relay_reply)106+ else if ((is_relay_use_source || mess->giaddr.s_addr) && !is_relay_reply)107{108/* Send to BOOTP relay. */109if (is_relay_use_source)110111112