Bug #17038
opendhcrelay false positive "bad IP checksums" log spam on systems using hardware TX checksum offloading
0%
Description
Product / Environment Details
Hardware: Netgate 6100
OS Version: pfSense Plus 26.07-RELEASE
Interfaces / Drivers: Intel ix, utilizing 802.1Q tagged VLANs. Upstream DHCP Server: External Kea DHCP cluster (10.10.40.20 / 10.10.40.21) hosted on a server VLAN 40.
Problem Description
When pfSense Plus is configured with DHCP Relay enabled on client-facing VLANs, the system log is periodically flooded with the following warning message at regular intervals (correlating to client DHCP request intervals):
dhcrelay[82197]: 4 bad IP checksums seen in 7 packets
This behavior occurs regardless of the physical link being healthy (dev.ix.2.mac_stats.crc_errs: 0). Client devices are successfully acquiring leases, and hardware TX checksum offloading is enabled.
Analysis
1. Automated upstream flag generation: When a user configures DHCP Relay for client-facing interfaces (e.g., VLAN 20), the pfSense PHP backend automatically appends an upstream interface argument (-i ix0.40) matching the subnet of the destination DHCP servers. This forces the ISC dhcrelay daemon to open a raw Berkeley Packet Filter (bpf) socket on the server VLAN interface to listen for incoming unicast replies from the server.
2. TX offload loopback reflection: When a client request arrives, dhcrelay duplicates and forwards the unicast packet out towards the Kea servers via the server VLAN (ix0.40). Because hardware TX checksum offloading (TXCSUM) is enabled on the Intel interface, the FreeBSD kernel leaves a placeholder value of 0 in the outbound IP header checksum field, intending for the Intel physical chipset to calculate it on egress.
3. Hardcoded mathematical validation: Because dhcrelay maintains a raw bpf sniffing socket on ix0.40, it intercepts its own outbound frames inside kernel memory before they reach the physical layer. The ISC dhcrelay source code (common/packet.c -> decode_udp_ip_header()) performs a manual, hardcoded software calculation on incoming buffers. It reads the unpopulated 0 placeholder value, interprets it as a malformed header, and increments the false-positive warning counter.
Evidence
1. Runtime arguments configuration
Inspecting the process tree reveals that dhcrelay is forced to listen on the server-facing VLAN (-i ix0.40), which sets up the loopback intercept:
/usr/local/sbin/dhcrelay -id ix0.10 -id ix0.20 -id ix0.100 -id ix0.30 -id ix0.50 -i ix0.40 10.10.40.20 10.10.40.21
2. Captured tcpdump
A raw, unbuffered packet capture explicitly catches the Netgate interface (10.10.40.254) emitting the zeroed-out checksums (bad cksum 0) as it attempts to forward requests to the Kea servers (10.10.40.20 and 10.10.40.21):
20:45:47.226508 IP (tos 0x0, ttl 64, id 15015, offset 0, flags [none], proto UDP (17), length 330, bad cksum 0 (->d9d5)!)
10.10.40.254.67 > 10.10.40.21.67: BOOTP/DHCP, Request from 94:45:60:a9:64:d7, length 302, hops 1, xid 0x725216c0, Flags [none]
Client-IP 10.10.20.55
Gateway-IP 10.10.20.254
20:45:47.226554 IP (tos 0x0, ttl 64, id 63167, offset 0, flags [none], proto UDP (17), length 330, bad cksum 0 (->1dbe)!)
10.10.40.254.67 > 10.10.40.20.67: BOOTP/DHCP, Request from 94:45:60:a9:64:d7, length 302, hops 1, xid 0x725216c0, Flags [none]
Note that the number of outbound frames generated with a placeholder 0 (4 packets) matches the exact log error line (4 bad IP checksums seen).
No data to display
Also available in: Atom