diff --git a/src/api/api_msg.c b/src/api/api_msg.c index 1e4649d10..eccb22fb1 100644 --- a/src/api/api_msg.c +++ b/src/api/api_msg.c @@ -2198,6 +2198,7 @@ lwip_netconn_do_join_leave_group_netif(void *m) static void lwip_netconn_do_dns_found(const char *name, const ip_addr_t *ipaddr, void *arg) { + u8_t i; struct dns_api_msg *msg = (struct dns_api_msg *)arg; /* we trust the internal implementation to be correct :-) */ @@ -2209,7 +2210,10 @@ lwip_netconn_do_dns_found(const char *name, const ip_addr_t *ipaddr, void *arg) } else { /* address was resolved */ API_EXPR_DEREF(msg->err) = ERR_OK; - API_EXPR_DEREF(msg->addr) = *ipaddr; + + for (i=0; iaddr+i) = *(ipaddr+i); + } } /* wake up the application task waiting in netconn_gethostbyname */ sys_sem_signal(API_EXPR_REF_SEM(msg->sem)); diff --git a/src/api/netdb.c b/src/api/netdb.c index c6a4c9af9..e9f48e616 100644 --- a/src/api/netdb.c +++ b/src/api/netdb.c @@ -51,8 +51,8 @@ /** helper struct for gethostbyname_r to access the char* buffer */ struct gethostbyname_r_helper { - ip_addr_t *addr_list[2]; - ip_addr_t addr; + ip_addr_t *addr_list[DNS_MAX_HOST_IP+1]; /* The last entry in the list is always NULL */ + ip_addr_t addr[DNS_MAX_HOST_IP]; char *aliases; }; @@ -77,7 +77,7 @@ int h_errno; /** * Returns an entry containing addresses of address family AF_INET * for the host with name name. - * Due to dns_gethostbyname limitations, only one address is returned. + * dns_gethostbyname can return as many address as configured in DNS_MAX_HOST_IP. * * @param name the hostname to resolve * @return an entry containing addresses of address family AF_INET @@ -86,18 +86,19 @@ int h_errno; struct hostent * lwip_gethostbyname(const char *name) { + u8_t i; err_t err; - ip_addr_t addr; + ip_addr_t addr[DNS_MAX_HOST_IP]={0}, addr_zero={0}; /* buffer variables for lwip_gethostbyname() */ HOSTENT_STORAGE struct hostent s_hostent; HOSTENT_STORAGE char *s_aliases; - HOSTENT_STORAGE ip_addr_t s_hostent_addr; - HOSTENT_STORAGE ip_addr_t *s_phostent_addr[2]; + HOSTENT_STORAGE ip_addr_t s_hostent_addr[DNS_MAX_HOST_IP]; + HOSTENT_STORAGE ip_addr_t *s_phostent_addr[DNS_MAX_HOST_IP+1]; /* The last entry in the list is always NULL */ HOSTENT_STORAGE char s_hostname[DNS_MAX_NAME_LENGTH + 1]; /* query host IP address */ - err = netconn_gethostbyname(name, &addr); + err = netconn_gethostbyname(name, addr); if (err != ERR_OK) { LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err)); h_errno = HOST_NOT_FOUND; @@ -105,16 +106,22 @@ lwip_gethostbyname(const char *name) } /* fill hostent */ - s_hostent_addr = addr; - s_phostent_addr[0] = &s_hostent_addr; - s_phostent_addr[1] = NULL; + for (i=0; iaddr); + err = netconn_gethostbyname(name, h->addr); if (err != ERR_OK) { LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err)); *h_errnop = HOST_NOT_FOUND; @@ -208,13 +218,19 @@ lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf, hostname[namelen] = 0; /* fill hostent */ - h->addr_list[0] = &h->addr; - h->addr_list[1] = NULL; + for (i=0; iaddr[i])) { + h->addr_list[i] = &h->addr[i]; + } else { + break; + } + } + h->addr_list[i] = NULL; h->aliases = NULL; ret->h_name = hostname; ret->h_aliases = &h->aliases; - ret->h_addrtype = (IPADDR_TYPE_V4 == IP_GET_TYPE(&h->addr)? AF_INET : AF_INET6); - ret->h_length = IP_ADDR_RAW_SIZE(h->addr); + ret->h_addrtype = (IPADDR_TYPE_V4 == IP_GET_TYPE(&h->addr[0])? AF_INET : AF_INET6); + ret->h_length = IP_ADDR_RAW_SIZE(h->addr[0]); ret->h_addr_list = (char **)&h->addr_list; /* set result != NULL */ @@ -243,6 +259,107 @@ lwip_freeaddrinfo(struct addrinfo *ai) } } +/** + * Creates a new address information (addrinfo) structure based on the provided parameters. + * + * @param addr IP address to be used. + * @param nodename Optional node name associated with the address. + * @param hints Pointer to a struct addrinfo containing hints for the address resolution. + * @param port_nr Port number associated with the address. + * @param res Pointer to a pointer to struct addrinfo to store the created address information. + * @param idx Index of the address info in the list of returned address info. + * + * @return Returns ERR_OK on success, or an error code (EAI_FAIL, EAI_MEMORY) on failure. + */ +static int +create_addrinfo(ip_addr_t addr, const char *nodename, const struct addrinfo *hints, + int port_nr, struct addrinfo **res, const unsigned char idx) +{ + size_t total_size; + size_t namelen = 0; + struct addrinfo *ai; + struct sockaddr_storage *sa = NULL; +#if ESP_LWIP && LWIP_IPV4 && LWIP_IPV6 + int ai_family; + + if (hints != NULL) { + ai_family = hints->ai_family; + } else { + ai_family = AF_UNSPEC; + } + + if (ai_family == AF_INET6 && (hints->ai_flags & AI_V4MAPPED) + && IP_GET_TYPE(&addr) == IPADDR_TYPE_V4) { + /* Convert native V4 address to a V4-mapped IPV6 address */ + ip4_2_ipv4_mapped_ipv6(ip_2_ip6(&addr), ip_2_ip4(&addr)); + IP_SET_TYPE_VAL(addr, IPADDR_TYPE_V6); + } +#endif /* ESP_LWIP && LWIP_IPV4 && LWIP_IPV6 */ + + total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_storage); + if (nodename != NULL) { + namelen = strlen(nodename); + if (namelen > DNS_MAX_NAME_LENGTH) { + /* invalid name length */ + return EAI_FAIL; + } + LWIP_ASSERT("namelen is too long", total_size + namelen + 1 > total_size); + total_size += namelen + 1; + } + /* If this fails, please report to lwip-devel! :-) */ + LWIP_ASSERT("total_size <= NETDB_ELEM_SIZE: please report this!", + total_size <= NETDB_ELEM_SIZE); + ai = (struct addrinfo *)memp_malloc(MEMP_NETDB); + if (ai == NULL) { + return EAI_MEMORY; + } + memset(ai, 0, total_size); + /* cast through void* to get rid of alignment warnings */ + sa = (struct sockaddr_storage *)(void *)((u8_t *)ai + sizeof(struct addrinfo)); + if (IP_IS_V6_VAL(addr)) { +#if LWIP_IPV6 + struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa; + /* set up sockaddr */ + inet6_addr_from_ip6addr(&sa6->sin6_addr, ip_2_ip6(&addr)); + sa6->sin6_family = AF_INET6; + sa6->sin6_len = sizeof(struct sockaddr_in6); + sa6->sin6_port = lwip_htons((u16_t)port_nr); + sa6->sin6_scope_id = ip6_addr_zone(ip_2_ip6(&addr)); + ai->ai_family = AF_INET6; +#endif /* LWIP_IPV6 */ + } else { +#if LWIP_IPV4 + struct sockaddr_in *sa4 = (struct sockaddr_in *)sa; + /* set up sockaddr */ + inet_addr_from_ip4addr(&sa4->sin_addr, ip_2_ip4(&addr)); + sa4->sin_family = AF_INET; + sa4->sin_len = sizeof(struct sockaddr_in); + sa4->sin_port = lwip_htons((u16_t)port_nr); + ai->ai_family = AF_INET; +#endif /* LWIP_IPV4 */ + } + + /* set up addrinfo */ + if (hints != NULL) { + /* copy socktype & protocol from hints if specified */ + ai->ai_socktype = hints->ai_socktype; + ai->ai_protocol = hints->ai_protocol; + } + if ((idx == 0) && (nodename != NULL) && (hints != NULL) + && (hints->ai_flags & AI_CANONNAME)) { + /* copy nodename to canonname if specified */ + ai->ai_canonname = ((char *)ai + sizeof(struct addrinfo) + sizeof(struct sockaddr_storage)); + MEMCPY(ai->ai_canonname, nodename, namelen); + ai->ai_canonname[namelen] = 0; + } + ai->ai_addrlen = sizeof(struct sockaddr_storage); + ai->ai_addr = (struct sockaddr *)sa; + + *res = ai; + + return ERR_OK; +} + /** * Translates the name of a service location (for example, a host name) and/or * a service name and returns a set of socket addresses and associated @@ -251,8 +368,7 @@ lwip_freeaddrinfo(struct addrinfo *ai) * Memory for the result is allocated internally and must be freed by calling * lwip_freeaddrinfo()! * - * Due to a limitation in dns_gethostbyname, only the first address of a - * host is returned. + * dns_gethostbyname can return as many address as configured in DNS_MAX_HOST_IP. * Also, service names are not supported (only port numbers)! * * @param nodename descriptive name or address string of the host @@ -269,13 +385,12 @@ lwip_getaddrinfo(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res) { err_t err; - ip_addr_t addr; - struct addrinfo *ai; - struct sockaddr_storage *sa = NULL; + ip_addr_t addr[DNS_MAX_HOST_IP]={0}, addr_zero={0}; + struct addrinfo *ai=NULL, *ai_head=NULL, *ai_tail=NULL; int port_nr = 0; - size_t total_size; - size_t namelen = 0; int ai_family; + int ret; + u8_t i; if (res == NULL) { return EAI_FAIL; @@ -318,12 +433,12 @@ lwip_getaddrinfo(const char *nodename, const char *servname, /* service location specified, try to resolve */ if ((hints != NULL) && (hints->ai_flags & AI_NUMERICHOST)) { /* no DNS lookup, just parse for an address string */ - if (!ipaddr_aton(nodename, &addr)) { + if (!ipaddr_aton(nodename, &addr[0])) { return EAI_NONAME; } #if LWIP_IPV4 && LWIP_IPV6 - if ((IP_IS_V6_VAL(addr) && ai_family == AF_INET) || - (IP_IS_V4_VAL(addr) && ai_family == AF_INET6)) { + if ((IP_IS_V6_VAL(addr[0]) && ai_family == AF_INET) || + (IP_IS_V4_VAL(addr[0]) && ai_family == AF_INET6)) { return EAI_NONAME; } #endif /* LWIP_IPV4 && LWIP_IPV6 */ @@ -342,7 +457,7 @@ lwip_getaddrinfo(const char *nodename, const char *servname, #endif /* ESP_LWIP */ } #endif /* LWIP_IPV4 && LWIP_IPV6 */ - err = netconn_gethostbyname_addrtype(nodename, &addr, type); + err = netconn_gethostbyname_addrtype(nodename, addr, type); if (err != ERR_OK) { return EAI_FAIL; } @@ -350,80 +465,39 @@ lwip_getaddrinfo(const char *nodename, const char *servname, } else { /* service location specified, use loopback address */ if ((hints != NULL) && (hints->ai_flags & AI_PASSIVE)) { - ip_addr_set_any_val(ai_family == AF_INET6, addr); + ip_addr_set_any_val(ai_family == AF_INET6, addr[0]); } else { - ip_addr_set_loopback_val(ai_family == AF_INET6, addr); + ip_addr_set_loopback_val(ai_family == AF_INET6, addr[0]); } } -#if ESP_LWIP && LWIP_IPV4 && LWIP_IPV6 - if (ai_family == AF_INET6 && (hints->ai_flags & AI_V4MAPPED) - && IP_GET_TYPE(&addr) == IPADDR_TYPE_V4) { - /* Convert native V4 address to a V4-mapped IPV6 address */ - ip4_2_ipv4_mapped_ipv6(ip_2_ip6(&addr), ip_2_ip4(&addr)); - IP_SET_TYPE_VAL(addr, IPADDR_TYPE_V6); - } -#endif /* ESP_LWIP && LWIP_IPV4 && LWIP_IPV6 */ + for (i=0; iai_next; + memp_free(MEMP_NETDB, ai_head); + ai_head = ai; + } + *res = NULL; + return ret; + } - total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_storage); - if (nodename != NULL) { - namelen = strlen(nodename); - if (namelen > DNS_MAX_NAME_LENGTH) { - /* invalid name length */ - return EAI_FAIL; + if (ai != NULL) { + if (ai_head == NULL) { + /* Initialize head */ + ai_head = ai; + ai_tail = ai_head; + } else { + ai_tail->ai_next = ai; + ai_tail = ai; + } + ai_tail->ai_next = NULL; + } } - LWIP_ASSERT("namelen is too long", total_size + namelen + 1 > total_size); - total_size += namelen + 1; - } - /* If this fails, please report to lwip-devel! :-) */ - LWIP_ASSERT("total_size <= NETDB_ELEM_SIZE: please report this!", - total_size <= NETDB_ELEM_SIZE); - ai = (struct addrinfo *)memp_malloc(MEMP_NETDB); - if (ai == NULL) { - return EAI_MEMORY; } - memset(ai, 0, total_size); - /* cast through void* to get rid of alignment warnings */ - sa = (struct sockaddr_storage *)(void *)((u8_t *)ai + sizeof(struct addrinfo)); - if (IP_IS_V6_VAL(addr)) { -#if LWIP_IPV6 - struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa; - /* set up sockaddr */ - inet6_addr_from_ip6addr(&sa6->sin6_addr, ip_2_ip6(&addr)); - sa6->sin6_family = AF_INET6; - sa6->sin6_len = sizeof(struct sockaddr_in6); - sa6->sin6_port = lwip_htons((u16_t)port_nr); - sa6->sin6_scope_id = ip6_addr_zone(ip_2_ip6(&addr)); - ai->ai_family = AF_INET6; -#endif /* LWIP_IPV6 */ - } else { -#if LWIP_IPV4 - struct sockaddr_in *sa4 = (struct sockaddr_in *)sa; - /* set up sockaddr */ - inet_addr_from_ip4addr(&sa4->sin_addr, ip_2_ip4(&addr)); - sa4->sin_family = AF_INET; - sa4->sin_len = sizeof(struct sockaddr_in); - sa4->sin_port = lwip_htons((u16_t)port_nr); - ai->ai_family = AF_INET; -#endif /* LWIP_IPV4 */ - } - - /* set up addrinfo */ - if (hints != NULL) { - /* copy socktype & protocol from hints if specified */ - ai->ai_socktype = hints->ai_socktype; - ai->ai_protocol = hints->ai_protocol; - } - if (nodename != NULL) { - /* copy nodename to canonname if specified */ - ai->ai_canonname = ((char *)ai + sizeof(struct addrinfo) + sizeof(struct sockaddr_storage)); - MEMCPY(ai->ai_canonname, nodename, namelen); - ai->ai_canonname[namelen] = 0; - } - ai->ai_addrlen = sizeof(struct sockaddr_storage); - ai->ai_addr = (struct sockaddr *)sa; - - *res = ai; + *res = ai_head; return 0; } diff --git a/src/core/dns.c b/src/core/dns.c index 02de62b63..e9edc205f 100644 --- a/src/core/dns.c +++ b/src/core/dns.c @@ -227,8 +227,9 @@ typedef enum { /** DNS table entry */ struct dns_table_entry { - u32_t ttl; - ip_addr_t ipaddr; + u32_t ttl[DNS_MAX_HOST_IP]; + ip_addr_t ipaddr[DNS_MAX_HOST_IP]; + u8_t ipaddr_cnt; u16_t txid; u8_t state; u8_t server_idx; @@ -663,7 +664,6 @@ dns_local_addhost(const char *hostname, const ip_addr_t *addr) static err_t dns_lookup(const char *name, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype)) { - u8_t i; #if DNS_LOCAL_HOSTLIST if (dns_lookup_local(name, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)) == ERR_OK) { return ERR_OK; @@ -676,17 +676,28 @@ dns_lookup(const char *name, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addr #endif /* DNS_LOOKUP_LOCAL_EXTERN */ /* Walk through name list, return entry if found. If not, return NULL. */ - for (i = 0; i < DNS_TABLE_SIZE; ++i) { - if ((dns_table[i].state == DNS_STATE_DONE) && - (lwip_strnicmp(name, dns_table[i].name, sizeof(dns_table[i].name)) == 0) && - LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, dns_table[i].ipaddr)) { - LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name)); - ip_addr_debug_print_val(DNS_DEBUG, dns_table[i].ipaddr); - LWIP_DEBUGF(DNS_DEBUG, ("\n")); - if (addr) { - ip_addr_copy(*addr, dns_table[i].ipaddr); + { + u8_t i, j; + u8_t out_idx=0; + + for (i = 0; i < DNS_TABLE_SIZE; ++i) { + if ((dns_table[i].state == DNS_STATE_DONE) && + (lwip_strnicmp(name, dns_table[i].name, sizeof(dns_table[i].name)) == 0)) { + LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name)); + for (j=0; jstate) { case DNS_STATE_NEW: @@ -1127,7 +1139,7 @@ dns_check_entry(u8_t i) } #endif /* send DNS packet for this entry */ - err = dns_send(i); + err = dns_send(idx); if (err != ERR_OK) { LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING, ("dns_send returned error: %s\n", lwip_strerr(err))); @@ -1154,7 +1166,7 @@ dns_check_entry(u8_t i) } else { LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": timeout\n", entry->name)); /* call specified callback function if provided */ - dns_call_found(i, NULL); + dns_call_found(idx, NULL); /* flush this entry */ entry->state = DNS_STATE_UNUSED; break; @@ -1165,7 +1177,7 @@ dns_check_entry(u8_t i) } /* send DNS packet for this entry */ - err = dns_send(i); + err = dns_send(idx); if (err != ERR_OK) { LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING, ("dns_send returned error: %s\n", lwip_strerr(err))); @@ -1174,7 +1186,15 @@ dns_check_entry(u8_t i) break; case DNS_STATE_DONE: /* if the time to live is nul */ - if ((entry->ttl == 0) || (--entry->ttl == 0)) { + initial_ipaddr_cnt = entry->ipaddr_cnt; + for (i=0; ittl[i] == 0) || (--entry->ttl[i] == 0)) { + ip_addr_set_zero(&entry->ipaddr[i]); + entry->ipaddr_cnt--; + } + } + + if (entry->ipaddr_cnt == 0) { LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": flush\n", entry->name)); /* flush this entry, there cannot be any related pending entries in this state */ entry->state = DNS_STATE_UNUSED; @@ -1203,32 +1223,39 @@ dns_check_entries(void) } /** - * Save TTL and call dns_call_found for correct response. + * Call dns_call_found for correct response. */ static void -dns_correct_response(u8_t idx, u32_t ttl) +dns_correct_response(u8_t idx) { + u8_t i; + u8_t initial_ipaddr_cnt; struct dns_table_entry *entry = &dns_table[idx]; entry->state = DNS_STATE_DONE; LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", entry->name)); - ip_addr_debug_print_val(DNS_DEBUG, entry->ipaddr); - LWIP_DEBUGF(DNS_DEBUG, ("\n")); + for (i=0; iipaddr_cnt; i++) { + ip_addr_debug_print_val(DNS_DEBUG, entry->ipaddr[i]); + LWIP_DEBUGF(DNS_DEBUG, ("\n")); + } - /* read the answer resource record's TTL, and maximize it if needed */ - entry->ttl = ttl; - if (entry->ttl > DNS_MAX_TTL) { - entry->ttl = DNS_MAX_TTL; + dns_call_found(idx, entry->ipaddr); + + initial_ipaddr_cnt = entry->ipaddr_cnt; + for (i=0; ittl[i] == 0) { + /* RFC 883, page 29: "Zero values are + interpreted to mean that the RR can only be used for the + transaction in progress, and should not be cached." + -> flush this entry now */ + /* entry reused during callback? */ + ip_addr_set_zero(&entry->ipaddr[i]); + entry->ipaddr_cnt--; + } } - dns_call_found(idx, &entry->ipaddr); - - if (entry->ttl == 0) { - /* RFC 883, page 29: "Zero values are - interpreted to mean that the RR can only be used for the - transaction in progress, and should not be cached." - -> flush this entry now */ - /* entry reused during callback? */ + + if (entry->ipaddr_cnt == 0) { if (entry->state == DNS_STATE_DONE) { entry->state = DNS_STATE_UNUSED; } @@ -1242,6 +1269,7 @@ static void dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) { u8_t i; + u8_t initial_ipaddr_cnt; u16_t txid; u16_t res_idx; struct dns_hdr hdr; @@ -1337,6 +1365,7 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, goto ignore_packet; } } else { + initial_ipaddr_cnt = entry->ipaddr_cnt; while ((nanswers > 0) && (res_idx < p->tot_len)) { /* skip answer resource record's host name */ res_idx = dns_skip_name(p, res_idx); @@ -1353,7 +1382,7 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, } res_idx = (u16_t)(res_idx + SIZEOF_DNS_ANSWER); - if (ans.cls == PP_HTONS(DNS_RRCLASS_IN)) { + if ((ans.cls == PP_HTONS(DNS_RRCLASS_IN)) && (entry->ipaddr_cnt < DNS_MAX_HOST_IP)) { #if LWIP_IPV4 if ((ans.type == PP_HTONS(DNS_RRTYPE_A)) && (ans.len == PP_HTONS(sizeof(ip4_addr_t)))) { #if LWIP_IPV4 && LWIP_IPV6 @@ -1365,11 +1394,14 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, if (pbuf_copy_partial(p, &ip4addr, sizeof(ip4_addr_t), res_idx) != sizeof(ip4_addr_t)) { goto ignore_packet; /* ignore this packet */ } - ip_addr_copy_from_ip4(dns_table[i].ipaddr, ip4addr); - pbuf_free(p); - /* handle correct response */ - dns_correct_response(i, lwip_ntohl(ans.ttl)); - return; + ip_addr_copy_from_ip4(entry->ipaddr[entry->ipaddr_cnt], ip4addr); + + /* read the answer resource record's TTL, and maximize it if needed */ + entry->ttl[entry->ipaddr_cnt] = lwip_ntohl(ans.ttl); + if (entry->ttl[entry->ipaddr_cnt] > DNS_MAX_TTL) { + entry->ttl[entry->ipaddr_cnt] = DNS_MAX_TTL; + } + entry->ipaddr_cnt++; } } #endif /* LWIP_IPV4 */ @@ -1385,11 +1417,14 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, goto ignore_packet; /* ignore this packet */ } /* @todo: scope ip6addr? Might be required for link-local addresses at least? */ - ip_addr_copy_from_ip6_packed(dns_table[i].ipaddr, ip6addr); - pbuf_free(p); - /* handle correct response */ - dns_correct_response(i, lwip_ntohl(ans.ttl)); - return; + ip_addr_copy_from_ip6_packed(entry->ipaddr[entry->ipaddr_cnt], ip6addr); + + /* read the answer resource record's TTL, and maximize it if needed */ + entry->ttl[entry->ipaddr_cnt] = lwip_ntohl(ans.ttl); + if (entry->ttl[entry->ipaddr_cnt] > DNS_MAX_TTL) { + entry->ttl[entry->ipaddr_cnt] = DNS_MAX_TTL; + } + entry->ipaddr_cnt++; } } #endif /* LWIP_IPV6 */ @@ -1401,6 +1436,14 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, res_idx = (u16_t)(res_idx + lwip_htons(ans.len)); --nanswers; } + + if (initial_ipaddr_cnt < entry->ipaddr_cnt) { + pbuf_free(p); + /* handle correct response */ + dns_correct_response(i); + return; + } + #if LWIP_IPV4 && LWIP_IPV6 if ((entry->reqaddrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) || (entry->reqaddrtype == LWIP_DNS_ADDRTYPE_IPV6_IPV4)) { @@ -1423,6 +1466,7 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, pbuf_free(p); dns_call_found(i, NULL); dns_table[i].state = DNS_STATE_UNUSED; + entry->ipaddr_cnt = 0; return; } } @@ -1541,6 +1585,7 @@ dns_enqueue(const char *name, size_t hostnamelen, dns_found_callback found, /* fill the entry */ entry->state = DNS_STATE_NEW; entry->seqno = dns_seqno; + entry->ipaddr_cnt = 0; LWIP_DNS_SET_ADDRTYPE(entry->reqaddrtype, dns_addrtype); LWIP_DNS_SET_ADDRTYPE(req->reqaddrtype, dns_addrtype); req->found = found; @@ -1555,6 +1600,7 @@ dns_enqueue(const char *name, size_t hostnamelen, dns_found_callback found, /* failed to get a UDP pcb */ LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": failed to allocate a pcb\n", name)); entry->state = DNS_STATE_UNUSED; + entry->ipaddr_cnt = 0; req->found = NULL; return ERR_MEM; } @@ -1593,7 +1639,7 @@ dns_enqueue(const char *name, size_t hostnamelen, dns_found_callback found, * - ERR_ARG: dns client not initialized or invalid hostname * * @param hostname the hostname that is to be queried - * @param addr pointer to a ip_addr_t where to store the address if it is already + * @param addr pointer to an array of ip_addr_t where to store the addresses if they are already * cached in the dns_table (only valid if ERR_OK is returned!) * @param found a callback function to be called on success, failure or timeout (only if * ERR_INPROGRESS is returned!) @@ -1624,7 +1670,7 @@ static bool dns_server_is_set (void) * @ingroup dns * Like dns_gethostbyname, but returned address type can be controlled: * @param hostname the hostname that is to be queried - * @param addr pointer to a ip_addr_t where to store the address if it is already + * @param addr pointer to an array of ip_addr_t where to store the addresses if they are already * cached in the dns_table (only valid if ERR_OK is returned!) * @param found a callback function to be called on success, failure or timeout (only if * ERR_INPROGRESS is returned!) diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index e08ec79a6..2c58c5322 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -1113,6 +1113,11 @@ #define DNS_MAX_NAME_LENGTH 256 #endif +/** DNS maximum number of ip address stored per host. */ +#if !defined DNS_MAX_HOST_IP || defined __DOXYGEN__ +#define DNS_MAX_HOST_IP 1 +#endif + /** The maximum of DNS servers * The first server can be initialized automatically by defining * DNS_SERVER_ADDRESS(ipaddr), where 'ipaddr' is an 'ip_addr_t*'