libc/netdb: support multiple DNS nameservers when not using resolv.conf

Signed-off-by: Juha Niskanen <juha.niskanen@haltian.com>
This commit is contained in:
Juha Niskanen 2020-04-24 12:21:37 +03:00 committed by Xiang Xiao
parent ba0a17ca8c
commit b34d7bf56d
8 changed files with 163 additions and 36 deletions

View File

@ -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.
*
****************************************************************************/

View File

@ -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

View File

@ -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)

View File

@ -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.
*
****************************************************************************/

View File

@ -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;
}

View File

@ -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 <nuttx/config.h>
#include <stdbool.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/net/dns.h>
#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 */

View File

@ -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(&copy, &g_dns_servers[i].ipv4, sizeof(struct sockaddr_in));
addr = (FAR struct sockaddr *)&copy;
/* 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(&copy, &g_dns_servers[i].ipv6, sizeof(struct sockaddr_in6));
addr = (FAR struct sockaddr *)&copy;
/* 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;
}

View File

@ -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.
*
****************************************************************************/