anyone else?
On 2021-12-04 17:26 -07, Joel Knight <knight.j...@gmail.com> wrote: > We have a winner here. I tested from INIT through to REBINDING and the > behavior matches what's in the RFC now. ok joel@ > > One cosmetic thing I noticed this time around: log_dhcp_hdr() in > engine.c should be printing dhcp_hdr->xid in host byte order. > > > > .joel > > On Fri, Dec 3, 2021 at 5:21 AM Florian Obser <flor...@openbsd.org> wrote: >> >> Last one, Joel spotted one more bug in the previous one, I was missing >> an assignment to dhcp_server in the ACK case. >> >> This is a rewrite of the package construction logic to send the correct >> information in the right states: >> >> RFC 2131 4.3.6, Table 4 >> --------------------------------------------------------------------- >> | |REBOOTING |REQUESTING |RENEWING |REBINDING | >> --------------------------------------------------------------------- >> |broad/unicast |broadcast |broadcast |unicast |broadcast | >> |server-ip |MUST NOT |MUST |MUST NOT |MUST NOT | >> |requested-ip |MUST |MUST |MUST NOT |MUST NOT | >> |ciaddr |zero |zero |IP address |IP address| >> --------------------------------------------------------------------- >> >> Previous this logic was all over the place and difficult to check. >> This diff moves it all into the engine.c functions >> request_dhcp_discover() and request_dhcp_request(). >> >> The frontend then leaves out dhcp options that are set to INADDR_ARPA, >> but it does not need to know in which state the engine is. >> >> OK? >> >> >> diff --git dhcpleased.h dhcpleased.h >> index b3b4938ad3c..6df38be6f5b 100644 >> --- dhcpleased.h >> +++ dhcpleased.h >> @@ -287,15 +287,10 @@ struct imsg_dhcp { >> uint8_t packet[1500]; >> }; >> >> - >> -struct imsg_req_discover { >> - uint32_t if_index; >> - uint32_t xid; >> -}; >> - >> -struct imsg_req_request { >> +struct imsg_req_dhcp { >> 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..3169bd80d40 100644 >> --- engine.c >> +++ engine.c >> @@ -1170,6 +1170,7 @@ parse_dhcp(struct dhcpleased_iface *iface, struct >> imsg_dhcp *dhcp) >> return; >> } >> iface->server_identifier.s_addr = server_identifier.s_addr; >> + iface->dhcp_server.s_addr = server_identifier.s_addr; >> iface->requested_ip.s_addr = dhcp_hdr->yiaddr.s_addr; >> state_transition(iface, IF_REQUESTING); >> break; >> @@ -1228,6 +1229,7 @@ parse_dhcp(struct dhcpleased_iface *iface, struct >> imsg_dhcp *dhcp) >> >> clock_gettime(CLOCK_MONOTONIC, &iface->request_time); >> iface->server_identifier.s_addr = server_identifier.s_addr; >> + iface->dhcp_server.s_addr = server_identifier.s_addr; >> iface->requested_ip.s_addr = dhcp_hdr->yiaddr.s_addr; >> iface->mask.s_addr = subnet_mask.s_addr; >> #ifndef SMALL >> @@ -1354,11 +1356,8 @@ state_transition(struct dhcpleased_iface *iface, enum >> if_state new_state) >> case IF_REBOOTING: >> if (old_state == IF_REBOOTING) >> iface->timo.tv_sec *= 2; >> - else { >> - /* make sure we send broadcast */ >> - iface->dhcp_server.s_addr = INADDR_ANY; >> + else >> iface->timo.tv_sec = START_EXP_BACKOFF; >> - } >> request_dhcp_request(iface); >> break; >> case IF_REQUESTING: >> @@ -1377,10 +1376,6 @@ state_transition(struct dhcpleased_iface *iface, enum >> if_state new_state) >> break; >> case IF_RENEWING: >> if (old_state == IF_BOUND) { >> - iface->dhcp_server.s_addr = >> - iface->server_identifier.s_addr; >> - iface->server_identifier.s_addr = INADDR_ANY; >> - >> iface->timo.tv_sec = (iface->rebinding_time - >> iface->renewal_time) / 2; /* RFC 2131 4.4.5 */ >> } else >> @@ -1392,7 +1387,6 @@ state_transition(struct dhcpleased_iface *iface, enum >> if_state new_state) >> break; >> case IF_REBINDING: >> if (old_state == IF_RENEWING) { >> - iface->dhcp_server.s_addr = INADDR_ANY; >> iface->timo.tv_sec = (iface->lease_time - >> iface->rebinding_time) / 2; /* RFC 2131 4.4.5 */ >> } else >> @@ -1470,28 +1464,90 @@ iface_timeout(int fd, short events, void *arg) >> void >> request_dhcp_discover(struct dhcpleased_iface *iface) >> { >> - struct imsg_req_discover imsg_req_discover; >> + struct imsg_req_dhcp imsg; >> >> - imsg_req_discover.if_index = iface->if_index; >> - imsg_req_discover.xid = iface->xid = arc4random(); >> - engine_imsg_compose_frontend(IMSG_SEND_DISCOVER, 0, >> &imsg_req_discover, >> - sizeof(imsg_req_discover)); >> + memset(&imsg, 0, sizeof(imsg)); >> + >> + iface->xid = arc4random(); >> + imsg.if_index = iface->if_index; >> + imsg.xid = iface->xid; >> + >> + /* >> + * similar to RFC 2131 4.3.6, Table 4 for DHCPDISCOVER >> + * ------------------------------ >> + * | | INIT | >> + * ------------------------------ >> + * |broad/unicast | broadcast | >> + * |server-ip | MUST NOT | >> + * |requested-ip | MAY | >> + * |ciaddr | zero | >> + * ------------------------------ >> + * >> + * Leaving everything at 0 from the memset results in this table with >> + * requested-ip not set. >> + */ >> + >> + engine_imsg_compose_frontend(IMSG_SEND_DISCOVER, 0, &imsg, >> sizeof(imsg)); >> } >> >> void >> request_dhcp_request(struct dhcpleased_iface *iface) >> { >> - struct imsg_req_request imsg_req_request; >> + struct imsg_req_dhcp imsg; >> >> iface->xid = arc4random(); >> - imsg_req_request.if_index = iface->if_index; >> - imsg_req_request.xid = iface->xid; >> - imsg_req_request.server_identifier.s_addr = >> - iface->server_identifier.s_addr; >> - imsg_req_request.requested_ip.s_addr = iface->requested_ip.s_addr; >> - imsg_req_request.dhcp_server.s_addr = iface->dhcp_server.s_addr; >> - engine_imsg_compose_frontend(IMSG_SEND_REQUEST, 0, &imsg_req_request, >> - sizeof(imsg_req_request)); >> + imsg.if_index = iface->if_index; >> + imsg.xid = iface->xid; >> + >> + /* >> + * RFC 2131 4.3.6, Table 4 >> + * >> --------------------------------------------------------------------- >> + * | |REBOOTING |REQUESTING |RENEWING >> |REBINDING | >> + * >> --------------------------------------------------------------------- >> + * |broad/unicast |broadcast |broadcast |unicast >> |broadcast | >> + * |server-ip |MUST NOT |MUST |MUST NOT |MUST >> NOT | >> + * |requested-ip |MUST |MUST |MUST NOT |MUST >> NOT | >> + * |ciaddr |zero |zero |IP address |IP >> address| >> + * >> --------------------------------------------------------------------- >> + */ >> + switch (iface->state) { >> + case IF_DOWN: >> + fatalx("invalid state IF_DOWN in %s", __func__); >> + break; >> + case IF_INIT: >> + fatalx("invalid state IF_INIT in %s", __func__); >> + break; >> + case IF_BOUND: >> + fatalx("invalid state IF_BOUND in %s", __func__); >> + break; >> + case IF_REBOOTING: >> + imsg.dhcp_server.s_addr = INADDR_ANY; /* broadcast >> */ >> + imsg.server_identifier.s_addr = INADDR_ANY; /* MUST NOT >> */ >> + imsg.requested_ip = iface->requested_ip; /* MUST */ >> + imsg.ciaddr.s_addr = INADDR_ANY; /* zero */ >> + break; >> + case IF_REQUESTING: >> + imsg.dhcp_server.s_addr = INADDR_ANY; /* broadcast >> */ >> + imsg.server_identifier = >> + iface->server_identifier; /* MUST */ >> + imsg.requested_ip = iface->requested_ip; /* MUST */ >> + imsg.ciaddr.s_addr = INADDR_ANY; /* zero */ >> + break; >> + case IF_RENEWING: >> + imsg.dhcp_server = iface->dhcp_server; /* unicast */ >> + imsg.server_identifier.s_addr = INADDR_ANY; /* MUST NOT >> */ >> + imsg.requested_ip.s_addr = INADDR_ANY; /* MUST NOT >> */ >> + imsg.ciaddr = iface->requested_ip; /* IP >> address */ >> + break; >> + case IF_REBINDING: >> + imsg.dhcp_server.s_addr = INADDR_ANY; /* broadcast >> */ >> + imsg.server_identifier.s_addr = INADDR_ANY; /* MUST NOT >> */ >> + imsg.requested_ip.s_addr = INADDR_ANY; /* MUST NOT >> */ >> + imsg.ciaddr = iface->requested_ip; /* IP >> address */ >> + break; >> + } >> + >> + engine_imsg_compose_frontend(IMSG_SEND_REQUEST, 0, &imsg, >> sizeof(imsg)); >> } >> >> void >> diff --git frontend.c frontend.c >> index bd1e37fe952..e2c626ce5d2 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; >> @@ -90,10 +91,10 @@ int get_xflags(char *); >> struct iface *get_iface_by_id(uint32_t); >> void remove_iface(uint32_t); >> void set_bpfsock(int, uint32_t); >> +void iface_data_from_imsg(struct iface*, struct imsg_req_dhcp *); >> ssize_t build_packet(uint8_t, char *, uint32_t, struct >> ether_addr *, >> - struct in_addr *, struct in_addr *); >> -void send_discover(struct iface *); >> -void send_request(struct iface *); >> + struct in_addr *, struct in_addr *, struct in_addr *); >> +void send_packet(uint8_t, struct iface *); >> void bpf_send_packet(struct iface *, uint8_t *, ssize_t); >> int udp_send_packet(struct iface *, uint8_t *, ssize_t); >> #ifndef SMALL >> @@ -480,39 +481,39 @@ frontend_dispatch_engine(int fd, short event, void >> *bula) >> break; >> #endif /* SMALL */ >> case IMSG_SEND_DISCOVER: { >> - struct imsg_req_discover imsg_req_discover; >> - if (IMSG_DATA_SIZE(imsg) != >> sizeof(imsg_req_discover)) >> + struct imsg_req_dhcp imsg_req_dhcp; >> + if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_req_dhcp)) >> fatalx("%s: IMSG_SEND_DISCOVER wrong " >> "length: %lu", __func__, >> IMSG_DATA_SIZE(imsg)); >> - memcpy(&imsg_req_discover, imsg.data, >> - sizeof(imsg_req_discover)); >> - iface = get_iface_by_id(imsg_req_discover.if_index); >> - if (iface != NULL) { >> - iface->xid = imsg_req_discover.xid; >> - send_discover(iface); >> - } >> + memcpy(&imsg_req_dhcp, imsg.data, >> + sizeof(imsg_req_dhcp)); >> + >> + iface = get_iface_by_id(imsg_req_dhcp.if_index); >> + >> + if (iface == NULL) >> + break; >> + >> + iface_data_from_imsg(iface, &imsg_req_dhcp); >> + send_packet(DHCPDISCOVER, iface); >> break; >> } >> case IMSG_SEND_REQUEST: { >> - struct imsg_req_request imsg_req_request; >> - if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_req_request)) >> + struct imsg_req_dhcp imsg_req_dhcp; >> + if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_req_dhcp)) >> fatalx("%s: IMSG_SEND_REQUEST wrong " >> "length: %lu", __func__, >> IMSG_DATA_SIZE(imsg)); >> - memcpy(&imsg_req_request, imsg.data, >> - sizeof(imsg_req_request)); >> - iface = get_iface_by_id(imsg_req_request.if_index); >> - if (iface != NULL) { >> - iface->xid = imsg_req_request.xid; >> - iface->requested_ip.s_addr = >> - imsg_req_request.requested_ip.s_addr; >> - iface->server_identifier.s_addr = >> - >> imsg_req_request.server_identifier.s_addr; >> - iface->dhcp_server.s_addr = >> - imsg_req_request.dhcp_server.s_addr; >> - send_request(iface); >> - } >> + memcpy(&imsg_req_dhcp, imsg.data, >> + sizeof(imsg_req_dhcp)); >> + >> + iface = get_iface_by_id(imsg_req_dhcp.if_index); >> + >> + if (iface == NULL) >> + break; >> + >> + iface_data_from_imsg(iface, &imsg_req_dhcp); >> + send_packet(DHCPREQUEST, iface); >> break; >> } >> default: >> @@ -885,10 +886,20 @@ bpf_receive(int fd, short events, void *arg) >> } >> } >> >> +void >> +iface_data_from_imsg(struct iface* iface, struct imsg_req_dhcp *imsg) >> +{ >> + iface->xid = imsg->xid; >> + iface->ciaddr.s_addr = imsg->ciaddr.s_addr; >> + iface->requested_ip.s_addr = imsg->requested_ip.s_addr; >> + iface->server_identifier.s_addr = imsg->server_identifier.s_addr; >> + iface->dhcp_server.s_addr = imsg->dhcp_server.s_addr; >> +} >> + >> 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 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; >> static uint8_t dhcp_message_type[] = {DHO_DHCP_MESSAGE_TYPE, 1, >> @@ -926,6 +937,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)); >> @@ -966,20 +978,20 @@ build_packet(uint8_t message_type, char *if_name, >> uint32_t xid, >> memcpy(p, dhcp_req_list, sizeof(dhcp_req_list)); >> p += sizeof(dhcp_req_list); >> >> - if (message_type == DHCPREQUEST) { >> + if (requested_ip->s_addr != INADDR_ANY) { >> 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, >> - sizeof(*server_identifier)); >> - memcpy(p, dhcp_server_identifier, >> - sizeof(dhcp_server_identifier)); >> - p += sizeof(dhcp_server_identifier); >> - } >> + if (server_identifier->s_addr != INADDR_ANY) { >> + memcpy(dhcp_server_identifier + 2, server_identifier, >> + sizeof(*server_identifier)); >> + memcpy(p, dhcp_server_identifier, >> + sizeof(dhcp_server_identifier)); >> + p += sizeof(dhcp_server_identifier); >> } >> >> *p = DHO_END; >> @@ -995,7 +1007,7 @@ build_packet(uint8_t message_type, char *if_name, >> uint32_t xid, >> } >> >> void >> -send_discover(struct iface *iface) >> +send_packet(uint8_t message_type, struct iface *iface) >> { >> ssize_t pkt_len; >> char ifnamebuf[IF_NAMESIZE], *if_name; >> @@ -1004,27 +1016,17 @@ send_discover(struct iface *iface) >> iface->send_discover = 1; >> return; >> } >> - iface->send_discover = 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); >> - bpf_send_packet(iface, dhcp_packet, pkt_len); >> -} >> + iface->send_discover = 0; >> >> -void >> -send_request(struct iface *iface) >> -{ >> - ssize_t pkt_len; >> - char ifnamebuf[IF_NAMESIZE], *if_name; >> + if ((if_name = if_indextoname(iface->ifinfo.if_index, ifnamebuf)) == >> NULL) >> + return; /* iface went away, nothing to do */ >> >> - if_name = if_indextoname(iface->ifinfo.if_index, ifnamebuf); >> - log_debug("DHCPREQUEST on %s", if_name == NULL ? "?" : if_name); >> + log_debug("%s on %s", message_type == DHCPDISCOVER ? "DHCPDISCOVER" : >> + "DHCPREQUEST", if_name); >> >> - pkt_len = build_packet(DHCPREQUEST, if_name, iface->xid, >> - &iface->ifinfo.hw_address, &iface->requested_ip, >> + pkt_len = build_packet(message_type, if_name, iface->xid, >> + &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) >> @@ -1162,7 +1164,7 @@ set_bpfsock(int bpfsock, uint32_t if_index) >> EV_PERSIST, bpf_receive, iface); >> event_add(&iface->bpfev.ev, NULL); >> if (iface->send_discover) >> - send_discover(iface); >> + send_packet(DHCPDISCOVER, iface); >> } >> } >> >> >> >> -- >> I'm not entirely sure you are real. >> > -- I'm not entirely sure you are real.