DNS: Finish off low-level DNS IPv6 request processing. Untested on initial commit

This commit is contained in:
Gregory Nutt 2015-07-12 16:23:08 -06:00
parent d8da7009c6
commit 9a6cf5724e
3 changed files with 264 additions and 80 deletions

View File

@ -10702,10 +10702,16 @@
logic in preparation for IPv6 support (2015-07-12): logic in preparation for IPv6 support (2015-07-12):
- Rename include/nuttx/net/dnsclient.h to dns.h - Rename include/nuttx/net/dnsclient.h to dns.h
- Move internal DNS prototypes from dns.h to libc/netdb/lib_dns.h - Move internal DNS prototypes from dns.h to libc/netdb/lib_dns.h
- Global standard DNS definitions from libc/netdb/dns_soccket.c to dns.h - Global standard DNS definitions from libc/netdb/dns_soccket.c to
- Eliminate dns_gethostip(). This is now an internal part of gethostbyname() dns.h
- Eliminate dns_gethostip(). This is now an internal part of
gethostbyname()
- Eliminate interface dns_whois(). Not needed in this new context. - Eliminate interface dns_whois(). Not needed in this new context.
* include/nuttx/net/ and libc/netdb: Modifications to DNS client logic * include/nuttx/net/ and libc/netdb: Modifications to DNS client logic
and to dns_get/setserver() interfaces to support DNS clients at IPv6 and to dns_get/setserver() interfaces to support DNS clients at IPv6
addresses (still no support for resolution to IPv6 addresses) (2015-07-12). addresses (still no support for resolution to IPv6 addresses)
(2015-07-12).
* include/nuttx/net/ and libc/netdb: Implement the low-level network DNS
packet protocol to request and receive IPv6 address mappings
(2015-07-12).

View File

