From b34d7bf56da4c259af71b34f30549579dc95741a Mon Sep 17 00:00:00 2001 From: Juha Niskanen Date: Fri, 24 Apr 2020 12:21:37 +0300 Subject: [PATCH] libc/netdb: support multiple DNS nameservers when not using resolv.conf Signed-off-by: Juha Niskanen --- include/nuttx/net/dns.h | 12 ++--- libs/libc/netdb/Kconfig | 16 +++++-- libs/libc/netdb/Make.defs | 3 +- libs/libc/netdb/lib_dns.h | 12 +++-- libs/libc/netdb/lib_dnsaddserver.c | 33 +++++++++---- libs/libc/netdb/lib_dnsdefaultserver.c | 66 ++++++++++++++++++++++++++ libs/libc/netdb/lib_dnsforeach.c | 43 +++++++++++++---- libs/libc/netdb/lib_dnsinit.c | 14 ++++-- 8 files changed, 163 insertions(+), 36 deletions(-) create mode 100644 libs/libc/netdb/lib_dnsdefaultserver.c diff --git a/include/nuttx/net/dns.h b/include/nuttx/net/dns.h index 04e44c5784..12b5675135 100644 --- a/include/nuttx/net/dns.h +++ b/include/nuttx/net/dns.h @@ -136,7 +136,7 @@ * Public Type Definitions ****************************************************************************/ - /* The DNS message header */ +/* The DNS message header */ struct dns_header_s { @@ -208,20 +208,20 @@ extern "C" int dns_add_nameserver(FAR const struct sockaddr *addr, socklen_t addrlen); /**************************************************************************** - * Name: dns_del_nameserver + * Name: dns_default_nameserver * * Description: - * Remove a DNS server so it is no longer available for further use. + * Reset the resolver to use only the default DNS server, if any. * ****************************************************************************/ -/* REVISIT: Not implemented */ + +int dns_default_nameserver(void); /**************************************************************************** * Name: dns_foreach_nameserver * * Description: - * Traverse each nameserver entry in the resolv.conf file and perform the - * the provided callback. + * Traverse each nameserver entry and perform the provided callback. * ****************************************************************************/ diff --git a/libs/libc/netdb/Kconfig b/libs/libc/netdb/Kconfig index b205732c70..3478001e62 100644 --- a/libs/libc/netdb/Kconfig +++ b/libs/libc/netdb/Kconfig @@ -76,7 +76,7 @@ config NETDB_DNSCLIENT_ENTRIES cached and if the name mapping can be found in that cache, the network query can be avoid. Of course, this is only useful if you query the same name often and if the IP address of the name is - stable. If the IP address can change, then cachin DNS address + stable. If the IP address can change, then caching DNS address might have undesirable side-effects (see help for CONFIG_NETDB_DNSCLIENT_LIFESEC). @@ -155,6 +155,14 @@ config NETDB_RESOLVCONF_NONSTDPORT endif # NETDB_RESOLVCONF +config NETDB_DNSSERVER_NAMESERVERS + int "Max number of configured nameservers" + default 1 + depends on !NETDB_RESOLVCONF + ---help--- + This setting determines how many nameservers there can be + in use concurrently. + choice prompt "DNS server address type" default NETDB_DNSSERVER_IPv4 if NET_IPv4 @@ -166,7 +174,7 @@ config NETDB_DNSSERVER_NOADDR bool "No default DNS server address" ---help--- There is not default DNS nameserver address. Application must call - dns_add_server() at runtime to add the DNS server address. + dns_add_nameserver() at runtime to add the DNS server address. config NETDB_DNSSERVER_IPv4 bool "IPv4 DNS server address" @@ -174,7 +182,7 @@ config NETDB_DNSSERVER_IPv4 ---help--- An IPv4 default DNS nameserver address will be provided. Application may overwrite this start default server address by calling - dns_add_server() at runtime. + dns_add_nameserver() at runtime. config NETDB_DNSSERVER_IPv6 bool "IPv6 DNS server address" @@ -182,7 +190,7 @@ config NETDB_DNSSERVER_IPv6 ---help--- An IPv6 default DNS nameserver address will be provided. Application may overwrite this start default server address by calling - dns_add_server() at runtime. + dns_add_nameserver() at runtime. endchoice # DNS server address type diff --git a/libs/libc/netdb/Make.defs b/libs/libc/netdb/Make.defs index 56256bb488..cdd79c5a57 100644 --- a/libs/libc/netdb/Make.defs +++ b/libs/libc/netdb/Make.defs @@ -55,7 +55,8 @@ endif # Add DNS lookup support ifeq ($(CONFIG_NETDB_DNSCLIENT),y) -CSRCS += lib_dnsinit.c lib_dnsbind.c lib_dnsquery.c lib_dnsaddserver.c +CSRCS += lib_dnsinit.c lib_dnsbind.c lib_dnsquery.c +CSRCS += lib_dnsaddserver.c lib_dnsdefaultserver.c CSRCS += lib_dnsforeach.c lib_dnsnotify.c ifneq ($(CONFIG_NETDB_DNSCLIENT_ENTRIES),0) diff --git a/libs/libc/netdb/lib_dns.h b/libs/libc/netdb/lib_dns.h index 6a2b2fc4f7..95e2dcc81a 100644 --- a/libs/libc/netdb/lib_dns.h +++ b/libs/libc/netdb/lib_dns.h @@ -80,6 +80,10 @@ # define CONFIG_NETDB_RESOLVCONF_PATH "/etc/resolv.conf" #endif +#ifndef CONFIG_NETDB_DNSSERVER_NAMESERVERS +# define CONFIG_NETDB_DNSSERVER_NAMESERVERS 1 +#endif + #define DNS_MAX_ADDRSTR 48 #define DNS_MAX_LINE 64 #define NETDB_DNS_KEYWORD "nameserver" @@ -117,10 +121,10 @@ extern "C" #endif #ifndef CONFIG_NETDB_RESOLVCONF -/* The DNS server address */ +/* The DNS server addresses */ -EXTERN union dns_addr_u g_dns_server; -EXTERN bool g_dns_address; /* true: We have the address of the DNS server */ +EXTERN union dns_addr_u g_dns_servers[]; +EXTERN uint8_t g_dns_nservers; #endif /**************************************************************************** @@ -141,7 +145,7 @@ bool dns_initialize(void); * Name: dns_semtake * * Description: - * Take the DNS semaphore, ignoring errors do to the receipt of signals. + * Take the DNS semaphore, ignoring errors due to the receipt of signals. * ****************************************************************************/ diff --git a/libs/libc/netdb/lib_dnsaddserver.c b/libs/libc/netdb/lib_dnsaddserver.c index 65fedbdd07..4bad46ba78 100644 --- a/libs/libc/netdb/lib_dnsaddserver.c +++ b/libs/libc/netdb/lib_dnsaddserver.c @@ -43,10 +43,10 @@ ****************************************************************************/ #ifndef CONFIG_NETDB_RESOLVCONF -/* The DNS server address */ +/* The DNS server addresses */ -union dns_addr_u g_dns_server; -bool g_dns_address; /* true: We have the address of the DNS server */ +union dns_addr_u g_dns_servers[CONFIG_NETDB_DNSSERVER_NAMESERVERS]; +uint8_t g_dns_nservers; /* Number of currently configured nameservers */ #endif /**************************************************************************** @@ -198,10 +198,24 @@ int dns_add_nameserver(FAR const struct sockaddr *addr, socklen_t addrlen) { FAR uint16_t *pport; size_t copylen; + int nservers; + int idx; DEBUGASSERT(addr != NULL); - /* Copy the new server IP address into our private global data structure */ + /* Get the index of the next free nameserver slot. */ + + dns_semtake(); + if (g_dns_nservers == CONFIG_NETDB_DNSSERVER_NAMESERVERS) + { + idx = 0; + nservers = g_dns_nservers; + } + else + { + idx = g_dns_nservers; + nservers = idx + 1; + } #ifdef CONFIG_NET_IPv4 /* Check for an IPv4 address */ @@ -211,7 +225,7 @@ int dns_add_nameserver(FAR const struct sockaddr *addr, socklen_t addrlen) /* Set up for the IPv4 address copy */ copylen = sizeof(struct sockaddr_in); - pport = &g_dns_server.ipv4.sin_port; + pport = &g_dns_servers[idx].ipv4.sin_port; } else #endif @@ -224,12 +238,13 @@ int dns_add_nameserver(FAR const struct sockaddr *addr, socklen_t addrlen) /* Set up for the IPv6 address copy */ copylen = sizeof(struct sockaddr_in6); - pport = &g_dns_server.ipv6.sin6_port; + pport = &g_dns_servers[idx].ipv6.sin6_port; } else #endif { nerr("ERROR: Unsupported family: %d\n", addr->sa_family); + dns_semgive(); return -ENOSYS; } @@ -239,10 +254,11 @@ int dns_add_nameserver(FAR const struct sockaddr *addr, socklen_t addrlen) { nerr("ERROR: Invalid addrlen %ld for family %d\n", (long)addrlen, addr->sa_family); + dns_semgive(); return -EINVAL; } - memcpy(&g_dns_server.addr, addr, copylen); + memcpy(&g_dns_servers[idx].addr, addr, copylen); /* A port number of zero means to use the default DNS server port number */ @@ -253,7 +269,8 @@ int dns_add_nameserver(FAR const struct sockaddr *addr, socklen_t addrlen) /* We now have a valid DNS address */ - g_dns_address = true; + g_dns_nservers = nservers; + dns_semgive(); dns_notify_nameserver(addr, addrlen); return OK; } diff --git a/libs/libc/netdb/lib_dnsdefaultserver.c b/libs/libc/netdb/lib_dnsdefaultserver.c new file mode 100644 index 0000000000..5511e02b64 --- /dev/null +++ b/libs/libc/netdb/lib_dnsdefaultserver.c @@ -0,0 +1,66 @@ +/**************************************************************************** + * libs/libc/netdb/lib_dnsdefaultserver.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include + +#include "netdb/lib_dns.h" + +#ifdef CONFIG_NETDB_DNSCLIENT + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: dns_default_nameserver + * + * Description: + * Reset the resolver to use only the default DNS server, if any. + * + ****************************************************************************/ + +#ifdef CONFIG_NETDB_RESOLVCONF +int dns_default_nameserver(void) +{ + /* REVISIT: not implemented */ + + return -ENOSYS; +} +#else /* CONFIG_NETDB_RESOLVCONF */ +int dns_default_nameserver(void) +{ + dns_semtake(); + g_dns_nservers = 0; + dns_semgive(); + return OK; +} +#endif /* CONFIG_NETDB_RESOLVCONF */ +#endif /* CONFIG_NETDB_DNSCLIENT */ diff --git a/libs/libc/netdb/lib_dnsforeach.c b/libs/libc/netdb/lib_dnsforeach.c index 5543820b32..4d80c09729 100644 --- a/libs/libc/netdb/lib_dnsforeach.c +++ b/libs/libc/netdb/lib_dnsforeach.c @@ -81,7 +81,7 @@ static FAR char *find_spaces(FAR char *ptr) * Name: dns_foreach_nameserver * * Description: - * Traverse each nameserver entry in the resolv.conf file and perform the + * Traverse each nameserver entry in the resolv.conf file and perform * the provided callback. * ****************************************************************************/ @@ -247,19 +247,30 @@ int dns_foreach_nameserver(dns_callback_t callback, FAR void *arg) int dns_foreach_nameserver(dns_callback_t callback, FAR void *arg) { + FAR struct sockaddr *addr; int ret = OK; + int i; - if (g_dns_address) + dns_semtake(); + for (i = 0; i < g_dns_nservers; i++) { #ifdef CONFIG_NET_IPv4 /* Check for an IPv4 address */ - if (g_dns_server.addr.sa_family == AF_INET) + if (g_dns_servers[i].addr.sa_family == AF_INET) { + struct sockaddr_in copy; + + /* Operate on copy of server address, in case it changes. */ + + memcpy(©, &g_dns_servers[i].ipv4, sizeof(struct sockaddr_in)); + addr = (FAR struct sockaddr *)© + /* Perform the callback */ - ret = callback(arg, (FAR struct sockaddr *)&g_dns_server.ipv4, - sizeof(struct sockaddr_in)); + dns_semgive(); + ret = callback(arg, addr, sizeof(struct sockaddr_in)); + dns_semtake(); } else #endif @@ -267,22 +278,36 @@ int dns_foreach_nameserver(dns_callback_t callback, FAR void *arg) #ifdef CONFIG_NET_IPv6 /* Check for an IPv6 address */ - if (g_dns_server.addr.sa_family == AF_INET6) + if (g_dns_servers[i].addr.sa_family == AF_INET6) { + struct sockaddr_in6 copy; + + /* Operate on copy of server address, in case it changes. */ + + memcpy(©, &g_dns_servers[i].ipv6, sizeof(struct sockaddr_in6)); + addr = (FAR struct sockaddr *)© + /* Perform the callback */ - ret = callback(arg, (FAR struct sockaddr *)&g_dns_server.ipv6, - sizeof(struct sockaddr_in6)); + dns_semgive(); + ret = callback(arg, addr, sizeof(struct sockaddr_in6)); + dns_semtake(); } else #endif { nerr("ERROR: Unsupported family: %d\n", - g_dns_server.addr.sa_family); + g_dns_servers[i].addr.sa_family); ret = -ENOSYS; } + + if (ret != OK) + { + break; + } } + dns_semgive(); return ret; } diff --git a/libs/libc/netdb/lib_dnsinit.c b/libs/libc/netdb/lib_dnsinit.c index efc6a1fe53..09c28474a5 100644 --- a/libs/libc/netdb/lib_dnsinit.c +++ b/libs/libc/netdb/lib_dnsinit.c @@ -54,7 +54,7 @@ * Private Data ****************************************************************************/ -/* Protects g_seqno, DNS cache and notify */ +/* Protects DNS cache, nameserver list and notify list. */ static sem_t g_dns_sem = SEM_INITIALIZER(1); @@ -94,9 +94,15 @@ static const uint16_t g_ipv6_hostaddr[8] = bool dns_initialize(void) { #ifndef CONFIG_NETDB_RESOLVCONF - /* Has the DNS server IP address been assigned? */ + int nservers; - if (!g_dns_address) + dns_semtake(); + nservers = g_dns_nservers; + dns_semgive(); + + /* Has at least one DNS server IP address been assigned? */ + + if (nservers == 0) { #if defined(CONFIG_NETDB_DNSSERVER_IPv4) struct sockaddr_in addr4; @@ -147,7 +153,7 @@ bool dns_initialize(void) * Name: dns_semtake * * Description: - * Take the DNS semaphore, ignoring errors do to the receipt of signals. + * Take the DNS semaphore, ignoring errors due to the receipt of signals. * ****************************************************************************/