From 386784657453900881c4ac99db2983a95e876203 Mon Sep 17 00:00:00 2001 From: Paul Donald Date: Fri, 19 Dec 2025 03:26:11 +0100 Subject: [PATCH 1/4] dhcpv6: set static defines for DHCPv6 option header size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit so the number 4 isn't so mysterious at first glance. (cherry picked from commit 5a13d875ac71d52a221515a30d21916ed4976126) Signed-off-by: Paul Donald Link: https://github.com/openwrt/odhcpd/pull/363 Signed-off-by: Álvaro Fernández Rojas --- src/dhcpv6-ia.c | 44 ++++++++++++++++++++++---------------------- src/dhcpv6.c | 4 ++-- src/odhcpd.h | 2 ++ 3 files changed, 26 insertions(+), 24 deletions(-) diff --git a/src/dhcpv6-ia.c b/src/dhcpv6-ia.c index d1881ee5..4747151e 100644 --- a/src/dhcpv6-ia.c +++ b/src/dhcpv6-ia.c @@ -587,14 +587,14 @@ static size_t build_ia(uint8_t *buf, size_t buflen, uint16_t status, uint16_t val; } o_status = { .type = htons(DHCPV6_OPT_STATUS), - .len = htons(sizeof(o_status) - 4), + .len = htons(sizeof(o_status) - DHCPV6_OPT_HDR_SIZE), .val = htons(status), }; memcpy(buf + ia_len, &o_status, sizeof(o_status)); ia_len += sizeof(o_status); - o_ia.len = htons(ia_len - 4); + o_ia.len = htons(ia_len - DHCPV6_OPT_HDR_SIZE); memcpy(buf, &o_ia, sizeof(o_ia)); return ia_len; @@ -668,7 +668,7 @@ static size_t build_ia(uint8_t *buf, size_t buflen, uint16_t status, if (a->flags & OAF_DHCPV6_PD) { struct dhcpv6_ia_prefix o_ia_p = { .type = htons(DHCPV6_OPT_IA_PREFIX), - .len = htons(sizeof(o_ia_p) - 4), + .len = htons(sizeof(o_ia_p) - DHCPV6_OPT_HDR_SIZE), .preferred_lt = htonl(prefix_preferred_lt), .valid_lt = htonl(prefix_valid_lt), .prefix_len = a->length, @@ -691,7 +691,7 @@ static size_t build_ia(uint8_t *buf, size_t buflen, uint16_t status, if (a->flags & OAF_DHCPV6_NA) { struct dhcpv6_ia_addr o_ia_a = { .type = htons(DHCPV6_OPT_IA_ADDR), - .len = htons(sizeof(o_ia_a) - 4), + .len = htons(sizeof(o_ia_a) - DHCPV6_OPT_HDR_SIZE), .addr = in6_from_prefix_and_iid(&addrs[i], a->assigned_host_id), .preferred_lt = htonl(prefix_preferred_lt), .valid_lt = htonl(prefix_valid_lt) @@ -736,16 +736,16 @@ static size_t build_ia(uint8_t *buf, size_t buflen, uint16_t status, } if (!request) { - uint8_t *odata, *end = ((uint8_t*)ia) + htons(ia->len) + 4; + uint8_t *odata, *end = ((uint8_t*)ia) + htons(ia->len) + DHCPV6_OPT_HDR_SIZE; uint16_t otype, olen; dhcpv6_for_each_option((uint8_t*)&ia[1], end, otype, olen, odata) { - struct dhcpv6_ia_prefix *ia_p = (struct dhcpv6_ia_prefix *)&odata[-4]; - struct dhcpv6_ia_addr *ia_a = (struct dhcpv6_ia_addr *)&odata[-4]; + struct dhcpv6_ia_prefix *ia_p = (struct dhcpv6_ia_prefix *)&odata[-DHCPV6_OPT_HDR_SIZE]; + struct dhcpv6_ia_addr *ia_a = (struct dhcpv6_ia_addr *)&odata[-DHCPV6_OPT_HDR_SIZE]; bool found = false; - if ((otype != DHCPV6_OPT_IA_PREFIX || olen < sizeof(*ia_p) - 4) && - (otype != DHCPV6_OPT_IA_ADDR || olen < sizeof(*ia_a) - 4)) + if ((otype != DHCPV6_OPT_IA_PREFIX || olen < sizeof(*ia_p) - DHCPV6_OPT_HDR_SIZE) && + (otype != DHCPV6_OPT_IA_ADDR || olen < sizeof(*ia_a) - DHCPV6_OPT_HDR_SIZE)) continue; if (a) { @@ -785,7 +785,7 @@ static size_t build_ia(uint8_t *buf, size_t buflen, uint16_t status, if (otype == DHCPV6_OPT_IA_PREFIX) { struct dhcpv6_ia_prefix o_ia_p = { .type = htons(DHCPV6_OPT_IA_PREFIX), - .len = htons(sizeof(o_ia_p) - 4), + .len = htons(sizeof(o_ia_p) - DHCPV6_OPT_HDR_SIZE), .preferred_lt = 0, .valid_lt = 0, .prefix_len = ia_p->prefix_len, @@ -800,7 +800,7 @@ static size_t build_ia(uint8_t *buf, size_t buflen, uint16_t status, } else { struct dhcpv6_ia_addr o_ia_a = { .type = htons(DHCPV6_OPT_IA_ADDR), - .len = htons(sizeof(o_ia_a) - 4), + .len = htons(sizeof(o_ia_a) - DHCPV6_OPT_HDR_SIZE), .addr = ia_a->addr, .preferred_lt = 0, .valid_lt = 0, @@ -816,7 +816,7 @@ static size_t build_ia(uint8_t *buf, size_t buflen, uint16_t status, } } - o_ia.len = htons(ia_len - 4); + o_ia.len = htons(ia_len - DHCPV6_OPT_HDR_SIZE); memcpy(buf, &o_ia, sizeof(o_ia)); return ia_len; } @@ -906,16 +906,16 @@ static bool dhcpv6_ia_on_link(const struct dhcpv6_ia_hdr *ia, struct dhcpv6_leas struct odhcpd_ipaddr *addrs = iface->addr6; size_t addrlen = iface->addr6_len; time_t now = odhcpd_time(); - uint8_t *odata, *end = ((uint8_t*)ia) + htons(ia->len) + 4; + uint8_t *odata, *end = ((uint8_t*)ia) + htons(ia->len) + DHCPV6_OPT_HDR_SIZE; uint16_t otype, olen; bool onlink = true; dhcpv6_for_each_option((uint8_t*)&ia[1], end, otype, olen, odata) { - struct dhcpv6_ia_prefix *p = (struct dhcpv6_ia_prefix *)&odata[-4]; - struct dhcpv6_ia_addr *n = (struct dhcpv6_ia_addr *)&odata[-4]; + struct dhcpv6_ia_prefix *p = (struct dhcpv6_ia_prefix *)&odata[-DHCPV6_OPT_HDR_SIZE]; + struct dhcpv6_ia_addr *n = (struct dhcpv6_ia_addr *)&odata[-DHCPV6_OPT_HDR_SIZE]; - if ((otype != DHCPV6_OPT_IA_PREFIX || olen < sizeof(*p) - 4) && - (otype != DHCPV6_OPT_IA_ADDR || olen < sizeof(*n) - 4)) + if ((otype != DHCPV6_OPT_IA_PREFIX || olen < sizeof(*p) - DHCPV6_OPT_HDR_SIZE) && + (otype != DHCPV6_OPT_IA_ADDR || olen < sizeof(*n) - DHCPV6_OPT_HDR_SIZE)) continue; onlink = false; @@ -992,7 +992,7 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac if (!is_pd && !is_na) continue; - struct dhcpv6_ia_hdr *ia = (struct dhcpv6_ia_hdr*)&odata[-4]; + struct dhcpv6_ia_hdr *ia = (struct dhcpv6_ia_hdr*)&odata[-DHCPV6_OPT_HDR_SIZE]; size_t ia_response_len = 0; uint8_t reqlen = (is_pd) ? 62 : 128; uint32_t reqhint = 0; @@ -1010,10 +1010,10 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac uint8_t *sdata; uint16_t stype, slen; dhcpv6_for_each_sub_option(&ia[1], odata + olen, stype, slen, sdata) { - if (stype != DHCPV6_OPT_IA_PREFIX || slen < sizeof(struct dhcpv6_ia_prefix) - 4) + if (stype != DHCPV6_OPT_IA_PREFIX || slen < sizeof(struct dhcpv6_ia_prefix) - DHCPV6_OPT_HDR_SIZE) continue; - struct dhcpv6_ia_prefix *p = (struct dhcpv6_ia_prefix*)&sdata[-4]; + struct dhcpv6_ia_prefix *p = (struct dhcpv6_ia_prefix*)&sdata[-DHCPV6_OPT_HDR_SIZE]; if (p->prefix_len) { reqlen = p->prefix_len; reqhint = ntohl(p->addr.s6_addr32[1]); @@ -1053,7 +1053,7 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac uint8_t *sdata; uint16_t stype, slen; dhcpv6_for_each_sub_option(&ia[1], odata + olen, stype, slen, sdata) { - if (stype != DHCPV6_OPT_IA_ADDR || slen < sizeof(struct dhcpv6_ia_addr) - 4) + if (stype != DHCPV6_OPT_IA_ADDR || slen < sizeof(struct dhcpv6_ia_addr) - DHCPV6_OPT_HDR_SIZE) continue; ia_addr_present = true; @@ -1211,7 +1211,7 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac if (hdr->msg_type == DHCPV6_MSG_REQUEST) { struct dhcpv6_auth_reconfigure auth = { htons(DHCPV6_OPT_AUTH), - htons(sizeof(auth) - 4), + htons(sizeof(auth) - DHCPV6_OPT_HDR_SIZE), 3, 1, 0, {htonl(time(NULL)), htonl(++serial)}, 1, diff --git a/src/dhcpv6.c b/src/dhcpv6.c index 9d32e6b0..a211b259 100644 --- a/src/dhcpv6.c +++ b/src/dhcpv6.c @@ -400,7 +400,7 @@ static void handle_client_request(void *addr, void *data, size_t len, uint16_t type; uint16_t len; uint32_t value; - } maxrt = {htons(DHCPV6_OPT_SOL_MAX_RT), htons(sizeof(maxrt) - 4), + } maxrt = {htons(DHCPV6_OPT_SOL_MAX_RT), htons(sizeof(maxrt) - DHCPV6_OPT_HDR_SIZE), htonl(60)}; struct _o_packed { @@ -412,7 +412,7 @@ static void handle_client_request(void *addr, void *data, size_t len, uint16_t type; uint16_t len; uint16_t value; - } stat = {htons(DHCPV6_OPT_STATUS), htons(sizeof(stat) - 4), + } stat = {htons(DHCPV6_OPT_STATUS), htons(sizeof(stat) - DHCPV6_OPT_HDR_SIZE), htons(DHCPV6_STATUS_USEMULTICAST)}; struct _o_packed { diff --git a/src/odhcpd.h b/src/odhcpd.h index f005909b..9298d62a 100644 --- a/src/odhcpd.h +++ b/src/odhcpd.h @@ -194,6 +194,8 @@ enum odhcpd_assignment_flags { OAF_DHCPV6_PD = (1 << 1), }; +#define DHCPV6_OPT_HDR_SIZE 4 + /* 2-byte type + 128-byte DUID, RFC8415, §11.1 */ #define DUID_MAX_LEN 130 /* In theory, 2 (type only), or 7 (DUID-EN + 1-byte data), but be reasonable */ From e282a3c7e3f765d2fc3dcbd6a976c75880fcab14 Mon Sep 17 00:00:00 2001 From: Paul Donald Date: Mon, 22 Dec 2025 14:44:58 +0100 Subject: [PATCH 2/4] dhcpv6-ia: switch case refactor in dhcpv6_handle_ias() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rewrite core logic using switch cases for clarity and improved performance. This also simplifies the DHCPV6_MSG_REBIND cases: DHCPV6_MSG_REBIND and !a is parsed in the switch DHCPV6_MSG_REBIND and a is now parsed after the switch (5 lines) (cherry picked from commit 9857adb8ac999742836e5c30e75da9aad34a4ba9) Signed-off-by: Paul Donald https://github.com/openwrt/odhcpd/pull/360 Signed-off-by: Álvaro Fernández Rojas --- src/dhcpv6-ia.c | 203 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 139 insertions(+), 64 deletions(-) diff --git a/src/dhcpv6-ia.c b/src/dhcpv6-ia.c index 4747151e..3366bd09 100644 --- a/src/dhcpv6-ia.c +++ b/src/dhcpv6-ia.c @@ -958,7 +958,8 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac char duidbuf[DUID_HEXSTRLEN], hostname[256]; dhcpv6_for_each_option(start, end, otype, olen, odata) { - if (otype == DHCPV6_OPT_CLIENTID) { + switch (otype) { + case DHCPV6_OPT_CLIENTID: duid = odata; duid_len = olen; @@ -969,17 +970,33 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac if (olen <= DUID_MAX_LEN) odhcpd_hexlify(duidbuf, odata, olen); - } else if (otype == DHCPV6_OPT_FQDN && olen >= 2 && olen <= 255) { + break; + + case DHCPV6_OPT_FQDN: + if (olen < 2 || olen > 255) + break; + uint8_t fqdn_buf[256]; memcpy(fqdn_buf, odata, olen); fqdn_buf[olen++] = 0; if (dn_expand(&fqdn_buf[1], &fqdn_buf[olen], &fqdn_buf[1], hostname, sizeof(hostname)) > 0) hostname_len = strcspn(hostname, "."); - } else if (otype == DHCPV6_OPT_RECONF_ACCEPT) + + break; + + case DHCPV6_OPT_RECONF_ACCEPT: accept_reconf = true; - else if (otype == DHCPV6_OPT_RAPID_COMMIT && hdr->msg_type == DHCPV6_MSG_SOLICIT) - rapid_commit = true; + break; + + case DHCPV6_OPT_RAPID_COMMIT: + if (hdr->msg_type == DHCPV6_MSG_SOLICIT) + rapid_commit = true; + break; + + default: + break; + } } if (!duid || duid_len < DUID_MIN_LEN || duid_len > DUID_MAX_LEN) @@ -1095,8 +1112,8 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac * If there's a DUID configured for this static lease, but without * an IAID, we will proceed under the assumption that a request * with the right DUID but with *any* IAID should be able to take - * over the assignment. E.g. when switching from WiFi to ethernet - * on the same client. This is similar to how multiple MAC adresses + * over the assignment. E.g. when switching from WiFi to Ethernet + * on the same client. This is similar to how multiple MAC addresses * are handled for DHCPv4. */ for (size_t i = 0; i < lease_cfg->duid_count; i++) { @@ -1139,11 +1156,16 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac proceed: /* Generic message handling */ uint16_t status = DHCPV6_STATUS_OK; + bool assigned = false; - if (hdr->msg_type == DHCPV6_MSG_SOLICIT || - hdr->msg_type == DHCPV6_MSG_REQUEST || - (hdr->msg_type == DHCPV6_MSG_REBIND && !a)) { - bool assigned = !!a; + switch (hdr->msg_type) { + case DHCPV6_MSG_SOLICIT: + case DHCPV6_MSG_REQUEST: + case DHCPV6_MSG_REBIND: { + if (hdr->msg_type == DHCPV6_MSG_REBIND && a) + break; + + assigned = (a != NULL); if (!a) { if ((!iface->no_dynamic_dhcp || (lease_cfg && is_na)) && @@ -1157,25 +1179,27 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac a->iaid = ia->iaid; a->length = reqlen; a->peer = *addr; + a->iface = iface; + a->flags = is_pd ? OAF_DHCPV6_PD : OAF_DHCPV6_NA; + a->valid_until = now; + a->preferred_until = now; + if (is_na) a->assigned_host_id = lease_cfg ? lease_cfg->hostid : 0; else a->assigned_subnet_id = reqhint; - a->valid_until = now; - a->preferred_until = now; - a->iface = iface; - a->flags = (is_pd ? OAF_DHCPV6_PD : OAF_DHCPV6_NA); if (first) memcpy(a->key, first->key, sizeof(a->key)); else odhcpd_urandom(a->key, sizeof(a->key)); - if (is_pd && iface->dhcpv6_pd) + if (is_pd && iface->dhcpv6_pd) { while (!(assigned = assign_pd(iface, a)) && ++a->length <= 64); - else if (is_na && iface->dhcpv6_na) + } else if (is_na && iface->dhcpv6_na) { assigned = assign_na(iface, a); + } if (lease_cfg && assigned) { if (lease_cfg->hostname) { @@ -1193,15 +1217,20 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac } } - if (!assigned || iface->addr6_len == 0) + /* Status evaluation */ + if (!assigned || iface->addr6_len == 0) { /* Set error status */ - status = (is_pd) ? DHCPV6_STATUS_NOPREFIXAVAIL : DHCPV6_STATUS_NOADDRSAVAIL; - else if (hdr->msg_type == DHCPV6_MSG_REQUEST && !dhcpv6_ia_on_link(ia, a, iface)) { + status = is_pd ? DHCPV6_STATUS_NOPREFIXAVAIL : DHCPV6_STATUS_NOADDRSAVAIL; + } else if (hdr->msg_type == DHCPV6_MSG_REQUEST && !dhcpv6_ia_on_link(ia, a, iface)) { /* Send NOTONLINK status for the IA */ status = DHCPV6_STATUS_NOTONLINK; assigned = false; - } else if (accept_reconf && assigned && !first && - hdr->msg_type != DHCPV6_MSG_REBIND) { + } + + /* Reconfigure Accept */ + if (accept_reconf && assigned && !first && + hdr->msg_type != DHCPV6_MSG_REBIND) { + size_t handshake_len = 4; buf[0] = 0; buf[1] = DHCPV6_OPT_RECONF_ACCEPT; @@ -1217,12 +1246,12 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac 1, {0} }; + memcpy(auth.key, a->key, sizeof(a->key)); memcpy(buf + handshake_len, &auth, sizeof(auth)); handshake_len += sizeof(auth); } - buf += handshake_len; buflen -= handshake_len; response_len += handshake_len; @@ -1230,61 +1259,97 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac first = a; } - ia_response_len = build_ia(buf, buflen, status, ia, a, iface, - hdr->msg_type == DHCPV6_MSG_REBIND ? false : true); + ia_response_len = build_ia( + buf, buflen, status, ia, a, iface, + hdr->msg_type != DHCPV6_MSG_REBIND); /* Was only a solicitation: mark binding for removal in 60 seconds */ - if (assigned && hdr->msg_type == DHCPV6_MSG_SOLICIT && !rapid_commit) { - a->bound = false; - a->valid_until = now + 60; - - } else if (assigned && - ((hdr->msg_type == DHCPV6_MSG_SOLICIT && rapid_commit) || - hdr->msg_type == DHCPV6_MSG_REQUEST || - hdr->msg_type == DHCPV6_MSG_REBIND)) { - if (hostname_len > 0 && (!a->lease_cfg || !a->lease_cfg->hostname)) { - char *tmp = realloc(a->hostname, hostname_len + 1); - if (tmp) { - a->hostname = tmp; - memcpy(a->hostname, hostname, hostname_len); - a->hostname[hostname_len] = 0; - a->hostname_valid = odhcpd_hostname_valid(a->hostname); + if (assigned) { + switch (hdr->msg_type) { + case DHCPV6_MSG_SOLICIT: + if (!rapid_commit) { + a->bound = false; + a->valid_until = now + 60; + break; + } + + _o_fallthrough; + case DHCPV6_MSG_REQUEST: + case DHCPV6_MSG_REBIND: + if (hostname_len > 0 && (!a->lease_cfg || !a->lease_cfg->hostname)) { + + char *tmp = realloc(a->hostname, hostname_len + 1); + if (tmp) { + a->hostname = tmp; + memcpy(a->hostname, hostname, hostname_len); + a->hostname[hostname_len] = 0; + a->hostname_valid = odhcpd_hostname_valid(a->hostname); + } } + + a->accept_fr_nonce = accept_reconf; + a->bound = true; + apply_lease(a, true); + break; + + default: + break; } - a->accept_fr_nonce = accept_reconf; - a->bound = true; - apply_lease(a, true); - } else if (!assigned) { - /* Cleanup failed assignment */ + } else { + /* Clean up failed assignment */ dhcpv6_free_lease(a); a = NULL; } - } else if (hdr->msg_type == DHCPV6_MSG_RENEW || - hdr->msg_type == DHCPV6_MSG_RELEASE || - hdr->msg_type == DHCPV6_MSG_REBIND || - hdr->msg_type == DHCPV6_MSG_DECLINE) { - if (!a && hdr->msg_type != DHCPV6_MSG_REBIND) { + + break; + } + + case DHCPV6_MSG_RENEW: + case DHCPV6_MSG_RELEASE: + case DHCPV6_MSG_DECLINE: { + /* RENEW / RELEASE / DECLINE require an existing binding */ + if (!a) { status = DHCPV6_STATUS_NOBINDING; ia_response_len = build_ia(buf, buflen, status, ia, a, iface, false); - } else if (hdr->msg_type == DHCPV6_MSG_RENEW || - hdr->msg_type == DHCPV6_MSG_REBIND) { + break; + } + + switch (hdr->msg_type) { + case DHCPV6_MSG_RENEW: ia_response_len = build_ia(buf, buflen, status, ia, a, iface, false); - if (a) { - a->bound = true; - apply_lease(a, true); - } - } else if (hdr->msg_type == DHCPV6_MSG_RELEASE) { + + a->bound = true; + apply_lease(a, true); + break; + + case DHCPV6_MSG_RELEASE: + /* Immediately expire the lease */ a->valid_until = now - 1; - } else if ((a->flags & OAF_DHCPV6_NA) && hdr->msg_type == DHCPV6_MSG_DECLINE) { + break; + + case DHCPV6_MSG_DECLINE: + /* DECLINE only applies to non-temporary addresses */ + if (!(a->flags & OAF_DHCPV6_NA)) + break; + a->bound = false; - if (!a->lease_cfg || a->lease_cfg->hostid != a->assigned_host_id) { - memset(a->duid, 0, a->duid_len); - a->valid_until = now + 3600; /* Block address for 1h */ - } else + if (a->lease_cfg && + a->lease_cfg->hostid == a->assigned_host_id) { + /* Static lease: release immediately */ a->valid_until = now - 1; + } else { + /* Dynamic lease: block address for 1 hour */ + memset(a->duid, 0, a->duid_len); + a->valid_until = now + 3600; + } + break; } - } else if (hdr->msg_type == DHCPV6_MSG_CONFIRM) { + + break; + } + + case DHCPV6_MSG_CONFIRM: if (ia_addr_present && !dhcpv6_ia_on_link(ia, a, iface)) { notonlink = true; break; @@ -1294,13 +1359,23 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac response_len = 0; goto out; } + break; + + default: + break; + } + + if (hdr->msg_type == DHCPV6_MSG_REBIND && a) { + ia_response_len = build_ia(buf, buflen, status, ia, a, iface, false); + a->bound = true; + apply_lease(a, true); } buf += ia_response_len; buflen -= ia_response_len; response_len += ia_response_len; dhcpv6_log(hdr->msg_type, iface, now, duidbuf, is_pd, a, status); - } + } /* end dhcpv6_for_each_option */ switch (hdr->msg_type) { case DHCPV6_MSG_RELEASE: From 90929d9d2c78e76cd9ef0612ca13bc80f52117e1 Mon Sep 17 00:00:00 2001 From: Paul Donald Date: Tue, 30 Dec 2025 16:13:29 +0100 Subject: [PATCH 3/4] netlink: clean up sockets, close files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sockets are handled for most usage paths, except for shutdown. Handle those at shutdown. (cherry picked from commit 3cbbea830ddd1d9e55a5ba77b49bacbac0257685) Signed-off-by: Paul Donald Link: https://github.com/openwrt/odhcpd/pull/367 Signed-off-by: Álvaro Fernández Rojas --- src/netlink.c | 36 ++++++++++++++++++++++++++---------- src/router.c | 17 +++++++++++++---- 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/src/netlink.c b/src/netlink.c index d58e4527..24734769 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -53,6 +53,29 @@ static struct event_socket rtnl_event = { .sock_bufsize = 133120, }; +/* Shut down and free netlink sockets/registration. Safe to call multiple times. */ +static void netlink_shutdown(void) +{ + /* Deregister event and free the event socket */ + if (rtnl_event.sock) { + odhcpd_deregister(&rtnl_event.ev); + + if (rtnl_event.ev.uloop.fd >= 0) { + close(rtnl_event.ev.uloop.fd); + rtnl_event.ev.uloop.fd = -1; + } + + nl_socket_free(rtnl_event.sock); + rtnl_event.sock = NULL; + } + + /* Free the primary rtnl socket */ + if (rtnl_socket) { + nl_socket_free(rtnl_socket); + rtnl_socket = NULL; + } +} + int netlink_init(void) { rtnl_socket = create_socket(NETLINK_ROUTE); @@ -85,19 +108,12 @@ int netlink_init(void) odhcpd_register(&rtnl_event.ev); + atexit(netlink_shutdown); + return 0; err: - if (rtnl_socket) { - nl_socket_free(rtnl_socket); - rtnl_socket = NULL; - } - - if (rtnl_event.sock) { - nl_socket_free(rtnl_event.sock); - rtnl_event.sock = NULL; - rtnl_event.ev.uloop.fd = -1; - } + netlink_shutdown(); return -1; } diff --git a/src/router.c b/src/router.c index 6a1d9cba..731a6dc0 100644 --- a/src/router.c +++ b/src/router.c @@ -45,6 +45,15 @@ static FILE *fp_route = NULL; #define TIME_LEFT(t1, now) ((t1) != UINT32_MAX ? (t1) - (now) : UINT32_MAX) +/* Shutdown helper: close fp_route if open. Safe to call multiple times. */ +static void router_shutdown(void) +{ + if (fp_route) { + fclose(fp_route); + fp_route = NULL; + } +} + int router_init(void) { int ret = 0; @@ -60,11 +69,11 @@ int router_init(void) ret = -1; } + atexit(router_shutdown); + out: - if (ret < 0 && fp_route) { - fclose(fp_route); - fp_route = NULL; - } + if (ret < 0) + router_shutdown(); return ret; } From 2e5068b9729011587b9c1c489b65480e8219a97d Mon Sep 17 00:00:00 2001 From: Paul Donald Date: Mon, 19 Jan 2026 01:07:44 +0100 Subject: [PATCH 4/4] dhcpv4: de-escalate error logging to debug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Logging in dhcpv4_handle_msg() was changed from debug to error during code refactor. (cherry picked from commit 13ef483716a504378b223d668c2482c93a804336) Signed-off-by: Paul Donald Link: https://github.com/openwrt/odhcpd/pull/375 Signed-off-by: Álvaro Fernández Rojas --- src/dhcpv4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dhcpv4.c b/src/dhcpv4.c index bb4444e8..c802cdea 100644 --- a/src/dhcpv4.c +++ b/src/dhcpv4.c @@ -1330,7 +1330,7 @@ void dhcpv4_handle_msg(void *src_addr, void *data, size_t len, } else { char ipv4_str[INET_ADDRSTRLEN]; - error("Sent %s to %s - %s", + debug("Sent %s to %s - %s", dhcpv4_msg_to_string(reply_msg.data), dest_addr.sin_addr.s_addr == INADDR_BROADCAST ? "ff:ff:ff:ff:ff:ff": odhcpd_print_mac(req->chaddr, req->hlen),