On 2021-11-16 09:56 -07, Joel Knight <knight.j...@gmail.com> wrote: > 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.
Nice catch. I'd like to solve it a bit differently. The frontend process should not need to know about protocol state specifics. The idea is that the engine process tells it to send a packet and that's it. We are doing the same thing with server_identifier when we transition to RENEWING, that is, we are setting it to INADDR_ANY so that the frontend doesn't send it out. (Unfortunately send_discover() in the frontend needs to know to clear ciaddr. Maybe a bit of refactoring is in order. Also build_packet's signature gets a bit out of hand. We should probably just pass in an interface pointer and be done with it.) > > 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). One problem at a time, I'll extract this out in a bit. > > Since gmail will undoubtedly muck up this diff, a clean copy is here: > www.packetmischief.ca/files/patches/dhcpleased.ciaddr.diff > > > .joel > Does this work for you? diff --git dhcpleased.h dhcpleased.h index b3b4938ad3c..d209d50a246 100644 --- dhcpleased.h +++ dhcpleased.h @@ -296,6 +296,7 @@ struct imsg_req_discover { struct imsg_req_request { uint32_t if_index; uint32_t xid; + struct in_addr ciaddr; struct in_addr requested_ip; struct in_addr server_identifier; struct in_addr dhcp_server; diff --git engine.c engine.c index 17e65fbe789..3abae44afa4 100644 --- engine.c +++ engine.c @@ -1486,6 +1486,10 @@ request_dhcp_request(struct dhcpleased_iface *iface) iface->xid = arc4random(); imsg_req_request.if_index = iface->if_index; imsg_req_request.xid = iface->xid; + if (iface->state == IF_RENEWING || iface->state == IF_REBINDING) + imsg_req_request.ciaddr.s_addr = iface->requested_ip.s_addr; + else + imsg_req_request.ciaddr.s_addr = 0; imsg_req_request.server_identifier.s_addr = iface->server_identifier.s_addr; imsg_req_request.requested_ip.s_addr = iface->requested_ip.s_addr; diff --git frontend.c frontend.c index 5131dce1471..e4b2419c96a 100644 --- frontend.c +++ frontend.c @@ -70,6 +70,7 @@ struct iface { struct imsg_ifinfo ifinfo; int send_discover; uint32_t xid; + struct in_addr ciaddr; struct in_addr requested_ip; struct in_addr server_identifier; struct in_addr dhcp_server; @@ -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 *, struct in_addr *); void send_discover(struct iface *); void send_request(struct iface *); void bpf_send_packet(struct iface *, uint8_t *, ssize_t); @@ -505,6 +506,7 @@ frontend_dispatch_engine(int fd, short event, void *bula) iface = get_iface_by_id(imsg_req_request.if_index); if (iface != NULL) { iface->xid = imsg_req_request.xid; + iface->ciaddr.s_addr = imsg_req_request.ciaddr.s_addr; iface->requested_ip.s_addr = imsg_req_request.requested_ip.s_addr; iface->server_identifier.s_addr = @@ -887,7 +889,7 @@ bpf_receive(int fd, short events, void *arg) 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 ether_addr *hw_address, struct in_addr *ciaddr, struct in_addr *requested_ip, struct in_addr *server_identifier) { static uint8_t dhcp_cookie[] = DHCP_COOKIE; @@ -926,6 +928,7 @@ build_packet(uint8_t message_type, char *if_name, uint32_t xid, hdr->hops = 0; hdr->xid = xid; hdr->secs = 0; + hdr->ciaddr.s_addr = ciaddr->s_addr; memcpy(hdr->chaddr, hw_address, sizeof(*hw_address)); p += sizeof(struct dhcp_hdr); memcpy(p, dhcp_cookie, sizeof(dhcp_cookie)); @@ -1001,12 +1004,13 @@ send_discover(struct iface *iface) return; } iface->send_discover = 0; + iface->ciaddr.s_addr = 0; if_name = if_indextoname(iface->ifinfo.if_index, ifnamebuf); 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->ciaddr, &iface->requested_ip, NULL); bpf_send_packet(iface, dhcp_packet, pkt_len); } @@ -1020,7 +1024,7 @@ send_request(struct iface *iface) log_debug("DHCPREQUEST on %s", if_name == NULL ? "?" : if_name); pkt_len = build_packet(DHCPREQUEST, if_name, iface->xid, - &iface->ifinfo.hw_address, &iface->requested_ip, + &iface->ifinfo.hw_address, &iface->ciaddr, &iface->requested_ip, &iface->server_identifier); if (iface->dhcp_server.s_addr != INADDR_ANY) { if (udp_send_packet(iface, dhcp_packet, pkt_len) == -1) -- I'm not entirely sure you are real.