odhcpd: rename iface->search -> iface->dns_search
authorDavid Härdeman <[email protected]>
Thu, 20 Nov 2025 16:17:49 +0000 (17:17 +0100)
committerÁlvaro Fernández Rojas <[email protected]>
Thu, 27 Nov 2025 07:24:27 +0000 (08:24 +0100)
And fix some bugs/nits in the process, e.g.:
 - realloc() not handled properly in config.c
 - replace a number of magic values
 - in router.c, the DNSSL options has 8 bytes of superfluous padding

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/320
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
src/config.c
src/dhcpv4.c
src/dhcpv4.h
src/dhcpv6.c
src/odhcpd.h
src/router.c
src/statefiles.c

index b5048780bc1c795d2d6c353f9d204c05a2cfd5e2..30609a63dccede6527b79b243d957ead1a9b34be 100644 (file)
@@ -107,7 +107,7 @@ enum {
        IFACE_ATTR_DNS,
        IFACE_ATTR_DNR,
        IFACE_ATTR_DNS_SERVICE,
-       IFACE_ATTR_DOMAIN,
+       IFACE_ATTR_DNS_DOMAIN_SEARCH,
        IFACE_ATTR_DHCPV4_FORCERECONF,
        IFACE_ATTR_DHCPV6_RAW,
        IFACE_ATTR_DHCPV6_ASSIGNALL,
@@ -160,7 +160,7 @@ static const struct blobmsg_policy iface_attrs[IFACE_ATTR_MAX] = {
        [IFACE_ATTR_DNS] = { .name = "dns", .type = BLOBMSG_TYPE_ARRAY },
        [IFACE_ATTR_DNR] = { .name = "dnr", .type = BLOBMSG_TYPE_ARRAY },
        [IFACE_ATTR_DNS_SERVICE] = { .name = "dns_service", .type = BLOBMSG_TYPE_BOOL },
-       [IFACE_ATTR_DOMAIN] = { .name = "domain", .type = BLOBMSG_TYPE_ARRAY },
+       [IFACE_ATTR_DNS_DOMAIN_SEARCH] = { .name = "domain", .type = BLOBMSG_TYPE_ARRAY },
        [IFACE_ATTR_DHCPV4_FORCERECONF] = { .name = "dhcpv4_forcereconf", .type = BLOBMSG_TYPE_BOOL },
        [IFACE_ATTR_DHCPV6_RAW] = { .name = "dhcpv6_raw", .type = BLOBMSG_TYPE_STRING },
        [IFACE_ATTR_DHCPV6_ASSIGNALL] = { .name ="dhcpv6_assignall", .type = BLOBMSG_TYPE_BOOL },
@@ -344,7 +344,7 @@ static void clean_interface(struct interface *iface)
 {
        free(iface->dns_addrs4);
        free(iface->dns_addrs6);
-       free(iface->search);
+       free(iface->dns_search);
        free(iface->upstream);
        free(iface->dhcpv4_router);
        free(iface->dhcpv6_raw);
@@ -1373,15 +1373,16 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr
        if ((c = tb[IFACE_ATTR_DNS_SERVICE]))
                iface->dns_service = blobmsg_get_bool(c);
 
-       if ((c = tb[IFACE_ATTR_DOMAIN])) {
+       if ((c = tb[IFACE_ATTR_DNS_DOMAIN_SEARCH])) {
                struct blob_attr *cur;
                unsigned rem;
 
                blobmsg_for_each_attr(cur, c, rem) {
-                       uint8_t buf[256];
-                       char *domain = blobmsg_get_string(cur);
-                       size_t domainlen = strlen(domain);
+                       uint8_t buf[DNS_MAX_NAME_LEN];
+                       char *domain;
+                       size_t domainlen;
                        int len;
+                       uint8_t *tmp;
 
                        if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING || !blobmsg_check_attr(cur, false))
                                continue;
@@ -1395,16 +1396,17 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr
                        len = dn_comp(domain, buf, sizeof(buf), NULL, NULL);
                        if (len <= 0) {
                                error("Invalid %s value configured for interface '%s'",
-                                     iface_attrs[IFACE_ATTR_DOMAIN].name, iface->name);
+                                     iface_attrs[IFACE_ATTR_DNS_DOMAIN_SEARCH].name, iface->name);
                                continue;
                        }
 
-                       iface->search = realloc(iface->search, iface->search_len + len);
-                       if (!iface->search)
+                       tmp = realloc(iface->dns_search, iface->dns_search_len + len);
+                       if (!tmp)
                                goto err;
 
-                       memcpy(&iface->search[iface->search_len], buf, len);
-                       iface->search_len += len;
+                       iface->dns_search = tmp;
+                       memcpy(&iface->dns_search[iface->dns_search_len], buf, len);
+                       iface->dns_search_len += len;
                }
        }
 
index 98d1d7d48bd0d0ec787c44a7736e118eb5783829..545c8142b9d6fecb3a4227b4c3fcde4188ebcb1a 100644 (file)
@@ -891,7 +891,7 @@ void dhcpv4_handle_msg(void *src_addr, void *data, size_t len,
                .len = sizeof(reply_auth_body),
        };
        struct dhcpv4_option reply_srch_domain = {
-               .code = DHCPV4_OPT_SEARCH_DOMAIN,
+               .code = DHCPV4_OPT_DNS_DOMAIN_SEARCH,
        };
        struct dhcpv4_option_u8 reply_fr_nonce_cap = {
                .code = DHCPV4_OPT_FORCERENEW_NONCE_CAPABLE,
@@ -948,7 +948,7 @@ void dhcpv4_handle_msg(void *src_addr, void *data, size_t len,
                DHCPV4_OPT_REBIND,
                DHCPV4_OPT_CLIENTID, // Must be in reply if present in req, RFC6842, §3
                DHCPV4_OPT_AUTHENTICATION,
-               DHCPV4_OPT_SEARCH_DOMAIN,
+               DHCPV4_OPT_DNS_DOMAIN_SEARCH,
                DHCPV4_OPT_CAPTIVE_PORTAL,
                DHCPV4_OPT_FORCERENEW_NONCE_CAPABLE,
        };
@@ -1193,15 +1193,15 @@ void dhcpv4_handle_msg(void *src_addr, void *data, size_t len,
                        iov[IOV_AUTH_BODY].iov_len = sizeof(reply_auth_body);
                        break;
 
-               case DHCPV4_OPT_SEARCH_DOMAIN:
-                       if (iov[IOV_SRCH_DOMAIN].iov_len || iface->search_len > UINT8_MAX)
+               case DHCPV4_OPT_DNS_DOMAIN_SEARCH:
+                       if (iov[IOV_SRCH_DOMAIN].iov_len || iface->dns_search_len > UINT8_MAX)
                                break;
 
-                       if (iface->search) {
-                               reply_srch_domain.len = iface->search_len;
+                       if (iface->dns_search) {
+                               reply_srch_domain.len = iface->dns_search_len;
                                iov[IOV_SRCH_DOMAIN].iov_len = sizeof(reply_srch_domain);
-                               iov[IOV_SRCH_DOMAIN_NAME].iov_base = iface->search;
-                               iov[IOV_SRCH_DOMAIN_NAME].iov_len = iface->search_len;
+                               iov[IOV_SRCH_DOMAIN_NAME].iov_base = iface->dns_search;
+                               iov[IOV_SRCH_DOMAIN_NAME].iov_len = iface->dns_search_len;
                        } else if (!res_init() && _res.dnsrch[0] && _res.dnsrch[0][0]) {
                                int len;
 
index 330df61d97d4ff87dcde166182d5b94e8815db02..045f78b3ec4b3b54b70f8b231e2f7a45d3c94fb3 100644 (file)
@@ -81,7 +81,7 @@ enum dhcpv4_opt {
        DHCPV4_OPT_USER_CLASS = 77,
        DHCPV4_OPT_AUTHENTICATION = 90,
        DHCPV4_OPT_CAPTIVE_PORTAL = 114, // RFC8910
-       DHCPV4_OPT_SEARCH_DOMAIN = 119,
+       DHCPV4_OPT_DNS_DOMAIN_SEARCH = 119,
        DHCPV4_OPT_FORCERENEW_NONCE_CAPABLE = 145,
        DHCPV4_OPT_DNR = 162,
        DHCPV4_OPT_END = 255,
index f4c30aefb847c90889931c848a259eff26f7112f..06b7f594784b11d292853891aebc09e4cfd96d1b 100644 (file)
@@ -615,22 +615,23 @@ static void handle_client_request(void *addr, void *data, size_t len,
        }
 
        /* DNS Search options */
-       uint8_t search_buf[256], *search_domain = iface->search;
-       size_t search_len = iface->search_len;
+       uint8_t dns_search_buf[DNS_MAX_NAME_LEN];
+       uint8_t *dns_search = iface->dns_search;
+       size_t dns_search_len = iface->dns_search_len;
 
-       if (!search_domain && !res_init() && _res.dnsrch[0] && _res.dnsrch[0][0]) {
-               int len = dn_comp(_res.dnsrch[0], search_buf,
-                               sizeof(search_buf), NULL, NULL);
+       if (!dns_search && !res_init() && _res.dnsrch[0] && _res.dnsrch[0][0]) {
+               int len = dn_comp(_res.dnsrch[0], dns_search_buf,
+                               sizeof(dns_search_buf), NULL, NULL);
                if (len > 0) {
-                       search_domain = search_buf;
-                       search_len = len;
+                       dns_search = dns_search_buf;
+                       dns_search_len = len;
                }
        }
 
        struct {
                uint16_t type;
                uint16_t len;
-       } search = {htons(DHCPV6_OPT_DNS_DOMAIN), htons(search_len)};
+       } dns_search_hdr = { htons(DHCPV6_OPT_DNS_DOMAIN), htons(dns_search_len) };
 
 
        struct _o_packed dhcpv4o6_server {
@@ -649,8 +650,8 @@ static void handle_client_request(void *addr, void *data, size_t len,
                [IOV_RAPID_COMMIT] = {&rapid_commit, 0},
                [IOV_DNS] = { &dns_hdr, (dns_addrs6_cnt) ? sizeof(dns_hdr) : 0},
                [IOV_DNS_ADDR] = { dns_addrs6, dns_addrs6_cnt * sizeof(*dns_addrs6) },
-               [IOV_SEARCH] = {&search, (search_len) ? sizeof(search) : 0},
-               [IOV_SEARCH_DOMAIN] = {search_domain, search_len},
+               [IOV_SEARCH] = { &dns_search_hdr, (dns_search_len) ? sizeof(dns_search_hdr) : 0 },
+               [IOV_SEARCH_DOMAIN] = { dns_search, dns_search_len },
                [IOV_PDBUF] = {pdbuf, 0},
                [IOV_DHCPV6_RAW] = {iface->dhcpv6_raw, iface->dhcpv6_raw_len},
                [IOV_NTP] = {&ntp, (ntp_cnt) ? sizeof(ntp) : 0},
index 9db8662c1a5804ebaf90539e7f270cbe306bb66c..a74c295cc7815a4324db7369571a8d05eec0dfbd 100644 (file)
@@ -456,8 +456,8 @@ struct interface {
        size_t dns_addrs4_cnt;          // Count of IPv4 DNS addresses
        struct in6_addr *dns_addrs6;    // IPv6 DNS server addresses to announce
        size_t dns_addrs6_cnt;          // Count of IPv6 DNS addresses
-       uint8_t *search;
-       size_t search_len;
+       uint8_t *dns_search;            // DNS domain search list to announce (concatenated)
+       size_t dns_search_len;          // Length of the DNS domain search list (bytes)
 
        // DHCPV6
        void *dhcpv6_raw;
index 957b61d1c68e9a689bfd71c20872e22cc4ee99dc..b882e016c0f0042ac72357591405b4dd36dac144 100644 (file)
@@ -412,11 +412,10 @@ struct nd_opt_dns_server {
 struct nd_opt_search_list {
        uint8_t type;
        uint8_t len;
-       uint8_t pad;
-       uint8_t pad2;
+       uint16_t reserved;
        uint32_t lifetime;
        uint8_t name[];
-};
+} _o_packed;
 
 struct nd_opt_route_info {
        uint8_t type;
@@ -834,9 +833,9 @@ static int send_router_advert(struct interface *iface, const struct in6_addr *fr
        /* DNS options */
        if (iface->ra_dns) {
                struct in6_addr *dns_addrs6 = NULL, dns_addr6;
-               size_t dns_addrs6_cnt = 0, search_len = iface->search_len;
-               uint8_t *search_domain = iface->search;
-               uint8_t search_buf[256];
+               size_t dns_addrs6_cnt = 0, dns_search_len = iface->dns_search_len;
+               uint8_t *dns_search = iface->dns_search;
+               uint8_t dns_search_buf[DNS_MAX_NAME_LEN];
 
                /* DNS Recursive DNS aka RDNSS Type 25; RFC8106 */
                if (iface->dns_addrs6_cnt > 0) {
@@ -858,28 +857,26 @@ static int send_router_advert(struct interface *iface, const struct in6_addr *fr
                        memcpy(dns->addr, dns_addrs6, dns_addrs6_cnt * sizeof(*dns_addrs6));
                }
 
-               /* DNS Search options aka DNSSL Type 31; RFC8106 */
-               if (!search_domain && !res_init() && _res.dnsrch[0] && _res.dnsrch[0][0]) {
-                       int len = dn_comp(_res.dnsrch[0], search_buf,
-                                       sizeof(search_buf), NULL, NULL);
+               /* DNS Search List option aka DNSSL Type 31; RFC8106, §5.2 */
+               if (!dns_search && !res_init() && _res.dnsrch[0] && _res.dnsrch[0][0]) {
+                       int len = dn_comp(_res.dnsrch[0], dns_search_buf,
+                                       sizeof(dns_search_buf), NULL, NULL);
                        if (len > 0) {
-                               search_domain = search_buf;
-                               search_len = len;
+                               dns_search = dns_search_buf;
+                               dns_search_len = len;
                        }
                }
 
-               if (search_len > 0) {
-                       size_t search_padded = ((search_len + 7) & (~7)) + 8;
-
-                       search_sz = sizeof(*search) + search_padded;
-
+               if (dns_search_len > 0) {
+                       search_sz = sizeof(*search) + ((dns_search_len + 7) & (~7));
                        search = alloca(search_sz);
-                       memset(search, 0, search_sz);
-                       search->type = ND_OPT_DNS_SEARCH;
-                       search->len = search_len ? ((sizeof(*search) + search_padded) / 8) : 0;
-                       search->lifetime = htonl(highest_found_lifetime);
-                       memcpy(search->name, search_domain, search_len);
-                       memset(&search->name[search_len], 0, search_padded - search_len);
+                       *search = (struct nd_opt_search_list) {
+                               .type = ND_OPT_DNS_SEARCH,
+                               .len = search_sz / 8,
+                               .reserved = 0,
+                               .lifetime = htonl(highest_found_lifetime),
+                       };
+                       memcpy(search->name, dns_search, dns_search_len);
                }
        }
 
index a5d4e3ea6aeb8bd3e55594706901b37a814e13f0..8862f1b435ebc0ff1d275972bfc257112f7dbafe 100644 (file)
@@ -45,8 +45,8 @@ static void statefiles_write_host(const char *ipbuf, const char *hostname, struc
 {
        char exp_dn[DNS_MAX_NAME_LEN];
 
-       if (dn_expand(ctxt->iface->search, ctxt->iface->search + ctxt->iface->search_len,
-                     ctxt->iface->search, exp_dn, sizeof(exp_dn)) > 0)
+       if (dn_expand(ctxt->iface->dns_search, ctxt->iface->dns_search + ctxt->iface->dns_search_len,
+                     ctxt->iface->dns_search, exp_dn, sizeof(exp_dn)) > 0)
                fprintf(ctxt->fp, "%s\t%s.%s\t%s\n", ipbuf, hostname, exp_dn, hostname);
        else
                fprintf(ctxt->fp, "%s\t%s\n", ipbuf, hostname);