xref: /btstack/3rd-party/lwip/core/src/core/dns.c (revision 97dc5e692c7d94a280158af58036a0efee5b0e56)
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