Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-ports
Path: blob/main/dns/dnsmasq/files/patch-src_dhcp.c
42641 views
1
commit 84415a87be571a6da82c910c1b87b194e5f54727
2
Author: Clayton O'Neill <[email protected]>
3
Date: Thu Feb 5 15:38:27 2026 +0000
4
5
Fix PXE boot server (PXEBS) responses broken in 2.92
6
7
I think I've found a regression in dnsmasq 2.92 that breaks PXE boot server
8
(PXEBS) responses when running in proxy DHCP mode. Fair warning: I'm not
9
familiar with the dnsmasq codebase and used AI tooling to help trace through
10
the source and identify the issue, so please take the analysis below with
11
appropriate skepticism. PXE boot works fine on 2.91
12
but fails on 2.92 the client gets the initial proxy DHCPOFFER, but the PXEBS
13
ACK on port 4011 never reaches it.
14
15
My setup is dnsmasq in proxy DHCP mode serving iPXE to Proxmox VMs via their
16
virtio-net ROM. Here's a stripped-down version of my config:
17
18
port=0
19
enable-tftp
20
tftp-root=/tftpboot
21
dhcp-range=172.19.74.0,proxy,255.255.255.0
22
interface=eno1
23
bind-interfaces
24
dhcp-match=set:ipxe,175
25
pxe-service=tag:ipxe,x86PC,"Network Boot",http://server:8081/boot.ipxe
26
pxe-service=tag:!ipxe,x86PC,"Network Boot",undionly.kpxe
27
log-dhcp
28
29
The issue seems to be in src/dhcp.c in the response routing logic after
30
dhcp_reply() returns. In 2.91, the destination selection was an if/else-if
31
chain:
32
33
if (pxe_fd)
34
{ ... }
35
else if (mess->giaddr.s_addr && !is_relay_reply)
36
{ ... }
37
else if (mess->ciaddr.s_addr)
38
{ ... }
39
else
40
{ ... broadcast to 255.255.255.255:68 ... }
41
42
In 2.92, the else between the pxe_fd block and the giaddr/relay check was
43
removed in commit 4fbe1ad ("Implement RFC-4388 DHCPv4 leasequery") to
44
accommodate the new is_relay_use_source logic:
45
46
if (pxe_fd)
47
{ ... }
48
if ((is_relay_use_source || mess->giaddr.s_addr) && !is_relay_reply)
49
{ ... }
50
else if (mess->ciaddr.s_addr)
51
{ ... }
52
else
53
{ ... broadcast to 255.255.255.255:68 ... }
54
55
For PXEBS responses, dhcp_reply() in rfc2131.c (around line 924-925) does:
56
57
mess->yiaddr = mess->ciaddr;
58
mess->ciaddr.s_addr = 0;
59
60
So after dhcp_reply() returns for a PXEBS request, ciaddr is 0, giaddr is 0
61
(no relay), and is_relay_use_source is 0. In 2.91, the pxe_fd block runs and
62
the rest of the chain is skipped dest stays as received from recvmsg, and the
63
response goes back to the client correctly. In 2.92, the pxe_fd block runs but
64
then falls through to the standalone if, which is false, so the else block runs
65
and sets dest to 255.255.255.255 port 68. The client is listening on port 4011
66
and ignores it.
67
68
Here are the relevant dnsmasq logs. With 2.91 (working), I see normal proxy
69
DHCP and PXE boot server exchanges:
70
71
dnsmasq-dhcp: DHCPDISCOVER(eno1) bc:24:11:59:85:90
72
dnsmasq-dhcp: DHCPOFFER(eno1) 172.19.74.60 bc:24:11:59:85:90
73
dnsmasq-dhcp: DHCPREQUEST(eno1) 172.19.74.60 bc:24:11:59:85:90
74
dnsmasq-dhcp: DHCPACK(eno1) 172.19.74.60 bc:24:11:59:85:90
75
dnsmasq-dhcp: PXE(eno1) bc:24:11:59:85:90 proxy
76
dnsmasq-dhcp: PXE(eno1) bc:24:11:59:85:90 proxy
77
dnsmasq-dhcp: PXEBS(eno1) bc:24:11:59:85:90 undionly.kpxe
78
dnsmasq-dhcp: PXE(eno1) bc:24:11:59:85:90 proxy
79
dnsmasq-dhcp: PXEBS(eno1) bc:24:11:59:85:90 http://infra1.oneill.net:8081/boot.ipxe
80
81
With 2.92 (broken), the DHCPDISCOVER/OFFER/REQUEST/ACK cycle and the proxy
82
PXE response work, but the PXEBS response never reaches the client it times
83
out after repeated attempts. The dnsmasq side shows it sending the response,
84
but the client keeps retrying:
85
86
dnsmasq-dhcp: PXE(eno1) bc:24:11:59:85:90 proxy
87
dnsmasq-dhcp: PXE(eno1) bc:24:11:59:85:90 proxy
88
dnsmasq-dhcp: PXEBS(eno1) bc:24:11:59:85:90 undionly.kpxe
89
dnsmasq-dhcp: PXEBS(eno1) bc:24:11:59:85:90 undionly.kpxe
90
dnsmasq-dhcp: PXEBS(eno1) bc:24:11:59:85:90 undionly.kpxe
91
dnsmasq-dhcp: PXEBS(eno1) bc:24:11:59:85:90 undionly.kpxe
92
93
I tested by restoring the else keyword and the fix appears to work 2.92 with
94
the patch below PXE boots successfully. I believe this change preserves the
95
leasequery behavior since that path only applies when pxe_fd is false (normal
96
DHCP handling, not port 4011).
97
98
diff --git a/src/dhcp.c b/src/dhcp.c
99
index 6775fb6..efda023 100644
100
--- src/dhcp.c~
101
+++ src/dhcp.c
102
@@ -399,7 +399,7 @@ void dhcp_packet(time_t now, int pxe_fd)
103
if (mess->ciaddr.s_addr != 0)
104
dest.sin_addr = mess->ciaddr;
105
}
106
- if ((is_relay_use_source || mess->giaddr.s_addr) && !is_relay_reply)
107
+ else if ((is_relay_use_source || mess->giaddr.s_addr) && !is_relay_reply)
108
{
109
/* Send to BOOTP relay. */
110
if (is_relay_use_source)
111
112