1 /** 2 * @file 3 * DNS - host name to IP address resolver. 4 * 5 * @defgroup dns DNS 6 * @ingroup callbackstyle_api 7 * 8 * Implements a DNS host name to IP address resolver. 9 * 10 * The lwIP DNS resolver functions are used to lookup a host name and 11 * map it to a numerical IP address. It maintains a list of resolved 12 * hostnames that can be queried with the dns_lookup() function. 13 * New hostnames can be resolved using the dns_query() function. 14 * 15 * The lwIP version of the resolver also adds a non-blocking version of 16 * gethostbyname() that will work with a raw API application. This function 17 * checks for an IP address string first and converts it if it is valid. 18 * gethostbyname() then does a dns_lookup() to see if the name is 19 * already in the table. If so, the IP is returned. If not, a query is 20 * issued and the function returns with a ERR_INPROGRESS status. The app 21 * using the dns client must then go into a waiting state. 22 * 23 * Once a hostname has been resolved (or found to be non-existent), 24 * the resolver code calls a specified callback function (which 25 * must be implemented by the module that uses the resolver). 26 * 27 * Multicast DNS queries are supported for names ending on ".local". 28 * However, only "One-Shot Multicast DNS Queries" are supported (RFC 6762 29 * chapter 5.1), this is not a fully compliant implementation of continuous 30 * mDNS querying! 31 * 32 * All functions must be called from TCPIP thread. 33 * 34 * @see DNS_MAX_SERVERS 35 * @see LWIP_DHCP_MAX_DNS_SERVERS 36 * @see @ref netconn_common for thread-safe access. 37 */ 38 39 /* 40 * Port to lwIP from uIP 41 * by Jim Pettinato April 2007 42 * 43 * security fixes and more by Simon Goldschmidt 44 * 45 * uIP version Copyright (c) 2002-2003, Adam Dunkels. 46 * All rights reserved. 47 * 48 * Redistribution and use in source and binary forms, with or without 49 * modification, are permitted provided that the following conditions 50 * are met: 51 * 1. Redistributions of source code must retain the above copyright 52 * notice, this list of conditions and the following disclaimer. 53 * 2. Redistributions in binary form must reproduce the above copyright 54 * notice, this list of conditions and the following disclaimer in the 55 * documentation and/or other materials provided with the distribution. 56 * 3. The name of the author may not be used to endorse or promote 57 * products derived from this software without specific prior 58 * written permission. 59 * 60 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 61 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 62 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 63 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 64 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 65 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 66 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 67 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 68 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 69 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 70 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 71 */ 72 73 /*----------------------------------------------------------------------------- 74 * RFC 1035 - Domain names - implementation and specification 75 * RFC 2181 - Clarifications to the DNS Specification 76 *----------------------------------------------------------------------------*/ 77 78 /** @todo: define good default values (rfc compliance) */ 79 /** @todo: improve answer parsing, more checkings... */ 80 /** @todo: check RFC1035 - 7.3. Processing responses */ 81 /** @todo: one-shot mDNS: dual-stack fallback to another IP version */ 82 83 /*----------------------------------------------------------------------------- 84 * Includes 85 *----------------------------------------------------------------------------*/ 86 87 #include "lwip/opt.h" 88 89 #if LWIP_DNS /* don't build if not configured for use in lwipopts.h */ 90 91 #include "lwip/def.h" 92 #include "lwip/udp.h" 93 #include "lwip/mem.h" 94 #include "lwip/memp.h" 95 #include "lwip/dns.h" 96 #include "lwip/prot/dns.h" 97 98 #include <string.h> 99 100 /** Random generator function to create random TXIDs and source ports for queries */ 101 #ifndef DNS_RAND_TXID 102 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_XID) != 0) 103 #define DNS_RAND_TXID LWIP_RAND 104 #else 105 static u16_t dns_txid; 106 #define DNS_RAND_TXID() (++dns_txid) 107 #endif 108 #endif 109 110 /** Limits the source port to be >= 1024 by default */ 111 #ifndef DNS_PORT_ALLOWED 112 #define DNS_PORT_ALLOWED(port) ((port) >= 1024) 113 #endif 114 115 /** DNS resource record max. TTL (one week as default) */ 116 #ifndef DNS_MAX_TTL 117 #define DNS_MAX_TTL 604800 118 #elif DNS_MAX_TTL > 0x7FFFFFFF 119 #error DNS_MAX_TTL must be a positive 32-bit value 120 #endif 121 122 #if DNS_TABLE_SIZE > 255 123 #error DNS_TABLE_SIZE must fit into an u8_t 124 #endif 125 #if DNS_MAX_SERVERS > 255 126 #error DNS_MAX_SERVERS must fit into an u8_t 127 #endif 128 129 /* The number of parallel requests (i.e. calls to dns_gethostbyname 130 * that cannot be answered from the DNS table. 131 * This is set to the table size by default. 132 */ 133 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0) 134 #ifndef DNS_MAX_REQUESTS 135 #define DNS_MAX_REQUESTS DNS_TABLE_SIZE 136 #else 137 #if DNS_MAX_REQUESTS > 255 138 #error DNS_MAX_REQUESTS must fit into an u8_t 139 #endif 140 #endif 141 #else 142 /* In this configuration, both arrays have to have the same size and are used 143 * like one entry (used/free) */ 144 #define DNS_MAX_REQUESTS DNS_TABLE_SIZE 145 #endif 146 147 /* The number of UDP source ports used in parallel */ 148 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) 149 #ifndef DNS_MAX_SOURCE_PORTS 150 #define DNS_MAX_SOURCE_PORTS DNS_MAX_REQUESTS 151 #else 152 #if DNS_MAX_SOURCE_PORTS > 255 153 #error DNS_MAX_SOURCE_PORTS must fit into an u8_t 154 #endif 155 #endif 156 #else 157 #ifdef DNS_MAX_SOURCE_PORTS 158 #undef DNS_MAX_SOURCE_PORTS 159 #endif 160 #define DNS_MAX_SOURCE_PORTS 1 161 #endif 162 163 #if LWIP_IPV4 && LWIP_IPV6 164 #define LWIP_DNS_ADDRTYPE_IS_IPV6(t) (((t) == LWIP_DNS_ADDRTYPE_IPV6_IPV4) || ((t) == LWIP_DNS_ADDRTYPE_IPV6)) 165 #define LWIP_DNS_ADDRTYPE_MATCH_IP(t, ip) (IP_IS_V6_VAL(ip) ? LWIP_DNS_ADDRTYPE_IS_IPV6(t) : (!LWIP_DNS_ADDRTYPE_IS_IPV6(t))) 166 #define LWIP_DNS_ADDRTYPE_ARG(x) , x 167 #define LWIP_DNS_ADDRTYPE_ARG_OR_ZERO(x) x 168 #define LWIP_DNS_SET_ADDRTYPE(x, y) do { x = y; } while(0) 169 #else 170 #if LWIP_IPV6 171 #define LWIP_DNS_ADDRTYPE_IS_IPV6(t) 1 172 #else 173 #define LWIP_DNS_ADDRTYPE_IS_IPV6(t) 0 174 #endif 175 #define LWIP_DNS_ADDRTYPE_MATCH_IP(t, ip) 1 176 #define LWIP_DNS_ADDRTYPE_ARG(x) 177 #define LWIP_DNS_ADDRTYPE_ARG_OR_ZERO(x) 0 178 #define LWIP_DNS_SET_ADDRTYPE(x, y) 179 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 180 181 #if LWIP_DNS_SUPPORT_MDNS_QUERIES 182 #define LWIP_DNS_ISMDNS_ARG(x) , x 183 #else 184 #define LWIP_DNS_ISMDNS_ARG(x) 185 #endif 186 187 /** DNS query message structure. 188 No packing needed: only used locally on the stack. */ 189 struct dns_query { 190 /* DNS query record starts with either a domain name or a pointer 191 to a name already present somewhere in the packet. */ 192 u16_t type; 193 u16_t cls; 194 }; 195 #define SIZEOF_DNS_QUERY 4 196 197 /** DNS answer message structure. 198 No packing needed: only used locally on the stack. */ 199 struct dns_answer { 200 /* DNS answer record starts with either a domain name or a pointer 201 to a name already present somewhere in the packet. */ 202 u16_t type; 203 u16_t cls; 204 u32_t ttl; 205 u16_t len; 206 }; 207 #define SIZEOF_DNS_ANSWER 10 208 /* maximum allowed size for the struct due to non-packed */ 209 #define SIZEOF_DNS_ANSWER_ASSERT 12 210 211 /* DNS table entry states */ 212 typedef enum { 213 DNS_STATE_UNUSED = 0, 214 DNS_STATE_NEW = 1, 215 DNS_STATE_ASKING = 2, 216 DNS_STATE_DONE = 3 217 } dns_state_enum_t; 218 219 /** DNS table entry */ 220 struct dns_table_entry { 221 u32_t ttl; 222 ip_addr_t ipaddr; 223 u16_t txid; 224 u8_t state; 225 u8_t server_idx; 226 u8_t tmr; 227 u8_t retries; 228 u8_t seqno; 229 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) 230 u8_t pcb_idx; 231 #endif 232 char name[DNS_MAX_NAME_LENGTH]; 233 #if LWIP_IPV4 && LWIP_IPV6 234 u8_t reqaddrtype; 235 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 236 #if LWIP_DNS_SUPPORT_MDNS_QUERIES 237 u8_t is_mdns; 238 #endif 239 }; 240 241 /** DNS request table entry: used when dns_gehostbyname cannot answer the 242 * request from the DNS table */ 243 struct dns_req_entry { 244 /* pointer to callback on DNS query done */ 245 dns_found_callback found; 246 /* argument passed to the callback function */ 247 void *arg; 248 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0) 249 u8_t dns_table_idx; 250 #endif 251 #if LWIP_IPV4 && LWIP_IPV6 252 u8_t reqaddrtype; 253 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 254 }; 255 256 #if DNS_LOCAL_HOSTLIST 257 258 #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC 259 /** Local host-list. For hostnames in this list, no 260 * external name resolution is performed */ 261 static struct local_hostlist_entry *local_hostlist_dynamic; 262 #else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ 263 264 /** Defining this allows the local_hostlist_static to be placed in a different 265 * linker section (e.g. FLASH) */ 266 #ifndef DNS_LOCAL_HOSTLIST_STORAGE_PRE 267 #define DNS_LOCAL_HOSTLIST_STORAGE_PRE static 268 #endif /* DNS_LOCAL_HOSTLIST_STORAGE_PRE */ 269 /** Defining this allows the local_hostlist_static to be placed in a different 270 * linker section (e.g. FLASH) */ 271 #ifndef DNS_LOCAL_HOSTLIST_STORAGE_POST 272 #define DNS_LOCAL_HOSTLIST_STORAGE_POST 273 #endif /* DNS_LOCAL_HOSTLIST_STORAGE_POST */ 274 DNS_LOCAL_HOSTLIST_STORAGE_PRE struct local_hostlist_entry local_hostlist_static[] 275 DNS_LOCAL_HOSTLIST_STORAGE_POST = DNS_LOCAL_HOSTLIST_INIT; 276 277 #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ 278 279 static void dns_init_local(void); 280 static err_t dns_lookup_local(const char *hostname, size_t hostnamelen, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype)); 281 #endif /* DNS_LOCAL_HOSTLIST */ 282 283 284 /* forward declarations */ 285 static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port); 286 static void dns_check_entries(void); 287 static void dns_call_found(u8_t idx, ip_addr_t *addr); 288 289 /*----------------------------------------------------------------------------- 290 * Globals 291 *----------------------------------------------------------------------------*/ 292 293 /* DNS variables */ 294 static struct udp_pcb *dns_pcbs[DNS_MAX_SOURCE_PORTS]; 295 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) 296 static u8_t dns_last_pcb_idx; 297 #endif 298 static u8_t dns_seqno; 299 static struct dns_table_entry dns_table[DNS_TABLE_SIZE]; 300 static struct dns_req_entry dns_requests[DNS_MAX_REQUESTS]; 301 static ip_addr_t dns_servers[DNS_MAX_SERVERS]; 302 303 #if LWIP_IPV4 304 const ip_addr_t dns_mquery_v4group = DNS_MQUERY_IPV4_GROUP_INIT; 305 #endif /* LWIP_IPV4 */ 306 #if LWIP_IPV6 307 const ip_addr_t dns_mquery_v6group = DNS_MQUERY_IPV6_GROUP_INIT; 308 #endif /* LWIP_IPV6 */ 309 310 /** 311 * Initialize the resolver: set up the UDP pcb and configure the default server 312 * (if DNS_SERVER_ADDRESS is set). 313 */ 314 void dns_init(void)315 dns_init(void) 316 { 317 #ifdef DNS_SERVER_ADDRESS 318 /* initialize default DNS server address */ 319 ip_addr_t dnsserver; 320 DNS_SERVER_ADDRESS(&dnsserver); 321 dns_setserver(0, &dnsserver); 322 #endif /* DNS_SERVER_ADDRESS */ 323 324 LWIP_ASSERT("sanity check SIZEOF_DNS_QUERY", 325 sizeof(struct dns_query) == SIZEOF_DNS_QUERY); 326 LWIP_ASSERT("sanity check SIZEOF_DNS_ANSWER", 327 sizeof(struct dns_answer) <= SIZEOF_DNS_ANSWER_ASSERT); 328 329 LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n")); 330 331 /* if dns client not yet initialized... */ 332 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) == 0) 333 if (dns_pcbs[0] == NULL) { 334 dns_pcbs[0] = udp_new_ip_type(IPADDR_TYPE_ANY); 335 LWIP_ASSERT("dns_pcbs[0] != NULL", dns_pcbs[0] != NULL); 336 337 /* initialize DNS table not needed (initialized to zero since it is a 338 * global variable) */ 339 LWIP_ASSERT("For implicit initialization to work, DNS_STATE_UNUSED needs to be 0", 340 DNS_STATE_UNUSED == 0); 341 342 /* initialize DNS client */ 343 udp_bind(dns_pcbs[0], IP_ANY_TYPE, 0); 344 udp_recv(dns_pcbs[0], dns_recv, NULL); 345 } 346 #endif 347 348 #if DNS_LOCAL_HOSTLIST 349 dns_init_local(); 350 #endif 351 } 352 353 /** 354 * @ingroup dns 355 * Initialize one of the DNS servers. 356 * 357 * @param numdns the index of the DNS server to set must be < DNS_MAX_SERVERS 358 * @param dnsserver IP address of the DNS server to set 359 */ 360 void dns_setserver(u8_t numdns,const ip_addr_t * dnsserver)361 dns_setserver(u8_t numdns, const ip_addr_t *dnsserver) 362 { 363 if (numdns < DNS_MAX_SERVERS) { 364 if (dnsserver != NULL) { 365 dns_servers[numdns] = (*dnsserver); 366 } else { 367 dns_servers[numdns] = *IP_ADDR_ANY; 368 } 369 } 370 } 371 372 /** 373 * @ingroup dns 374 * Obtain one of the currently configured DNS server. 375 * 376 * @param numdns the index of the DNS server 377 * @return IP address of the indexed DNS server or "ip_addr_any" if the DNS 378 * server has not been configured. 379 */ 380 const ip_addr_t * dns_getserver(u8_t numdns)381 dns_getserver(u8_t numdns) 382 { 383 if (numdns < DNS_MAX_SERVERS) { 384 return &dns_servers[numdns]; 385 } else { 386 return IP_ADDR_ANY; 387 } 388 } 389 390 /** 391 * The DNS resolver client timer - handle retries and timeouts and should 392 * be called every DNS_TMR_INTERVAL milliseconds (every second by default). 393 */ 394 void dns_tmr(void)395 dns_tmr(void) 396 { 397 LWIP_DEBUGF(DNS_DEBUG, ("dns_tmr: dns_check_entries\n")); 398 dns_check_entries(); 399 } 400 401 #if DNS_LOCAL_HOSTLIST 402 static void dns_init_local(void)403 dns_init_local(void) 404 { 405 #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) 406 size_t i; 407 struct local_hostlist_entry *entry; 408 /* Dynamic: copy entries from DNS_LOCAL_HOSTLIST_INIT to list */ 409 struct local_hostlist_entry local_hostlist_init[] = DNS_LOCAL_HOSTLIST_INIT; 410 size_t namelen; 411 for (i = 0; i < LWIP_ARRAYSIZE(local_hostlist_init); i++) { 412 struct local_hostlist_entry *init_entry = &local_hostlist_init[i]; 413 LWIP_ASSERT("invalid host name (NULL)", init_entry->name != NULL); 414 namelen = strlen(init_entry->name); 415 LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN); 416 entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST); 417 LWIP_ASSERT("mem-error in dns_init_local", entry != NULL); 418 if (entry != NULL) { 419 char *entry_name = (char *)entry + sizeof(struct local_hostlist_entry); 420 MEMCPY(entry_name, init_entry->name, namelen); 421 entry_name[namelen] = 0; 422 entry->name = entry_name; 423 entry->addr = init_entry->addr; 424 entry->next = local_hostlist_dynamic; 425 local_hostlist_dynamic = entry; 426 } 427 } 428 #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) */ 429 } 430 431 /** 432 * @ingroup dns 433 * Iterate the local host-list for a hostname. 434 * 435 * @param iterator_fn a function that is called for every entry in the local host-list 436 * @param iterator_arg 3rd argument passed to iterator_fn 437 * @return the number of entries in the local host-list 438 */ 439 size_t dns_local_iterate(dns_found_callback iterator_fn,void * iterator_arg)440 dns_local_iterate(dns_found_callback iterator_fn, void *iterator_arg) 441 { 442 size_t i; 443 #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC 444 struct local_hostlist_entry *entry = local_hostlist_dynamic; 445 i = 0; 446 while (entry != NULL) { 447 if (iterator_fn != NULL) { 448 iterator_fn(entry->name, &entry->addr, iterator_arg); 449 } 450 i++; 451 entry = entry->next; 452 } 453 #else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ 454 for (i = 0; i < LWIP_ARRAYSIZE(local_hostlist_static); i++) { 455 if (iterator_fn != NULL) { 456 iterator_fn(local_hostlist_static[i].name, &local_hostlist_static[i].addr, iterator_arg); 457 } 458 } 459 #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ 460 return i; 461 } 462 463 /** 464 * @ingroup dns 465 * Scans the local host-list for a hostname. 466 * 467 * @param hostname Hostname to look for in the local host-list 468 * @param addr the first IP address for the hostname in the local host-list or 469 * IPADDR_NONE if not found. 470 * @param dns_addrtype - LWIP_DNS_ADDRTYPE_IPV4_IPV6: try to resolve IPv4 (ATTENTION: no fallback here!) 471 * - LWIP_DNS_ADDRTYPE_IPV6_IPV4: try to resolve IPv6 (ATTENTION: no fallback here!) 472 * - LWIP_DNS_ADDRTYPE_IPV4: try to resolve IPv4 only 473 * - LWIP_DNS_ADDRTYPE_IPV6: try to resolve IPv6 only 474 * @return ERR_OK if found, ERR_ARG if not found 475 */ 476 err_t dns_local_lookup(const char * hostname,ip_addr_t * addr,u8_t dns_addrtype)477 dns_local_lookup(const char *hostname, ip_addr_t *addr, u8_t dns_addrtype) 478 { 479 size_t hostnamelen; 480 LWIP_UNUSED_ARG(dns_addrtype); 481 if ((addr == NULL) || 482 (!hostname) || (!hostname[0])) { 483 return ERR_ARG; 484 } 485 hostnamelen = strlen(hostname); 486 if (hostname[hostnamelen - 1] == '.') { 487 hostnamelen--; 488 } 489 if (hostnamelen >= DNS_MAX_NAME_LENGTH) { 490 LWIP_DEBUGF(DNS_DEBUG, ("dns_local_lookup: name too long to resolve")); 491 return ERR_ARG; 492 } 493 return dns_lookup_local(hostname, hostnamelen, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)); 494 } 495 496 /* Internal implementation for dns_local_lookup and dns_lookup */ 497 static err_t dns_lookup_local(const char * hostname,size_t hostnamelen,ip_addr_t * addr LWIP_DNS_ADDRTYPE_ARG (u8_t dns_addrtype))498 dns_lookup_local(const char *hostname, size_t hostnamelen, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype)) 499 { 500 #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC 501 struct local_hostlist_entry *entry = local_hostlist_dynamic; 502 while (entry != NULL) { 503 if ((lwip_strnicmp(entry->name, hostname, hostnamelen) == 0) && 504 !entry->name[hostnamelen] && 505 LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, entry->addr)) { 506 if (addr) { 507 ip_addr_copy(*addr, entry->addr); 508 } 509 return ERR_OK; 510 } 511 entry = entry->next; 512 } 513 #else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ 514 size_t i; 515 for (i = 0; i < LWIP_ARRAYSIZE(local_hostlist_static); i++) { 516 if ((lwip_strnicmp(local_hostlist_static[i].name, hostname, hostnamelen) == 0) && 517 !local_hostlist_static[i].name[hostnamelen] && 518 LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, local_hostlist_static[i].addr)) { 519 if (addr) { 520 ip_addr_copy(*addr, local_hostlist_static[i].addr); 521 } 522 return ERR_OK; 523 } 524 } 525 #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ 526 return ERR_ARG; 527 } 528 529 #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC 530 /** 531 * @ingroup dns 532 * Remove all entries from the local host-list for a specific hostname 533 * and/or IP address 534 * 535 * @param hostname hostname for which entries shall be removed from the local 536 * host-list 537 * @param addr address for which entries shall be removed from the local host-list 538 * @return the number of removed entries 539 */ 540 int dns_local_removehost(const char * hostname,const ip_addr_t * addr)541 dns_local_removehost(const char *hostname, const ip_addr_t *addr) 542 { 543 int removed = 0; 544 struct local_hostlist_entry *entry = local_hostlist_dynamic; 545 struct local_hostlist_entry *last_entry = NULL; 546 while (entry != NULL) { 547 if (((hostname == NULL) || !lwip_stricmp(entry->name, hostname)) && 548 ((addr == NULL) || ip_addr_cmp(&entry->addr, addr))) { 549 struct local_hostlist_entry *free_entry; 550 if (last_entry != NULL) { 551 last_entry->next = entry->next; 552 } else { 553 local_hostlist_dynamic = entry->next; 554 } 555 free_entry = entry; 556 entry = entry->next; 557 memp_free(MEMP_LOCALHOSTLIST, free_entry); 558 removed++; 559 } else { 560 last_entry = entry; 561 entry = entry->next; 562 } 563 } 564 return removed; 565 } 566 567 /** 568 * @ingroup dns 569 * Add a hostname/IP address pair to the local host-list. 570 * Duplicates are not checked. 571 * 572 * @param hostname hostname of the new entry 573 * @param addr IP address of the new entry 574 * @return ERR_OK if succeeded or ERR_MEM on memory error 575 */ 576 err_t dns_local_addhost(const char * hostname,const ip_addr_t * addr)577 dns_local_addhost(const char *hostname, const ip_addr_t *addr) 578 { 579 struct local_hostlist_entry *entry; 580 size_t namelen; 581 char *entry_name; 582 LWIP_ASSERT("invalid host name (NULL)", hostname != NULL); 583 namelen = strlen(hostname); 584 LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN); 585 entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST); 586 if (entry == NULL) { 587 return ERR_MEM; 588 } 589 entry_name = (char *)entry + sizeof(struct local_hostlist_entry); 590 MEMCPY(entry_name, hostname, namelen); 591 entry_name[namelen] = 0; 592 entry->name = entry_name; 593 ip_addr_copy(entry->addr, *addr); 594 entry->next = local_hostlist_dynamic; 595 local_hostlist_dynamic = entry; 596 return ERR_OK; 597 } 598 #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC*/ 599 #endif /* DNS_LOCAL_HOSTLIST */ 600 601 /** 602 * @ingroup dns 603 * Look up a hostname in the array of known hostnames. 604 * 605 * @note This function only looks in the internal array of known 606 * hostnames, it does not send out a query for the hostname if none 607 * was found. The function dns_enqueue() can be used to send a query 608 * for a hostname. 609 * 610 * @param name the hostname to look up 611 * @param hostnamelen length of the hostname 612 * @param addr the hostname's IP address, as u32_t (instead of ip_addr_t to 613 * better check for failure: != IPADDR_NONE) or IPADDR_NONE if the hostname 614 * was not found in the cached dns_table. 615 * @return ERR_OK if found, ERR_ARG if not found 616 */ 617 static err_t dns_lookup(const char * name,size_t hostnamelen,ip_addr_t * addr LWIP_DNS_ADDRTYPE_ARG (u8_t dns_addrtype))618 dns_lookup(const char *name, size_t hostnamelen, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype)) 619 { 620 size_t namelen; 621 u8_t i; 622 #if DNS_LOCAL_HOSTLIST 623 if (dns_lookup_local(name, hostnamelen, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)) == ERR_OK) { 624 return ERR_OK; 625 } 626 #endif /* DNS_LOCAL_HOSTLIST */ 627 #ifdef DNS_LOOKUP_LOCAL_EXTERN 628 if (DNS_LOOKUP_LOCAL_EXTERN(name, hostnamelen, addr, LWIP_DNS_ADDRTYPE_ARG_OR_ZERO(dns_addrtype)) == ERR_OK) { 629 return ERR_OK; 630 } 631 #endif /* DNS_LOOKUP_LOCAL_EXTERN */ 632 633 namelen = LWIP_MIN(hostnamelen, DNS_MAX_NAME_LENGTH - 1); 634 /* Walk through name list, return entry if found. If not, return NULL. */ 635 for (i = 0; i < DNS_TABLE_SIZE; ++i) { 636 if ((dns_table[i].state == DNS_STATE_DONE) && 637 (lwip_strnicmp(name, dns_table[i].name, namelen) == 0) && 638 !dns_table[i].name[namelen] && 639 LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, dns_table[i].ipaddr)) { 640 LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name)); 641 ip_addr_debug_print_val(DNS_DEBUG, dns_table[i].ipaddr); 642 LWIP_DEBUGF(DNS_DEBUG, ("\n")); 643 if (addr) { 644 ip_addr_copy(*addr, dns_table[i].ipaddr); 645 } 646 return ERR_OK; 647 } 648 } 649 650 return ERR_ARG; 651 } 652 653 /** 654 * Compare the "dotted" name "query" with the encoded name "response" 655 * to make sure an answer from the DNS server matches the current dns_table 656 * entry (otherwise, answers might arrive late for hostname not on the list 657 * any more). 658 * 659 * For now, this function compares case-insensitive to cope with all kinds of 660 * servers. This also means that "dns 0x20 bit encoding" must be checked 661 * externally, if we want to implement it. 662 * Currently, the request is sent exactly as passed in by he user request. 663 * 664 * @param query hostname (not encoded) from the dns_table 665 * @param p pbuf containing the encoded hostname in the DNS response 666 * @param start_offset offset into p where the name starts 667 * @return 0xFFFF: names differ, other: names equal -> offset behind name 668 */ 669 static u16_t dns_compare_name(const char * query,struct pbuf * p,u16_t start_offset)670 dns_compare_name(const char *query, struct pbuf *p, u16_t start_offset) 671 { 672 int n; 673 u16_t response_offset = start_offset; 674 675 do { 676 n = pbuf_try_get_at(p, response_offset); 677 if ((n < 0) || (response_offset == 0xFFFF)) { 678 /* error or overflow */ 679 return 0xFFFF; 680 } 681 response_offset++; 682 /** @see RFC 1035 - 4.1.4. Message compression */ 683 if ((n & 0xc0) == 0xc0) { 684 /* Compressed name: cannot be equal since we don't send them */ 685 return 0xFFFF; 686 } else { 687 /* Not compressed name */ 688 while (n > 0) { 689 int c = pbuf_try_get_at(p, response_offset); 690 if (c < 0) { 691 return 0xFFFF; 692 } 693 if (lwip_tolower((*query)) != lwip_tolower((u8_t)c)) { 694 return 0xFFFF; 695 } 696 if (response_offset == 0xFFFF) { 697 /* would overflow */ 698 return 0xFFFF; 699 } 700 response_offset++; 701 ++query; 702 --n; 703 } 704 ++query; 705 } 706 n = pbuf_try_get_at(p, response_offset); 707 if (n < 0) { 708 return 0xFFFF; 709 } 710 } while (n != 0); 711 712 if (response_offset == 0xFFFF) { 713 /* would overflow */ 714 return 0xFFFF; 715 } 716 return (u16_t)(response_offset + 1); 717 } 718 719 /** 720 * Walk through a compact encoded DNS name and return the end of the name. 721 * 722 * @param p pbuf containing the name 723 * @param query_idx start index into p pointing to encoded DNS name in the DNS server response 724 * @return index to end of the name 725 */ 726 static u16_t dns_skip_name(struct pbuf * p,u16_t query_idx)727 dns_skip_name(struct pbuf *p, u16_t query_idx) 728 { 729 int n; 730 u16_t offset = query_idx; 731 732 do { 733 n = pbuf_try_get_at(p, offset++); 734 if ((n < 0) || (offset == 0)) { 735 return 0xFFFF; 736 } 737 /** @see RFC 1035 - 4.1.4. Message compression */ 738 if ((n & 0xc0) == 0xc0) { 739 /* Compressed name: since we only want to skip it (not check it), stop here */ 740 break; 741 } else { 742 /* Not compressed name */ 743 if (offset + n >= p->tot_len) { 744 return 0xFFFF; 745 } 746 offset = (u16_t)(offset + n); 747 } 748 n = pbuf_try_get_at(p, offset); 749 if (n < 0) { 750 return 0xFFFF; 751 } 752 } while (n != 0); 753 754 if (offset == 0xFFFF) { 755 return 0xFFFF; 756 } 757 return (u16_t)(offset + 1); 758 } 759 760 /** 761 * Send a DNS query packet. 762 * 763 * @param idx the DNS table entry index for which to send a request 764 * @return ERR_OK if packet is sent; an err_t indicating the problem otherwise 765 */ 766 static err_t dns_send(u8_t idx)767 dns_send(u8_t idx) 768 { 769 err_t err; 770 struct dns_hdr hdr; 771 struct dns_query qry; 772 struct pbuf *p; 773 u16_t query_idx, copy_len; 774 const char *hostname, *hostname_part; 775 u8_t n; 776 u8_t pcb_idx; 777 struct dns_table_entry *entry = &dns_table[idx]; 778 779 LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n", 780 (u16_t)(entry->server_idx), entry->name)); 781 LWIP_ASSERT("dns server out of array", entry->server_idx < DNS_MAX_SERVERS); 782 if (ip_addr_isany_val(dns_servers[entry->server_idx]) 783 #if LWIP_DNS_SUPPORT_MDNS_QUERIES 784 && !entry->is_mdns 785 #endif 786 ) { 787 /* DNS server not valid anymore, e.g. PPP netif has been shut down */ 788 /* call specified callback function if provided */ 789 dns_call_found(idx, NULL); 790 /* flush this entry */ 791 entry->state = DNS_STATE_UNUSED; 792 return ERR_OK; 793 } 794 795 /* if here, we have either a new query or a retry on a previous query to process */ 796 p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(SIZEOF_DNS_HDR + strlen(entry->name) + 2 + 797 SIZEOF_DNS_QUERY), PBUF_RAM); 798 if (p != NULL) { 799 const ip_addr_t *dst; 800 u16_t dst_port; 801 /* fill dns header */ 802 memset(&hdr, 0, SIZEOF_DNS_HDR); 803 hdr.id = lwip_htons(entry->txid); 804 hdr.flags1 = DNS_FLAG1_RD; 805 hdr.numquestions = PP_HTONS(1); 806 pbuf_take(p, &hdr, SIZEOF_DNS_HDR); 807 hostname = entry->name; 808 --hostname; 809 810 /* convert hostname into suitable query format. */ 811 query_idx = SIZEOF_DNS_HDR; 812 do { 813 ++hostname; 814 hostname_part = hostname; 815 for (n = 0; *hostname != '.' && *hostname != 0; ++hostname) { 816 ++n; 817 } 818 copy_len = (u16_t)(hostname - hostname_part); 819 if (query_idx + n + 1 > 0xFFFF) { 820 /* u16_t overflow */ 821 goto overflow_return; 822 } 823 pbuf_put_at(p, query_idx, n); 824 pbuf_take_at(p, hostname_part, copy_len, (u16_t)(query_idx + 1)); 825 query_idx = (u16_t)(query_idx + n + 1); 826 } while (*hostname != 0); 827 pbuf_put_at(p, query_idx, 0); 828 query_idx++; 829 830 /* fill dns query */ 831 if (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype)) { 832 qry.type = PP_HTONS(DNS_RRTYPE_AAAA); 833 } else { 834 qry.type = PP_HTONS(DNS_RRTYPE_A); 835 } 836 qry.cls = PP_HTONS(DNS_RRCLASS_IN); 837 pbuf_take_at(p, &qry, SIZEOF_DNS_QUERY, query_idx); 838 839 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) 840 pcb_idx = entry->pcb_idx; 841 #else 842 pcb_idx = 0; 843 #endif 844 /* send dns packet */ 845 LWIP_DEBUGF(DNS_DEBUG, ("sending DNS request ID %d for name \"%s\" to server %d\r\n", 846 entry->txid, entry->name, entry->server_idx)); 847 #if LWIP_DNS_SUPPORT_MDNS_QUERIES 848 if (entry->is_mdns) { 849 dst_port = DNS_MQUERY_PORT; 850 #if LWIP_IPV6 851 if (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype)) { 852 dst = &dns_mquery_v6group; 853 } 854 #endif 855 #if LWIP_IPV4 && LWIP_IPV6 856 else 857 #endif 858 #if LWIP_IPV4 859 { 860 dst = &dns_mquery_v4group; 861 } 862 #endif 863 } else 864 #endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */ 865 { 866 dst_port = DNS_SERVER_PORT; 867 dst = &dns_servers[entry->server_idx]; 868 } 869 err = udp_sendto(dns_pcbs[pcb_idx], p, dst, dst_port); 870 871 /* free pbuf */ 872 pbuf_free(p); 873 } else { 874 err = ERR_MEM; 875 } 876 877 return err; 878 overflow_return: 879 pbuf_free(p); 880 return ERR_VAL; 881 } 882 883 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) 884 static struct udp_pcb * dns_alloc_random_port(void)885 dns_alloc_random_port(void) 886 { 887 err_t err; 888 struct udp_pcb *pcb; 889 890 pcb = udp_new_ip_type(IPADDR_TYPE_ANY); 891 if (pcb == NULL) { 892 /* out of memory, have to reuse an existing pcb */ 893 return NULL; 894 } 895 do { 896 u16_t port = (u16_t)DNS_RAND_TXID(); 897 if (DNS_PORT_ALLOWED(port)) { 898 err = udp_bind(pcb, IP_ANY_TYPE, port); 899 } else { 900 /* this port is not allowed, try again */ 901 err = ERR_USE; 902 } 903 } while (err == ERR_USE); 904 if (err != ERR_OK) { 905 udp_remove(pcb); 906 return NULL; 907 } 908 udp_recv(pcb, dns_recv, NULL); 909 return pcb; 910 } 911 912 /** 913 * dns_alloc_pcb() - allocates a new pcb (or reuses an existing one) to be used 914 * for sending a request 915 * 916 * @return an index into dns_pcbs 917 */ 918 static u8_t dns_alloc_pcb(void)919 dns_alloc_pcb(void) 920 { 921 u8_t i; 922 u8_t idx; 923 924 for (i = 0; i < DNS_MAX_SOURCE_PORTS; i++) { 925 if (dns_pcbs[i] == NULL) { 926 break; 927 } 928 } 929 if (i < DNS_MAX_SOURCE_PORTS) { 930 dns_pcbs[i] = dns_alloc_random_port(); 931 if (dns_pcbs[i] != NULL) { 932 /* succeeded */ 933 dns_last_pcb_idx = i; 934 return i; 935 } 936 } 937 /* if we come here, creating a new UDP pcb failed, so we have to use 938 an already existing one (so overflow is no issue) */ 939 for (i = 0, idx = (u8_t)(dns_last_pcb_idx + 1); i < DNS_MAX_SOURCE_PORTS; i++, idx++) { 940 if (idx >= DNS_MAX_SOURCE_PORTS) { 941 idx = 0; 942 } 943 if (dns_pcbs[idx] != NULL) { 944 dns_last_pcb_idx = idx; 945 return idx; 946 } 947 } 948 return DNS_MAX_SOURCE_PORTS; 949 } 950 #endif /* ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) */ 951 952 /** 953 * dns_call_found() - call the found callback and check if there are duplicate 954 * entries for the given hostname. If there are any, their found callback will 955 * be called and they will be removed. 956 * 957 * @param idx dns table index of the entry that is resolved or removed 958 * @param addr IP address for the hostname (or NULL on error or memory shortage) 959 */ 960 static void dns_call_found(u8_t idx,ip_addr_t * addr)961 dns_call_found(u8_t idx, ip_addr_t *addr) 962 { 963 #if ((LWIP_DNS_SECURE & (LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING | LWIP_DNS_SECURE_RAND_SRC_PORT)) != 0) 964 u8_t i; 965 #endif 966 967 #if LWIP_IPV4 && LWIP_IPV6 968 if (addr != NULL) { 969 /* check that address type matches the request and adapt the table entry */ 970 if (IP_IS_V6_VAL(*addr)) { 971 LWIP_ASSERT("invalid response", LWIP_DNS_ADDRTYPE_IS_IPV6(dns_table[idx].reqaddrtype)); 972 dns_table[idx].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV6; 973 } else { 974 LWIP_ASSERT("invalid response", !LWIP_DNS_ADDRTYPE_IS_IPV6(dns_table[idx].reqaddrtype)); 975 dns_table[idx].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV4; 976 } 977 } 978 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 979 980 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0) 981 for (i = 0; i < DNS_MAX_REQUESTS; i++) { 982 if (dns_requests[i].found && (dns_requests[i].dns_table_idx == idx)) { 983 (*dns_requests[i].found)(dns_table[idx].name, addr, dns_requests[i].arg); 984 /* flush this entry */ 985 dns_requests[i].found = NULL; 986 } 987 } 988 #else 989 if (dns_requests[idx].found) { 990 (*dns_requests[idx].found)(dns_table[idx].name, addr, dns_requests[idx].arg); 991 } 992 dns_requests[idx].found = NULL; 993 #endif 994 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) 995 /* close the pcb used unless other request are using it */ 996 for (i = 0; i < DNS_MAX_REQUESTS; i++) { 997 if (i == idx) { 998 continue; /* only check other requests */ 999 } 1000 if (dns_table[i].state == DNS_STATE_ASKING) { 1001 if (dns_table[i].pcb_idx == dns_table[idx].pcb_idx) { 1002 /* another request is still using the same pcb */ 1003 dns_table[idx].pcb_idx = DNS_MAX_SOURCE_PORTS; 1004 break; 1005 } 1006 } 1007 } 1008 if (dns_table[idx].pcb_idx < DNS_MAX_SOURCE_PORTS) { 1009 /* if we come here, the pcb is not used any more and can be removed */ 1010 udp_remove(dns_pcbs[dns_table[idx].pcb_idx]); 1011 dns_pcbs[dns_table[idx].pcb_idx] = NULL; 1012 dns_table[idx].pcb_idx = DNS_MAX_SOURCE_PORTS; 1013 } 1014 #endif 1015 } 1016 1017 /* Create a query transmission ID that is unique for all outstanding queries */ 1018 static u16_t dns_create_txid(void)1019 dns_create_txid(void) 1020 { 1021 u16_t txid; 1022 u8_t i; 1023 1024 again: 1025 txid = (u16_t)DNS_RAND_TXID(); 1026 1027 /* check whether the ID is unique */ 1028 for (i = 0; i < DNS_TABLE_SIZE; i++) { 1029 if ((dns_table[i].state == DNS_STATE_ASKING) && 1030 (dns_table[i].txid == txid)) { 1031 /* ID already used by another pending query */ 1032 goto again; 1033 } 1034 } 1035 1036 return txid; 1037 } 1038 1039 /** 1040 * Check whether there are other backup DNS servers available to try 1041 */ 1042 static u8_t dns_backupserver_available(struct dns_table_entry * pentry)1043 dns_backupserver_available(struct dns_table_entry *pentry) 1044 { 1045 u8_t ret = 0; 1046 1047 if (pentry) { 1048 if ((pentry->server_idx + 1 < DNS_MAX_SERVERS) && !ip_addr_isany_val(dns_servers[pentry->server_idx + 1])) { 1049 ret = 1; 1050 } 1051 } 1052 1053 return ret; 1054 } 1055 1056 /** 1057 * dns_check_entry() - see if entry has not yet been queried and, if so, sends out a query. 1058 * Check an entry in the dns_table: 1059 * - send out query for new entries 1060 * - retry old pending entries on timeout (also with different servers) 1061 * - remove completed entries from the table if their TTL has expired 1062 * 1063 * @param i index of the dns_table entry to check 1064 */ 1065 static void dns_check_entry(u8_t i)1066 dns_check_entry(u8_t i) 1067 { 1068 err_t err; 1069 struct dns_table_entry *entry = &dns_table[i]; 1070 1071 LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE); 1072 1073 switch (entry->state) { 1074 case DNS_STATE_NEW: 1075 /* initialize new entry */ 1076 entry->txid = dns_create_txid(); 1077 entry->state = DNS_STATE_ASKING; 1078 entry->server_idx = 0; 1079 entry->tmr = 1; 1080 entry->retries = 0; 1081 1082 /* send DNS packet for this entry */ 1083 err = dns_send(i); 1084 if (err != ERR_OK) { 1085 LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING, 1086 ("dns_send returned error: %s\n", lwip_strerr(err))); 1087 } 1088 break; 1089 case DNS_STATE_ASKING: 1090 if (--entry->tmr == 0) { 1091 if (++entry->retries == DNS_MAX_RETRIES) { 1092 if (dns_backupserver_available(entry) 1093 #if LWIP_DNS_SUPPORT_MDNS_QUERIES 1094 && !entry->is_mdns 1095 #endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */ 1096 ) { 1097 /* change of server */ 1098 entry->server_idx++; 1099 entry->tmr = 1; 1100 entry->retries = 0; 1101 } else { 1102 LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": timeout\n", entry->name)); 1103 /* call specified callback function if provided */ 1104 dns_call_found(i, NULL); 1105 /* flush this entry */ 1106 entry->state = DNS_STATE_UNUSED; 1107 break; 1108 } 1109 } else { 1110 /* wait longer for the next retry */ 1111 entry->tmr = entry->retries; 1112 } 1113 1114 /* send DNS packet for this entry */ 1115 err = dns_send(i); 1116 if (err != ERR_OK) { 1117 LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING, 1118 ("dns_send returned error: %s\n", lwip_strerr(err))); 1119 } 1120 } 1121 break; 1122 case DNS_STATE_DONE: 1123 /* if the time to live is nul */ 1124 if ((entry->ttl == 0) || (--entry->ttl == 0)) { 1125 LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": flush\n", entry->name)); 1126 /* flush this entry, there cannot be any related pending entries in this state */ 1127 entry->state = DNS_STATE_UNUSED; 1128 } 1129 break; 1130 case DNS_STATE_UNUSED: 1131 /* nothing to do */ 1132 break; 1133 default: 1134 LWIP_ASSERT("unknown dns_table entry state:", 0); 1135 break; 1136 } 1137 } 1138 1139 /** 1140 * Call dns_check_entry for each entry in dns_table - check all entries. 1141 */ 1142 static void dns_check_entries(void)1143 dns_check_entries(void) 1144 { 1145 u8_t i; 1146 1147 for (i = 0; i < DNS_TABLE_SIZE; ++i) { 1148 dns_check_entry(i); 1149 } 1150 } 1151 1152 /** 1153 * Save TTL and call dns_call_found for correct response. 1154 */ 1155 static void dns_correct_response(u8_t idx,u32_t ttl)1156 dns_correct_response(u8_t idx, u32_t ttl) 1157 { 1158 struct dns_table_entry *entry = &dns_table[idx]; 1159 1160 entry->state = DNS_STATE_DONE; 1161 1162 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", entry->name)); 1163 ip_addr_debug_print_val(DNS_DEBUG, entry->ipaddr); 1164 LWIP_DEBUGF(DNS_DEBUG, ("\n")); 1165 1166 /* read the answer resource record's TTL, and maximize it if needed */ 1167 entry->ttl = ttl; 1168 if (entry->ttl > DNS_MAX_TTL) { 1169 entry->ttl = DNS_MAX_TTL; 1170 } 1171 dns_call_found(idx, &entry->ipaddr); 1172 1173 if (entry->ttl == 0) { 1174 /* RFC 883, page 29: "Zero values are 1175 interpreted to mean that the RR can only be used for the 1176 transaction in progress, and should not be cached." 1177 -> flush this entry now */ 1178 /* entry reused during callback? */ 1179 if (entry->state == DNS_STATE_DONE) { 1180 entry->state = DNS_STATE_UNUSED; 1181 } 1182 } 1183 } 1184 1185 /** 1186 * Receive input function for DNS response packets arriving for the dns UDP pcb. 1187 */ 1188 static void dns_recv(void * arg,struct udp_pcb * pcb,struct pbuf * p,const ip_addr_t * addr,u16_t port)1189 dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) 1190 { 1191 u8_t i; 1192 u16_t txid; 1193 u16_t res_idx; 1194 struct dns_hdr hdr; 1195 struct dns_answer ans; 1196 struct dns_query qry; 1197 u16_t nquestions, nanswers; 1198 1199 LWIP_UNUSED_ARG(arg); 1200 LWIP_UNUSED_ARG(pcb); 1201 LWIP_UNUSED_ARG(port); 1202 1203 /* is the dns message big enough ? */ 1204 if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY)) { 1205 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n")); 1206 /* free pbuf and return */ 1207 goto ignore_packet; 1208 } 1209 1210 /* copy dns payload inside static buffer for processing */ 1211 if (pbuf_copy_partial(p, &hdr, SIZEOF_DNS_HDR, 0) == SIZEOF_DNS_HDR) { 1212 /* Match the ID in the DNS header with the name table. */ 1213 txid = lwip_htons(hdr.id); 1214 for (i = 0; i < DNS_TABLE_SIZE; i++) { 1215 struct dns_table_entry *entry = &dns_table[i]; 1216 if ((entry->state == DNS_STATE_ASKING) && 1217 (entry->txid == txid)) { 1218 1219 /* We only care about the question(s) and the answers. The authrr 1220 and the extrarr are simply discarded. */ 1221 nquestions = lwip_htons(hdr.numquestions); 1222 nanswers = lwip_htons(hdr.numanswers); 1223 1224 /* Check for correct response. */ 1225 if ((hdr.flags1 & DNS_FLAG1_RESPONSE) == 0) { 1226 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": not a response\n", entry->name)); 1227 goto ignore_packet; /* ignore this packet */ 1228 } 1229 if (nquestions != 1) { 1230 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", entry->name)); 1231 goto ignore_packet; /* ignore this packet */ 1232 } 1233 1234 #if LWIP_DNS_SUPPORT_MDNS_QUERIES 1235 if (!entry->is_mdns) 1236 #endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */ 1237 { 1238 /* Check whether response comes from the same network address to which the 1239 question was sent. (RFC 5452) */ 1240 if (!ip_addr_cmp(addr, &dns_servers[entry->server_idx])) { 1241 goto ignore_packet; /* ignore this packet */ 1242 } 1243 } 1244 1245 /* Check if the name in the "question" part match with the name in the entry and 1246 skip it if equal. */ 1247 res_idx = dns_compare_name(entry->name, p, SIZEOF_DNS_HDR); 1248 if (res_idx == 0xFFFF) { 1249 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", entry->name)); 1250 goto ignore_packet; /* ignore this packet */ 1251 } 1252 1253 /* check if "question" part matches the request */ 1254 if (pbuf_copy_partial(p, &qry, SIZEOF_DNS_QUERY, res_idx) != SIZEOF_DNS_QUERY) { 1255 goto ignore_packet; /* ignore this packet */ 1256 } 1257 if ((qry.cls != PP_HTONS(DNS_RRCLASS_IN)) || 1258 (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype) && (qry.type != PP_HTONS(DNS_RRTYPE_AAAA))) || 1259 (!LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype) && (qry.type != PP_HTONS(DNS_RRTYPE_A)))) { 1260 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", entry->name)); 1261 goto ignore_packet; /* ignore this packet */ 1262 } 1263 /* skip the rest of the "question" part */ 1264 if (res_idx + SIZEOF_DNS_QUERY > 0xFFFF) { 1265 goto ignore_packet; 1266 } 1267 res_idx = (u16_t)(res_idx + SIZEOF_DNS_QUERY); 1268 1269 /* Check for error. If so, call callback to inform. */ 1270 if (hdr.flags2 & DNS_FLAG2_ERR_MASK) { 1271 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in flags\n", entry->name)); 1272 1273 /* if there is another backup DNS server to try 1274 * then don't stop the DNS request 1275 */ 1276 if (dns_backupserver_available(entry)) { 1277 /* avoid retrying the same server */ 1278 entry->retries = DNS_MAX_RETRIES-1; 1279 entry->tmr = 1; 1280 1281 /* contact next available server for this entry */ 1282 dns_check_entry(i); 1283 1284 goto ignore_packet; 1285 } 1286 } else { 1287 while ((nanswers > 0) && (res_idx < p->tot_len)) { 1288 /* skip answer resource record's host name */ 1289 res_idx = dns_skip_name(p, res_idx); 1290 if (res_idx == 0xFFFF) { 1291 goto ignore_packet; /* ignore this packet */ 1292 } 1293 1294 /* Check for IP address type and Internet class. Others are discarded. */ 1295 if (pbuf_copy_partial(p, &ans, SIZEOF_DNS_ANSWER, res_idx) != SIZEOF_DNS_ANSWER) { 1296 goto ignore_packet; /* ignore this packet */ 1297 } 1298 if (res_idx + SIZEOF_DNS_ANSWER > 0xFFFF) { 1299 goto ignore_packet; 1300 } 1301 res_idx = (u16_t)(res_idx + SIZEOF_DNS_ANSWER); 1302 1303 if (ans.cls == PP_HTONS(DNS_RRCLASS_IN)) { 1304 #if LWIP_IPV4 1305 if ((ans.type == PP_HTONS(DNS_RRTYPE_A)) && (ans.len == PP_HTONS(sizeof(ip4_addr_t)))) { 1306 #if LWIP_IPV4 && LWIP_IPV6 1307 if (!LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype)) 1308 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 1309 { 1310 ip4_addr_t ip4addr; 1311 /* read the IP address after answer resource record's header */ 1312 if (pbuf_copy_partial(p, &ip4addr, sizeof(ip4_addr_t), res_idx) != sizeof(ip4_addr_t)) { 1313 goto ignore_packet; /* ignore this packet */ 1314 } 1315 ip_addr_copy_from_ip4(dns_table[i].ipaddr, ip4addr); 1316 pbuf_free(p); 1317 /* handle correct response */ 1318 dns_correct_response(i, lwip_ntohl(ans.ttl)); 1319 return; 1320 } 1321 } 1322 #endif /* LWIP_IPV4 */ 1323 #if LWIP_IPV6 1324 if ((ans.type == PP_HTONS(DNS_RRTYPE_AAAA)) && (ans.len == PP_HTONS(sizeof(ip6_addr_p_t)))) { 1325 #if LWIP_IPV4 && LWIP_IPV6 1326 if (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype)) 1327 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 1328 { 1329 ip6_addr_p_t ip6addr; 1330 /* read the IP address after answer resource record's header */ 1331 if (pbuf_copy_partial(p, &ip6addr, sizeof(ip6_addr_p_t), res_idx) != sizeof(ip6_addr_p_t)) { 1332 goto ignore_packet; /* ignore this packet */ 1333 } 1334 /* @todo: scope ip6addr? Might be required for link-local addresses at least? */ 1335 ip_addr_copy_from_ip6_packed(dns_table[i].ipaddr, ip6addr); 1336 pbuf_free(p); 1337 /* handle correct response */ 1338 dns_correct_response(i, lwip_ntohl(ans.ttl)); 1339 return; 1340 } 1341 } 1342 #endif /* LWIP_IPV6 */ 1343 } 1344 /* skip this answer */ 1345 if ((int)(res_idx + lwip_htons(ans.len)) > 0xFFFF) { 1346 goto ignore_packet; /* ignore this packet */ 1347 } 1348 res_idx = (u16_t)(res_idx + lwip_htons(ans.len)); 1349 --nanswers; 1350 } 1351 #if LWIP_IPV4 && LWIP_IPV6 1352 if ((entry->reqaddrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) || 1353 (entry->reqaddrtype == LWIP_DNS_ADDRTYPE_IPV6_IPV4)) { 1354 if (entry->reqaddrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) { 1355 /* IPv4 failed, try IPv6 */ 1356 dns_table[i].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV6; 1357 } else { 1358 /* IPv6 failed, try IPv4 */ 1359 dns_table[i].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV4; 1360 } 1361 pbuf_free(p); 1362 dns_table[i].state = DNS_STATE_NEW; 1363 dns_check_entry(i); 1364 return; 1365 } 1366 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 1367 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in response\n", entry->name)); 1368 } 1369 /* call callback to indicate error, clean up memory and return */ 1370 pbuf_free(p); 1371 dns_call_found(i, NULL); 1372 dns_table[i].state = DNS_STATE_UNUSED; 1373 return; 1374 } 1375 } 1376 } 1377 1378 ignore_packet: 1379 /* deallocate memory and return */ 1380 pbuf_free(p); 1381 return; 1382 } 1383 1384 /** 1385 * Queues a new hostname to resolve and sends out a DNS query for that hostname 1386 * 1387 * @param name the hostname that is to be queried 1388 * @param hostnamelen length of the hostname 1389 * @param found a callback function to be called on success, failure or timeout 1390 * @param callback_arg argument to pass to the callback function 1391 * @return err_t return code. 1392 */ 1393 static err_t dns_enqueue(const char * name,size_t hostnamelen,dns_found_callback found,void * callback_arg LWIP_DNS_ADDRTYPE_ARG (u8_t dns_addrtype)LWIP_DNS_ISMDNS_ARG (u8_t is_mdns))1394 dns_enqueue(const char *name, size_t hostnamelen, dns_found_callback found, 1395 void *callback_arg LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype) LWIP_DNS_ISMDNS_ARG(u8_t is_mdns)) 1396 { 1397 u8_t i; 1398 u8_t lseq, lseqi; 1399 struct dns_table_entry *entry = NULL; 1400 size_t namelen; 1401 struct dns_req_entry *req; 1402 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0) 1403 u8_t r; 1404 #endif 1405 1406 namelen = LWIP_MIN(hostnamelen, DNS_MAX_NAME_LENGTH - 1); 1407 1408 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0) 1409 /* check for duplicate entries */ 1410 for (i = 0; i < DNS_TABLE_SIZE; i++) { 1411 if ((dns_table[i].state == DNS_STATE_ASKING) && 1412 (lwip_strnicmp(name, dns_table[i].name, namelen) == 0) && 1413 !dns_table[i].name[namelen]) { 1414 #if LWIP_IPV4 && LWIP_IPV6 1415 if (dns_table[i].reqaddrtype != dns_addrtype) { 1416 /* requested address types don't match 1417 this can lead to 2 concurrent requests, but mixing the address types 1418 for the same host should not be that common */ 1419 continue; 1420 } 1421 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 1422 /* this is a duplicate entry, find a free request entry */ 1423 for (r = 0; r < DNS_MAX_REQUESTS; r++) { 1424 if (dns_requests[r].found == 0) { 1425 dns_requests[r].found = found; 1426 dns_requests[r].arg = callback_arg; 1427 dns_requests[r].dns_table_idx = i; 1428 LWIP_DNS_SET_ADDRTYPE(dns_requests[r].reqaddrtype, dns_addrtype); 1429 LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": duplicate request\n", name)); 1430 return ERR_INPROGRESS; 1431 } 1432 } 1433 } 1434 } 1435 /* no duplicate entries found */ 1436 #endif 1437 1438 /* search an unused entry, or the oldest one */ 1439 lseq = 0; 1440 lseqi = DNS_TABLE_SIZE; 1441 for (i = 0; i < DNS_TABLE_SIZE; ++i) { 1442 entry = &dns_table[i]; 1443 /* is it an unused entry ? */ 1444 if (entry->state == DNS_STATE_UNUSED) { 1445 break; 1446 } 1447 /* check if this is the oldest completed entry */ 1448 if (entry->state == DNS_STATE_DONE) { 1449 u8_t age = (u8_t)(dns_seqno - entry->seqno); 1450 if (age > lseq) { 1451 lseq = age; 1452 lseqi = i; 1453 } 1454 } 1455 } 1456 1457 /* if we don't have found an unused entry, use the oldest completed one */ 1458 if (i == DNS_TABLE_SIZE) { 1459 if ((lseqi >= DNS_TABLE_SIZE) || (dns_table[lseqi].state != DNS_STATE_DONE)) { 1460 /* no entry can be used now, table is full */ 1461 LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS entries table is full\n", name)); 1462 return ERR_MEM; 1463 } else { 1464 /* use the oldest completed one */ 1465 i = lseqi; 1466 entry = &dns_table[i]; 1467 } 1468 } 1469 1470 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0) 1471 /* find a free request entry */ 1472 req = NULL; 1473 for (r = 0; r < DNS_MAX_REQUESTS; r++) { 1474 if (dns_requests[r].found == NULL) { 1475 req = &dns_requests[r]; 1476 break; 1477 } 1478 } 1479 if (req == NULL) { 1480 /* no request entry can be used now, table is full */ 1481 LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS request entries table is full\n", name)); 1482 return ERR_MEM; 1483 } 1484 req->dns_table_idx = i; 1485 #else 1486 /* in this configuration, the entry index is the same as the request index */ 1487 req = &dns_requests[i]; 1488 #endif 1489 1490 /* use this entry */ 1491 LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS entry %"U16_F"\n", name, (u16_t)(i))); 1492 1493 /* fill the entry */ 1494 entry->state = DNS_STATE_NEW; 1495 entry->seqno = dns_seqno; 1496 LWIP_DNS_SET_ADDRTYPE(entry->reqaddrtype, dns_addrtype); 1497 LWIP_DNS_SET_ADDRTYPE(req->reqaddrtype, dns_addrtype); 1498 req->found = found; 1499 req->arg = callback_arg; 1500 MEMCPY(entry->name, name, namelen); 1501 entry->name[namelen] = 0; 1502 1503 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) 1504 entry->pcb_idx = dns_alloc_pcb(); 1505 if (entry->pcb_idx >= DNS_MAX_SOURCE_PORTS) { 1506 /* failed to get a UDP pcb */ 1507 LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": failed to allocate a pcb\n", name)); 1508 entry->state = DNS_STATE_UNUSED; 1509 req->found = NULL; 1510 return ERR_MEM; 1511 } 1512 LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS pcb %"U16_F"\n", name, (u16_t)(entry->pcb_idx))); 1513 #endif 1514 1515 #if LWIP_DNS_SUPPORT_MDNS_QUERIES 1516 entry->is_mdns = is_mdns; 1517 #endif 1518 1519 dns_seqno++; 1520 1521 /* force to send query without waiting timer */ 1522 dns_check_entry(i); 1523 1524 /* dns query is enqueued */ 1525 return ERR_INPROGRESS; 1526 } 1527 1528 /** 1529 * @ingroup dns 1530 * Resolve a hostname (string) into an IP address. 1531 * NON-BLOCKING callback version for use with raw API!!! 1532 * 1533 * Returns immediately with one of err_t return codes: 1534 * - ERR_OK if hostname is a valid IP address string or the host 1535 * name is already in the local names table. 1536 * - ERR_INPROGRESS enqueue a request to be sent to the DNS server 1537 * for resolution if no errors are present. 1538 * - ERR_ARG: dns client not initialized or invalid hostname 1539 * 1540 * @param hostname the hostname that is to be queried 1541 * @param addr pointer to a ip_addr_t where to store the address if it is already 1542 * cached in the dns_table (only valid if ERR_OK is returned!) 1543 * @param found a callback function to be called on success, failure or timeout (only if 1544 * ERR_INPROGRESS is returned!) 1545 * @param callback_arg argument to pass to the callback function 1546 * @return a err_t return code. 1547 */ 1548 err_t dns_gethostbyname(const char * hostname,ip_addr_t * addr,dns_found_callback found,void * callback_arg)1549 dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found, 1550 void *callback_arg) 1551 { 1552 return dns_gethostbyname_addrtype(hostname, addr, found, callback_arg, LWIP_DNS_ADDRTYPE_DEFAULT); 1553 } 1554 1555 /** 1556 * @ingroup dns 1557 * Like dns_gethostbyname, but returned address type can be controlled: 1558 * @param hostname the hostname that is to be queried 1559 * @param addr pointer to a ip_addr_t where to store the address if it is already 1560 * cached in the dns_table (only valid if ERR_OK is returned!) 1561 * @param found a callback function to be called on success, failure or timeout (only if 1562 * ERR_INPROGRESS is returned!) 1563 * @param callback_arg argument to pass to the callback function 1564 * @param dns_addrtype - LWIP_DNS_ADDRTYPE_IPV4_IPV6: try to resolve IPv4 first, try IPv6 if IPv4 fails only 1565 * - LWIP_DNS_ADDRTYPE_IPV6_IPV4: try to resolve IPv6 first, try IPv4 if IPv6 fails only 1566 * - LWIP_DNS_ADDRTYPE_IPV4: try to resolve IPv4 only 1567 * - LWIP_DNS_ADDRTYPE_IPV6: try to resolve IPv6 only 1568 */ 1569 err_t dns_gethostbyname_addrtype(const char * hostname,ip_addr_t * addr,dns_found_callback found,void * callback_arg,u8_t dns_addrtype)1570 dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, dns_found_callback found, 1571 void *callback_arg, u8_t dns_addrtype) 1572 { 1573 size_t hostnamelen; 1574 #if LWIP_DNS_SUPPORT_MDNS_QUERIES 1575 u8_t is_mdns; 1576 #endif 1577 /* not initialized or no valid server yet, or invalid addr pointer 1578 * or invalid hostname or invalid hostname length */ 1579 if ((addr == NULL) || 1580 (!hostname) || (!hostname[0])) { 1581 return ERR_ARG; 1582 } 1583 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) == 0) 1584 if (dns_pcbs[0] == NULL) { 1585 return ERR_ARG; 1586 } 1587 #endif 1588 hostnamelen = strlen(hostname); 1589 if (hostname[hostnamelen - 1] == '.') { 1590 hostnamelen--; 1591 } 1592 if (hostnamelen >= DNS_MAX_NAME_LENGTH) { 1593 LWIP_DEBUGF(DNS_DEBUG, ("dns_gethostbyname: name too long to resolve")); 1594 return ERR_ARG; 1595 } 1596 1597 1598 #if LWIP_HAVE_LOOPIF 1599 if (strcmp(hostname, "localhost") == 0) { 1600 ip_addr_set_loopback(LWIP_DNS_ADDRTYPE_IS_IPV6(dns_addrtype), addr); 1601 return ERR_OK; 1602 } 1603 #endif /* LWIP_HAVE_LOOPIF */ 1604 1605 /* host name already in octet notation? set ip addr and return ERR_OK */ 1606 if (ipaddr_aton(hostname, addr)) { 1607 #if LWIP_IPV4 && LWIP_IPV6 1608 if ((IP_IS_V6(addr) && (dns_addrtype != LWIP_DNS_ADDRTYPE_IPV4)) || 1609 (IP_IS_V4(addr) && (dns_addrtype != LWIP_DNS_ADDRTYPE_IPV6))) 1610 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 1611 { 1612 return ERR_OK; 1613 } 1614 } 1615 /* already have this address cached? */ 1616 if (dns_lookup(hostname, hostnamelen, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)) == ERR_OK) { 1617 return ERR_OK; 1618 } 1619 #if LWIP_IPV4 && LWIP_IPV6 1620 if ((dns_addrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) || (dns_addrtype == LWIP_DNS_ADDRTYPE_IPV6_IPV4)) { 1621 /* fallback to 2nd IP type and try again to lookup */ 1622 u8_t fallback; 1623 if (dns_addrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) { 1624 fallback = LWIP_DNS_ADDRTYPE_IPV6; 1625 } else { 1626 fallback = LWIP_DNS_ADDRTYPE_IPV4; 1627 } 1628 if (dns_lookup(hostname, hostnamelen, addr LWIP_DNS_ADDRTYPE_ARG(fallback)) == ERR_OK) { 1629 return ERR_OK; 1630 } 1631 } 1632 #else /* LWIP_IPV4 && LWIP_IPV6 */ 1633 LWIP_UNUSED_ARG(dns_addrtype); 1634 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 1635 1636 #if LWIP_DNS_SUPPORT_MDNS_QUERIES 1637 if (strstr(hostname, ".local") == &hostname[hostnamelen] - 6) { 1638 is_mdns = 1; 1639 } else { 1640 is_mdns = 0; 1641 } 1642 1643 if (!is_mdns) 1644 #endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */ 1645 { 1646 /* prevent calling found callback if no server is set, return error instead */ 1647 if (ip_addr_isany_val(dns_servers[0])) { 1648 return ERR_VAL; 1649 } 1650 } 1651 1652 /* queue query with specified callback */ 1653 return dns_enqueue(hostname, hostnamelen, found, callback_arg LWIP_DNS_ADDRTYPE_ARG(dns_addrtype) 1654 LWIP_DNS_ISMDNS_ARG(is_mdns)); 1655 } 1656 1657 #endif /* LWIP_DNS */ 1658