libs/libc/netdb: Support multiple IP addresses per hostname

This commit is contained in:
Juha Niskanen
2018-11-23 07:09:47 -06:00
committed by Gregory Nutt
parent d2a11cdea5
commit 3e7281e699
8 changed files with 213 additions and 168 deletions
+6 -3
View File
@@ -90,10 +90,12 @@
#define DNS_RECTYPE_NSEC 47 /* RFC 4034 Next-Secure record */ #define DNS_RECTYPE_NSEC 47 /* RFC 4034 Next-Secure record */
#define DNS_RECTYPE_NSEC3 50 /* RFC 5155 NSEC record version 3 */ #define DNS_RECTYPE_NSEC3 50 /* RFC 5155 NSEC record version 3 */
#define DNS_RECTYPE_NSEC3PARAM 51 /* RFC 5155 NSEC3 parameters */ #define DNS_RECTYPE_NSEC3PARAM 51 /* RFC 5155 NSEC3 parameters */
#define DNS_RECTYPE_OPENPGPKEY 61 /* RFC 7929 OpenPGP public key record */
#define DNS_RECTYPE_PTR 12 /* RFC 1035 Pointer record */ #define DNS_RECTYPE_PTR 12 /* RFC 1035 Pointer record */
#define DNS_RECTYPE_RRSIG 46 /* RFC 4034 DNSSEC signature */ #define DNS_RECTYPE_RRSIG 46 /* RFC 4034 DNSSEC signature */
#define DNS_RECTYPE_RP 17 /* RFC 1183 Responsible person */ #define DNS_RECTYPE_RP 17 /* RFC 1183 Responsible person */
#define DNS_RECTYPE_SIG 24 /* RFC 2535 Signature */ #define DNS_RECTYPE_SIG 24 /* RFC 2535 Signature */
#define DNS_RECTYPE_SMIMEA 53 /* RFC 8162 S/MIME cert association */
#define DNS_RECTYPE_SOA 6 /* RFC 1035 and RFC 2308 Start of [a zone of] authority record */ #define DNS_RECTYPE_SOA 6 /* RFC 1035 and RFC 2308 Start of [a zone of] authority record */
#define DNS_RECTYPE_SRV 33 /* RFC 2782 Service locator */ #define DNS_RECTYPE_SRV 33 /* RFC 2782 Service locator */
#define DNS_RECTYPE_SSHFP 44 /* RFC 4255 SSH Public Key Fingerprint */ #define DNS_RECTYPE_SSHFP 44 /* RFC 4255 SSH Public Key Fingerprint */
@@ -101,7 +103,8 @@
#define DNS_RECTYPE_TKEY 249 /* RFC 2930 Secret key record */ #define DNS_RECTYPE_TKEY 249 /* RFC 2930 Secret key record */
#define DNS_RECTYPE_TLSA 52 /* RFC 6698 TLSA certificate association */ #define DNS_RECTYPE_TLSA 52 /* RFC 6698 TLSA certificate association */
#define DNS_RECTYPE_TSIG 250 /* RFC 2845 Transaction Signature */ #define DNS_RECTYPE_TSIG 250 /* RFC 2845 Transaction Signature */
#define DNS_RECTYPE_TXT 16 /* RFC 1035[1] Text record */ #define DNS_RECTYPE_TXT 16 /* RFC 1035 Text record */
#define DNS_RECTYPE_URI 256 /* RFC 7553 Uniform Resource Identifier */
#define DNS_RECTYPE_ALL 255 /* RFC 1035 All cached records */ #define DNS_RECTYPE_ALL 255 /* RFC 1035 All cached records */
#define DNS_RECTYPE_AXFR 252 /* RFC 1035 Authoritative Zone Transfer */ #define DNS_RECTYPE_AXFR 252 /* RFC 1035 Authoritative Zone Transfer */
@@ -156,7 +159,7 @@ struct dns_question_s
/* The DNS answer message structure */ /* The DNS answer message structure */
struct dns_answer_s begin_packed_struct struct dns_answer_s
{ {
uint16_t type; uint16_t type;
uint16_t class; uint16_t class;
@@ -172,7 +175,7 @@ struct dns_answer_s
struct in6_addr ipv6; struct in6_addr ipv6;
#endif #endif
} u; } u;
}; } end_packed_struct;
/* The type of the callback from dns_foreach_nameserver() */ /* The type of the callback from dns_foreach_nameserver() */
+7
View File
@@ -102,6 +102,13 @@ config NETDB_DNSCLIENT_MAXRESPONSE
can be received by the DNS resolver. The default is 96 but may can be received by the DNS resolver. The default is 96 but may
need to be larger on enterprise networks (perhaps 176). need to be larger on enterprise networks (perhaps 176).
config NETDB_DNSCLIENT_MAXIP
int "Max number of IP addresses per host"
default 1
---help---
This setting determines the maximum number of IP addresses
stored to the name resolution cache for a given host.
config NETDB_DNSCLIENT_RECV_TIMEOUT config NETDB_DNSCLIENT_RECV_TIMEOUT
int "DNS receive timeout" int "DNS receive timeout"
default 30 default 30
+23 -21
View File
@@ -62,12 +62,14 @@
# define CONFIG_NETDB_DNSCLIENT_ENTRIES 4 # define CONFIG_NETDB_DNSCLIENT_ENTRIES 4
#endif #endif
#define RESOLV_ENTRIES CONFIG_NETDB_DNSCLIENT_ENTRIES
#ifndef CONFIG_NETDB_DNSCLIENT_MAXRESPONSE #ifndef CONFIG_NETDB_DNSCLIENT_MAXRESPONSE
# define CONFIG_NETDB_DNSCLIENT_MAXRESPONSE 96 # define CONFIG_NETDB_DNSCLIENT_MAXRESPONSE 96
#endif #endif
#ifndef CONFIG_NETDB_DNSCLIENT_MAXIP
# define CONFIG_NETDB_DNSCLIENT_MAXIP 1
#endif
#ifndef CONFIG_NETDB_DNSCLIENT_NAMESIZE #ifndef CONFIG_NETDB_DNSCLIENT_NAMESIZE
# define CONFIG_NETDB_DNSCLIENT_NAMESIZE 32 # define CONFIG_NETDB_DNSCLIENT_NAMESIZE 32
#endif #endif
@@ -91,7 +93,7 @@
* alternative to sockaddr_storage. * alternative to sockaddr_storage.
*/ */
union dns_server_u union dns_addr_u
{ {
struct sockaddr addr; /* Common address representation */ struct sockaddr addr; /* Common address representation */
#ifdef CONFIG_NET_IPv4 #ifdef CONFIG_NET_IPv4
@@ -118,7 +120,7 @@ extern "C"
#ifndef CONFIG_NETDB_RESOLVCONF #ifndef CONFIG_NETDB_RESOLVCONF
/* The DNS server address */ /* The DNS server address */
EXTERN union dns_server_u g_dns_server; EXTERN union dns_addr_u g_dns_server;
EXTERN bool g_dns_address; /* true: We have the address of the DNS server */ EXTERN bool g_dns_address; /* true: We have the address of the DNS server */
#endif #endif
@@ -184,19 +186,19 @@ int dns_bind(void);
* Input Parameters: * Input Parameters:
* sd - The socket descriptor previously initialized by dsn_bind(). * sd - The socket descriptor previously initialized by dsn_bind().
* hostname - The hostname string to be resolved. * hostname - The hostname string to be resolved.
* addr - The location to return the IP address associated with the * addr - The location to return the IP addresses associated with the
* hostname * hostname.
* addrlen - On entry, the size of the buffer backing up the 'addr' * naddr - On entry, the count of addresses backing up the 'addr'
* pointer. On return, this location will hold the actual size of * pointer. On return, this location will hold the actual count of
* the returned address. * the returned addresses.
* *
* Returned Value: * Returned Value:
* Returns zero (OK) if the query was successful. * Returns zero (OK) if the query was successful.
* *
****************************************************************************/ ****************************************************************************/
int dns_query(int sd, FAR const char *hostname, FAR struct sockaddr *addr, int dns_query(int sd, FAR const char *hostname, FAR union dns_addr_u *addr,
FAR socklen_t *addrlen); FAR int *naddr);
/**************************************************************************** /****************************************************************************
* Name: dns_save_answer * Name: dns_save_answer
@@ -206,8 +208,8 @@ int dns_query(int sd, FAR const char *hostname, FAR struct sockaddr *addr,
* *
* Input Parameters: * Input Parameters:
* hostname - The hostname string to be cached. * hostname - The hostname string to be cached.
* addr - The IP address associated with the hostname * addr - The IP addresses associated with the hostname.
* addrlen - The size of the of the IP address. * naddr - The count of the IP addresses.
* *
* Returned Value: * Returned Value:
* None * None
@@ -216,7 +218,7 @@ int dns_query(int sd, FAR const char *hostname, FAR struct sockaddr *addr,
#if CONFIG_NETDB_DNSCLIENT_ENTRIES > 0 #if CONFIG_NETDB_DNSCLIENT_ENTRIES > 0
void dns_save_answer(FAR const char *hostname, void dns_save_answer(FAR const char *hostname,
FAR const struct sockaddr *addr, socklen_t addrlen); FAR const union dns_addr_u *addr, int naddr);
#endif #endif
/**************************************************************************** /****************************************************************************
@@ -227,11 +229,11 @@ void dns_save_answer(FAR const char *hostname,
* *
* Input Parameters: * Input Parameters:
* hostname - The hostname string to be resolved. * hostname - The hostname string to be resolved.
* addr - The location to return the IP address associated with the * addr - The location to return the IP addresses associated with the
* hostname * hostname.
* addrlen - On entry, the size of the buffer backing up the 'addr' * naddr - On entry, the count of addresses backing up the 'addr'
* pointer. On return, this location will hold the actual size of * pointer. On return, this location will hold the actual count of
* the returned address. * the returned addresses.
* *
* Returned Value: * Returned Value:
* If the host name was successfully found in the DNS name resolution * If the host name was successfully found in the DNS name resolution
@@ -242,8 +244,8 @@ void dns_save_answer(FAR const char *hostname,
****************************************************************************/ ****************************************************************************/
#if CONFIG_NETDB_DNSCLIENT_ENTRIES > 0 #if CONFIG_NETDB_DNSCLIENT_ENTRIES > 0
int dns_find_answer(FAR const char *hostname, FAR struct sockaddr *addr, int dns_find_answer(FAR const char *hostname, FAR union dns_addr_u *addr,
FAR socklen_t *addrlen); FAR int *naddr);
#endif #endif
#undef EXTERN #undef EXTERN
+1 -1
View File
@@ -60,7 +60,7 @@
#ifndef CONFIG_NETDB_RESOLVCONF #ifndef CONFIG_NETDB_RESOLVCONF
/* The DNS server address */ /* The DNS server address */
union dns_server_u g_dns_server; union dns_addr_u g_dns_server;
bool g_dns_address; /* true: We have the address of the DNS server */ bool g_dns_address; /* true: We have the address of the DNS server */
#endif #endif
+27 -44
View File
@@ -42,6 +42,7 @@
#include <sys/time.h> #include <sys/time.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <assert.h>
#include <errno.h> #include <errno.h>
#include <debug.h> #include <debug.h>
@@ -65,15 +66,20 @@
* Private Types * Private Types
****************************************************************************/ ****************************************************************************/
/* This described one entry in the cache of resolved hostnames */ /* This described one entry in the cache of resolved hostnames.
*
* REVISIT: this consumes extra space, especially when multiple
* addresses per name are stored.
*/
struct dns_cache_s struct dns_cache_s
{ {
#if CONFIG_NETDB_DNSCLIENT_LIFESEC > 0 #if CONFIG_NETDB_DNSCLIENT_LIFESEC > 0
time_t ctime; /* Creation time */ time_t ctime; /* Creation time */
#endif #endif
char name[CONFIG_NETDB_DNSCLIENT_NAMESIZE]; char name[CONFIG_NETDB_DNSCLIENT_NAMESIZE];
union dns_server_u addr; /* Resolved address */ uint8_t naddr; /* How many addresses per name */
union dns_addr_u addr[CONFIG_NETDB_DNSCLIENT_MAXIP]; /* Resolved address */
}; };
/**************************************************************************** /****************************************************************************
@@ -103,8 +109,8 @@ static struct dns_cache_s g_dns_cache[CONFIG_NETDB_DNSCLIENT_ENTRIES];
* *
* Input Parameters: * Input Parameters:
* hostname - The hostname string to be cached. * hostname - The hostname string to be cached.
* addr - The IP address associated with the hostname * addr - The IP addresses associated with the hostname.
* addrlen - The size of the of the IP address. * naddr - The count of the IP addresses.
* *
* Returned Value: * Returned Value:
* None * None
@@ -112,7 +118,7 @@ static struct dns_cache_s g_dns_cache[CONFIG_NETDB_DNSCLIENT_ENTRIES];
****************************************************************************/ ****************************************************************************/
void dns_save_answer(FAR const char *hostname, void dns_save_answer(FAR const char *hostname,
FAR const struct sockaddr *addr, socklen_t addrlen) FAR const union dns_addr_u *addr, int naddr)
{ {
FAR struct dns_cache_s *entry; FAR struct dns_cache_s *entry;
#if CONFIG_NETDB_DNSCLIENT_LIFESEC > 0 #if CONFIG_NETDB_DNSCLIENT_LIFESEC > 0
@@ -121,6 +127,9 @@ void dns_save_answer(FAR const char *hostname,
int next; int next;
int ndx; int ndx;
naddr = MIN(naddr, CONFIG_NETDB_DNSCLIENT_MAXIP);
DEBUGASSERT(naddr >= 1 && naddr <= UCHAR_MAX);
/* Get exclusive access to the DNS cache */ /* Get exclusive access to the DNS cache */
dns_semtake(); dns_semtake();
@@ -161,7 +170,8 @@ void dns_save_answer(FAR const char *hostname,
#endif #endif
strncpy(entry->name, hostname, CONFIG_NETDB_DNSCLIENT_NAMESIZE); strncpy(entry->name, hostname, CONFIG_NETDB_DNSCLIENT_NAMESIZE);
memcpy(&entry->addr.addr, addr, addrlen); memcpy(&entry->addr, addr, naddr * sizeof(*addr));
entry->naddr = naddr;
/* Save the updated head index */ /* Save the updated head index */
@@ -177,11 +187,11 @@ void dns_save_answer(FAR const char *hostname,
* *
* Input Parameters: * Input Parameters:
* hostname - The hostname string to be resolved. * hostname - The hostname string to be resolved.
* addr - The location to return the IP address associated with the * addr - The location to return the IP addresses associated with the
* hostname * hostname.
* addrlen - On entry, the size of the buffer backing up the 'addr' * naddr - On entry, the count of addresses backing up the 'addr'
* pointer. On return, this location will hold the actual size of * pointer. On return, this location will hold the actual count of
* the returned address. * the returned addresses.
* *
* Returned Value: * Returned Value:
* If the host name was successfully found in the DNS name resolution * If the host name was successfully found in the DNS name resolution
@@ -191,8 +201,8 @@ void dns_save_answer(FAR const char *hostname,
* *
****************************************************************************/ ****************************************************************************/
int dns_find_answer(FAR const char *hostname, FAR struct sockaddr *addr, int dns_find_answer(FAR const char *hostname, FAR union dns_addr_u *addr,
FAR socklen_t *addrlen) FAR int *naddr)
{ {
FAR struct dns_cache_s *entry; FAR struct dns_cache_s *entry;
#if CONFIG_NETDB_DNSCLIENT_LIFESEC > 0 #if CONFIG_NETDB_DNSCLIENT_LIFESEC > 0
@@ -221,8 +231,6 @@ int dns_find_answer(FAR const char *hostname, FAR struct sockaddr *addr,
ret = clock_gettime(DNS_CLOCK, &now); ret = clock_gettime(DNS_CLOCK, &now);
#endif #endif
/* REVISIT: This is not thread safe */
for (ndx = g_dns_tail; ndx != g_dns_head; ndx = next) for (ndx = g_dns_tail; ndx != g_dns_head; ndx = next)
{ {
entry = &g_dns_cache[ndx]; entry = &g_dns_cache[ndx];
@@ -263,41 +271,17 @@ int dns_find_answer(FAR const char *hostname, FAR struct sockaddr *addr,
if (strncmp(hostname, entry->name, CONFIG_NETDB_DNSCLIENT_NAMESIZE) == 0) if (strncmp(hostname, entry->name, CONFIG_NETDB_DNSCLIENT_NAMESIZE) == 0)
{ {
socklen_t inlen;
/* We have a match. Return the resolved host address */ /* We have a match. Return the resolved host address */
#ifdef CONFIG_NET_IPv4
#ifdef CONFIG_NET_IPv6
if (entry->addr.addr.sa_family == AF_INET)
#endif
{
inlen = sizeof(struct sockaddr_in);
}
#endif
#ifdef CONFIG_NET_IPv6
#ifdef CONFIG_NET_IPv4
else
#endif
{
inlen = sizeof(struct sockaddr_in6);
}
#endif
/* Make sure that the address will fit in the caller-provided /* Make sure that the address will fit in the caller-provided
* buffer. * buffer.
*/ */
if (*addrlen < inlen) *naddr = MIN(*naddr, entry->naddr);
{
ret = -ERANGE;
goto errout_with_sem;
}
/* Return the address information */ /* Return the address information */
memcpy(addr, &entry->addr.addr, inlen); memcpy(addr, &entry->addr, *naddr * sizeof(*addr));
*addrlen = inlen;
dns_semgive(); dns_semgive();
return OK; return OK;
@@ -307,7 +291,6 @@ int dns_find_answer(FAR const char *hostname, FAR struct sockaddr *addr,
ret = -ENOENT; ret = -ENOENT;
errout_with_sem:
dns_semgive(); dns_semgive();
return ret; return ret;
} }
+1 -1
View File
@@ -90,7 +90,7 @@ static FAR char *find_spaces(FAR char *ptr)
int dns_foreach_nameserver(dns_callback_t callback, FAR void *arg) int dns_foreach_nameserver(dns_callback_t callback, FAR void *arg)
{ {
union dns_server_u u; union dns_addr_u u;
FAR FILE *stream; FAR FILE *stream;
char line[DNS_MAX_LINE]; char line[DNS_MAX_LINE];
FAR char *addrstr; FAR char *addrstr;
+65 -39
View File
@@ -88,8 +88,8 @@ struct dns_query_s
int sd; /* DNS server socket */ int sd; /* DNS server socket */
int result; /* Explanation of the failure */ int result; /* Explanation of the failure */
FAR const char *hostname; /* Hostname to lookup */ FAR const char *hostname; /* Hostname to lookup */
FAR struct sockaddr *addr; /* Location to return host address */ FAR union dns_addr_u *addr; /* Location to return host address */
FAR socklen_t *addrlen; /* Length of the address */ FAR int *naddr; /* Number of returned addresses */
}; };
/* Query info to check response against. */ /* Query info to check response against. */
@@ -205,7 +205,7 @@ static inline uint16_t dns_alloc_id(void)
****************************************************************************/ ****************************************************************************/
static int dns_send_query(int sd, FAR const char *name, static int dns_send_query(int sd, FAR const char *name,
FAR union dns_server_u *uaddr, uint16_t rectype, FAR union dns_addr_u *uaddr, uint16_t rectype,
FAR struct dns_query_info_s *qinfo) FAR struct dns_query_info_s *qinfo)
{ {
FAR struct dns_header_s *hdr; FAR struct dns_header_s *hdr;
@@ -337,10 +337,13 @@ static int dns_send_query(int sd, FAR const char *name,
* Description: * Description:
* Called when new UDP data arrives * Called when new UDP data arrives
* *
* Returned Value:
* Returns number of valid IP address responses. Negated errno value is
* returned in all other cases.
*
****************************************************************************/ ****************************************************************************/
static int dns_recv_response(int sd, FAR struct sockaddr *addr, static int dns_recv_response(int sd, FAR union dns_addr_u *addr, int *naddr,
FAR socklen_t *addrlen,
FAR struct dns_query_info_s *qinfo) FAR struct dns_query_info_s *qinfo)
{ {
FAR uint8_t *nameptr; FAR uint8_t *nameptr;
@@ -352,8 +355,9 @@ static int dns_recv_response(int sd, FAR struct sockaddr *addr,
FAR struct dns_question_s *que; FAR struct dns_question_s *que;
uint16_t nquestions; uint16_t nquestions;
uint16_t nanswers; uint16_t nanswers;
union dns_server_u recvaddr; union dns_addr_u recvaddr;
socklen_t raddrlen; socklen_t raddrlen;
int naddr_read;
int errcode; int errcode;
int ret; int ret;
@@ -535,6 +539,9 @@ static int dns_recv_response(int sd, FAR struct sockaddr *addr,
nameptr += sizeof(struct dns_question_s); nameptr += sizeof(struct dns_question_s);
ret = OK;
naddr_read = 0;
for (; nanswers > 0; nanswers--) for (; nanswers > 0; nanswers--)
{ {
/* Each answer starts with a name */ /* Each answer starts with a name */
@@ -542,7 +549,8 @@ static int dns_recv_response(int sd, FAR struct sockaddr *addr,
nameptr = dns_parse_name(nameptr, endofbuffer); nameptr = dns_parse_name(nameptr, endofbuffer);
if (nameptr == endofbuffer) if (nameptr == endofbuffer)
{ {
return -EILSEQ; ret = -EILSEQ;
break;
} }
ans = (FAR struct dns_answer_s *)nameptr; ans = (FAR struct dns_answer_s *)nameptr;
@@ -562,7 +570,7 @@ static int dns_recv_response(int sd, FAR struct sockaddr *addr,
ans->len == HTONS(4) && ans->len == HTONS(4) &&
nameptr + 10 + 4 <= endofbuffer) nameptr + 10 + 4 <= endofbuffer)
{ {
ans->u.ipv4.s_addr = *(FAR uint32_t *)(nameptr + 10); nameptr += 10 + 4;
ninfo("IPv4 address: %d.%d.%d.%d\n", ninfo("IPv4 address: %d.%d.%d.%d\n",
(ans->u.ipv4.s_addr ) & 0xff, (ans->u.ipv4.s_addr ) & 0xff,
@@ -570,21 +578,25 @@ static int dns_recv_response(int sd, FAR struct sockaddr *addr,
(ans->u.ipv4.s_addr >> 16) & 0xff, (ans->u.ipv4.s_addr >> 16) & 0xff,
(ans->u.ipv4.s_addr >> 24) & 0xff); (ans->u.ipv4.s_addr >> 24) & 0xff);
if (*addrlen >= sizeof(struct sockaddr_in)) if (naddr_read < *naddr)
{ {
FAR struct sockaddr_in *inaddr; FAR struct sockaddr_in *inaddr;
inaddr = (FAR struct sockaddr_in *)addr; inaddr = (FAR struct sockaddr_in *)&addr[naddr_read].addr;
inaddr->sin_family = AF_INET; inaddr->sin_family = AF_INET;
inaddr->sin_port = 0; inaddr->sin_port = 0;
inaddr->sin_addr.s_addr = ans->u.ipv4.s_addr; inaddr->sin_addr.s_addr = ans->u.ipv4.s_addr;
*addrlen = sizeof(struct sockaddr_in); naddr_read++;
return OK; if (naddr_read >= *naddr)
{
break;
}
} }
else else
{ {
return -ERANGE; ret = -ERANGE;
break;
} }
} }
else else
@@ -595,7 +607,7 @@ static int dns_recv_response(int sd, FAR struct sockaddr *addr,
ans->len == HTONS(16) && ans->len == HTONS(16) &&
nameptr + 10 + 16 <= endofbuffer) nameptr + 10 + 16 <= endofbuffer)
{ {
memcpy(&ans->u.ipv6.s6_addr, nameptr + 10, 16); nameptr += 10 + 16;
ninfo("IPv6 address: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", ninfo("IPv6 address: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
htons(ans->u.ipv6.s6_addr[7]), htons(ans->u.ipv6.s6_addr[6]), htons(ans->u.ipv6.s6_addr[7]), htons(ans->u.ipv6.s6_addr[6]),
@@ -603,21 +615,25 @@ static int dns_recv_response(int sd, FAR struct sockaddr *addr,
htons(ans->u.ipv6.s6_addr[3]), htons(ans->u.ipv6.s6_addr[2]), htons(ans->u.ipv6.s6_addr[3]), htons(ans->u.ipv6.s6_addr[2]),
htons(ans->u.ipv6.s6_addr[1]), htons(ans->u.ipv6.s6_addr[0])); htons(ans->u.ipv6.s6_addr[1]), htons(ans->u.ipv6.s6_addr[0]));
if (*addrlen >= sizeof(struct sockaddr_in6)) if (naddr_read < *naddr)
{ {
FAR struct sockaddr_in6 *inaddr; FAR struct sockaddr_in6 *inaddr;
inaddr = (FAR struct sockaddr_in6 *)addr; inaddr = (FAR struct sockaddr_in6 *)&addr[naddr_read].addr;
inaddr->sin6_family = AF_INET; inaddr->sin6_family = AF_INET6;
inaddr->sin6_port = 0; inaddr->sin6_port = 0;
memcpy(inaddr->sin6_addr.s6_addr, ans->u.ipv6.s6_addr, 16); memcpy(inaddr->sin6_addr.s6_addr, ans->u.ipv6.s6_addr, 16);
*addrlen = sizeof(struct sockaddr_in6); naddr_read++;
return OK; if (naddr_read >= *naddr)
{
break;
}
} }
else else
{ {
return -ERANGE; ret = -ERANGE;
break;
} }
} }
else else
@@ -627,7 +643,17 @@ static int dns_recv_response(int sd, FAR struct sockaddr *addr,
} }
} }
return -EADDRNOTAVAIL; if (naddr_read == 0 && ret == OK)
{
ret = -EADDRNOTAVAIL;
}
else if (naddr_read > 0 && ret != OK)
{
nwarn("Got an IP, but further parse returned %d\n", ret);
}
*naddr = naddr_read;
return (naddr_read > 0) ? naddr_read : ret;
} }
/**************************************************************************** /****************************************************************************
@@ -684,7 +710,7 @@ static int dns_query_callback(FAR void *arg, FAR struct sockaddr *addr,
/* Send the IPv4 query */ /* Send the IPv4 query */
ret = dns_send_query(query->sd, query->hostname, ret = dns_send_query(query->sd, query->hostname,
(FAR union dns_server_u *)addr, (FAR union dns_addr_u *)addr,
DNS_RECTYPE_A, &qinfo); DNS_RECTYPE_A, &qinfo);
if (ret < 0) if (ret < 0)
{ {
@@ -699,7 +725,7 @@ static int dns_query_callback(FAR void *arg, FAR struct sockaddr *addr,
/* Obtain the IPv4 response */ /* Obtain the IPv4 response */
ret = dns_recv_response(query->sd, query->addr, query->addrlen, ret = dns_recv_response(query->sd, query->addr, query->naddr,
&qinfo); &qinfo);
if (ret >= 0) if (ret >= 0)
{ {
@@ -709,7 +735,7 @@ static int dns_query_callback(FAR void *arg, FAR struct sockaddr *addr,
/* Save the answer in the DNS cache */ /* Save the answer in the DNS cache */
dns_save_answer(query->hostname, query->addr, dns_save_answer(query->hostname, query->addr,
*query->addrlen); *query->naddr);
#endif #endif
/* Return 1 to indicate to (1) stop the traversal, and (2) /* Return 1 to indicate to (1) stop the traversal, and (2)
* indicate that the address was found. * indicate that the address was found.
@@ -749,7 +775,7 @@ static int dns_query_callback(FAR void *arg, FAR struct sockaddr *addr,
#ifdef CONFIG_NET_IPv6 #ifdef CONFIG_NET_IPv6
/* Is this an IPv6 address? */ /* Is this an IPv6 address? */
if (query->addr->sa_family == AF_INET6) if (addr->sa_family == AF_INET6)
{ {
/* Yes.. verify the address size */ /* Yes.. verify the address size */
@@ -767,7 +793,7 @@ static int dns_query_callback(FAR void *arg, FAR struct sockaddr *addr,
/* Send the IPv6 query */ /* Send the IPv6 query */
ret = dns_send_query(query->sd, query->hostname, ret = dns_send_query(query->sd, query->hostname,
(FAR union dns_server_u *)addr, (FAR union dns_addr_u *)addr,
DNS_RECTYPE_AAAA, &qinfo); DNS_RECTYPE_AAAA, &qinfo);
if (ret < 0) if (ret < 0)
{ {
@@ -782,7 +808,7 @@ static int dns_query_callback(FAR void *arg, FAR struct sockaddr *addr,
/* Obtain the IPv6 response */ /* Obtain the IPv6 response */
ret = dns_recv_response(query->sd, query->addr, query->addrlen, ret = dns_recv_response(query->sd, query->addr, query->naddr,
&qinfo); &qinfo);
if (ret >= 0) if (ret >= 0)
{ {
@@ -791,7 +817,7 @@ static int dns_query_callback(FAR void *arg, FAR struct sockaddr *addr,
#if CONFIG_NETDB_DNSCLIENT_ENTRIES > 0 #if CONFIG_NETDB_DNSCLIENT_ENTRIES > 0
/* Save the answer in the DNS cache */ /* Save the answer in the DNS cache */
dns_save_answer(query->hostname, query->addr, *query->addrlen); dns_save_answer(query->hostname, query->addr, *query->naddr);
#endif #endif
/* Return 1 to indicate to (1) stop the traversal, and (2) /* Return 1 to indicate to (1) stop the traversal, and (2)
* indicate that the address was found. * indicate that the address was found.
@@ -859,19 +885,19 @@ static int dns_query_callback(FAR void *arg, FAR struct sockaddr *addr,
* Input Parameters: * Input Parameters:
* sd - The socket descriptor previously initialized by dsn_bind(). * sd - The socket descriptor previously initialized by dsn_bind().
* hostname - The hostname string to be resolved. * hostname - The hostname string to be resolved.
* addr - The location to return the IP address associated with the * addr - The location to return the IP addresses associated with the
* hostname * hostname.
* addrlen - On entry, the size of the buffer backing up the 'addr' * naddr - On entry, the count of addresses backing up the 'addr'
* pointer. On return, this location will hold the actual size of * pointer. On return, this location will hold the actual count of
* the returned address. * the returned addresses.
* *
* Returned Value: * Returned Value:
* Returns zero (OK) if the query was successful. * Returns zero (OK) if the query was successful.
* *
****************************************************************************/ ****************************************************************************/
int dns_query(int sd, FAR const char *hostname, FAR struct sockaddr *addr, int dns_query(int sd, FAR const char *hostname, FAR union dns_addr_u *addr,
FAR socklen_t *addrlen) FAR int *naddr)
{ {
FAR struct dns_query_s query; FAR struct dns_query_s query;
int ret; int ret;
@@ -882,7 +908,7 @@ int dns_query(int sd, FAR const char *hostname, FAR struct sockaddr *addr,
query.result = -EADDRNOTAVAIL; query.result = -EADDRNOTAVAIL;
query.hostname = hostname; query.hostname = hostname;
query.addr = addr; query.addr = addr;
query.addrlen = addrlen; query.naddr = naddr;
/* Perform the query. dns_foreach_nameserver() will return: /* Perform the query. dns_foreach_nameserver() will return:
* *
+83 -59
View File
@@ -66,7 +66,7 @@
struct hostent_info_s struct hostent_info_s
{ {
FAR char *hi_addrlist[2]; FAR char *hi_addrlist[CONFIG_NETDB_DNSCLIENT_MAXIP + 1];
char hi_data[1]; char hi_data[1];
}; };
@@ -360,9 +360,11 @@ static int lib_find_answer(FAR const char *name, FAR struct hostent *host,
FAR char *ptr; FAR char *ptr;
FAR void *addrdata; FAR void *addrdata;
socklen_t addrlen; socklen_t addrlen;
int naddr;
int addrtype; int addrtype;
int namelen; int namelen;
int ret; int ret;
int i;
/* Verify that we have a buffer big enough to get started (it still may not /* Verify that we have a buffer big enough to get started (it still may not
* be big enough). * be big enough).
@@ -379,13 +381,20 @@ static int lib_find_answer(FAR const char *name, FAR struct hostent *host,
ptr = info->hi_data; ptr = info->hi_data;
buflen -= (sizeof(struct hostent_info_s) - 1); buflen -= (sizeof(struct hostent_info_s) - 1);
/* Verify again that there is space for at least one address. */
if (buflen < sizeof(union dns_addr_u))
{
return -ERANGE;
}
memset(host, 0, sizeof(struct hostent)); memset(host, 0, sizeof(struct hostent));
memset(info, 0, sizeof(struct hostent_info_s)); memset(info, 0, sizeof(struct hostent_info_s));
/* Try to get the host address using the DNS name server */ /* Try to get the host address using the DNS name server */
addrlen = buflen; naddr = buflen / sizeof(union dns_addr_u);
ret = dns_find_answer(name, (FAR struct sockaddr *)ptr, &addrlen); ret = dns_find_answer(name, (FAR union dns_addr_u *)ptr, &naddr);
if (ret < 0) if (ret < 0)
{ {
/* No, nothing found in the cache */ /* No, nothing found in the cache */
@@ -393,41 +402,45 @@ static int lib_find_answer(FAR const char *name, FAR struct hostent *host,
return ret; return ret;
} }
/* Get the address type; verify the address size. */ DEBUGASSERT(naddr <= CONFIG_NETDB_DNSCLIENT_MAXIP);
/* Get the address type. */
for (i = 0; i < naddr; i++)
{
#ifdef CONFIG_NET_IPv4 #ifdef CONFIG_NET_IPv4
#ifdef CONFIG_NET_IPv6 #ifdef CONFIG_NET_IPv6
if (((FAR struct sockaddr_in *)ptr)->sin_family == AF_INET) if (((FAR struct sockaddr_in *)ptr)->sin_family == AF_INET)
#endif #endif
{ {
DEBUGASSERT(addrlen == sizeof(struct sockaddr_in)); addrlen = sizeof(struct sockaddr_in);
addrlen = sizeof(struct sockaddr_in); addrtype = AF_INET;
addrtype = AF_INET; addrdata = &((FAR struct sockaddr_in *)ptr)->sin_addr;
addrdata = &((FAR struct sockaddr_in *)ptr)->sin_addr; }
}
#endif #endif
#ifdef CONFIG_NET_IPv6 #ifdef CONFIG_NET_IPv6
#ifdef CONFIG_NET_IPv4 #ifdef CONFIG_NET_IPv4
else else
#endif #endif
{ {
DEBUGASSERT(addrlen == sizeof(struct sockaddr_in6)); addrlen = sizeof(struct sockaddr_in6);
addrlen = sizeof(struct sockaddr_in6); addrtype = AF_INET6;
addrtype = AF_INET6; addrdata = &((FAR struct sockaddr_in6 *)ptr)->sin6_addr;
addrdata = &((FAR struct sockaddr_in6 *)ptr)->sin6_addr; }
#endif
/* REVISIT: This assumes addresses are all either IPv4 or IPv6. */
info->hi_addrlist[i] = addrdata;
host->h_addrtype = addrtype;
host->h_length = addrlen;
ptr += sizeof(union dns_addr_u);
buflen -= sizeof(union dns_addr_u);
} }
#endif
/* Yes.. Return the address that we obtained from the DNS cache. */ host->h_addr_list = info->hi_addrlist;
info->hi_addrlist[0] = addrdata;
host->h_addr_list = info->hi_addrlist;
host->h_addrtype = addrtype;
host->h_length = addrlen;
ptr += addrlen;
buflen -= addrlen;
/* And copy name */ /* And copy name */
@@ -459,7 +472,7 @@ static int lib_find_answer(FAR const char *name, FAR struct hostent *host,
#ifdef CONFIG_NETDB_DNSCLIENT #ifdef CONFIG_NETDB_DNSCLIENT
static int lib_dns_query(FAR const char *hostname, static int lib_dns_query(FAR const char *hostname,
FAR struct sockaddr *addr, socklen_t *addrlen) FAR union dns_addr_u *addr, int *naddr)
{ {
int sd; int sd;
int ret; int ret;
@@ -474,7 +487,7 @@ static int lib_dns_query(FAR const char *hostname,
/* Perform the query to get the IP address */ /* Perform the query to get the IP address */
ret = dns_query(sd, hostname, addr, addrlen); ret = dns_query(sd, hostname, addr, naddr);
/* Release the socket */ /* Release the socket */
@@ -509,9 +522,11 @@ static int lib_dns_lookup(FAR const char *name, FAR struct hostent *host,
FAR char *ptr; FAR char *ptr;
FAR void *addrdata; FAR void *addrdata;
socklen_t addrlen; socklen_t addrlen;
int naddr;
int addrtype; int addrtype;
int namelen; int namelen;
int ret; int ret;
int i;
/* Verify that we have a buffer big enough to get started (it still may not /* Verify that we have a buffer big enough to get started (it still may not
* be big enough). * be big enough).
@@ -528,26 +543,36 @@ static int lib_dns_lookup(FAR const char *name, FAR struct hostent *host,
ptr = info->hi_data; ptr = info->hi_data;
buflen -= (sizeof(struct hostent_info_s) - 1); buflen -= (sizeof(struct hostent_info_s) - 1);
/* Verify again that there is space for at least one address. */
if (buflen < sizeof(union dns_addr_u))
{
return -ERANGE;
}
memset(host, 0, sizeof(struct hostent)); memset(host, 0, sizeof(struct hostent));
memset(info, 0, sizeof(struct hostent_info_s)); memset(info, 0, sizeof(struct hostent_info_s));
/* Try to get the host address using the DNS name server */ /* Try to get the host address using the DNS name server */
addrlen = buflen; naddr = buflen / sizeof(union dns_addr_u);
ret = lib_dns_query(name, (FAR struct sockaddr *)ptr, &addrlen); ret = lib_dns_query(name, (FAR union dns_addr_u *)ptr, &naddr);
if (ret < 0)
/* Was the DNS lookup successful? */
if (ret >= 0)
{ {
/* Get the address type; verify the address size. */ return ret;
}
/* We can read more than maximum, limit here. */
naddr = MIN(naddr, CONFIG_NETDB_DNSCLIENT_MAXIP);
for (i = 0; i < naddr; i++)
{
#ifdef CONFIG_NET_IPv4 #ifdef CONFIG_NET_IPv4
#ifdef CONFIG_NET_IPv6 #ifdef CONFIG_NET_IPv6
if (((FAR struct sockaddr_in *)ptr)->sin_family == AF_INET) if (((FAR struct sockaddr_in *)ptr)->sin_family == AF_INET)
#endif #endif
{ {
DEBUGASSERT(addrlen == sizeof(struct sockaddr_in));
addrlen = sizeof(struct sockaddr_in); addrlen = sizeof(struct sockaddr_in);
addrtype = AF_INET; addrtype = AF_INET;
addrdata = &((FAR struct sockaddr_in *)ptr)->sin_addr; addrdata = &((FAR struct sockaddr_in *)ptr)->sin_addr;
@@ -559,40 +584,39 @@ static int lib_dns_lookup(FAR const char *name, FAR struct hostent *host,
else else
#endif #endif
{ {
DEBUGASSERT(addrlen == sizeof(struct sockaddr_in6));
addrlen = sizeof(struct sockaddr_in6); addrlen = sizeof(struct sockaddr_in6);
addrtype = AF_INET6; addrtype = AF_INET6;
addrdata = &((FAR struct sockaddr_in6 *)ptr)->sin6_addr; addrdata = &((FAR struct sockaddr_in6 *)ptr)->sin6_addr;
} }
#endif #endif
/* Yes.. Return the address that we obtained from the DNS name server. */ /* REVISIT: This assumes addresses are all either IPv4 or IPv6. */
info->hi_addrlist[0] = addrdata; info->hi_addrlist[i] = addrdata;
host->h_addr_list = info->hi_addrlist;
host->h_addrtype = addrtype; host->h_addrtype = addrtype;
host->h_length = addrlen; host->h_length = addrlen;
ptr += addrlen; ptr += sizeof(union dns_addr_u);
buflen -= addrlen; buflen -= sizeof(union dns_addr_u);
/* And copy name */
namelen = strlen(name);
if ((namelen + 1) > buflen)
{
return -ERANGE;
}
strncpy(ptr, name, buflen);
/* Set the address to h_name */
host->h_name = ptr;
return OK;
} }
return ret; host->h_addr_list = info->hi_addrlist;
/* And copy name */
namelen = strlen(name);
if ((namelen + 1) > buflen)
{
return -ERANGE;
}
strncpy(ptr, name, buflen);
/* Set the address to h_name */
host->h_name = ptr;
return OK;
} }
#endif /* CONFIG_NETDB_DNSCLIENT */ #endif /* CONFIG_NETDB_DNSCLIENT */