diff --git a/libc/netdb/lib_dns.h b/libc/netdb/lib_dns.h index 826b4c94c37..0f2544df7b5 100644 --- a/libc/netdb/lib_dns.h +++ b/libc/netdb/lib_dns.h @@ -74,17 +74,39 @@ # define CONFIG_NETDB_DNSCLIENT_LIFESEC 3600 #endif +#ifndef CONFIG_NETDB_RESOLVCONF_PATH +# define CONFIG_NETDB_RESOLVCONF_PATH "/etc/resolv.conf" +#endif + #define DNS_MAX_LINE 80 #define NETDB_DNS_KEYWORD "nameserver" /**************************************************************************** * Public Types ****************************************************************************/ +/* This describes either an IPv4 or IPv6 address. It is essentially a named + * alternative to sockaddr_storage. + */ -typedef CODE int (*dns_callback_t)(FAR void *arg, int af, FAR void *addr); +union dns_server_u +{ + struct sockaddr addr; /* Common address representation */ +#ifdef CONFIG_NET_IPv4 + struct sockaddr_in ipv4; /* IPv4 address */ +#endif +#ifdef CONFIG_NET_IPv6 + struct sockaddr_in6 ipv6; /* IPv6 address */ +#endif +}; + +/* The type of the callback from dns_foreach_nameserver() */ + +typedef CODE int (*dns_callback_t)(FAR void *arg, + FAR struct sockaddr *addr, + FAR socklen_t *addrlen); /**************************************************************************** - * Public Function Prototypes + * Public Data ****************************************************************************/ #undef EXTERN @@ -96,6 +118,17 @@ extern "C" #define EXTERN extern #endif +#ifndef CONFIG_NETDB_RESOLVCONF +/* The DNS server address */ + +EXTERN union dns_server_u g_dns_server; +EXTERN bool g_dns_address; /* true: We have the address of the DNS server */ +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + /**************************************************************************** * Name: dns_bind * diff --git a/libc/netdb/lib_dnsaddserver.c b/libc/netdb/lib_dnsaddserver.c new file mode 100644 index 00000000000..2cbc68644b1 --- /dev/null +++ b/libc/netdb/lib_dnsaddserver.c @@ -0,0 +1,211 @@ +/**************************************************************************** + * libc/netdb/lib_dnsaddserver.c + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "netdb/lib_dns.h" + +#ifdef CONFIG_NETDB_DNSCLIENT + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef CONFIG_NETDB_RESOLVCONF +/* The DNS server address */ + +union dns_server_u g_dns_server; +bool g_dns_address; /* true: We have the address of the DNS server */ +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: dns_add_nameserver + * + * Description: + * Configure which DNS server to use for queries + * + ****************************************************************************/ + +#ifdef CONFIG_NETDB_RESOLVCONF +int dns_add_nameserver(FAR const struct sockaddr *addr, socklen_t addrlen) +{ + FAR FILE *stream; + char line[DNS_MAX_LINE]; + int ret = OK; + + stream = fopen(CONFIG_NETDB_RESOLVCONF, "at"); + if (stream == NULL) + { + int errcode = errno; + ndbg("ERROR: Failed to open %s: %d\n", + CONFIG_NETDB_RESOLVCONF, errcode); + DEBUGASSERT(errcode > 0); + return -errcode; + } + +#ifdef CONFIG_NET_IPv4 + /* Check for an IPv4 address */ + + if (addr->sa_family == AF_INET) + { + if (socklen < sizeof(struct sockaddr_in)) + { + ret = -EINVAL; + } + else + { + FAR struct sockaddr_in *in4 = (FAR struct sockaddr_in *)addr; + + if (inet_ntop(AF_INET, &in4->sin_addr, line, DNS_MAX_LINE) == NULL) + { + int errcode = errno; + ndbg("ERROR: inet_ntop failed: %d\n", errcode); + DEBUGASSERT(errcode > 0); + ret = -errcode; + } + } + else +#endif + +#ifdef CONFIG_NET_IPv6 + /* Check for an IPv4 address */ + + if (addr->sa_family == AF_INET6) + { + if (socklen < sizeof(struct sockaddr_in6)) + { + ret = -EINVAL; + } + else + { + FAR struct sockaddr_in6 *in6 = (FAR struct sockaddr_in6 *)addr; + + if (inet_ntop(AF_INET6, &in6->sin6_addr, line, DNS_MAX_LINE) == NULL) + { + int errcode = errno; + ndbg("ERROR: inet_ntop failed: %d\n", errcode); + DEBUGASSERT(errcode > 0); + return -errcode; + } + } + else +#endif + { + nvdbg("ERROR: Unsupported family: %d\n", + g_dns_server.addr.sa_family); + ret = -ENOSYS; + } + + fclose(stream); + return ret; +} + +#else /* CONFIG_NETDB_RESOLVCONF */ + +int dns_add_nameserver(FAR const struct sockaddr *addr, socklen_t addrlen) +{ + FAR uint16_t *pport; + size_t copylen; + + DEBUGASSERT(addr != NULL); + + /* Copy the new server IP address into our private global data structure */ + +#ifdef CONFIG_NET_IPv4 + /* Check for an IPv4 address */ + + if (addr->sa_family == AF_INET) + { + /* Set up for the IPv4 address copy */ + + copylen = sizeof(struct sockaddr_in); + pport = &g_dns_server.ipv4.sin_port; + } + else +#endif + +#ifdef CONFIG_NET_IPv6 + /* Check for an IPv6 address */ + + if (addr->sa_family == AF_INET6) + { + /* Set up for the IPv6 address copy */ + + copylen = sizeof(struct sockaddr_in6); + pport = &g_dns_server.ipv6.sin6_port; + } + else +#endif + { + nvdbg("ERROR: Unsupported family: %d\n", addr->sa_family); + return -ENOSYS; + } + + /* Copy the IP address */ + + if (addrlen < copylen) + { + nvdbg("ERROR: Invalid addrlen %ld for family %d\n", + (long)addrlen, addr->sa_family); + return -EINVAL; + } + + memcpy(&g_dns_server.addr, addr, copylen); + + /* A port number of zero means to use the default DNS server port number */ + + if (*pport == 0) + { + *pport = HTONS(DNS_DEFAULT_PORT); + } + + /* We now have a valid DNS address */ + + g_dns_address = true; + return OK; +#endif /* CONFIG_NETDB_RESOLVCONF */ +} + +#endif /* CONFIG_NETDB_DNSCLIENT */ diff --git a/libc/netdb/lib_dnsclient.c b/libc/netdb/lib_dnsclient.c index 70f1eb4af57..be87213029c 100644 --- a/libc/netdb/lib_dnsclient.c +++ b/libc/netdb/lib_dnsclient.c @@ -89,20 +89,6 @@ /**************************************************************************** * Private Types ****************************************************************************/ -/* This describes either an IPv4 or IPv6 address. It is essentially a named - * alternative to sockaddr_storage. - */ - -union dns_server_u -{ - struct sockaddr addr; /* Common address representation */ -#ifdef CONFIG_NET_IPv4 - struct sockaddr_in ipv4; /* IPv4 address */ -#endif -#ifdef CONFIG_NET_IPv6 - struct sockaddr_in6 ipv6; /* IPv6 address */ -#endif -}; #if CONFIG_NETDB_DNSCLIENT_ENTRIES > 0 /* This described one entry in the cache of resolved hostnames */ @@ -123,17 +109,12 @@ struct dns_cache_s static sem_t g_dns_sem; /* Protects g_seqno and DNS cache */ static bool g_dns_initialized; /* DNS data structures initialized */ -static bool g_dns_address; /* We have the address of the DNS server */ #if CONFIG_NETDB_DNSCLIENT_ENTRIES > 0 static uint8_t g_dns_head; /* Head of the circular, DNS resolver cache */ static uint8_t g_dns_tail; /* Tail of the circular, DNS resolver cache */ #endif static uint8_t g_seqno; /* Sequence number of the next request */ -/* The DNS server address */ - -static union dns_server_u g_dns_server; - #ifdef CONFIG_NETDB_DNSSERVER_IPv6 /* This is the default IPv6 DNS server address */ @@ -877,52 +858,6 @@ int dns_query(int sd, FAR const char *hostname, FAR struct sockaddr *addr, return -ETIMEDOUT; } -/**************************************************************************** - * Name: dns_getserver - * - * Description: - * Obtain the currently configured DNS server. - * - ****************************************************************************/ - -int dns_getserver(FAR struct sockaddr *addr, FAR socklen_t *addrlen) -{ - socklen_t copylen; - - DEBUGASSERT(addr != NULL && addrlen != NULL); - -#ifdef CONFIG_NET_IPv4 -#ifdef CONFIG_NET_IPv6 - if (g_dns_server.addr.sa_family == AF_INET) -#endif - { - copylen = sizeof(struct sockaddr_in); - } -#endif - -#ifdef CONFIG_NET_IPv6 -#ifdef CONFIG_NET_IPv4 - else -#endif - { - copylen = sizeof(struct sockaddr_in6); - } -#endif - - /* Copy the DNS server address to the caller-provided buffer */ - - if (copylen > *addrlen) - { - nvdbg("ERROR: addrlen %ld too small for address family %d\n", - (long)addrlen, g_dns_server.addr.sa_family); - return -EINVAL; - } - - memcpy(addr, &g_dns_server.addr, copylen); - *addrlen = copylen; - return OK; -} - /**************************************************************************** * Name: dns_find_answer * diff --git a/libc/netdb/lib_dnsforeach.c b/libc/netdb/lib_dnsforeach.c new file mode 100644 index 00000000000..ca6c01ee6f8 --- /dev/null +++ b/libc/netdb/lib_dnsforeach.c @@ -0,0 +1,215 @@ +/**************************************************************************** + * libc/netdb/lib_dnsforeach.c + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "netdb/lib_dns.h" + +#ifdef CONFIG_NETDB_DNSCLIENT + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static FAR char *skip_spaces(FAR char *ptr) +{ + while (isspace(*ptr)) ptr++; + return ptr; +} + +static FAR char *find_spaces(FAR char *ptr) +{ + while (isspace(*ptr)) ptr++; + return ptr; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: dns_foreach_nameserver + * + * Description: + * Traverse each nameserver entry in the resolv.conf file and perform the + * the provided callback. + * + ****************************************************************************/ + +#ifdef CONFIG_NETDB_RESOLVCONF + +int dns_foreach_nameserver(dns_callback_t callback, FAR void *arg) +{ + union dns_server_u u; + FAR FILE *stream; + char line[DNS_MAX_LINE]; + FAR char *ptr; + int keylen; + int ret; + + /* Open the resolver configuration file */ + + stream = fopen(CONFIG_NETDB_RESOLVCONF, "rb"); + if (stream == NULL) + { + int errcode = errno; + ndbg("ERROR: Failed to open %s: %d\n", + CONFIG_NETDB_RESOLVCONF, errcode); + DEBUGASSERT(errcode > 0); + return -errcode; + } + + keylen = strlen(NETDB_DNS_KEYWORD); + while (fgets(line, DNS_MAX_LINE, stream) != NULL) + { + ptr = skip_spaces(line); + if (strncmp(ptr, NETDB_DNS_KEYWORD, keylen) == 0) + { + socklen_t copylen; + + /* REVISIT: We really need a customizable port number. The + * OpenBSD version supports a [host]:port syntax. When a + * non-standard port is specified the host address must be + * enclosed in square brackets. For example: + * + * nameserver [10.0.0.1]:5353 + * nameserver [::1]:5353 + */ + +#ifdef CONFIG_NET_IPv4 + /* Try to convert the IPv4 address */ + + ret = inet_pton(AF_INET, ptr, &u.ipv4.sin_addr); + + /* The inet_pton() function returns 1 if the conversion succeeds */ + + if (ret == 1) + { + /* REVISIT: We really need a customizable port number */ + + u.ipv4.sin_family = AF_INET; + u.ipv4.sin_port = DNS_DEFAULT_PORT; + ret = callback(arg, AF_INET, &u.ipv4, sizeof(struct sockaddr_in)); + } + else +#endif +#ifdef CONFIG_NET_IPv6 + { + /* Try to convert the IPv6 address */ + + ret = inet_pton(AF_INET6, ptr, &u.ipv6.sin6_addr); + + /* The inet_pton() function returns 1 if the conversion + * succeeds. + */ + + if (ret == 1) + { + /* REVISIT: We really need a customizable port number */ + + u.ipv6.sin6_family = AF_INET6; + u.ipv6.sin6_port = DNS_DEFAULT_PORT; + ret = callback(arg, &u.ipv6, sizeof(struct sockaddr_in6)); + } + else +#endif + { + ndbg("ERROR: Unrecognized address: %s\n", ptr) + ret = OK; + } +#ifdef CONFIG_NET_IPv6 + } +#endif + if (ret != OK) + { + fclose(stream); + return ret; + } + } + } + + fclose(stream); + return OK; +} + +#else /* CONFIG_NETDB_RESOLVCONF */ + +int dns_foreach_nameserver(dns_callback_t callback, FAR void *arg) +{ + int ret = OK; + + if (g_dns_address) + { +#ifdef CONFIG_NET_IPv4 + /* Check for an IPv4 address */ + + if (g_dns_server.addr.sa_family == AF_INET) + { + /* Perform the callback */ + + ret = callback(arg, &g_dns_server.ipv4, sizeof(struct sockaddr_in); + } + else +#endif + +#ifdef CONFIG_NET_IPv6 + /* Check for an IPv6 address */ + + if (g_dns_server.addr.sa_family == AF_INET6) + { + /* Perform the callback */ + + ret = callback(arg, &g_dns_server.ipv6, sizeof(struct sockaddr_in6); + } + else +#endif + { + nvdbg("ERROR: Unsupported family: %d\n", + g_dns_server.addr.sa_family); + ret = -ENOSYS; + } + } + + return ret; +} + +#endif /* CONFIG_NETDB_RESOLVCONF */ +#endif /* CONFIG_NETDB_DNSCLIENT */