• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "lwip/sys.h"
98 #include "arch/sys_arch.h"
99 #include "lwip/tcpip.h"
100 #include "lwip/netdb.h"
101 
102 #include <string.h>
103 
104 #if LWIP_DNS64 && LWIP_NAT64
105 #include "lwip/nat64.h"
106 #include "lwip/nat64_addr.h"
107 #endif
108 
109 #if LWIP_RIPPLE
110 #include "lwip/lwip_rpl.h"
111 #endif
112 
113 /** Random generator function to create random TXIDs and source ports for queries */
114 #ifndef DNS_RAND_TXID
115 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_XID) != 0) && defined(LWIP_RAND)
116 #define DNS_RAND_TXID LWIP_RAND
117 #else
118 static u16_t dns_txid;
119 #define DNS_RAND_TXID() (++dns_txid)
120 #endif
121 #endif
122 
123 /** Limits the source port to be >= 1024 by default */
124 #ifndef DNS_PORT_ALLOWED
125 #define DNS_PORT_ALLOWED(port) ((port) >= 1024)
126 #endif
127 
128 /** DNS resource record max. TTL (one week as default) */
129 #ifndef DNS_MAX_TTL
130 #define DNS_MAX_TTL               604800
131 #elif DNS_MAX_TTL > 0x7FFFFFFF
132 #error DNS_MAX_TTL must be a positive 32-bit value
133 #endif
134 
135 #if DNS_TABLE_SIZE > 255
136 #error DNS_TABLE_SIZE must fit into an u8_t
137 #endif
138 #if DNS_MAX_SERVERS > 255
139 #error DNS_MAX_SERVERS must fit into an u8_t
140 #endif
141 
142 #if LWIP_RIPPLE
143 #define IS_DNS_SERVER_VALID(server) ((!ip_addr_isany(server)) && (!ip_addr_ismulticast(server)) && \
144                                      (!ip_addr_islinklocal(server)) && (!ip_addr_isloopback(server)))
145 #endif
146 
147 /* The number of parallel requests (i.e. calls to dns_gethostbyname
148  * that cannot be answered from the DNS table.
149  * This is set to the table size by default.
150  */
151 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0)
152 #ifndef DNS_MAX_REQUESTS
153 #define DNS_MAX_REQUESTS          DNS_TABLE_SIZE
154 #else
155 #if DNS_MAX_REQUESTS > 255
156 #error DNS_MAX_REQUESTS must fit into an u8_t
157 #endif
158 #endif
159 #else
160 /* In this configuration, both arrays have to have the same size and are used
161  * like one entry (used/free) */
162 #define DNS_MAX_REQUESTS          DNS_TABLE_SIZE
163 #endif
164 
165 /* The number of UDP source ports used in parallel */
166 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0)
167 #ifndef DNS_MAX_SOURCE_PORTS
168 #define DNS_MAX_SOURCE_PORTS      DNS_MAX_REQUESTS
169 #else
170 #if DNS_MAX_SOURCE_PORTS > 255
171 #error DNS_MAX_SOURCE_PORTS must fit into an u8_t
172 #endif
173 #endif
174 #else
175 #ifdef DNS_MAX_SOURCE_PORTS
176 #undef DNS_MAX_SOURCE_PORTS
177 #endif
178 #define DNS_MAX_SOURCE_PORTS      1
179 #endif
180 
181 /* This entry is allowed to use this DNS server (unmask this server) */
182 #define DNS_SERVER_SET_AVAILABLE(entry, server_idx) do { \
183   (entry)->server_bitmap &= ~(u32_t)(1 << (server_idx)); \
184 } while (0)
185 
186 /* This entry is NOT allowed to use this DNS server in this transaction (mask this server) */
187 #define DNS_SERVER_SET_UNAVAILABLE(entry, server_idx) do { \
188   (entry)->server_bitmap |= (1 << (server_idx)); \
189 } while (0)
190 
191 /* Check if this entry is allowed to use this DNS server */
192 #define DNS_SERVER_IS_AVAILABLE(entry, server_idx) \
193   (((entry)->server_bitmap & (1 << (server_idx))) == 0 && !ip_addr_isany(&dns_servers[(server_idx)]))
194 
195 /* Switch to the available DNS server when searching */
196 #define DNS_SERVER_SEARCHING_FLAG_SWITCH 0x1
197 
198 #if LWIP_DNS_REVERSE
199 #define REVERSE_DOMAIN_MAXLEN 256
200 #endif
201 
202 #if LWIP_IPV4 && LWIP_IPV6
203 #define LWIP_DNS_ADDRTYPE_IS_IPV6(t) (((t) == LWIP_DNS_ADDRTYPE_IPV6_IPV4) || ((t) == LWIP_DNS_ADDRTYPE_IPV6))
204 #define LWIP_DNS_ADDRTYPE_IS_FALLBACK(t) (((t) == LWIP_DNS_ADDRTYPE_IPV4_IPV6) || ((t) == LWIP_DNS_ADDRTYPE_IPV6_IPV4))
205 #define LWIP_DNS_ADDRTYPE_MATCH_IP(t, ip) (IP_IS_V6_VAL(ip) ? \
206                                           (LWIP_DNS_ADDRTYPE_IS_IPV6(t) || LWIP_DNS_ADDRTYPE_IS_FALLBACK(t)) : \
207                                           (!LWIP_DNS_ADDRTYPE_IS_IPV6(t)) || LWIP_DNS_ADDRTYPE_IS_FALLBACK(t))
208 #define LWIP_DNS_ADDRTYPE_ARG(x) , x
209 #define LWIP_DNS_ADDRTYPE_ARG_OR_ZERO(x) x
210 #define LWIP_DNS_SET_ADDRTYPE(x, y) do { x = y; } while(0)
211 #else
212 #if LWIP_IPV6
213 #define LWIP_DNS_ADDRTYPE_IS_IPV6(t) 1
214 #else
215 #define LWIP_DNS_ADDRTYPE_IS_IPV6(t) 0
216 #endif /* LWIP_IPV6 */
217 #define LWIP_DNS_ADDRTYPE_IS_FALLBACK(t) 0
218 #define LWIP_DNS_ADDRTYPE_MATCH_IP(t, ip) 1
219 #define LWIP_DNS_ADDRTYPE_ARG(x)
220 #define LWIP_DNS_ADDRTYPE_ARG_OR_ZERO(x) 0
221 #define LWIP_DNS_SET_ADDRTYPE(x, y)
222 #endif /* LWIP_IPV4 && LWIP_IPV6 */
223 
224 #if LWIP_DNS_SUPPORT_MDNS_QUERIES
225 #define LWIP_DNS_ISMDNS_ARG(x) , x
226 #else
227 #define LWIP_DNS_ISMDNS_ARG(x)
228 #endif
229 
230 #define LOCALHOST_STRING  "localhost"
231 
232 /* DNS table entry states */
233 typedef enum {
234   DNS_STATE_UNUSED           = 0,
235   DNS_STATE_NEW              = 1,
236   DNS_STATE_ASKING           = 2,
237   DNS_STATE_DONE             = 3
238 } dns_state_enum_t;
239 
240 /** DNS table entry */
241 struct dns_table_entry {
242   u32_t ttl;
243   u32_t ipaddr_count;
244   u32_t first_send_time;
245   ip_addr_t ipaddr[DNS_MAX_IPADDR];
246   u16_t txid;
247   u8_t  state;
248   u8_t  server_idx;
249   u32_t server_bitmap;  /* Bitmap for available DNS servers. 0-unmasked, 1-masked */
250   u8_t  tmr;
251   u8_t  retries;
252   u8_t  seqno;
253 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0)
254   u8_t pcb_idx;
255 #endif
256   char name[DNS_MAX_NAME_LENGTH];
257 #if LWIP_IPV4 && LWIP_IPV6
258   u8_t reqaddrtype;
259 #endif /* LWIP_IPV4 && LWIP_IPV6 */
260 #if LWIP_DNS_SUPPORT_MDNS_QUERIES
261   u8_t is_mdns;
262 #endif
263 };
264 
265 #if LWIP_DNS_REVERSE
266 struct reverse_domain {
267   /* Encoded domain name */
268   char name[REVERSE_DOMAIN_MAXLEN];
269   /* Total length of domain name, including zero */
270   size_t length;
271 };
272 
273 /* Reverse DNS table entry */
274 struct reverse_dns_table_entry {
275   u32_t ttl;
276   u32_t name_count;
277   u32_t first_send_time;
278   struct reverse_domain encoded_ip;
279   char name[NI_MAXHOST + 1];
280   u16_t txid;
281   u8_t  state;
282   u8_t  server_idx;
283   u32_t server_bitmap;  /* Bitmap for available DNS servers. 0-unmasked, 1-masked */
284   u8_t  tmr;
285   u8_t  retries;
286   u8_t  seqno;
287 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0)
288   u8_t pcb_idx;
289 #endif /* (LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0 */
290 #if LWIP_DNS_SUPPORT_MDNS_QUERIES
291   u8_t is_mdns;
292 #endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */
293 };
294 #endif
295 
296 /** DNS request table entry: used when dns_gethostbyname cannot answer the
297  * request from the DNS table */
298 struct dns_req_entry {
299   /* pointer to callback on DNS query done */
300   dns_found_callback found;
301   /* argument passed to the callback function */
302   void *arg;
303 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0)
304   u8_t dns_table_idx;
305 #endif
306 #if LWIP_IPV4 && LWIP_IPV6
307   u8_t reqaddrtype;
308 #endif /* LWIP_IPV4 && LWIP_IPV6 */
309 };
310 
311 #if LWIP_DNS_REVERSE
312 /* Reverse DNS request table entry: used when reverse_dns_getnamebyhost cannot answer the
313  * request from the Reverse DNS table */
314 struct reverse_dns_req_entry {
315   /* pointer to callback on DNS query done */
316   reverse_dns_found_callback found;
317   /* argument passed to the callback function */
318   void *arg;
319 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0)
320   u8_t reverse_dns_table_idx;
321 #endif /* (LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0 */
322 };
323 #endif
324 
325 #if DNS_LOCAL_HOSTLIST
326 
327 #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
328 /** Local host-list. For hostnames in this list, no
329  *  external name resolution is performed */
330 static struct local_hostlist_entry *local_hostlist_dynamic;
331 #else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
332 
333 /** Defining this allows the local_hostlist_static to be placed in a different
334  * linker section (e.g. FLASH) */
335 #ifndef DNS_LOCAL_HOSTLIST_STORAGE_PRE
336 #define DNS_LOCAL_HOSTLIST_STORAGE_PRE static
337 #endif /* DNS_LOCAL_HOSTLIST_STORAGE_PRE */
338 /** Defining this allows the local_hostlist_static to be placed in a different
339  * linker section (e.g. FLASH) */
340 #ifndef DNS_LOCAL_HOSTLIST_STORAGE_POST
341 #define DNS_LOCAL_HOSTLIST_STORAGE_POST
342 #endif /* DNS_LOCAL_HOSTLIST_STORAGE_POST */
343 DNS_LOCAL_HOSTLIST_STORAGE_PRE struct local_hostlist_entry local_hostlist_static[]
344   DNS_LOCAL_HOSTLIST_STORAGE_POST = DNS_LOCAL_HOSTLIST_INIT;
345 
346 #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
347 
348 static void dns_init_local(void);
349 static err_t dns_lookup_local(const char *hostname, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype));
350 #endif /* DNS_LOCAL_HOSTLIST */
351 
352 
353 /* forward declarations */
354 static err_t dns_send(u8_t idx);
355 static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port);
356 
357 static void process_forward_dns(struct pbuf *p, u8_t entry_idx, struct dns_table_entry *entry, struct dns_hdr hdr,
358                                 const ip_addr_t *addr);
359 static err_t dns_check_entry(u8_t i);
360 static void dns_check_entries(void);
361 static void dns_correct_response(u8_t idx, u32_t ttl);
362 static void dns_call_found(u8_t idx, const ip_addr_t *addr, u32_t ipaddr_count);
363 static u16_t dns_create_txid(void);
364 static void dns_find_first_server(void);
365 
366 static err_t
367 dns_enqueue(const char *name, size_t hostnamelen, dns_found_callback found,
368             void *callback_arg, u8_t dns_addrtype LWIP_DNS_ISMDNS_ARG(u8_t is_mdns));
369 static u8_t
370 dns_backupserver_available(struct dns_table_entry *pentry, u8_t flags);
371 
372 static u16_t
373 dns_compare_name(char *query, struct pbuf *p, u16_t start_offset, u16_t allow_compressed_hdr);
374 static err_t
375 dns_lookup(const char *name, ip_addr_t *addr, u32_t *count LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype));
376 
377 #if LWIP_DNS_REVERSE
378 #ifdef LWIP_TESTBED
379 err_t reverse_dns_domain_add_label(struct reverse_domain *domain, const char *label, size_t len);
380 #else
381 static err_t reverse_dns_domain_add_label(struct reverse_domain *domain, const char *label, size_t len);
382 #endif
383 
384 #if LWIP_IPV4
385 static err_t reverse_dns_build_reverse_v4_domain(struct reverse_domain *domain, const ip4_addr_t *addr);
386 #endif /* LWIP_IPV4 */
387 
388 #if LWIP_IPV6
389 static err_t reverse_dns_build_reverse_v6_domain(struct reverse_domain *domain, const ip6_addr_t *addr);
390 #endif /* LWIP_IPV6 */
391 
392 static void process_reverse_dns(struct pbuf *p, u8_t entry_idx, struct reverse_dns_table_entry *reverse_entry,
393                                 struct dns_hdr hdr, const ip_addr_t *addr);
394 
395 static void reverse_dns_check_entries(void);
396 static err_t reverse_dns_lookup(const struct reverse_domain *encoded_ip, char *hostname);
397 static err_t reverse_dns_send(u8_t idx);
398 static void reverse_dns_call_found(u8_t idx, const char *hostname, u32_t name_count);
399 static err_t reverse_dns_check_entry(u8_t i);
400 static void reverse_dns_correct_response(u8_t idx, u32_t ttl);
401 static err_t reverse_dns_enqueue(const struct reverse_domain *encoded_ip, reverse_dns_found_callback found,
402                                  void *callback_arg);
403 static u8_t reverse_dns_backupserver_available(struct reverse_dns_table_entry *rentry, u8_t flags);
404 #endif /* LWIP_DNS_REVERSE */
405 
406 /*-----------------------------------------------------------------------------
407  * Globals
408  *----------------------------------------------------------------------------*/
409 
410 /* DNS variables */
411 static struct udp_pcb        *dns_pcbs[DNS_MAX_SOURCE_PORTS];
412 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0)
413 static u8_t                   dns_last_pcb_idx;
414 #endif /* (LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0 */
415 static u8_t                   dns_seqno = 0;
416 static struct dns_table_entry dns_table[DNS_TABLE_SIZE];
417 static struct dns_req_entry   dns_requests[DNS_MAX_REQUESTS];
418 static ip_addr_t              dns_servers[DNS_MAX_SERVERS];
419 
420 #if LWIP_DNS_REVERSE
421 static struct reverse_dns_table_entry reverse_dns_table[DNS_TABLE_SIZE];
422 static struct reverse_dns_req_entry   reverse_dns_requests[DNS_MAX_REQUESTS];
423 #endif /* LWIP_DNS_REVERSE */
424 
425 #if LWIP_IPV4
426 const ip_addr_t dns_mquery_v4group = DNS_MQUERY_IPV4_GROUP_INIT;
427 #endif /* LWIP_IPV4 */
428 #if LWIP_IPV6
429 const ip_addr_t dns_mquery_v6group = DNS_MQUERY_IPV6_GROUP_INIT;
430 #endif /* LWIP_IPV6 */
431 
432 static u8_t dns_first_server_idx = 0;
433 #if LWIP_DNS_REVERSE
434 static u8_t rdns_first_server_idx = 0;
435 #endif /* LWIP_DNS_REVERSE */
436 struct dns_msg {
437   u8_t numdns;
438   ip_addr_t *dnsserver;
439   sys_sem_t cb_completed;
440 };
441 
442 /**
443  * Initialize the resolver: set up the UDP pcb and configure the default server
444  * (if DNS_SERVER_ADDRESS is set).
445  */
446 void
dns_init(void)447 dns_init(void)
448 {
449 #ifdef DNS_SERVER_ADDRESS
450   /* initialize default DNS server address */
451   ip_addr_t dnsserver;
452   DNS_SERVER_ADDRESS(&dnsserver);
453   dns_setserver(0, &dnsserver);
454 #endif /* DNS_SERVER_ADDRESS */
455 
456   LWIP_ASSERT("sanity check SIZEOF_DNS_QUERY",
457               sizeof(struct dns_query) == SIZEOF_DNS_QUERY);
458   LWIP_ASSERT("sanity check SIZEOF_DNS_ANSWER",
459               sizeof(struct dns_answer) <= SIZEOF_DNS_ANSWER_ASSERT);
460 
461   LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n"));
462 
463   /* if dns client not yet initialized... */
464 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) == 0)
465   if (dns_pcbs[0] == NULL) {
466     dns_pcbs[0] = udp_new_ip_type(IPADDR_TYPE_ANY);
467     LWIP_ASSERT("dns_pcbs[0] != NULL", dns_pcbs[0] != NULL);
468 
469     /* initialize DNS table not needed (initialized to zero since it is a
470      * global variable) */
471     LWIP_ASSERT("For implicit initialization to work, DNS_STATE_UNUSED needs to be 0",
472                 DNS_STATE_UNUSED == 0);
473 
474 #if LWIP_SO_PRIORITY
475     dns_pcbs[0]->priority = LWIP_PKT_PRIORITY_DNS;
476 #endif /* LWIP_SO_PRIORITY */
477 
478     /* initialize DNS client */
479     udp_bind(dns_pcbs[0], IP_ANY_TYPE, 0);
480     udp_recv(dns_pcbs[0], dns_recv, NULL);
481   }
482 #endif
483 
484 #if DNS_LOCAL_HOSTLIST
485   dns_init_local();
486 #endif
487 }
488 
489 /**
490  * @ingroup dns
491  * Initialize one of the DNS servers.
492  *
493  * @param numdns the index of the DNS server to set must be < DNS_MAX_SERVERS
494  * @param dnsserver IP address of the DNS server to set
495  */
496 void
dns_setserver(u8_t numdns,const ip_addr_t * dnsserver)497 dns_setserver(u8_t numdns, const ip_addr_t *dnsserver)
498 {
499   u8_t i;
500 #if LWIP_RIPPLE
501   u8_t changed = 0;
502   u8_t cnt;
503   ip_addr_t server;
504 #endif
505   if (numdns < DNS_MAX_SERVERS) {
506 #if LWIP_RIPPLE
507     server = dns_servers[numdns];
508 #endif
509     if (dnsserver != NULL) {
510       dns_servers[numdns] = (*dnsserver);
511     } else {
512       dns_servers[numdns] = *IP_ADDR_ANY;
513     }
514 
515     /* once any change of DNS server happens, simply set it available here,
516     and check if it is a valid server when searching for first_server and backup_server. */
517     for (i = 0; i < DNS_TABLE_SIZE; i++) {
518       dns_table[i].server_bitmap = 0;
519 #if LWIP_DNS_REVERSE
520       reverse_dns_table[i].server_bitmap = 0;
521 #endif /* LWIP_DNS_REVERSE */
522     }
523 
524     /* once any changes of DNS servers, refind the first server */
525     dns_find_first_server();
526 #if LWIP_RIPPLE
527     if ((dnsserver != NULL) && IS_DNS_SERVER_VALID(dnsserver) &&
528         (memcmp(&server, dnsserver, sizeof(ip_addr_t)) != 0)) {
529       changed = 1;
530     } else if ((dnsserver == NULL) && IS_DNS_SERVER_VALID(&server)) {
531       cnt = lwip_dns_get_server_cnt(NULL, NULL);
532       if (cnt > 0) {
533         changed = 1;
534       }
535     }
536 
537     if (changed == 1) {
538 #ifdef LWIP_DNS_RPL_REPAIR
539       lwip_rpl_trigger_global_repair();
540 #else
541       lwip_rpl_trigger_global_dao();
542 #endif
543     }
544 #endif
545   }
546 }
547 
548 void
dns_setserver_internal(void * arg)549 dns_setserver_internal(void *arg)
550 {
551   struct dns_msg *msg = NULL;
552 
553   msg = (struct dns_msg *)arg;
554 
555   dns_setserver(msg->numdns, msg->dnsserver);
556   sys_sem_signal(&msg->cb_completed);
557 }
558 
559 err_t
lwip_dns_setserver(u8_t numdns,ip_addr_t * dnsserver)560 lwip_dns_setserver(u8_t numdns, ip_addr_t *dnsserver)
561 {
562   struct dns_msg dmsg;
563   err_t err;
564 
565   (void)memset_s(&dmsg, sizeof(dmsg), 0, sizeof(dmsg));
566   if (numdns >= DNS_MAX_SERVERS) {
567     LWIP_DEBUGF(DNS_DEBUG, ("lwip_dns_setserver: Invalid param, index %"S32_F", "
568                 "DNS_MAX_SERVERS is %"S32_F"\n", numdns, DNS_MAX_SERVERS));
569     return ERR_VAL;
570   }
571 
572   dmsg.numdns = numdns;
573   dmsg.dnsserver = dnsserver;
574 
575   err = sys_sem_new(&dmsg.cb_completed, 0);
576   if (err != ERR_OK) {
577     return err;
578   }
579 
580   err = tcpip_callback(dns_setserver_internal, &dmsg);
581   if (err != ERR_OK) {
582     sys_sem_free(&dmsg.cb_completed);
583     return err;
584   }
585 
586   (void)sys_arch_sem_wait(&dmsg.cb_completed, 0);
587   sys_sem_free(&dmsg.cb_completed);
588 
589   return ERR_OK;
590 }
591 
592 /**
593  * @ingroup dns
594  * Obtain one of the currently configured DNS server.
595  *
596  * @param numdns the index of the DNS server
597  * @return IP address of the indexed DNS server or "ip_addr_any" if the DNS
598  *         server has not been configured.
599  */
600 const ip_addr_t*
dns_getserver(u8_t numdns)601 dns_getserver(u8_t numdns)
602 {
603   if (numdns < DNS_MAX_SERVERS) {
604     return &dns_servers[numdns];
605   } else {
606     return IP_ADDR_ANY;
607   }
608 }
609 
610 void
dns_getserver_internal(void * arg)611 dns_getserver_internal(void *arg)
612 {
613   struct dns_msg *msg = NULL;
614 
615   msg = (struct dns_msg *)arg;
616 
617   *msg->dnsserver = *dns_getserver(msg->numdns);
618   sys_sem_signal(&msg->cb_completed);
619 }
620 
621 err_t
lwip_dns_getserver(u8_t numdns,ip_addr_t * dnsserver)622 lwip_dns_getserver(u8_t numdns, ip_addr_t *dnsserver)
623 {
624   struct dns_msg dmsg;
625   err_t err;
626 
627   (void)memset_s(&dmsg, sizeof(dmsg), 0, sizeof(dmsg));
628   if (dnsserver == NULL) {
629     LWIP_DEBUGF(DNS_DEBUG, ("lwip_dns_setserver: Invalid param, dnsserver 0x%p\n", (void *)dnsserver));
630     return ERR_VAL;
631   }
632 
633   dmsg.numdns = numdns;
634   dmsg.dnsserver = dnsserver;
635 
636   err = sys_sem_new(&dmsg.cb_completed, 0);
637   if (err != ERR_OK) {
638     return err;
639   }
640 
641   err = tcpip_callback(dns_getserver_internal, &dmsg);
642   if (err != ERR_OK) {
643     sys_sem_free(&dmsg.cb_completed);
644     return err;
645   }
646 
647   (void)sys_arch_sem_wait(&dmsg.cb_completed, 0);
648   sys_sem_free(&dmsg.cb_completed);
649 
650   return ERR_OK;
651 }
652 
653 u8_t
lwip_dns_get_server_cnt(u8_t * ip4cnt,u8_t * ip6cnt)654 lwip_dns_get_server_cnt(u8_t *ip4cnt, u8_t *ip6cnt)
655 {
656   int i;
657   u8_t cnt = 0;
658 
659   if (ip4cnt != NULL) {
660     *ip4cnt = 0;
661   }
662 
663   if (ip6cnt != NULL) {
664     *ip6cnt = 0;
665   }
666 
667   for (i = 0; i < DNS_MAX_SERVERS; i++) {
668     if (ip_addr_isany_val(dns_servers[i])) {
669       continue;
670     }
671 
672     cnt++;
673     if (IP_IS_V6_VAL(dns_servers[i])) {
674       (ip6cnt != NULL) ? (*ip6cnt)++ : 0;
675     } else if (ip4cnt != NULL) {
676       (*ip4cnt)++;
677     }
678   }
679 
680   return cnt;
681 }
682 
683 #if LWIP_IPV6
684 err_t
lwip_dns_copy_ip6server_addr(const struct netif * nif,ip6_addr_t * ip6addr,u8_t num)685 lwip_dns_copy_ip6server_addr(const struct netif *nif, ip6_addr_t *ip6addr, u8_t num)
686 {
687   int i;
688   int cnt = 0;
689 
690   if ((nif == NULL) || (ip6addr == NULL) || (num == 0)) {
691     return ERR_ARG;
692   }
693 
694   for (i = 0; i < DNS_MAX_SERVERS; i++) {
695     if (ip_addr_isany_val(dns_servers[i])) {
696       continue;
697     }
698 
699     if (IP_IS_V6_VAL(dns_servers[i]) && (!ip_addr_isloopback(&dns_servers[i])) &&
700         (!ip_addr_ismulticast(&dns_servers[i])) && (!ip_addr_islinklocal(&dns_servers[i]))) {
701       ip6_addr_copy(ip6addr[cnt], *ip_2_ip6(&dns_servers[i]));
702       cnt++;
703       if (cnt >= num) {
704         return ERR_OK;
705       }
706       continue;
707     }
708 #if LWIP_RIPPLE && LWIP_DNS64 && LWIP_NAT64
709     if ((lwip_rpl_is_rpl_netif(nif) == lwIP_TRUE) && (lwip_rpl_is_br() == lwIP_TRUE) &&
710         (nat64_status_check() == NAT64_RET_OK) && IP_IS_V4_VAL(dns_servers[i]) &&
711         (nat64_stateless_addr_4to6(ip_2_ip4(&dns_servers[i]), &ip6addr[cnt]) == ERR_OK)) {
712       cnt++;
713       if (cnt >= num) {
714         return ERR_OK;
715       }
716     }
717 #endif
718   }
719 
720   if (cnt != num) {
721     return ERR_VAL;
722   }
723 
724   return ERR_OK;
725 }
726 #endif
727 
728 #if LWIP_DNS_REVERSE
729 /*
730  * Add a label part to a domain
731  * @param domain The domain to add a label to
732  * @param label The label to add, like <hostname>, 'local', 'com' or ''
733  * @param len The length of the label
734  * @return ERR_OK on success, an err_t otherwise if label too long
735  */
736 #ifdef LWIP_TESTBED
737 err_t
738 #else
739 static err_t
740 #endif
reverse_dns_domain_add_label(struct reverse_domain * domain,const char * label,size_t len)741 reverse_dns_domain_add_label(struct reverse_domain *domain, const char *label, size_t len)
742 {
743   if (len > DNS_MAX_LABEL_LENGTH) {
744     return ERR_VAL;
745   }
746   if ((len > 0) && (1 + len + domain->length >= REVERSE_DOMAIN_MAXLEN)) {
747     return ERR_VAL;
748   }
749   /* Allow only zero marker on last byte */
750   if ((len == 0) && (1 + domain->length > REVERSE_DOMAIN_MAXLEN)) {
751     return ERR_VAL;
752   }
753   if ((domain->length != 0) && (label != NULL)) {
754     domain->name[domain->length] = '.';
755     domain->length++;
756   }
757   if ((len != 0) && (label != NULL)) {
758     if (memcpy_s(&domain->name[domain->length], (REVERSE_DOMAIN_MAXLEN - domain->length), label, len) != EOK) {
759       return ERR_MEM;
760     }
761     domain->length += len;
762   }
763   return ERR_OK;
764 }
765 
766 
767 #if LWIP_IPV4
768 /*
769  * Build domain for reverse lookup of IPv4 address
770  * 192.168.0.12 will be mapped to 12.0.168.192.in-addr.arpa.
771  * @param domain Where to write the domain name
772  * @param addr Pointer to an IPv4 address to encode
773  * @return ERR_OK if domain was written, an err_t otherwise
774  */
775 static err_t
reverse_dns_build_reverse_v4_domain(struct reverse_domain * domain,const ip4_addr_t * addr)776 reverse_dns_build_reverse_v4_domain(struct reverse_domain *domain, const ip4_addr_t *addr)
777 {
778   int i;
779   err_t res;
780   const u8_t *ptr = NULL;
781   /* ip4 address have 4 parts, biggges parts is 255, less than 4 */
782   char buf[4];
783   u8_t val;
784 
785   LWIP_ERROR("reverse_dns_build_reverse_v4_domain: domain is NULL", (domain != NULL), return ERR_ARG);
786   LWIP_ERROR("reverse_dns_build_reverse_v4_domain: addr is NULL", (addr != NULL), return ERR_ARG);
787 
788   (void)memset_s(domain, sizeof(struct reverse_domain), 0, sizeof(struct reverse_domain));
789 
790   ptr = (const u8_t *)addr;
791   for (i = (int)(sizeof(ip4_addr_t)) - 1; i >= 0; --i) {
792     val = ptr[i];
793     lwip_itoa(buf, sizeof(buf), val);
794     res = reverse_dns_domain_add_label(domain, buf, strlen(buf));
795     LWIP_ERROR("reverse_dns_build_reverse_v4_domain: Failed to add label: buf", (res == ERR_OK), return res);
796   }
797   res = reverse_dns_domain_add_label(domain, REVERSE_PTR_V4_DOMAIN, (sizeof(REVERSE_PTR_V4_DOMAIN)-1));
798   LWIP_ERROR("reverse_dns_build_reverse_v4_domain: Failed to add label: REVERSE_PTR_V4_DOMAIN",
799              (res == ERR_OK), return res);
800   res = reverse_dns_domain_add_label(domain, REVERSE_PTR_TOP_DOMAIN, (sizeof(REVERSE_PTR_TOP_DOMAIN)-1));
801   LWIP_ERROR("reverse_dns_build_reverse_v4_domain: Failed to add label: REVERSE_PTR_TOP_DOMAIN",
802              (res == ERR_OK), return res);
803   res = reverse_dns_domain_add_label(domain, NULL, 0);
804   LWIP_ERROR("reverse_dns_build_reverse_v4_domain: Failed to add label: NULL", (res == ERR_OK), return res);
805 
806   return ERR_OK;
807 }
808 #endif /* LWIP_IPV4 */
809 
810 #if LWIP_IPV6
811 /*
812  * Build domain for reverse lookup of IP address
813  * 2001:db8::567:89ab will be mapped to b.a.9.8.7.6.5.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.
814  * @param domain Where to write the domain name
815  * @param addr Pointer to an IPv6 address to encode
816  * @return ERR_OK if domain was written, an err_t otherwise
817  */
818 static err_t
reverse_dns_build_reverse_v6_domain(struct reverse_domain * domain,const ip6_addr_t * addr)819 reverse_dns_build_reverse_v6_domain(struct reverse_domain *domain, const ip6_addr_t *addr)
820 {
821   int i;
822   int j;
823   err_t res;
824   u8_t byte;
825   char buf;
826   const u8_t *ptr = NULL;
827 
828   LWIP_ERROR("reverse_dns_build_reverse_v6_domain: domain is NULL", (domain != NULL), return ERR_ARG);
829   LWIP_ERROR("reverse_dns_build_reverse_v6_domain: addr is NULL", (addr != NULL), return ERR_ARG);
830 
831   (void)memset_s(domain, sizeof(struct reverse_domain), 0, sizeof(struct reverse_domain));
832 
833   ptr = (const u8_t *)addr;
834   for (i = (int)(sizeof(ip6_addr_t)) - 1; i >= 0; i--) {
835     byte = ptr[i];
836     /* each byte have 2 nibbles */
837     for (j = 0; j < 2; j++) {
838       if ((byte & 0x0F) < 0xA) {
839         buf = (char)('0' + (byte & 0x0F));
840       } else {
841         buf = (char)('a' + (byte & 0x0F) - (0xA));
842       }
843       res = reverse_dns_domain_add_label(domain, &buf, sizeof(buf));
844       LWIP_ERROR("reverse_dns_build_reverse_v6_domain: Failed to add label: buf", (res == ERR_OK), return res);
845       /* get next nibble */
846       byte >>= 4;
847     }
848   }
849   res = reverse_dns_domain_add_label(domain, REVERSE_PTR_V6_DOMAIN, (sizeof(REVERSE_PTR_V6_DOMAIN)-1));
850   LWIP_ERROR("reverse_dns_build_reverse_v6_domain: Failed to add label: REVERSE_PTR_V6_DOMAIN",
851              (res == ERR_OK), return res);
852   res = reverse_dns_domain_add_label(domain, REVERSE_PTR_TOP_DOMAIN, (sizeof(REVERSE_PTR_TOP_DOMAIN)-1));
853   LWIP_ERROR("reverse_dns_build_reverse_v6_domain: Failed to add label: REVERSE_PTR_TOP_DOMAIN",
854              (res == ERR_OK), return res);
855   res = reverse_dns_domain_add_label(domain, NULL, 0);
856   LWIP_ERROR("reverse_dns_build_reverse_v6_domain: Failed to add label: NULL", (res == ERR_OK), return res);
857 
858   return ERR_OK;
859 }
860 #endif /* LWIP_IPV6 */
861 #endif /* LWIP_DNS_REVERSE */
862 
863 /*
864  * The DNS resolver client timer - handle retries and timeouts and should
865  * be called every DNS_TMR_INTERVAL milliseconds (every second by default).
866  */
867 void
dns_tmr(void)868 dns_tmr(void)
869 {
870   LWIP_DEBUGF(DNS_DEBUG, ("dns_tmr: dns_check_entries\n"));
871   dns_check_entries();
872 #if LWIP_DNS_REVERSE
873   reverse_dns_check_entries();
874 #endif /* LWIP_DNS_REVERSE */
875 }
876 
877 #if LWIP_LOWPOWER
878 #include "lwip/lowpower.h"
879 u32_t
dns_tmr_tick(void)880 dns_tmr_tick(void)
881 {
882   u32_t tick = 0;
883   u32_t val;
884   s32_t i;
885 
886   for (i = 0; i < DNS_TABLE_SIZE; i++) {
887     if ((dns_table[i].state == DNS_STATE_NEW) ||
888         (dns_table[i].state == DNS_STATE_ASKING)) {
889       LOWPOWER_DEBUG(("%s tmr tick: 1\n", __func__));
890       return 1;
891     }
892     if (dns_table[i].state == DNS_STATE_DONE) {
893       val = dns_table[i].ttl;
894       SET_TMR_TICK(tick, val);
895     }
896 #if LWIP_DNS_REVERSE
897     if ((reverse_dns_table[i].state == DNS_STATE_NEW) ||
898         (reverse_dns_table[i].state == DNS_STATE_ASKING)) {
899       LOWPOWER_DEBUG(("%s tmr tick: 1\n", __func__));
900       return 1;
901     }
902     if (reverse_dns_table[i].state == DNS_STATE_DONE) {
903       val = reverse_dns_table[i].ttl;
904       SET_TMR_TICK(tick, val);
905     }
906 #endif /* LWIP_DNS_REVERSE */
907   }
908   LOWPOWER_DEBUG(("%s tmr tick: %u\n", __func__, tick));
909   return tick;
910 }
911 #endif
912 
913 #if DNS_LOCAL_HOSTLIST
914 static void
dns_init_local(void)915 dns_init_local(void)
916 {
917 #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT)
918   size_t i;
919   struct local_hostlist_entry *entry;
920   /* Dynamic: copy entries from DNS_LOCAL_HOSTLIST_INIT to list */
921   struct local_hostlist_entry local_hostlist_init[] = DNS_LOCAL_HOSTLIST_INIT;
922   size_t namelen;
923   for (i = 0; i < LWIP_ARRAYSIZE(local_hostlist_init); i++) {
924     struct local_hostlist_entry *init_entry = &local_hostlist_init[i];
925     LWIP_ASSERT("invalid host name (NULL)", init_entry->name != NULL);
926     namelen = strlen(init_entry->name);
927     LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN);
928     entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST);
929     LWIP_ASSERT("mem-error in dns_init_local", entry != NULL);
930     if (entry != NULL) {
931       entry->name = (char*)entry + sizeof(struct local_hostlist_entry);
932       MEMCPY((char*)entry->name, init_entry->name, namelen);
933       ((char*)entry->name)[namelen] = 0;
934       entry->addr = init_entry->addr;
935       entry->next = local_hostlist_dynamic;
936       local_hostlist_dynamic = entry;
937     }
938   }
939 #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) */
940 }
941 
942 /**
943  * @ingroup dns
944  * Iterate the local host-list for a hostname.
945  *
946  * @param iterator_fn a function that is called for every entry in the local host-list
947  * @param iterator_arg 3rd argument passed to iterator_fn
948  * @return the number of entries in the local host-list
949  */
950 size_t
dns_local_iterate(dns_found_callback iterator_fn,void * iterator_arg)951 dns_local_iterate(dns_found_callback iterator_fn, void *iterator_arg)
952 {
953   size_t i;
954 #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
955   struct local_hostlist_entry *entry = local_hostlist_dynamic;
956   i = 0;
957   while (entry != NULL) {
958     if (iterator_fn != NULL) {
959       iterator_fn(entry->name, &entry->addr, 1, iterator_arg);
960     }
961     i++;
962     entry = entry->next;
963   }
964 #else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
965   for (i = 0; i < LWIP_ARRAYSIZE(local_hostlist_static); i++) {
966     if (iterator_fn != NULL) {
967       iterator_fn(local_hostlist_static[i].name, &local_hostlist_static[i].addr, 1, iterator_arg);
968     }
969   }
970 #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
971   return i;
972 }
973 
974 /**
975  * @ingroup dns
976  * Scans the local host-list for a hostname.
977  *
978  * @param hostname Hostname to look for in the local host-list
979  * @param addr the first IP address for the hostname in the local host-list or
980  *         IPADDR_NONE if not found.
981  * @param dns_addrtype - LWIP_DNS_ADDRTYPE_IPV4_IPV6: try to resolve IPv4 (ATTENTION: no fallback here!)
982  *                     - LWIP_DNS_ADDRTYPE_IPV6_IPV4: try to resolve IPv6 (ATTENTION: no fallback here!)
983  *                     - LWIP_DNS_ADDRTYPE_IPV4: try to resolve IPv4 only
984  *                     - LWIP_DNS_ADDRTYPE_IPV6: try to resolve IPv6 only
985  * @return ERR_OK if found, ERR_ARG if not found
986  */
987 err_t
dns_local_lookup(const char * hostname,ip_addr_t * addr,u8_t dns_addrtype)988 dns_local_lookup(const char *hostname, ip_addr_t *addr, u8_t dns_addrtype)
989 {
990   LWIP_UNUSED_ARG(dns_addrtype);
991   return dns_lookup_local(hostname, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype));
992 }
993 
994 /* Internal implementation for dns_local_lookup and dns_lookup */
995 static err_t
dns_lookup_local(const char * hostname,ip_addr_t * addr LWIP_DNS_ADDRTYPE_ARG (u8_t dns_addrtype))996 dns_lookup_local(const char *hostname, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype))
997 {
998 #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
999   struct local_hostlist_entry *entry = local_hostlist_dynamic;
1000   while (entry != NULL) {
1001     if ((lwip_stricmp(entry->name, hostname) == 0) &&
1002         LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, entry->addr)) {
1003       if (addr) {
1004         ip_addr_copy(*addr, entry->addr);
1005       }
1006       return ERR_OK;
1007     }
1008     entry = entry->next;
1009   }
1010 #else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
1011   size_t i;
1012   for (i = 0; i < LWIP_ARRAYSIZE(local_hostlist_static); i++) {
1013     if ((lwip_stricmp(local_hostlist_static[i].name, hostname) == 0) &&
1014         LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, local_hostlist_static[i].addr)) {
1015       if (addr) {
1016         ip_addr_copy(*addr, local_hostlist_static[i].addr);
1017       }
1018       return ERR_OK;
1019     }
1020   }
1021 #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
1022   return ERR_ARG;
1023 }
1024 
1025 #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
1026 /**
1027  * @ingroup dns
1028  * Remove all entries from the local host-list for a specific hostname
1029  * and/or IP address
1030  *
1031  * @param hostname hostname for which entries shall be removed from the local
1032  *                 host-list
1033  * @param addr address for which entries shall be removed from the local host-list
1034  * @return the number of removed entries
1035  */
1036 int
dns_local_removehost(const char * hostname,const ip_addr_t * addr)1037 dns_local_removehost(const char *hostname, const ip_addr_t *addr)
1038 {
1039   int removed = 0;
1040   struct local_hostlist_entry *entry = local_hostlist_dynamic;
1041   struct local_hostlist_entry *last_entry = NULL;
1042   while (entry != NULL) {
1043     if (((hostname == NULL) || !lwip_stricmp(entry->name, hostname)) &&
1044         ((addr == NULL) || ip_addr_cmp(&entry->addr, addr))) {
1045       struct local_hostlist_entry *free_entry;
1046       if (last_entry != NULL) {
1047         last_entry->next = entry->next;
1048       } else {
1049         local_hostlist_dynamic = entry->next;
1050       }
1051       free_entry = entry;
1052       entry = entry->next;
1053       memp_free(MEMP_LOCALHOSTLIST, free_entry);
1054       removed++;
1055     } else {
1056       last_entry = entry;
1057       entry = entry->next;
1058     }
1059   }
1060   return removed;
1061 }
1062 
1063 /**
1064  * @ingroup dns
1065  * Add a hostname/IP address pair to the local host-list.
1066  * Duplicates are not checked.
1067  *
1068  * @param hostname hostname of the new entry
1069  * @param addr IP address of the new entry
1070  * @return ERR_OK if succeeded or ERR_MEM on memory error
1071  */
1072 err_t
dns_local_addhost(const char * hostname,const ip_addr_t * addr)1073 dns_local_addhost(const char *hostname, const ip_addr_t *addr)
1074 {
1075   struct local_hostlist_entry *entry;
1076   size_t namelen;
1077   LWIP_ASSERT("invalid host name (NULL)", hostname != NULL);
1078   namelen = strlen(hostname);
1079   LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN);
1080   entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST);
1081   if (entry == NULL) {
1082     return ERR_MEM;
1083   }
1084   entry->name = (char*)entry + sizeof(struct local_hostlist_entry);
1085   MEMCPY((char*)entry->name, hostname, namelen);
1086   ((char*)entry->name)[namelen] = 0;
1087 
1088   ip_addr_copy(entry->addr, *addr);
1089   entry->next = local_hostlist_dynamic;
1090   local_hostlist_dynamic = entry;
1091   return ERR_OK;
1092 }
1093 #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC*/
1094 #endif /* DNS_LOCAL_HOSTLIST */
1095 
1096 /**
1097  * @ingroup dns
1098  * Look up a hostname in the array of known hostnames.
1099  *
1100  * @note This function only looks in the internal array of known
1101  * hostnames, it does not send out a query for the hostname if none
1102  * was found. The function dns_enqueue() can be used to send a query
1103  * for a hostname.
1104  *
1105  * @param name the hostname to look up
1106  * @param addr the hostname's IP address, as u32_t (instead of ip_addr_t to
1107  *         better check for failure: != IPADDR_NONE) or IPADDR_NONE if the hostname
1108  *         was not found in the cached dns_table.
1109  * @param count the maximum number of resolved IP Address requested for name
1110  * @return ERR_OK if found, ERR_ARG if not found
1111  */
1112 static err_t
dns_lookup(const char * name,ip_addr_t * addr,u32_t * count LWIP_DNS_ADDRTYPE_ARG (u8_t dns_addrtype))1113 dns_lookup(const char *name, ip_addr_t *addr, u32_t *count LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype))
1114 {
1115   u8_t i;
1116   u8_t j;
1117   u8_t matching_response = 0;
1118 #if DNS_LOCAL_HOSTLIST
1119   if (dns_lookup_local(name, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)) == ERR_OK) {
1120     *count = 1;
1121     return ERR_OK;
1122   }
1123 #endif /* DNS_LOCAL_HOSTLIST */
1124 #ifdef DNS_LOOKUP_LOCAL_EXTERN
1125   if (DNS_LOOKUP_LOCAL_EXTERN(name, addr, LWIP_DNS_ADDRTYPE_ARG_OR_ZERO(dns_addrtype)) == ERR_OK) {
1126     *count = 1;
1127     return ERR_OK;
1128   }
1129 #endif /* DNS_LOOKUP_LOCAL_EXTERN */
1130 
1131   /* Walk through name list, return entry if found. If not, return NULL. */
1132   for (i = 0; i < DNS_TABLE_SIZE; ++i) {
1133     if ((dns_table[i].state == DNS_STATE_DONE) &&
1134         (lwip_strnicmp(name, dns_table[i].name, sizeof(dns_table[i].name)) == 0)) {
1135 
1136       LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup : found = \"%s\"", name));
1137 
1138       for (j = 0; j < LWIP_MIN(*count, dns_table[i].ipaddr_count); j++) {
1139         if (LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, dns_table[i].ipaddr[j])) {
1140 #ifdef  LWIP_DEV_DEBUG
1141           ip_addr_debug_print_val(DNS_DEBUG, dns_table[i].ipaddr[j]);
1142           LWIP_DEBUGF(DNS_DEBUG, ("\n"));
1143 #endif  /* LWIP_DEV_DEBUG */
1144           LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup : found = \"%s\" with matching ADDRTYPE\n", name));
1145           ip_addr_copy(addr[matching_response], dns_table[i].ipaddr[j]);
1146           ++matching_response;
1147         }
1148       }
1149 
1150       if (matching_response == 0) {
1151         continue;
1152       }
1153 
1154       *count = matching_response;
1155       return ERR_OK;
1156     }
1157   }
1158 
1159   return ERR_ARG;
1160 }
1161 
1162 #if LWIP_DNS_REVERSE
1163 static err_t
reverse_dns_lookup(const struct reverse_domain * encoded_ip,char * hostname)1164 reverse_dns_lookup(const struct reverse_domain *encoded_ip, char *hostname)
1165 {
1166   u8_t i;
1167 
1168   /* Walk through name list, return entry if found. If not, return NULL. */
1169   for (i = 0; i < DNS_TABLE_SIZE; ++i) {
1170     if ((reverse_dns_table[i].state == DNS_STATE_DONE) &&
1171         (lwip_strnicmp((const char*)(encoded_ip->name), (const char*)(reverse_dns_table[i].encoded_ip.name),
1172                        sizeof(reverse_dns_table[i].encoded_ip.name)) == 0)) {
1173       if (strncpy_s(hostname, NI_MAXHOST, reverse_dns_table[i].name, strlen(reverse_dns_table[i].name)) != EOK) {
1174         LWIP_DEBUGF(DNS_DEBUG, ("reverse_dns_lookup : memory error\n"));
1175         return ERR_MEM;
1176       }
1177       LWIP_DEBUGF(DNS_DEBUG, ("reverse_dns_lookup : found = \"%s\"\n", hostname));
1178 
1179       return ERR_OK;
1180     }
1181   }
1182   return ERR_ARG;
1183 }
1184 #endif /* LWIP_DNS_REVERSE */
1185 
1186 /**
1187  * Compare the "dotted" name "query" with the encoded name "response"
1188  * to make sure an answer from the DNS server matches the current dns_table
1189  * entry (otherwise, answers might arrive late for hostname not on the list
1190  * any more).
1191  *
1192  * For now, this function compares case-insensitive to cope with all kinds of
1193  * servers. This also means that "dns 0x20 bit encoding" must be checked
1194  * externally, if we want to implement it.
1195  * Currently, the request is sent exactly as passed in by he user request.
1196  *
1197  * @param query hostname (not encoded) from the dns_table
1198  * @param p pbuf containing the encoded hostname in the DNS response
1199  * @param start_offset offset into p where the name starts
1200  * @return 0xFFFF: names differ, other: names equal -> offset behind name
1201  */
1202 static u16_t
dns_compare_name(char * query,struct pbuf * p,u16_t start_offset,u16_t allow_compressed_hdr)1203 dns_compare_name(char *query, struct pbuf *p, u16_t start_offset, u16_t allow_compressed_hdr)
1204 {
1205   unsigned char n;
1206   u16_t response_offset = start_offset;
1207   u16_t ret;
1208 
1209   do {
1210     n = (u8_t)pbuf_try_get_at(p, response_offset);
1211     if (!n) {
1212       /* error or overflow */
1213       return 0xFFFF;
1214     }
1215     response_offset++;
1216     /** @see RFC 1035 - 4.1.4. Message compression */
1217     if (((n & 0xc0) == 0xc0)  && (response_offset == (start_offset + 1)) && (allow_compressed_hdr)) {
1218       /* Compressed name: cannot be equal since we don't send them */
1219       n = (u8_t)pbuf_try_get_at(p, response_offset);
1220 
1221       if (!n) {
1222         /* if the offset of compressed hdr is 0, fail from here */
1223         return 0xFFFF;
1224       }
1225 
1226       ret = dns_compare_name(query, p, (u16_t)n, 0);
1227       if (ret == 0xFFFF) {
1228         return 0xFFFF;
1229       } else if (ret == n) {
1230         return start_offset;
1231       } else {
1232         return (u16_t)(response_offset + (u16_t)1);
1233       }
1234     } else if (n > DNS_MAX_LABEL_LENGTH) {
1235       return 0xFFFF;
1236     } else {
1237       /* Not compressed name */
1238       while ((n > 0) && (*query != 0)) {
1239         u8_t c = pbuf_get_at(p, response_offset);
1240         if (lwip_tolower((*query)) != lwip_tolower((u8_t)c)) {
1241           return start_offset;
1242         }
1243         response_offset++;
1244         ++query;
1245         --n;
1246       }
1247       if (*query) {
1248         ++query;
1249       }
1250     }
1251   } while ((pbuf_get_at(p, response_offset) != 0) && (*query != 0));
1252 
1253   if (response_offset > p->tot_len) {
1254     return 0xFFFF;
1255   }
1256   if ((pbuf_get_at(p, response_offset) == 0) && (*query == 0) && (n == 0)) {
1257     return (u16_t)(response_offset + (u16_t)1);
1258   }
1259   return start_offset;
1260 }
1261 
1262 /**
1263  * Walk through a compact encoded DNS name and return the end of the name.
1264  *
1265  * @param p pbuf containing the name
1266  * @param query_idx start index into p pointing to encoded DNS name in the DNS server response
1267  * @return index to end of the name
1268  */
1269 u16_t
dns_skip_name(const struct pbuf * p,u16_t query_idx)1270 dns_skip_name(const struct pbuf *p, u16_t query_idx)
1271 {
1272   int n;
1273   u16_t offset = query_idx;
1274 
1275   do {
1276     n = pbuf_try_get_at(p, offset++);
1277     if ((n < 0) || (offset == 0)) {
1278       return 0xFFFF;
1279     }
1280     /** @see RFC 1035 - 4.1.4. Message compression */
1281     if ((n & 0xc0) == 0xc0) {
1282       /* Compressed name: since we only want to skip it (not check it), stop here */
1283       break;
1284     } else if (n > DNS_MAX_LABEL_LENGTH) {
1285       return 0xFFFF;
1286     } else if (offset + n >= p->tot_len) {
1287       /* Not compressed name */
1288       return 0xFFFF;
1289     } else {
1290       offset = (u16_t)(offset + n);
1291     }
1292     n = pbuf_try_get_at(p, offset);
1293     if (n < 0) {
1294       return 0xFFFF;
1295     }
1296   } while (n != 0);
1297 
1298   if (offset == 0xFFFF) {
1299     return 0xFFFF;
1300   }
1301   return (u16_t)(offset + 1);
1302 }
1303 
1304 /**
1305  * Send a DNS query packet.
1306  *
1307  * @param idx the DNS table entry index for which to send a request
1308  * @return ERR_OK if packet is sent; an err_t indicating the problem otherwise
1309  */
1310 static err_t
dns_send(u8_t idx)1311 dns_send(u8_t idx)
1312 {
1313   err_t err;
1314   struct dns_hdr hdr;
1315   struct dns_query qry;
1316   struct pbuf *p;
1317   u16_t query_idx, copy_len;
1318   const char *hostname, *hostname_part;
1319   u8_t n;
1320   u8_t pcb_idx;
1321   struct dns_table_entry *entry = &dns_table[idx];
1322   const ip_addr_t *dst;
1323   ip_addr_t dns_server_addr;
1324   u16_t dst_port;
1325 
1326   LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n",
1327                           (u16_t)(entry->server_idx), entry->name));
1328   LWIP_ASSERT("dns server out of array", entry->server_idx < DNS_MAX_SERVERS);
1329 
1330   if (!DNS_SERVER_IS_AVAILABLE(entry, entry->server_idx)
1331 #if LWIP_DNS_SUPPORT_MDNS_QUERIES
1332       && !entry->is_mdns
1333 #endif
1334      ) {
1335     /* DNS server not valid anymore, e.g. PPP netif has been shut down */
1336     /* call specified callback function if provided */
1337     dns_call_found(idx, NULL, 0);
1338     /* flush this entry */
1339     entry->retries = DNS_MAX_RETRIES - 1;
1340     return ERR_OK;
1341   }
1342 
1343   // memory overflow (adding const and variable)
1344   if (strlen(entry->name) > DNS_MAX_NAME_LENGTH) {
1345     return ERR_MEM;
1346   }
1347 
1348   /* if here, we have either a new query or a retry on a previous query to process */
1349   p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(SIZEOF_DNS_HDR + strlen(entry->name) + 2 +
1350                                          SIZEOF_DNS_QUERY), PBUF_RAM);
1351   if (p != NULL) {
1352 
1353     /* fill dns header */
1354     memset(&hdr, 0, SIZEOF_DNS_HDR);
1355     hdr.id = lwip_htons(entry->txid);
1356     hdr.flags1 = DNS_FLAG1_RD;
1357     hdr.numquestions = PP_HTONS(1);
1358     pbuf_take(p, &hdr, SIZEOF_DNS_HDR);
1359     hostname = entry->name;
1360     --hostname;
1361 
1362     /* convert hostname into suitable query format. */
1363     query_idx = SIZEOF_DNS_HDR;
1364     do {
1365       ++hostname;
1366       hostname_part = hostname;
1367       for (n = 0; *hostname != '.' && *hostname != 0; ++hostname, ++n) {
1368       }
1369       if (n > DNS_MAX_LABEL_LENGTH) {
1370         (void)pbuf_free(p);
1371         entry->state = DNS_STATE_UNUSED;
1372         return ERR_ARG;
1373       }
1374       copy_len = (u16_t)(hostname - hostname_part);
1375       if (query_idx + n + 1 > 0xFFFF) {
1376         /* u16_t overflow */
1377         goto overflow_return;
1378       }
1379       pbuf_put_at(p, query_idx, n);
1380       pbuf_take_at(p, hostname_part, copy_len, (u16_t)(query_idx + 1));
1381       query_idx = (u16_t)(query_idx + n + 1);
1382     } while (*hostname != 0);
1383     pbuf_put_at(p, query_idx, 0);
1384     query_idx++;
1385 
1386     /* fill dns query */
1387     if (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype)) {
1388       qry.type = PP_HTONS(DNS_RRTYPE_AAAA);
1389     } else {
1390       qry.type = PP_HTONS(DNS_RRTYPE_A);
1391     }
1392     qry.cls = PP_HTONS(DNS_RRCLASS_IN);
1393     pbuf_take_at(p, &qry, SIZEOF_DNS_QUERY, query_idx);
1394 
1395 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0)
1396     pcb_idx = entry->pcb_idx;
1397 #else
1398     pcb_idx = 0;
1399 #endif
1400     /* send dns packet */
1401     LWIP_DEBUGF(DNS_DEBUG, ("sending DNS request ID %d for name \"%s\" to server %d\r\n",
1402                             entry->txid, entry->name, entry->server_idx));
1403 #if LWIP_DNS_SUPPORT_MDNS_QUERIES
1404     if (entry->is_mdns) {
1405       dst_port = DNS_MQUERY_PORT;
1406 #if LWIP_IPV6
1407       if (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype)) {
1408         dst = &dns_mquery_v6group;
1409       }
1410 #endif
1411 #if LWIP_IPV4 && LWIP_IPV6
1412       else
1413 #endif
1414 #if LWIP_IPV4
1415       {
1416         dst = &dns_mquery_v4group;
1417       }
1418 #endif
1419     } else
1420 #endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */
1421     {
1422       dst_port = DNS_SERVER_PORT;
1423       ip_addr_copy(dns_server_addr, dns_servers[entry->server_idx]);
1424 
1425 #if LWIP_IPV4 && LWIP_IPV6
1426       /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
1427       if (IP_IS_V6_VAL(dns_server_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&dns_server_addr))) {
1428         unmap_ipv4_mapped_ipv6(ip_2_ip4(&dns_server_addr), ip_2_ip6(&dns_server_addr));
1429         IP_SET_TYPE_VAL(dns_server_addr, IPADDR_TYPE_V4);
1430       }
1431 #endif /* LWIP_IPV4 && LWIP_IPV6 */
1432       dst = &dns_server_addr;
1433     }
1434     err = udp_sendto(dns_pcbs[pcb_idx], p, dst, dst_port);
1435 
1436     /* free pbuf */
1437     pbuf_free(p);
1438   } else {
1439     err = ERR_MEM;
1440   }
1441 
1442   return err;
1443 overflow_return:
1444   pbuf_free(p);
1445   return ERR_VAL;
1446 }
1447 
1448 #if LWIP_DNS_REVERSE
1449 static err_t
reverse_dns_send(u8_t idx)1450 reverse_dns_send(u8_t idx)
1451 {
1452   err_t err;
1453   struct dns_hdr hdr;
1454   struct dns_query qry;
1455   struct pbuf *p = NULL;
1456   u16_t query_idx;
1457   u16_t copy_len;
1458   const char *encoded_domain = NULL;
1459   const char *encoded_domain_part = NULL;
1460   u8_t n;
1461   u8_t pcb_idx;
1462   struct reverse_dns_table_entry *entry = &reverse_dns_table[idx];
1463   const ip_addr_t *dst = NULL;
1464   ip_addr_t dns_server_addr;
1465   u16_t dst_port;
1466 
1467   LWIP_DEBUGF(DNS_DEBUG, ("reverse_dns_send: dns_servers[%"U16_F"] \"%s\": request\n",
1468               (u16_t)(entry->server_idx), entry->encoded_ip.name));
1469 
1470   LWIP_ASSERT("dns server out of array", entry->server_idx < DNS_MAX_SERVERS);
1471 
1472   if (!DNS_SERVER_IS_AVAILABLE(entry, entry->server_idx)
1473 #if LWIP_DNS_SUPPORT_MDNS_QUERIES
1474       && !entry->is_mdns
1475 #endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */
1476     ) {
1477     /* DNS server not valid anymore, e.g. PPP netif has been shut down */
1478     /* call specified callback function if provided */
1479     reverse_dns_call_found(idx, NULL, 0);
1480     /* flush this entry */
1481     entry->retries = DNS_MAX_RETRIES - 1;
1482     return ERR_OK;
1483   }
1484 
1485   /* if here, we have either a new query or a retry on a previous query to process */
1486   p = pbuf_alloc(PBUF_TRANSPORT,
1487                  (u16_t)(SIZEOF_DNS_HDR + strlen((char *)(entry->encoded_ip.name)) +
1488                  DNS_TYPE_LENGTH + SIZEOF_DNS_QUERY), PBUF_RAM);
1489   if (p == NULL) {
1490     return ERR_MEM;
1491   }
1492 
1493   /* fill dns header */
1494   memset(&hdr, 0, SIZEOF_DNS_HDR);
1495   hdr.id = lwip_htons(entry->txid);
1496   hdr.flags1 = DNS_FLAG1_RD;
1497   hdr.numquestions = PP_HTONS(1);
1498   (void)pbuf_take(p, &hdr, SIZEOF_DNS_HDR);
1499   encoded_domain = (char *)(entry->encoded_ip.name);
1500   --encoded_domain;
1501 
1502   /* convert hostname into suitable query format. */
1503   query_idx = SIZEOF_DNS_HDR;
1504   do {
1505     ++encoded_domain;
1506     encoded_domain_part = encoded_domain;
1507     for (n = 0; (*encoded_domain != '.') && (*encoded_domain != 0); ++encoded_domain, ++n) {
1508     }
1509     copy_len = (u16_t)(encoded_domain - encoded_domain_part);
1510     pbuf_put_at(p, query_idx, n);
1511     (void)pbuf_take_at(p, encoded_domain_part, copy_len, (u16_t)(query_idx + 1));
1512     query_idx = (u16_t)(query_idx + n + 1);
1513   } while (*encoded_domain != 0);
1514   pbuf_put_at(p, query_idx, 0);
1515   query_idx++;
1516 
1517   /* fill dns query */
1518   qry.type = PP_HTONS(DNS_RRTYPE_PTR);
1519   qry.cls = PP_HTONS(DNS_RRCLASS_IN);
1520   (void)pbuf_take_at(p, &qry, SIZEOF_DNS_QUERY, query_idx);
1521 
1522 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0)
1523   pcb_idx = entry->pcb_idx;
1524 #else
1525   pcb_idx = 0;
1526 #endif /* (LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0 */
1527 
1528   /* send dns packet */
1529   LWIP_DEBUGF(DNS_DEBUG, ("sending Reverse DNS request ID %d for name \"%s\" to server %d\r\n",
1530               entry->txid, entry->encoded_ip.name, entry->server_idx));
1531 #if LWIP_DNS_SUPPORT_MDNS_QUERIES
1532   if (entry->is_mdns) {
1533     dst_port = DNS_MQUERY_PORT;
1534   } else
1535 #endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */
1536   {
1537     dst_port = DNS_SERVER_PORT;
1538     ip_addr_copy(dns_server_addr, dns_servers[entry->server_idx]);
1539 
1540 #if LWIP_IPV4 && LWIP_IPV6
1541     /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
1542     if (IP_IS_V6_VAL(dns_server_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&dns_server_addr))) {
1543       unmap_ipv4_mapped_ipv6(ip_2_ip4(&dns_server_addr), ip_2_ip6(&dns_server_addr));
1544       IP_SET_TYPE_VAL(dns_server_addr, IPADDR_TYPE_V4);
1545     }
1546 #endif /* LWIP_IPV4 && LWIP_IPV6 */
1547     dst = &dns_server_addr;
1548   }
1549   err = udp_sendto(dns_pcbs[pcb_idx], p, dst, dst_port);
1550 
1551   /* free pbuf */
1552   (void)pbuf_free(p);
1553 
1554   return err;
1555 }
1556 #endif /* LWIP_DNS_REVERSE */
1557 
1558 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0)
1559 static struct udp_pcb *
dns_alloc_random_port(void)1560 dns_alloc_random_port(void)
1561 {
1562   err_t err;
1563   struct udp_pcb *pcb;
1564 
1565   pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
1566   if (pcb == NULL) {
1567     /* out of memory, have to reuse an existing pcb */
1568     return NULL;
1569   }
1570   do {
1571     u16_t port = (u16_t)DNS_RAND_TXID();
1572     if (DNS_PORT_ALLOWED(port)) {
1573       err = udp_bind(pcb, IP_ANY_TYPE, port);
1574     } else {
1575       /* this port is not allowed, try again */
1576       err = ERR_USE;
1577     }
1578   } while (err == ERR_USE);
1579   if ((err != ERR_OK) && (err != ERR_USE)) {
1580     udp_remove(pcb);
1581     return NULL;
1582   }
1583 #if LWIP_SO_PRIORITY
1584   pcb->priority = LWIP_PKT_PRIORITY_DNS;
1585 #endif /* LWIP_SO_PRIORITY */
1586   udp_recv(pcb, dns_recv, NULL);
1587   return pcb;
1588 }
1589 
1590 /**
1591  * dns_alloc_pcb() - allocates a new pcb (or reuses an existing one) to be used
1592  * for sending a request
1593  *
1594  * @return an index into dns_pcbs
1595  */
1596 static u8_t
dns_alloc_pcb(void)1597 dns_alloc_pcb(void)
1598 {
1599   u8_t i;
1600   u8_t idx;
1601 
1602   for (i = 0; i < DNS_MAX_SOURCE_PORTS; i++) {
1603     if (dns_pcbs[i] == NULL) {
1604       break;
1605     }
1606   }
1607   if (i < DNS_MAX_SOURCE_PORTS) {
1608     dns_pcbs[i] = dns_alloc_random_port();
1609     if (dns_pcbs[i] != NULL) {
1610       /* succeeded */
1611       dns_last_pcb_idx = i;
1612       return i;
1613     }
1614   }
1615   /* if we come here, creating a new UDP pcb failed, so we have to use
1616      an already existing one (so overflow is no issue) */
1617   idx = (u8_t)(dns_last_pcb_idx + 1);
1618   for (i = 0;  i < DNS_MAX_SOURCE_PORTS; i++, idx++) {
1619     if (idx >= DNS_MAX_SOURCE_PORTS) {
1620       idx = 0;
1621     }
1622     if (dns_pcbs[idx] != NULL) {
1623       dns_last_pcb_idx = idx;
1624       return idx;
1625     }
1626   }
1627   return DNS_MAX_SOURCE_PORTS;
1628 }
1629 #endif /* ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) */
1630 
1631 /**
1632  * dns_call_found() - call the found callback and check if there are duplicate
1633  * entries for the given hostname. If there are any, their found callback will
1634  * be called and they will be removed.
1635  *
1636  * @param idx dns table index of the entry that is resolved or removed
1637  * @param addr IP address for the hostname (or NULL on error or memory shortage)
1638  * @param ipaddr_count number of resolved IP address for hostname (or 0 on error or memory shortage)
1639  *        If addr = NULL, then count will contain the error code which will be set to h_errno
1640  *        If count contains error code, then it will be reset to zero after it is set to h_errno
1641  */
1642 static void
dns_call_found(u8_t idx,const ip_addr_t * addr,u32_t ipaddr_count)1643 dns_call_found(u8_t idx, const ip_addr_t *addr, u32_t ipaddr_count)
1644 {
1645 #if ((LWIP_DNS_SECURE & (LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING | LWIP_DNS_SECURE_RAND_SRC_PORT)) != 0)
1646   u32_t i;
1647 #endif /* (LWIP_DNS_SECURE & (LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING | LWIP_DNS_SECURE_RAND_SRC_PORT)) != 0 */
1648 
1649 #if LWIP_IPV4 && LWIP_IPV6
1650   if (addr != NULL) {
1651     /* check that address type matches the request and adapt the table entry */
1652     for (i = 0; i < ipaddr_count; ++i) {
1653       if (IP_IS_V6_VAL(addr[i])) {
1654         LWIP_ASSERT("invalid response", LWIP_DNS_ADDRTYPE_IS_IPV6(dns_table[idx].reqaddrtype));
1655         dns_table[idx].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV6;
1656       } else {
1657         LWIP_ASSERT("invalid response", !LWIP_DNS_ADDRTYPE_IS_IPV6(dns_table[idx].reqaddrtype));
1658         dns_table[idx].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV4;
1659       }
1660     }
1661   }
1662 #endif /* LWIP_IPV4 && LWIP_IPV6 */
1663 
1664 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0)
1665   for (i = 0; i < DNS_MAX_REQUESTS; i++) {
1666     if (dns_requests[i].found && (dns_requests[i].dns_table_idx == idx)) {
1667       (*dns_requests[i].found)(dns_table[idx].name, addr, ipaddr_count, dns_requests[i].arg);
1668       /* flush this entry */
1669       dns_requests[i].found = NULL;
1670     }
1671   }
1672 #else
1673   if (dns_requests[idx].found) {
1674     (*dns_requests[idx].found)(dns_table[idx].name, addr, ipaddr_count, dns_requests[idx].arg);
1675   }
1676   dns_requests[idx].found = NULL;
1677 #endif /* (LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0 */
1678 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0)
1679   /* close the pcb used unless other request are using it */
1680   for (i = 0; i < DNS_MAX_REQUESTS; i++) {
1681     if (i == idx) {
1682       continue; /* only check other requests */
1683     }
1684     if (dns_table[i].state == DNS_STATE_ASKING) {
1685       if (dns_table[i].pcb_idx == dns_table[idx].pcb_idx) {
1686         /* another request is still using the same pcb */
1687         dns_table[idx].pcb_idx = DNS_MAX_SOURCE_PORTS;
1688         break;
1689       }
1690     }
1691   }
1692   if (dns_table[idx].pcb_idx < DNS_MAX_SOURCE_PORTS) {
1693     /* if we come here, the pcb is not used any more and can be removed */
1694     udp_remove(dns_pcbs[dns_table[idx].pcb_idx]);
1695     dns_pcbs[dns_table[idx].pcb_idx] = NULL;
1696     dns_table[idx].pcb_idx = DNS_MAX_SOURCE_PORTS;
1697   }
1698 #endif /* (LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0 */
1699 }
1700 
1701 #if LWIP_DNS_REVERSE
1702 static void
reverse_dns_call_found(u8_t idx,const char * hostname,u32_t name_count)1703 reverse_dns_call_found(u8_t idx, const char *hostname, u32_t name_count)
1704 {
1705 #if ((LWIP_DNS_SECURE & (LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING | LWIP_DNS_SECURE_RAND_SRC_PORT)) != 0)
1706   u8_t i;
1707 #endif /* (LWIP_DNS_SECURE & (LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING | LWIP_DNS_SECURE_RAND_SRC_PORT)) != 0 */
1708 
1709 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0)
1710   for (i = 0; i < DNS_MAX_REQUESTS; i++) {
1711     if (reverse_dns_requests[i].found && (reverse_dns_requests[i].reverse_dns_table_idx == idx)) {
1712       (*reverse_dns_requests[i].found)(hostname, name_count, reverse_dns_requests[i].arg);
1713       /* flush this entry */
1714       reverse_dns_requests[i].found = NULL;
1715     }
1716   }
1717 #else
1718   if (reverse_dns_requests[idx].found) {
1719     (*reverse_dns_requests[idx].found)(hostname, name_count, reverse_dns_requests[idx].arg);
1720   }
1721   reverse_dns_requests[idx].found = NULL;
1722 #endif /* (LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0 */
1723 
1724 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0)
1725   /* close the pcb used unless other request are using it */
1726   for (i = 0; i < DNS_MAX_REQUESTS; i++) {
1727     if (i == idx) {
1728       continue; /* only check other requests */
1729     }
1730     if (reverse_dns_table[i].state == DNS_STATE_ASKING) {
1731       if (reverse_dns_table[i].pcb_idx == reverse_dns_table[idx].pcb_idx) {
1732         /* another request is still using the same pcb */
1733         reverse_dns_table[idx].pcb_idx = DNS_MAX_SOURCE_PORTS;
1734         break;
1735       }
1736     }
1737   }
1738   if (reverse_dns_table[idx].pcb_idx < DNS_MAX_SOURCE_PORTS) {
1739     /* if we come here, the pcb is not used any more and can be removed */
1740     udp_remove(dns_pcbs[reverse_dns_table[idx].pcb_idx]);
1741     dns_pcbs[reverse_dns_table[idx].pcb_idx] = NULL;
1742     reverse_dns_table[idx].pcb_idx = DNS_MAX_SOURCE_PORTS;
1743   }
1744 #endif /* (LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0 */
1745 }
1746 #endif /* LWIP_DNS_REVERSE */
1747 
1748 /* Create a query transmission ID that is unique for all outstanding queries */
1749 static u16_t
dns_create_txid(void)1750 dns_create_txid(void)
1751 {
1752   u16_t txid;
1753   u8_t i;
1754 
1755 again:
1756   txid = (u16_t)DNS_RAND_TXID();
1757 
1758   /* check whether the ID is unique */
1759   for (i = 0; i < DNS_TABLE_SIZE; i++) {
1760     if ((dns_table[i].state == DNS_STATE_ASKING) &&
1761         (dns_table[i].txid == txid)) {
1762       /* ID already used by another pending query */
1763       goto again;
1764     }
1765   }
1766 
1767   return txid;
1768 }
1769 
1770 /* Search for the first DNS server in server list */
1771 static void
dns_find_first_server(void)1772 dns_find_first_server(void)
1773 {
1774   u8_t i;
1775 
1776   for (i = 0; i < DNS_MAX_SERVERS; i++) {
1777     if (!ip_addr_isany(&dns_servers[i])) {
1778       dns_first_server_idx = i;
1779 #if LWIP_DNS_REVERSE
1780       rdns_first_server_idx = i;
1781 #endif /* LWIP_DNS_REVERSE */
1782       return;
1783     }
1784   }
1785   /* if no valid dns server, should be processed in dns_gethostbyname and reverse_dns_getnamebyhost */
1786   /* server will be checked before send requests, so it's fine to return 0 */
1787   return;
1788 }
1789 
1790 /**
1791  * dns_check_entry() - see if entry has not yet been queried and, if so, sends out a query.
1792  * Check an entry in the dns_table:
1793  * - send out query for new entries
1794  * - retry old pending entries on timeout (also with different servers)
1795  * - remove completed entries from the table if their TTL has expired
1796  *
1797  * @param i index of the dns_table entry to check
1798  */
1799 static err_t
dns_check_entry(u8_t i)1800 dns_check_entry(u8_t i)
1801 {
1802   err_t err = ERR_OK;
1803   struct dns_table_entry *entry = NULL;
1804   LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE);
1805 
1806   entry = &dns_table[i];
1807 
1808   switch (entry->state) {
1809     case DNS_STATE_NEW:
1810       /* initialize new entry */
1811       entry->txid = dns_create_txid();
1812       entry->state = DNS_STATE_ASKING;
1813       entry->server_idx = dns_first_server_idx;
1814       entry->server_bitmap = 0;
1815       entry->tmr = 1;
1816       entry->retries = 0;
1817       entry->first_send_time = sys_now();
1818 
1819       /* send DNS packet for this entry */
1820       err = dns_send(i);
1821       if (err != ERR_OK) {
1822         LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING,
1823                     ("dns_send returned error: %s\n", lwip_strerr(err)));
1824       }
1825       break;
1826     case DNS_STATE_ASKING:
1827       /* To ensure that the time gap between the force send routine and periodic send routine is atleast 100ms */
1828       if (sys_now() - (entry->first_send_time) <= 100) {
1829         /* If the gap is less than 100ms, then retransmit the DNS Query in the next tick */
1830         break;
1831       }
1832       if (--entry->tmr == 0) {
1833         if (dns_backupserver_available(entry, DNS_SERVER_SEARCHING_FLAG_SWITCH) == 0) {
1834           /* reset timer for next retry, linearly increasing as retries in each round */
1835           entry->tmr = entry->retries + 1;
1836 
1837           /* send DNS packet for this entry */
1838           err = dns_send(i);
1839           if (err != ERR_OK) {
1840             LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING,
1841                         ("dns_send returned error: %s\n", lwip_strerr(err)));
1842           }
1843         } else {
1844           /* no available DNS server found */
1845           LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": timeout\n", entry->name));
1846           /* call specified callback function if provided */
1847           dns_call_found(i, NULL, TRY_AGAIN);
1848           /* flush this entry */
1849           entry->state = DNS_STATE_UNUSED;
1850           break;
1851         }
1852       }
1853       break;
1854     case DNS_STATE_DONE:
1855       /* if the time to live is nul */
1856       if ((entry->ttl == 0) || (--entry->ttl == 0)) {
1857         LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": flush\n", entry->name));
1858         /* flush this entry, there cannot be any related pending entries in this state */
1859         entry->state = DNS_STATE_UNUSED;
1860       }
1861       break;
1862     case DNS_STATE_UNUSED:
1863       /* nothing to do */
1864       break;
1865     default:
1866       LWIP_ASSERT("unknown dns_table entry state:", 0);
1867       break;
1868   }
1869 
1870   return err;
1871 }
1872 
1873 #if LWIP_DNS_REVERSE
1874 static err_t
reverse_dns_check_entry(u8_t i)1875 reverse_dns_check_entry(u8_t i)
1876 {
1877   err_t err = ERR_OK;
1878   struct reverse_dns_table_entry *entry = NULL;
1879 
1880   LWIP_ASSERT("reverse_dns_check_entry: array index out of bounds\n", i < DNS_TABLE_SIZE);
1881 
1882   entry = &reverse_dns_table[i];
1883 
1884   switch (entry->state) {
1885     case DNS_STATE_NEW:
1886       /* initialize new entry */
1887       entry->txid = dns_create_txid();
1888       entry->state = DNS_STATE_ASKING;
1889       entry->server_idx = rdns_first_server_idx;
1890       entry->server_bitmap = 0;
1891       entry->tmr = 1;
1892       entry->retries = 0;
1893       entry->first_send_time = sys_now();
1894 
1895       /* send DNS packet for this entry */
1896       err = reverse_dns_send(i);
1897       if (err != ERR_OK) {
1898         LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING, ("reverse_dns_send returned error: %s\n", lwip_strerr(err)));
1899       }
1900       break;
1901     case DNS_STATE_ASKING:
1902       /* To ensure that the time gap between the force send routine and periodic send routine is atleast 100ms */
1903       if (sys_now() - (entry->first_send_time) <= 100) {
1904         /* If the gap is less than 100ms, then retransmit the DNS Query in the next tick */
1905         break;
1906       }
1907       if (--entry->tmr == 0) {
1908         if (reverse_dns_backupserver_available(entry, DNS_SERVER_SEARCHING_FLAG_SWITCH) == 0) {
1909           /* reset timer for next retry, linearly increasing as retries in each round */
1910           entry->tmr = entry->retries + 1;
1911 
1912           /* send DNS packet for this entry */
1913           err = reverse_dns_send(i);
1914           if (err != ERR_OK) {
1915             LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING,
1916                         ("reverse_dns_send returned error: %s\n", lwip_strerr(err)));
1917           }
1918         } else {
1919           /* no available DNS server found */
1920           LWIP_DEBUGF(DNS_DEBUG, ("reverse_dns_check_entry: \"%s\": timeout\n", entry->encoded_ip.name));
1921           /* call specified callback function if provided */
1922           reverse_dns_call_found(i, NULL, TRY_AGAIN);
1923           /* flush this entry */
1924           entry->state = DNS_STATE_UNUSED;
1925           break;
1926         }
1927       }
1928       break;
1929     case DNS_STATE_DONE:
1930       /* if the time to live is null */
1931       if ((entry->ttl == 0) || (--entry->ttl == 0)) {
1932         LWIP_DEBUGF(DNS_DEBUG, ("reverse_dns_check_entry: \"%s\": flush\n", entry->encoded_ip.name));
1933         /* flush this entry, there cannot be any related pending entries in this state */
1934         entry->state = DNS_STATE_UNUSED;
1935       }
1936       break;
1937     case DNS_STATE_UNUSED:
1938       /* nothing to do */
1939       break;
1940     default:
1941       LWIP_ASSERT("unknown reverse_dns_table entry state:", 0);
1942       break;
1943   }
1944 
1945   return err;
1946 }
1947 #endif /* LWIP_DNS_REVERSE */
1948 
1949 /**
1950  * Call dns_check_entry for each entry in dns_table - check all entries.
1951  */
1952 static void
dns_check_entries(void)1953 dns_check_entries(void)
1954 {
1955   u8_t i;
1956 
1957   for (i = 0; i < DNS_TABLE_SIZE; ++i) {
1958     (void)dns_check_entry(i);
1959   }
1960 }
1961 
1962 #if LWIP_DNS_REVERSE
1963 /**
1964  * Call dns_check_entry for each entry in dns_table - check all entries.
1965  */
1966 static void
reverse_dns_check_entries(void)1967 reverse_dns_check_entries(void)
1968 {
1969   u8_t i;
1970 
1971   for (i = 0; i < DNS_TABLE_SIZE; ++i) {
1972     (void)reverse_dns_check_entry(i);
1973   }
1974 }
1975 #endif /* LWIP_DNS_REVERSE */
1976 
1977 /**
1978  * Save TTL and call dns_call_found for correct response.
1979  */
1980 static void
dns_correct_response(u8_t idx,u32_t ttl)1981 dns_correct_response(u8_t idx, u32_t ttl)
1982 {
1983   struct dns_table_entry *entry = &dns_table[idx];
1984   entry->state = DNS_STATE_DONE;
1985 
1986   LWIP_DEBUGF(DNS_DEBUG, ("dns_recv:  response = \"%s\"\n", entry->name));
1987 
1988 #ifdef LWIP_DEV_DEBUG
1989   u32_t j;
1990   for (j = 0; j < entry->ipaddr_count; j++) {
1991     ip_addr_debug_print_val(DNS_DEBUG, entry->ipaddr[j]);
1992     LWIP_DEBUGF(DNS_DEBUG, ("\n"));
1993   }
1994 #endif /* LWIP_DEV_DEBUG */
1995 
1996   /* read the answer resource record's TTL, and maximize it if needed */
1997   if (ttl > DNS_MAX_TTL) {
1998     ttl = DNS_MAX_TTL;
1999   }
2000   entry->ttl = ttl;
2001 
2002   /* consider this server as the 'main' fDNS server, for query, try this first */
2003   if (dns_first_server_idx != entry->server_idx) {
2004     dns_first_server_idx = entry->server_idx;
2005   }
2006 
2007   dns_call_found(idx, entry->ipaddr, entry->ipaddr_count);
2008 
2009   if (entry->ttl == 0) {
2010     /* RFC 883, page 29: "Zero values are
2011        interpreted to mean that the RR can only be used for the
2012        transaction in progress, and should not be cached."
2013        -> flush this entry now */
2014     /* entry reused during callback? */
2015     if (entry->state == DNS_STATE_DONE) {
2016       entry->state = DNS_STATE_UNUSED;
2017     }
2018   }
2019 }
2020 
2021 #if LWIP_DNS_REVERSE
2022 /**
2023  * Save TTL and call reverse_dns_call_found for correct response.
2024  */
2025 static void
reverse_dns_correct_response(u8_t idx,u32_t ttl)2026 reverse_dns_correct_response(u8_t idx, u32_t ttl)
2027 {
2028   struct reverse_dns_table_entry *entry = &reverse_dns_table[idx];
2029   entry->state = DNS_STATE_DONE;
2030 
2031   LWIP_DEBUGF(DNS_DEBUG, ("reverse_dns_correct_response: response = \"%s\"\n", entry->name));
2032 
2033   /* read the answer resource record's TTL, and maximize it if needed */
2034   if (ttl > DNS_MAX_TTL) {
2035     ttl = DNS_MAX_TTL;
2036   }
2037   entry->ttl = ttl;
2038 
2039   /* consider this server as the 'main' rDNS server, for next query, try this first */
2040   if (rdns_first_server_idx != entry->server_idx) {
2041     rdns_first_server_idx = entry->server_idx;
2042   }
2043 
2044   reverse_dns_call_found(idx, entry->name, entry->name_count);
2045 
2046   if (entry->ttl == 0) {
2047     /* RFC 883, page 29: "Zero values are
2048        interpreted to mean that the RR can only be used for the
2049        transaction in progress, and should not be cached."
2050        -> flush this entry now */
2051     /* entry reused during callback? */
2052     if (entry->state == DNS_STATE_DONE) {
2053       entry->state = DNS_STATE_UNUSED;
2054     }
2055   }
2056 }
2057 #endif /* LWIP_DNS_REVERSE */
2058 
2059 /*
2060  * Check whether there are other backup DNS servers available to try
2061  * @param
2062  *  - pentry: the forward dns_table entry to check.
2063  *  - flags: Only support DNS_SERVER_SEARCHING_FLAG_SWITCH for now.
2064  *           If DNS_SERVER_SEARCHING_FLAG_SWITCH set, switch to an available DNS server when searching.
2065  *           Otherwise, only seach for an available DNS server without switching to it.
2066  * @Return value:
2067  *  - 0: OK
2068  *  - 1: NOK
2069  */
2070 static u8_t
dns_backupserver_available(struct dns_table_entry * pentry,u8_t flags)2071 dns_backupserver_available(struct dns_table_entry *pentry, u8_t flags)
2072 {
2073   u8_t idx, retries;
2074   u8_t j;
2075 
2076   if (pentry != NULL) {
2077     idx = pentry->server_idx;
2078     retries = pentry->retries;
2079 
2080     for (j = 0; j < DNS_MAX_SERVERS; j++) {
2081       idx = (idx + 1) % DNS_MAX_SERVERS;
2082       if (idx == dns_first_server_idx) {
2083         /* for the next round, increase retry times */
2084         retries++;
2085       }
2086       if (retries >= DNS_MAX_RETRIES) {
2087         /* return NOK if greater than limited retry times */
2088         return 1;
2089       }
2090 
2091       if (DNS_SERVER_IS_AVAILABLE(pentry, idx)
2092 #if LWIP_DNS_SUPPORT_MDNS_QUERIES
2093           && !pentry->is_mdns
2094 #endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */
2095         ) {
2096         if ((flags & DNS_SERVER_SEARCHING_FLAG_SWITCH) != 0) {
2097           /* if here, we need to update the information for this entry.
2098           in other failure cases, no need to do this because the request will stop. */
2099           pentry->server_idx = idx;
2100           pentry->retries = retries;
2101         }
2102         return 0;
2103       }
2104     }
2105   }
2106   return 1;
2107 }
2108 
2109 #if LWIP_DNS_REVERSE
2110 /*
2111  * Check whether there are other backup reverse DNS servers available to try
2112  * @param
2113  *  - rentry: the reverse dns_table entry to check.
2114  *  - flags: Only support DNS_SERVER_SEARCHING_FLAG_SWITCH for now.
2115  *           If DNS_SERVER_SEARCHING_FLAG_SWITCH set, switch to an available DNS server when searching.
2116  *           Otherwise, only seach for an available DNS server without switching to it.
2117  * @Return value:
2118  *  - 0: OK
2119  *  - 1: NOK
2120  */
2121 static u8_t
reverse_dns_backupserver_available(struct reverse_dns_table_entry * rentry,u8_t flags)2122 reverse_dns_backupserver_available(struct reverse_dns_table_entry *rentry, u8_t flags)
2123 {
2124   u8_t idx, retries;
2125   u8_t j;
2126 
2127   if (rentry != NULL) {
2128     idx = rentry->server_idx;
2129     retries = rentry->retries;
2130 
2131     for (j = 0; j < DNS_MAX_SERVERS; j++) {
2132       idx = (idx + 1) % DNS_MAX_SERVERS;
2133       if (idx == rdns_first_server_idx) {
2134         /* for the next round, increase retry times */
2135         retries++;
2136       }
2137       if (retries >= DNS_MAX_RETRIES) {
2138         /* return NOK if greater than limited retry times */
2139         return 1;
2140       }
2141 
2142       if (DNS_SERVER_IS_AVAILABLE(rentry, idx)
2143 #if LWIP_DNS_SUPPORT_MDNS_QUERIES
2144           && !rentry->is_mdns
2145 #endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */
2146         ) {
2147         if ((flags & DNS_SERVER_SEARCHING_FLAG_SWITCH) != 0) {
2148           /* if here, we need to update the information for this entry.
2149           in other failure cases, no need to do this because the request will stop. */
2150           rentry->server_idx = idx;
2151           rentry->retries = retries;
2152         }
2153         return 0;
2154       }
2155     }
2156   }
2157   return 1;
2158 }
2159 #endif /* LWIP_DNS_REVERSE */
2160 
2161 /**
2162  * Receive input function for DNS response packets arriving for the dns UDP pcb.
2163  * It multiplexes to process_forward_dns() and process_reverse_dns() based on the response txn id
2164  */
2165 static void
dns_recv(void * arg,struct udp_pcb * pcb,struct pbuf * p,const ip_addr_t * addr,u16_t port)2166 dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
2167 {
2168   u8_t i;
2169   u16_t txid;
2170   struct dns_hdr hdr;
2171   struct dns_table_entry *forward_entry = NULL;
2172 #if LWIP_DNS_REVERSE
2173   struct reverse_dns_table_entry *reverse_entry = NULL;
2174 #endif /* LWIP_DNS_REVERSE */
2175 
2176   LWIP_UNUSED_ARG(arg);
2177   LWIP_UNUSED_ARG(pcb);
2178   LWIP_UNUSED_ARG(port);
2179 
2180   (void)memset_s(&hdr, sizeof(hdr), 0, sizeof(hdr));
2181 
2182   /* is the dns message big enough ? */
2183   if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY)) {
2184     LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n"));
2185     /* free pbuf and return */
2186     goto ignore_packet;
2187   }
2188 
2189   /* copy dns payload inside static buffer for processing */
2190   if (pbuf_copy_partial(p, &hdr, SIZEOF_DNS_HDR, 0) == SIZEOF_DNS_HDR) {
2191     /* Match the ID in the DNS header with the name table. */
2192     txid = lwip_htons(hdr.id);
2193     for (i = 0; i < DNS_TABLE_SIZE; i++) {
2194       forward_entry = &dns_table[i];
2195 #if LWIP_DNS_REVERSE
2196       reverse_entry = &reverse_dns_table[i];
2197 #endif /* LWIP_DNS_REVERSE */
2198       if ((forward_entry->state == DNS_STATE_ASKING) && (forward_entry->txid == txid)) {
2199         process_forward_dns(p, i, forward_entry, hdr, addr);
2200         break;
2201       }
2202 #if LWIP_DNS_REVERSE
2203       else if ((reverse_entry->state == DNS_STATE_ASKING) && (reverse_entry->txid == txid)) {
2204         process_reverse_dns(p, i, reverse_entry, hdr, addr);
2205         break;
2206       }
2207 #endif /* LWIP_DNS_REVERSE */
2208     }
2209   }
2210 
2211 ignore_packet:
2212   /* deallocate memory and return */
2213   pbuf_free(p);
2214   return;
2215 }
2216 
2217 /**
2218  * Queues a new hostname to resolve and sends out a DNS query for that hostname
2219  *
2220  * @param name the hostname that is to be queried
2221  * @param hostnamelen length of the hostname
2222  * @param found a callback function to be called on success, failure or timeout
2223  * @param callback_arg argument to pass to the callback function
2224  * @return err_t return code.
2225  */
2226 static err_t
dns_enqueue(const char * name,size_t hostnamelen,dns_found_callback found,void * callback_arg,u8_t dns_addrtype LWIP_DNS_ISMDNS_ARG (u8_t is_mdns))2227 dns_enqueue(const char *name, size_t hostnamelen, dns_found_callback found,
2228             void *callback_arg, u8_t dns_addrtype LWIP_DNS_ISMDNS_ARG(u8_t is_mdns))
2229 {
2230   u8_t i;
2231   u8_t lseq, lseqi;
2232   struct dns_table_entry *entry = NULL;
2233   size_t namelen;
2234   struct dns_req_entry *req;
2235   err_t err;
2236 
2237 #if !LWIP_IPV6
2238   LWIP_UNUSED_ARG(dns_addrtype);
2239 #endif
2240 
2241 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0)
2242   u8_t r;
2243   /* check for duplicate entries */
2244   for (i = 0; i < DNS_TABLE_SIZE; i++) {
2245     if ((dns_table[i].state == DNS_STATE_ASKING) &&
2246         (lwip_strnicmp(name, dns_table[i].name, sizeof(dns_table[i].name)) == 0)) {
2247 #if LWIP_IPV4 && LWIP_IPV6
2248       if (dns_table[i].reqaddrtype != dns_addrtype) {
2249         /* requested address types don't match
2250            this can lead to 2 concurrent requests, but mixing the address types
2251            for the same host should not be that common */
2252         continue;
2253       }
2254 #endif /* LWIP_IPV4 && LWIP_IPV6 */
2255       /* this is a duplicate entry, find a free request entry */
2256       for (r = 0; r < DNS_MAX_REQUESTS; r++) {
2257         if (dns_requests[r].found == 0) {
2258           dns_requests[r].found = found;
2259           dns_requests[r].arg = callback_arg;
2260           dns_requests[r].dns_table_idx = i;
2261           LWIP_DNS_SET_ADDRTYPE(dns_requests[r].reqaddrtype, dns_addrtype);
2262           LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": duplicate request\n", name));
2263           return ERR_INPROGRESS;
2264         }
2265       }
2266     }
2267   }
2268   /* no duplicate entries found */
2269 #endif
2270 
2271   /* search an unused entry, or the oldest one */
2272   lseq = 0;
2273   lseqi = DNS_TABLE_SIZE;
2274   for (i = 0; i < DNS_TABLE_SIZE; ++i) {
2275     entry = &dns_table[i];
2276     /* is it an unused entry ? */
2277     if (entry->state == DNS_STATE_UNUSED) {
2278       break;
2279     }
2280     /* check if this is the oldest completed entry */
2281     if (entry->state == DNS_STATE_DONE) {
2282       u8_t age = (u8_t)(dns_seqno - entry->seqno);
2283       if (age > lseq) {
2284         lseq = age;
2285         lseqi = i;
2286       }
2287     }
2288   }
2289 
2290   /* if we don't have found an unused entry, use the oldest completed one */
2291   if (i == DNS_TABLE_SIZE) {
2292     if ((lseqi >= DNS_TABLE_SIZE) || (dns_table[lseqi].state != DNS_STATE_DONE)) {
2293       /* no entry can be used now, table is full */
2294       LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS entries table is full\n", name));
2295       return ERR_MEM;
2296     } else {
2297       /* use the oldest completed one */
2298       i = lseqi;
2299       entry = &dns_table[i];
2300     }
2301   }
2302 
2303 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0)
2304   /* find a free request entry */
2305   req = NULL;
2306   for (r = 0; r < DNS_MAX_REQUESTS; r++) {
2307     if (dns_requests[r].found == NULL) {
2308       req = &dns_requests[r];
2309       break;
2310     }
2311   }
2312   if (req == NULL) {
2313     /* no request entry can be used now, table is full */
2314     LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS request entries table is full\n", name));
2315     return ERR_MEM;
2316   }
2317   req->dns_table_idx = i;
2318 #else
2319   /* in this configuration, the entry index is the same as the request index */
2320   req = &dns_requests[i];
2321 #endif
2322 
2323   /* use this entry */
2324   LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS entry %"U16_F"\n", name, (u16_t)(i)));
2325 
2326   /* fill the entry */
2327   entry->state = DNS_STATE_NEW;
2328   entry->seqno = dns_seqno;
2329   entry->ipaddr_count = 0;
2330   LWIP_DNS_SET_ADDRTYPE(entry->reqaddrtype, dns_addrtype);
2331   LWIP_DNS_SET_ADDRTYPE(req->reqaddrtype, dns_addrtype);
2332   req->found = found;
2333   req->arg   = callback_arg;
2334   namelen = LWIP_MIN(hostnamelen, DNS_MAX_NAME_LENGTH - 1);
2335   MEMCPY(entry->name, name, namelen);
2336   entry->name[namelen] = 0;
2337 
2338 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0)
2339   entry->pcb_idx = dns_alloc_pcb();
2340   if (entry->pcb_idx >= DNS_MAX_SOURCE_PORTS) {
2341     /* failed to get a UDP pcb */
2342     LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": failed to allocate a pcb\n", name));
2343     entry->state = DNS_STATE_UNUSED;
2344     req->found = NULL;
2345     return ERR_MEM;
2346   }
2347   LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS pcb %"U16_F"\n", name, (u16_t)(entry->pcb_idx)));
2348 #endif
2349 
2350 #if LWIP_DNS_SUPPORT_MDNS_QUERIES
2351   entry->is_mdns = is_mdns;
2352 #endif
2353 
2354   dns_seqno++;
2355 
2356   /* force to send query without waiting timer */
2357   err = dns_check_entry(i);
2358 
2359   /* dns query is enqueued */
2360   if (err == ERR_OK) {
2361     return ERR_INPROGRESS;
2362   } else {
2363     entry->state = DNS_STATE_UNUSED;
2364     req->found = NULL;
2365     return err;
2366   }
2367 }
2368 
2369 #if LWIP_DNS_REVERSE
2370 static err_t
reverse_dns_enqueue(const struct reverse_domain * encoded_ip,reverse_dns_found_callback found,void * callback_arg)2371 reverse_dns_enqueue(const struct reverse_domain *encoded_ip, reverse_dns_found_callback found, void *callback_arg)
2372 {
2373   u8_t i;
2374   u8_t lseq, lseqi;
2375   struct reverse_dns_table_entry *entry = NULL;
2376   struct reverse_dns_req_entry *req = NULL;
2377   err_t err;
2378 
2379 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0)
2380   u8_t r;
2381   /* check for duplicate entries */
2382   for (i = 0; i < DNS_TABLE_SIZE; i++) {
2383     if ((reverse_dns_table[i].state == DNS_STATE_ASKING) &&
2384         (lwip_strnicmp((const char*)(encoded_ip->name), (const char*)(reverse_dns_table[i].encoded_ip.name),
2385                        sizeof(reverse_dns_table[i].encoded_ip.name)) == 0)) {
2386       /* this is a duplicate entry, find a free request entry */
2387       for (r = 0; r < DNS_MAX_REQUESTS; r++) {
2388         if (reverse_dns_requests[r].found == NULL) {
2389           reverse_dns_requests[r].found = found;
2390           reverse_dns_requests[r].arg = callback_arg;
2391           reverse_dns_requests[r].reverse_dns_table_idx = i;
2392           LWIP_DEBUGF(DNS_DEBUG, ("reverse_dns_enqueue: \"%s\": duplicate request\n", encoded_ip->name));
2393           return ERR_INPROGRESS;
2394         }
2395       }
2396     }
2397   }
2398   /* no duplicate entries found */
2399 #endif /* (LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0 */
2400 
2401   /* search an unused entry, or the oldest one */
2402   lseq = 0;
2403   lseqi = DNS_TABLE_SIZE;
2404   for (i = 0; i < DNS_TABLE_SIZE; ++i) {
2405     entry = &reverse_dns_table[i];
2406     /* is it an unused entry ? */
2407     if (entry->state == DNS_STATE_UNUSED) {
2408       break;
2409     }
2410     /* check if this is the oldest completed entry */
2411     if (entry->state == DNS_STATE_DONE) {
2412       u8_t age = (u8_t)(dns_seqno - entry->seqno);
2413       if (age > lseq) {
2414         lseq = age;
2415         lseqi = i;
2416       }
2417     }
2418   }
2419 
2420   /* if we don't have found an unused entry, use the oldest completed one */
2421   if (i == DNS_TABLE_SIZE) {
2422     if ((lseqi >= DNS_TABLE_SIZE) || (reverse_dns_table[lseqi].state != DNS_STATE_DONE)) {
2423       /* no entry can be used now, table is full */
2424       LWIP_DEBUGF(DNS_DEBUG, ("reverse_dns_enqueue: \"%s\": Reverse DNS entries table is full\n", encoded_ip->name));
2425       return ERR_MEM;
2426     } else {
2427       /* use the oldest completed one */
2428       i = lseqi;
2429       entry = &reverse_dns_table[i];
2430     }
2431   }
2432 
2433 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0)
2434   /* find a free request entry */
2435   req = NULL;
2436   for (r = 0; r < DNS_MAX_REQUESTS; r++) {
2437     if (reverse_dns_requests[r].found == NULL) {
2438       req = &reverse_dns_requests[r];
2439       break;
2440     }
2441   }
2442   if (req == NULL) {
2443     /* no request entry can be used now, table is full */
2444     LWIP_DEBUGF(DNS_DEBUG, ("reverse_dns_enqueue: \"%s\": DNS request entries table is full\n", encoded_ip->name));
2445     return ERR_MEM;
2446   }
2447   req->reverse_dns_table_idx = i;
2448 #else
2449   /* in this configuration, the entry index is the same as the request index */
2450   req = &reverse_dns_requests[i];
2451 #endif /* (LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0 */
2452 
2453   /* use this entry */
2454   LWIP_DEBUGF(DNS_DEBUG, ("reverse_dns_enqueue: \"%s\": use DNS entry %"U16_F"\n", encoded_ip->name, (u16_t)(i)));
2455 
2456   /* fill the entry */
2457   entry->state = DNS_STATE_NEW;
2458   entry->seqno = dns_seqno;
2459   entry->encoded_ip = *encoded_ip;
2460 
2461   req->found = found;
2462   req->arg   = callback_arg;
2463 
2464 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0)
2465   entry->pcb_idx = dns_alloc_pcb();
2466   if (entry->pcb_idx >= DNS_MAX_SOURCE_PORTS) {
2467     /* failed to get a UDP pcb */
2468     LWIP_DEBUGF(DNS_DEBUG, ("reverse_dns_enqueue: \"%s\": failed to allocate a pcb\n", encoded_ip->name));
2469     entry->state = DNS_STATE_UNUSED;
2470     req->found = NULL;
2471     return ERR_MEM;
2472   }
2473   LWIP_DEBUGF(DNS_DEBUG, ("reverse_dns_enqueue: \"%s\": use DNS pcb %"U16_F"\n",
2474               encoded_ip->name, (u16_t)(entry->pcb_idx)));
2475 #endif /* (LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0 */
2476 
2477 #if LWIP_DNS_SUPPORT_MDNS_QUERIES
2478   entry->is_mdns = 0;
2479 #endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */
2480 
2481   dns_seqno++;
2482 
2483   /* force to send query without waiting timer */
2484   err = reverse_dns_check_entry(i);
2485   /* dns query is enqueued */
2486   if (err == ERR_OK) {
2487     return ERR_INPROGRESS;
2488   } else {
2489     entry->state = DNS_STATE_UNUSED;
2490     req->found = NULL;
2491     return err;
2492   }
2493 }
2494 #endif /* LWIP_DNS_REVERSE */
2495 
2496 /**
2497  * @ingroup dns
2498  * Resolve a hostname (string) into an IP address.
2499  * NON-BLOCKING callback version for use with raw API!!!
2500  *
2501  * Returns immediately with one of err_t return codes:
2502  * - ERR_OK if hostname is a valid IP address string or the host
2503  *   name is already in the local names table.
2504  * - ERR_INPROGRESS enqueue a request to be sent to the DNS server
2505  *   for resolution if no errors are present.
2506  * - ERR_ARG: dns client not initialized or invalid hostname
2507  *
2508  * @param hostname the hostname that is to be queried
2509  * @param addr pointer to a ip_addr_t where to store the address if it is already
2510  *             cached in the dns_table (only valid if ERR_OK is returned!)
2511  * @param count the number of resolved IP Address for hostname
2512  * @param found a callback function to be called on success, failure or timeout (only if
2513  *              ERR_INPROGRESS is returned!)
2514  * @param callback_arg argument to pass to the callback function
2515  * @return a err_t return code.
2516  */
2517 err_t
dns_gethostbyname(const char * hostname,ip_addr_t * addr,u32_t * count,dns_found_callback found,void * callback_arg)2518 dns_gethostbyname(const char *hostname, ip_addr_t *addr, u32_t *count, dns_found_callback found,
2519                   void *callback_arg)
2520 {
2521   return dns_gethostbyname_addrtype(hostname, addr, count, found, callback_arg, LWIP_DNS_ADDRTYPE_DEFAULT);
2522 }
2523 
2524 /**
2525  * @ingroup dns
2526  * Like dns_gethostbyname, but returned address type can be controlled:
2527  * @param hostname the hostname that is to be queried
2528  * @param addr pointer to a ip_addr_t where to store the address if it is already
2529  *             cached in the dns_table (only valid if ERR_OK is returned!)
2530  * @param found a callback function to be called on success, failure or timeout (only if
2531  *              ERR_INPROGRESS is returned!)
2532  * @param callback_arg argument to pass to the callback function
2533  * @param dns_addrtype - LWIP_DNS_ADDRTYPE_IPV4_IPV6: try to resolve IPv4 first, try IPv6 if IPv4 fails only
2534  *                     - LWIP_DNS_ADDRTYPE_IPV6_IPV4: try to resolve IPv6 first, try IPv4 if IPv6 fails only
2535  *                     - LWIP_DNS_ADDRTYPE_IPV4: try to resolve IPv4 only
2536  *                     - LWIP_DNS_ADDRTYPE_IPV6: try to resolve IPv6 only
2537  */
2538 err_t
dns_gethostbyname_addrtype(const char * hostname,ip_addr_t * addr,u32_t * count,dns_found_callback found,void * callback_arg,u8_t dns_addrtype)2539 dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, u32_t *count, dns_found_callback found,
2540                            void *callback_arg, u8_t dns_addrtype)
2541 {
2542   size_t hostnamelen;
2543   int i = 0;
2544   int valid_dns_server = 0;
2545 #if LWIP_DNS_SUPPORT_MDNS_QUERIES
2546   u8_t is_mdns;
2547 #endif
2548   /* not initialized or no valid server yet, or invalid addr pointer
2549    * or invalid hostname or invalid hostname length */
2550   if ((addr == NULL) || (hostname == NULL) || (!hostname[0]) || (count == NULL) || (*count == 0)) {
2551     return ERR_ARG;
2552   }
2553 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) == 0)
2554   if (dns_pcbs[0] == NULL) {
2555     return ERR_ARG;
2556   }
2557 #endif
2558   hostnamelen = strlen(hostname);
2559   if (hostnamelen >= DNS_MAX_NAME_LENGTH) {
2560     LWIP_DEBUGF(DNS_DEBUG, ("dns_gethostbyname: name too long to resolve"));
2561     return ERR_ARG;
2562   }
2563 
2564   /* host name already in octet notation? set ip addr and return ERR_OK */
2565   if (ipaddr_aton(hostname, &addr[0])) {
2566 #if LWIP_IPV4 && LWIP_IPV6
2567     if ((IP_IS_V6(addr) && (dns_addrtype != LWIP_DNS_ADDRTYPE_IPV4)) ||
2568         (IP_IS_V4(addr) && (dns_addrtype != LWIP_DNS_ADDRTYPE_IPV6)))
2569 #endif /* LWIP_IPV4 && LWIP_IPV6 */
2570     {
2571      *count = 1;
2572       return ERR_OK;
2573     }
2574   }
2575 
2576 #if LWIP_HAVE_LOOPIF
2577   if (strcmp(hostname, "localhost") == 0) {
2578     ip_addr_set_loopback(LWIP_DNS_ADDRTYPE_IS_IPV6(dns_addrtype), &addr[0]);
2579     *count = 1;
2580     return ERR_OK;
2581   }
2582 #endif /* LWIP_HAVE_LOOPIF */
2583 
2584   for (i = 0; i < DNS_MAX_SERVERS; i++) {
2585     if (!ip_addr_isany_val(dns_servers[i])) {
2586       valid_dns_server = 1;
2587       break;
2588     }
2589   }
2590 
2591   if (!valid_dns_server) {
2592     LWIP_DEBUGF(DNS_DEBUG, ("dns_gethostbyname: There is no valid DNS server"));
2593     return ERR_CONN;
2594   }
2595 
2596   /* already have this address cached? */
2597   if (dns_lookup(hostname, addr, count LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)) == ERR_OK) {
2598     if (((IP_GET_TYPE(addr) == IPADDR_TYPE_V4) && (dns_addrtype == LWIP_DNS_ADDRTYPE_IPV6)) ||
2599         ((IP_GET_TYPE(addr) == IPADDR_TYPE_V6) && (dns_addrtype == LWIP_DNS_ADDRTYPE_IPV4))) {
2600       return ERR_VAL;
2601     }
2602     return ERR_OK;
2603   }
2604 #if LWIP_IPV4 && LWIP_IPV6
2605   if ((dns_addrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) || (dns_addrtype == LWIP_DNS_ADDRTYPE_IPV6_IPV4)) {
2606     /* fallback to 2nd IP type and try again to lookup */
2607     u8_t fallback;
2608     if (dns_addrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) {
2609       fallback = LWIP_DNS_ADDRTYPE_IPV6;
2610     } else {
2611       fallback = LWIP_DNS_ADDRTYPE_IPV4;
2612     }
2613     if (dns_lookup(hostname, addr, count LWIP_DNS_ADDRTYPE_ARG(fallback)) == ERR_OK) {
2614       return ERR_OK;
2615     }
2616   }
2617 #else /* LWIP_IPV4 && LWIP_IPV6 */
2618   LWIP_UNUSED_ARG(dns_addrtype);
2619 #endif /* LWIP_IPV4 && LWIP_IPV6 */
2620 
2621 #if LWIP_DNS_SUPPORT_MDNS_QUERIES
2622   if (strstr(hostname, ".local") == &hostname[hostnamelen] - 6) {
2623     is_mdns = 1;
2624   } else {
2625     is_mdns = 0;
2626   }
2627 #endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */
2628 
2629   *count = 0;
2630   /* queue query with specified callback */
2631   return dns_enqueue(hostname, hostnamelen, found, callback_arg, dns_addrtype LWIP_DNS_ISMDNS_ARG(is_mdns));
2632 }
2633 
2634 #if LWIP_DNS_REVERSE
2635 err_t
reverse_dns_getnamebyhost(const ip_addr_t * ipaddr,char * hostname,reverse_dns_found_callback found,void * callback_arg)2636 reverse_dns_getnamebyhost(const ip_addr_t *ipaddr, char *hostname, reverse_dns_found_callback found,
2637                           void *callback_arg)
2638 {
2639   int i;
2640   err_t err = 0;
2641   int valid_dns_server = 0;
2642   struct reverse_domain encoded_ip;
2643 
2644   if ((ipaddr == NULL) || (hostname == NULL) || (found == NULL)) {
2645     LWIP_DEBUGF(DNS_DEBUG, ("reverse_dns_getnamebyhost: Invalid parameters\n"));
2646     return ERR_ARG;
2647   }
2648 
2649   if (!IP_IS_V4(ipaddr)
2650 #if LWIP_IPV6
2651    && !IP_IS_V6(ipaddr)
2652 #endif /* LWIP_IPV6 */
2653     ) {
2654     LWIP_DEBUGF(DNS_DEBUG, ("reverse_dns_getnamebyhost: ipaddr not of a valid type\n"));
2655     return ERR_ARG;
2656   }
2657 
2658   if (ip_addr_isloopback(ipaddr)) {
2659     if (strncpy_s(hostname, sizeof(LOCALHOST_STRING), LOCALHOST_STRING, sizeof(LOCALHOST_STRING)-1) != EOK) {
2660       return ERR_MEM;
2661     }
2662     return ERR_OK;
2663   }
2664 
2665   for (i = 0; i < DNS_MAX_SERVERS; i++) {
2666     if (!ip_addr_isany_val(dns_servers[i])) {
2667       valid_dns_server = 1;
2668       break;
2669     }
2670   }
2671 
2672   if (!valid_dns_server) {
2673     LWIP_DEBUGF(DNS_DEBUG, ("reverse_dns_getnamebyhost: There is no valid DNS server\n"));
2674     return ERR_CONN;
2675   }
2676 
2677   if (IP_IS_V4(ipaddr)) {
2678     err = reverse_dns_build_reverse_v4_domain(&encoded_ip, (const ip4_addr_t*)ip_2_ip4(ipaddr));
2679   }
2680 
2681 #if LWIP_IPV6
2682   if (IP_IS_V6(ipaddr)) {
2683     err = reverse_dns_build_reverse_v6_domain(&encoded_ip, (const ip6_addr_t*)ip_2_ip6(ipaddr));
2684   }
2685 #endif /* LWIP_IPV6 */
2686 
2687   if (err != ERR_OK) {
2688     LWIP_DEBUGF(DNS_DEBUG,
2689                 ("reverse_dns_getnamebyhost: Error during conversion from IP-Address to Reverse Domain Name\n"));
2690     return ERR_VAL;
2691   }
2692 
2693   /* already have this IP cached? */
2694   if (reverse_dns_lookup(&encoded_ip, hostname) == ERR_OK) {
2695     return ERR_OK;
2696   }
2697 
2698   return reverse_dns_enqueue(&encoded_ip, found, callback_arg);
2699 }
2700 #endif /* LWIP_DNS_REVERSE */
2701 
2702 static
process_forward_dns(struct pbuf * p,u8_t entry_idx,struct dns_table_entry * entry,struct dns_hdr hdr,const ip_addr_t * addr)2703 void process_forward_dns(struct pbuf *p, u8_t entry_idx, struct dns_table_entry *entry, struct dns_hdr hdr,
2704                          const ip_addr_t *addr)
2705 {
2706   struct dns_answer ans = {0};
2707   struct dns_query qry = {0};
2708   u8_t err_code = 0;
2709   u16_t res_idx;
2710   u16_t ret;
2711   u16_t nquestions, nanswers;
2712   ip_addr_t dns_server_addr;
2713 
2714   entry->ipaddr_count = 0;
2715 
2716   /* We only care about the question(s) and the answers. The authrr
2717       and the extrarr are simply discarded. */
2718   nquestions = lwip_htons(hdr.numquestions);
2719   nanswers   = lwip_htons(hdr.numanswers);
2720 
2721   /* Check for correct response. */
2722   if ((hdr.flags1 & DNS_FLAG1_RESPONSE) == 0) {
2723     LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": not a response\n", entry->name));
2724     goto forward_dns_responseerr;
2725   }
2726 
2727   if ((hdr.flags2 & DNS_FLAG2_ERR_MASK) != 0) {
2728     LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in flags\n", entry->name));
2729 
2730     if ((hdr.flags2 & DNS_FLAG2_ERR_SERVER_FAILURE) != 0) {
2731       LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": Some non-recoverable server failure occured\n", entry->name));
2732       err_code = NO_RECOVERY;
2733     } else if ((hdr.flags2 & DNS_FLAG2_ERR_NAME) != 0) {
2734       LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": No such host name\n", entry->name));
2735       err_code = HOST_NOT_FOUND;
2736     }
2737 
2738     goto forward_dns_responseerr;
2739   }
2740 
2741   if (nquestions != 1) {
2742     LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", entry->name));
2743     goto forward_dns_responseerr;
2744   }
2745 
2746 #if LWIP_DNS_SUPPORT_MDNS_QUERIES
2747   if (!entry->is_mdns)
2748 #endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */
2749   {
2750     /* Check whether response comes from the same network address to which the
2751        question was sent. (RFC 5452) */
2752     ip_addr_copy(dns_server_addr, dns_servers[entry->server_idx]);
2753 #if LWIP_IPV4 && LWIP_IPV6
2754     /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
2755     if (IP_IS_V6_VAL(dns_server_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&dns_server_addr))) {
2756       unmap_ipv4_mapped_ipv6(ip_2_ip4(&dns_server_addr), ip_2_ip6(&dns_server_addr));
2757       IP_SET_TYPE_VAL(dns_server_addr, IPADDR_TYPE_V4);
2758     }
2759 #endif /* LWIP_IPV4 && LWIP_IPV6 */
2760     if (!ip_addr_cmp(addr, &dns_server_addr)) {
2761       goto forward_dns_responseerr;
2762     }
2763   }
2764 
2765   /* Check if the name in the "question" part match with the name in the entry and
2766       skip it if equal. */
2767   res_idx = dns_compare_name(entry->name, p, SIZEOF_DNS_HDR, 1);
2768   if ((res_idx == 0xFFFF) || (res_idx == SIZEOF_DNS_HDR)) {
2769     LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", entry->name));
2770     goto forward_dns_responseerr;
2771   }
2772 
2773   /* check if "question" part matches the request */
2774   if (pbuf_copy_partial(p, &qry, SIZEOF_DNS_QUERY, res_idx) != SIZEOF_DNS_QUERY) {
2775     LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", entry->name));
2776     goto forward_dns_responseerr;
2777   }
2778 
2779   if ((qry.cls != PP_HTONS(DNS_RRCLASS_IN)) ||
2780       (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype) && (qry.type != PP_HTONS(DNS_RRTYPE_AAAA))) ||
2781       (!LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype) && (qry.type != PP_HTONS(DNS_RRTYPE_A)))) {
2782     LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", entry->name));
2783     goto forward_dns_responseerr;
2784   }
2785   /* skip the rest of the "question" part */
2786   res_idx = (u16_t)(res_idx + SIZEOF_DNS_QUERY);
2787 
2788   if (nanswers == 0) {
2789     /* If there are no answers, then there is a chance to fallback based on entry->reqaddrtype */
2790     /* In that case, set err_code only if even the fallback response also has zero answers */
2791     if (!LWIP_DNS_ADDRTYPE_IS_FALLBACK(entry->reqaddrtype)) {
2792       LWIP_DEBUGF(DNS_DEBUG,
2793                   ("dns_recv: \"%s\": Requested name is valid but there is no associated A / AAAA records with it\n",
2794                   entry->name));
2795       err_code = NO_DATA;
2796       goto forward_dns_responseerr;
2797     }
2798   }
2799 
2800   while ((nanswers > 0) && (res_idx < p->tot_len)) {
2801       res_idx = dns_skip_name(p, res_idx);
2802       if (res_idx == 0) {
2803         LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: Insufficient buffer length for parsing domain name\n"));
2804         goto forward_dns_responseerr;
2805       }
2806 
2807     /* Check for IP address type and Internet class. Others are discarded. */
2808     if (pbuf_copy_partial(p, &ans, SIZEOF_DNS_ANSWER, res_idx) != SIZEOF_DNS_ANSWER) {
2809       LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: Parsing DNS answer failed\n"));
2810       goto forward_dns_responseerr;
2811     }
2812     if (res_idx + SIZEOF_DNS_ANSWER > 0xFFFF) {
2813       return;
2814     }
2815     res_idx = (u16_t)(res_idx + SIZEOF_DNS_ANSWER);
2816 
2817   /* Only support a answer whose Internet class is 'the Internet' and IP address type is A or AAAA */
2818     if (ans.cls == PP_HTONS(DNS_RRCLASS_IN)) {
2819 #if LWIP_IPV4
2820       if ((ans.type == PP_HTONS(DNS_RRTYPE_A)) && (ans.len == PP_HTONS(sizeof(ip4_addr_t)))) {
2821 #if LWIP_IPV4 && LWIP_IPV6
2822         if (!LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype))
2823 #endif /* LWIP_IPV4 && LWIP_IPV6 */
2824         {
2825           /* keep the lowest ttl of multiple IP_add */
2826           if (lwip_ntohl(ans.ttl) < entry->ttl) {
2827             entry->ttl = lwip_ntohl(ans.ttl);
2828           }
2829 
2830           /* read the IP address after answer resource record's header */
2831           ret = pbuf_copy_partial(p, &(entry->ipaddr[entry->ipaddr_count]), sizeof(ip4_addr_t), res_idx);
2832 
2833           if (ret != sizeof(ip4_addr_t)) {
2834             LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: Parsing DNS answer failed\n"));
2835             goto forward_dns_responseerr;
2836           }
2837           if (ip4_addr_isany_val(*ip_2_ip4(&entry->ipaddr[entry->ipaddr_count])) ||
2838              ip4_addr_isnone_val(*ip_2_ip4(&entry->ipaddr[entry->ipaddr_count]))) {
2839             err_code = NO_DATA;
2840             goto forward_dns_responseerr;
2841           }
2842           IP_SET_TYPE(&(entry->ipaddr[entry->ipaddr_count]), IPADDR_TYPE_V4);
2843           entry->ipaddr_count++;
2844 
2845           if (entry->ipaddr_count >= DNS_MAX_IPADDR) {
2846             break;
2847           }
2848         }
2849       }
2850 #endif /* LWIP_IPV4 */
2851 #if LWIP_IPV6
2852       if ((ans.type == PP_HTONS(DNS_RRTYPE_AAAA)) && (ans.len == PP_HTONS(sizeof(ip6_addr_t)))) {
2853 #if LWIP_IPV4 && LWIP_IPV6
2854         if (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype))
2855 #endif /* LWIP_IPV4 && LWIP_IPV6 */
2856         {
2857           /* read the IP address after answer resource record's header */
2858           ret = pbuf_copy_partial(p, &(entry->ipaddr[entry->ipaddr_count]), sizeof(ip6_addr_t), res_idx);
2859 
2860           if (ret != sizeof(ip6_addr_t)) {
2861             LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: Parsing DNS answer failed\n"));
2862             goto forward_dns_responseerr;
2863           }
2864           if (ip6_addr_isany_val(*ip_2_ip6(&(entry->ipaddr[entry->ipaddr_count]))) ||
2865               ip6_addr_isnone_val(*ip_2_ip6(&(entry->ipaddr[entry->ipaddr_count])))) {
2866             err_code = NO_DATA;
2867             goto forward_dns_responseerr;
2868           }
2869           IP_SET_TYPE(&(entry->ipaddr[entry->ipaddr_count]), IPADDR_TYPE_V6);
2870           entry->ipaddr_count++;
2871 
2872           if (entry->ipaddr_count >= DNS_MAX_IPADDR) {
2873             break;
2874           }
2875         }
2876       }
2877 #endif /* LWIP_IPV6 */
2878     }
2879   /* skip this answer */
2880     if ((int)(res_idx + lwip_htons(ans.len)) > 0xFFFF) {
2881       goto forward_dns_responseerr;
2882     }
2883     res_idx = (u16_t)(res_idx + lwip_htons(ans.len));
2884     --nanswers;
2885   }
2886 
2887 forward_dns_responseerr:
2888   if (entry->ipaddr_count) {
2889     LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: response =  \"%s\"\n", entry->name));
2890 #ifdef  LWIP_DEV_DEBUG
2891     u16_t i;
2892     for (i = 0; i < entry->ipaddr_count; i++) {
2893       ip_addr_debug_print(DNS_DEBUG, (&(entry->ipaddr[i])));
2894       LWIP_DEBUGF(DNS_DEBUG, ("\n"));
2895     }
2896 #endif /* LWIP_DEV_DEBUG */
2897     dns_correct_response(entry_idx, lwip_ntohl(ans.ttl));
2898   } else {
2899     /* if no IP address extracted from response, mark this server as unavailable */
2900     DNS_SERVER_SET_UNAVAILABLE(entry, entry->server_idx);
2901 
2902     if (dns_backupserver_available(entry, 0) == 0) {
2903       /* if there is another backup DNS server to try, then don't stop the DNS request */
2904       /* retry the next available server immediately */
2905       entry->tmr     = 1;
2906       entry->state   = DNS_STATE_ASKING;
2907       LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": request the other server\n", entry->name));
2908       /* contact next available server for this entry */
2909       (void)dns_check_entry(entry_idx);
2910       return;
2911     }
2912 
2913 #if LWIP_IPV4 && LWIP_IPV6
2914     if (LWIP_DNS_ADDRTYPE_IS_FALLBACK(entry->reqaddrtype)) {
2915       /* if no resolution and backup server is found, then check if there is scope for fallback */
2916       if (entry->reqaddrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) {
2917         /* IPv4 failed, try IPv6 */
2918         dns_table[entry_idx].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV6;
2919       } else {
2920         /* IPv6 failed, try IPv4 */
2921         dns_table[entry_idx].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV4;
2922       }
2923       dns_table[entry_idx].state = DNS_STATE_NEW;
2924       (void)dns_check_entry(entry_idx);
2925       return;
2926     }
2927 #endif
2928 
2929     /* ERROR: call specified callback function with NULL as name to indicate an error */
2930     LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in response with err_code = %d\n", entry->name, err_code));
2931     dns_call_found(entry_idx, NULL, err_code);
2932     /* flush this entry */
2933     dns_table[entry_idx].state = DNS_STATE_UNUSED;
2934   }
2935 }
2936 
2937 #if LWIP_DNS_REVERSE
2938 static void
process_reverse_dns(struct pbuf * p,u8_t entry_idx,struct reverse_dns_table_entry * reverse_entry,struct dns_hdr hdr,const ip_addr_t * addr)2939 process_reverse_dns(struct pbuf *p, u8_t entry_idx, struct reverse_dns_table_entry *reverse_entry, struct dns_hdr hdr,
2940                     const ip_addr_t *addr)
2941 {
2942   struct dns_answer ans = {0};
2943   struct dns_query qry = {0};
2944   ip_addr_t dns_server_addr;
2945   u16_t res_idx;
2946   u16_t ret;
2947   u16_t nquestions, nanswers;
2948   u16_t i;
2949   u8_t err_code = 0;
2950   u8_t length;
2951 
2952   reverse_entry->name_count = 0;
2953 
2954   /* We only care about the question(s) and the answers. The authrr
2955      and the extrarr are simply discarded. */
2956   nquestions = lwip_htons(hdr.numquestions);
2957   nanswers   = lwip_htons(hdr.numanswers);
2958 
2959   /* Check for correct response. */
2960   if ((hdr.flags1 & DNS_FLAG1_RESPONSE) == 0) {
2961     LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": not a response\n", reverse_entry->encoded_ip.name));
2962     goto reverse_dns_responseerr;
2963   }
2964 
2965   if ((hdr.flags2 & DNS_FLAG2_ERR_MASK) != 0) {
2966     LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in flags\n", reverse_entry->encoded_ip.name));
2967 
2968     if ((hdr.flags2 & DNS_FLAG2_ERR_SERVER_FAILURE) != 0) {
2969       LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": Some non-recoverable server failure occured\n",
2970                   reverse_entry->encoded_ip.name));
2971       err_code = NO_RECOVERY;
2972     }
2973 
2974     goto reverse_dns_responseerr;
2975   }
2976 
2977   if (nquestions != 1) {
2978     LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", reverse_entry->encoded_ip.name));
2979     goto reverse_dns_responseerr;
2980   }
2981 
2982   /* Check whether response comes from the same network address to which the
2983      question was sent. (RFC 5452) */
2984   ip_addr_copy(dns_server_addr, dns_servers[reverse_entry->server_idx]);
2985 #if LWIP_IPV4 && LWIP_IPV6
2986   /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
2987   if (IP_IS_V6_VAL(dns_server_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&dns_server_addr))) {
2988     unmap_ipv4_mapped_ipv6(ip_2_ip4(&dns_server_addr), ip_2_ip6(&dns_server_addr));
2989     IP_SET_TYPE_VAL(dns_server_addr, IPADDR_TYPE_V4);
2990   }
2991 #endif /* LWIP_IPV4 && LWIP_IPV6 */
2992   if (!ip_addr_cmp(addr, &dns_server_addr)) {
2993     goto reverse_dns_responseerr;
2994   }
2995 
2996   /* Check if the name in the "question" part match with the name in the entry and
2997      skip it if equal. */
2998   res_idx = dns_compare_name(reverse_entry->encoded_ip.name, p, SIZEOF_DNS_HDR, 1);
2999   if ((res_idx == 0xFFFF) || (res_idx == SIZEOF_DNS_HDR)) {
3000     LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", reverse_entry->encoded_ip.name));
3001     goto reverse_dns_responseerr;
3002   }
3003 
3004   /* check if "question" part matches the request */
3005   if (pbuf_copy_partial(p, &qry, SIZEOF_DNS_QUERY, res_idx) != SIZEOF_DNS_QUERY) {
3006     LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", reverse_entry->encoded_ip.name));
3007     goto reverse_dns_responseerr;
3008   }
3009 
3010   if (qry.type != PP_HTONS(DNS_RRTYPE_PTR)) {
3011     LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to a reverse_dns query\n",
3012                 reverse_entry->encoded_ip.name));
3013     goto reverse_dns_responseerr;
3014   }
3015 
3016   /* skip the rest of the "question" part */
3017   res_idx = (u16_t)(res_idx + SIZEOF_DNS_QUERY);
3018 
3019   while ((nanswers > 0) && (res_idx < p->tot_len)) {
3020       res_idx = dns_skip_name(p, res_idx);
3021       if (res_idx == 0) {
3022         LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: Insufficient buffer length for parsing domain name\n"));
3023         goto reverse_dns_responseerr;
3024     }
3025 
3026     /* Check for IP address type and Internet class. Others are discarded. */
3027     if (pbuf_copy_partial(p, &ans, SIZEOF_DNS_ANSWER, res_idx) != SIZEOF_DNS_ANSWER) {
3028       LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: Parsing Reverse DNS answer failed\n"));
3029       goto reverse_dns_responseerr;
3030     }
3031 
3032     res_idx =  (u16_t)(res_idx + SIZEOF_DNS_ANSWER);
3033 
3034     /* Only need an answer whose Internet class is 'the Internet' and type is 'domain name pointer' */
3035     if (ans.cls == PP_HTONS(DNS_RRCLASS_IN) && ans.type == PP_HTONS(DNS_RRTYPE_PTR)) {
3036       ret = pbuf_copy_partial(p, reverse_entry->name, NI_MAXHOST, res_idx);
3037       if (ret == 0) {
3038         LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: Parsing Reverse DNS answer failed\n"));
3039         goto reverse_dns_responseerr;
3040       }
3041 
3042       /* Hostname received from the network will be of type [3]www[6]google[3]com\0 */
3043       /* Where [] contains the length of the next part */
3044       /* This has to be converted to www.google.com\0 */
3045       i = 0;
3046       while (reverse_entry->name[i] != '\0') {
3047         length = (u8_t)(reverse_entry->name[i++]);
3048         if (length > DNS_MAX_LABEL_LENGTH) {
3049           LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: Malformed Reverse DNS answer received\n"));
3050           goto reverse_dns_responseerr;
3051         }
3052         while (length && reverse_entry->name[i] != '\0') {
3053           reverse_entry->name[i - 1] = reverse_entry->name[i];
3054           ++i;
3055           --length;
3056         }
3057         if (reverse_entry->name[i] != '\0') {
3058           /* Dont insert period if there arent any more characters in the hostname */
3059           reverse_entry->name[i - 1] = '.';
3060         }
3061       }
3062       if (i) {
3063         reverse_entry->name[i - 1] = '\0';
3064       }
3065       reverse_entry->name_count = 1;
3066       break;
3067     }
3068     /* skip this answer */
3069     if ((u32_t)(res_idx + lwip_htons(ans.len)) > 0xFFFFU) {
3070       goto reverse_dns_responseerr;
3071     }
3072     res_idx = (u16_t)(res_idx + lwip_htons(ans.len));
3073     --nanswers;
3074   }
3075 
3076 reverse_dns_responseerr:
3077   if (reverse_entry->name_count) {
3078     LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: response = \"%s\"\n", reverse_entry->name));
3079     reverse_dns_correct_response(entry_idx, lwip_ntohl(ans.ttl));
3080   } else {
3081     /* if no IP address extracted from response, mark this server as unavailable */
3082     DNS_SERVER_SET_UNAVAILABLE(reverse_entry, reverse_entry->server_idx);
3083 
3084     if (reverse_dns_backupserver_available(reverse_entry, 0) == 0) {
3085       /* if there is another backup DNS server to try, then don't stop the DNS request */
3086       /* retry the next available server immediately */
3087       reverse_entry->tmr     = 1;
3088       reverse_entry->state   = DNS_STATE_ASKING;
3089       LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": request the other server\n", reverse_entry->encoded_ip.name));
3090       /* contact next available server for this entry */
3091       (void)reverse_dns_check_entry(entry_idx);
3092       return;
3093     }
3094 
3095     /* ERROR: call specified callback function with NULL as name to indicate an error */
3096     LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in response\n", reverse_entry->encoded_ip.name));
3097     reverse_dns_call_found(entry_idx, NULL, err_code);
3098 
3099     /* flush this entry */
3100     reverse_dns_table[entry_idx].state = DNS_STATE_UNUSED;
3101   }
3102 }
3103 #endif /* LWIP_DNS_REVERSE */
3104 
3105 #endif /* LWIP_DNS */
3106 
3107 #if defined(LWIP_DENY_DNS_SERVER) && (LWIP_DENY_DNS_SERVER)
3108 static struct udp_pcb *dns_server_pcb = NULL;
3109 
3110 static void
dns_server_recv(void * arg,struct udp_pcb * pcb,struct pbuf * p,const ip_addr_t * addr,u16_t port)3111 dns_server_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
3112 {
3113   struct pbuf *send_p = NULL;
3114   struct dns_hdr send_hdr = {0};
3115 
3116   LWIP_UNUSED_ARG(arg);
3117 
3118   LWIP_DEBUGF(DNS_DEBUG, ("dns_server_recv::ip "));
3119   ip_addr_debug_print_val(DNS_DEBUG, *addr);
3120   LWIP_DEBUGF(DNS_DEBUG, ("port %d\r\n", port));
3121 
3122   /* is the dns message big enough ? */
3123   if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY)) {
3124     LWIP_DEBUGF(DNS_DEBUG, ("dns_server_recv: pbuf too small\n"));
3125     /* free pbuf and return */
3126     goto ignore_packet;
3127   }
3128 
3129   if (pbuf_copy_partial(p, &send_hdr, SIZEOF_DNS_HDR, 0) == SIZEOF_DNS_HDR) {
3130     /* set flags */
3131     send_hdr.flags1 |= DNS_FLAG1_RESPONSE;
3132     send_hdr.flags2 = DNS_FLAG2_REFUSE; /* Reply code (Query Refused) */
3133   }
3134 
3135   send_p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(p->tot_len), PBUF_RAM);
3136   if (send_p != NULL) {
3137     memcpy_s(send_p->payload, p->tot_len, p->payload, p->tot_len);
3138     pbuf_take(send_p, &send_hdr, SIZEOF_DNS_HDR);
3139   } else {
3140     LWIP_DEBUGF(DNS_DEBUG, ("dns_server_recv: pbuf alloc fail\n"));
3141     goto ignore_packet;
3142   }
3143 
3144   (void)udp_sendto(pcb, send_p, addr, port);
3145 
3146 ignore_packet:
3147   /* deallocate memory and return */
3148   pbuf_free(p);
3149   return;
3150 }
3151 
dns_server_init(void)3152 void dns_server_init(void)
3153 {
3154   LWIP_DEBUGF(DNS_DEBUG, ("dns_server_init: initializing\n"));
3155 
3156   if (dns_server_pcb == NULL) {
3157     dns_server_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
3158 #if LWIP_SO_PRIORITY
3159     dns_server_pcb->priority = LWIP_PKT_PRIORITY_DNS;
3160 #endif /* LWIP_SO_PRIORITY */
3161     udp_bind(dns_server_pcb, IP_ANY_TYPE, DNS_SERVER_PORT);
3162     udp_recv(dns_server_pcb, dns_server_recv, NULL);
3163   }
3164   LWIP_DEBUGF(DNS_DEBUG, ("dns_server_init\r\n"));
3165 }
3166 
dns_server_deinit(void)3167 void dns_server_deinit(void)
3168 {
3169   if (dns_server_pcb != NULL) {
3170     udp_remove(dns_server_pcb);
3171     dns_server_pcb = NULL;
3172   }
3173 }
3174 #endif /* defined(LWIP_DENY_DNS_SERVER) && (LWIP_DENY_DNS_SERVER) */