From 196120fabd2897f6cfb9ebb31535d2328554c52c Mon Sep 17 00:00:00 2001 From: goldsimon Date: Fri, 4 Sep 2015 13:57:20 +0200 Subject: [PATCH] worked on task #12243 (Add support for AAAA/IPv6 records to DNS) --- src/api/api_lib.c | 14 ++++++++++ src/api/api_msg.c | 6 ++++- src/api/netdb.c | 53 +++++++++++++++++++++++++++++++++----- src/core/dns.c | 34 +++++++++++++++++++++++- src/include/lwip/api.h | 15 +++++++++++ src/include/lwip/api_msg.h | 4 +++ src/include/lwip/dns.h | 34 +++--------------------- src/include/lwip/netdb.h | 21 ++++++++++++--- 8 files changed, 139 insertions(+), 42 deletions(-) diff --git a/src/api/api_lib.c b/src/api/api_lib.c index 481b2e72..b864c64e 100644 --- a/src/api/api_lib.c +++ b/src/api/api_lib.c @@ -821,8 +821,13 @@ netconn_join_leave_group(struct netconn *conn, * ERR_ARG: dns client not initialized or invalid hostname * ERR_VAL: dns server response was invalid */ +#if LWIP_IPV4 && LWIP_IPV6 +err_t +netconn_gethostbyname_addrtype(const char *name, ip_addr_t *addr, u8_t dns_addrtype) +#else err_t netconn_gethostbyname(const char *name, ip_addr_t *addr) +#endif { API_VAR_DECLARE(struct dns_api_msg, msg); #if !LWIP_MPU_COMPATIBLE @@ -848,15 +853,24 @@ netconn_gethostbyname(const char *name, ip_addr_t *addr) API_VAR_REF(msg).addr = API_VAR_REF(addr); API_VAR_REF(msg).name = name; #endif /* LWIP_MPU_COMPATIBLE */ +#if LWIP_IPV4 && LWIP_IPV6 + API_VAR_REF(msg).dns_addrtype = dns_addrtype; +#endif LWIP_IPV4 && LWIP_IPV6 +#if LWIP_NETCONN_SEM_PER_THREAD + API_VAR_REF(msg).sem = LWIP_NETCONN_THREAD_SEM_GET(); +#else /* LWIP_NETCONN_SEM_PER_THREAD*/ err = sys_sem_new(API_EXPR_REF(API_VAR_REF(msg).sem), 0); if (err != ERR_OK) { API_VAR_FREE(MEMP_DNS_API_MSG, msg); return err; } +#endif /* LWIP_NETCONN_SEM_PER_THREAD */ tcpip_callback(lwip_netconn_do_gethostbyname, &API_VAR_REF(msg)); sys_sem_wait(API_EXPR_REF(API_VAR_REF(msg).sem)); +#if !LWIP_NETCONN_SEM_PER_THREAD sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem)); +#endif /* !LWIP_NETCONN_SEM_PER_THREAD */ #if LWIP_MPU_COMPATIBLE *addr = msg->addr; diff --git a/src/api/api_msg.c b/src/api/api_msg.c index 71c8d510..2764342b 100644 --- a/src/api/api_msg.c +++ b/src/api/api_msg.c @@ -1841,7 +1841,11 @@ lwip_netconn_do_gethostbyname(void *arg) { struct dns_api_msg *msg = (struct dns_api_msg*)arg; - API_EXPR_DEREF(msg->err) = dns_gethostbyname(msg->name, API_EXPR_REF(msg->addr), lwip_netconn_do_dns_found, msg); + API_EXPR_DEREF(msg->err) = dns_gethostbyname_addrtype(msg->name, API_EXPR_REF(msg->addr), lwip_netconn_do_dns_found, msg +#if LWIP_IPV4 && LWIP_IPV6 + , msg->dns_addrtype +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + ); if (API_EXPR_DEREF(msg->err) != ERR_INPROGRESS) { /* on error or immediate success, wake up the application * task waiting in netconn_gethostbyname */ diff --git a/src/api/netdb.c b/src/api/netdb.c index 3996ec91..d89d7e1b 100644 --- a/src/api/netdb.c +++ b/src/api/netdb.c @@ -260,6 +260,8 @@ lwip_freeaddrinfo(struct addrinfo *ai) * @param hints structure containing input values that set socktype and protocol * @param res pointer to a pointer where to store the result (set to NULL on failure) * @return 0 on success, non-zero on failure + * + * @todo: implement AI_V4MAPPED, AI_ADDRCONFIG */ int lwip_getaddrinfo(const char *nodename, const char *servname, @@ -272,6 +274,7 @@ lwip_getaddrinfo(const char *nodename, const char *servname, int port_nr = 0; size_t total_size; size_t namelen = 0; + int ai_family; if (res == NULL) { return EAI_FAIL; @@ -282,14 +285,24 @@ lwip_getaddrinfo(const char *nodename, const char *servname, } if (hints != NULL) { - if ((hints->ai_family != AF_UNSPEC) && (hints->ai_family != AF_INET)) { + ai_family = hints->ai_family; + if ((ai_family != AF_UNSPEC) +#if LWIP_IPV4 + && (ai_family != AF_INET) +#endif /* LWIP_IPV4 */ +#if LWIP_IPV4 + && (ai_family != AF_INET6) +#endif /* LWIP_IPV4 */ + ) { return EAI_FAMILY; } + } else { + ai_family = AF_UNSPEC; } if (servname != NULL) { /* service name specified: convert to port number - * @todo?: currently, only ASCII integers (port numbers) are supported! */ + * @todo?: currently, only ASCII integers (port numbers) are supported (AI_NUMERICSERV)! */ port_nr = atoi(servname); if ((port_nr <= 0) || (port_nr > 0xffff)) { return EAI_SERVICE; @@ -298,13 +311,38 @@ lwip_getaddrinfo(const char *nodename, const char *servname, if (nodename != NULL) { /* service location specified, try to resolve */ - err = netconn_gethostbyname(nodename, &addr); - if (err != ERR_OK) { - return EAI_FAIL; + if ((hints != NULL) && (hints->ai_flags & AI_NUMERICHOST)) { + /* no DNS lookup, just parse for an address string */ + if(!ipaddr_aton(nodename, &addr)) { + return EAI_NONAME; + } +#if LWIP_IPV4 && LWIP_IPV6 + if ((IP_IS_V6_VAL(addr) && ai_family == AF_INET) || + (!IP_IS_V6_VAL(addr) && ai_family == AF_INET6)) { + return EAI_NONAME; + } + } else { +#if LWIP_IPV4 && LWIP_IPV6 + /* AF_UNSPEC: prefer IPv4 */ + u8_t type = NETCONN_DNS_IPV4_IPV6; + if (ai_family == AF_INET) { + type = NETCONN_DNS_IPV4; + } else if(ai_family == AF_INET6) { + type = NETCONN_DNS_IPV6; + } +#endif /* LWIP_IPV4 && LWIP_IPV6 */ + err = netconn_gethostbyname_addrtype(nodename, &addr, type); + if (err != ERR_OK) { + return EAI_FAIL; + } } } else { /* service location specified, use loopback address */ - ip_addr_set_loopback(1, &addr); + if ((hints != NULL) && (hints->ai_flags & AI_PASSIVE)) { + ip_addr_set_any(ai_family == AF_INET6, &addr); + } else { + ip_addr_set_loopback(ai_family == AF_INET6, &addr); + } } total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_in); @@ -330,6 +368,7 @@ lwip_getaddrinfo(const char *nodename, const char *servname, sa6->sin6_family = AF_INET6; sa6->sin6_len = sizeof(struct sockaddr_in6); sa6->sin6_port = htons((u16_t)port_nr); + ai->ai_family = AF_INET6; #endif /* LWIP_IPV6 */ } else { #if LWIP_IPV4 @@ -339,11 +378,11 @@ lwip_getaddrinfo(const char *nodename, const char *servname, sa4->sin_family = AF_INET; sa4->sin_len = sizeof(struct sockaddr_in); sa4->sin_port = htons((u16_t)port_nr); + ai->ai_family = AF_INET; #endif /* LWIP_IPV4 */ } /* set up addrinfo */ - ai->ai_family = AF_INET; if (hints != NULL) { /* copy socktype & protocol from hints if specified */ ai->ai_socktype = hints->ai_socktype; diff --git a/src/core/dns.c b/src/core/dns.c index e3c27cd4..967fca4a 100644 --- a/src/core/dns.c +++ b/src/core/dns.c @@ -179,6 +179,32 @@ static u16_t dns_txid; #define LWIP_DNS_SET_ADDRTYPE(x, y) #endif /* LWIP_IPV4 && LWIP_IPV6 */ +/** DNS field TYPE used for "Resource Records" */ +#define DNS_RRTYPE_A 1 /* a host address */ +#define DNS_RRTYPE_NS 2 /* an authoritative name server */ +#define DNS_RRTYPE_MD 3 /* a mail destination (Obsolete - use MX) */ +#define DNS_RRTYPE_MF 4 /* a mail forwarder (Obsolete - use MX) */ +#define DNS_RRTYPE_CNAME 5 /* the canonical name for an alias */ +#define DNS_RRTYPE_SOA 6 /* marks the start of a zone of authority */ +#define DNS_RRTYPE_MB 7 /* a mailbox domain name (EXPERIMENTAL) */ +#define DNS_RRTYPE_MG 8 /* a mail group member (EXPERIMENTAL) */ +#define DNS_RRTYPE_MR 9 /* a mail rename domain name (EXPERIMENTAL) */ +#define DNS_RRTYPE_NULL 10 /* a null RR (EXPERIMENTAL) */ +#define DNS_RRTYPE_WKS 11 /* a well known service description */ +#define DNS_RRTYPE_PTR 12 /* a domain name pointer */ +#define DNS_RRTYPE_HINFO 13 /* host information */ +#define DNS_RRTYPE_MINFO 14 /* mailbox or mail list information */ +#define DNS_RRTYPE_MX 15 /* mail exchange */ +#define DNS_RRTYPE_TXT 16 /* text strings */ +#define DNS_RRTYPE_AAAA 28 /* IPv6 address */ + +/** DNS field CLASS used for "Resource Records" */ +#define DNS_RRCLASS_IN 1 /* the Internet */ +#define DNS_RRCLASS_CS 2 /* the CSNET class (Obsolete - used only for examples in some obsolete RFCs) */ +#define DNS_RRCLASS_CH 3 /* the CHAOS class */ +#define DNS_RRCLASS_HS 4 /* Hesiod [Dyer 87] */ +#define DNS_RRCLASS_FLUSH 0x800 /* Flush bit */ + /* DNS protocol flags */ #define DNS_FLAG1_RESPONSE 0x80 #define DNS_FLAG1_OPCODE_STATUS 0x10 @@ -1439,7 +1465,13 @@ dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, dns_found_call /* host name already in octet notation? set ip addr and return ERR_OK */ if (ipaddr_aton(hostname, addr)) { - return ERR_OK; +#if LWIP_IPV4 && LWIP_IPV6 + if ((IP_IS_V6(addr) && (dns_addrtype != LWIP_DNS_ADDRTYPE_IPV4)) || + !(IP_IS_V6(addr) && (dns_addrtype != LWIP_DNS_ADDRTYPE_IPV6))) +#endif LWIP_IPV4 && LWIP_IPV6 + { + return ERR_OK; + } } /* already have this address cached? */ if(dns_lookup(hostname, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)) == ERR_OK) { diff --git a/src/include/lwip/api.h b/src/include/lwip/api.h index 876489f4..c09dee16 100644 --- a/src/include/lwip/api.h +++ b/src/include/lwip/api.h @@ -149,6 +149,15 @@ enum netconn_igmp { }; #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ +#if LWIP_DNS +/* Used for netconn_gethostbyname_addrtype(), these should match the DNS_ADDRTYPE defines in dns.h */ +#define NETCONN_DNS_DEFAULT NETCONN_DNS_IPV4_IPV6 +#define NETCONN_DNS_IPV4 0 +#define NETCONN_DNS_IPV6 1 +#define NETCONN_DNS_IPV4_IPV6 2 /* try to resolve IPv4 first, try IPv6 if IPv4 fails only */ +#define NETCONN_DNS_IPV6_IPV4 3 /* try to resolve IPv6 first, try IPv4 if IPv6 fails only */ +#endif /* LWIP_DNS */ + /* forward-declare some structs to avoid to include their headers */ struct ip_pcb; struct tcp_pcb; @@ -283,7 +292,13 @@ LWIP_NETCONN_SCOPE err_t netconn_join_leave_group(struct netconn *conn, const const ip_addr_t *netif_addr, enum netconn_igmp join_or_leave); #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ #if LWIP_DNS +#if LWIP_IPV4 && LWIP_IPV6 +err_t netconn_gethostbyname_addrtype(const char *name, ip_addr_t *addr, u8_t dns_addrtype); +#define netconn_gethostbyname(name, addr) netconn_gethostbyname_addrtype(name, addr, NETCONN_DNS_DEFAULT) +#else /* LWIP_IPV4 && LWIP_IPV6 */ err_t netconn_gethostbyname(const char *name, ip_addr_t *addr); +#define netconn_gethostbyname_addrtype(name, addr, dns_addrtype netconn_gethostbyname(name, addr) +#endif /* LWIP_IPV4 && LWIP_IPV6 */ #endif /* LWIP_DNS */ #define netconn_err(conn) ((conn)->last_err) diff --git a/src/include/lwip/api_msg.h b/src/include/lwip/api_msg.h index 2a214163..98381ef8 100644 --- a/src/include/lwip/api_msg.h +++ b/src/include/lwip/api_msg.h @@ -171,6 +171,10 @@ struct dns_api_msg { #endif /* LWIP_MPU_COMPATIBLE */ /** The resolved address is stored here */ ip_addr_t API_MSG_M_DEF(addr); +#if LWIP_IPV4 && LWIP_IPV6 + /** Type of resolve call */ + u8_t dns_addrtype; +#endif /* LWIP_IPV4 && LWIP_IPV6 */ /** This semaphore is posted when the name is resolved, the application thread should wait on it. */ sys_sem_t API_MSG_M_DEF(sem); diff --git a/src/include/lwip/dns.h b/src/include/lwip/dns.h index 67ac3206..cfe5be18 100644 --- a/src/include/lwip/dns.h +++ b/src/include/lwip/dns.h @@ -45,37 +45,11 @@ extern "C" { /** DNS timer period */ #define DNS_TMR_INTERVAL 1000 -/** DNS field TYPE used for "Resource Records" */ -#define DNS_RRTYPE_A 1 /* a host address */ -#define DNS_RRTYPE_NS 2 /* an authoritative name server */ -#define DNS_RRTYPE_MD 3 /* a mail destination (Obsolete - use MX) */ -#define DNS_RRTYPE_MF 4 /* a mail forwarder (Obsolete - use MX) */ -#define DNS_RRTYPE_CNAME 5 /* the canonical name for an alias */ -#define DNS_RRTYPE_SOA 6 /* marks the start of a zone of authority */ -#define DNS_RRTYPE_MB 7 /* a mailbox domain name (EXPERIMENTAL) */ -#define DNS_RRTYPE_MG 8 /* a mail group member (EXPERIMENTAL) */ -#define DNS_RRTYPE_MR 9 /* a mail rename domain name (EXPERIMENTAL) */ -#define DNS_RRTYPE_NULL 10 /* a null RR (EXPERIMENTAL) */ -#define DNS_RRTYPE_WKS 11 /* a well known service description */ -#define DNS_RRTYPE_PTR 12 /* a domain name pointer */ -#define DNS_RRTYPE_HINFO 13 /* host information */ -#define DNS_RRTYPE_MINFO 14 /* mailbox or mail list information */ -#define DNS_RRTYPE_MX 15 /* mail exchange */ -#define DNS_RRTYPE_TXT 16 /* text strings */ -#define DNS_RRTYPE_AAAA 28 /* IPv6 address */ - -/** DNS field CLASS used for "Resource Records" */ -#define DNS_RRCLASS_IN 1 /* the Internet */ -#define DNS_RRCLASS_CS 2 /* the CSNET class (Obsolete - used only for examples in some obsolete RFCs) */ -#define DNS_RRCLASS_CH 3 /* the CHAOS class */ -#define DNS_RRCLASS_HS 4 /* Hesiod [Dyer 87] */ -#define DNS_RRCLASS_FLUSH 0x800 /* Flush bit */ - /* DNS resolve types: */ -#define LWIP_DNS_ADDRTYPE_IPV4_IPV6 0 /* try to resolve IPv4 first, try IPv6 if IPv4 fails only */ -#define LWIP_DNS_ADDRTYPE_IPV6_IPV4 0xFF /* try to resolve IPv6 first, try IPv4 if IPv6 fails only */ -#define LWIP_DNS_ADDRTYPE_IPV4 DNS_RRTYPE_A -#define LWIP_DNS_ADDRTYPE_IPV6 DNS_RRTYPE_AAAA +#define LWIP_DNS_ADDRTYPE_IPV4 0 +#define LWIP_DNS_ADDRTYPE_IPV6 1 +#define LWIP_DNS_ADDRTYPE_IPV4_IPV6 2 /* try to resolve IPv4 first, try IPv6 if IPv4 fails only */ +#define LWIP_DNS_ADDRTYPE_IPV6_IPV4 3 /* try to resolve IPv6 first, try IPv4 if IPv6 fails only */ #if DNS_LOCAL_HOSTLIST /** struct used for local host-list */ diff --git a/src/include/lwip/netdb.h b/src/include/lwip/netdb.h index 199c7c53..fbcd5f2d 100644 --- a/src/include/lwip/netdb.h +++ b/src/include/lwip/netdb.h @@ -44,15 +44,19 @@ extern "C" { /* some rarely used options */ #ifndef LWIP_DNS_API_DECLARE_H_ERRNO -#define LWIP_DNS_API_DECLARE_H_ERRNO 1 +#define LWIP_DNS_API_DECLARE_H_ERRNO 1 #endif #ifndef LWIP_DNS_API_DEFINE_ERRORS -#define LWIP_DNS_API_DEFINE_ERRORS 1 +#define LWIP_DNS_API_DEFINE_ERRORS 1 +#endif + +#ifndef LWIP_DNS_API_DEFINE_FLAGS +#define LWIP_DNS_API_DEFINE_FLAGS 1 #endif #ifndef LWIP_DNS_API_DECLARE_STRUCTS -#define LWIP_DNS_API_DECLARE_STRUCTS 1 +#define LWIP_DNS_API_DECLARE_STRUCTS 1 #endif #if LWIP_DNS_API_DEFINE_ERRORS @@ -69,6 +73,17 @@ extern "C" { #define TRY_AGAIN 213 #endif /* LWIP_DNS_API_DEFINE_ERRORS */ +#if LWIP_DNS_API_DEFINE_FLAGS +/* input flags for struct addrinfo */ +#define AI_PASSIVE 0x01 +#define AI_CANONNAME 0x02 +#define AI_NUMERICHOST 0x04 +#define AI_NUMERICSERV 0x08 +#define AI_V4MAPPED 0x10 +#define AI_ALL 0x20 +#define AI_ADDRCONFIG 0x40 +#endif /* LWIP_DNS_API_DEFINE_FLAGS */ + #if LWIP_DNS_API_DECLARE_STRUCTS struct hostent { char *h_name; /* Official name of the host. */