summaryrefslogtreecommitdiff
path: root/apps/netutils/dnsclient
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2014-04-11 12:41:13 -0600
committerGregory Nutt <gnutt@nuttx.org>2014-04-11 12:41:13 -0600
commit7150125fb8f7eba8ec7bf04112a6ca5cd23fc2e0 (patch)
tree9debe9e1dafba8f3c7f81e75c8c0850c9903ce6e /apps/netutils/dnsclient
parent57d2acba435f67d561b63e6635330f182edc5047 (diff)
downloadnuttx-7150125fb8f7eba8ec7bf04112a6ca5cd23fc2e0.tar.gz
nuttx-7150125fb8f7eba8ec7bf04112a6ca5cd23fc2e0.tar.bz2
nuttx-7150125fb8f7eba8ec7bf04112a6ca5cd23fc2e0.zip
The rest of the resolv->DNS client naming change: Renamed directories and header files
Diffstat (limited to 'apps/netutils/dnsclient')
-rw-r--r--apps/netutils/dnsclient/.gitignore6
-rw-r--r--apps/netutils/dnsclient/Kconfig29
-rw-r--r--apps/netutils/dnsclient/Makefile100
-rw-r--r--apps/netutils/dnsclient/dnsclient.c723
4 files changed, 858 insertions, 0 deletions
diff --git a/apps/netutils/dnsclient/.gitignore b/apps/netutils/dnsclient/.gitignore
new file mode 100644
index 000000000..f21c854d1
--- /dev/null
+++ b/apps/netutils/dnsclient/.gitignore
@@ -0,0 +1,6 @@
+/.built
+/.depend
+/Make.dep
+/*.src
+/*.obj
+/*.lst
diff --git a/apps/netutils/dnsclient/Kconfig b/apps/netutils/dnsclient/Kconfig
new file mode 100644
index 000000000..77b2bd634
--- /dev/null
+++ b/apps/netutils/dnsclient/Kconfig
@@ -0,0 +1,29 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+
+config NETUTILS_DNSCLIENT
+ bool "DNS Name resolution"
+ default n
+ depends on NET && NET_UDP && NET_BROADCAST
+ ---help---
+ Enable support for the name resolution.
+
+if NETUTILS_DNSCLIENT
+
+config NETUTILS_DNSCLIENT_ENTRIES
+ int "Number of DNS resolver entries"
+ default 8
+ ---help---
+ Number of DNS resolver entries. Default: 8
+
+config NETUTILS_DNSCLIENT_MAXRESPONSE
+ int "Max response size"
+ default 96
+ ---help---
+ This setting determines the maximum size of response message that
+ can be received by the DNS resolver. The default is 96 but may
+ need to be larger on enterprise networks (perhaps 176).
+
+endif # NETUTILS_DNSCLIENT
diff --git a/apps/netutils/dnsclient/Makefile b/apps/netutils/dnsclient/Makefile
new file mode 100644
index 000000000..076fa5290
--- /dev/null
+++ b/apps/netutils/dnsclient/Makefile
@@ -0,0 +1,100 @@
+############################################################################
+# apps/netutils/dnsclient/Makefile
+#
+# Copyright (C) 2011-2012 Gregory Nutt. All rights reserved.
+# Author: Gregory Nutt <gnutt@nuttx.org>
+#
+# 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.
+#
+############################################################################
+
+-include $(TOPDIR)/.config
+-include $(TOPDIR)/Make.defs
+include $(APPDIR)/Make.defs
+
+# DNS Resolver library
+
+ASRCS =
+CSRCS =
+
+ifeq ($(CONFIG_NET_UDP),y)
+CSRCS = dnsclient.c
+endif
+
+AOBJS = $(ASRCS:.S=$(OBJEXT))
+COBJS = $(CSRCS:.c=$(OBJEXT))
+
+SRCS = $(ASRCS) $(CSRCS)
+OBJS = $(AOBJS) $(COBJS)
+
+ifeq ($(CONFIG_WINDOWS_NATIVE),y)
+ BIN = ..\..\libapps$(LIBEXT)
+else
+ifeq ($(WINTOOL),y)
+ BIN = ..\\..\\libapps$(LIBEXT)
+else
+ BIN = ../../libapps$(LIBEXT)
+endif
+endif
+
+ROOTDEPPATH = --dep-path .
+
+# Common build
+
+VPATH =
+
+all: .built
+.PHONY: context depend clean distclean
+
+$(AOBJS): %$(OBJEXT): %.S
+ $(call ASSEMBLE, $<, $@)
+
+$(COBJS): %$(OBJEXT): %.c
+ $(call COMPILE, $<, $@)
+
+.built: $(OBJS)
+ $(call ARCHIVE, $(BIN), $(OBJS))
+ $(Q) touch .built
+
+context:
+
+.depend: Makefile $(SRCS)
+ $(Q) $(MKDEP) $(ROOTDEPPATH) "$(CC)" -- $(CFLAGS) -- $(SRCS) >Make.dep
+ $(Q) touch $@
+
+depend: .depend
+
+clean:
+ $(call DELFILE, .built)
+ $(call CLEAN)
+
+distclean: clean
+ $(call DELFILE, Make.dep)
+ $(call DELFILE, .depend)
+
+-include Make.dep
diff --git a/apps/netutils/dnsclient/dnsclient.c b/apps/netutils/dnsclient/dnsclient.c
new file mode 100644
index 000000000..b2dbae8c6
--- /dev/null
+++ b/apps/netutils/dnsclient/dnsclient.c
@@ -0,0 +1,723 @@
+/****************************************************************************
+ * apps/netutils/dnsclient/dnsclient.c
+ * DNS host name to IP address resolver.
+ *
+ * The uIP DNS resolver functions are used to lookup a hostname and
+ * map it to a numerical IP address. It maintains a list of resolved
+ * hostnames that can be queried. New hostnames can be resolved using the
+ * dns_whois() function.
+ *
+ * Copyright (C) 2007, 2009, 2012, 2014 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Based heavily on portions of uIP:
+ *
+ * Author: Adam Dunkels <adam@dunkels.com>
+ * Copyright (c) 2002-2003, Adam Dunkels.
+ * All rights reserved.
+ *
+ * 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. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 <nuttx/config.h>
+
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <errno.h>
+#include <debug.h>
+#include <assert.h>
+
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include <apps/netutils/dnsclient.h>
+#include <apps/netutils/uiplib.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifndef CONFIG_NETUTILS_DNSCLIENT_ENTRIES
+# define RESOLV_ENTRIES 4
+#else /* CONFIG_NETUTILS_DNSCLIENT_ENTRIES */
+# define RESOLV_ENTRIES CONFIG_NETUTILS_DNSCLIENT_ENTRIES
+#endif /* CONFIG_NETUTILS_DNSCLIENT_ENTRIES */
+
+#ifndef NULL
+# define NULL (void *)0
+#endif /* NULL */
+
+/* The maximum number of retries when asking for a name */
+
+#define MAX_RETRIES 8
+
+#define DNS_FLAG1_RESPONSE 0x80
+#define DNS_FLAG1_OPCODE_STATUS 0x10
+#define DNS_FLAG1_OPCODE_INVERSE 0x08
+#define DNS_FLAG1_OPCODE_STANDARD 0x00
+#define DNS_FLAG1_AUTHORATIVE 0x04
+#define DNS_FLAG1_TRUNC 0x02
+#define DNS_FLAG1_RD 0x01
+#define DNS_FLAG2_RA 0x80
+#define DNS_FLAG2_ERR_MASK 0x0f
+#define DNS_FLAG2_ERR_NONE 0x00
+#define DNS_FLAG2_ERR_NAME 0x03
+
+#define SEND_BUFFER_SIZE 64
+
+#ifdef CONFIG_NETUTILS_DNSCLIENT_MAXRESPONSE
+# define RECV_BUFFER_SIZE CONFIG_NETUTILS_DNSCLIENT_MAXRESPONSE
+#else
+# define RECV_BUFFER_SIZE 96
+#endif
+
+#ifdef CONFIG_NET_IPv6
+# define ADDRLEN sizeof(struct sockaddr_in6)
+#else
+# define ADDRLEN sizeof(struct sockaddr_in)
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* The DNS message header */
+
+struct dns_hdr
+{
+ uint16_t id;
+ uint8_t flags1;
+ uint8_t flags2;
+ uint16_t numquestions;
+ uint16_t numanswers;
+ uint16_t numauthrr;
+ uint16_t numextrarr;
+};
+
+/* The DNS answer message structure */
+
+struct dns_answer
+{
+ /* DNS answer record starts with either a domain name or a pointer
+ * to a name already present somewhere in the packet.
+ */
+
+ uint16_t type;
+ uint16_t class;
+ uint16_t ttl[2];
+ uint16_t len;
+#ifdef CONFIG_NET_IPv6
+ struct in6_addr ipaddr;
+#else
+ struct in_addr ipaddr;
+#endif
+};
+
+struct namemap
+{
+ uint8_t state;
+ uint8_t tmr;
+ uint8_t retries;
+ uint8_t seqno;
+ uint8_t err;
+ char name[32];
+#ifdef CONFIG_NET_IPv6
+ struct in6_addr ipaddr;
+#else
+ struct in_addr ipaddr;
+#endif
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static uint8_t g_seqno;
+static int g_sockfd = -1;
+#ifdef CONFIG_NET_IPv6
+static struct sockaddr_in6 g_dnsserver;
+#else
+static struct sockaddr_in g_dnsserver;
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: parse_name
+ *
+ * Description:
+ * Walk through a compact encoded DNS name and return the end of it.
+ *
+ ****************************************************************************/
+
+static FAR unsigned char *parse_name(FAR unsigned char *query)
+{
+ unsigned char n;
+
+ do
+ {
+ n = *query++;
+
+ while(n > 0)
+ {
+ ++query;
+ --n;
+ }
+ }
+ while(*query != 0);
+
+ return query + 1;
+}
+
+/****************************************************************************
+ * Name: send_query_socket
+ *
+ * Description:
+ * Runs through the list of names to see if there are any that have
+ * not yet been queried and, if so, sends out a query.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IPv6
+static int send_query_socket(int sockfd, FAR const char *name,
+ FAR struct sockaddr_in6 *addr)
+#else
+static int send_query_socket(int sockfd, FAR const char *name,
+ FAR struct sockaddr_in *addr)
+#endif
+{
+ register FAR struct dns_hdr *hdr;
+ FAR char *query;
+ FAR char *nptr;
+ FAR const char *nameptr;
+ uint8_t seqno = g_seqno++;
+ static unsigned char endquery[] = {0, 0, 1, 0, 1};
+ char buffer[SEND_BUFFER_SIZE];
+ int n;
+
+ hdr = (FAR struct dns_hdr*)buffer;
+ memset(hdr, 0, sizeof(struct dns_hdr));
+ hdr->id = htons(seqno);
+ hdr->flags1 = DNS_FLAG1_RD;
+ hdr->numquestions = HTONS(1);
+ query = buffer + 12;
+
+ /* Convert hostname into suitable query format. */
+
+ nameptr = name - 1;
+ do
+ {
+ nameptr++;
+ nptr = query++;
+ for (n = 0; *nameptr != '.' && *nameptr != 0; nameptr++)
+ {
+ *query++ = *nameptr;
+ n++;
+ }
+
+ *nptr = n;
+ }
+ while(*nameptr != 0);
+
+ memcpy(query, endquery, 5);
+
+#ifdef CONFIG_NET_IPv6
+ DEBUGASSERT(((struct sockaddr *)addr)->sa_family == AF_INET6);
+#else
+ DEBUGASSERT(((struct sockaddr *)addr)->sa_family == AF_INET);
+#endif
+
+ return sendto(sockfd, buffer, query + 5 - buffer,
+ 0, (struct sockaddr*)addr, ADDRLEN);
+}
+
+/****************************************************************************
+ * Name: send_query
+ ****************************************************************************/
+
+#if 0 /* Not used */
+#ifdef CONFIG_NET_IPv6
+static int send_query(FAR const char *name, FAR struct sockaddr_in6 *addr)
+#else
+static int send_query(FAR const char *name, FAR struct sockaddr_in *addr)
+#endif
+{
+ return send_query_socket(g_sockfd, name, addr);
+}
+#endif
+
+/****************************************************************************
+ * Name: recv_response_socket
+ *
+ * Description:
+ * Called when new UDP data arrives
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IPv6
+# error "Not implemented"
+#else
+int recv_response_socket(int sockfd, FAR struct sockaddr_in *addr)
+#endif
+{
+ FAR unsigned char *nameptr;
+ char buffer[RECV_BUFFER_SIZE];
+ FAR struct dns_answer *ans;
+ FAR struct dns_hdr *hdr;
+#if 0 /* Not used */
+ uint8_t nquestions;
+#endif
+ uint8_t nanswers;
+ int ret;
+
+ /* Receive the response */
+
+ ret = recv(sockfd, buffer, RECV_BUFFER_SIZE, 0);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ hdr = (FAR struct dns_hdr *)buffer;
+
+ ndbg("ID %d\n", htons(hdr->id));
+ ndbg("Query %d\n", hdr->flags1 & DNS_FLAG1_RESPONSE);
+ ndbg("Error %d\n", hdr->flags2 & DNS_FLAG2_ERR_MASK);
+ ndbg("Num questions %d, answers %d, authrr %d, extrarr %d\n",
+ htons(hdr->numquestions), htons(hdr->numanswers),
+ htons(hdr->numauthrr), htons(hdr->numextrarr));
+
+ /* Check for error. If so, call callback to inform */
+
+ if ((hdr->flags2 & DNS_FLAG2_ERR_MASK) != 0)
+ {
+ return ERROR;
+ }
+
+ /* We only care about the question(s) and the answers. The authrr
+ * and the extrarr are simply discarded.
+ */
+
+#if 0 /* Not used */
+ nquestions = htons(hdr->numquestions);
+#endif
+ nanswers = htons(hdr->numanswers);
+
+ /* Skip the name in the question. TODO: This should really be
+ * checked against the name in the question, to be sure that they
+ * match.
+ */
+
+#ifdef CONFIG_DEBUG_NET
+ {
+ int d = 64;
+ nameptr = parse_name((unsigned char *)buffer + 12) + 4;
+
+ for (;;)
+ {
+ ndbg("%02X %02X %02X %02X %02X %02X %02X %02X \n",
+ nameptr[0],nameptr[1],nameptr[2],nameptr[3],
+ nameptr[4],nameptr[5],nameptr[6],nameptr[7]);
+
+ nameptr += 8;
+ d -= 8;
+ if (d < 0)
+ {
+ break;
+ }
+ }
+ }
+#endif
+
+ nameptr = parse_name((unsigned char *)buffer + 12) + 4;
+
+ for (; nanswers > 0; nanswers--)
+ {
+ /* The first byte in the answer resource record determines if it
+ * is a compressed record or a normal one.
+ */
+
+ if (*nameptr & 0xc0)
+ {
+ /* Compressed name. */
+
+ nameptr += 2;
+ ndbg("Compressed answer\n");
+ }
+ else
+ {
+ /* Not compressed name. */
+
+ nameptr = parse_name(nameptr);
+ }
+
+ ans = (struct dns_answer *)nameptr;
+ ndbg("Answer: type %x, class %x, ttl %x, length %x \n", /* 0x%08X\n", */
+ htons(ans->type), htons(ans->class),
+ (htons(ans->ttl[0]) << 16) | htons(ans->ttl[1]),
+ htons(ans->len) /* , ans->ipaddr.s_addr */);
+
+ /* Check for IP address type and Internet class. Others are discarded. */
+
+ if (ans->type == HTONS(1) &&
+ ans->class == HTONS(1) &&
+ ans->len == HTONS(4))
+ {
+ ans->ipaddr.s_addr = *(FAR uint32_t *)(nameptr + 10);
+
+ ndbg("IP address %d.%d.%d.%d\n",
+ (ans->ipaddr.s_addr ) & 0xff,
+ (ans->ipaddr.s_addr >> 8 ) & 0xff,
+ (ans->ipaddr.s_addr >> 16 ) & 0xff,
+ (ans->ipaddr.s_addr >> 24 ) & 0xff);
+
+ /* TODO: we should really check that this IP address is the one
+ * we want.
+ */
+
+ addr->sin_addr.s_addr = ans->ipaddr.s_addr;
+ return OK;
+ }
+ else
+ {
+ nameptr = nameptr + 10 + htons(ans->len);
+ }
+ }
+
+ return ERROR;
+}
+
+/****************************************************************************
+ * Name: recv_response
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IPv6
+# error "Not implemented"
+#else
+int recv_response(FAR struct sockaddr_in *addr)
+#endif
+{
+ return recv_response_socket(g_sockfd, addr);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: dns_bind_sock
+ *
+ * Description:
+ * Initialize the DNS resolver using the caller provided socket.
+ *
+ ****************************************************************************/
+
+int dns_bind_sock(FAR int *sockfd)
+{
+ struct timeval tv;
+ int ret;
+
+ if (*sockfd >= 0) dns_free_sock(sockfd);
+
+ *sockfd = socket(PF_INET, SOCK_DGRAM, 0);
+ if (*sockfd < 0)
+ {
+ return ERROR;
+ }
+
+ /* Set up a receive timeout */
+
+ tv.tv_sec = 30;
+ tv.tv_usec = 0;
+
+ ret = setsockopt(*sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv,
+ sizeof(struct timeval));
+
+ if (ret < 0)
+ {
+ close(*sockfd);
+ *sockfd = -1;
+ return ERROR;
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: dns_bind
+ *
+ * Description:
+ * Initialize the DNS resolver using an internal, share-able socket.
+ *
+ ****************************************************************************/
+
+int dns_bind(void)
+{
+ return dns_bind_sock(&g_sockfd);
+}
+
+/****************************************************************************
+ * Name: dns_free_sock
+ *
+ * Description:
+ * Release the DNS resolver by closing the socket.
+ *
+ ****************************************************************************/
+
+int dns_free_sock(FAR int *sockfd)
+{
+ if (*sockfd >= 0)
+ {
+ close(*sockfd);
+ *sockfd = -1;
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: dns_query_sock
+ *
+ * Description:
+ * Using the DNS resolver socket (sockfd), look up the the 'hostname', and
+ * return its IP address in 'ipaddr'
+ *
+ * Returned Value:
+ * Returns zero (OK) if the query was successful.
+ *
+ ****************************************************************************/
+
+int dns_query_sock(int sockfd, FAR const char *hostname, FAR in_addr_t *ipaddr)
+{
+#ifdef CONFIG_HAVE_GETHOSTBYNAME
+
+ FAR struct hostent *he;
+
+ nvdbg("Getting address of %s\n", hostname);
+ he = gethostbyname(hostname);
+ if (!he)
+ {
+ ndbg("gethostbyname failed: %d\n", h_errno);
+ return ERROR;
+ }
+
+ nvdbg("Using IP address %04x%04x\n",
+ (uint16_t)he->h_addr[1], (uint16_t)he->h_addr[0]);
+
+ memcpy(ipaddr, he->h_addr, sizeof(in_addr_t));
+ return OK;
+
+#else
+
+# ifdef CONFIG_NET_IPv6
+ struct sockaddr_in6 addr;
+# else
+ struct sockaddr_in addr;
+# endif
+
+ /* First check if the host is an IP address. */
+
+ if (!uiplib_ipaddrconv(hostname, (uint8_t*)ipaddr))
+ {
+ /* 'host' does not point to a valid address string. Try to resolve
+ * the host name to an IP address.
+ */
+
+ if (dns_whois_socket(sockfd, hostname, &addr) < 0)
+ {
+ /* Needs to set the errno here */
+
+ return ERROR;
+ }
+
+ /* Save the host address -- Needs fixed for IPv6 */
+
+ *ipaddr = addr.sin_addr.s_addr;
+ }
+
+ return OK;
+#endif
+}
+
+/****************************************************************************
+ * Name: dns_query
+ *
+ * Description:
+ * Using the internal DNS resolver socket, look up the the 'hostname', and
+ * return its IP address in 'ipaddr'
+ *
+ * Returned Value:
+ * Returns zero (OK) if the query was successful.
+ *
+ ****************************************************************************/
+
+int dns_query(FAR const char *hostname, FAR in_addr_t *ipaddr)
+{
+ return dns_query_sock(g_sockfd, hostname, ipaddr);
+}
+
+/****************************************************************************
+ * Name: dns_setserver
+ *
+ * Description:
+ * Configure which DNS server to use for queries
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IPv6
+void dns_setserver(FAR const struct in6_addr *dnsserver)
+#else
+void dns_setserver(FAR const struct in_addr *dnsserver)
+#endif
+{
+ g_dnsserver.sin_family = AF_INET;
+ g_dnsserver.sin_port = HTONS(53);
+#ifdef CONFIG_NET_IPv6
+ memcpy(&g_dnsserver.sin6_addr, dnsserver, ADDRLEN);
+#else
+ g_dnsserver.sin_addr.s_addr = dnsserver->s_addr;
+#endif
+}
+
+/****************************************************************************
+ * Name: dns_getserver
+ *
+ * Description:
+ * Obtain the currently configured DNS server.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IPv6
+void dns_getserver(FAR struct in6_addr *dnsserver)
+#else
+void dns_getserver(FAR struct in_addr *dnsserver)
+#endif
+{
+#ifdef CONFIG_NET_IPv6
+ memcpy(dnsserver, &g_dnsserver.sin6_addr, ADDRLEN);
+#else
+ dnsserver->s_addr = g_dnsserver.sin_addr.s_addr;
+#endif
+}
+
+/****************************************************************************
+ * Name: dns_whois_socket
+ *
+ * Description:
+ * Get the binding for 'name' using the DNS server accessed via 'sockfd'
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IPv6
+int dns_whois_socket(int sockfd, FAR const char *name,
+ FAR struct sockaddr_in6 *addr)
+#else
+int dns_whois_socket(int sockfd, FAR const char *name,
+ FAR struct sockaddr_in *addr)
+#endif
+{
+ int retries;
+ int ret;
+
+ /* Loop while receive timeout errors occur and there are remaining retries */
+
+ for (retries = 0; retries < 3; retries++)
+ {
+ if (send_query_socket(sockfd, name, &g_dnsserver) < 0)
+ {
+ return ERROR;
+ }
+
+ ret = recv_response_socket(sockfd, addr);
+ if (ret >= 0)
+ {
+ /* Response received successfully */
+
+ return OK;
+ }
+
+ else if (errno != EAGAIN)
+ {
+ /* Some failure other than receive timeout occurred */
+
+ return ERROR;
+ }
+ }
+
+ return ERROR;
+}
+
+/****************************************************************************
+ * Name: dns_whois
+ *
+ * Description:
+ * Get the binding for 'name' using the DNS server accessed via the DNS
+ * resolvers internal socket.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IPv6
+int dns_whois(FAR const char *name, FAR struct sockaddr_in6 *addr)
+#else
+int dns_whois(FAR const char *name, FAR struct sockaddr_in *addr)
+#endif
+{
+ return dns_whois_socket(g_sockfd, name, addr);
+}
+
+/****************************************************************************
+ * Name: dns_gethostip
+ *
+ * Descriptions:
+ * Combines the operations of dns_bind_sock(), dns_query_sock(), and
+ * dns_free_sock() to obtain the the IP address ('ipaddr') associated with
+ * the 'hostname' in one operation.
+ *
+ ****************************************************************************/
+
+int dns_gethostip(FAR const char *hostname, FAR in_addr_t *ipaddr)
+{
+ int sockfd = -1;
+ int ret=ERROR;
+
+ dns_bind_sock(&sockfd);
+ if (sockfd >= 0)
+ {
+ ret = dns_query_sock(sockfd, hostname, ipaddr);
+ dns_free_sock(&sockfd);
+ }
+
+ return ret;
+}
+