If network interface is specified in the DNS server, then send the queries to the server via the network interface. Print this information in the server list. Signed-off-by: Jukka Rissanen <jukka.rissanen@nordicsemi.no>
272 lines
6.1 KiB
C
272 lines
6.1 KiB
C
/*
|
|
* Copyright (c) 2016 Intel Corporation
|
|
* Copyright (c) 2023 Nordic Semiconductor ASA
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr/logging/log.h>
|
|
LOG_MODULE_DECLARE(net_shell);
|
|
|
|
#include <zephyr/net/socket.h>
|
|
#include <zephyr/net/dns_resolve.h>
|
|
|
|
#include "net_shell_private.h"
|
|
|
|
#if defined(CONFIG_DNS_RESOLVER)
|
|
static void dns_result_cb(enum dns_resolve_status status,
|
|
struct dns_addrinfo *info,
|
|
void *user_data)
|
|
{
|
|
const struct shell *sh = user_data;
|
|
|
|
if (status == DNS_EAI_CANCELED) {
|
|
PR_WARNING("dns: Timeout while resolving name.\n");
|
|
return;
|
|
}
|
|
|
|
if (status == DNS_EAI_INPROGRESS && info) {
|
|
char addr[NET_IPV6_ADDR_LEN];
|
|
|
|
if (info->ai_family == AF_INET) {
|
|
net_addr_ntop(AF_INET,
|
|
&net_sin(&info->ai_addr)->sin_addr,
|
|
addr, NET_IPV4_ADDR_LEN);
|
|
} else if (info->ai_family == AF_INET6) {
|
|
net_addr_ntop(AF_INET6,
|
|
&net_sin6(&info->ai_addr)->sin6_addr,
|
|
addr, NET_IPV6_ADDR_LEN);
|
|
} else {
|
|
strncpy(addr, "Invalid protocol family",
|
|
sizeof(addr));
|
|
/* strncpy() doesn't guarantee NUL byte at the end. */
|
|
addr[sizeof(addr) - 1] = 0;
|
|
}
|
|
|
|
PR("dns: %s\n", addr);
|
|
return;
|
|
}
|
|
|
|
if (status == DNS_EAI_ALLDONE) {
|
|
PR("dns: All results received\n");
|
|
return;
|
|
}
|
|
|
|
if (status == DNS_EAI_FAIL) {
|
|
PR_WARNING("dns: No such name found.\n");
|
|
return;
|
|
}
|
|
|
|
PR_WARNING("dns: Unhandled status %d received\n", status);
|
|
}
|
|
|
|
static const char *printable_iface(const char *iface_name,
|
|
const char *found,
|
|
const char *not_found)
|
|
{
|
|
if (iface_name[0] != '\0') {
|
|
return found;
|
|
}
|
|
|
|
return not_found;
|
|
}
|
|
|
|
static void print_dns_info(const struct shell *sh,
|
|
struct dns_resolve_context *ctx)
|
|
{
|
|
int i, ret;
|
|
|
|
PR("DNS servers:\n");
|
|
|
|
for (i = 0; i < CONFIG_DNS_RESOLVER_MAX_SERVERS +
|
|
DNS_MAX_MCAST_SERVERS; i++) {
|
|
char iface_name[IFNAMSIZ] = { 0 };
|
|
|
|
if (ctx->servers[i].if_index > 0) {
|
|
ret = net_if_get_name(
|
|
net_if_get_by_index(ctx->servers[i].if_index),
|
|
iface_name, sizeof(iface_name));
|
|
if (ret < 0) {
|
|
snprintk(iface_name, sizeof(iface_name), "%d",
|
|
ctx->servers[i].if_index);
|
|
}
|
|
}
|
|
|
|
if (ctx->servers[i].dns_server.sa_family == AF_INET) {
|
|
PR("\t%s:%u%s%s\n",
|
|
net_sprint_ipv4_addr(
|
|
&net_sin(&ctx->servers[i].dns_server)->
|
|
sin_addr),
|
|
ntohs(net_sin(&ctx->servers[i].dns_server)->sin_port),
|
|
printable_iface(iface_name, " via ", ""),
|
|
printable_iface(iface_name, iface_name, ""));
|
|
|
|
} else if (ctx->servers[i].dns_server.sa_family == AF_INET6) {
|
|
PR("\t[%s]:%u%s%s\n",
|
|
net_sprint_ipv6_addr(
|
|
&net_sin6(&ctx->servers[i].dns_server)->
|
|
sin6_addr),
|
|
ntohs(net_sin6(&ctx->servers[i].dns_server)->sin6_port),
|
|
printable_iface(iface_name, " via ", ""),
|
|
printable_iface(iface_name, iface_name, ""));
|
|
}
|
|
}
|
|
|
|
PR("Pending queries:\n");
|
|
|
|
for (i = 0; i < CONFIG_DNS_NUM_CONCUR_QUERIES; i++) {
|
|
int32_t remaining;
|
|
|
|
if (!ctx->queries[i].cb || !ctx->queries[i].query) {
|
|
continue;
|
|
}
|
|
|
|
remaining = k_ticks_to_ms_ceil32(
|
|
k_work_delayable_remaining_get(&ctx->queries[i].timer));
|
|
|
|
if (ctx->queries[i].query_type == DNS_QUERY_TYPE_A) {
|
|
PR("\tIPv4[%u]: %s remaining %d\n",
|
|
ctx->queries[i].id,
|
|
ctx->queries[i].query,
|
|
remaining);
|
|
} else if (ctx->queries[i].query_type == DNS_QUERY_TYPE_AAAA) {
|
|
PR("\tIPv6[%u]: %s remaining %d\n",
|
|
ctx->queries[i].id,
|
|
ctx->queries[i].query,
|
|
remaining);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static int cmd_net_dns_cancel(const struct shell *sh, size_t argc, char *argv[])
|
|
{
|
|
#if defined(CONFIG_DNS_RESOLVER)
|
|
struct dns_resolve_context *ctx;
|
|
int ret, i;
|
|
#endif
|
|
|
|
ARG_UNUSED(argc);
|
|
ARG_UNUSED(argv);
|
|
|
|
#if defined(CONFIG_DNS_RESOLVER)
|
|
ctx = dns_resolve_get_default();
|
|
if (!ctx) {
|
|
PR_WARNING("No default DNS context found.\n");
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
for (ret = 0, i = 0; i < CONFIG_DNS_NUM_CONCUR_QUERIES; i++) {
|
|
if (!ctx->queries[i].cb) {
|
|
continue;
|
|
}
|
|
|
|
if (!dns_resolve_cancel(ctx, ctx->queries[i].id)) {
|
|
ret++;
|
|
}
|
|
}
|
|
|
|
if (ret) {
|
|
PR("Cancelled %d pending requests.\n", ret);
|
|
} else {
|
|
PR("No pending DNS requests.\n");
|
|
}
|
|
#else
|
|
PR_INFO("Set %s to enable %s support.\n", "CONFIG_DNS_RESOLVER",
|
|
"DNS resolver");
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
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 */
|
|
enum dns_query_type qtype = DNS_QUERY_TYPE_A;
|
|
char *host, *type = NULL;
|
|
int ret, arg = 1;
|
|
|
|
host = argv[arg++];
|
|
if (!host) {
|
|
PR_WARNING("Hostname not specified.\n");
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
if (argv[arg]) {
|
|
type = argv[arg];
|
|
}
|
|
|
|
if (type) {
|
|
if (strcmp(type, "A") == 0) {
|
|
qtype = DNS_QUERY_TYPE_A;
|
|
PR("IPv4 address type\n");
|
|
} else if (strcmp(type, "AAAA") == 0) {
|
|
qtype = DNS_QUERY_TYPE_AAAA;
|
|
PR("IPv6 address type\n");
|
|
} else {
|
|
PR_WARNING("Unknown query type, specify either "
|
|
"A or AAAA\n");
|
|
return -ENOEXEC;
|
|
}
|
|
}
|
|
|
|
ret = dns_get_addr_info(host, qtype, NULL, dns_result_cb,
|
|
(void *)sh, DNS_TIMEOUT);
|
|
if (ret < 0) {
|
|
PR_WARNING("Cannot resolve '%s' (%d)\n", host, ret);
|
|
} else {
|
|
PR("Query for '%s' sent.\n", host);
|
|
}
|
|
#else
|
|
PR_INFO("DNS resolver not supported. Set CONFIG_DNS_RESOLVER to "
|
|
"enable it.\n");
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int cmd_net_dns(const struct shell *sh, size_t argc, char *argv[])
|
|
{
|
|
#if defined(CONFIG_DNS_RESOLVER)
|
|
struct dns_resolve_context *ctx;
|
|
#endif
|
|
|
|
#if defined(CONFIG_DNS_RESOLVER)
|
|
if (argv[1]) {
|
|
/* So this is a query then */
|
|
cmd_net_dns_query(sh, argc, argv);
|
|
return 0;
|
|
}
|
|
|
|
/* DNS status */
|
|
ctx = dns_resolve_get_default();
|
|
if (!ctx) {
|
|
PR_WARNING("No default DNS context found.\n");
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
print_dns_info(sh, ctx);
|
|
#else
|
|
PR_INFO("DNS resolver not supported. Set CONFIG_DNS_RESOLVER to "
|
|
"enable it.\n");
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_dns,
|
|
SHELL_CMD(cancel, NULL, "Cancel all pending requests.",
|
|
cmd_net_dns_cancel),
|
|
SHELL_CMD(query, NULL,
|
|
"'net dns <hostname> [A or AAAA]' queries IPv4 address "
|
|
"(default) or IPv6 address for a host name.",
|
|
cmd_net_dns_query),
|
|
SHELL_SUBCMD_SET_END
|
|
);
|
|
|
|
SHELL_SUBCMD_ADD((net), dns, &net_cmd_dns,
|
|
"Show how DNS is configured. Optionally do a query using a given name.",
|
|
cmd_net_dns, 1, 2);
|