odhcpd: remove fallback DNS search domain master
authorDavid Härdeman <david@hardeman.nu>
Sat, 13 Dec 2025 19:21:44 +0000 (20:21 +0100)
committerÁlvaro Fernández Rojas <noltari@gmail.com>
Sun, 14 Dec 2025 21:19:06 +0000 (22:19 +0100)
This might require some explanation :)

First, res_init() is marked as deprecated in the Linux man-pages (read: in
glibc), and has been so for a while.

Second, we use musl on OpenWrt, and what does res_init() look like in musl?

 musl/src/network/res_init.c:

int res_init()
{
return 0;
}

 musl/include/resolv.h (commit date 2011-02-12):

/* unused; purely for broken apps */
typedef struct __res_state {

OpenWrt switched to musl sometime in 2015 (from a quick search, don't
quote me on that), and res_init() hasn't worked since then.

Ok, so first I thought I might reimplement res_init(), using the glibc
implementation as inspiration.

glibc's res_init() basically has three sources of domain search data:
 1. The LOCALDOMAIN environment variable
 2. /etc/resolv.conf
 3. gethostname() followed by checking if there's at least one dot in the name

1. The environment variable won't help us, we don't have it on OpenWrt and it
would just be confusing.

2. resolv.conf seems reasonable, but note that it is typically a symlink:
/etc/resolv.conf -> /tmp/resolv.conf -> /tmp/resolv.conf.d/resolv.conf.auto

The latter is created by netifd. Where do we get iface->dns_search from? From
netifd via ubus. In addition, the resolv.conf.auto that netifd generates
includes all dns search domain and we might end up picking a random one (so if
the user has set a domain on the guest network, but not on the main network,
the former might end up being the fallback for the latter, not good).

3. gethostname() will return the hostname, which on OpenWrt is typically set to
exactly that - the hostname and not a FQDN (and this is what the UIs tell the
users to do).

In summary, all these calls to res_init() are pointless right now, and there is
no reasonable fallback once we've failed to get the info we want from netifd.

So, remove the DNS search domain fallback logic if one isn't set. It's not like
DHCPv[46] clients or hosts listening to RAs have any expectation that the
domain search list MUST be defined.

Signed-off-by: David Härdeman <david@hardeman.nu>
Link: https://github.com/openwrt/odhcpd/pull/358
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
src/dhcpv4.c
src/dhcpv6.c
src/odhcpd.c
src/router.c

index 6dbc61d43ac3cc7789c0e031e4fa05e86203206c..bb4444e8ef9f1363664a97a46e6d3b7f7d53a89a 100644 (file)
@@ -19,7 +19,6 @@
 #include <unistd.h>
 #include <stddef.h>
 #include <stdlib.h>
-#include <resolv.h>
 #include <limits.h>
 #include <alloca.h>
 #include <net/if.h>
@@ -1211,21 +1210,6 @@ void dhcpv4_handle_msg(void *src_addr, void *data, size_t len,
                                iov[IOV_SRCH_DOMAIN].iov_len = sizeof(reply_srch_domain);
                                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 dds_len;
-
-                               if (!iov[IOV_SRCH_DOMAIN_NAME].iov_base)
-                                       iov[IOV_SRCH_DOMAIN_NAME].iov_base = alloca(DNS_MAX_NAME_LEN);
-
-                               dds_len = dn_comp(_res.dnsrch[0],
-                                             iov[IOV_SRCH_DOMAIN_NAME].iov_base,
-                                             DNS_MAX_NAME_LEN, NULL, NULL);
-                               if (dds_len < 0)
-                                       break;
-
-                               reply_srch_domain.len = dds_len;
-                               iov[IOV_SRCH_DOMAIN].iov_len = sizeof(reply_srch_domain);
-                               iov[IOV_SRCH_DOMAIN_NAME].iov_len = dds_len;
                        }
                        break;
 
index 03537fd6d7929c8a98abe79a538377f266fa6ffb..9d32e6b053a760bf78fafb0f19a7a0da8efbc054 100644 (file)
@@ -16,8 +16,6 @@
 #include <errno.h>
 #include <unistd.h>
 #include <stddef.h>
-#include <resolv.h>
-#include <sys/timerfd.h>
 #include <arpa/inet.h>
 
 #include <libubox/utils.h>
@@ -615,23 +613,10 @@ static void handle_client_request(void *addr, void *data, size_t len,
        }
 
        /* DNS Search options */
-       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 (!dns_search && !res_init() && _res.dnsrch[0] && _res.dnsrch[0][0]) {
-               int ds_len = dn_comp(_res.dnsrch[0], dns_search_buf,
-                               sizeof(dns_search_buf), NULL, NULL);
-               if (ds_len > 0) {
-                       dns_search = dns_search_buf;
-                       dns_search_len = ds_len;
-               }
-       }
-
        struct {
                uint16_t type;
                uint16_t len;
-       } dns_search_hdr = { htons(DHCPV6_OPT_DNS_DOMAIN), htons(dns_search_len) };
+       } dns_search_hdr = { htons(DHCPV6_OPT_DNS_DOMAIN), htons(iface->dns_search_len) };
 
 
        struct _o_packed dhcpv4o6_server {
@@ -650,8 +635,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] = { &dns_search_hdr, (dns_search_len) ? sizeof(dns_search_hdr) : 0 },
-               [IOV_SEARCH_DOMAIN] = { dns_search, dns_search_len },
+               [IOV_SEARCH] = { &dns_search_hdr, iface->dns_search_len ? sizeof(dns_search_hdr) : 0 },
+               [IOV_SEARCH_DOMAIN] = { iface->dns_search, iface->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 00ca42d7a9d016246468feb7a807ec3a85c0ce08..9921e1b0713f259edaa65babb834346c4b9d1e16 100644 (file)
@@ -16,7 +16,6 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
-#include <resolv.h>
 #include <getopt.h>
 #include <stddef.h>
 #include <stdlib.h>
index 3c32a1129cf2e1ab402e0380a044d405f0289025..6a1d9cba3492213bc49e08ff28a4dcff681ad9d5 100644 (file)
@@ -16,7 +16,6 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <signal.h>
-#include <resolv.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -881,14 +880,11 @@ static int send_router_advert(struct interface *iface, const struct in6_addr *fr
 
        debug("Using a RA lifetime of %d seconds on %s", ntohs(adv.h.nd_ra_router_lifetime), iface->name);
 
-       /* DNS options */
+       /* Recursive DNS Server aka RDNSS; RFC8106, §5.1 */
        if (iface->ra_dns) {
                struct in6_addr *dns_addrs6 = NULL, dns_addr6;
-               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];
+               size_t dns_addrs6_cnt = 0;
 
-               /* DNS Recursive DNS aka RDNSS Type 25; RFC8106 */
                if (iface->dns_addrs6_cnt > 0) {
                        dns_addrs6 = iface->dns_addrs6;
                        dns_addrs6_cnt = iface->dns_addrs6_cnt;
@@ -907,32 +903,22 @@ static int send_router_advert(struct interface *iface, const struct in6_addr *fr
                        dns->lifetime = htonl(highest_found_lifetime);
                        memcpy(dns->addr, dns_addrs6, dns_addrs6_cnt * sizeof(*dns_addrs6));
                }
-
-               /* 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) {
-                               dns_search = dns_search_buf;
-                               dns_search_len = len;
-                       }
-               }
-
-               if (dns_search_len > 0) {
-                       search_sz = sizeof(*search) + ((dns_search_len + 7) & (~7));
-                       search = alloca(search_sz);
-                       *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);
-               }
        }
-
        iov[IOV_RA_DNS].iov_base = dns;
        iov[IOV_RA_DNS].iov_len = dns_sz;
+
+       /* DNS Search List aka DNSSL; RFC8106, §5.2 */
+       if (iface->ra_dns && iface->dns_search_len > 0) {
+               search_sz = sizeof(*search) + ((iface->dns_search_len + 7) & ~7);
+               search = alloca(search_sz);
+               *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, iface->dns_search, iface->dns_search_len);
+       }
        iov[IOV_RA_SEARCH].iov_base = search;
        iov[IOV_RA_SEARCH].iov_len = search_sz;