diff --git a/src/api/api_lib.c b/src/api/api_lib.c index f0581b9d..56b0e77f 100644 --- a/src/api/api_lib.c +++ b/src/api/api_lib.c @@ -1272,9 +1272,46 @@ netconn_join_leave_group_netif(struct netconn *conn, /** @param dns_addrtype IP address type (IPv4 / IPv6) */ err_t netconn_gethostbyname_addrtype(const char *name, ip_addr_t *addr, u8_t dns_addrtype) +{ + return netconn_gethostbyname_addrtype_n(name, addr, 1, dns_addrtype); +} + +/** + * @ingroup netconn_common + * Execute a DNS query, can return multiple IP addresses + * + * @param name a string representation of the DNS host name to query + * @param addr a preallocated array of ip_addr_t where to store the resolved IP addresses + * @param addr_cnt number of addresses requested; must be > 0 and <= DNS_MAX_HOST_IP + * @param dns_addrtype IP address type (IPv4 / IPv6) + * @return ERR_OK: resolving succeeded + * ERR_MEM: memory error, try again later + * ERR_ARG: dns client not initialized, invalid hostname, or invalid addr_cnt + * ERR_VAL: dns server response was invalid + */ +err_t +netconn_gethostbyname_addrtype_n(const char *name, ip_addr_t *addr, u8_t addr_cnt, u8_t dns_addrtype) #else err_t netconn_gethostbyname(const char *name, ip_addr_t *addr) +{ + return netconn_gethostbyname_n(name, addr, 1); +} + +/** + * @ingroup netconn_common + * Execute a DNS query, can return multiple IP addresses + * + * @param name a string representation of the DNS host name to query + * @param addr a preallocated array of ip_addr_t where to store the resolved IP addresses + * @param addr_cnt number of addresses requested; must be > 0 and <= DNS_MAX_HOST_IP + * @return ERR_OK: resolving succeeded + * ERR_MEM: memory error, try again later + * ERR_ARG: dns client not initialized, invalid hostname, or invalid addr_cnt + * ERR_VAL: dns server response was invalid + */ +err_t +netconn_gethostbyname_n(const char *name, ip_addr_t *addr, u8_t addr_cnt) #endif { API_VAR_DECLARE(struct dns_api_msg, msg); @@ -1286,6 +1323,9 @@ netconn_gethostbyname(const char *name, ip_addr_t *addr) LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;); LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;); + if ((addr_cnt == 0) || (addr_cnt > DNS_MAX_HOST_IP)) { + return ERR_ARG; + } #if LWIP_MPU_COMPATIBLE if (strlen(name) >= DNS_MAX_NAME_LENGTH) { return ERR_ARG; @@ -1314,6 +1354,7 @@ 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 */ + API_VAR_REF(msg).addr_cnt = addr_cnt; #if LWIP_IPV4 && LWIP_IPV6 API_VAR_REF(msg).dns_addrtype = dns_addrtype; #endif /* LWIP_IPV4 && LWIP_IPV6 */ diff --git a/src/api/api_msg.c b/src/api/api_msg.c index 4db89c01..0f4a71ba 100644 --- a/src/api/api_msg.c +++ b/src/api/api_msg.c @@ -2212,7 +2212,7 @@ lwip_netconn_do_dns_found(const char *name, const ip_addr_t *ipaddr, void *arg) /* address was resolved */ API_EXPR_DEREF(msg->err) = ERR_OK; - for (i=0; iaddr_cnt; i++) { API_EXPR_DEREF(msg->addr+i) = *(ipaddr+i); } } @@ -2237,8 +2237,8 @@ lwip_netconn_do_gethostbyname(void *arg) LWIP_DNS_ADDRTYPE_DEFAULT; #endif - API_EXPR_DEREF(msg->err) = dns_gethostbyname_addrtype(msg->name, - API_EXPR_REF(msg->addr), lwip_netconn_do_dns_found, msg, addrtype); + API_EXPR_DEREF(msg->err) = dns_gethostbyname_addrtype_n(msg->name, + API_EXPR_REF(msg->addr), msg->addr_cnt, lwip_netconn_do_dns_found, msg, addrtype); #if LWIP_TCPIP_CORE_LOCKING /* For core locking, only block if we need to wait for answer/timeout */ if (API_EXPR_DEREF(msg->err) == ERR_INPROGRESS) { diff --git a/src/api/netdb.c b/src/api/netdb.c index 6ca853b7..d278f678 100644 --- a/src/api/netdb.c +++ b/src/api/netdb.c @@ -115,7 +115,7 @@ lwip_gethostbyname(const char *name) HOSTENT_STORAGE char s_hostname[DNS_MAX_NAME_LENGTH + 1]; /* query host IP address */ - err = netconn_gethostbyname(name, addr); + err = netconn_gethostbyname_n(name, addr, DNS_MAX_HOST_IP); if (err != ERR_OK) { LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err)); h_errno = HOST_NOT_FOUND; @@ -492,7 +492,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_n(nodename, addr, DNS_MAX_HOST_IP, type); if (err != ERR_OK) { return EAI_FAIL; } diff --git a/src/core/dns.c b/src/core/dns.c index d2aa4d1b..196e0fdf 100644 --- a/src/core/dns.c +++ b/src/core/dns.c @@ -693,7 +693,7 @@ dns_local_addhost(const char *hostname, const ip_addr_t *addr) * @return ERR_OK if found, ERR_ARG if not found */ static err_t -dns_lookup(const char *name, size_t hostnamelen, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype)) +dns_lookup(const char *name, size_t hostnamelen, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype), u8_t addr_cnt) { size_t namelen; #if DNS_LOCAL_HOSTLIST @@ -722,7 +722,7 @@ dns_lookup(const char *name, size_t hostnamelen, ip_addr_t *addr LWIP_DNS_ADDRTY if (LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, dns_table[i].ipaddr[j])) { ip_addr_debug_print_val(DNS_DEBUG, dns_table[i].ipaddr[j]); LWIP_DEBUGF(DNS_DEBUG, ("\n")); - if (addr) { + if (addr && out_idx < addr_cnt) { ip_addr_copy(addr[out_idx], dns_table[i].ipaddr[j]); out_idx++; } @@ -1625,6 +1625,12 @@ dns_enqueue(const char *name, size_t hostnamelen, dns_found_callback found, entry->state = DNS_STATE_NEW; entry->seqno = dns_seqno; entry->ipaddr_cnt = 0; + { + u8_t j; + for (j = 0; j < DNS_MAX_HOST_IP; j++) { + ip_addr_set_zero(&entry->ipaddr[j]); + } + } LWIP_DNS_SET_ADDRTYPE(entry->reqaddrtype, dns_addrtype); LWIP_DNS_SET_ADDRTYPE(req->reqaddrtype, dns_addrtype); req->found = found; @@ -1708,7 +1714,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 an array of ip_addr_t where to store the addresses if they are already + * @param addr pointer to an ip_addr_t where to store the address if it is 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!) @@ -1721,6 +1727,29 @@ static bool dns_server_is_set (void) err_t dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, dns_found_callback found, void *callback_arg, u8_t dns_addrtype) +{ + return dns_gethostbyname_addrtype_n(hostname, addr, 1, found, callback_arg, dns_addrtype); +} + +/** + * @ingroup dns + * Like dns_gethostbyname_addrtype, but can return multiple addresses: + * @param hostname the hostname that is to be queried + * @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 addr_cnt number of addresses requested; must be > 0 and <= DNS_MAX_HOST_IP + * @param found a callback function to be called on success, failure or timeout (only if + * ERR_INPROGRESS is returned!) + * @param callback_arg argument to pass to the callback function + * @param dns_addrtype - LWIP_DNS_ADDRTYPE_IPV4_IPV6: try to resolve IPv4 first, try IPv6 if IPv4 fails only + * - LWIP_DNS_ADDRTYPE_IPV6_IPV4: try to resolve IPv6 first, try IPv4 if IPv6 fails only + * - LWIP_DNS_ADDRTYPE_IPV4: try to resolve IPv4 only + * - LWIP_DNS_ADDRTYPE_IPV6: try to resolve IPv6 only + * @return ERR_ARG if addr_cnt is 0 or greater than DNS_MAX_HOST_IP (among other invalid parameters) + */ +err_t +dns_gethostbyname_addrtype_n(const char *hostname, ip_addr_t *addr, u8_t addr_cnt, dns_found_callback found, + void *callback_arg, u8_t dns_addrtype) { size_t hostnamelen; #if LWIP_DNS_SUPPORT_MDNS_QUERIES @@ -1732,6 +1761,9 @@ dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, dns_found_call (!hostname) || (!hostname[0])) { return ERR_ARG; } + if ((addr_cnt == 0) || (addr_cnt > DNS_MAX_HOST_IP)) { + return ERR_ARG; + } #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) == 0) if (dns_pcbs[0] == NULL) { return ERR_ARG; @@ -1773,7 +1805,7 @@ dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, dns_found_call } } /* already have this address cached? */ - if (dns_lookup(hostname, hostnamelen, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)) == ERR_OK) { + if (dns_lookup(hostname, hostnamelen, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype), addr_cnt) == ERR_OK) { return ERR_OK; } #if LWIP_IPV4 && LWIP_IPV6 @@ -1785,7 +1817,7 @@ dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, dns_found_call } else { fallback = LWIP_DNS_ADDRTYPE_IPV4; } - if (dns_lookup(hostname, hostnamelen, addr LWIP_DNS_ADDRTYPE_ARG(fallback)) == ERR_OK) { + if (dns_lookup(hostname, hostnamelen, addr LWIP_DNS_ADDRTYPE_ARG(fallback), addr_cnt) == ERR_OK) { return ERR_OK; } } diff --git a/src/include/lwip/api.h b/src/include/lwip/api.h index be8c22aa..ff3292b3 100644 --- a/src/include/lwip/api.h +++ b/src/include/lwip/api.h @@ -358,10 +358,14 @@ err_t netconn_join_leave_group_netif(struct netconn *conn, const ip_addr_t *mu #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ #if LWIP_DNS #if LWIP_IPV4 && LWIP_IPV6 +err_t netconn_gethostbyname_addrtype_n(const char *name, ip_addr_t *addr, u8_t addr_cnt, u8_t dns_addrtype); err_t netconn_gethostbyname_addrtype(const char *name, ip_addr_t *addr, u8_t dns_addrtype); +#define netconn_gethostbyname_n(name, addr, addr_cnt) netconn_gethostbyname_addrtype_n(name, addr, addr_cnt, NETCONN_DNS_DEFAULT) #define netconn_gethostbyname(name, addr) netconn_gethostbyname_addrtype(name, addr, NETCONN_DNS_DEFAULT) #else /* LWIP_IPV4 && LWIP_IPV6 */ +err_t netconn_gethostbyname_n(const char *name, ip_addr_t *addr, u8_t addr_cnt); err_t netconn_gethostbyname(const char *name, ip_addr_t *addr); +#define netconn_gethostbyname_addrtype_n(name, addr, addr_cnt, dns_addrtype) netconn_gethostbyname_n(name, addr, addr_cnt) #define netconn_gethostbyname_addrtype(name, addr, dns_addrtype) netconn_gethostbyname(name, addr) #endif /* LWIP_IPV4 && LWIP_IPV6 */ #endif /* LWIP_DNS */ diff --git a/src/include/lwip/dns.h b/src/include/lwip/dns.h index 964daafb..441aec00 100644 --- a/src/include/lwip/dns.h +++ b/src/include/lwip/dns.h @@ -111,6 +111,25 @@ err_t dns_gethostbyname(const char *hostname, ip_addr_t *addr, err_t dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, dns_found_callback found, void *callback_arg, u8_t dns_addrtype); +/** + * @ingroup dns + * Like dns_gethostbyname_addrtype, but can return multiple addresses: + * @param hostname the hostname that is to be queried + * @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 addr_cnt number of addresses requested; must be > 0 and <= DNS_MAX_HOST_IP + * @param found a callback function to be called on success, failure or timeout (only if + * ERR_INPROGRESS is returned!) + * @param callback_arg argument to pass to the callback function + * @param dns_addrtype - LWIP_DNS_ADDRTYPE_IPV4_IPV6: try to resolve IPv4 first, try IPv6 if IPv4 fails only + * - LWIP_DNS_ADDRTYPE_IPV6_IPV4: try to resolve IPv6 first, try IPv4 if IPv6 fails only + * - LWIP_DNS_ADDRTYPE_IPV4: try to resolve IPv4 only + * - LWIP_DNS_ADDRTYPE_IPV6: try to resolve IPv6 only + * @return ERR_ARG if addr_cnt is 0 or greater than DNS_MAX_HOST_IP (among other invalid parameters) + */ +err_t dns_gethostbyname_addrtype_n(const char *hostname, ip_addr_t *addr, u8_t addr_cnt, + dns_found_callback found, void *callback_arg, + u8_t dns_addrtype); void dns_clear_cache(void); #if DNS_LOCAL_HOSTLIST diff --git a/src/include/lwip/priv/api_msg.h b/src/include/lwip/priv/api_msg.h index 9e8ffc9e..cf61eecc 100644 --- a/src/include/lwip/priv/api_msg.h +++ b/src/include/lwip/priv/api_msg.h @@ -166,6 +166,13 @@ struct api_msg { it has its own struct (to avoid struct api_msg getting bigger than necessary). lwip_netconn_do_gethostbyname must be called using tcpip_callback instead of tcpip_apimsg (see netconn_gethostbyname). */ +#if LWIP_MPU_COMPATIBLE && (DNS_MAX_HOST_IP > 1) +/* When LWIP_MPU_COMPATIBLE is enabled dns_api_msg embeds a single ip_addr_t + (not a pointer), so the multi-address copy loop in lwip_netconn_do_dns_found + would overflow into adjacent struct members. Either disable MPU compat or + keep DNS_MAX_HOST_IP == 1 until dns_api_msg is extended to an array. */ +#error "DNS_MAX_HOST_IP > 1 is not supported with LWIP_MPU_COMPATIBLE" +#endif struct dns_api_msg { /** Hostname to query or dotted IP address string */ #if LWIP_MPU_COMPATIBLE @@ -179,6 +186,8 @@ struct dns_api_msg { /** Type of resolve call */ u8_t dns_addrtype; #endif /* LWIP_IPV4 && LWIP_IPV6 */ + /** Number of addresses requested */ + u8_t addr_cnt; /** This semaphore is posted when the name is resolved, the application thread should wait on it. */ sys_sem_t API_MSG_M_DEF_SEM(sem);