DNS: Finish off low-level DNS IPv6 request processing. Untested on initial commit
This commit is contained in:
parent
d8da7009c6
commit
9a6cf5724e
12
ChangeLog
12
ChangeLog
@ -10702,10 +10702,16 @@
|
||||
logic in preparation for IPv6 support (2015-07-12):
|
||||
- Rename include/nuttx/net/dnsclient.h to 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
|
||||
- Eliminate dns_gethostip(). This is now an internal part of gethostbyname()
|
||||
- Global standard DNS definitions from libc/netdb/dns_soccket.c to
|
||||
dns.h
|
||||
- Eliminate dns_gethostip(). This is now an internal part of
|
||||
gethostbyname()
|
||||
- Eliminate interface dns_whois(). Not needed in this new context.
|
||||
* include/nuttx/net/ and libc/netdb: Modifications to DNS client logic
|
||||
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).
|
||||
|
@ -53,6 +53,60 @@
|
||||
/****************************************************************************
|
||||
* 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_OPCODE_STATUS 0x10
|
||||
@ -61,6 +115,9 @@
|
||||
#define DNS_FLAG1_AUTHORATIVE 0x04
|
||||
#define DNS_FLAG1_TRUNC 0x02
|
||||
#define DNS_FLAG1_RD 0x01
|
||||
|
||||
/* Flag2 bit definitions */
|
||||
|
||||
#define DNS_FLAG2_RA 0x80
|
||||
#define DNS_FLAG2_ERR_MASK 0x0f
|
||||
#define DNS_FLAG2_ERR_NONE 0x00
|
||||
@ -87,19 +144,20 @@ struct dns_header_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 class;
|
||||
uint16_t ttl[2];
|
||||
uint16_t len;
|
||||
#if 0 /* REVISIT: Not yet support for IPv6 */
|
||||
struct in6_addr ipaddr;
|
||||
#else
|
||||
struct in_addr ipaddr;
|
||||
|
||||
union
|
||||
{
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
struct in_addr ipv4;
|
||||
#endif
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
struct in6_addr ipv6;
|
||||
#endif
|
||||
} u;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -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
|
||||
{
|
||||
@ -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,
|
||||
FAR union dns_server_u *uaddr)
|
||||
FAR union dns_server_u *uaddr, uint16_t rectype)
|
||||
{
|
||||
register FAR struct dns_header_s *hdr;
|
||||
FAR char *query;
|
||||
FAR char *nptr;
|
||||
FAR const char *nameptr;
|
||||
FAR uint8_t *dest;
|
||||
FAR uint8_t *nptr;
|
||||
FAR const char *src;
|
||||
uint8_t seqno = g_seqno++;
|
||||
static unsigned char endquery[] = {0, 0, 1, 0, 1};
|
||||
char buffer[SEND_BUFFER_SIZE];
|
||||
uint8_t buffer[SEND_BUFFER_SIZE];
|
||||
socklen_t addrlen;
|
||||
int errcode;
|
||||
int ret;
|
||||
@ -157,26 +156,36 @@ static int dns_send_query(int sd, FAR const char *name,
|
||||
hdr->id = htons(seqno);
|
||||
hdr->flags1 = DNS_FLAG1_RD;
|
||||
hdr->numquestions = HTONS(1);
|
||||
query = buffer + 12;
|
||||
dest = buffer + 12;
|
||||
|
||||
/* Convert hostname into suitable query format. */
|
||||
|
||||
nameptr = name - 1;
|
||||
src = name - 1;
|
||||
do
|
||||
{
|
||||
nameptr++;
|
||||
nptr = query++;
|
||||
for (n = 0; *nameptr != '.' && *nameptr != 0; nameptr++)
|
||||
{
|
||||
*query++ = *nameptr;
|
||||
n++;
|
||||
}
|
||||
/* Copy the name string */
|
||||
|
||||
*nptr = n;
|
||||
}
|
||||
while (*nameptr != 0);
|
||||
src++;
|
||||
nptr = dest++;
|
||||
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 */
|
||||
|
||||
@ -198,7 +207,7 @@ static int dns_send_query(int sd, FAR const char *name,
|
||||
}
|
||||
#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 */
|
||||
|
||||
@ -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,
|
||||
FAR socklen_t *addrlen)
|
||||
{
|
||||
FAR unsigned char *nameptr;
|
||||
FAR uint8_t *nameptr;
|
||||
char buffer[RECV_BUFFER_SIZE];
|
||||
FAR struct dns_answer_s *ans;
|
||||
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
|
||||
{
|
||||
int d = 64;
|
||||
nameptr = dns_parse_name((unsigned char *)buffer + 12) + 4;
|
||||
nameptr = dns_parse_name((uint8_t *)buffer + 12) + 4;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
@ -296,7 +305,7 @@ static int dns_recv_response(int sd, FAR struct sockaddr *addr,
|
||||
}
|
||||
#endif
|
||||
|
||||
nameptr = dns_parse_name((unsigned char *)buffer + 12) + 4;
|
||||
nameptr = dns_parse_name((uint8_t *)buffer + 12) + 4;
|
||||
|
||||
for (; nanswers > 0; nanswers--)
|
||||
{
|
||||
@ -318,43 +327,36 @@ static int dns_recv_response(int sd, FAR struct sockaddr *addr,
|
||||
nameptr = dns_parse_name(nameptr);
|
||||
}
|
||||
|
||||
ans = (struct dns_answer_s *)nameptr;
|
||||
nvdbg("Answer: type %x, class %x, ttl %x, length %x \n", /* 0x%08X\n", */
|
||||
ans = (FAR struct dns_answer_s *)nameptr;
|
||||
|
||||
nvdbg("Answer: type=%04x, class=%04x, ttl=%06x, length=%04x \n",
|
||||
htons(ans->type), htons(ans->class),
|
||||
(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. */
|
||||
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
# warning Missing IPv6 support!
|
||||
#endif
|
||||
/* Check for IPv4/6 address type and Internet class. Others are discarded. */
|
||||
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
if (ans->type == HTONS(1) &&
|
||||
ans->class == HTONS(1) &&
|
||||
if (ans->type == HTONS(DNS_RECTYPE_A) &&
|
||||
ans->class == HTONS(DNS_CLASS_IN) &&
|
||||
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",
|
||||
(ans->ipaddr.s_addr ) & 0xff,
|
||||
(ans->ipaddr.s_addr >> 8 ) & 0xff,
|
||||
(ans->ipaddr.s_addr >> 16 ) & 0xff,
|
||||
(ans->ipaddr.s_addr >> 24 ) & 0xff);
|
||||
nvdbg("IPv4 address: %d.%d.%d.%d\n",
|
||||
(ans->u.ipv4.s_addr ) & 0xff,
|
||||
(ans->u.ipv4.s_addr >> 8 ) & 0xff,
|
||||
(ans->u.ipv4.s_addr >> 16 ) & 0xff,
|
||||
(ans->u.ipv4.s_addr >> 24 ) & 0xff);
|
||||
|
||||
/* TODO: we should really check that this IP address is the one
|
||||
* we want.
|
||||
*/
|
||||
|
||||
if (*addrlen >=sizeof(struct sockaddr_in))
|
||||
if (*addrlen >= sizeof(struct sockaddr_in))
|
||||
{
|
||||
FAR struct sockaddr_in *inaddr;
|
||||
|
||||
inaddr = (FAR struct sockaddr_in *)addr;
|
||||
inaddr->sin_family = AF_INET;
|
||||
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);
|
||||
return OK;
|
||||
@ -365,6 +367,38 @@ static int dns_recv_response(int sd, FAR struct sockaddr *addr,
|
||||
}
|
||||
}
|
||||
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
|
||||
{
|
||||
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,
|
||||
FAR socklen_t *addrlen)
|
||||
{
|
||||
#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv4)
|
||||
int noipv4 = false;
|
||||
int noipv6 = false;
|
||||
#endif
|
||||
int retries;
|
||||
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++)
|
||||
{
|
||||
/* 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 (ret < 0)
|
||||
if (!noipv4)
|
||||
#endif
|
||||
{
|
||||
ndbg("ERROR: dns_send_query failed: %d\n", ret);
|
||||
return ret;
|
||||
/* Send the IPv4 query */
|
||||
|
||||
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 (ret >= 0)
|
||||
if (!noipv6)
|
||||
#endif
|
||||
{
|
||||
/* Response received successfully */
|
||||
/* Save the host address -- Needs fixed for IPv6 */
|
||||
/* Send the IPv6 query */
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* Handler errors */
|
||||
|
||||
ndbg("ERROR: dns_recv_response failed: %d\n", ret);
|
||||
|
||||
if (ret != -EAGAIN)
|
||||
{
|
||||
/* Some failure other than receive timeout occurred */
|
||||
|
||||
return ret;
|
||||
ret = dns_send_query(sd, hostname, &g_dns_server,
|
||||
DNS_RECTYPE_AAAA);
|
||||
if (ret < 0)
|
||||
{
|
||||
ndbg("ERROR: IPv6 dns_send_query failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Obtain the IPv6 response */
|
||||
|
||||
ret = dns_recv_response(sd, addr, addrlen);
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user