From: David Härdeman Date: Mon, 6 Oct 2025 13:40:23 +0000 (+0200) Subject: dhcpv4: use iovec for DNS search and MTU X-Git-Url: http://git.openwrt.org/?a=commitdiff_plain;h=b81cfaa7859e007ae0219c11849d5e7517eca3f4;p=project%2Fodhcpd.git dhcpv4: use iovec for DNS search and MTU Some more options converted. Signed-off-by: David Härdeman Link: https://github.com/openwrt/odhcpd/pull/278 Signed-off-by: Álvaro Fernández Rojas --- diff --git a/src/dhcpv4.c b/src/dhcpv4.c index 4909669..4b2073a 100644 --- a/src/dhcpv4.c +++ b/src/dhcpv4.c @@ -624,12 +624,15 @@ enum { IOV_NETMASK, IOV_HOSTNAME, IOV_HOSTNAME_NAME, + IOV_MTU, IOV_BROADCAST, IOV_NTP, IOV_NTP_ADDR, IOV_LEASETIME, IOV_RENEW, IOV_REBIND, + IOV_SRCH_DOMAIN, + IOV_SRCH_DOMAIN_NAME, IOV_DNR, IOV_DNR_BODY, IOV_END, @@ -682,6 +685,10 @@ void dhcpv4_handle_msg(void *src_addr, void *data, size_t len, struct dhcpv4_option reply_hostname = { .code = DHCPV4_OPT_HOSTNAME, }; + struct dhcpv4_option_u16 reply_mtu = { + .code = DHCPV4_OPT_MTU, + .len = sizeof(uint16_t), + }; struct dhcpv4_option_u32 reply_broadcast = { .code = DHCPV4_OPT_BROADCAST, .len = sizeof(uint32_t), @@ -702,6 +709,9 @@ void dhcpv4_handle_msg(void *src_addr, void *data, size_t len, .code = DHCPV4_OPT_REBIND, .len = sizeof(uint32_t), }; + struct dhcpv4_option reply_srch_domain = { + .code = DHCPV4_OPT_SEARCH_DOMAIN, + }; struct dhcpv4_option reply_dnr = { .code = DHCPV4_OPT_DNR, }; @@ -716,12 +726,15 @@ void dhcpv4_handle_msg(void *src_addr, void *data, size_t len, [IOV_NETMASK] = { &reply_netmask, 0 }, [IOV_HOSTNAME] = { &reply_hostname, 0 }, [IOV_HOSTNAME_NAME] = { NULL, 0 }, + [IOV_MTU] = { &reply_mtu, 0 }, [IOV_BROADCAST] = { &reply_broadcast, 0 }, [IOV_NTP] = { &reply_ntp, 0 }, [IOV_NTP_ADDR] = { iface->dhcpv4_ntp, 0 }, [IOV_LEASETIME] = { &reply_leasetime, 0 }, [IOV_RENEW] = { &reply_renew, 0 }, [IOV_REBIND] = { &reply_rebind, 0 }, + [IOV_SRCH_DOMAIN] = { &reply_srch_domain, 0 }, + [IOV_SRCH_DOMAIN_NAME] = { NULL, 0 }, [IOV_DNR] = { &reply_dnr, 0 }, [IOV_DNR_BODY] = { NULL, 0 }, [IOV_END] = { &reply_end, sizeof(reply_end) }, @@ -877,10 +890,12 @@ void dhcpv4_handle_msg(void *src_addr, void *data, size_t len, reply_opts[reply_opts_len++] = DHCPV4_OPT_NETMASK; reply_opts[reply_opts_len++] = DHCPV4_OPT_HOSTNAME; + reply_opts[reply_opts_len++] = DHCPV4_OPT_MTU; reply_opts[reply_opts_len++] = DHCPV4_OPT_BROADCAST; reply_opts[reply_opts_len++] = DHCPV4_OPT_LEASETIME; reply_opts[reply_opts_len++] = DHCPV4_OPT_RENEW; reply_opts[reply_opts_len++] = DHCPV4_OPT_REBIND; + reply_opts[reply_opts_len++] = DHCPV4_OPT_SEARCH_DOMAIN; if (a) { reply.yiaddr.s_addr = a->addr; @@ -908,30 +923,6 @@ void dhcpv4_handle_msg(void *src_addr, void *data, size_t len, } } - struct ifreq ifr; - - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, iface->ifname, sizeof(ifr.ifr_name) - 1); - - if (!ioctl(iface->dhcpv4_event.uloop.fd, SIOCGIFMTU, &ifr)) { - uint16_t mtu = htons(ifr.ifr_mtu); - dhcpv4_put(&reply, &cursor, DHCPV4_OPT_MTU, 2, &mtu); - reply_opts[reply_opts_len++] = DHCPV4_OPT_MTU; - } - - if (iface->search && iface->search_len <= 255) - dhcpv4_put(&reply, &cursor, DHCPV4_OPT_SEARCH_DOMAIN, - iface->search_len, iface->search); - else if (!res_init() && _res.dnsrch[0] && _res.dnsrch[0][0]) { - uint8_t search_buf[256]; - int len = dn_comp(_res.dnsrch[0], search_buf, - sizeof(search_buf), NULL, NULL); - if (len > 0) - dhcpv4_put(&reply, &cursor, DHCPV4_OPT_SEARCH_DOMAIN, - len, search_buf); - } - reply_opts[reply_opts_len++] = DHCPV4_OPT_SEARCH_DOMAIN; - if (iface->dhcpv4_router_cnt == 0) dhcpv4_put(&reply, &cursor, DHCPV4_OPT_ROUTER, 4, &iface->dhcpv4_local); else @@ -969,6 +960,19 @@ void dhcpv4_handle_msg(void *src_addr, void *data, size_t len, iov[IOV_HOSTNAME_NAME].iov_len = reply_hostname.len; break; + case DHCPV4_OPT_MTU: + if (iov[IOV_MTU].iov_len) + break; + + struct ifreq ifr = { .ifr_name = { 0x0, } }; + + strncpy(ifr.ifr_name, iface->ifname, sizeof(ifr.ifr_name) - 1); + if (!ioctl(iface->dhcpv4_event.uloop.fd, SIOCGIFMTU, &ifr)) { + reply_mtu.data = htons(ifr.ifr_mtu); + iov[IOV_MTU].iov_len = sizeof(reply_mtu); + } + break; + case DHCPV4_OPT_BROADCAST: if (!a || iface->dhcpv4_bcast.s_addr == INADDR_ANY) break; @@ -1004,6 +1008,33 @@ void dhcpv4_handle_msg(void *src_addr, void *data, size_t len, iov[IOV_REBIND].iov_len = sizeof(reply_rebind); break; + case DHCPV4_OPT_SEARCH_DOMAIN: + if (iov[IOV_SRCH_DOMAIN].iov_len || iface->search_len > UINT8_MAX) + break; + + if (iface->search) { + reply_srch_domain.len = iface->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; + } else if (!res_init() && _res.dnsrch[0] && _res.dnsrch[0][0]) { + int len; + + if (!iov[IOV_SRCH_DOMAIN_NAME].iov_base) + iov[IOV_SRCH_DOMAIN_NAME].iov_base = alloca(DNS_MAX_NAME_LEN); + + len = dn_comp(_res.dnsrch[0], + iov[IOV_SRCH_DOMAIN_NAME].iov_base, + DNS_MAX_NAME_LEN, NULL, NULL); + if (len < 0) + break; + + reply_srch_domain.len = len; + iov[IOV_SRCH_DOMAIN].iov_len = sizeof(reply_srch_domain); + iov[IOV_SRCH_DOMAIN_NAME].iov_len = len; + } + break; + case DHCPV4_OPT_DNR: struct dhcpv4_dnr *dnrs; size_t dnrs_len = 0; diff --git a/src/dhcpv4.h b/src/dhcpv4.h index c1dc136..4f4679f 100644 --- a/src/dhcpv4.h +++ b/src/dhcpv4.h @@ -148,6 +148,12 @@ struct dhcpv4_option_u8 { uint8_t data; }; +struct dhcpv4_option_u16 { + uint8_t code; + uint8_t len; + uint16_t data; +}; + struct dhcpv4_option_u32 { uint8_t code; uint8_t len; diff --git a/src/odhcpd.h b/src/odhcpd.h index 7d26365..ae0e6f5 100644 --- a/src/odhcpd.h +++ b/src/odhcpd.h @@ -29,6 +29,10 @@ #define min(a, b) (((a) < (b)) ? (a) : (b)) #define max(a, b) (((a) > (b)) ? (a) : (b)) +/* RFC 1035, §2.3.4, with one extra byte for buffers */ +#define DNS_MAX_NAME_LEN 256 +#define DNS_MAX_LABEL_LEN 63 + // RFC 6106 defines this router advertisement option #define ND_OPT_ROUTE_INFO 24 #define ND_OPT_RECURSIVE_DNS 25