From 8450fa4a7b9a8236a43b74639fc80bada994ce07 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 3 Feb 2023 19:36:57 +0000 Subject: [dhcp] Ignore DHCPNAK unless originating from the selected DHCP server RFC 2131 leaves undefined the behaviour of the client in response to a DHCPNAK that comes from a server other than the selected DHCP server. A substantial amount of online documentation suggests using multiple independent DHCP servers with non-overlapping ranges in the same subnet in order to provide some minimal redundancy. Experimentation shows that in this setup, at least ISC dhcpd will send a DHCPNAK in response to the client's DHCPREQUEST for an address that is not within the range defined on that server. (Since the requested address does lie within the subnet defined on that server, this will happen regardless of the "authoritative" parameter.) The client will therefore receive a DHCPACK from the selected DHCP server along with one or more DHCPNAKs from each of the non-selected DHCP servers. Filter out responses from non-selected DHCP servers before checking for a DHCPNAK, so that these arguably spurious DHCPNAKs will not cause iPXE to return to the discovery state. Continue to check for DHCPNAK before filtering out responses for non-selected lease addresses, since experimentation shows that the DHCPNAK will usually have an empty yiaddr field. Reported-by: Anders Blomdell Signed-off-by: Michael Brown --- src/net/udp/dhcp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/net/udp/dhcp.c b/src/net/udp/dhcp.c index b7b84e7..a1a481e 100644 --- a/src/net/udp/dhcp.c +++ b/src/net/udp/dhcp.c @@ -571,6 +571,10 @@ static void dhcp_request_rx ( struct dhcp_session *dhcp, if ( peer->sin_port != htons ( BOOTPS_PORT ) ) return; + /* Filter out non-selected servers */ + if ( server_id.s_addr != dhcp->server.s_addr ) + return; + /* Handle DHCPNAK */ if ( msgtype == DHCPNAK ) { dhcp_defer ( dhcp ); @@ -580,8 +584,6 @@ static void dhcp_request_rx ( struct dhcp_session *dhcp, /* Filter out unacceptable responses */ if ( msgtype /* BOOTP */ && ( msgtype != DHCPACK ) ) return; - if ( server_id.s_addr != dhcp->server.s_addr ) - return; if ( ip.s_addr != dhcp->offer.s_addr ) return; -- cgit v1.1