libc/netdb: Should query both IPv4 and IPv6 address regardless the server address type

Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
Change-Id: I1ba17b3078837cd5b857a13f104550613050d3e0
This commit is contained in:
Xiang Xiao 2020-03-29 14:34:14 +08:00 committed by patacongo
parent 2e57583219
commit 7f2810f73a

View File

@ -324,7 +324,7 @@ static int dns_send_query(int sd, FAR const char *name,
* *
****************************************************************************/ ****************************************************************************/
static int dns_recv_response(int sd, FAR union dns_addr_u *addr, int *naddr, static int dns_recv_response(int sd, FAR union dns_addr_u *addr, int naddr,
FAR struct dns_query_info_s *qinfo) FAR struct dns_query_info_s *qinfo)
{ {
FAR uint8_t *nameptr; FAR uint8_t *nameptr;
@ -339,6 +339,11 @@ static int dns_recv_response(int sd, FAR union dns_addr_u *addr, int *naddr,
int naddr_read; int naddr_read;
int ret; int ret;
if (naddr <= 0)
{
return -ERANGE;
}
/* Receive the response */ /* Receive the response */
ret = _NX_RECV(sd, buffer, RECV_BUFFER_SIZE, 0); ret = _NX_RECV(sd, buffer, RECV_BUFFER_SIZE, 0);
@ -456,6 +461,7 @@ static int dns_recv_response(int sd, FAR union dns_addr_u *addr, int *naddr,
if (nameptr == endofbuffer) if (nameptr == endofbuffer)
{ {
ret = -EILSEQ; ret = -EILSEQ;
nwarn("Further parse returned %d\n", ret);
break; break;
} }
@ -476,6 +482,8 @@ static int dns_recv_response(int sd, FAR union dns_addr_u *addr, int *naddr,
ans->len == HTONS(4) && ans->len == HTONS(4) &&
nameptr + 10 + 4 <= endofbuffer) nameptr + 10 + 4 <= endofbuffer)
{ {
FAR struct sockaddr_in *inaddr;
nameptr += 10 + 4; nameptr += 10 + 4;
ninfo("IPv4 address: %d.%d.%d.%d\n", ninfo("IPv4 address: %d.%d.%d.%d\n",
@ -484,22 +492,12 @@ static int dns_recv_response(int sd, FAR union dns_addr_u *addr, int *naddr,
(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 (naddr_read < *naddr)
{
FAR struct sockaddr_in *inaddr;
inaddr = &addr[naddr_read].ipv4; inaddr = &addr[naddr_read].ipv4;
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;
naddr_read++; if (++naddr_read >= naddr)
if (naddr_read >= *naddr)
{
break;
}
}
else
{ {
ret = -ERANGE; ret = -ERANGE;
break; break;
@ -513,6 +511,8 @@ static int dns_recv_response(int sd, FAR union dns_addr_u *addr, int *naddr,
ans->len == HTONS(16) && ans->len == HTONS(16) &&
nameptr + 10 + 16 <= endofbuffer) nameptr + 10 + 16 <= endofbuffer)
{ {
FAR struct sockaddr_in6 *inaddr;
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",
@ -521,22 +521,12 @@ static int dns_recv_response(int sd, FAR union dns_addr_u *addr, int *naddr,
ntohs(ans->u.ipv6.s6_addr[3]), ntohs(ans->u.ipv6.s6_addr[2]), ntohs(ans->u.ipv6.s6_addr[3]), ntohs(ans->u.ipv6.s6_addr[2]),
ntohs(ans->u.ipv6.s6_addr[1]), ntohs(*ans->u.ipv6.s6_addr)); ntohs(ans->u.ipv6.s6_addr[1]), ntohs(*ans->u.ipv6.s6_addr));
if (naddr_read < *naddr)
{
FAR struct sockaddr_in6 *inaddr;
inaddr = &addr[naddr_read].ipv6; inaddr = &addr[naddr_read].ipv6;
inaddr->sin6_family = AF_INET6; 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);
naddr_read++; if (++naddr_read >= naddr)
if (naddr_read >= *naddr)
{
break;
}
}
else
{ {
ret = -ERANGE; ret = -ERANGE;
break; break;
@ -553,13 +543,8 @@ static int dns_recv_response(int sd, FAR union dns_addr_u *addr, int *naddr,
{ {
ret = -EADDRNOTAVAIL; 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;
return (naddr_read > 0) ? naddr_read : ret;
} }
/**************************************************************************** /****************************************************************************
@ -586,6 +571,7 @@ static int dns_query_callback(FAR void *arg, FAR struct sockaddr *addr,
{ {
FAR struct dns_query_s *query = (FAR struct dns_query_s *)arg; FAR struct dns_query_s *query = (FAR struct dns_query_s *)arg;
FAR struct dns_query_info_s qinfo; FAR struct dns_query_info_s qinfo;
int next = 0;
int retries; int retries;
int ret; int ret;
@ -596,23 +582,6 @@ static int dns_query_callback(FAR void *arg, FAR struct sockaddr *addr,
for (retries = 0; retries < CONFIG_NETDB_DNSCLIENT_RETRIES; retries++) for (retries = 0; retries < CONFIG_NETDB_DNSCLIENT_RETRIES; retries++)
{ {
#ifdef CONFIG_NET_IPv4 #ifdef CONFIG_NET_IPv4
/* Is this an IPv4 address? */
if (addr->sa_family == AF_INET)
{
/* Yes.. verify the address size */
if (addrlen < sizeof(struct sockaddr_in))
{
/* Return zero to skip this address and try the next
* nameserver address in resolv.conf.
*/
nerr("ERROR: Invalid IPv4 address size: %d\n", addrlen);
query->result = -EINVAL;
return 0;
}
/* Send the IPv4 query */ /* Send the IPv4 query */
ret = dns_send_query(query->sd, query->hostname, ret = dns_send_query(query->sd, query->hostname,
@ -620,82 +589,28 @@ static int dns_query_callback(FAR void *arg, FAR struct sockaddr *addr,
DNS_RECTYPE_A, &qinfo); DNS_RECTYPE_A, &qinfo);
if (ret < 0) if (ret < 0)
{ {
/* Return zero to skip this address and try the next
* nameserver address in resolv.conf.
*/
nerr("ERROR: IPv4 dns_send_query failed: %d\n", ret); nerr("ERROR: IPv4 dns_send_query failed: %d\n", ret);
query->result = ret; query->result = ret;
return 0;
}
/* Obtain the IPv4 response */
ret = dns_recv_response(query->sd, query->addr, query->naddr,
&qinfo);
if (ret >= 0)
{
/* IPv4 response received successfully */
#if CONFIG_NETDB_DNSCLIENT_ENTRIES > 0
/* Save the answer in the DNS cache */
dns_save_answer(query->hostname, query->addr,
*query->naddr);
#endif
/* Return 1 to indicate to (1) stop the traversal, and (2)
* indicate that the address was found.
*/
return 1;
}
/* Handle errors */
nerr("ERROR: IPv4 dns_recv_response failed: %d\n", ret);
if (ret == -EADDRNOTAVAIL)
{
/* The IPv4 address is not available. Return zero to
* continue the tranversal with the next nameserver
* address in resolv.conf.
*/
query->result = -EADDRNOTAVAIL;
return 0;
}
else if (ret != -EAGAIN)
{
/* Some failure other than receive timeout occurred. Return
* zero to skip this address and try the next nameserver
* address in resolv.conf.
*/
query->result = ret;
return 0;
}
} }
else else
{
/* Obtain the IPv4 response */
ret = dns_recv_response(query->sd, &query->addr[next],
*query->naddr - next, &qinfo);
if (ret >= 0)
{
next += ret;
}
else
{
nerr("ERROR: IPv4 dns_recv_response failed: %d\n", ret);
query->result = ret;
}
}
#endif /* CONFIG_NET_IPv4 */ #endif /* CONFIG_NET_IPv4 */
#ifdef CONFIG_NET_IPv6 #ifdef CONFIG_NET_IPv6
/* Is this an IPv6 address? */
if (addr->sa_family == AF_INET6)
{
/* Yes.. verify the address size */
if (addrlen < sizeof(struct sockaddr_in6))
{
/* Return zero to skip this address and try the next
* nameserver address in resolv.conf.
*/
nerr("ERROR: Invalid IPv6 address size: %d\n", addrlen);
query->result = -EINVAL;
return 0;
}
/* Send the IPv6 query */ /* Send the IPv6 query */
ret = dns_send_query(query->sd, query->hostname, ret = dns_send_query(query->sd, query->hostname,
@ -703,77 +618,47 @@ static int dns_query_callback(FAR void *arg, FAR struct sockaddr *addr,
DNS_RECTYPE_AAAA, &qinfo); DNS_RECTYPE_AAAA, &qinfo);
if (ret < 0) if (ret < 0)
{ {
/* Return zero to skip this address and try the next
* nameserver address in resolv.conf.
*/
nerr("ERROR: IPv6 dns_send_query failed: %d\n", ret); nerr("ERROR: IPv6 dns_send_query failed: %d\n", ret);
query->result = ret; query->result = ret;
return 0;
} }
else
{
/* Obtain the IPv6 response */ /* Obtain the IPv6 response */
ret = dns_recv_response(query->sd, query->addr, query->naddr, ret = dns_recv_response(query->sd, &query->addr[next],
&qinfo); *query->naddr - next, &qinfo);
if (ret >= 0) if (ret >= 0)
{ {
/* IPv6 response received successfully */ next += ret;
}
else
{
nerr("ERROR: IPv6 dns_recv_response failed: %d\n", ret);
query->result = ret;
}
}
#endif
if (next > 0)
{
#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->naddr); dns_save_answer(query->hostname, query->addr, next);
#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.
*/ */
*query->naddr = next;
return 1; return 1;
} }
else if (query->result != -EAGAIN)
/* Handle errors */
nerr("ERROR: IPv6 dns_recv_response failed: %d\n", ret);
if (ret == -EADDRNOTAVAIL)
{ {
/* The IPv6 address is not available. Return zero to break;
* continue the tranversal with the next nameserver
* address in resolv.conf.
*/
query->result = -EADDRNOTAVAIL;
return 0;
}
else if (ret != -EAGAIN)
{
/* Some failure other than receive timeout occurred. Return
* zero to skip this address and try the next nameserver
* address in resolv.conf.
*/
query->result = ret;
return 0;
}
}
else
#endif
{
/* Unsupported address family. Return zero to continue the
* tranversal with the next nameserver address in resolv.conf.
*/
return 0;
} }
} }
/* We tried and could not communicate with this nameserver. Perhaps it
* is down? Return zero to continue with the next address in the
* resolv.conf file.
*/
query->result = -ETIMEDOUT;
return 0; return 0;
} }