dns: Add support for multiple DNS/IP records

2.1.3-esp: f1746813 feat(lwip): Added multiple dns ip support
2.1.3-esp: bced058f dns: Fixed incorrect handling of 0.0.0.0
This commit is contained in:
Abhik Roy
2024-03-18 23:40:14 +11:00
committed by David Cermak
parent 6e7c96f5fd
commit dcb01b9121
4 changed files with 337 additions and 171 deletions
+5 -1
View File
@@ -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));
+228 -117
View File
@@ -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;
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;
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;
}
+84 -38
View File
@@ -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,20 +694,31 @@ 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. */
{
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_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, dns_table[i].ipaddr)) {
!dns_table[i].name[namelen]) {
LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name));
ip_addr_debug_print_val(DNS_DEBUG, dns_table[i].ipaddr);
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, dns_table[i].ipaddr);
ip_addr_copy(addr[out_idx], dns_table[i].ipaddr[j]);
out_idx++;
}
}
}
if (out_idx) {
return ERR_OK;
}
}
}
}
return ERR_ARG;
}
@@ -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);
for (i=0; i<entry->ipaddr_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);
if (entry->ttl == 0) {
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!)
+5
View File
@@ -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*'