The Pedigree Project  0.1
dns.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
56 /*
57  * Port to lwIP from uIP
58  * by Jim Pettinato April 2007
59  *
60  * security fixes and more by Simon Goldschmidt
61  *
62  * uIP version Copyright (c) 2002-2003, Adam Dunkels.
63  * All rights reserved.
64  *
65  * Redistribution and use in source and binary forms, with or without
66  * modification, are permitted provided that the following conditions
67  * are met:
68  * 1. Redistributions of source code must retain the above copyright
69  * notice, this list of conditions and the following disclaimer.
70  * 2. Redistributions in binary form must reproduce the above copyright
71  * notice, this list of conditions and the following disclaimer in the
72  * documentation and/or other materials provided with the distribution.
73  * 3. The name of the author may not be used to endorse or promote
74  * products derived from this software without specific prior
75  * written permission.
76  *
77  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
78  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
79  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
80  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
81  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
82  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
83  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
84  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
85  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
86  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
87  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
88  */
89 
90 /*-----------------------------------------------------------------------------
91  * RFC 1035 - Domain names - implementation and specification
92  * RFC 2181 - Clarifications to the DNS Specification
93  *----------------------------------------------------------------------------*/
94 
100 /*-----------------------------------------------------------------------------
101  * Includes
102  *----------------------------------------------------------------------------*/
103 
104 #include "lwip/opt.h"
105 
106 #if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
107 
108 #include "lwip/def.h"
109 #include "lwip/udp.h"
110 #include "lwip/mem.h"
111 #include "lwip/memp.h"
112 #include "lwip/dns.h"
113 #include "lwip/prot/dns.h"
114 
115 #include <string.h>
116 
118 #ifndef DNS_RAND_TXID
119 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_XID) != 0)
120 #define DNS_RAND_TXID LWIP_RAND
121 #else
122 static u16_t dns_txid;
123 #define DNS_RAND_TXID() (++dns_txid)
124 #endif
125 #endif
126 
128 #ifndef DNS_PORT_ALLOWED
129 #define DNS_PORT_ALLOWED(port) ((port) >= 1024)
130 #endif
131 
133 #ifndef DNS_MAX_RETRIES
134 #define DNS_MAX_RETRIES 4
135 #endif
136 
138 #ifndef DNS_MAX_TTL
139 #define DNS_MAX_TTL 604800
140 #elif DNS_MAX_TTL > 0x7FFFFFFF
141 #error DNS_MAX_TTL must be a positive 32-bit value
142 #endif
143 
144 #if DNS_TABLE_SIZE > 255
145 #error DNS_TABLE_SIZE must fit into an u8_t
146 #endif
147 #if DNS_MAX_SERVERS > 255
148 #error DNS_MAX_SERVERS must fit into an u8_t
149 #endif
150 
151 /* The number of parallel requests (i.e. calls to dns_gethostbyname
152  * that cannot be answered from the DNS table.
153  * This is set to the table size by default.
154  */
155 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0)
156 #ifndef DNS_MAX_REQUESTS
157 #define DNS_MAX_REQUESTS DNS_TABLE_SIZE
158 #else
159 #if DNS_MAX_REQUESTS > 255
160 #error DNS_MAX_REQUESTS must fit into an u8_t
161 #endif
162 #endif
163 #else
164 /* In this configuration, both arrays have to have the same size and are used
165  * like one entry (used/free) */
166 #define DNS_MAX_REQUESTS DNS_TABLE_SIZE
167 #endif
168 
169 /* The number of UDP source ports used in parallel */
170 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0)
171 #ifndef DNS_MAX_SOURCE_PORTS
172 #define DNS_MAX_SOURCE_PORTS DNS_MAX_REQUESTS
173 #else
174 #if DNS_MAX_SOURCE_PORTS > 255
175 #error DNS_MAX_SOURCE_PORTS must fit into an u8_t
176 #endif
177 #endif
178 #else
179 #ifdef DNS_MAX_SOURCE_PORTS
180 #undef DNS_MAX_SOURCE_PORTS
181 #endif
182 #define DNS_MAX_SOURCE_PORTS 1
183 #endif
184 
185 #if LWIP_IPV4 && LWIP_IPV6
186 #define LWIP_DNS_ADDRTYPE_IS_IPV6(t) (((t) == LWIP_DNS_ADDRTYPE_IPV6_IPV4) || ((t) == LWIP_DNS_ADDRTYPE_IPV6))
187 #define LWIP_DNS_ADDRTYPE_MATCH_IP(t, ip) (IP_IS_V6_VAL(ip) ? LWIP_DNS_ADDRTYPE_IS_IPV6(t) : (!LWIP_DNS_ADDRTYPE_IS_IPV6(t)))
188 #define LWIP_DNS_ADDRTYPE_ARG(x) , x
189 #define LWIP_DNS_ADDRTYPE_ARG_OR_ZERO(x) x
190 #define LWIP_DNS_SET_ADDRTYPE(x, y) do { x = y; } while(0)
191 #else
192 #if LWIP_IPV6
193 #define LWIP_DNS_ADDRTYPE_IS_IPV6(t) 1
194 #else
195 #define LWIP_DNS_ADDRTYPE_IS_IPV6(t) 0
196 #endif
197 #define LWIP_DNS_ADDRTYPE_MATCH_IP(t, ip) 1
198 #define LWIP_DNS_ADDRTYPE_ARG(x)
199 #define LWIP_DNS_ADDRTYPE_ARG_OR_ZERO(x) 0
200 #define LWIP_DNS_SET_ADDRTYPE(x, y)
201 #endif /* LWIP_IPV4 && LWIP_IPV6 */
202 
203 #if LWIP_DNS_SUPPORT_MDNS_QUERIES
204 #define LWIP_DNS_ISMDNS_ARG(x) , x
205 #else
206 #define LWIP_DNS_ISMDNS_ARG(x)
207 #endif
208 
211 struct dns_query {
212  /* DNS query record starts with either a domain name or a pointer
213  to a name already present somewhere in the packet. */
214  u16_t type;
215  u16_t cls;
216 };
217 #define SIZEOF_DNS_QUERY 4
218 
221 struct dns_answer {
222  /* DNS answer record starts with either a domain name or a pointer
223  to a name already present somewhere in the packet. */
224  u16_t type;
225  u16_t cls;
226  u32_t ttl;
227  u16_t len;
228 };
229 #define SIZEOF_DNS_ANSWER 10
230 /* maximum allowed size for the struct due to non-packed */
231 #define SIZEOF_DNS_ANSWER_ASSERT 12
232 
233 /* DNS table entry states */
234 typedef enum {
235  DNS_STATE_UNUSED = 0,
236  DNS_STATE_NEW = 1,
237  DNS_STATE_ASKING = 2,
238  DNS_STATE_DONE = 3
239 } dns_state_enum_t;
240 
242 struct dns_table_entry {
243  u32_t ttl;
244  ip_addr_t ipaddr;
245  u16_t txid;
246  u8_t state;
247  u8_t server_idx;
248  u8_t tmr;
249  u8_t retries;
250  u8_t seqno;
251 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0)
252  u8_t pcb_idx;
253 #endif
254  char name[DNS_MAX_NAME_LENGTH];
255 #if LWIP_IPV4 && LWIP_IPV6
256  u8_t reqaddrtype;
257 #endif /* LWIP_IPV4 && LWIP_IPV6 */
258 #if LWIP_DNS_SUPPORT_MDNS_QUERIES
259  u8_t is_mdns;
260 #endif
261 };
262 
265 struct dns_req_entry {
266  /* pointer to callback on DNS query done */
267  dns_found_callback found;
268  /* argument passed to the callback function */
269  void *arg;
270 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0)
271  u8_t dns_table_idx;
272 #endif
273 #if LWIP_IPV4 && LWIP_IPV6
274  u8_t reqaddrtype;
275 #endif /* LWIP_IPV4 && LWIP_IPV6 */
276 };
277 
278 #if DNS_LOCAL_HOSTLIST
279 
280 #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
281 
283 static struct local_hostlist_entry *local_hostlist_dynamic;
284 #else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
285 
288 #ifndef DNS_LOCAL_HOSTLIST_STORAGE_PRE
289 #define DNS_LOCAL_HOSTLIST_STORAGE_PRE static
290 #endif /* DNS_LOCAL_HOSTLIST_STORAGE_PRE */
291 
293 #ifndef DNS_LOCAL_HOSTLIST_STORAGE_POST
294 #define DNS_LOCAL_HOSTLIST_STORAGE_POST
295 #endif /* DNS_LOCAL_HOSTLIST_STORAGE_POST */
296 DNS_LOCAL_HOSTLIST_STORAGE_PRE struct local_hostlist_entry local_hostlist_static[]
297  DNS_LOCAL_HOSTLIST_STORAGE_POST = DNS_LOCAL_HOSTLIST_INIT;
298 
299 #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
300 
301 static void dns_init_local(void);
302 static err_t dns_lookup_local(const char *hostname, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype));
303 #endif /* DNS_LOCAL_HOSTLIST */
304 
305 
306 /* forward declarations */
307 static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port);
308 static void dns_check_entries(void);
309 static void dns_call_found(u8_t idx, ip_addr_t* addr);
310 
311 /*-----------------------------------------------------------------------------
312  * Globals
313  *----------------------------------------------------------------------------*/
314 
315 /* DNS variables */
316 static struct udp_pcb *dns_pcbs[DNS_MAX_SOURCE_PORTS];
317 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0)
318 static u8_t dns_last_pcb_idx;
319 #endif
320 static u8_t dns_seqno;
321 static struct dns_table_entry dns_table[DNS_TABLE_SIZE];
322 static struct dns_req_entry dns_requests[DNS_MAX_REQUESTS];
323 static ip_addr_t dns_servers[DNS_MAX_SERVERS];
324 
325 #if LWIP_IPV4
326 const ip_addr_t dns_mquery_v4group = DNS_MQUERY_IPV4_GROUP_INIT;
327 #endif /* LWIP_IPV4 */
328 #if LWIP_IPV6
329 const ip_addr_t dns_mquery_v6group = DNS_MQUERY_IPV6_GROUP_INIT;
330 #endif /* LWIP_IPV6 */
331 
336 void
337 dns_init(void)
338 {
339 #ifdef DNS_SERVER_ADDRESS
340  /* initialize default DNS server address */
341  ip_addr_t dnsserver;
342  DNS_SERVER_ADDRESS(&dnsserver);
343  dns_setserver(0, &dnsserver);
344 #endif /* DNS_SERVER_ADDRESS */
345 
346  LWIP_ASSERT("sanity check SIZEOF_DNS_QUERY",
347  sizeof(struct dns_query) == SIZEOF_DNS_QUERY);
348  LWIP_ASSERT("sanity check SIZEOF_DNS_ANSWER",
349  sizeof(struct dns_answer) <= SIZEOF_DNS_ANSWER_ASSERT);
350 
351  LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n"));
352 
353  /* if dns client not yet initialized... */
354 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) == 0)
355  if (dns_pcbs[0] == NULL) {
356  dns_pcbs[0] = udp_new_ip_type(IPADDR_TYPE_ANY);
357  LWIP_ASSERT("dns_pcbs[0] != NULL", dns_pcbs[0] != NULL);
358 
359  /* initialize DNS table not needed (initialized to zero since it is a
360  * global variable) */
361  LWIP_ASSERT("For implicit initialization to work, DNS_STATE_UNUSED needs to be 0",
362  DNS_STATE_UNUSED == 0);
363 
364  /* initialize DNS client */
365  udp_bind(dns_pcbs[0], IP_ANY_TYPE, 0);
366  udp_recv(dns_pcbs[0], dns_recv, NULL);
367  }
368 #endif
369 
370 #if DNS_LOCAL_HOSTLIST
371  dns_init_local();
372 #endif
373 }
374 
382 void
383 dns_setserver(u8_t numdns, const ip_addr_t *dnsserver)
384 {
385  if (numdns < DNS_MAX_SERVERS) {
386  if (dnsserver != NULL) {
387  dns_servers[numdns] = (*dnsserver);
388  } else {
389  dns_servers[numdns] = *IP_ADDR_ANY;
390  }
391  }
392 }
393 
402 const ip_addr_t*
403 dns_getserver(u8_t numdns)
404 {
405  if (numdns < DNS_MAX_SERVERS) {
406  return &dns_servers[numdns];
407  } else {
408  return IP_ADDR_ANY;
409  }
410 }
411 
416 void
417 dns_tmr(void)
418 {
419  LWIP_DEBUGF(DNS_DEBUG, ("dns_tmr: dns_check_entries\n"));
420  dns_check_entries();
421 }
422 
423 #if DNS_LOCAL_HOSTLIST
424 static void
425 dns_init_local(void)
426 {
427 #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT)
428  size_t i;
429  struct local_hostlist_entry *entry;
430  /* Dynamic: copy entries from DNS_LOCAL_HOSTLIST_INIT to list */
431  struct local_hostlist_entry local_hostlist_init[] = DNS_LOCAL_HOSTLIST_INIT;
432  size_t namelen;
433  for (i = 0; i < LWIP_ARRAYSIZE(local_hostlist_init); i++) {
434  struct local_hostlist_entry *init_entry = &local_hostlist_init[i];
435  LWIP_ASSERT("invalid host name (NULL)", init_entry->name != NULL);
436  namelen = strlen(init_entry->name);
437  LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN);
438  entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST);
439  LWIP_ASSERT("mem-error in dns_init_local", entry != NULL);
440  if (entry != NULL) {
441  char* entry_name = (char*)entry + sizeof(struct local_hostlist_entry);
442  MEMCPY(entry_name, init_entry->name, namelen);
443  entry_name[namelen] = 0;
444  entry->name = entry_name;
445  entry->addr = init_entry->addr;
446  entry->next = local_hostlist_dynamic;
447  local_hostlist_dynamic = entry;
448  }
449  }
450 #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) */
451 }
452 
461 size_t
462 dns_local_iterate(dns_found_callback iterator_fn, void *iterator_arg)
463 {
464  size_t i;
465 #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
466  struct local_hostlist_entry *entry = local_hostlist_dynamic;
467  i = 0;
468  while (entry != NULL) {
469  if (iterator_fn != NULL) {
470  iterator_fn(entry->name, &entry->addr, iterator_arg);
471  }
472  i++;
473  entry = entry->next;
474  }
475 #else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
476  for (i = 0; i < LWIP_ARRAYSIZE(local_hostlist_static); i++) {
477  if (iterator_fn != NULL) {
478  iterator_fn(local_hostlist_static[i].name, &local_hostlist_static[i].addr, iterator_arg);
479  }
480  }
481 #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
482  return i;
483 }
484 
498 err_t
499 dns_local_lookup(const char *hostname, ip_addr_t *addr, u8_t dns_addrtype)
500 {
501  LWIP_UNUSED_ARG(dns_addrtype);
502  return dns_lookup_local(hostname, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype));
503 }
504 
505 /* Internal implementation for dns_local_lookup and dns_lookup */
506 static err_t
507 dns_lookup_local(const char *hostname, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype))
508 {
509 #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
510  struct local_hostlist_entry *entry = local_hostlist_dynamic;
511  while (entry != NULL) {
512  if ((lwip_stricmp(entry->name, hostname) == 0) &&
513  LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, entry->addr)) {
514  if (addr) {
515  ip_addr_copy(*addr, entry->addr);
516  }
517  return ERR_OK;
518  }
519  entry = entry->next;
520  }
521 #else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
522  size_t i;
523  for (i = 0; i < LWIP_ARRAYSIZE(local_hostlist_static); i++) {
524  if ((lwip_stricmp(local_hostlist_static[i].name, hostname) == 0) &&
525  LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, local_hostlist_static[i].addr)) {
526  if (addr) {
527  ip_addr_copy(*addr, local_hostlist_static[i].addr);
528  }
529  return ERR_OK;
530  }
531  }
532 #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
533  return ERR_ARG;
534 }
535 
536 #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
537 
547 int
548 dns_local_removehost(const char *hostname, const ip_addr_t *addr)
549 {
550  int removed = 0;
551  struct local_hostlist_entry *entry = local_hostlist_dynamic;
552  struct local_hostlist_entry *last_entry = NULL;
553  while (entry != NULL) {
554  if (((hostname == NULL) || !lwip_stricmp(entry->name, hostname)) &&
555  ((addr == NULL) || ip_addr_cmp(&entry->addr, addr))) {
556  struct local_hostlist_entry *free_entry;
557  if (last_entry != NULL) {
558  last_entry->next = entry->next;
559  } else {
560  local_hostlist_dynamic = entry->next;
561  }
562  free_entry = entry;
563  entry = entry->next;
564  memp_free(MEMP_LOCALHOSTLIST, free_entry);
565  removed++;
566  } else {
567  last_entry = entry;
568  entry = entry->next;
569  }
570  }
571  return removed;
572 }
573 
583 err_t
584 dns_local_addhost(const char *hostname, const ip_addr_t *addr)
585 {
586  struct local_hostlist_entry *entry;
587  size_t namelen;
588  char* entry_name;
589  LWIP_ASSERT("invalid host name (NULL)", hostname != NULL);
590  namelen = strlen(hostname);
591  LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN);
592  entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST);
593  if (entry == NULL) {
594  return ERR_MEM;
595  }
596  entry_name = (char*)entry + sizeof(struct local_hostlist_entry);
597  MEMCPY(entry_name, hostname, namelen);
598  entry_name[namelen] = 0;
599  entry->name = entry_name;
600  ip_addr_copy(entry->addr, *addr);
601  entry->next = local_hostlist_dynamic;
602  local_hostlist_dynamic = entry;
603  return ERR_OK;
604 }
605 #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC*/
606 #endif /* DNS_LOCAL_HOSTLIST */
607 
623 static err_t
624 dns_lookup(const char *name, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype))
625 {
626  u8_t i;
627 #if DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN)
628 #endif /* DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN) */
629 #if DNS_LOCAL_HOSTLIST
630  if (dns_lookup_local(name, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)) == ERR_OK) {
631  return ERR_OK;
632  }
633 #endif /* DNS_LOCAL_HOSTLIST */
634 #ifdef DNS_LOOKUP_LOCAL_EXTERN
635  if (DNS_LOOKUP_LOCAL_EXTERN(name, addr, LWIP_DNS_ADDRTYPE_ARG_OR_ZERO(dns_addrtype)) == ERR_OK) {
636  return ERR_OK;
637  }
638 #endif /* DNS_LOOKUP_LOCAL_EXTERN */
639 
640  /* Walk through name list, return entry if found. If not, return NULL. */
641  for (i = 0; i < DNS_TABLE_SIZE; ++i) {
642  if ((dns_table[i].state == DNS_STATE_DONE) &&
643  (lwip_strnicmp(name, dns_table[i].name, sizeof(dns_table[i].name)) == 0) &&
644  LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, dns_table[i].ipaddr)) {
645  LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name));
646  ip_addr_debug_print(DNS_DEBUG, &(dns_table[i].ipaddr));
647  LWIP_DEBUGF(DNS_DEBUG, ("\n"));
648  if (addr) {
649  ip_addr_copy(*addr, dns_table[i].ipaddr);
650  }
651  return ERR_OK;
652  }
653  }
654 
655  return ERR_ARG;
656 }
657 
669 static u16_t
670 dns_compare_name(const char *query, struct pbuf* p, u16_t start_offset)
671 {
672  int n;
673  u16_t response_offset = start_offset;
674 
675  do {
676  n = pbuf_try_get_at(p, response_offset++);
677  if (n < 0) {
678  return 0xFFFF;
679  }
681  if ((n & 0xc0) == 0xc0) {
682  /* Compressed name: cannot be equal since we don't send them */
683  return 0xFFFF;
684  } else {
685  /* Not compressed name */
686  while (n > 0) {
687  int c = pbuf_try_get_at(p, response_offset);
688  if (c < 0) {
689  return 0xFFFF;
690  }
691  if ((*query) != (u8_t)c) {
692  return 0xFFFF;
693  }
694  ++response_offset;
695  ++query;
696  --n;
697  }
698  ++query;
699  }
700  n = pbuf_try_get_at(p, response_offset);
701  if (n < 0) {
702  return 0xFFFF;
703  }
704  } while (n != 0);
705 
706  return response_offset + 1;
707 }
708 
716 static u16_t
717 dns_skip_name(struct pbuf* p, u16_t query_idx)
718 {
719  int n;
720  u16_t offset = query_idx;
721 
722  do {
723  n = pbuf_try_get_at(p, offset++);
724  if (n < 0) {
725  return 0xFFFF;
726  }
728  if ((n & 0xc0) == 0xc0) {
729  /* Compressed name: since we only want to skip it (not check it), stop here */
730  break;
731  } else {
732  /* Not compressed name */
733  if (offset + n >= p->tot_len) {
734  return 0xFFFF;
735  }
736  offset = (u16_t)(offset + n);
737  }
738  n = pbuf_try_get_at(p, offset);
739  if (n < 0) {
740  return 0xFFFF;
741  }
742  } while (n != 0);
743 
744  return offset + 1;
745 }
746 
753 static err_t
754 dns_send(u8_t idx)
755 {
756  err_t err;
757  struct dns_hdr hdr;
758  struct dns_query qry;
759  struct pbuf *p;
760  u16_t query_idx, copy_len;
761  const char *hostname, *hostname_part;
762  u8_t n;
763  u8_t pcb_idx;
764  struct dns_table_entry* entry = &dns_table[idx];
765 
766  LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n",
767  (u16_t)(entry->server_idx), entry->name));
768  LWIP_ASSERT("dns server out of array", entry->server_idx < DNS_MAX_SERVERS);
769  if (ip_addr_isany_val(dns_servers[entry->server_idx])
771  && !entry->is_mdns
772 #endif
773  ) {
774  /* DNS server not valid anymore, e.g. PPP netif has been shut down */
775  /* call specified callback function if provided */
776  dns_call_found(idx, NULL);
777  /* flush this entry */
778  entry->state = DNS_STATE_UNUSED;
779  return ERR_OK;
780  }
781 
782  /* if here, we have either a new query or a retry on a previous query to process */
783  p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(SIZEOF_DNS_HDR + strlen(entry->name) + 2 +
784  SIZEOF_DNS_QUERY), PBUF_RAM);
785  if (p != NULL) {
786  const ip_addr_t* dst;
787  u16_t dst_port;
788  /* fill dns header */
789  memset(&hdr, 0, SIZEOF_DNS_HDR);
790  hdr.id = lwip_htons(entry->txid);
791  hdr.flags1 = DNS_FLAG1_RD;
792  hdr.numquestions = PP_HTONS(1);
793  pbuf_take(p, &hdr, SIZEOF_DNS_HDR);
794  hostname = entry->name;
795  --hostname;
796 
797  /* convert hostname into suitable query format. */
798  query_idx = SIZEOF_DNS_HDR;
799  do {
800  ++hostname;
801  hostname_part = hostname;
802  for (n = 0; *hostname != '.' && *hostname != 0; ++hostname) {
803  ++n;
804  }
805  copy_len = (u16_t)(hostname - hostname_part);
806  pbuf_put_at(p, query_idx, n);
807  pbuf_take_at(p, hostname_part, copy_len, query_idx + 1);
808  query_idx += n + 1;
809  } while (*hostname != 0);
810  pbuf_put_at(p, query_idx, 0);
811  query_idx++;
812 
813  /* fill dns query */
814  if (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype)) {
815  qry.type = PP_HTONS(DNS_RRTYPE_AAAA);
816  } else {
817  qry.type = PP_HTONS(DNS_RRTYPE_A);
818  }
819  qry.cls = PP_HTONS(DNS_RRCLASS_IN);
820  pbuf_take_at(p, &qry, SIZEOF_DNS_QUERY, query_idx);
821 
822 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0)
823  pcb_idx = entry->pcb_idx;
824 #else
825  pcb_idx = 0;
826 #endif
827  /* send dns packet */
828  LWIP_DEBUGF(DNS_DEBUG, ("sending DNS request ID %d for name \"%s\" to server %d\r\n",
829  entry->txid, entry->name, entry->server_idx));
830 #if LWIP_DNS_SUPPORT_MDNS_QUERIES
831  if (entry->is_mdns) {
832  dst_port = DNS_MQUERY_PORT;
833 #if LWIP_IPV6
834  if (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype))
835  {
836  dst = &dns_mquery_v6group;
837  }
838 #endif
839 #if LWIP_IPV4 && LWIP_IPV6
840  else
841 #endif
842 #if LWIP_IPV4
843  {
844  dst = &dns_mquery_v4group;
845  }
846 #endif
847  } else
848 #endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */
849  {
850  dst_port = DNS_SERVER_PORT;
851  dst = &dns_servers[entry->server_idx];
852  }
853  err = udp_sendto(dns_pcbs[pcb_idx], p, dst, dst_port);
854 
855  /* free pbuf */
856  pbuf_free(p);
857  } else {
858  err = ERR_MEM;
859  }
860 
861  return err;
862 }
863 
864 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0)
865 static struct udp_pcb*
866 dns_alloc_random_port(void)
867 {
868  err_t err;
869  struct udp_pcb* ret;
870 
871  ret = udp_new_ip_type(IPADDR_TYPE_ANY);
872  if (ret == NULL) {
873  /* out of memory, have to reuse an existing pcb */
874  return NULL;
875  }
876  do {
877  u16_t port = (u16_t)DNS_RAND_TXID();
878  if (!DNS_PORT_ALLOWED(port)) {
879  /* this port is not allowed, try again */
880  err = ERR_USE;
881  continue;
882  }
883  err = udp_bind(ret, IP_ANY_TYPE, port);
884  } while (err == ERR_USE);
885  if (err != ERR_OK) {
886  udp_remove(ret);
887  return NULL;
888  }
889  udp_recv(ret, dns_recv, NULL);
890  return ret;
891 }
892 
899 static u8_t
900 dns_alloc_pcb(void)
901 {
902  u8_t i;
903  u8_t idx;
904 
905  for (i = 0; i < DNS_MAX_SOURCE_PORTS; i++) {
906  if (dns_pcbs[i] == NULL) {
907  break;
908  }
909  }
910  if (i < DNS_MAX_SOURCE_PORTS) {
911  dns_pcbs[i] = dns_alloc_random_port();
912  if (dns_pcbs[i] != NULL) {
913  /* succeeded */
914  dns_last_pcb_idx = i;
915  return i;
916  }
917  }
918  /* if we come here, creating a new UDP pcb failed, so we have to use
919  an already existing one */
920  for (i = 0, idx = dns_last_pcb_idx + 1; i < DNS_MAX_SOURCE_PORTS; i++, idx++) {
921  if (idx >= DNS_MAX_SOURCE_PORTS) {
922  idx = 0;
923  }
924  if (dns_pcbs[idx] != NULL) {
925  dns_last_pcb_idx = idx;
926  return idx;
927  }
928  }
929  return DNS_MAX_SOURCE_PORTS;
930 }
931 #endif /* ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) */
932 
941 static void
942 dns_call_found(u8_t idx, ip_addr_t* addr)
943 {
944 #if ((LWIP_DNS_SECURE & (LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING | LWIP_DNS_SECURE_RAND_SRC_PORT)) != 0)
945  u8_t i;
946 #endif
947 
948 #if LWIP_IPV4 && LWIP_IPV6
949  if (addr != NULL) {
950  /* check that address type matches the request and adapt the table entry */
951  if (IP_IS_V6_VAL(*addr)) {
952  LWIP_ASSERT("invalid response", LWIP_DNS_ADDRTYPE_IS_IPV6(dns_table[idx].reqaddrtype));
953  dns_table[idx].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV6;
954  } else {
955  LWIP_ASSERT("invalid response", !LWIP_DNS_ADDRTYPE_IS_IPV6(dns_table[idx].reqaddrtype));
956  dns_table[idx].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV4;
957  }
958  }
959 #endif /* LWIP_IPV4 && LWIP_IPV6 */
960 
961 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0)
962  for (i = 0; i < DNS_MAX_REQUESTS; i++) {
963  if (dns_requests[i].found && (dns_requests[i].dns_table_idx == idx)) {
964  (*dns_requests[i].found)(dns_table[idx].name, addr, dns_requests[i].arg);
965  /* flush this entry */
966  dns_requests[i].found = NULL;
967  }
968  }
969 #else
970  if (dns_requests[idx].found) {
971  (*dns_requests[idx].found)(dns_table[idx].name, addr, dns_requests[idx].arg);
972  }
973  dns_requests[idx].found = NULL;
974 #endif
975 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0)
976  /* close the pcb used unless other request are using it */
977  for (i = 0; i < DNS_MAX_REQUESTS; i++) {
978  if (i == idx) {
979  continue; /* only check other requests */
980  }
981  if (dns_table[i].state == DNS_STATE_ASKING) {
982  if (dns_table[i].pcb_idx == dns_table[idx].pcb_idx) {
983  /* another request is still using the same pcb */
984  dns_table[idx].pcb_idx = DNS_MAX_SOURCE_PORTS;
985  break;
986  }
987  }
988  }
989  if (dns_table[idx].pcb_idx < DNS_MAX_SOURCE_PORTS) {
990  /* if we come here, the pcb is not used any more and can be removed */
991  udp_remove(dns_pcbs[dns_table[idx].pcb_idx]);
992  dns_pcbs[dns_table[idx].pcb_idx] = NULL;
993  dns_table[idx].pcb_idx = DNS_MAX_SOURCE_PORTS;
994  }
995 #endif
996 }
997 
998 /* Create a query transmission ID that is unique for all outstanding queries */
999 static u16_t
1000 dns_create_txid(void)
1001 {
1002  u16_t txid;
1003  u8_t i;
1004 
1005 again:
1006  txid = (u16_t)DNS_RAND_TXID();
1007 
1008  /* check whether the ID is unique */
1009  for (i = 0; i < DNS_TABLE_SIZE; i++) {
1010  if ((dns_table[i].state == DNS_STATE_ASKING) &&
1011  (dns_table[i].txid == txid)) {
1012  /* ID already used by another pending query */
1013  goto again;
1014  }
1015  }
1016 
1017  return txid;
1018 }
1019 
1029 static void
1030 dns_check_entry(u8_t i)
1031 {
1032  err_t err;
1033  struct dns_table_entry *entry = &dns_table[i];
1034 
1035  LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE);
1036 
1037  switch (entry->state) {
1038  case DNS_STATE_NEW:
1039  /* initialize new entry */
1040  entry->txid = dns_create_txid();
1041  entry->state = DNS_STATE_ASKING;
1042  entry->server_idx = 0;
1043  entry->tmr = 1;
1044  entry->retries = 0;
1045 
1046  /* send DNS packet for this entry */
1047  err = dns_send(i);
1048  if (err != ERR_OK) {
1050  ("dns_send returned error: %s\n", lwip_strerr(err)));
1051  }
1052  break;
1053  case DNS_STATE_ASKING:
1054  if (--entry->tmr == 0) {
1055  if (++entry->retries == DNS_MAX_RETRIES) {
1056  if ((entry->server_idx + 1 < DNS_MAX_SERVERS) && !ip_addr_isany_val(dns_servers[entry->server_idx + 1])
1058  && !entry->is_mdns
1059 #endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */
1060  ) {
1061  /* change of server */
1062  entry->server_idx++;
1063  entry->tmr = 1;
1064  entry->retries = 0;
1065  } else {
1066  LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": timeout\n", entry->name));
1067  /* call specified callback function if provided */
1068  dns_call_found(i, NULL);
1069  /* flush this entry */
1070  entry->state = DNS_STATE_UNUSED;
1071  break;
1072  }
1073  } else {
1074  /* wait longer for the next retry */
1075  entry->tmr = entry->retries;
1076  }
1077 
1078  /* send DNS packet for this entry */
1079  err = dns_send(i);
1080  if (err != ERR_OK) {
1082  ("dns_send returned error: %s\n", lwip_strerr(err)));
1083  }
1084  }
1085  break;
1086  case DNS_STATE_DONE:
1087  /* if the time to live is nul */
1088  if ((entry->ttl == 0) || (--entry->ttl == 0)) {
1089  LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": flush\n", entry->name));
1090  /* flush this entry, there cannot be any related pending entries in this state */
1091  entry->state = DNS_STATE_UNUSED;
1092  }
1093  break;
1094  case DNS_STATE_UNUSED:
1095  /* nothing to do */
1096  break;
1097  default:
1098  LWIP_ASSERT("unknown dns_table entry state:", 0);
1099  break;
1100  }
1101 }
1102 
1106 static void
1107 dns_check_entries(void)
1108 {
1109  u8_t i;
1110 
1111  for (i = 0; i < DNS_TABLE_SIZE; ++i) {
1112  dns_check_entry(i);
1113  }
1114 }
1115 
1119 static void
1120 dns_correct_response(u8_t idx, u32_t ttl)
1121 {
1122  struct dns_table_entry *entry = &dns_table[idx];
1123 
1124  entry->state = DNS_STATE_DONE;
1125 
1126  LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", entry->name));
1127  ip_addr_debug_print(DNS_DEBUG, (&(entry->ipaddr)));
1128  LWIP_DEBUGF(DNS_DEBUG, ("\n"));
1129 
1130  /* read the answer resource record's TTL, and maximize it if needed */
1131  entry->ttl = ttl;
1132  if (entry->ttl > DNS_MAX_TTL) {
1133  entry->ttl = DNS_MAX_TTL;
1134  }
1135  dns_call_found(idx, &entry->ipaddr);
1136 
1137  if (entry->ttl == 0) {
1138  /* RFC 883, page 29: "Zero values are
1139  interpreted to mean that the RR can only be used for the
1140  transaction in progress, and should not be cached."
1141  -> flush this entry now */
1142  /* entry reused during callback? */
1143  if (entry->state == DNS_STATE_DONE) {
1144  entry->state = DNS_STATE_UNUSED;
1145  }
1146  }
1147 }
1151 static void
1152 dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
1153 {
1154  u8_t i;
1155  u16_t txid;
1156  u16_t res_idx;
1157  struct dns_hdr hdr;
1158  struct dns_answer ans;
1159  struct dns_query qry;
1160  u16_t nquestions, nanswers;
1161 
1162  LWIP_UNUSED_ARG(arg);
1163  LWIP_UNUSED_ARG(pcb);
1164  LWIP_UNUSED_ARG(port);
1165 
1166  /* is the dns message big enough ? */
1167  if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY)) {
1168  LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n"));
1169  /* free pbuf and return */
1170  goto memerr;
1171  }
1172 
1173  /* copy dns payload inside static buffer for processing */
1174  if (pbuf_copy_partial(p, &hdr, SIZEOF_DNS_HDR, 0) == SIZEOF_DNS_HDR) {
1175  /* Match the ID in the DNS header with the name table. */
1176  txid = lwip_htons(hdr.id);
1177  for (i = 0; i < DNS_TABLE_SIZE; i++) {
1178  const struct dns_table_entry *entry = &dns_table[i];
1179  if ((entry->state == DNS_STATE_ASKING) &&
1180  (entry->txid == txid)) {
1181 
1182  /* We only care about the question(s) and the answers. The authrr
1183  and the extrarr are simply discarded. */
1184  nquestions = lwip_htons(hdr.numquestions);
1185  nanswers = lwip_htons(hdr.numanswers);
1186 
1187  /* Check for correct response. */
1188  if ((hdr.flags1 & DNS_FLAG1_RESPONSE) == 0) {
1189  LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": not a response\n", entry->name));
1190  goto memerr; /* ignore this packet */
1191  }
1192  if (nquestions != 1) {
1193  LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", entry->name));
1194  goto memerr; /* ignore this packet */
1195  }
1196 
1197 #if LWIP_DNS_SUPPORT_MDNS_QUERIES
1198  if (!entry->is_mdns)
1199 #endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */
1200  {
1201  /* Check whether response comes from the same network address to which the
1202  question was sent. (RFC 5452) */
1203  if (!ip_addr_cmp(addr, &dns_servers[entry->server_idx])) {
1204  goto memerr; /* ignore this packet */
1205  }
1206  }
1207 
1208  /* Check if the name in the "question" part match with the name in the entry and
1209  skip it if equal. */
1210  res_idx = dns_compare_name(entry->name, p, SIZEOF_DNS_HDR);
1211  if (res_idx == 0xFFFF) {
1212  LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", entry->name));
1213  goto memerr; /* ignore this packet */
1214  }
1215 
1216  /* check if "question" part matches the request */
1217  if (pbuf_copy_partial(p, &qry, SIZEOF_DNS_QUERY, res_idx) != SIZEOF_DNS_QUERY) {
1218  goto memerr; /* ignore this packet */
1219  }
1220  if ((qry.cls != PP_HTONS(DNS_RRCLASS_IN)) ||
1221  (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype) && (qry.type != PP_HTONS(DNS_RRTYPE_AAAA))) ||
1222  (!LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype) && (qry.type != PP_HTONS(DNS_RRTYPE_A)))) {
1223  LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", entry->name));
1224  goto memerr; /* ignore this packet */
1225  }
1226  /* skip the rest of the "question" part */
1227  res_idx += SIZEOF_DNS_QUERY;
1228 
1229  /* Check for error. If so, call callback to inform. */
1230  if (hdr.flags2 & DNS_FLAG2_ERR_MASK) {
1231  LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in flags\n", entry->name));
1232  } else {
1233  while ((nanswers > 0) && (res_idx < p->tot_len)) {
1234  /* skip answer resource record's host name */
1235  res_idx = dns_skip_name(p, res_idx);
1236  if (res_idx == 0xFFFF) {
1237  goto memerr; /* ignore this packet */
1238  }
1239 
1240  /* Check for IP address type and Internet class. Others are discarded. */
1241  if (pbuf_copy_partial(p, &ans, SIZEOF_DNS_ANSWER, res_idx) != SIZEOF_DNS_ANSWER) {
1242  goto memerr; /* ignore this packet */
1243  }
1244  res_idx += SIZEOF_DNS_ANSWER;
1245 
1246  if (ans.cls == PP_HTONS(DNS_RRCLASS_IN)) {
1247 #if LWIP_IPV4
1248  if ((ans.type == PP_HTONS(DNS_RRTYPE_A)) && (ans.len == PP_HTONS(sizeof(ip4_addr_t)))) {
1249 #if LWIP_IPV4 && LWIP_IPV6
1250  if (!LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype))
1251 #endif /* LWIP_IPV4 && LWIP_IPV6 */
1252  {
1253  ip4_addr_t ip4addr;
1254  /* read the IP address after answer resource record's header */
1255  if (pbuf_copy_partial(p, &ip4addr, sizeof(ip4_addr_t), res_idx) != sizeof(ip4_addr_t)) {
1256  goto memerr; /* ignore this packet */
1257  }
1258  ip_addr_copy_from_ip4(dns_table[i].ipaddr, ip4addr);
1259  pbuf_free(p);
1260  /* handle correct response */
1261  dns_correct_response(i, lwip_ntohl(ans.ttl));
1262  return;
1263  }
1264  }
1265 #endif /* LWIP_IPV4 */
1266 #if LWIP_IPV6
1267  if ((ans.type == PP_HTONS(DNS_RRTYPE_AAAA)) && (ans.len == PP_HTONS(sizeof(ip6_addr_t)))) {
1268 #if LWIP_IPV4 && LWIP_IPV6
1269  if (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype))
1270 #endif /* LWIP_IPV4 && LWIP_IPV6 */
1271  {
1272  ip6_addr_t ip6addr;
1273  /* read the IP address after answer resource record's header */
1274  if (pbuf_copy_partial(p, &ip6addr, sizeof(ip6_addr_t), res_idx) != sizeof(ip6_addr_t)) {
1275  goto memerr; /* ignore this packet */
1276  }
1277  ip_addr_copy_from_ip6(dns_table[i].ipaddr, ip6addr);
1278  pbuf_free(p);
1279  /* handle correct response */
1280  dns_correct_response(i, lwip_ntohl(ans.ttl));
1281  return;
1282  }
1283  }
1284 #endif /* LWIP_IPV6 */
1285  }
1286  /* skip this answer */
1287  if ((int)(res_idx + lwip_htons(ans.len)) > 0xFFFF) {
1288  goto memerr; /* ignore this packet */
1289  }
1290  res_idx += lwip_htons(ans.len);
1291  --nanswers;
1292  }
1293 #if LWIP_IPV4 && LWIP_IPV6
1294  if ((entry->reqaddrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) ||
1295  (entry->reqaddrtype == LWIP_DNS_ADDRTYPE_IPV6_IPV4)) {
1296  if (entry->reqaddrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) {
1297  /* IPv4 failed, try IPv6 */
1298  dns_table[i].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV6;
1299  } else {
1300  /* IPv6 failed, try IPv4 */
1301  dns_table[i].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV4;
1302  }
1303  pbuf_free(p);
1304  dns_table[i].state = DNS_STATE_NEW;
1305  dns_check_entry(i);
1306  return;
1307  }
1308 #endif /* LWIP_IPV4 && LWIP_IPV6 */
1309  LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in response\n", entry->name));
1310  }
1311  /* call callback to indicate error, clean up memory and return */
1312  pbuf_free(p);
1313  dns_call_found(i, NULL);
1314  dns_table[i].state = DNS_STATE_UNUSED;
1315  return;
1316  }
1317  }
1318  }
1319 
1320 memerr:
1321  /* deallocate memory and return */
1322  pbuf_free(p);
1323  return;
1324 }
1325 
1335 static err_t
1336 dns_enqueue(const char *name, size_t hostnamelen, dns_found_callback found,
1337  void *callback_arg LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype) LWIP_DNS_ISMDNS_ARG(u8_t is_mdns))
1338 {
1339  u8_t i;
1340  u8_t lseq, lseqi;
1341  struct dns_table_entry *entry = NULL;
1342  size_t namelen;
1343  struct dns_req_entry* req;
1344 
1345 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0)
1346  u8_t r;
1347  /* check for duplicate entries */
1348  for (i = 0; i < DNS_TABLE_SIZE; i++) {
1349  if ((dns_table[i].state == DNS_STATE_ASKING) &&
1350  (lwip_strnicmp(name, dns_table[i].name, sizeof(dns_table[i].name)) == 0)) {
1351 #if LWIP_IPV4 && LWIP_IPV6
1352  if (dns_table[i].reqaddrtype != dns_addrtype) {
1353  /* requested address types don't match
1354  this can lead to 2 concurrent requests, but mixing the address types
1355  for the same host should not be that common */
1356  continue;
1357  }
1358 #endif /* LWIP_IPV4 && LWIP_IPV6 */
1359  /* this is a duplicate entry, find a free request entry */
1360  for (r = 0; r < DNS_MAX_REQUESTS; r++) {
1361  if (dns_requests[r].found == 0) {
1362  dns_requests[r].found = found;
1363  dns_requests[r].arg = callback_arg;
1364  dns_requests[r].dns_table_idx = i;
1365  LWIP_DNS_SET_ADDRTYPE(dns_requests[r].reqaddrtype, dns_addrtype);
1366  LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": duplicate request\n", name));
1367  return ERR_INPROGRESS;
1368  }
1369  }
1370  }
1371  }
1372  /* no duplicate entries found */
1373 #endif
1374 
1375  /* search an unused entry, or the oldest one */
1376  lseq = 0;
1377  lseqi = DNS_TABLE_SIZE;
1378  for (i = 0; i < DNS_TABLE_SIZE; ++i) {
1379  entry = &dns_table[i];
1380  /* is it an unused entry ? */
1381  if (entry->state == DNS_STATE_UNUSED) {
1382  break;
1383  }
1384  /* check if this is the oldest completed entry */
1385  if (entry->state == DNS_STATE_DONE) {
1386  u8_t age = dns_seqno - entry->seqno;
1387  if (age > lseq) {
1388  lseq = age;
1389  lseqi = i;
1390  }
1391  }
1392  }
1393 
1394  /* if we don't have found an unused entry, use the oldest completed one */
1395  if (i == DNS_TABLE_SIZE) {
1396  if ((lseqi >= DNS_TABLE_SIZE) || (dns_table[lseqi].state != DNS_STATE_DONE)) {
1397  /* no entry can be used now, table is full */
1398  LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS entries table is full\n", name));
1399  return ERR_MEM;
1400  } else {
1401  /* use the oldest completed one */
1402  i = lseqi;
1403  entry = &dns_table[i];
1404  }
1405  }
1406 
1407 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0)
1408  /* find a free request entry */
1409  req = NULL;
1410  for (r = 0; r < DNS_MAX_REQUESTS; r++) {
1411  if (dns_requests[r].found == NULL) {
1412  req = &dns_requests[r];
1413  break;
1414  }
1415  }
1416  if (req == NULL) {
1417  /* no request entry can be used now, table is full */
1418  LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS request entries table is full\n", name));
1419  return ERR_MEM;
1420  }
1421  req->dns_table_idx = i;
1422 #else
1423  /* in this configuration, the entry index is the same as the request index */
1424  req = &dns_requests[i];
1425 #endif
1426 
1427  /* use this entry */
1428  LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS entry %"U16_F"\n", name, (u16_t)(i)));
1429 
1430  /* fill the entry */
1431  entry->state = DNS_STATE_NEW;
1432  entry->seqno = dns_seqno;
1433  LWIP_DNS_SET_ADDRTYPE(entry->reqaddrtype, dns_addrtype);
1434  LWIP_DNS_SET_ADDRTYPE(req->reqaddrtype, dns_addrtype);
1435  req->found = found;
1436  req->arg = callback_arg;
1437  namelen = LWIP_MIN(hostnamelen, DNS_MAX_NAME_LENGTH-1);
1438  MEMCPY(entry->name, name, namelen);
1439  entry->name[namelen] = 0;
1440 
1441 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0)
1442  entry->pcb_idx = dns_alloc_pcb();
1443  if (entry->pcb_idx >= DNS_MAX_SOURCE_PORTS) {
1444  /* failed to get a UDP pcb */
1445  LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": failed to allocate a pcb\n", name));
1446  entry->state = DNS_STATE_UNUSED;
1447  req->found = NULL;
1448  return ERR_MEM;
1449  }
1450  LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS pcb %"U16_F"\n", name, (u16_t)(entry->pcb_idx)));
1451 #endif
1452 
1453 #if LWIP_DNS_SUPPORT_MDNS_QUERIES
1454  entry->is_mdns = is_mdns;
1455 #endif
1456 
1457  dns_seqno++;
1458 
1459  /* force to send query without waiting timer */
1460  dns_check_entry(i);
1461 
1462  /* dns query is enqueued */
1463  return ERR_INPROGRESS;
1464 }
1465 
1486 err_t
1487 dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found,
1488  void *callback_arg)
1489 {
1490  return dns_gethostbyname_addrtype(hostname, addr, found, callback_arg, LWIP_DNS_ADDRTYPE_DEFAULT);
1491 }
1492 
1507 err_t
1508 dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, dns_found_callback found,
1509  void *callback_arg, u8_t dns_addrtype)
1510 {
1511  size_t hostnamelen;
1512 #if LWIP_DNS_SUPPORT_MDNS_QUERIES
1513  u8_t is_mdns;
1514 #endif
1515  /* not initialized or no valid server yet, or invalid addr pointer
1516  * or invalid hostname or invalid hostname length */
1517  if ((addr == NULL) ||
1518  (!hostname) || (!hostname[0])) {
1519  return ERR_ARG;
1520  }
1521 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) == 0)
1522  if (dns_pcbs[0] == NULL) {
1523  return ERR_ARG;
1524  }
1525 #endif
1526  hostnamelen = strlen(hostname);
1527  if (hostnamelen >= DNS_MAX_NAME_LENGTH) {
1528  LWIP_DEBUGF(DNS_DEBUG, ("dns_gethostbyname: name too long to resolve"));
1529  return ERR_ARG;
1530  }
1531 
1532 
1533 #if LWIP_HAVE_LOOPIF
1534  if (strcmp(hostname, "localhost") == 0) {
1535  ip_addr_set_loopback(LWIP_DNS_ADDRTYPE_IS_IPV6(dns_addrtype), addr);
1536  return ERR_OK;
1537  }
1538 #endif /* LWIP_HAVE_LOOPIF */
1539 
1540  /* host name already in octet notation? set ip addr and return ERR_OK */
1541  if (ipaddr_aton(hostname, addr)) {
1542 #if LWIP_IPV4 && LWIP_IPV6
1543  if ((IP_IS_V6(addr) && (dns_addrtype != LWIP_DNS_ADDRTYPE_IPV4)) ||
1544  (IP_IS_V4(addr) && (dns_addrtype != LWIP_DNS_ADDRTYPE_IPV6)))
1545 #endif /* LWIP_IPV4 && LWIP_IPV6 */
1546  {
1547  return ERR_OK;
1548  }
1549  }
1550  /* already have this address cached? */
1551  if (dns_lookup(hostname, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)) == ERR_OK) {
1552  return ERR_OK;
1553  }
1554 #if LWIP_IPV4 && LWIP_IPV6
1555  if ((dns_addrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) || (dns_addrtype == LWIP_DNS_ADDRTYPE_IPV6_IPV4)) {
1556  /* fallback to 2nd IP type and try again to lookup */
1557  u8_t fallback;
1558  if (dns_addrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) {
1559  fallback = LWIP_DNS_ADDRTYPE_IPV6;
1560  } else {
1561  fallback = LWIP_DNS_ADDRTYPE_IPV4;
1562  }
1563  if (dns_lookup(hostname, addr LWIP_DNS_ADDRTYPE_ARG(fallback)) == ERR_OK) {
1564  return ERR_OK;
1565  }
1566  }
1567 #else /* LWIP_IPV4 && LWIP_IPV6 */
1568  LWIP_UNUSED_ARG(dns_addrtype);
1569 #endif /* LWIP_IPV4 && LWIP_IPV6 */
1570 
1571 #if LWIP_DNS_SUPPORT_MDNS_QUERIES
1572  if (strstr(hostname, ".local") == &hostname[hostnamelen] - 6) {
1573  is_mdns = 1;
1574  } else {
1575  is_mdns = 0;
1576  }
1577 
1578  if (!is_mdns)
1579 #endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */
1580  {
1581  /* prevent calling found callback if no server is set, return error instead */
1582  if (ip_addr_isany_val(dns_servers[0])) {
1583  return ERR_VAL;
1584  }
1585  }
1586 
1587  /* queue query with specified callback */
1588  return dns_enqueue(hostname, hostnamelen, found, callback_arg LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)
1589  LWIP_DNS_ISMDNS_ARG(is_mdns));
1590 }
1591 
1592 #endif /* LWIP_DNS */
#define DNS_TABLE_SIZE
Definition: opt.h:1035
u16_t tot_len
Definition: pbuf.h:175
#define DNS_DEBUG
Definition: opt.h:2861
#define LWIP_DNS_SUPPORT_MDNS_QUERIES
Definition: opt.h:1090
#define DNS_SERVER_PORT
Definition: prot/dns.h:70
void memp_free(memp_t type, void *mem)
Definition: memp.c:488
Definition: err.h:84
#define DNS_MAX_SERVERS
Definition: opt.h:1048
err_t pbuf_take_at(struct pbuf *buf, const void *dataptr, u16_t len, u16_t offset)
Definition: pbuf.c:1212
void pbuf_put_at(struct pbuf *p, u16_t offset, u8_t data)
Definition: pbuf.c:1358
Definition: err.h:115
#define DNS_MAX_NAME_LENGTH
Definition: opt.h:1040
Definition: pbuf.h:161
int lwip_stricmp(const char *str1, const char *str2)
Definition: def.c:147
s8_t err_t
Definition: err.h:76
#define LWIP_DEBUGF(debug, message)
struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
Definition: pbuf.c:267
u16_t pbuf_copy_partial(const struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
Definition: pbuf.c:1034
err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len)
Definition: pbuf.c:1168
Definition: pbuf.h:127
Definition: err.h:94
#define LWIP_UNUSED_ARG(x)
Definition: arch.h:327
u8_t pbuf_free(struct pbuf *p)
Definition: pbuf.c:734
Definition: err.h:82
Definition: err.h:98
void * memp_malloc(memp_t type)
Definition: memp.c:404
#define DNS_MQUERY_PORT
Definition: prot/dns.h:142
int pbuf_try_get_at(const struct pbuf *p, u16_t offset)
Definition: pbuf.c:1336
int lwip_strnicmp(const char *str1, const char *str2, size_t len)
Definition: def.c:182