From cdc6c324d785742291460e742be261cb37705d65 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 24 Jun 2025 14:01:51 +0300 Subject: [PATCH] net: dns: Save info about source when configuring DNS servers Remember which DNS server was added by a source like DHCPv4 or v6 message. This will allow system to remove DNS servers that were added by that source. Then when stopping for example DHCP, we can remove those specific DNS servers and not leaving DNS servers hanging in the system. Signed-off-by: Jukka Rissanen --- drivers/modem/hl7800.c | 3 +- drivers/wifi/esp_at/esp.c | 3 +- include/zephyr/net/dns_resolve.h | 38 +++++++++++++++- subsys/net/ip/ipv6_nbr.c | 3 +- subsys/net/l2/ppp/ipcp.c | 3 +- subsys/net/lib/dhcpv4/dhcpv4.c | 6 ++- subsys/net/lib/dhcpv6/dhcpv6.c | 6 ++- subsys/net/lib/dns/resolve.c | 61 +++++++++++++++++++++----- tests/net/lib/dns_addremove/src/main.c | 3 +- 9 files changed, 103 insertions(+), 23 deletions(-) diff --git a/drivers/modem/hl7800.c b/drivers/modem/hl7800.c index 58e4f663838..33064290639 100644 --- a/drivers/modem/hl7800.c +++ b/drivers/modem/hl7800.c @@ -1966,7 +1966,8 @@ static void dns_work_cb(struct k_work *work) } } else { LOG_DBG("Reconfiguring DNS resolver"); - ret = dns_resolve_reconfigure(dnsCtx, (const char **)dns_servers_str, NULL); + ret = dns_resolve_reconfigure(dnsCtx, (const char **)dns_servers_str, NULL, + DNS_SOURCE_MANUAL); if (ret < 0) { LOG_ERR("dns_resolve_reconfigure fail (%d)", ret); retry = true; diff --git a/drivers/wifi/esp_at/esp.c b/drivers/wifi/esp_at/esp.c index 25c47412c4c..427d548350b 100644 --- a/drivers/wifi/esp_at/esp.c +++ b/drivers/wifi/esp_at/esp.c @@ -506,7 +506,8 @@ static void esp_dns_work(struct k_work *work) dnsctx = dns_resolve_get_default(); err = dns_resolve_reconfigure_with_interfaces(dnsctx, NULL, dns_servers, - interfaces); + interfaces, + DNS_SOURCE_MANUAL); if (err) { LOG_ERR("Could not set DNS servers: %d", err); } diff --git a/include/zephyr/net/dns_resolve.h b/include/zephyr/net/dns_resolve.h index 0e9ab5aefa1..66ec99c481b 100644 --- a/include/zephyr/net/dns_resolve.h +++ b/include/zephyr/net/dns_resolve.h @@ -44,6 +44,24 @@ enum dns_query_type { DNS_QUERY_TYPE_AAAA = 28 }; +/** + * Entity that added the DNS server. + */ +enum dns_server_source { + /** Source is unknown */ + DNS_SOURCE_UNKNOWN = 0, + /** Server information is added manually, for example by an application */ + DNS_SOURCE_MANUAL, + /** Server information is from DHCPv4 server */ + DNS_SOURCE_DHCPV4, + /** Server information is from DHCPv6 server */ + DNS_SOURCE_DHCPV6, + /** Server information is from IPv6 SLAAC (router advertisement) */ + DNS_SOURCE_IPV6_RA, + /** Server information is from PPP */ + DNS_SOURCE_PPP, +}; + /** Max size of the resolved name. */ #if defined(CONFIG_DNS_RESOLVER_MAX_NAME_LEN) #define DNS_MAX_NAME_SIZE CONFIG_DNS_RESOLVER_MAX_NAME_LEN @@ -353,6 +371,9 @@ struct dns_resolve_context { */ int if_index; + /** Source of the DNS server, e.g., manual, DHCPv4/6, etc. */ + enum dns_server_source source; + /** Is this server mDNS one */ uint8_t is_mdns : 1; @@ -526,12 +547,14 @@ int dns_resolve_close(struct dns_resolve_context *ctx); * @param servers_sa DNS server addresses as struct sockaddr. The array * is NULL terminated. Port numbers are optional in struct sockaddr, the * default will be used if set to 0. + * @param source Source of the DNS servers, e.g., manual, DHCPv4/6, etc. * * @return 0 if ok, <0 if error. */ int dns_resolve_reconfigure(struct dns_resolve_context *ctx, const char *servers_str[], - const struct sockaddr *servers_sa[]); + const struct sockaddr *servers_sa[], + enum dns_server_source source); /** * @brief Reconfigure DNS resolving context with new server list and @@ -551,13 +574,15 @@ int dns_resolve_reconfigure(struct dns_resolve_context *ctx, * @param interfaces Network interfaces to which the DNS servers are bound. * This is an array of network interface indices. The array must be * the same length as the servers_str and servers_sa arrays. + * @param source Source of the DNS servers, e.g., manual, DHCPv4/6, etc. * * @return 0 if ok, <0 if error. */ int dns_resolve_reconfigure_with_interfaces(struct dns_resolve_context *ctx, const char *servers_str[], const struct sockaddr *servers_sa[], - int interfaces[]); + int interfaces[], + enum dns_server_source source); /** * @brief Remove servers from the DNS resolving context. @@ -747,6 +772,15 @@ static inline int dns_cancel_addr_info(uint16_t dns_id) /** @cond INTERNAL_HIDDEN */ +/** + * @brief Get string representation of the DNS server source. + * + * @param source Source of the DNS server. + * + * @return String representation of the DNS server source. + */ +const char *dns_get_source_str(enum dns_server_source source); + /** * @brief Initialize DNS subsystem. */ diff --git a/subsys/net/ip/ipv6_nbr.c b/subsys/net/ip/ipv6_nbr.c index 19a0405f6ea..1cf7e53ad48 100644 --- a/subsys/net/ip/ipv6_nbr.c +++ b/subsys/net/ip/ipv6_nbr.c @@ -2509,7 +2509,8 @@ static inline bool handle_ra_rdnss(struct net_pkt *pkt, uint8_t len) /* TODO: Handle lifetime. */ ctx = dns_resolve_get_default(); ret = dns_resolve_reconfigure_with_interfaces(ctx, NULL, dns_servers, - interfaces); + interfaces, + DNS_SOURCE_IPV6_RA); if (ret < 0) { NET_DBG("Failed to set RDNSS resolve address: %d", ret); } diff --git a/subsys/net/l2/ppp/ipcp.c b/subsys/net/l2/ppp/ipcp.c index e3e377adefd..35b7bac018b 100644 --- a/subsys/net/l2/ppp/ipcp.c +++ b/subsys/net/l2/ppp/ipcp.c @@ -341,7 +341,8 @@ static void ipcp_set_dns_servers(struct ppp_fsm *fsm) dnsctx = dns_resolve_get_default(); ret = dns_resolve_reconfigure_with_interfaces(dnsctx, NULL, dns_servers, - interfaces); + interfaces, + DNS_SOURCE_PPP); if (ret < 0) { NET_ERR("Could not set DNS servers"); return; diff --git a/subsys/net/lib/dhcpv4/dhcpv4.c b/subsys/net/lib/dhcpv4/dhcpv4.c index 6b65d31ab59..e019794d75a 100644 --- a/subsys/net/lib/dhcpv4/dhcpv4.c +++ b/subsys/net/lib/dhcpv4/dhcpv4.c @@ -1194,9 +1194,11 @@ static bool dhcpv4_parse_options(struct net_pkt *pkt, status = dns_resolve_reconfigure_with_interfaces(ctx, NULL, dns_servers, - interfaces); + interfaces, + DNS_SOURCE_DHCPV4); } else { - status = dns_resolve_reconfigure(ctx, NULL, dns_servers); + status = dns_resolve_reconfigure(ctx, NULL, dns_servers, + DNS_SOURCE_DHCPV4); } if (status < 0) { diff --git a/subsys/net/lib/dhcpv6/dhcpv6.c b/subsys/net/lib/dhcpv6/dhcpv6.c index 4f3809dfa7b..b09f3dc8513 100644 --- a/subsys/net/lib/dhcpv6/dhcpv6.c +++ b/subsys/net/lib/dhcpv6/dhcpv6.c @@ -1426,9 +1426,11 @@ static int dhcpv6_handle_dns_server_option(struct net_pkt *pkt) status = dns_resolve_reconfigure_with_interfaces(ctx, NULL, dns_servers, - interfaces); + interfaces, + DNS_SOURCE_DHCPV6); } else { - status = dns_resolve_reconfigure(ctx, NULL, dns_servers); + status = dns_resolve_reconfigure(ctx, NULL, dns_servers, + DNS_SOURCE_DHCPV6); } if (status < 0) { diff --git a/subsys/net/lib/dns/resolve.c b/subsys/net/lib/dns/resolve.c index 5614ae2218e..f95fb17dfbc 100644 --- a/subsys/net/lib/dns/resolve.c +++ b/subsys/net/lib/dns/resolve.c @@ -488,13 +488,34 @@ static int get_free_slot(struct dns_resolve_context *ctx) return -ENOENT; } +const char *dns_get_source_str(enum dns_server_source source) +{ + switch (source) { + case DNS_SOURCE_UNKNOWN: + return "unknown"; + case DNS_SOURCE_MANUAL: + return "manual"; + case DNS_SOURCE_DHCPV4: + __fallthrough; + case DNS_SOURCE_DHCPV6: + return "DHCP"; + case DNS_SOURCE_IPV6_RA: + return "IPv6 RA"; + case DNS_SOURCE_PPP: + return "PPP"; + } + + return ""; +} + /* Must be invoked with context lock held */ static int dns_resolve_init_locked(struct dns_resolve_context *ctx, const char *servers[], const struct sockaddr *servers_sa[], const struct net_socket_service_desc *svc, uint16_t port, int interfaces[], - bool do_cleanup) + bool do_cleanup, + enum dns_server_source source) { #if defined(CONFIG_NET_IPV6) struct sockaddr_in6 local_addr6 = { @@ -608,6 +629,8 @@ static int dns_resolve_init_locked(struct dns_resolve_context *ctx, } } + ctx->servers[idx].source = source; + addr = &ctx->servers[idx].dns_server; (void)memset(addr, 0, sizeof(*addr)); @@ -624,13 +647,16 @@ static int dns_resolve_init_locked(struct dns_resolve_context *ctx, dns_postprocess_server(ctx, idx); - NET_DBG("[%d] %.*s%s%s%s%s", i, (int)server_len, servers[i], + NET_DBG("[%d] %.*s%s%s%s%s%s%s%s", i, (int)server_len, servers[i], IS_ENABLED(CONFIG_MDNS_RESOLVER) ? (ctx->servers[i].is_mdns ? " mDNS" : "") : "", IS_ENABLED(CONFIG_LLMNR_RESOLVER) ? (ctx->servers[i].is_llmnr ? " LLMNR" : "") : "", iface_str != NULL ? " via " : "", - iface_str != NULL ? iface_str : ""); + iface_str != NULL ? iface_str : "", + source != DNS_SOURCE_UNKNOWN ? " (" : "", + source != DNS_SOURCE_UNKNOWN ? dns_get_source_str(source) : "", + source != DNS_SOURCE_UNKNOWN ? ")" : ""); idx++; } @@ -656,6 +682,8 @@ static int dns_resolve_init_locked(struct dns_resolve_context *ctx, break; } + ctx->servers[idx].source = source; + memcpy(&ctx->servers[idx].dns_server, servers_sa[i], sizeof(ctx->servers[idx].dns_server)); @@ -668,7 +696,7 @@ static int dns_resolve_init_locked(struct dns_resolve_context *ctx, dns_postprocess_server(ctx, idx); - NET_DBG("[%d] %s%s%s%s%s", i, + NET_DBG("[%d] %s%s%s%s%s%s%s%s", i, net_sprint_addr(servers_sa[i]->sa_family, &net_sin(servers_sa[i])->sin_addr), IS_ENABLED(CONFIG_MDNS_RESOLVER) ? @@ -676,7 +704,10 @@ static int dns_resolve_init_locked(struct dns_resolve_context *ctx, IS_ENABLED(CONFIG_LLMNR_RESOLVER) ? (ctx->servers[i].is_llmnr ? " LLMNR" : "") : "", interfaces != NULL ? " via " : "", - interfaces != NULL ? iface_str : ""); + interfaces != NULL ? iface_str : "", + source != DNS_SOURCE_UNKNOWN ? " (" : "", + source != DNS_SOURCE_UNKNOWN ? dns_get_source_str(source) : "", + source != DNS_SOURCE_UNKNOWN ? ")" : ""); idx++; } @@ -871,7 +902,7 @@ int dns_resolve_init_with_svc(struct dns_resolve_context *ctx, const char *serve } ret = dns_resolve_init_locked(ctx, servers, servers_sa, svc, port, - interfaces, true); + interfaces, true, DNS_SOURCE_UNKNOWN); k_mutex_unlock(&lock); @@ -2101,7 +2132,8 @@ static int do_dns_resolve_reconfigure(struct dns_resolve_context *ctx, const char *servers[], const struct sockaddr *servers_sa[], int interfaces[], - bool do_close) + bool do_close, + enum dns_server_source source) { int err; @@ -2138,7 +2170,8 @@ static int do_dns_resolve_reconfigure(struct dns_resolve_context *ctx, err = dns_resolve_init_locked(ctx, servers, servers_sa, &resolve_svc, 0, interfaces, - do_close); + do_close, + source); unlock: k_mutex_unlock(&ctx->lock); @@ -2150,26 +2183,30 @@ unlock: int dns_resolve_reconfigure_with_interfaces(struct dns_resolve_context *ctx, const char *servers[], const struct sockaddr *servers_sa[], - int interfaces[]) + int interfaces[], + enum dns_server_source source) { return do_dns_resolve_reconfigure(ctx, servers, servers_sa, interfaces, IS_ENABLED(CONFIG_DNS_RECONFIGURE_CLEANUP) ? - true : false); + true : false, + source); } int dns_resolve_reconfigure(struct dns_resolve_context *ctx, const char *servers[], - const struct sockaddr *servers_sa[]) + const struct sockaddr *servers_sa[], + enum dns_server_source source) { return do_dns_resolve_reconfigure(ctx, servers, servers_sa, NULL, IS_ENABLED(CONFIG_DNS_RECONFIGURE_CLEANUP) ? - true : false); + true : false, + source); } int dns_resolve_remove(struct dns_resolve_context *ctx, int if_index) diff --git a/tests/net/lib/dns_addremove/src/main.c b/tests/net/lib/dns_addremove/src/main.c index 8faf96b49cf..f8f9fdc1c80 100644 --- a/tests/net/lib/dns_addremove/src/main.c +++ b/tests/net/lib/dns_addremove/src/main.c @@ -466,7 +466,8 @@ ZTEST(dns_addremove, test_dns_reconfigure_callback) "Timeout while waiting for DNS added callback"); } - ret = dns_resolve_reconfigure(&resv_ipv4, dns2_servers_str, NULL); + ret = dns_resolve_reconfigure(&resv_ipv4, dns2_servers_str, NULL, + DNS_SOURCE_MANUAL); zassert_equal(ret, 0, "Cannot reconfigure DNS server"); /* Wait for DNS removed callback after reconfiguring DNS */