@ -53,6 +53,60 @@
/**************************************************************************** /****************************************************************************
* Pre-processor Definitions * Pre-processor Definitions
****************************************************************************/ ****************************************************************************/
/* DNS classes */
#define DNS_CLASS_IN 1 /* RFC 1035 Internet */
#define DNS_CLASS CH 3 /* N/A Chaos */
#define DNS_CLASS_HS 4 /* N/A Hesiod */
#define DNS_CLASS_QNONE 254 /* RFC 2136 QCLASS NONE */
#define DNS_CLASS_QANY 255 /* RFC 1035 QCLASS ANY */
/* DNS resource record types */
#define DNS_RECTYPE_A 1 /* RFC 1035 IPv4 ddress record */
#define DNS_RECTYPE_AAAA 28 /* RFC 3596 IPv6 address record */
#define DNS_RECTYPE_AFSDB 18 /* RFC 1183 AFS database record */
#define DNS_RECTYPE_APL 42 /* RFC 3123 Address Prefix List */
#define DNS_RECTYPE_CAA 257 /* RFC 6844 Certification Authority Authorization */
#define DNS_RECTYPE_CDNSKEY 60 /* RFC 7344 Child DNSKEY */
#define DNS_RECTYPE_CDS 59 /* RFC 7344 Child DS */
#define DNS_RECTYPE_CERT 37 /* RFC 4398 Certificate record */
#define DNS_RECTYPE_CNAME 5 /* RFC 1035 Canonical name record */
#define DNS_RECTYPE_DHCID 49 /* RFC 4701 DHCP identifier */
#define DNS_RECTYPE_DLV 32769 /* RFC 4431 DNSSEC Lookaside Validation record */
#define DNS_RECTYPE_DNAME 39 /* RFC 2672 Delegation Name */
#define DNS_RECTYPE_DNSKEY 48 /* RFC 4034 DNS Key record */
#define DNS_RECTYPE_DS 43 /* RFC 4034 Delegation signer */
#define DNS_RECTYPE_HIP 55 /* RFC 5205 Host Identity Protocol */
#define DNS_RECTYPE_IPSECKEY 45 /* RFC 4025 IPsec Key */
#define DNS_RECTYPE_KEY 25 /* RFC 2535 and RFC 2930 Key record */
#define DNS_RECTYPE_KX 36 /* RFC 2230 Key eXchanger record */
#define DNS_RECTYPE_LOC 29 /* RFC 1876 Location record */
#define DNS_RECTYPE_MX 15 /* RFC 1035 Mail exchange record */
#define DNS_RECTYPE_NAPTR 35 /* RFC 3403 Naming Authority Pointer */
#define DNS_RECTYPE_NS 2 /* RFC 1035 Name server 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_NSEC3PARAM 51 /* RFC 5155 NSEC3 parameters */
#define DNS_RECTYPE_PTR 12 /* RFC 1035 Pointer record */
#define DNS_RECTYPE_RRSIG 46 /* RFC 4034 DNSSEC signature */
#define DNS_RECTYPE_RP 17 /* RFC 1183 Responsible person */
#define DNS_RECTYPE_SIG 24 /* RFC 2535 Signature */
#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_SSHFP 44 /* RFC 4255 SSH Public Key Fingerprint */
#define DNS_RECTYPE_TA 32768 /* N/A DNSSEC Trust Authorities */
#define DNS_RECTYPE_TKEY 249 /* RFC 2930 Secret key record */
#define DNS_RECTYPE_TLSA 52 /* RFC 6698 TLSA certificate association */
#define DNS_RECTYPE_TSIG 250 /* RFC 2845 Transaction Signature */
#define DNS_RECTYPE_TXT 16 /* RFC 1035[1] Text record */
#define DNS_RECTYPE_ALL 255 /* RFC 1035 All cached records */
#define DNS_RECTYPE_AXFR 252 /* RFC 1035 Authoritative Zone Transfer */
#define DNS_RECTYPE_IXFR 251 /* RFC 1996 Incremental Zone Transfer */
#define DNS_RECTYPE_OPT 41 /* RFC 6891 Option */
/* Flag1 bit definitions */
#define DNS_FLAG1_RESPONSE 0x80 #define DNS_FLAG1_RESPONSE 0x80
#define DNS_FLAG1_OPCODE_STATUS 0x10 #define DNS_FLAG1_OPCODE_STATUS 0x10
@ -61,6 +115,9 @@
#define DNS_FLAG1_AUTHORATIVE 0x04 #define DNS_FLAG1_AUTHORATIVE 0x04
#define DNS_FLAG1_TRUNC 0x02 #define DNS_FLAG1_TRUNC 0x02
#define DNS_FLAG1_RD 0x01 #define DNS_FLAG1_RD 0x01
/* Flag2 bit definitions */
#define DNS_FLAG2_RA 0x80 #define DNS_FLAG2_RA 0x80
#define DNS_FLAG2_ERR_MASK 0x0f #define DNS_FLAG2_ERR_MASK 0x0f
#define DNS_FLAG2_ERR_NONE 0x00 #define DNS_FLAG2_ERR_NONE 0x00
@ -87,19 +144,20 @@ struct dns_header_s
struct dns_answer_s struct dns_answer_s
{ {
/* 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 type;
uint16_t class; uint16_t class;
uint16_t ttl[2]; uint16_t ttl[2];
uint16_t len; uint16_t len;
#if 0 /* REVISIT: Not yet support for IPv6 */
struct in6_addr ipaddr; union
#else {
struct in_addr ipaddr; #ifdef CONFIG_NET_IPv4
struct in_addr ipv4;
#endif #endif
#ifdef CONFIG_NET_IPv6
struct in6_addr ipv6;
#endif
} u;
}; };
/**************************************************************************** /****************************************************************************

View File

@ -109,9 +109,9 @@ static union dns_server_u g_dns_server;
* *
****************************************************************************/ ****************************************************************************/
static FAR unsigned char *dns_parse_name(FAR unsigned char *query) static FAR uint8_t *dns_parse_name(FAR uint8_t *query)
{ {
unsigned char n; uint8_t n;
do do
{ {
@ -138,15 +138,14 @@ static FAR unsigned char *dns_parse_name(FAR unsigned char *query)
****************************************************************************/ ****************************************************************************/
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) FAR union dns_server_u *uaddr, uint16_t rectype)
{ {
register FAR struct dns_header_s *hdr; register FAR struct dns_header_s *hdr;
FAR char *query; FAR uint8_t *dest;
FAR char *nptr; FAR uint8_t *nptr;
FAR const char *nameptr; FAR const char *src;
uint8_t seqno = g_seqno++; uint8_t seqno = g_seqno++;
static unsigned char endquery[] = {0, 0, 1, 0, 1}; uint8_t buffer[SEND_BUFFER_SIZE];
char buffer[SEND_BUFFER_SIZE];
socklen_t addrlen; socklen_t addrlen;
int errcode; int errcode;
int ret; int ret;
@ -157,26 +156,36 @@ static int dns_send_query(int sd, FAR const char *name,
hdr->id = htons(seqno); hdr->id = htons(seqno);
hdr->flags1 = DNS_FLAG1_RD; hdr->flags1 = DNS_FLAG1_RD;
hdr->numquestions = HTONS(1); hdr->numquestions = HTONS(1);
query = buffer + 12; dest = buffer + 12;
/* Convert hostname into suitable query format. */ /* Convert hostname into suitable query format. */
nameptr = name - 1; src = name - 1;
do do
{ {
nameptr++; /* Copy the name string */
nptr = query++;
for (n = 0; *nameptr != '.' && *nameptr != 0; nameptr++)
{
*query++ = *nameptr;
n++;
}
*nptr = n; src++;
} nptr = dest++;
while (*nameptr != 0); for (n = 0; *src != '.' && *src != 0; src++)
{
*dest++ = *(uint8_t *)src;
n++;
}
memcpy(query, endquery, 5); /* Pre-pend the name length */
*nptr = n;
}
while (*src != '\0');
/* Add NUL termination, DNS record type, and DNS class */
*dest++ = '\0'; /* NUL termination */
*dest++ = (rectype >> 8); /* DNS record type (big endian) */
*dest++ = (rectype & 0xff);
*dest++ = (DNS_CLASS_IN >> 8); /* DNS record class (big endian) */
*dest++ = (DNS_CLASS_IN & 0xff);
/* Send the request */ /* Send the request */
@ -198,7 +207,7 @@ static int dns_send_query(int sd, FAR const char *name,
} }
#endif #endif
ret = sendto(sd, buffer, query + 5 - buffer, 0, &uaddr->addr, addrlen); ret = sendto(sd, buffer, dest - buffer, 0, &uaddr->addr, addrlen);
/* Return the negated errno value on sendto failure */ /* Return the negated errno value on sendto failure */
@ -223,7 +232,7 @@ static int dns_send_query(int sd, FAR const char *name,
static int dns_recv_response(int sd, FAR struct sockaddr *addr, static int dns_recv_response(int sd, FAR struct sockaddr *addr,
FAR socklen_t *addrlen) FAR socklen_t *addrlen)
{ {
FAR unsigned char *nameptr; FAR uint8_t *nameptr;
char buffer[RECV_BUFFER_SIZE]; char buffer[RECV_BUFFER_SIZE];
FAR struct dns_answer_s *ans; FAR struct dns_answer_s *ans;
FAR struct dns_header_s *hdr; FAR struct dns_header_s *hdr;
@ -278,7 +287,7 @@ static int dns_recv_response(int sd, FAR struct sockaddr *addr,
#ifdef CONFIG_DEBUG_NET #ifdef CONFIG_DEBUG_NET
{ {
int d = 64; int d = 64;
nameptr = dns_parse_name((unsigned char *)buffer + 12) + 4; nameptr = dns_parse_name((uint8_t *)buffer + 12) + 4;
for (;;) for (;;)
{ {
@ -296,7 +305,7 @@ static int dns_recv_response(int sd, FAR struct sockaddr *addr,
} }
#endif #endif
nameptr = dns_parse_name((unsigned char *)buffer + 12) + 4; nameptr = dns_parse_name((uint8_t *)buffer + 12) + 4;
for (; nanswers > 0; nanswers--) for (; nanswers > 0; nanswers--)
{ {
@ -318,43 +327,36 @@ static int dns_recv_response(int sd, FAR struct sockaddr *addr,
nameptr = dns_parse_name(nameptr); nameptr = dns_parse_name(nameptr);
} }
ans = (struct dns_answer_s *)nameptr; ans = (FAR struct dns_answer_s *)nameptr;
nvdbg("Answer: type %x, class %x, ttl %x, length %x \n", /* 0x%08X\n", */
nvdbg("Answer: type=%04x, class=%04x, ttl=%06x, length=%04x \n",
htons(ans->type), htons(ans->class), htons(ans->type), htons(ans->class),
(htons(ans->ttl[0]) << 16) | htons(ans->ttl[1]), (htons(ans->ttl[0]) << 16) | htons(ans->ttl[1]),
htons(ans->len) /* , ans->ipaddr.s_addr */); htons(ans->len));
/* Check for IP address type and Internet class. Others are discarded. */ /* Check for IPv4/6 address type and Internet class. Others are discarded. */
#ifdef CONFIG_NET_IPv6
# warning Missing IPv6 support!
#endif
#ifdef CONFIG_NET_IPv4 #ifdef CONFIG_NET_IPv4
if (ans->type == HTONS(1) && if (ans->type == HTONS(DNS_RECTYPE_A) &&
ans->class == HTONS(1) && ans->class == HTONS(DNS_CLASS_IN) &&
ans->len == HTONS(4)) ans->len == HTONS(4))
{ {
ans->ipaddr.s_addr = *(FAR uint32_t *)(nameptr + 10); ans->u.ipv4.s_addr = *(FAR uint32_t *)(nameptr + 10);
nvdbg("IP address %d.%d.%d.%d\n", nvdbg("IPv4 address: %d.%d.%d.%d\n",
(ans->ipaddr.s_addr ) & 0xff, (ans->u.ipv4.s_addr ) & 0xff,
(ans->ipaddr.s_addr >> 8 ) & 0xff, (ans->u.ipv4.s_addr >> 8 ) & 0xff,
(ans->ipaddr.s_addr >> 16 ) & 0xff, (ans->u.ipv4.s_addr >> 16 ) & 0xff,
(ans->ipaddr.s_addr >> 24 ) & 0xff); (ans->u.ipv4.s_addr >> 24 ) & 0xff);
/* TODO: we should really check that this IP address is the one if (*addrlen >= sizeof(struct sockaddr_in))
* we want.
*/
if (*addrlen >=sizeof(struct sockaddr_in))
{ {
FAR struct sockaddr_in *inaddr; FAR struct sockaddr_in *inaddr;
inaddr = (FAR struct sockaddr_in *)addr; inaddr = (FAR struct sockaddr_in *)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->ipaddr.s_addr; inaddr->sin_addr.s_addr = ans->u.ipv4.s_addr;
*addrlen = sizeof(struct sockaddr_in); *addrlen = sizeof(struct sockaddr_in);
return OK; return OK;
@ -365,6 +367,38 @@ static int dns_recv_response(int sd, FAR struct sockaddr *addr,
} }
} }
else else
#endif
#ifdef CONFIG_NET_IPv6
if (ans->type == HTONS(DNS_RECTYPE_AAAA) &&
ans->class == HTONS(DNS_CLASS_IN) &&
ans->len == HTONS(16))
{
memcpy(&ans->u.ipv6.s6_addr, nameptr + 10, 16);
nvdbg("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[5]), htons(ans->u.ipv6.s6_addr[4]),
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]));
if (*addrlen >= sizeof(struct sockaddr_in6))
{
FAR struct sockaddr_in6 *inaddr;
inaddr = (FAR struct sockaddr_in6 *)addr;
inaddr->sin6_family = AF_INET;
inaddr->sin6_port = 0;
memcpy(inaddr->sin6_addr.s6_addr, ans->u.ipv6.s6_addr, 16);
*addrlen = sizeof(struct sockaddr_in6);
return OK;
}
else
{
return -ERANGE;
}
}
else
#endif #endif
{ {
nameptr = nameptr + 10 + htons(ans->len); nameptr = nameptr + 10 + htons(ans->len);
@ -443,6 +477,10 @@ int dns_bind(void)
int dns_query(int sd, FAR const char *hostname, FAR struct sockaddr *addr, int dns_query(int sd, FAR const char *hostname, FAR struct sockaddr *addr,
FAR socklen_t *addrlen) FAR socklen_t *addrlen)
{ {
#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv4)
int noipv4 = false;
int noipv6 = false;
#endif
int retries; int retries;
int ret; int ret;
@ -450,36 +488,118 @@ int dns_query(int sd, FAR const char *hostname, FAR struct sockaddr *addr,
for (retries = 0; retries < 3; retries++) for (retries = 0; retries < 3; retries++)
{ {
/* Send the query */ #ifdef CONFIG_NET_IPv4
#ifdef CONFIG_NET_IPv6
/* If we know that the IPv4 address is not available, then don't try
* again.
*/
ret = dns_send_query(sd, hostname, &g_dns_server); if (!noipv4)
if (ret < 0) #endif
{ {
ndbg("ERROR: dns_send_query failed: %d\n", ret); /* Send the IPv4 query */
return ret;
ret = dns_send_query(sd, hostname, &g_dns_server, DNS_RECTYPE_A);
if (ret < 0)
{
ndbg("ERROR: IPv4 dns_send_query failed: %d\n", ret);
return ret;
}
/* Obtain the IPv4 response */
ret = dns_recv_response(sd, addr, addrlen);
if (ret >= 0)
{
/* IPv4 response received successfully */
return OK;
}
/* Handle errors */
ndbg("ERROR: IPv4 dns_recv_response failed: %d\n", ret);
#ifdef CONFIG_NET_IPv6
if (ret != -EADDRNOTAVAIL)
{
/* The IPv4 address is not available. */
noipv4 = true;
if (noipv6)
{
/* Neither address is available */
return ret;
}
}
else
#endif
if (ret != -EAGAIN)
{
/* Some failure other than receive timeout occurred */
return ret;
}
} }
#endif
/* Obtain the response */ #ifdef CONFIG_NET_IPv6
#ifdef CONFIG_NET_IPv4
/* If we know that the IPv4 address is not available, then don't try
* again.
*/
ret = dns_recv_response(sd, addr, addrlen); if (!noipv6)
if (ret >= 0) #endif
{ {
/* Response received successfully */ /* Send the IPv6 query */
/* Save the host address -- Needs fixed for IPv6 */
return OK; ret = dns_send_query(sd, hostname, &g_dns_server,
} DNS_RECTYPE_AAAA);
if (ret < 0)
/* Handler errors */ {
ndbg("ERROR: IPv6 dns_send_query failed: %d\n", ret);
ndbg("ERROR: dns_recv_response failed: %d\n", ret); return ret;
}
if (ret != -EAGAIN)
{ /* Obtain the IPv6 response */
/* Some failure other than receive timeout occurred */
ret = dns_recv_response(sd, addr, addrlen);
return ret; if (ret >= 0)
{
/* IPv6 response received successfully */
return OK;
}
/* Handle errors */
ndbg("ERROR: IPv6 dns_recv_response failed: %d\n", ret);
#ifdef CONFIG_NET_IPv4
if (ret != -EADDRNOTAVAIL)
{
/* The IPv6 address is not available. */
noipv6 = true;
if (noipv4)
{
/* Neither address is available */
return ret;
}
}
else
#endif
if (ret != -EAGAIN)
{
/* Some failure other than receive timeout occurred */
return ret;
}
} }
#endif
} }
return -ETIMEDOUT; return -ETIMEDOUT;