From a3614c19e565a23b4f805c0999521583324bd7b3 Mon Sep 17 00:00:00 2001 From: Charles Hardin Date: Wed, 8 Oct 2025 16:14:19 -0700 Subject: [PATCH] net: dns: extend the service resolver command line for ptr, srv, addr The address resoution from RFC6763 is generally a PTR, SRV, TXT, and an A or AAAA. Records, so this change is mainly to start drawing a clear functional change between the DNS query shell and the DNS service shell that should be more of a "avahi-browse" or "dns-sd" functional style. So, this is not a very robust implementation since it is a chain of queries when the goal should be to get additional records from the message itself but those changes can be added iteratively. Basic point of this change is to show the procedure for the "browse" - PTR service resolution - SRV query from the result of the PTR - AAAA (or A) from the result of the SRV TXT records are ignored for now but should be added into this as additional record support is extended. Signed-off-by: Charles Hardin --- subsys/net/lib/shell/dns.c | 134 ++++++++++++++++++++++++++++++++++--- 1 file changed, 126 insertions(+), 8 deletions(-) diff --git a/subsys/net/lib/shell/dns.c b/subsys/net/lib/shell/dns.c index 4e04f4580ef3e..53838952c95da 100644 --- a/subsys/net/lib/shell/dns.c +++ b/subsys/net/lib/shell/dns.c @@ -70,7 +70,7 @@ static void dns_result_cb(enum dns_resolve_status status, break; } - /* fallthru */ + __fallthrough; default: strncpy(str, "Invalid proto family", MAX_STR_LEN + 1); break; @@ -95,6 +95,31 @@ static void dns_result_cb(enum dns_resolve_status status, PR_WARNING("dns: Unhandled status %d received (errno %d)\n", status, errno); } +K_MSGQ_DEFINE(dns_infoq, sizeof(struct dns_addrinfo), 3, 1); + +static void dns_service_cb(enum dns_resolve_status status, + struct dns_addrinfo *info, + void *user_data) +{ + int r; + const struct shell *sh = user_data; + + if (status == DNS_EAI_CANCELED) { + PR_WARNING("dns: Timeout while resolving service.\n"); + return; + } + + if ((status == DNS_EAI_INPROGRESS) && (info != NULL)) { + /* + * Only queue results that can be further processed. + */ + r = k_msgq_put(&dns_infoq, info, K_NO_WAIT); + if (r < 0) { + PR_WARNING("dns: k_msgq_put error %d", r); + } + } +} + static const char *printable_iface(const char *iface_name, const char *found, const char *not_found) @@ -237,7 +262,7 @@ static int cmd_net_dns_query(const struct shell *sh, size_t argc, char *argv[]) { #if defined(CONFIG_DNS_RESOLVER) -#define DNS_TIMEOUT (MSEC_PER_SEC * 2) /* ms */ +#define DNS_QUERY_TIMEOUT (MSEC_PER_SEC * 2) /* ms */ struct dns_resolve_context *ctx; enum dns_query_type qtype = DNS_QUERY_TYPE_A; char *host, *type = NULL; @@ -286,7 +311,7 @@ static int cmd_net_dns_query(const struct shell *sh, size_t argc, char *argv[]) } ret = dns_resolve_name(ctx, host, qtype, NULL, dns_result_cb, - (void *)sh, DNS_TIMEOUT); + (void *)sh, DNS_QUERY_TIMEOUT); if (ret < 0) { PR_WARNING("Cannot resolve '%s' (%d)\n", host, ret); } else { @@ -378,9 +403,11 @@ static int cmd_net_dns_list(const struct shell *sh, size_t argc, char *argv[]) static int cmd_net_dns_service(const struct shell *sh, size_t argc, char *argv[]) { #if defined(CONFIG_DNS_RESOLVER) -#define DNS_TIMEOUT (MSEC_PER_SEC * 2) /* ms */ +#define DNS_SERVICE_TIMEOUT (MSEC_PER_SEC * 4) /* ms */ struct dns_resolve_context *ctx; + char *cp; char *service; + uint16_t port; uint16_t dns_id; int ret, arg = 1; @@ -390,18 +417,109 @@ static int cmd_net_dns_service(const struct shell *sh, size_t argc, char *argv[] return -ENOEXEC; } + /* remove any lingering info data */ + k_msgq_purge(&dns_infoq); + ctx = dns_resolve_get_default(); if (ctx == NULL) { PR_WARNING("No default DNS context found.\n"); return -ENOEXEC; } - ret = dns_resolve_service(ctx, service, &dns_id, dns_result_cb, - (void *)sh, DNS_TIMEOUT); + ret = dns_resolve_service(ctx, service, &dns_id, dns_service_cb, + (void *)sh, DNS_SERVICE_TIMEOUT); if (ret < 0) { PR_WARNING("Cannot resolve '%s' (%d)\n", service, ret); - } else { - PR("Query for '%s' sent.\n", service); + return ret; + } + + PR("Resolve for '%s' service sent.\n", service); + port = 0; + for (;;) { + struct dns_addrinfo info; + enum dns_query_type qtype; + char query[DNS_MAX_NAME_SIZE + 1]; + union { + char in4[INET_ADDRSTRLEN]; + char in6[INET6_ADDRSTRLEN]; + } str; + + ret = k_msgq_get(&dns_infoq, &info, K_MSEC(DNS_SERVICE_TIMEOUT)); + if (ret < 0) { + /* just assume a timeout so no more data to process */ + break; + } + + switch (info.ai_family) { + case AF_INET: + cp = net_addr_ntop(AF_INET, + &net_sin(&info.ai_addr)->sin_addr, + str.in4, sizeof(str.in4)); + PR("AF_INET %s:%u\n", cp ? cp : "", port); + break; + + case AF_INET6: + cp = net_addr_ntop(AF_INET6, + &net_sin6(&info.ai_addr)->sin6_addr, + str.in6, sizeof(str.in6)); + PR("AF_INET6 [%s]:%u\n", cp ? cp : "", port); + break; + + case AF_LOCAL: + PR("AF_LOCAL %.*s\n", + (int)info.ai_addrlen, info.ai_canonname); + + snprintf(query, sizeof(query), "%.*s", + info.ai_addrlen, info.ai_canonname); + + qtype = DNS_QUERY_TYPE_SRV; + ret = dns_resolve_name(ctx, query, qtype, + &dns_id, + dns_service_cb, (void *)sh, + DNS_SERVICE_TIMEOUT); + if (ret < 0) { + return ret; + } + break; + + case AF_UNSPEC: + if (info.ai_extension == DNS_RESOLVE_SRV) { + PR("SRV %d %d %d %.*s\n", + info.ai_srv.priority, + info.ai_srv.weight, + info.ai_srv.port, + (int)info.ai_srv.targetlen, + info.ai_srv.target); + + port = info.ai_srv.port; + + snprintf(query, sizeof(query), "%.*s", + info.ai_srv.targetlen, + info.ai_srv.target); + + /* + * Sending a query for both AAAA and A records + * should be ok, but the resolver doesn't + * gracefully handle the query for different + * types. + */ + qtype = DNS_QUERY_TYPE_AAAA; + ret = dns_resolve_name(ctx, query, qtype, + &dns_id, + dns_service_cb, + (void *)sh, + DNS_SERVICE_TIMEOUT); + if (ret < 0) { + return ret; + } + break; + } + + __fallthrough; + default: + PR_WARNING("dns: unhandled info %u on msgq\n", info.ai_family); + break; + } } #else PR_INFO("DNS resolver not supported. Set CONFIG_DNS_RESOLVER to "