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 105static 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. */ 189struct 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. */ 199struct 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 */ 212typedef 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 */ 220struct 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 */ 243struct 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 */ 261static 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 */ 274DNS_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 279static void dns_init_local(void); 280static err_t dns_lookup_local(const char *hostname, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype)); 281#endif /* DNS_LOCAL_HOSTLIST */ 282 283 284/* forward declarations */ 285static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port); 286static void dns_check_entries(void); 287static void dns_call_found(u8_t idx, ip_addr_t *addr); 288 289/*----------------------------------------------------------------------------- 290 * Globals 291 *----------------------------------------------------------------------------*/ 292 293/* DNS variables */ 294static struct udp_pcb *dns_pcbs[DNS_MAX_SOURCE_PORTS]; 295#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) 296static u8_t dns_last_pcb_idx; 297#endif 298static u8_t dns_seqno; 299static struct dns_table_entry dns_table[DNS_TABLE_SIZE]; 300static struct dns_req_entry dns_requests[DNS_MAX_REQUESTS]; 301static ip_addr_t dns_servers[DNS_MAX_SERVERS]; 302 303#if LWIP_IPV4 304const ip_addr_t dns_mquery_v4group = DNS_MQUERY_IPV4_GROUP_INIT; 305#endif /* LWIP_IPV4 */ 306#if LWIP_IPV6 307const 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 */ 314void 315dns_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 */ 360void 361dns_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 */ 380const ip_addr_t * 381dns_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 */ 394void 395dns_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 402static void 403dns_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 */ 439size_t 440dns_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 */ 476err_t 477dns_local_lookup(const char *hostname, ip_addr_t *addr, u8_t dns_addrtype) 478{ 479 LWIP_UNUSED_ARG(dns_addrtype); 480 return dns_lookup_local(hostname, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)); 481} 482 483/* Internal implementation for dns_local_lookup and dns_lookup */ 484static err_t 485dns_lookup_local(const char *hostname, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype)) 486{ 487#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC 488 struct local_hostlist_entry *entry = local_hostlist_dynamic; 489 while (entry != NULL) { 490 if ((lwip_stricmp(entry->name, hostname) == 0) && 491 LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, entry->addr)) { 492 if (addr) { 493 ip_addr_copy(*addr, entry->addr); 494 } 495 return ERR_OK; 496 } 497 entry = entry->next; 498 } 499#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ 500 size_t i; 501 for (i = 0; i < LWIP_ARRAYSIZE(local_hostlist_static); i++) { 502 if ((lwip_stricmp(local_hostlist_static[i].name, hostname) == 0) && 503 LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, local_hostlist_static[i].addr)) { 504 if (addr) { 505 ip_addr_copy(*addr, local_hostlist_static[i].addr); 506 } 507 return ERR_OK; 508 } 509 } 510#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ 511 return ERR_ARG; 512} 513 514#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC 515/** 516 * @ingroup dns 517 * Remove all entries from the local host-list for a specific hostname 518 * and/or IP address 519 * 520 * @param hostname hostname for which entries shall be removed from the local 521 * host-list 522 * @param addr address for which entries shall be removed from the local host-list 523 * @return the number of removed entries 524 */ 525int 526dns_local_removehost(const char *hostname, const ip_addr_t *addr) 527{ 528 int removed = 0; 529 struct local_hostlist_entry *entry = local_hostlist_dynamic; 530 struct local_hostlist_entry *last_entry = NULL; 531 while (entry != NULL) { 532 if (((hostname == NULL) || !lwip_stricmp(entry->name, hostname)) && 533 ((addr == NULL) || ip_addr_cmp(&entry->addr, addr))) { 534 struct local_hostlist_entry *free_entry; 535 if (last_entry != NULL) { 536 last_entry->next = entry->next; 537 } else { 538 local_hostlist_dynamic = entry->next; 539 } 540 free_entry = entry; 541 entry = entry->next; 542 memp_free(MEMP_LOCALHOSTLIST, free_entry); 543 removed++; 544 } else { 545 last_entry = entry; 546 entry = entry->next; 547 } 548 } 549 return removed; 550} 551 552/** 553 * @ingroup dns 554 * Add a hostname/IP address pair to the local host-list. 555 * Duplicates are not checked. 556 * 557 * @param hostname hostname of the new entry 558 * @param addr IP address of the new entry 559 * @return ERR_OK if succeeded or ERR_MEM on memory error 560 */ 561err_t 562dns_local_addhost(const char *hostname, const ip_addr_t *addr) 563{ 564 struct local_hostlist_entry *entry; 565 size_t namelen; 566 char *entry_name; 567 LWIP_ASSERT("invalid host name (NULL)", hostname != NULL); 568 namelen = strlen(hostname); 569 LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN); 570 entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST); 571 if (entry == NULL) { 572 return ERR_MEM; 573 } 574 entry_name = (char *)entry + sizeof(struct local_hostlist_entry); 575 MEMCPY(entry_name, hostname, namelen); 576 entry_name[namelen] = 0; 577 entry->name = entry_name; 578 ip_addr_copy(entry->addr, *addr); 579 entry->next = local_hostlist_dynamic; 580 local_hostlist_dynamic = entry; 581 return ERR_OK; 582} 583#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC*/ 584#endif /* DNS_LOCAL_HOSTLIST */ 585 586/** 587 * @ingroup dns 588 * Look up a hostname in the array of known hostnames. 589 * 590 * @note This function only looks in the internal array of known 591 * hostnames, it does not send out a query for the hostname if none 592 * was found. The function dns_enqueue() can be used to send a query 593 * for a hostname. 594 * 595 * @param name the hostname to look up 596 * @param addr the hostname's IP address, as u32_t (instead of ip_addr_t to 597 * better check for failure: != IPADDR_NONE) or IPADDR_NONE if the hostname 598 * was not found in the cached dns_table. 599 * @return ERR_OK if found, ERR_ARG if not found 600 */ 601static err_t 602dns_lookup(const char *name, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype)) 603{ 604 u8_t i; 605#if DNS_LOCAL_HOSTLIST 606 if (dns_lookup_local(name, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)) == ERR_OK) { 607 return ERR_OK; 608 } 609#endif /* DNS_LOCAL_HOSTLIST */ 610#ifdef DNS_LOOKUP_LOCAL_EXTERN 611 if (DNS_LOOKUP_LOCAL_EXTERN(name, addr, LWIP_DNS_ADDRTYPE_ARG_OR_ZERO(dns_addrtype)) == ERR_OK) { 612 return ERR_OK; 613 } 614#endif /* DNS_LOOKUP_LOCAL_EXTERN */ 615 616 /* Walk through name list, return entry if found. If not, return NULL. */ 617 for (i = 0; i < DNS_TABLE_SIZE; ++i) { 618 if ((dns_table[i].state == DNS_STATE_DONE) && 619 (lwip_strnicmp(name, dns_table[i].name, sizeof(dns_table[i].name)) == 0) && 620 LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, dns_table[i].ipaddr)) { 621 LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name)); 622 ip_addr_debug_print_val(DNS_DEBUG, dns_table[i].ipaddr); 623 LWIP_DEBUGF(DNS_DEBUG, ("\n")); 624 if (addr) { 625 ip_addr_copy(*addr, dns_table[i].ipaddr); 626 } 627 return ERR_OK; 628 } 629 } 630 631 return ERR_ARG; 632} 633 634/** 635 * Compare the "dotted" name "query" with the encoded name "response" 636 * to make sure an answer from the DNS server matches the current dns_table 637 * entry (otherwise, answers might arrive late for hostname not on the list 638 * any more). 639 * 640 * For now, this function compares case-insensitive to cope with all kinds of 641 * servers. This also means that "dns 0x20 bit encoding" must be checked 642 * externally, if we want to implement it. 643 * Currently, the request is sent exactly as passed in by he user request. 644 * 645 * @param query hostname (not encoded) from the dns_table 646 * @param p pbuf containing the encoded hostname in the DNS response 647 * @param start_offset offset into p where the name starts 648 * @return 0xFFFF: names differ, other: names equal -> offset behind name 649 */ 650static u16_t 651dns_compare_name(const char *query, struct pbuf *p, u16_t start_offset) 652{ 653 int n; 654 u16_t response_offset = start_offset; 655 656 do { 657 n = pbuf_try_get_at(p, response_offset); 658 if ((n < 0) || (response_offset == 0xFFFF)) { 659 /* error or overflow */ 660 return 0xFFFF; 661 } 662 response_offset++; 663 /** @see RFC 1035 - 4.1.4. Message compression */ 664 if ((n & 0xc0) == 0xc0) { 665 /* Compressed name: cannot be equal since we don't send them */ 666 return 0xFFFF; 667 } else { 668 /* Not compressed name */ 669 while (n > 0) { 670 int c = pbuf_try_get_at(p, response_offset); 671 if (c < 0) { 672 return 0xFFFF; 673 } 674 if (lwip_tolower((*query)) != lwip_tolower((u8_t)c)) { 675 return 0xFFFF; 676 } 677 if (response_offset == 0xFFFF) { 678 /* would overflow */ 679 return 0xFFFF; 680 } 681 response_offset++; 682 ++query; 683 --n; 684 } 685 ++query; 686 } 687 n = pbuf_try_get_at(p, response_offset); 688 if (n < 0) { 689 return 0xFFFF; 690 } 691 } while (n != 0); 692 693 if (response_offset == 0xFFFF) { 694 /* would overflow */ 695 return 0xFFFF; 696 } 697 return (u16_t)(response_offset + 1); 698} 699 700/** 701 * Walk through a compact encoded DNS name and return the end of the name. 702 * 703 * @param p pbuf containing the name 704 * @param query_idx start index into p pointing to encoded DNS name in the DNS server response 705 * @return index to end of the name 706 */ 707static u16_t 708dns_skip_name(struct pbuf *p, u16_t query_idx) 709{ 710 int n; 711 u16_t offset = query_idx; 712 713 do { 714 n = pbuf_try_get_at(p, offset++); 715 if ((n < 0) || (offset == 0)) { 716 return 0xFFFF; 717 } 718 /** @see RFC 1035 - 4.1.4. Message compression */ 719 if ((n & 0xc0) == 0xc0) { 720 /* Compressed name: since we only want to skip it (not check it), stop here */ 721 break; 722 } else { 723 /* Not compressed name */ 724 if (offset + n >= p->tot_len) { 725 return 0xFFFF; 726 } 727 offset = (u16_t)(offset + n); 728 } 729 n = pbuf_try_get_at(p, offset); 730 if (n < 0) { 731 return 0xFFFF; 732 } 733 } while (n != 0); 734 735 if (offset == 0xFFFF) { 736 return 0xFFFF; 737 } 738 return (u16_t)(offset + 1); 739} 740 741/** 742 * Send a DNS query packet. 743 * 744 * @param idx the DNS table entry index for which to send a request 745 * @return ERR_OK if packet is sent; an err_t indicating the problem otherwise 746 */ 747static err_t 748dns_send(u8_t idx) 749{ 750 err_t err; 751 struct dns_hdr hdr; 752 struct dns_query qry; 753 struct pbuf *p; 754 u16_t query_idx, copy_len; 755 const char *hostname, *hostname_part; 756 u8_t n; 757 u8_t pcb_idx; 758 struct dns_table_entry *entry = &dns_table[idx]; 759 760 LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n", 761 (u16_t)(entry->server_idx), entry->name)); 762 LWIP_ASSERT("dns server out of array", entry->server_idx < DNS_MAX_SERVERS); 763 if (ip_addr_isany_val(dns_servers[entry->server_idx]) 764#if LWIP_DNS_SUPPORT_MDNS_QUERIES 765 && !entry->is_mdns 766#endif 767 ) { 768 /* DNS server not valid anymore, e.g. PPP netif has been shut down */ 769 /* call specified callback function if provided */ 770 dns_call_found(idx, NULL); 771 /* flush this entry */ 772 entry->state = DNS_STATE_UNUSED; 773 return ERR_OK; 774 } 775 776 /* if here, we have either a new query or a retry on a previous query to process */ 777 p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(SIZEOF_DNS_HDR + strlen(entry->name) + 2 + 778 SIZEOF_DNS_QUERY), PBUF_RAM); 779 if (p != NULL) { 780 const ip_addr_t *dst; 781 u16_t dst_port; 782 /* fill dns header */ 783 memset(&hdr, 0, SIZEOF_DNS_HDR); 784 hdr.id = lwip_htons(entry->txid); 785 hdr.flags1 = DNS_FLAG1_RD; 786 hdr.numquestions = PP_HTONS(1); 787 pbuf_take(p, &hdr, SIZEOF_DNS_HDR); 788 hostname = entry->name; 789 --hostname; 790 791 /* convert hostname into suitable query format. */ 792 query_idx = SIZEOF_DNS_HDR; 793 do { 794 ++hostname; 795 hostname_part = hostname; 796 for (n = 0; *hostname != '.' && *hostname != 0; ++hostname) { 797 ++n; 798 } 799 copy_len = (u16_t)(hostname - hostname_part); 800 if (query_idx + n + 1 > 0xFFFF) { 801 /* u16_t overflow */ 802 goto overflow_return; 803 } 804 pbuf_put_at(p, query_idx, n); 805 pbuf_take_at(p, hostname_part, copy_len, (u16_t)(query_idx + 1)); 806 query_idx = (u16_t)(query_idx + n + 1); 807 } while (*hostname != 0); 808 pbuf_put_at(p, query_idx, 0); 809 query_idx++; 810 811 /* fill dns query */ 812 if (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype)) { 813 qry.type = PP_HTONS(DNS_RRTYPE_AAAA); 814 } else { 815 qry.type = PP_HTONS(DNS_RRTYPE_A); 816 } 817 qry.cls = PP_HTONS(DNS_RRCLASS_IN); 818 pbuf_take_at(p, &qry, SIZEOF_DNS_QUERY, query_idx); 819 820#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) 821 pcb_idx = entry->pcb_idx; 822#else 823 pcb_idx = 0; 824#endif 825 /* send dns packet */ 826 LWIP_DEBUGF(DNS_DEBUG, ("sending DNS request ID %d for name \"%s\" to server %d\r\n", 827 entry->txid, entry->name, entry->server_idx)); 828#if LWIP_DNS_SUPPORT_MDNS_QUERIES 829 if (entry->is_mdns) { 830 dst_port = DNS_MQUERY_PORT; 831#if LWIP_IPV6 832 if (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype)) { 833 dst = &dns_mquery_v6group; 834 } 835#endif 836#if LWIP_IPV4 && LWIP_IPV6 837 else 838#endif 839#if LWIP_IPV4 840 { 841 dst = &dns_mquery_v4group; 842 } 843#endif 844 } else 845#endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */ 846 { 847 dst_port = DNS_SERVER_PORT; 848 dst = &dns_servers[entry->server_idx]; 849 } 850 err = udp_sendto(dns_pcbs[pcb_idx], p, dst, dst_port); 851 852 /* free pbuf */ 853 pbuf_free(p); 854 } else { 855 err = ERR_MEM; 856 } 857 858 return err; 859overflow_return: 860 pbuf_free(p); 861 return ERR_VAL; 862} 863 864#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) 865static struct udp_pcb * 866dns_alloc_random_port(void) 867{ 868 err_t err; 869 struct udp_pcb *pcb; 870 871 pcb = udp_new_ip_type(IPADDR_TYPE_ANY); 872 if (pcb == NULL) { 873 /* out of memory, have to reuse an existing pcb */ 874 return NULL; 875 } 876 do { 877 u16_t port = (u16_t)DNS_RAND_TXID(); 878 if (DNS_PORT_ALLOWED(port)) { 879 err = udp_bind(pcb, IP_ANY_TYPE, port); 880 } else { 881 /* this port is not allowed, try again */ 882 err = ERR_USE; 883 } 884 } while (err == ERR_USE); 885 if (err != ERR_OK) { 886 udp_remove(pcb); 887 return NULL; 888 } 889 udp_recv(pcb, dns_recv, NULL); 890 return pcb; 891} 892 893/** 894 * dns_alloc_pcb() - allocates a new pcb (or reuses an existing one) to be used 895 * for sending a request 896 * 897 * @return an index into dns_pcbs 898 */ 899static u8_t 900dns_alloc_pcb(void) 901{ 902 u8_t i; 903 u8_t idx; 904 905 for (i = 0; i < DNS_MAX_SOURCE_PORTS; i++) { 906 if (dns_pcbs[i] == NULL) { 907 break; 908 } 909 } 910 if (i < DNS_MAX_SOURCE_PORTS) { 911 dns_pcbs[i] = dns_alloc_random_port(); 912 if (dns_pcbs[i] != NULL) { 913 /* succeeded */ 914 dns_last_pcb_idx = i; 915 return i; 916 } 917 } 918 /* if we come here, creating a new UDP pcb failed, so we have to use 919 an already existing one (so overflow is no issue) */ 920 for (i = 0, idx = (u8_t)(dns_last_pcb_idx + 1); i < DNS_MAX_SOURCE_PORTS; i++, idx++) { 921 if (idx >= DNS_MAX_SOURCE_PORTS) { 922 idx = 0; 923 } 924 if (dns_pcbs[idx] != NULL) { 925 dns_last_pcb_idx = idx; 926 return idx; 927 } 928 } 929 return DNS_MAX_SOURCE_PORTS; 930} 931#endif /* ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) */ 932 933/** 934 * dns_call_found() - call the found callback and check if there are duplicate 935 * entries for the given hostname. If there are any, their found callback will 936 * be called and they will be removed. 937 * 938 * @param idx dns table index of the entry that is resolved or removed 939 * @param addr IP address for the hostname (or NULL on error or memory shortage) 940 */ 941static void 942dns_call_found(u8_t idx, ip_addr_t *addr) 943{ 944#if ((LWIP_DNS_SECURE & (LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING | LWIP_DNS_SECURE_RAND_SRC_PORT)) != 0) 945 u8_t i; 946#endif 947 948#if LWIP_IPV4 && LWIP_IPV6 949 if (addr != NULL) { 950 /* check that address type matches the request and adapt the table entry */ 951 if (IP_IS_V6_VAL(*addr)) { 952 LWIP_ASSERT("invalid response", LWIP_DNS_ADDRTYPE_IS_IPV6(dns_table[idx].reqaddrtype)); 953 dns_table[idx].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV6; 954 } else { 955 LWIP_ASSERT("invalid response", !LWIP_DNS_ADDRTYPE_IS_IPV6(dns_table[idx].reqaddrtype)); 956 dns_table[idx].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV4; 957 } 958 } 959#endif /* LWIP_IPV4 && LWIP_IPV6 */ 960 961#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0) 962 for (i = 0; i < DNS_MAX_REQUESTS; i++) { 963 if (dns_requests[i].found && (dns_requests[i].dns_table_idx == idx)) { 964 (*dns_requests[i].found)(dns_table[idx].name, addr, dns_requests[i].arg); 965 /* flush this entry */ 966 dns_requests[i].found = NULL; 967 } 968 } 969#else 970 if (dns_requests[idx].found) { 971 (*dns_requests[idx].found)(dns_table[idx].name, addr, dns_requests[idx].arg); 972 } 973 dns_requests[idx].found = NULL; 974#endif 975#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) 976 /* close the pcb used unless other request are using it */ 977 for (i = 0; i < DNS_MAX_REQUESTS; i++) { 978 if (i == idx) { 979 continue; /* only check other requests */ 980 } 981 if (dns_table[i].state == DNS_STATE_ASKING) { 982 if (dns_table[i].pcb_idx == dns_table[idx].pcb_idx) { 983 /* another request is still using the same pcb */ 984 dns_table[idx].pcb_idx = DNS_MAX_SOURCE_PORTS; 985 break; 986 } 987 } 988 } 989 if (dns_table[idx].pcb_idx < DNS_MAX_SOURCE_PORTS) { 990 /* if we come here, the pcb is not used any more and can be removed */ 991 udp_remove(dns_pcbs[dns_table[idx].pcb_idx]); 992 dns_pcbs[dns_table[idx].pcb_idx] = NULL; 993 dns_table[idx].pcb_idx = DNS_MAX_SOURCE_PORTS; 994 } 995#endif 996} 997 998/* Create a query transmission ID that is unique for all outstanding queries */ 999static u16_t 1000dns_create_txid(void) 1001{ 1002 u16_t txid; 1003 u8_t i; 1004 1005again: 1006 txid = (u16_t)DNS_RAND_TXID(); 1007 1008 /* check whether the ID is unique */ 1009 for (i = 0; i < DNS_TABLE_SIZE; i++) { 1010 if ((dns_table[i].state == DNS_STATE_ASKING) && 1011 (dns_table[i].txid == txid)) { 1012 /* ID already used by another pending query */ 1013 goto again; 1014 } 1015 } 1016 1017 return txid; 1018} 1019 1020/** 1021 * Check whether there are other backup DNS servers available to try 1022 */ 1023static u8_t 1024dns_backupserver_available(struct dns_table_entry *pentry) 1025{ 1026 u8_t ret = 0; 1027 1028 if (pentry) { 1029 if ((pentry->server_idx + 1 < DNS_MAX_SERVERS) && !ip_addr_isany_val(dns_servers[pentry->server_idx + 1])) { 1030 ret = 1; 1031 } 1032 } 1033 1034 return ret; 1035} 1036 1037/** 1038 * dns_check_entry() - see if entry has not yet been queried and, if so, sends out a query. 1039 * Check an entry in the dns_table: 1040 * - send out query for new entries 1041 * - retry old pending entries on timeout (also with different servers) 1042 * - remove completed entries from the table if their TTL has expired 1043 * 1044 * @param i index of the dns_table entry to check 1045 */ 1046static void 1047dns_check_entry(u8_t i) 1048{ 1049 err_t err; 1050 struct dns_table_entry *entry = &dns_table[i]; 1051 1052 LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE); 1053 1054 switch (entry->state) { 1055 case DNS_STATE_NEW: 1056 /* initialize new entry */ 1057 entry->txid = dns_create_txid(); 1058 entry->state = DNS_STATE_ASKING; 1059 entry->server_idx = 0; 1060 entry->tmr = 1; 1061 entry->retries = 0; 1062 1063 /* send DNS packet for this entry */ 1064 err = dns_send(i); 1065 if (err != ERR_OK) { 1066 LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING, 1067 ("dns_send returned error: %s\n", lwip_strerr(err))); 1068 } 1069 break; 1070 case DNS_STATE_ASKING: 1071 if (--entry->tmr == 0) { 1072 if (++entry->retries == DNS_MAX_RETRIES) { 1073 if (dns_backupserver_available(entry) 1074#if LWIP_DNS_SUPPORT_MDNS_QUERIES 1075 && !entry->is_mdns 1076#endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */ 1077 ) { 1078 /* change of server */ 1079 entry->server_idx++; 1080 entry->tmr = 1; 1081 entry->retries = 0; 1082 } else { 1083 LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": timeout\n", entry->name)); 1084 /* call specified callback function if provided */ 1085 dns_call_found(i, NULL); 1086 /* flush this entry */ 1087 entry->state = DNS_STATE_UNUSED; 1088 break; 1089 } 1090 } else { 1091 /* wait longer for the next retry */ 1092 entry->tmr = entry->retries; 1093 } 1094 1095 /* send DNS packet for this entry */ 1096 err = dns_send(i); 1097 if (err != ERR_OK) { 1098 LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING, 1099 ("dns_send returned error: %s\n", lwip_strerr(err))); 1100 } 1101 } 1102 break; 1103 case DNS_STATE_DONE: 1104 /* if the time to live is nul */ 1105 if ((entry->ttl == 0) || (--entry->ttl == 0)) { 1106 LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": flush\n", entry->name)); 1107 /* flush this entry, there cannot be any related pending entries in this state */ 1108 entry->state = DNS_STATE_UNUSED; 1109 } 1110 break; 1111 case DNS_STATE_UNUSED: 1112 /* nothing to do */ 1113 break; 1114 default: 1115 LWIP_ASSERT("unknown dns_table entry state:", 0); 1116 break; 1117 } 1118} 1119 1120/** 1121 * Call dns_check_entry for each entry in dns_table - check all entries. 1122 */ 1123static void 1124dns_check_entries(void) 1125{ 1126 u8_t i; 1127 1128 for (i = 0; i < DNS_TABLE_SIZE; ++i) { 1129 dns_check_entry(i); 1130 } 1131} 1132 1133/** 1134 * Save TTL and call dns_call_found for correct response. 1135 */ 1136static void 1137dns_correct_response(u8_t idx, u32_t ttl) 1138{ 1139 struct dns_table_entry *entry = &dns_table[idx]; 1140 1141 entry->state = DNS_STATE_DONE; 1142 1143 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", entry->name)); 1144 ip_addr_debug_print_val(DNS_DEBUG, entry->ipaddr); 1145 LWIP_DEBUGF(DNS_DEBUG, ("\n")); 1146 1147 /* read the answer resource record's TTL, and maximize it if needed */ 1148 entry->ttl = ttl; 1149 if (entry->ttl > DNS_MAX_TTL) { 1150 entry->ttl = DNS_MAX_TTL; 1151 } 1152 dns_call_found(idx, &entry->ipaddr); 1153 1154 if (entry->ttl == 0) { 1155 /* RFC 883, page 29: "Zero values are 1156 interpreted to mean that the RR can only be used for the 1157 transaction in progress, and should not be cached." 1158 -> flush this entry now */ 1159 /* entry reused during callback? */ 1160 if (entry->state == DNS_STATE_DONE) { 1161 entry->state = DNS_STATE_UNUSED; 1162 } 1163 } 1164} 1165 1166/** 1167 * Receive input function for DNS response packets arriving for the dns UDP pcb. 1168 */ 1169static void 1170dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) 1171{ 1172 u8_t i; 1173 u16_t txid; 1174 u16_t res_idx; 1175 struct dns_hdr hdr; 1176 struct dns_answer ans; 1177 struct dns_query qry; 1178 u16_t nquestions, nanswers; 1179 1180 LWIP_UNUSED_ARG(arg); 1181 LWIP_UNUSED_ARG(pcb); 1182 LWIP_UNUSED_ARG(port); 1183 1184 /* is the dns message big enough ? */ 1185 if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY)) { 1186 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n")); 1187 /* free pbuf and return */ 1188 goto ignore_packet; 1189 } 1190 1191 /* copy dns payload inside static buffer for processing */ 1192 if (pbuf_copy_partial(p, &hdr, SIZEOF_DNS_HDR, 0) == SIZEOF_DNS_HDR) { 1193 /* Match the ID in the DNS header with the name table. */ 1194 txid = lwip_htons(hdr.id); 1195 for (i = 0; i < DNS_TABLE_SIZE; i++) { 1196 struct dns_table_entry *entry = &dns_table[i]; 1197 if ((entry->state == DNS_STATE_ASKING) && 1198 (entry->txid == txid)) { 1199 1200 /* We only care about the question(s) and the answers. The authrr 1201 and the extrarr are simply discarded. */ 1202 nquestions = lwip_htons(hdr.numquestions); 1203 nanswers = lwip_htons(hdr.numanswers); 1204 1205 /* Check for correct response. */ 1206 if ((hdr.flags1 & DNS_FLAG1_RESPONSE) == 0) { 1207 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": not a response\n", entry->name)); 1208 goto ignore_packet; /* ignore this packet */ 1209 } 1210 if (nquestions != 1) { 1211 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", entry->name)); 1212 goto ignore_packet; /* ignore this packet */ 1213 } 1214 1215#if LWIP_DNS_SUPPORT_MDNS_QUERIES 1216 if (!entry->is_mdns) 1217#endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */ 1218 { 1219 /* Check whether response comes from the same network address to which the 1220 question was sent. (RFC 5452) */ 1221 if (!ip_addr_cmp(addr, &dns_servers[entry->server_idx])) { 1222 goto ignore_packet; /* ignore this packet */ 1223 } 1224 } 1225 1226 /* Check if the name in the "question" part match with the name in the entry and 1227 skip it if equal. */ 1228 res_idx = dns_compare_name(entry->name, p, SIZEOF_DNS_HDR); 1229 if (res_idx == 0xFFFF) { 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 /* check if "question" part matches the request */ 1235 if (pbuf_copy_partial(p, &qry, SIZEOF_DNS_QUERY, res_idx) != SIZEOF_DNS_QUERY) { 1236 goto ignore_packet; /* ignore this packet */ 1237 } 1238 if ((qry.cls != PP_HTONS(DNS_RRCLASS_IN)) || 1239 (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype) && (qry.type != PP_HTONS(DNS_RRTYPE_AAAA))) || 1240 (!LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype) && (qry.type != PP_HTONS(DNS_RRTYPE_A)))) { 1241 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", entry->name)); 1242 goto ignore_packet; /* ignore this packet */ 1243 } 1244 /* skip the rest of the "question" part */ 1245 if (res_idx + SIZEOF_DNS_QUERY > 0xFFFF) { 1246 goto ignore_packet; 1247 } 1248 res_idx = (u16_t)(res_idx + SIZEOF_DNS_QUERY); 1249 1250 /* Check for error. If so, call callback to inform. */ 1251 if (hdr.flags2 & DNS_FLAG2_ERR_MASK) { 1252 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in flags\n", entry->name)); 1253 1254 /* if there is another backup DNS server to try 1255 * then don't stop the DNS request 1256 */ 1257 if (dns_backupserver_available(entry)) { 1258 /* avoid retrying the same server */ 1259 entry->retries = DNS_MAX_RETRIES-1; 1260 entry->tmr = 1; 1261 1262 /* contact next available server for this entry */ 1263 dns_check_entry(i); 1264 1265 goto ignore_packet; 1266 } 1267 } else { 1268 while ((nanswers > 0) && (res_idx < p->tot_len)) { 1269 /* skip answer resource record's host name */ 1270 res_idx = dns_skip_name(p, res_idx); 1271 if (res_idx == 0xFFFF) { 1272 goto ignore_packet; /* ignore this packet */ 1273 } 1274 1275 /* Check for IP address type and Internet class. Others are discarded. */ 1276 if (pbuf_copy_partial(p, &ans, SIZEOF_DNS_ANSWER, res_idx) != SIZEOF_DNS_ANSWER) { 1277 goto ignore_packet; /* ignore this packet */ 1278 } 1279 if (res_idx + SIZEOF_DNS_ANSWER > 0xFFFF) { 1280 goto ignore_packet; 1281 } 1282 res_idx = (u16_t)(res_idx + SIZEOF_DNS_ANSWER); 1283 1284 if (ans.cls == PP_HTONS(DNS_RRCLASS_IN)) { 1285#if LWIP_IPV4 1286 if ((ans.type == PP_HTONS(DNS_RRTYPE_A)) && (ans.len == PP_HTONS(sizeof(ip4_addr_t)))) { 1287#if LWIP_IPV4 && LWIP_IPV6 1288 if (!LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype)) 1289#endif /* LWIP_IPV4 && LWIP_IPV6 */ 1290 { 1291 ip4_addr_t ip4addr; 1292 /* read the IP address after answer resource record's header */ 1293 if (pbuf_copy_partial(p, &ip4addr, sizeof(ip4_addr_t), res_idx) != sizeof(ip4_addr_t)) { 1294 goto ignore_packet; /* ignore this packet */ 1295 } 1296 ip_addr_copy_from_ip4(dns_table[i].ipaddr, ip4addr); 1297 pbuf_free(p); 1298 /* handle correct response */ 1299 dns_correct_response(i, lwip_ntohl(ans.ttl)); 1300 return; 1301 } 1302 } 1303#endif /* LWIP_IPV4 */ 1304#if LWIP_IPV6 1305 if ((ans.type == PP_HTONS(DNS_RRTYPE_AAAA)) && (ans.len == PP_HTONS(sizeof(ip6_addr_p_t)))) { 1306#if LWIP_IPV4 && LWIP_IPV6 1307 if (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype)) 1308#endif /* LWIP_IPV4 && LWIP_IPV6 */ 1309 { 1310 ip6_addr_p_t ip6addr; 1311 /* read the IP address after answer resource record's header */ 1312 if (pbuf_copy_partial(p, &ip6addr, sizeof(ip6_addr_p_t), res_idx) != sizeof(ip6_addr_p_t)) { 1313 goto ignore_packet; /* ignore this packet */ 1314 } 1315 /* @todo: scope ip6addr? Might be required for link-local addresses at least? */ 1316 ip_addr_copy_from_ip6_packed(dns_table[i].ipaddr, ip6addr); 1317 pbuf_free(p); 1318 /* handle correct response */ 1319 dns_correct_response(i, lwip_ntohl(ans.ttl)); 1320 return; 1321 } 1322 } 1323#endif /* LWIP_IPV6 */ 1324 } 1325 /* skip this answer */ 1326 if ((int)(res_idx + lwip_htons(ans.len)) > 0xFFFF) { 1327 goto ignore_packet; /* ignore this packet */ 1328 } 1329 res_idx = (u16_t)(res_idx + lwip_htons(ans.len)); 1330 --nanswers; 1331 } 1332#if LWIP_IPV4 && LWIP_IPV6 1333 if ((entry->reqaddrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) || 1334 (entry->reqaddrtype == LWIP_DNS_ADDRTYPE_IPV6_IPV4)) { 1335 if (entry->reqaddrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) { 1336 /* IPv4 failed, try IPv6 */ 1337 dns_table[i].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV6; 1338 } else { 1339 /* IPv6 failed, try IPv4 */ 1340 dns_table[i].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV4; 1341 } 1342 pbuf_free(p); 1343 dns_table[i].state = DNS_STATE_NEW; 1344 dns_check_entry(i); 1345 return; 1346 } 1347#endif /* LWIP_IPV4 && LWIP_IPV6 */ 1348 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in response\n", entry->name)); 1349 } 1350 /* call callback to indicate error, clean up memory and return */ 1351 pbuf_free(p); 1352 dns_call_found(i, NULL); 1353 dns_table[i].state = DNS_STATE_UNUSED; 1354 return; 1355 } 1356 } 1357 } 1358 1359ignore_packet: 1360 /* deallocate memory and return */ 1361 pbuf_free(p); 1362 return; 1363} 1364 1365/** 1366 * Queues a new hostname to resolve and sends out a DNS query for that hostname 1367 * 1368 * @param name the hostname that is to be queried 1369 * @param hostnamelen length of the hostname 1370 * @param found a callback function to be called on success, failure or timeout 1371 * @param callback_arg argument to pass to the callback function 1372 * @return err_t return code. 1373 */ 1374static err_t 1375dns_enqueue(const char *name, size_t hostnamelen, dns_found_callback found, 1376 void *callback_arg LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype) LWIP_DNS_ISMDNS_ARG(u8_t is_mdns)) 1377{ 1378 u8_t i; 1379 u8_t lseq, lseqi; 1380 struct dns_table_entry *entry = NULL; 1381 size_t namelen; 1382 struct dns_req_entry *req; 1383 1384#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0) 1385 u8_t r; 1386 /* check for duplicate entries */ 1387 for (i = 0; i < DNS_TABLE_SIZE; i++) { 1388 if ((dns_table[i].state == DNS_STATE_ASKING) && 1389 (lwip_strnicmp(name, dns_table[i].name, sizeof(dns_table[i].name)) == 0)) { 1390#if LWIP_IPV4 && LWIP_IPV6 1391 if (dns_table[i].reqaddrtype != dns_addrtype) { 1392 /* requested address types don't match 1393 this can lead to 2 concurrent requests, but mixing the address types 1394 for the same host should not be that common */ 1395 continue; 1396 } 1397#endif /* LWIP_IPV4 && LWIP_IPV6 */ 1398 /* this is a duplicate entry, find a free request entry */ 1399 for (r = 0; r < DNS_MAX_REQUESTS; r++) { 1400 if (dns_requests[r].found == 0) { 1401 dns_requests[r].found = found; 1402 dns_requests[r].arg = callback_arg; 1403 dns_requests[r].dns_table_idx = i; 1404 LWIP_DNS_SET_ADDRTYPE(dns_requests[r].reqaddrtype, dns_addrtype); 1405 LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": duplicate request\n", name)); 1406 return ERR_INPROGRESS; 1407 } 1408 } 1409 } 1410 } 1411 /* no duplicate entries found */ 1412#endif 1413 1414 /* search an unused entry, or the oldest one */ 1415 lseq = 0; 1416 lseqi = DNS_TABLE_SIZE; 1417 for (i = 0; i < DNS_TABLE_SIZE; ++i) { 1418 entry = &dns_table[i]; 1419 /* is it an unused entry ? */ 1420 if (entry->state == DNS_STATE_UNUSED) { 1421 break; 1422 } 1423 /* check if this is the oldest completed entry */ 1424 if (entry->state == DNS_STATE_DONE) { 1425 u8_t age = (u8_t)(dns_seqno - entry->seqno); 1426 if (age > lseq) { 1427 lseq = age; 1428 lseqi = i; 1429 } 1430 } 1431 } 1432 1433 /* if we don't have found an unused entry, use the oldest completed one */ 1434 if (i == DNS_TABLE_SIZE) { 1435 if ((lseqi >= DNS_TABLE_SIZE) || (dns_table[lseqi].state != DNS_STATE_DONE)) { 1436 /* no entry can be used now, table is full */ 1437 LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS entries table is full\n", name)); 1438 return ERR_MEM; 1439 } else { 1440 /* use the oldest completed one */ 1441 i = lseqi; 1442 entry = &dns_table[i]; 1443 } 1444 } 1445 1446#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0) 1447 /* find a free request entry */ 1448 req = NULL; 1449 for (r = 0; r < DNS_MAX_REQUESTS; r++) { 1450 if (dns_requests[r].found == NULL) { 1451 req = &dns_requests[r]; 1452 break; 1453 } 1454 } 1455 if (req == NULL) { 1456 /* no request entry can be used now, table is full */ 1457 LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS request entries table is full\n", name)); 1458 return ERR_MEM; 1459 } 1460 req->dns_table_idx = i; 1461#else 1462 /* in this configuration, the entry index is the same as the request index */ 1463 req = &dns_requests[i]; 1464#endif 1465 1466 /* use this entry */ 1467 LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS entry %"U16_F"\n", name, (u16_t)(i))); 1468 1469 /* fill the entry */ 1470 entry->state = DNS_STATE_NEW; 1471 entry->seqno = dns_seqno; 1472 LWIP_DNS_SET_ADDRTYPE(entry->reqaddrtype, dns_addrtype); 1473 LWIP_DNS_SET_ADDRTYPE(req->reqaddrtype, dns_addrtype); 1474 req->found = found; 1475 req->arg = callback_arg; 1476 namelen = LWIP_MIN(hostnamelen, DNS_MAX_NAME_LENGTH - 1); 1477 MEMCPY(entry->name, name, namelen); 1478 entry->name[namelen] = 0; 1479 1480#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) 1481 entry->pcb_idx = dns_alloc_pcb(); 1482 if (entry->pcb_idx >= DNS_MAX_SOURCE_PORTS) { 1483 /* failed to get a UDP pcb */ 1484 LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": failed to allocate a pcb\n", name)); 1485 entry->state = DNS_STATE_UNUSED; 1486 req->found = NULL; 1487 return ERR_MEM; 1488 } 1489 LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS pcb %"U16_F"\n", name, (u16_t)(entry->pcb_idx))); 1490#endif 1491 1492#if LWIP_DNS_SUPPORT_MDNS_QUERIES 1493 entry->is_mdns = is_mdns; 1494#endif 1495 1496 dns_seqno++; 1497 1498 /* force to send query without waiting timer */ 1499 dns_check_entry(i); 1500 1501 /* dns query is enqueued */ 1502 return ERR_INPROGRESS; 1503} 1504 1505/** 1506 * @ingroup dns 1507 * Resolve a hostname (string) into an IP address. 1508 * NON-BLOCKING callback version for use with raw API!!! 1509 * 1510 * Returns immediately with one of err_t return codes: 1511 * - ERR_OK if hostname is a valid IP address string or the host 1512 * name is already in the local names table. 1513 * - ERR_INPROGRESS enqueue a request to be sent to the DNS server 1514 * for resolution if no errors are present. 1515 * - ERR_ARG: dns client not initialized or invalid hostname 1516 * 1517 * @param hostname the hostname that is to be queried 1518 * @param addr pointer to a ip_addr_t where to store the address if it is already 1519 * cached in the dns_table (only valid if ERR_OK is returned!) 1520 * @param found a callback function to be called on success, failure or timeout (only if 1521 * ERR_INPROGRESS is returned!) 1522 * @param callback_arg argument to pass to the callback function 1523 * @return a err_t return code. 1524 */ 1525err_t 1526dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found, 1527 void *callback_arg) 1528{ 1529 return dns_gethostbyname_addrtype(hostname, addr, found, callback_arg, LWIP_DNS_ADDRTYPE_DEFAULT); 1530} 1531 1532/** 1533 * @ingroup dns 1534 * Like dns_gethostbyname, but returned address type can be controlled: 1535 * @param hostname the hostname that is to be queried 1536 * @param addr pointer to a ip_addr_t where to store the address if it is already 1537 * cached in the dns_table (only valid if ERR_OK is returned!) 1538 * @param found a callback function to be called on success, failure or timeout (only if 1539 * ERR_INPROGRESS is returned!) 1540 * @param callback_arg argument to pass to the callback function 1541 * @param dns_addrtype - LWIP_DNS_ADDRTYPE_IPV4_IPV6: try to resolve IPv4 first, try IPv6 if IPv4 fails only 1542 * - LWIP_DNS_ADDRTYPE_IPV6_IPV4: try to resolve IPv6 first, try IPv4 if IPv6 fails only 1543 * - LWIP_DNS_ADDRTYPE_IPV4: try to resolve IPv4 only 1544 * - LWIP_DNS_ADDRTYPE_IPV6: try to resolve IPv6 only 1545 */ 1546err_t 1547dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, dns_found_callback found, 1548 void *callback_arg, u8_t dns_addrtype) 1549{ 1550 size_t hostnamelen; 1551#if LWIP_DNS_SUPPORT_MDNS_QUERIES 1552 u8_t is_mdns; 1553#endif 1554 /* not initialized or no valid server yet, or invalid addr pointer 1555 * or invalid hostname or invalid hostname length */ 1556 if ((addr == NULL) || 1557 (!hostname) || (!hostname[0])) { 1558 return ERR_ARG; 1559 } 1560#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) == 0) 1561 if (dns_pcbs[0] == NULL) { 1562 return ERR_ARG; 1563 } 1564#endif 1565 hostnamelen = strlen(hostname); 1566 if (hostnamelen >= DNS_MAX_NAME_LENGTH) { 1567 LWIP_DEBUGF(DNS_DEBUG, ("dns_gethostbyname: name too long to resolve")); 1568 return ERR_ARG; 1569 } 1570 1571 1572#if LWIP_HAVE_LOOPIF 1573 if (strcmp(hostname, "localhost") == 0) { 1574 ip_addr_set_loopback(LWIP_DNS_ADDRTYPE_IS_IPV6(dns_addrtype), addr); 1575 return ERR_OK; 1576 } 1577#endif /* LWIP_HAVE_LOOPIF */ 1578 1579 /* host name already in octet notation? set ip addr and return ERR_OK */ 1580 if (ipaddr_aton(hostname, addr)) { 1581#if LWIP_IPV4 && LWIP_IPV6 1582 if ((IP_IS_V6(addr) && (dns_addrtype != LWIP_DNS_ADDRTYPE_IPV4)) || 1583 (IP_IS_V4(addr) && (dns_addrtype != LWIP_DNS_ADDRTYPE_IPV6))) 1584#endif /* LWIP_IPV4 && LWIP_IPV6 */ 1585 { 1586 return ERR_OK; 1587 } 1588 } 1589 /* already have this address cached? */ 1590 if (dns_lookup(hostname, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)) == ERR_OK) { 1591 return ERR_OK; 1592 } 1593#if LWIP_IPV4 && LWIP_IPV6 1594 if ((dns_addrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) || (dns_addrtype == LWIP_DNS_ADDRTYPE_IPV6_IPV4)) { 1595 /* fallback to 2nd IP type and try again to lookup */ 1596 u8_t fallback; 1597 if (dns_addrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) { 1598 fallback = LWIP_DNS_ADDRTYPE_IPV6; 1599 } else { 1600 fallback = LWIP_DNS_ADDRTYPE_IPV4; 1601 } 1602 if (dns_lookup(hostname, addr LWIP_DNS_ADDRTYPE_ARG(fallback)) == ERR_OK) { 1603 return ERR_OK; 1604 } 1605 } 1606#else /* LWIP_IPV4 && LWIP_IPV6 */ 1607 LWIP_UNUSED_ARG(dns_addrtype); 1608#endif /* LWIP_IPV4 && LWIP_IPV6 */ 1609 1610#if LWIP_DNS_SUPPORT_MDNS_QUERIES 1611 if (strstr(hostname, ".local") == &hostname[hostnamelen] - 6) { 1612 is_mdns = 1; 1613 } else { 1614 is_mdns = 0; 1615 } 1616 1617 if (!is_mdns) 1618#endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */ 1619 { 1620 /* prevent calling found callback if no server is set, return error instead */ 1621 if (ip_addr_isany_val(dns_servers[0])) { 1622 return ERR_VAL; 1623 } 1624 } 1625 1626 /* queue query with specified callback */ 1627 return dns_enqueue(hostname, hostnamelen, found, callback_arg LWIP_DNS_ADDRTYPE_ARG(dns_addrtype) 1628 LWIP_DNS_ISMDNS_ARG(is_mdns)); 1629} 1630 1631#endif /* LWIP_DNS */ 1632