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
122static 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
211struct 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
221struct 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 */
234typedef 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
242struct 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
265struct 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
283static 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 */
293#ifndef DNS_LOCAL_HOSTLIST_STORAGE_POST
294#define DNS_LOCAL_HOSTLIST_STORAGE_POST
295#endif /* DNS_LOCAL_HOSTLIST_STORAGE_POST */
296DNS_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
301static void dns_init_local(void);
302static 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 */
307static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port);
308static void dns_check_entries(void);
309static void dns_call_found(u8_t idx, ip_addr_t* addr);
310
311/*-----------------------------------------------------------------------------
312 * Globals
313 *----------------------------------------------------------------------------*/
314
315/* DNS variables */
316static struct udp_pcb *dns_pcbs[DNS_MAX_SOURCE_PORTS];
317#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0)
318static u8_t dns_last_pcb_idx;
319#endif
320static u8_t dns_seqno;
321static struct dns_table_entry dns_table[DNS_TABLE_SIZE];
322static struct dns_req_entry dns_requests[DNS_MAX_REQUESTS];
323static ip_addr_t dns_servers[DNS_MAX_SERVERS];
324
325#if LWIP_IPV4
326const ip_addr_t dns_mquery_v4group = DNS_MQUERY_IPV4_GROUP_INIT;
327#endif /* LWIP_IPV4 */
328#if LWIP_IPV6
329const ip_addr_t dns_mquery_v6group = DNS_MQUERY_IPV6_GROUP_INIT;
330#endif /* LWIP_IPV6 */
331
336void
337dns_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
382void
383dns_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
402const ip_addr_t*
403dns_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
416void
417dns_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
424static void
425dns_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
461size_t
462dns_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
498err_t
499dns_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 */
506static err_t
507dns_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
547int
548dns_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
583err_t
584dns_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
623static err_t
624dns_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
669static u16_t
670dns_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
716static u16_t
717dns_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
753static err_t
754dns_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)
865static struct udp_pcb*
866dns_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
899static u8_t
900dns_alloc_pcb(void)
901{
902 u8_t i;
903 u8_t idx;
904
905 for (i = 0; i < DNS_MAX_SOURCE_PORTS; i++) {
906 if (dns_pcbs[i] == NULL) {
907 break;
908 }
909 }
910 if (i < DNS_MAX_SOURCE_PORTS) {
911 dns_pcbs[i] = dns_alloc_random_port();
912 if (dns_pcbs[i] != NULL) {
913 /* succeeded */
914 dns_last_pcb_idx = i;
915 return i;
916 }
917 }
918 /* if we come here, creating a new UDP pcb failed, so we have to use
919 an already existing one */
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
941static void
942dns_call_found(u8_t idx, ip_addr_t* addr)
943{
944#if ((LWIP_DNS_SECURE & (LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING | LWIP_DNS_SECURE_RAND_SRC_PORT)) != 0)
945 u8_t i;
946#endif
947
948#if LWIP_IPV4 && LWIP_IPV6
949 if (addr != NULL) {
950 /* check that address type matches the request and adapt the table entry */
951 if (IP_IS_V6_VAL(*addr)) {
952 LWIP_ASSERT("invalid response", LWIP_DNS_ADDRTYPE_IS_IPV6(dns_table[idx].reqaddrtype));
953 dns_table[idx].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV6;
954 } else {
955 LWIP_ASSERT("invalid response", !LWIP_DNS_ADDRTYPE_IS_IPV6(dns_table[idx].reqaddrtype));
956 dns_table[idx].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV4;
957 }
958 }
959#endif /* LWIP_IPV4 && LWIP_IPV6 */
960
961#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0)
962 for (i = 0; i < DNS_MAX_REQUESTS; i++) {
963 if (dns_requests[i].found && (dns_requests[i].dns_table_idx == idx)) {
964 (*dns_requests[i].found)(dns_table[idx].name, addr, dns_requests[i].arg);
965 /* flush this entry */
966 dns_requests[i].found = NULL;
967 }
968 }
969#else
970 if (dns_requests[idx].found) {
971 (*dns_requests[idx].found)(dns_table[idx].name, addr, dns_requests[idx].arg);
972 }
973 dns_requests[idx].found = NULL;
974#endif
975#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0)
976 /* close the pcb used unless other request are using it */
977 for (i = 0; i < DNS_MAX_REQUESTS; i++) {
978 if (i == idx) {
979 continue; /* only check other requests */
980 }
981 if (dns_table[i].state == DNS_STATE_ASKING) {
982 if (dns_table[i].pcb_idx == dns_table[idx].pcb_idx) {
983 /* another request is still using the same pcb */
984 dns_table[idx].pcb_idx = DNS_MAX_SOURCE_PORTS;
985 break;
986 }
987 }
988 }
989 if (dns_table[idx].pcb_idx < DNS_MAX_SOURCE_PORTS) {
990 /* if we come here, the pcb is not used any more and can be removed */
991 udp_remove(dns_pcbs[dns_table[idx].pcb_idx]);
992 dns_pcbs[dns_table[idx].pcb_idx] = NULL;
993 dns_table[idx].pcb_idx = DNS_MAX_SOURCE_PORTS;
994 }
995#endif
996}
997
998/* Create a query transmission ID that is unique for all outstanding queries */
999static u16_t
1000dns_create_txid(void)
1001{
1002 u16_t txid;
1003 u8_t i;
1004
1005again:
1006 txid = (u16_t)DNS_RAND_TXID();
1007
1008 /* check whether the ID is unique */
1009 for (i = 0; i < DNS_TABLE_SIZE; i++) {
1010 if ((dns_table[i].state == DNS_STATE_ASKING) &&
1011 (dns_table[i].txid == txid)) {
1012 /* ID already used by another pending query */
1013 goto again;
1014 }
1015 }
1016
1017 return txid;
1018}
1019
1029static void
1030dns_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
1106static void
1107dns_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
1119static void
1120dns_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}
1151static void
1152dns_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
1320memerr:
1321 /* deallocate memory and return */
1322 pbuf_free(p);
1323 return;
1324}
1325
1335static err_t
1336dns_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#endif
1348
1349#ifdef DNS_RAND_READY
1350 /* No table entry or PCB may consume predictable identifiers before seeding. */
1351 if (!DNS_RAND_READY()) {
1352 return ERR_WOULDBLOCK;
1353 }
1354#endif
1355
1356#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0)
1357 /* check for duplicate entries */
1358 for (i = 0; i < DNS_TABLE_SIZE; i++) {
1359 if ((dns_table[i].state == DNS_STATE_ASKING) &&
1360 (lwip_strnicmp(name, dns_table[i].name, sizeof(dns_table[i].name)) == 0)) {
1361#if LWIP_IPV4 && LWIP_IPV6
1362 if (dns_table[i].reqaddrtype != dns_addrtype) {
1363 /* requested address types don't match
1364 this can lead to 2 concurrent requests, but mixing the address types
1365 for the same host should not be that common */
1366 continue;
1367 }
1368#endif /* LWIP_IPV4 && LWIP_IPV6 */
1369 /* this is a duplicate entry, find a free request entry */
1370 for (r = 0; r < DNS_MAX_REQUESTS; r++) {
1371 if (dns_requests[r].found == 0) {
1372 dns_requests[r].found = found;
1373 dns_requests[r].arg = callback_arg;
1374 dns_requests[r].dns_table_idx = i;
1375 LWIP_DNS_SET_ADDRTYPE(dns_requests[r].reqaddrtype, dns_addrtype);
1376 LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": duplicate request\n", name));
1377 return ERR_INPROGRESS;
1378 }
1379 }
1380 }
1381 }
1382 /* no duplicate entries found */
1383#endif
1384
1385 /* search an unused entry, or the oldest one */
1386 lseq = 0;
1387 lseqi = DNS_TABLE_SIZE;
1388 for (i = 0; i < DNS_TABLE_SIZE; ++i) {
1389 entry = &dns_table[i];
1390 /* is it an unused entry ? */
1391 if (entry->state == DNS_STATE_UNUSED) {
1392 break;
1393 }
1394 /* check if this is the oldest completed entry */
1395 if (entry->state == DNS_STATE_DONE) {
1396 u8_t age = dns_seqno - entry->seqno;
1397 if (age > lseq) {
1398 lseq = age;
1399 lseqi = i;
1400 }
1401 }
1402 }
1403
1404 /* if we don't have found an unused entry, use the oldest completed one */
1405 if (i == DNS_TABLE_SIZE) {
1406 if ((lseqi >= DNS_TABLE_SIZE) || (dns_table[lseqi].state != DNS_STATE_DONE)) {
1407 /* no entry can be used now, table is full */
1408 LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS entries table is full\n", name));
1409 return ERR_MEM;
1410 } else {
1411 /* use the oldest completed one */
1412 i = lseqi;
1413 entry = &dns_table[i];
1414 }
1415 }
1416
1417#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0)
1418 /* find a free request entry */
1419 req = NULL;
1420 for (r = 0; r < DNS_MAX_REQUESTS; r++) {
1421 if (dns_requests[r].found == NULL) {
1422 req = &dns_requests[r];
1423 break;
1424 }
1425 }
1426 if (req == NULL) {
1427 /* no request entry can be used now, table is full */
1428 LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS request entries table is full\n", name));
1429 return ERR_MEM;
1430 }
1431 req->dns_table_idx = i;
1432#else
1433 /* in this configuration, the entry index is the same as the request index */
1434 req = &dns_requests[i];
1435#endif
1436
1437 /* use this entry */
1438 LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS entry %"U16_F"\n", name, (u16_t)(i)));
1439
1440 /* fill the entry */
1441 entry->state = DNS_STATE_NEW;
1442 entry->seqno = dns_seqno;
1443 LWIP_DNS_SET_ADDRTYPE(entry->reqaddrtype, dns_addrtype);
1444 LWIP_DNS_SET_ADDRTYPE(req->reqaddrtype, dns_addrtype);
1445 req->found = found;
1446 req->arg = callback_arg;
1447 namelen = LWIP_MIN(hostnamelen, DNS_MAX_NAME_LENGTH-1);
1448 MEMCPY(entry->name, name, namelen);
1449 entry->name[namelen] = 0;
1450
1451#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0)
1452 entry->pcb_idx = dns_alloc_pcb();
1453 if (entry->pcb_idx >= DNS_MAX_SOURCE_PORTS) {
1454 /* failed to get a UDP pcb */
1455 LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": failed to allocate a pcb\n", name));
1456 entry->state = DNS_STATE_UNUSED;
1457 req->found = NULL;
1458 return ERR_MEM;
1459 }
1460 LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS pcb %"U16_F"\n", name, (u16_t)(entry->pcb_idx)));
1461#endif
1462
1463#if LWIP_DNS_SUPPORT_MDNS_QUERIES
1464 entry->is_mdns = is_mdns;
1465#endif
1466
1467 dns_seqno++;
1468
1469 /* force to send query without waiting timer */
1470 dns_check_entry(i);
1471
1472 /* dns query is enqueued */
1473 return ERR_INPROGRESS;
1474}
1475
1496err_t
1497dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found,
1498 void *callback_arg)
1499{
1500 return dns_gethostbyname_addrtype(hostname, addr, found, callback_arg, LWIP_DNS_ADDRTYPE_DEFAULT);
1501}
1502
1517err_t
1518dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, dns_found_callback found,
1519 void *callback_arg, u8_t dns_addrtype)
1520{
1521 size_t hostnamelen;
1522#if LWIP_DNS_SUPPORT_MDNS_QUERIES
1523 u8_t is_mdns;
1524#endif
1525 /* not initialized or no valid server yet, or invalid addr pointer
1526 * or invalid hostname or invalid hostname length */
1527 if ((addr == NULL) ||
1528 (!hostname) || (!hostname[0])) {
1529 return ERR_ARG;
1530 }
1531#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) == 0)
1532 if (dns_pcbs[0] == NULL) {
1533 return ERR_ARG;
1534 }
1535#endif
1536 hostnamelen = strlen(hostname);
1537 if (hostnamelen >= DNS_MAX_NAME_LENGTH) {
1538 LWIP_DEBUGF(DNS_DEBUG, ("dns_gethostbyname: name too long to resolve"));
1539 return ERR_ARG;
1540 }
1541
1542
1543#if LWIP_HAVE_LOOPIF
1544 if (strcmp(hostname, "localhost") == 0) {
1545 ip_addr_set_loopback(LWIP_DNS_ADDRTYPE_IS_IPV6(dns_addrtype), addr);
1546 return ERR_OK;
1547 }
1548#endif /* LWIP_HAVE_LOOPIF */
1549
1550 /* host name already in octet notation? set ip addr and return ERR_OK */
1551 if (ipaddr_aton(hostname, addr)) {
1552#if LWIP_IPV4 && LWIP_IPV6
1553 if ((IP_IS_V6(addr) && (dns_addrtype != LWIP_DNS_ADDRTYPE_IPV4)) ||
1554 (IP_IS_V4(addr) && (dns_addrtype != LWIP_DNS_ADDRTYPE_IPV6)))
1555#endif /* LWIP_IPV4 && LWIP_IPV6 */
1556 {
1557 return ERR_OK;
1558 }
1559 }
1560 /* already have this address cached? */
1561 if (dns_lookup(hostname, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)) == ERR_OK) {
1562 return ERR_OK;
1563 }
1564#if LWIP_IPV4 && LWIP_IPV6
1565 if ((dns_addrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) || (dns_addrtype == LWIP_DNS_ADDRTYPE_IPV6_IPV4)) {
1566 /* fallback to 2nd IP type and try again to lookup */
1567 u8_t fallback;
1568 if (dns_addrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) {
1569 fallback = LWIP_DNS_ADDRTYPE_IPV6;
1570 } else {
1571 fallback = LWIP_DNS_ADDRTYPE_IPV4;
1572 }
1573 if (dns_lookup(hostname, addr LWIP_DNS_ADDRTYPE_ARG(fallback)) == ERR_OK) {
1574 return ERR_OK;
1575 }
1576 }
1577#else /* LWIP_IPV4 && LWIP_IPV6 */
1578 LWIP_UNUSED_ARG(dns_addrtype);
1579#endif /* LWIP_IPV4 && LWIP_IPV6 */
1580
1581#if LWIP_DNS_SUPPORT_MDNS_QUERIES
1582 if (strstr(hostname, ".local") == &hostname[hostnamelen] - 6) {
1583 is_mdns = 1;
1584 } else {
1585 is_mdns = 0;
1586 }
1587
1588 if (!is_mdns)
1589#endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */
1590 {
1591 /* prevent calling found callback if no server is set, return error instead */
1592 if (ip_addr_isany_val(dns_servers[0])) {
1593 return ERR_VAL;
1594 }
1595 }
1596
1597 /* queue query with specified callback */
1598 return dns_enqueue(hostname, hostnamelen, found, callback_arg LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)
1599 LWIP_DNS_ISMDNS_ARG(is_mdns));
1600}
1601
1602#endif /* LWIP_DNS */
#define LWIP_DEBUGF(debug, message)
Definition debug.h:183
#define LWIP_UNUSED_ARG(x)
Definition arch.h:327
#define LWIP_DBG_LEVEL_WARNING
Definition debug.h:74
s8_t err_t
Definition err.h:76
@ ERR_INPROGRESS
Definition err.h:92
@ ERR_USE
Definition err.h:98
@ ERR_OK
Definition err.h:82
@ ERR_VAL
Definition err.h:94
@ ERR_MEM
Definition err.h:84
@ ERR_ARG
Definition err.h:115
@ ERR_WOULDBLOCK
Definition err.h:96
@ IPADDR_TYPE_ANY
Definition ip_addr.h:79
#define DNS_DEBUG
Definition opt.h:2861
#define DNS_TABLE_SIZE
Definition opt.h:1035
#define DNS_MAX_NAME_LENGTH
Definition opt.h:1040
#define DNS_MAX_SERVERS
Definition opt.h:1048
#define LWIP_DNS_SUPPORT_MDNS_QUERIES
Definition opt.h:1090
int pbuf_try_get_at(const struct pbuf *p, u16_t offset)
Definition pbuf.c:1336
struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
Definition pbuf.c:267
u8_t pbuf_free(struct pbuf *p)
Definition pbuf.c:734
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
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
@ PBUF_RAM
Definition pbuf.h:127
@ PBUF_TRANSPORT
Definition pbuf.h:95
int lwip_stricmp(const char *str1, const char *str2)
Definition def.c:147
int lwip_strnicmp(const char *str1, const char *str2, size_t len)
Definition def.c:182
void * memp_malloc(memp_t type)
Definition memp.c:404
void memp_free(memp_t type, void *mem)
Definition memp.c:488
#define DNS_MQUERY_PORT
Definition prot/dns.h:142
#define DNS_SERVER_PORT
Definition prot/dns.h:70
Definition pbuf.h:161
u16_t tot_len
Definition pbuf.h:175