mirror of
https://github.com/espressif/esp-lwip.git
synced 2026-06-05 21:04:45 +00:00
dns: Add support for multiple DNS/IP records
2.1.3-esp:f1746813feat(lwip): Added multiple dns ip support 2.1.3-esp:bced058fdns: Fixed incorrect handling of 0.0.0.0
This commit is contained in:
+5
-1
@@ -2199,6 +2199,7 @@ done:
|
||||
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 :-) */
|
||||
@@ -2210,7 +2211,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; i<DNS_MAX_HOST_IP; i++) {
|
||||
API_EXPR_DEREF(msg->addr+i) = *(ipaddr+i);
|
||||
}
|
||||
}
|
||||
/* wake up the application task waiting in netconn_gethostbyname */
|
||||
sys_sem_signal(API_EXPR_REF_SEM(msg->sem));
|
||||
|
||||
+230
-119
@@ -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;
|
||||
};
|
||||
|
||||
@@ -79,10 +79,21 @@ int h_errno;
|
||||
#define HOSTENT_STORAGE static
|
||||
#endif /* LWIP_DNS_API_STATIC_HOSTENT */
|
||||
|
||||
/* Counts IP addresses in addr array until a zero IP address is encountered */
|
||||
#define COUNT_NON_ZERO_IP_ADDRESSES(addr, ipaddr_cnt) \
|
||||
do { \
|
||||
ipaddr_cnt = 0; \
|
||||
for (i = 0; i < DNS_MAX_HOST_IP; i++) { \
|
||||
if (!ip_addr_cmp(&addr_zero, &addr[i])) { \
|
||||
ipaddr_cnt++; \
|
||||
} \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -91,35 +102,51 @@ 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};
|
||||
u8_t ipaddr_cnt = 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;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* fill hostent */
|
||||
s_hostent_addr = addr;
|
||||
s_phostent_addr[0] = &s_hostent_addr;
|
||||
s_phostent_addr[1] = NULL;
|
||||
COUNT_NON_ZERO_IP_ADDRESSES(addr, ipaddr_cnt);
|
||||
|
||||
if (ipaddr_cnt == 0) {
|
||||
/* handle 0.0.0.0 */
|
||||
s_hostent_addr[0] = addr[0];
|
||||
s_phostent_addr[0] = &s_hostent_addr[0];
|
||||
s_phostent_addr[1] = NULL;
|
||||
} else {
|
||||
for (i=0; i<ipaddr_cnt; i++){
|
||||
if (!ip_addr_cmp(&addr_zero, &addr[i])) {
|
||||
s_hostent_addr[i] = addr[i];
|
||||
s_phostent_addr[i] = &s_hostent_addr[i];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
s_phostent_addr[i] = NULL;
|
||||
}
|
||||
strncpy(s_hostname, name, DNS_MAX_NAME_LENGTH);
|
||||
s_hostname[DNS_MAX_NAME_LENGTH] = 0;
|
||||
s_hostent.h_name = s_hostname;
|
||||
s_aliases = NULL;
|
||||
s_hostent.h_aliases = &s_aliases;
|
||||
s_hostent.h_addrtype = (IPADDR_TYPE_V4 == IP_GET_TYPE(&addr)? AF_INET : AF_INET6);
|
||||
s_hostent.h_length = IP_ADDR_RAW_SIZE(addr);
|
||||
s_hostent.h_addrtype = (IPADDR_TYPE_V4 == IP_GET_TYPE(&addr[0])? AF_INET : AF_INET6);
|
||||
s_hostent.h_length = IP_ADDR_RAW_SIZE(addr[0]);
|
||||
s_hostent.h_addr_list = (char **)&s_phostent_addr;
|
||||
|
||||
#if DNS_DEBUG
|
||||
@@ -166,11 +193,14 @@ int
|
||||
lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
|
||||
size_t buflen, struct hostent **result, int *h_errnop)
|
||||
{
|
||||
u8_t i;
|
||||
err_t err;
|
||||
struct gethostbyname_r_helper *h;
|
||||
char *hostname;
|
||||
size_t namelen;
|
||||
ip_addr_t addr_zero={0};
|
||||
int lh_errno;
|
||||
u8_t ipaddr_cnt = 0;
|
||||
|
||||
if (h_errnop == NULL) {
|
||||
/* ensure h_errnop is never NULL */
|
||||
@@ -197,11 +227,12 @@ lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(buf, 0, buflen);
|
||||
h = (struct gethostbyname_r_helper *)LWIP_MEM_ALIGN(buf);
|
||||
hostname = ((char *)h) + sizeof(struct gethostbyname_r_helper);
|
||||
|
||||
/* query host IP address */
|
||||
err = netconn_gethostbyname(name, &h->addr);
|
||||
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;
|
||||
@@ -212,14 +243,28 @@ lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
|
||||
MEMCPY(hostname, name, namelen);
|
||||
hostname[namelen] = 0;
|
||||
|
||||
/* fill hostent */
|
||||
h->addr_list[0] = &h->addr;
|
||||
h->addr_list[1] = NULL;
|
||||
COUNT_NON_ZERO_IP_ADDRESSES(h->addr, ipaddr_cnt);
|
||||
|
||||
if (ipaddr_cnt == 0) {
|
||||
/* handle 0.0.0.0 */
|
||||
h->addr_list[0] = &h->addr[0];
|
||||
h->addr_list[1] = NULL;
|
||||
} else {
|
||||
for (i=0; i<ipaddr_cnt; i++) {
|
||||
if (!ip_addr_cmp(&addr_zero, &h->addr[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 */
|
||||
@@ -249,119 +294,34 @@ lwip_freeaddrinfo(struct addrinfo *ai)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* information to be used in creating a socket with which to address the
|
||||
* specified service.
|
||||
* Memory for the result is allocated internally and must be freed by calling
|
||||
* lwip_freeaddrinfo()!
|
||||
* Creates a new address information (addrinfo) structure based on the provided parameters.
|
||||
*
|
||||
* Due to a limitation in dns_gethostbyname, only the first address of a
|
||||
* host is returned.
|
||||
* Also, service names are not supported (only port numbers)!
|
||||
* @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.
|
||||
*
|
||||
* @param nodename descriptive name or address string of the host
|
||||
* (may be NULL -> local address)
|
||||
* @param servname port number as string of NULL
|
||||
* @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
|
||||
* @return Returns ERR_OK on success, or an error code (EAI_FAIL, EAI_MEMORY) on failure.
|
||||
*/
|
||||
int
|
||||
lwip_getaddrinfo(const char *nodename, const char *servname,
|
||||
const struct addrinfo *hints, struct addrinfo **res)
|
||||
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)
|
||||
{
|
||||
err_t err;
|
||||
ip_addr_t addr;
|
||||
struct addrinfo *ai;
|
||||
struct sockaddr_storage *sa = NULL;
|
||||
int port_nr = 0;
|
||||
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 (res == NULL) {
|
||||
return EAI_FAIL;
|
||||
}
|
||||
*res = NULL;
|
||||
if ((nodename == NULL) && (servname == NULL)) {
|
||||
return EAI_NONAME;
|
||||
}
|
||||
|
||||
if (hints != NULL) {
|
||||
ai_family = hints->ai_family;
|
||||
if ((ai_family != AF_UNSPEC)
|
||||
#if LWIP_IPV4
|
||||
&& (ai_family != AF_INET)
|
||||
#endif /* LWIP_IPV4 */
|
||||
#if LWIP_IPV6
|
||||
&& (ai_family != AF_INET6)
|
||||
#endif /* LWIP_IPV6 */
|
||||
) {
|
||||
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 (AI_NUMERICSERV)! */
|
||||
port_nr = atoi(servname);
|
||||
if (port_nr == 0 && (servname[0] != '0')) {
|
||||
/* atoi failed - service was not numeric */
|
||||
return EAI_SERVICE;
|
||||
}
|
||||
if ((port_nr < 0) || (port_nr > 0xffff)) {
|
||||
return EAI_SERVICE;
|
||||
}
|
||||
}
|
||||
|
||||
if (nodename != NULL) {
|
||||
/* 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)) {
|
||||
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)) {
|
||||
return EAI_NONAME;
|
||||
}
|
||||
#endif /* LWIP_IPV4 && LWIP_IPV6 */
|
||||
} 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;
|
||||
#if ESP_LWIP
|
||||
if (hints->ai_flags & AI_V4MAPPED) {
|
||||
type = NETCONN_DNS_IPV6_IPV4;
|
||||
}
|
||||
#endif /* ESP_LWIP */
|
||||
}
|
||||
#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 */
|
||||
if ((hints != NULL) && (hints->ai_flags & AI_PASSIVE)) {
|
||||
ip_addr_set_any_val(ai_family == AF_INET6, addr);
|
||||
} else {
|
||||
ip_addr_set_loopback_val(ai_family == AF_INET6, addr);
|
||||
}
|
||||
}
|
||||
|
||||
#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 */
|
||||
@@ -419,7 +379,8 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
|
||||
ai->ai_socktype = hints->ai_socktype;
|
||||
ai->ai_protocol = hints->ai_protocol;
|
||||
}
|
||||
if (nodename != NULL) {
|
||||
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);
|
||||
@@ -430,6 +391,156 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
|
||||
|
||||
*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
|
||||
* information to be used in creating a socket with which to address the
|
||||
* specified service.
|
||||
* Memory for the result is allocated internally and must be freed by calling
|
||||
* lwip_freeaddrinfo()!
|
||||
*
|
||||
* 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
|
||||
* (may be NULL -> local address)
|
||||
* @param servname port number as string of NULL
|
||||
* @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,
|
||||
const struct addrinfo *hints, struct addrinfo **res)
|
||||
{
|
||||
err_t err;
|
||||
ip_addr_t addr[DNS_MAX_HOST_IP]={0}, addr_zero={0};
|
||||
u8_t ipaddr_cnt = 0;
|
||||
struct addrinfo *ai=NULL, *ai_head=NULL, *ai_tail=NULL;
|
||||
int port_nr = 0;
|
||||
int ai_family;
|
||||
int ret;
|
||||
u8_t i;
|
||||
|
||||
if (res == NULL) {
|
||||
return EAI_FAIL;
|
||||
}
|
||||
*res = NULL;
|
||||
if ((nodename == NULL) && (servname == NULL)) {
|
||||
return EAI_NONAME;
|
||||
}
|
||||
|
||||
if (hints != NULL) {
|
||||
ai_family = hints->ai_family;
|
||||
if ((ai_family != AF_UNSPEC)
|
||||
#if LWIP_IPV4
|
||||
&& (ai_family != AF_INET)
|
||||
#endif /* LWIP_IPV4 */
|
||||
#if LWIP_IPV6
|
||||
&& (ai_family != AF_INET6)
|
||||
#endif /* LWIP_IPV6 */
|
||||
) {
|
||||
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 (AI_NUMERICSERV)! */
|
||||
port_nr = atoi(servname);
|
||||
if (port_nr == 0 && (servname[0] != '0')) {
|
||||
/* atoi failed - service was not numeric */
|
||||
return EAI_SERVICE;
|
||||
}
|
||||
if ((port_nr < 0) || (port_nr > 0xffff)) {
|
||||
return EAI_SERVICE;
|
||||
}
|
||||
}
|
||||
|
||||
if (nodename != NULL) {
|
||||
/* 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[0])) {
|
||||
return EAI_NONAME;
|
||||
}
|
||||
#if LWIP_IPV4 && LWIP_IPV6
|
||||
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 */
|
||||
} 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;
|
||||
#if ESP_LWIP
|
||||
if (hints->ai_flags & AI_V4MAPPED) {
|
||||
type = NETCONN_DNS_IPV6_IPV4;
|
||||
}
|
||||
#endif /* ESP_LWIP */
|
||||
}
|
||||
#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 */
|
||||
if ((hints != NULL) && (hints->ai_flags & AI_PASSIVE)) {
|
||||
ip_addr_set_any_val(ai_family == AF_INET6, addr[0]);
|
||||
} else {
|
||||
ip_addr_set_loopback_val(ai_family == AF_INET6, addr[0]);
|
||||
}
|
||||
}
|
||||
|
||||
COUNT_NON_ZERO_IP_ADDRESSES(addr, ipaddr_cnt);
|
||||
|
||||
if (ipaddr_cnt == 0) {
|
||||
/* handle 0.0.0.0 */
|
||||
ret = create_addrinfo(addr[0], nodename, hints, port_nr, &ai, 0);
|
||||
if (ret != ERR_OK) {
|
||||
*res = NULL;
|
||||
return ret;
|
||||
}
|
||||
*res = ai;
|
||||
} else {
|
||||
for (i=0; i<ipaddr_cnt; i++) {
|
||||
if (!ip_addr_cmp(&addr_zero, &addr[i])) {
|
||||
ret = create_addrinfo(addr[i], nodename, hints, port_nr, &ai, i);
|
||||
if (ret != ERR_OK) { /* failure: free the entire list */
|
||||
lwip_freeaddrinfo(ai_head);
|
||||
*res = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ai != NULL) {
|
||||
if (ai_head == NULL) {
|
||||
/* Initialize head */
|
||||
ai_head = ai;
|
||||
} else {
|
||||
ai_tail->ai_next = ai;
|
||||
}
|
||||
ai_tail = ai;
|
||||
ai_tail->ai_next = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
*res = ai_head;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+97
-51
@@ -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;
|
||||
@@ -680,7 +681,6 @@ static err_t
|
||||
dns_lookup(const char *name, size_t hostnamelen, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype))
|
||||
{
|
||||
size_t namelen;
|
||||
u8_t i;
|
||||
#if DNS_LOCAL_HOSTLIST
|
||||
if (dns_lookup_local(name, hostnamelen, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)) == ERR_OK) {
|
||||
return ERR_OK;
|
||||
@@ -694,18 +694,29 @@ dns_lookup(const char *name, size_t hostnamelen, ip_addr_t *addr LWIP_DNS_ADDRTY
|
||||
|
||||
namelen = LWIP_MIN(hostnamelen, DNS_MAX_NAME_LENGTH - 1);
|
||||
/* 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, namelen) == 0) &&
|
||||
!dns_table[i].name[namelen] &&
|
||||
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, namelen) == 0) &&
|
||||
!dns_table[i].name[namelen]) {
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name));
|
||||
for (j=0; j<dns_table[i].ipaddr_cnt; j++) {
|
||||
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) {
|
||||
ip_addr_copy(addr[out_idx], dns_table[i].ipaddr[j]);
|
||||
out_idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (out_idx) {
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1122,15 +1133,16 @@ dns_backupserver_available(struct dns_table_entry *pentry)
|
||||
* - retry old pending entries on timeout (also with different servers)
|
||||
* - remove completed entries from the table if their TTL has expired
|
||||
*
|
||||
* @param i index of the dns_table entry to check
|
||||
* @param idx index of the dns_table entry to check
|
||||
*/
|
||||
static void
|
||||
dns_check_entry(u8_t i)
|
||||
dns_check_entry(u8_t idx)
|
||||
{
|
||||
err_t err;
|
||||
struct dns_table_entry *entry = &dns_table[i];
|
||||
struct dns_table_entry *entry = &dns_table[idx];
|
||||
u8_t i, initial_ipaddr_cnt;
|
||||
|
||||
LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE);
|
||||
LWIP_ASSERT("array index out of bounds", idx < DNS_TABLE_SIZE);
|
||||
|
||||
switch (entry->state) {
|
||||
case DNS_STATE_NEW:
|
||||
@@ -1146,7 +1158,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)));
|
||||
@@ -1173,7 +1185,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;
|
||||
@@ -1184,7 +1196,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)));
|
||||
@@ -1193,7 +1205,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; i<initial_ipaddr_cnt; i++) {
|
||||
if ((entry->ttl[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;
|
||||
@@ -1222,32 +1242,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"));
|
||||
|
||||
/* 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;
|
||||
for (i=0; i<entry->ipaddr_cnt; i++) {
|
||||
ip_addr_debug_print_val(DNS_DEBUG, entry->ipaddr[i]);
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("\n"));
|
||||
}
|
||||
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? */
|
||||
dns_call_found(idx, entry->ipaddr);
|
||||
|
||||
initial_ipaddr_cnt = entry->ipaddr_cnt;
|
||||
for (i=0; i<initial_ipaddr_cnt; i++) {
|
||||
if (entry->ttl[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--;
|
||||
}
|
||||
}
|
||||
|
||||
if (entry->ipaddr_cnt == 0) {
|
||||
if (entry->state == DNS_STATE_DONE) {
|
||||
entry->state = DNS_STATE_UNUSED;
|
||||
}
|
||||
@@ -1261,6 +1288,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;
|
||||
@@ -1356,6 +1384,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);
|
||||
@@ -1372,7 +1401,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
|
||||
@@ -1384,11 +1413,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 */
|
||||
@@ -1404,11 +1436,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 */
|
||||
@@ -1420,6 +1455,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)) {
|
||||
@@ -1442,6 +1485,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;
|
||||
}
|
||||
}
|
||||
@@ -1565,6 +1609,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;
|
||||
@@ -1578,6 +1623,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;
|
||||
}
|
||||
@@ -1616,7 +1662,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!)
|
||||
@@ -1647,7 +1693,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!)
|
||||
|
||||
@@ -1153,6 +1153,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*'
|
||||
|
||||
Reference in New Issue
Block a user