Hi. On a firewall recently upgraded to 7.0, I noticed that dhcpleased was not getting a reply from my ISP's DHCP server during renewal at T1. At T2, dhcpleased would broadcast the REQUEST which would be answered. Testing with dhclient showed successful renewals at T1.
Inspecting the REQUEST packets showed that dhclient was setting the ciaddr to the existing leased IP address while dhcpleased was not setting this field. RFC 2131 4.3.2 (with a nice summary at 4.3.6) is pretty strict about when ciaddr and the 'requested ip' option should be used. The diff below modifies dhcpleased to set ciaddr and 'requested ip' at the appropriate times. While here, I also noticed that if you configure an interface in dhcpleased.conf but do not use "set client id", dhcpleased will not send the default client id as is stated in dhcpleased.conf(5). Since gmail will undoubtedly muck up this diff, a clean copy is here: www.packetmischief.ca/files/patches/dhcpleased.ciaddr.diff .joel Index: src/sbin/dhcpleased/dhcpleased.h =================================================================== RCS file: /data/cvs-mirror/OpenBSD/src/sbin/dhcpleased/dhcpleased.h,v retrieving revision 1.11 diff -p -u -r1.11 dhcpleased.h --- src/sbin/dhcpleased/dhcpleased.h 12 Aug 2021 12:41:08 -0000 1.11 +++ src/sbin/dhcpleased/dhcpleased.h 16 Nov 2021 04:06:06 -0000 @@ -191,6 +191,18 @@ struct dhcp_route { struct in_addr gw; }; +enum if_state { + IF_DOWN, + IF_INIT, + /* IF_SELECTING, */ + IF_REQUESTING, + IF_BOUND, + IF_RENEWING, + IF_REBINDING, + /* IF_INIT_REBOOT, */ + IF_REBOOTING, +}; + enum imsg_type { IMSG_NONE, #ifndef SMALL @@ -294,6 +306,7 @@ struct imsg_req_discover { }; struct imsg_req_request { + enum if_state if_state; uint32_t if_index; uint32_t xid; struct in_addr requested_ip; Index: src/sbin/dhcpleased/engine.c =================================================================== RCS file: /data/cvs-mirror/OpenBSD/src/sbin/dhcpleased/engine.c,v retrieving revision 1.29 diff -p -u -r1.29 engine.c --- src/sbin/dhcpleased/engine.c 14 Nov 2021 18:13:19 -0000 1.29 +++ src/sbin/dhcpleased/engine.c 16 Nov 2021 04:06:34 -0000 @@ -60,18 +60,6 @@ #define MAX_EXP_BACKOFF_FAST 2 #define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) -enum if_state { - IF_DOWN, - IF_INIT, - /* IF_SELECTING, */ - IF_REQUESTING, - IF_BOUND, - IF_RENEWING, - IF_REBINDING, - /* IF_INIT_REBOOT, */ - IF_REBOOTING, -}; - const char* if_state_name[] = { "Down", "Init", @@ -1485,6 +1473,7 @@ request_dhcp_request(struct dhcpleased_i iface->xid = arc4random(); imsg_req_request.if_index = iface->if_index; + imsg_req_request.if_state = iface->state; imsg_req_request.xid = iface->xid; imsg_req_request.server_identifier.s_addr = iface->server_identifier.s_addr; Index: src/sbin/dhcpleased/frontend.c =================================================================== RCS file: /data/cvs-mirror/OpenBSD/src/sbin/dhcpleased/frontend.c,v retrieving revision 1.23 diff -p -u -r1.23 frontend.c --- src/sbin/dhcpleased/frontend.c 20 Oct 2021 07:04:49 -0000 1.23 +++ src/sbin/dhcpleased/frontend.c 16 Nov 2021 04:14:23 -0000 @@ -74,6 +74,7 @@ struct iface { struct in_addr server_identifier; struct in_addr dhcp_server; int udpsock; + enum if_state state; }; __dead void frontend_shutdown(void); @@ -91,7 +92,7 @@ struct iface *get_iface_by_id(uint32_t); void remove_iface(uint32_t); void set_bpfsock(int, uint32_t); ssize_t build_packet(uint8_t, char *, uint32_t, struct ether_addr *, - struct in_addr *, struct in_addr *); + struct in_addr *, struct in_addr *, enum if_state *); void send_discover(struct iface *); void send_request(struct iface *); void bpf_send_packet(struct iface *, uint8_t *, ssize_t); @@ -511,6 +512,7 @@ frontend_dispatch_engine(int fd, short e imsg_req_request.server_identifier.s_addr; iface->dhcp_server.s_addr = imsg_req_request.dhcp_server.s_addr; + iface->state = imsg_req_request.if_state; send_request(iface); } break; @@ -888,7 +890,7 @@ bpf_receive(int fd, short events, void * ssize_t build_packet(uint8_t message_type, char *if_name, uint32_t xid, struct ether_addr *hw_address, struct in_addr *requested_ip, - struct in_addr *server_identifier) + struct in_addr *server_identifier, enum if_state *if_state) { static uint8_t dhcp_cookie[] = DHCP_COOKIE; static uint8_t dhcp_message_type[] = {DHO_DHCP_MESSAGE_TYPE, 1, @@ -926,6 +928,9 @@ build_packet(uint8_t message_type, char hdr->hops = 0; hdr->xid = xid; hdr->secs = 0; + if (message_type == DHCPREQUEST && (*if_state == IF_RENEWING || + *if_state == IF_REBINDING)) + memcpy(&hdr->ciaddr, requested_ip, sizeof(*requested_ip)); memcpy(hdr->chaddr, hw_address, sizeof(*hw_address)); p += sizeof(struct dhcp_hdr); memcpy(p, dhcp_cookie, sizeof(dhcp_cookie)); @@ -946,6 +951,11 @@ build_packet(uint8_t message_type, char /* XXX check space */ memcpy(p, iface_conf->c_id, iface_conf->c_id_len); p += iface_conf->c_id_len; + } else { + memcpy(dhcp_client_id + 3, hw_address, + sizeof(*hw_address)); + memcpy(p, dhcp_client_id, sizeof(dhcp_client_id)); + p += sizeof(dhcp_client_id); } if (iface_conf->vc_id_len > 0) { /* XXX check space */ @@ -963,11 +973,14 @@ build_packet(uint8_t message_type, char p += sizeof(dhcp_req_list); if (message_type == DHCPREQUEST) { - memcpy(dhcp_requested_address + 2, requested_ip, - sizeof(*requested_ip)); - memcpy(p, dhcp_requested_address, - sizeof(dhcp_requested_address)); - p += sizeof(dhcp_requested_address); + if (*if_state == IF_INIT || *if_state == IF_REBOOTING || + *if_state == IF_REQUESTING) { + memcpy(dhcp_requested_address + 2, requested_ip, + sizeof(*requested_ip)); + memcpy(p, dhcp_requested_address, + sizeof(dhcp_requested_address)); + p += sizeof(dhcp_requested_address); + } if (server_identifier->s_addr != INADDR_ANY) { memcpy(dhcp_server_identifier + 2, server_identifier, @@ -1006,7 +1019,7 @@ send_discover(struct iface *iface) log_debug("DHCPDISCOVER on %s", if_name == NULL ? "?" : if_name); pkt_len = build_packet(DHCPDISCOVER, if_name, iface->xid, - &iface->ifinfo.hw_address, &iface->requested_ip, NULL); + &iface->ifinfo.hw_address, &iface->requested_ip, NULL, NULL); bpf_send_packet(iface, dhcp_packet, pkt_len); } @@ -1021,7 +1034,7 @@ send_request(struct iface *iface) pkt_len = build_packet(DHCPREQUEST, if_name, iface->xid, &iface->ifinfo.hw_address, &iface->requested_ip, - &iface->server_identifier); + &iface->server_identifier, &iface->state); if (iface->dhcp_server.s_addr != INADDR_ANY) { if (udp_send_packet(iface, dhcp_packet, pkt_len) == -1) bpf_send_packet(iface, dhcp_packet, pkt_len);