ReactOS 0.4.16-dev-570-g1868985
dns.c
Go to the documentation of this file.
1
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
83/*-----------------------------------------------------------------------------
84 * Includes
85 *----------------------------------------------------------------------------*/
86
87#include "lwip/opt.h"
88
89#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
90
91#include "lwip/def.h"
92#include "lwip/udp.h"
93#include "lwip/mem.h"
94#include "lwip/memp.h"
95#include "lwip/dns.h"
96#include "lwip/prot/dns.h"
97
98#include <string.h>
99
101#ifndef DNS_RAND_TXID
102#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_XID) != 0)
103#define DNS_RAND_TXID LWIP_RAND
104#else
105static u16_t dns_txid;
106#define DNS_RAND_TXID() (++dns_txid)
107#endif
108#endif
109
111#ifndef DNS_PORT_ALLOWED
112#define DNS_PORT_ALLOWED(port) ((port) >= 1024)
113#endif
114
116#ifndef DNS_MAX_TTL
117#define DNS_MAX_TTL 604800
118#elif DNS_MAX_TTL > 0x7FFFFFFF
119#error DNS_MAX_TTL must be a positive 32-bit value
120#endif
121
122#if DNS_TABLE_SIZE > 255
123#error DNS_TABLE_SIZE must fit into an u8_t
124#endif
125#if DNS_MAX_SERVERS > 255
126#error DNS_MAX_SERVERS must fit into an u8_t
127#endif
128
129/* The number of parallel requests (i.e. calls to dns_gethostbyname
130 * that cannot be answered from the DNS table.
131 * This is set to the table size by default.
132 */
133#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0)
134#ifndef DNS_MAX_REQUESTS
135#define DNS_MAX_REQUESTS DNS_TABLE_SIZE
136#else
137#if DNS_MAX_REQUESTS > 255
138#error DNS_MAX_REQUESTS must fit into an u8_t
139#endif
140#endif
141#else
142/* In this configuration, both arrays have to have the same size and are used
143 * like one entry (used/free) */
144#define DNS_MAX_REQUESTS DNS_TABLE_SIZE
145#endif
146
147/* The number of UDP source ports used in parallel */
148#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0)
149#ifndef DNS_MAX_SOURCE_PORTS
150#define DNS_MAX_SOURCE_PORTS DNS_MAX_REQUESTS
151#else
152#if DNS_MAX_SOURCE_PORTS > 255
153#error DNS_MAX_SOURCE_PORTS must fit into an u8_t
154#endif
155#endif
156#else
157#ifdef DNS_MAX_SOURCE_PORTS
158#undef DNS_MAX_SOURCE_PORTS
159#endif
160#define DNS_MAX_SOURCE_PORTS 1
161#endif
162
163#if LWIP_IPV4 && LWIP_IPV6
164#define LWIP_DNS_ADDRTYPE_IS_IPV6(t) (((t) == LWIP_DNS_ADDRTYPE_IPV6_IPV4) || ((t) == LWIP_DNS_ADDRTYPE_IPV6))
165#define LWIP_DNS_ADDRTYPE_MATCH_IP(t, ip) (IP_IS_V6_VAL(ip) ? LWIP_DNS_ADDRTYPE_IS_IPV6(t) : (!LWIP_DNS_ADDRTYPE_IS_IPV6(t)))
166#define LWIP_DNS_ADDRTYPE_ARG(x) , x
167#define LWIP_DNS_ADDRTYPE_ARG_OR_ZERO(x) x
168#define LWIP_DNS_SET_ADDRTYPE(x, y) do { x = y; } while(0)
169#else
170#if LWIP_IPV6
171#define LWIP_DNS_ADDRTYPE_IS_IPV6(t) 1
172#else
173#define LWIP_DNS_ADDRTYPE_IS_IPV6(t) 0
174#endif
175#define LWIP_DNS_ADDRTYPE_MATCH_IP(t, ip) 1
176#define LWIP_DNS_ADDRTYPE_ARG(x)
177#define LWIP_DNS_ADDRTYPE_ARG_OR_ZERO(x) 0
178#define LWIP_DNS_SET_ADDRTYPE(x, y)
179#endif /* LWIP_IPV4 && LWIP_IPV6 */
180
181#if LWIP_DNS_SUPPORT_MDNS_QUERIES
182#define LWIP_DNS_ISMDNS_ARG(x) , x
183#else
184#define LWIP_DNS_ISMDNS_ARG(x)
185#endif
186
189struct dns_query {
190 /* DNS query record starts with either a domain name or a pointer
191 to a name already present somewhere in the packet. */
192 u16_t type;
193 u16_t cls;
194};
195#define SIZEOF_DNS_QUERY 4
196
199struct dns_answer {
200 /* DNS answer record starts with either a domain name or a pointer
201 to a name already present somewhere in the packet. */
202 u16_t type;
203 u16_t cls;
204 u32_t ttl;
205 u16_t len;
206};
207#define SIZEOF_DNS_ANSWER 10
208/* maximum allowed size for the struct due to non-packed */
209#define SIZEOF_DNS_ANSWER_ASSERT 12
210
211/* DNS table entry states */
212typedef enum {
213 DNS_STATE_UNUSED = 0,
214 DNS_STATE_NEW = 1,
215 DNS_STATE_ASKING = 2,
216 DNS_STATE_DONE = 3
217} dns_state_enum_t;
218
220struct dns_table_entry {
221 u32_t ttl;
222 ip_addr_t ipaddr;
223 u16_t txid;
224 u8_t state;
225 u8_t server_idx;
226 u8_t tmr;
227 u8_t retries;
228 u8_t seqno;
229#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0)
230 u8_t pcb_idx;
231#endif
233#if LWIP_IPV4 && LWIP_IPV6
234 u8_t reqaddrtype;
235#endif /* LWIP_IPV4 && LWIP_IPV6 */
236#if LWIP_DNS_SUPPORT_MDNS_QUERIES
237 u8_t is_mdns;
238#endif
239};
240
243struct dns_req_entry {
244 /* pointer to callback on DNS query done */
245 dns_found_callback found;
246 /* argument passed to the callback function */
247 void *arg;
248#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0)
249 u8_t dns_table_idx;
250#endif
251#if LWIP_IPV4 && LWIP_IPV6
252 u8_t reqaddrtype;
253#endif /* LWIP_IPV4 && LWIP_IPV6 */
254};
255
256#if DNS_LOCAL_HOSTLIST
257
258#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
261static struct local_hostlist_entry *local_hostlist_dynamic;
262#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
263
266#ifndef DNS_LOCAL_HOSTLIST_STORAGE_PRE
267#define DNS_LOCAL_HOSTLIST_STORAGE_PRE static
268#endif /* DNS_LOCAL_HOSTLIST_STORAGE_PRE */
271#ifndef DNS_LOCAL_HOSTLIST_STORAGE_POST
272#define DNS_LOCAL_HOSTLIST_STORAGE_POST
273#endif /* DNS_LOCAL_HOSTLIST_STORAGE_POST */
274DNS_LOCAL_HOSTLIST_STORAGE_PRE struct local_hostlist_entry local_hostlist_static[]
275 DNS_LOCAL_HOSTLIST_STORAGE_POST = DNS_LOCAL_HOSTLIST_INIT;
276
277#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
278
279static void dns_init_local(void);
280static err_t dns_lookup_local(const char *hostname, size_t hostnamelen, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype));
281#endif /* DNS_LOCAL_HOSTLIST */
282
283
284/* forward declarations */
285static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port);
286static void dns_check_entries(void);
287static void dns_call_found(u8_t idx, ip_addr_t *addr);
288
289/*-----------------------------------------------------------------------------
290 * Globals
291 *----------------------------------------------------------------------------*/
292
293/* DNS variables */
294static struct udp_pcb *dns_pcbs[DNS_MAX_SOURCE_PORTS];
295#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0)
296static u8_t dns_last_pcb_idx;
297#endif
298static u8_t dns_seqno;
299static struct dns_table_entry dns_table[DNS_TABLE_SIZE];
300static struct dns_req_entry dns_requests[DNS_MAX_REQUESTS];
301static ip_addr_t dns_servers[DNS_MAX_SERVERS];
302
303#if LWIP_IPV4
304const ip_addr_t dns_mquery_v4group = DNS_MQUERY_IPV4_GROUP_INIT;
305#endif /* LWIP_IPV4 */
306#if LWIP_IPV6
307const ip_addr_t dns_mquery_v6group = DNS_MQUERY_IPV6_GROUP_INIT;
308#endif /* LWIP_IPV6 */
309
314void
315dns_init(void)
316{
317#ifdef DNS_SERVER_ADDRESS
318 /* initialize default DNS server address */
319 ip_addr_t dnsserver;
320 DNS_SERVER_ADDRESS(&dnsserver);
321 dns_setserver(0, &dnsserver);
322#endif /* DNS_SERVER_ADDRESS */
323
324 LWIP_ASSERT("sanity check SIZEOF_DNS_QUERY",
325 sizeof(struct dns_query) == SIZEOF_DNS_QUERY);
326 LWIP_ASSERT("sanity check SIZEOF_DNS_ANSWER",
327 sizeof(struct dns_answer) <= SIZEOF_DNS_ANSWER_ASSERT);
328
329 LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n"));
330
331 /* if dns client not yet initialized... */
332#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) == 0)
333 if (dns_pcbs[0] == NULL) {
334 dns_pcbs[0] = udp_new_ip_type(IPADDR_TYPE_ANY);
335 LWIP_ASSERT("dns_pcbs[0] != NULL", dns_pcbs[0] != NULL);
336
337 /* initialize DNS table not needed (initialized to zero since it is a
338 * global variable) */
339 LWIP_ASSERT("For implicit initialization to work, DNS_STATE_UNUSED needs to be 0",
340 DNS_STATE_UNUSED == 0);
341
342 /* initialize DNS client */
343 udp_bind(dns_pcbs[0], IP_ANY_TYPE, 0);
344 udp_recv(dns_pcbs[0], dns_recv, NULL);
345 }
346#endif
347
348#if DNS_LOCAL_HOSTLIST
349 dns_init_local();
350#endif
351}
352
360void
361dns_setserver(u8_t numdns, const ip_addr_t *dnsserver)
362{
363 if (numdns < DNS_MAX_SERVERS) {
364 if (dnsserver != NULL) {
365 dns_servers[numdns] = (*dnsserver);
366 } else {
367 dns_servers[numdns] = *IP_ADDR_ANY;
368 }
369 }
370}
371
380const ip_addr_t *
381dns_getserver(u8_t numdns)
382{
383 if (numdns < DNS_MAX_SERVERS) {
384 return &dns_servers[numdns];
385 } else {
386 return IP_ADDR_ANY;
387 }
388}
389
394void
395dns_tmr(void)
396{
397 LWIP_DEBUGF(DNS_DEBUG, ("dns_tmr: dns_check_entries\n"));
398 dns_check_entries();
399}
400
401#if DNS_LOCAL_HOSTLIST
402static void
403dns_init_local(void)
404{
405#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT)
406 size_t i;
407 struct local_hostlist_entry *entry;
408 /* Dynamic: copy entries from DNS_LOCAL_HOSTLIST_INIT to list */
409 struct local_hostlist_entry local_hostlist_init[] = DNS_LOCAL_HOSTLIST_INIT;
410 size_t namelen;
411 for (i = 0; i < LWIP_ARRAYSIZE(local_hostlist_init); i++) {
412 struct local_hostlist_entry *init_entry = &local_hostlist_init[i];
413 LWIP_ASSERT("invalid host name (NULL)", init_entry->name != NULL);
414 namelen = strlen(init_entry->name);
415 LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN);
416 entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST);
417 LWIP_ASSERT("mem-error in dns_init_local", entry != NULL);
418 if (entry != NULL) {
419 char *entry_name = (char *)entry + sizeof(struct local_hostlist_entry);
420 MEMCPY(entry_name, init_entry->name, namelen);
421 entry_name[namelen] = 0;
422 entry->name = entry_name;
423 entry->addr = init_entry->addr;
424 entry->next = local_hostlist_dynamic;
425 local_hostlist_dynamic = entry;
426 }
427 }
428#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) */
429}
430
439size_t
440dns_local_iterate(dns_found_callback iterator_fn, void *iterator_arg)
441{
442 size_t i;
443#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
444 struct local_hostlist_entry *entry = local_hostlist_dynamic;
445 i = 0;
446 while (entry != NULL) {
447 if (iterator_fn != NULL) {
448 iterator_fn(entry->name, &entry->addr, iterator_arg);
449 }
450 i++;
451 entry = entry->next;
452 }
453#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
454 for (i = 0; i < LWIP_ARRAYSIZE(local_hostlist_static); i++) {
455 if (iterator_fn != NULL) {
456 iterator_fn(local_hostlist_static[i].name, &local_hostlist_static[i].addr, iterator_arg);
457 }
458 }
459#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
460 return i;
461}
462
476err_t
477dns_local_lookup(const char *hostname, ip_addr_t *addr, u8_t dns_addrtype)
478{
479 size_t hostnamelen;
480 LWIP_UNUSED_ARG(dns_addrtype);
481 if ((addr == NULL) ||
482 (!hostname) || (!hostname[0])) {
483 return ERR_ARG;
484 }
485 hostnamelen = strlen(hostname);
486 if (hostname[hostnamelen - 1] == '.') {
487 hostnamelen--;
488 }
489 if (hostnamelen >= DNS_MAX_NAME_LENGTH) {
490 LWIP_DEBUGF(DNS_DEBUG, ("dns_local_lookup: name too long to resolve\n"));
491 return ERR_ARG;
492 }
493 return dns_lookup_local(hostname, hostnamelen, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype));
494}
495
496/* Internal implementation for dns_local_lookup and dns_lookup */
497static err_t
498dns_lookup_local(const char *hostname, size_t hostnamelen, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype))
499{
500#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
501 struct local_hostlist_entry *entry = local_hostlist_dynamic;
502 while (entry != NULL) {
503 if ((lwip_strnicmp(entry->name, hostname, hostnamelen) == 0) &&
504 !entry->name[hostnamelen] &&
505 LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, entry->addr)) {
506 if (addr) {
507 ip_addr_copy(*addr, entry->addr);
508 }
509 return ERR_OK;
510 }
511 entry = entry->next;
512 }
513#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
514 size_t i;
515 for (i = 0; i < LWIP_ARRAYSIZE(local_hostlist_static); i++) {
516 if ((lwip_strnicmp(local_hostlist_static[i].name, hostname, hostnamelen) == 0) &&
517 !local_hostlist_static[i].name[hostnamelen] &&
518 LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, local_hostlist_static[i].addr)) {
519 if (addr) {
520 ip_addr_copy(*addr, local_hostlist_static[i].addr);
521 }
522 return ERR_OK;
523 }
524 }
525#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
526 return ERR_ARG;
527}
528
529#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
540int
541dns_local_removehost(const char *hostname, const ip_addr_t *addr)
542{
543 int removed = 0;
544 struct local_hostlist_entry *entry = local_hostlist_dynamic;
545 struct local_hostlist_entry *last_entry = NULL;
546 while (entry != NULL) {
547 if (((hostname == NULL) || !lwip_stricmp(entry->name, hostname)) &&
548 ((addr == NULL) || ip_addr_eq(&entry->addr, addr))) {
549 struct local_hostlist_entry *free_entry;
550 if (last_entry != NULL) {
551 last_entry->next = entry->next;
552 } else {
553 local_hostlist_dynamic = entry->next;
554 }
555 free_entry = entry;
556 entry = entry->next;
557 memp_free(MEMP_LOCALHOSTLIST, free_entry);
558 removed++;
559 } else {
560 last_entry = entry;
561 entry = entry->next;
562 }
563 }
564 return removed;
565}
566
576err_t
577dns_local_addhost(const char *hostname, const ip_addr_t *addr)
578{
579 struct local_hostlist_entry *entry;
580 size_t namelen;
581 char *entry_name;
582 LWIP_ASSERT("invalid host name (NULL)", hostname != NULL);
584 LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN);
585 entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST);
586 if (entry == NULL) {
587 return ERR_MEM;
588 }
589 entry_name = (char *)entry + sizeof(struct local_hostlist_entry);
590 MEMCPY(entry_name, hostname, namelen);
591 entry_name[namelen] = 0;
592 entry->name = entry_name;
593 ip_addr_copy(entry->addr, *addr);
594 entry->next = local_hostlist_dynamic;
595 local_hostlist_dynamic = entry;
596 return ERR_OK;
597}
598#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC*/
599#endif /* DNS_LOCAL_HOSTLIST */
600
617static err_t
618dns_lookup(const char *name, size_t hostnamelen, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype))
619{
620 size_t namelen;
621 u8_t i;
622#if DNS_LOCAL_HOSTLIST
623 if (dns_lookup_local(name, hostnamelen, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)) == ERR_OK) {
624 return ERR_OK;
625 }
626#endif /* DNS_LOCAL_HOSTLIST */
627#ifdef DNS_LOOKUP_LOCAL_EXTERN
628 if (DNS_LOOKUP_LOCAL_EXTERN(name, hostnamelen, addr, LWIP_DNS_ADDRTYPE_ARG_OR_ZERO(dns_addrtype)) == ERR_OK) {
629 return ERR_OK;
630 }
631#endif /* DNS_LOOKUP_LOCAL_EXTERN */
632
633 namelen = LWIP_MIN(hostnamelen, DNS_MAX_NAME_LENGTH - 1);
634 /* Walk through name list, return entry if found. If not, return NULL. */
635 for (i = 0; i < DNS_TABLE_SIZE; ++i) {
636 if ((dns_table[i].state == DNS_STATE_DONE) &&
637 (lwip_strnicmp(name, dns_table[i].name, namelen) == 0) &&
638 !dns_table[i].name[namelen] &&
639 LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, dns_table[i].ipaddr)) {
640 LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name));
641 ip_addr_debug_print_val(DNS_DEBUG, dns_table[i].ipaddr);
642 LWIP_DEBUGF(DNS_DEBUG, ("\n"));
643 if (addr) {
644 ip_addr_copy(*addr, dns_table[i].ipaddr);
645 }
646 return ERR_OK;
647 }
648 }
649
650 return ERR_ARG;
651}
652
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) || (response_offset == 0xFFFF)) {
678 /* error or overflow */
679 return 0xFFFF;
680 }
681 response_offset++;
683 if ((n & 0xc0) == 0xc0) {
684 /* Compressed name: cannot be equal since we don't send them */
685 return 0xFFFF;
686 } else {
687 /* Not compressed name */
688 while (n > 0) {
689 int c = pbuf_try_get_at(p, response_offset);
690 if (c < 0) {
691 return 0xFFFF;
692 }
693 if (lwip_tolower((*query)) != lwip_tolower((u8_t)c)) {
694 return 0xFFFF;
695 }
696 if (response_offset == 0xFFFF) {
697 /* would overflow */
698 return 0xFFFF;
699 }
700 response_offset++;
701 ++query;
702 --n;
703 }
704 ++query;
705 }
706 n = pbuf_try_get_at(p, response_offset);
707 if (n < 0) {
708 return 0xFFFF;
709 }
710 } while (n != 0);
711
712 if (response_offset == 0xFFFF) {
713 /* would overflow */
714 return 0xFFFF;
715 }
716 return (u16_t)(response_offset + 1);
717}
718
726static u16_t
727dns_skip_name(struct pbuf *p, u16_t query_idx)
728{
729 int n;
730 u16_t offset = query_idx;
731
732 do {
734 if ((n < 0) || (offset == 0)) {
735 return 0xFFFF;
736 }
738 if ((n & 0xc0) == 0xc0) {
739 /* Compressed name: since we only want to skip it (not check it), stop here */
740 break;
741 } else {
742 /* Not compressed name */
743 if (offset + n >= p->tot_len) {
744 return 0xFFFF;
745 }
746 offset = (u16_t)(offset + n);
747 }
749 if (n < 0) {
750 return 0xFFFF;
751 }
752 } while (n != 0);
753
754 if (offset == 0xFFFF) {
755 return 0xFFFF;
756 }
757 return (u16_t)(offset + 1);
758}
759
766static err_t
767dns_send(u8_t idx)
768{
769 err_t err;
770 struct dns_hdr hdr;
771 struct dns_query qry;
772 struct pbuf *p;
773 u16_t query_idx, copy_len;
774 const char *hostname, *hostname_part;
775 u8_t n;
776 u8_t pcb_idx;
777 struct dns_table_entry *entry = &dns_table[idx];
778
779 LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n",
780 (u16_t)(entry->server_idx), entry->name));
781 LWIP_ASSERT("dns server out of array", entry->server_idx < DNS_MAX_SERVERS);
782 if (ip_addr_isany_val(dns_servers[entry->server_idx])
784 && !entry->is_mdns
785#endif
786 ) {
787 /* DNS server not valid anymore, e.g. PPP netif has been shut down */
788 /* call specified callback function if provided */
789 dns_call_found(idx, NULL);
790 /* flush this entry */
791 entry->state = DNS_STATE_UNUSED;
792 return ERR_OK;
793 }
794
795 /* if here, we have either a new query or a retry on a previous query to process */
797 SIZEOF_DNS_QUERY), PBUF_RAM);
798 if (p != NULL) {
799 const ip_addr_t *dst;
800 u16_t dst_port;
801 /* fill dns header */
803 hdr.id = lwip_htons(entry->txid);
804 hdr.flags1 = DNS_FLAG1_RD;
805 hdr.numquestions = PP_HTONS(1);
807 hostname = entry->name;
808 --hostname;
809
810 /* convert hostname into suitable query format. */
811 query_idx = SIZEOF_DNS_HDR;
812 do {
813 ++hostname;
814 hostname_part = hostname;
815 for (n = 0; *hostname != '.' && *hostname != 0; ++hostname) {
816 ++n;
817 }
818 copy_len = (u16_t)(hostname - hostname_part);
819 if (query_idx + n + 1 > 0xFFFF) {
820 /* u16_t overflow */
821 goto overflow_return;
822 }
823 pbuf_put_at(p, query_idx, n);
824 pbuf_take_at(p, hostname_part, copy_len, (u16_t)(query_idx + 1));
825 query_idx = (u16_t)(query_idx + n + 1);
826 } while (*hostname != 0);
827 pbuf_put_at(p, query_idx, 0);
828 query_idx++;
829
830 /* fill dns query */
831 if (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype)) {
832 qry.type = PP_HTONS(DNS_RRTYPE_AAAA);
833 } else {
834 qry.type = PP_HTONS(DNS_RRTYPE_A);
835 }
836 qry.cls = PP_HTONS(DNS_RRCLASS_IN);
837 pbuf_take_at(p, &qry, SIZEOF_DNS_QUERY, query_idx);
838
839#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0)
840 pcb_idx = entry->pcb_idx;
841#else
842 pcb_idx = 0;
843#endif
844 /* send dns packet */
845 LWIP_DEBUGF(DNS_DEBUG, ("sending DNS request ID %d for name \"%s\" to server %d\r\n",
846 entry->txid, entry->name, entry->server_idx));
847#if LWIP_DNS_SUPPORT_MDNS_QUERIES
848 if (entry->is_mdns) {
849 dst_port = DNS_MQUERY_PORT;
850#if LWIP_IPV6
851 if (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype)) {
852 dst = &dns_mquery_v6group;
853 }
854#endif
855#if LWIP_IPV4 && LWIP_IPV6
856 else
857#endif
858#if LWIP_IPV4
859 {
860 dst = &dns_mquery_v4group;
861 }
862#endif
863 } else
864#endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */
865 {
866 dst_port = DNS_SERVER_PORT;
867 dst = &dns_servers[entry->server_idx];
868 }
869 err = udp_sendto(dns_pcbs[pcb_idx], p, dst, dst_port);
870
871 /* free pbuf */
872 pbuf_free(p);
873 } else {
874 err = ERR_MEM;
875 }
876
877 return err;
878overflow_return:
879 pbuf_free(p);
880 return ERR_VAL;
881}
882
883#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0)
884static struct udp_pcb *
885dns_alloc_random_port(void)
886{
887 err_t err;
888 struct udp_pcb *pcb;
889
890 pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
891 if (pcb == NULL) {
892 /* out of memory, have to reuse an existing pcb */
893 return NULL;
894 }
895 do {
896 u16_t port = (u16_t)DNS_RAND_TXID();
897 if (DNS_PORT_ALLOWED(port)) {
898 err = udp_bind(pcb, IP_ANY_TYPE, port);
899 } else {
900 /* this port is not allowed, try again */
901 err = ERR_USE;
902 }
903 } while (err == ERR_USE);
904 if (err != ERR_OK) {
905 udp_remove(pcb);
906 return NULL;
907 }
908 udp_recv(pcb, dns_recv, NULL);
909 return pcb;
910}
911
918static u8_t
919dns_alloc_pcb(void)
920{
921 u8_t i;
922 u8_t idx;
923
924 for (i = 0; i < DNS_MAX_SOURCE_PORTS; i++) {
925 if (dns_pcbs[i] == NULL) {
926 break;
927 }
928 }
929 if (i < DNS_MAX_SOURCE_PORTS) {
930 dns_pcbs[i] = dns_alloc_random_port();
931 if (dns_pcbs[i] != NULL) {
932 /* succeeded */
933 dns_last_pcb_idx = i;
934 return i;
935 }
936 }
937 /* if we come here, creating a new UDP pcb failed, so we have to use
938 an already existing one (so overflow is no issue) */
939 for (i = 0, idx = (u8_t)(dns_last_pcb_idx + 1); i < DNS_MAX_SOURCE_PORTS; i++, idx++) {
940 if (idx >= DNS_MAX_SOURCE_PORTS) {
941 idx = 0;
942 }
943 if (dns_pcbs[idx] != NULL) {
944 dns_last_pcb_idx = idx;
945 return idx;
946 }
947 }
948 return DNS_MAX_SOURCE_PORTS;
949}
950#endif /* ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) */
951
960static void
961dns_call_found(u8_t idx, ip_addr_t *addr)
962{
963#if ((LWIP_DNS_SECURE & (LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING | LWIP_DNS_SECURE_RAND_SRC_PORT)) != 0)
964 u8_t i;
965#endif
966
967#if LWIP_IPV4 && LWIP_IPV6
968 if (addr != NULL) {
969 /* check that address type matches the request and adapt the table entry */
970 if (IP_IS_V6_VAL(*addr)) {
971 LWIP_ASSERT("invalid response", LWIP_DNS_ADDRTYPE_IS_IPV6(dns_table[idx].reqaddrtype));
972 dns_table[idx].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV6;
973 } else {
974 LWIP_ASSERT("invalid response", !LWIP_DNS_ADDRTYPE_IS_IPV6(dns_table[idx].reqaddrtype));
975 dns_table[idx].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV4;
976 }
977 }
978#endif /* LWIP_IPV4 && LWIP_IPV6 */
979
980#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0)
981 for (i = 0; i < DNS_MAX_REQUESTS; i++) {
982 if (dns_requests[i].found && (dns_requests[i].dns_table_idx == idx)) {
983 (*dns_requests[i].found)(dns_table[idx].name, addr, dns_requests[i].arg);
984 /* flush this entry */
985 dns_requests[i].found = NULL;
986 }
987 }
988#else
989 if (dns_requests[idx].found) {
990 (*dns_requests[idx].found)(dns_table[idx].name, addr, dns_requests[idx].arg);
991 }
992 dns_requests[idx].found = NULL;
993#endif
994#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0)
995 /* close the pcb used unless other request are using it */
996 for (i = 0; i < DNS_MAX_REQUESTS; i++) {
997 if (i == idx) {
998 continue; /* only check other requests */
999 }
1000 if (dns_table[i].state == DNS_STATE_ASKING) {
1001 if (dns_table[i].pcb_idx == dns_table[idx].pcb_idx) {
1002 /* another request is still using the same pcb */
1003 dns_table[idx].pcb_idx = DNS_MAX_SOURCE_PORTS;
1004 break;
1005 }
1006 }
1007 }
1008 if (dns_table[idx].pcb_idx < DNS_MAX_SOURCE_PORTS) {
1009 /* if we come here, the pcb is not used any more and can be removed */
1010 udp_remove(dns_pcbs[dns_table[idx].pcb_idx]);
1011 dns_pcbs[dns_table[idx].pcb_idx] = NULL;
1012 dns_table[idx].pcb_idx = DNS_MAX_SOURCE_PORTS;
1013 }
1014#endif
1015}
1016
1017/* Create a query transmission ID that is unique for all outstanding queries */
1018static u16_t
1019dns_create_txid(void)
1020{
1021 u16_t txid;
1022 u8_t i;
1023
1024again:
1025 txid = (u16_t)DNS_RAND_TXID();
1026
1027 /* check whether the ID is unique */
1028 for (i = 0; i < DNS_TABLE_SIZE; i++) {
1029 if ((dns_table[i].state == DNS_STATE_ASKING) &&
1030 (dns_table[i].txid == txid)) {
1031 /* ID already used by another pending query */
1032 goto again;
1033 }
1034 }
1035
1036 return txid;
1037}
1038
1042static u8_t
1043dns_backupserver_available(struct dns_table_entry *pentry)
1044{
1045 u8_t ret = 0;
1046
1047 if (pentry) {
1048 if ((pentry->server_idx + 1 < DNS_MAX_SERVERS) && !ip_addr_isany_val(dns_servers[pentry->server_idx + 1])) {
1049 ret = 1;
1050 }
1051 }
1052
1053 return ret;
1054}
1055
1065static void
1066dns_check_entry(u8_t i)
1067{
1068 err_t err;
1069 struct dns_table_entry *entry = &dns_table[i];
1070
1071 LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE);
1072
1073 switch (entry->state) {
1074 case DNS_STATE_NEW:
1075 /* initialize new entry */
1076 entry->txid = dns_create_txid();
1077 entry->state = DNS_STATE_ASKING;
1078 entry->server_idx = 0;
1079 entry->tmr = 1;
1080 entry->retries = 0;
1081
1082 /* send DNS packet for this entry */
1083 err = dns_send(i);
1084 if (err != ERR_OK) {
1086 ("dns_send returned error: %s\n", lwip_strerr(err)));
1087 }
1088 break;
1089 case DNS_STATE_ASKING:
1090 if (--entry->tmr == 0) {
1091 if (++entry->retries == DNS_MAX_RETRIES) {
1092 if (dns_backupserver_available(entry)
1094 && !entry->is_mdns
1095#endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */
1096 ) {
1097 /* change of server */
1098 entry->server_idx++;
1099 entry->tmr = 1;
1100 entry->retries = 0;
1101 } else {
1102 LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": timeout\n", entry->name));
1103 /* call specified callback function if provided */
1104 dns_call_found(i, NULL);
1105 /* flush this entry */
1106 entry->state = DNS_STATE_UNUSED;
1107 break;
1108 }
1109 } else {
1110 /* wait longer for the next retry */
1111 entry->tmr = entry->retries;
1112 }
1113
1114 /* send DNS packet for this entry */
1115 err = dns_send(i);
1116 if (err != ERR_OK) {
1118 ("dns_send returned error: %s\n", lwip_strerr(err)));
1119 }
1120 }
1121 break;
1122 case DNS_STATE_DONE:
1123 /* if the time to live is nul */
1124 if ((entry->ttl == 0) || (--entry->ttl == 0)) {
1125 LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": flush\n", entry->name));
1126 /* flush this entry, there cannot be any related pending entries in this state */
1127 entry->state = DNS_STATE_UNUSED;
1128 }
1129 break;
1130 case DNS_STATE_UNUSED:
1131 /* nothing to do */
1132 break;
1133 default:
1134 LWIP_ASSERT("unknown dns_table entry state:", 0);
1135 break;
1136 }
1137}
1138
1142static void
1143dns_check_entries(void)
1144{
1145 u8_t i;
1146
1147 for (i = 0; i < DNS_TABLE_SIZE; ++i) {
1148 dns_check_entry(i);
1149 }
1150}
1151
1155static void
1156dns_correct_response(u8_t idx, u32_t ttl)
1157{
1158 struct dns_table_entry *entry = &dns_table[idx];
1159
1160 entry->state = DNS_STATE_DONE;
1161
1162 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", entry->name));
1164 LWIP_DEBUGF(DNS_DEBUG, ("\n"));
1165
1166 /* read the answer resource record's TTL, and maximize it if needed */
1167 entry->ttl = ttl;
1168 if (entry->ttl > DNS_MAX_TTL) {
1169 entry->ttl = DNS_MAX_TTL;
1170 }
1171 dns_call_found(idx, &entry->ipaddr);
1172
1173 if (entry->ttl == 0) {
1174 /* RFC 883, page 29: "Zero values are
1175 interpreted to mean that the RR can only be used for the
1176 transaction in progress, and should not be cached."
1177 -> flush this entry now */
1178 /* entry reused during callback? */
1179 if (entry->state == DNS_STATE_DONE) {
1180 entry->state = DNS_STATE_UNUSED;
1181 }
1182 }
1183}
1184
1188static void
1189dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
1190{
1191 u8_t i;
1192 u16_t txid;
1193 u16_t res_idx;
1194 struct dns_hdr hdr;
1195 struct dns_answer ans;
1196 struct dns_query qry;
1197 u16_t nquestions, nanswers;
1198
1200 LWIP_UNUSED_ARG(pcb);
1202
1203 /* is the dns message big enough ? */
1204 if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY)) {
1205 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n"));
1206 /* free pbuf and return */
1207 goto ignore_packet;
1208 }
1209
1210 /* copy dns payload inside static buffer for processing */
1212 /* Match the ID in the DNS header with the name table. */
1213 txid = lwip_htons(hdr.id);
1214 for (i = 0; i < DNS_TABLE_SIZE; i++) {
1215 struct dns_table_entry *entry = &dns_table[i];
1216 if ((entry->state == DNS_STATE_ASKING) &&
1217 (entry->txid == txid)) {
1218
1219 /* We only care about the question(s) and the answers. The authrr
1220 and the extrarr are simply discarded. */
1221 nquestions = lwip_htons(hdr.numquestions);
1222 nanswers = lwip_htons(hdr.numanswers);
1223
1224 /* Check for correct response. */
1225 if ((hdr.flags1 & DNS_FLAG1_RESPONSE) == 0) {
1226 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": not a response\n", entry->name));
1227 goto ignore_packet; /* ignore this packet */
1228 }
1229 if (nquestions != 1) {
1230 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", entry->name));
1231 goto ignore_packet; /* ignore this packet */
1232 }
1233
1234#if LWIP_DNS_SUPPORT_MDNS_QUERIES
1235 if (!entry->is_mdns)
1236#endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */
1237 {
1238 /* Check whether response comes from the same network address to which the
1239 question was sent. (RFC 5452) */
1240 if (!ip_addr_eq(addr, &dns_servers[entry->server_idx])) {
1241 goto ignore_packet; /* ignore this packet */
1242 }
1243 }
1244
1245 /* Check if the name in the "question" part match with the name in the entry and
1246 skip it if equal. */
1247 res_idx = dns_compare_name(entry->name, p, SIZEOF_DNS_HDR);
1248 if (res_idx == 0xFFFF) {
1249 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", entry->name));
1250 goto ignore_packet; /* ignore this packet */
1251 }
1252
1253 /* check if "question" part matches the request */
1254 if (pbuf_copy_partial(p, &qry, SIZEOF_DNS_QUERY, res_idx) != SIZEOF_DNS_QUERY) {
1255 goto ignore_packet; /* ignore this packet */
1256 }
1257 if ((qry.cls != PP_HTONS(DNS_RRCLASS_IN)) ||
1258 (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype) && (qry.type != PP_HTONS(DNS_RRTYPE_AAAA))) ||
1259 (!LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype) && (qry.type != PP_HTONS(DNS_RRTYPE_A)))) {
1260 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", entry->name));
1261 goto ignore_packet; /* ignore this packet */
1262 }
1263 /* skip the rest of the "question" part */
1264 if (res_idx + SIZEOF_DNS_QUERY > 0xFFFF) {
1265 goto ignore_packet;
1266 }
1267 res_idx = (u16_t)(res_idx + SIZEOF_DNS_QUERY);
1268
1269 /* Check for error. If so, call callback to inform. */
1270 if (hdr.flags2 & DNS_FLAG2_ERR_MASK) {
1271 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in flags\n", entry->name));
1272
1273 /* if there is another backup DNS server to try
1274 * then don't stop the DNS request
1275 */
1276 if (dns_backupserver_available(entry)) {
1277 /* avoid retrying the same server */
1278 entry->retries = DNS_MAX_RETRIES-1;
1279 entry->tmr = 1;
1280
1281 /* contact next available server for this entry */
1282 dns_check_entry(i);
1283
1284 goto ignore_packet;
1285 }
1286 } else {
1287 while ((nanswers > 0) && (res_idx < p->tot_len)) {
1288 /* skip answer resource record's host name */
1289 res_idx = dns_skip_name(p, res_idx);
1290 if (res_idx == 0xFFFF) {
1291 goto ignore_packet; /* ignore this packet */
1292 }
1293
1294 /* Check for IP address type and Internet class. Others are discarded. */
1295 if (pbuf_copy_partial(p, &ans, SIZEOF_DNS_ANSWER, res_idx) != SIZEOF_DNS_ANSWER) {
1296 goto ignore_packet; /* ignore this packet */
1297 }
1298 if (res_idx + SIZEOF_DNS_ANSWER > 0xFFFF) {
1299 goto ignore_packet;
1300 }
1301 res_idx = (u16_t)(res_idx + SIZEOF_DNS_ANSWER);
1302
1303 if (ans.cls == PP_HTONS(DNS_RRCLASS_IN)) {
1304#if LWIP_IPV4
1305 if ((ans.type == PP_HTONS(DNS_RRTYPE_A)) && (ans.len == PP_HTONS(sizeof(ip4_addr_t)))) {
1306#if LWIP_IPV4 && LWIP_IPV6
1307 if (!LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype))
1308#endif /* LWIP_IPV4 && LWIP_IPV6 */
1309 {
1310 ip4_addr_t ip4addr;
1311 /* read the IP address after answer resource record's header */
1312 if (pbuf_copy_partial(p, &ip4addr, sizeof(ip4_addr_t), res_idx) != sizeof(ip4_addr_t)) {
1313 goto ignore_packet; /* ignore this packet */
1314 }
1315 ip_addr_copy_from_ip4(dns_table[i].ipaddr, ip4addr);
1316 pbuf_free(p);
1317 /* handle correct response */
1318 dns_correct_response(i, lwip_ntohl(ans.ttl));
1319 return;
1320 }
1321 }
1322#endif /* LWIP_IPV4 */
1323#if LWIP_IPV6
1324 if ((ans.type == PP_HTONS(DNS_RRTYPE_AAAA)) && (ans.len == PP_HTONS(sizeof(ip6_addr_p_t)))) {
1325#if LWIP_IPV4 && LWIP_IPV6
1326 if (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype))
1327#endif /* LWIP_IPV4 && LWIP_IPV6 */
1328 {
1329 ip6_addr_p_t ip6addr;
1330 /* read the IP address after answer resource record's header */
1331 if (pbuf_copy_partial(p, &ip6addr, sizeof(ip6_addr_p_t), res_idx) != sizeof(ip6_addr_p_t)) {
1332 goto ignore_packet; /* ignore this packet */
1333 }
1334 /* @todo: scope ip6addr? Might be required for link-local addresses at least? */
1335 ip_addr_copy_from_ip6_packed(dns_table[i].ipaddr, ip6addr);
1336 pbuf_free(p);
1337 /* handle correct response */
1338 dns_correct_response(i, lwip_ntohl(ans.ttl));
1339 return;
1340 }
1341 }
1342#endif /* LWIP_IPV6 */
1343 }
1344 /* skip this answer */
1345 if ((int)(res_idx + lwip_htons(ans.len)) > 0xFFFF) {
1346 goto ignore_packet; /* ignore this packet */
1347 }
1348 res_idx = (u16_t)(res_idx + lwip_htons(ans.len));
1349 --nanswers;
1350 }
1351#if LWIP_IPV4 && LWIP_IPV6
1352 if ((entry->reqaddrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) ||
1353 (entry->reqaddrtype == LWIP_DNS_ADDRTYPE_IPV6_IPV4)) {
1354 if (entry->reqaddrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) {
1355 /* IPv4 failed, try IPv6 */
1356 dns_table[i].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV6;
1357 } else {
1358 /* IPv6 failed, try IPv4 */
1359 dns_table[i].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV4;
1360 }
1361 pbuf_free(p);
1362 dns_table[i].state = DNS_STATE_NEW;
1363 dns_check_entry(i);
1364 return;
1365 }
1366#endif /* LWIP_IPV4 && LWIP_IPV6 */
1367 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in response\n", entry->name));
1368 }
1369 /* call callback to indicate error, clean up memory and return */
1370 pbuf_free(p);
1371 dns_call_found(i, NULL);
1372 dns_table[i].state = DNS_STATE_UNUSED;
1373 return;
1374 }
1375 }
1376 }
1377
1378ignore_packet:
1379 /* deallocate memory and return */
1380 pbuf_free(p);
1381 return;
1382}
1383
1393static err_t
1394dns_enqueue(const char *name, size_t hostnamelen, dns_found_callback found,
1395 void *callback_arg LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype) LWIP_DNS_ISMDNS_ARG(u8_t is_mdns))
1396{
1397 u8_t i;
1398 u8_t lseq, lseqi;
1399 struct dns_table_entry *entry = NULL;
1400 size_t namelen;
1401 struct dns_req_entry *req;
1402#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0)
1403 u8_t r;
1404#endif
1405
1406 namelen = LWIP_MIN(hostnamelen, DNS_MAX_NAME_LENGTH - 1);
1407
1408#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0)
1409 /* check for duplicate entries */
1410 for (i = 0; i < DNS_TABLE_SIZE; i++) {
1411 if ((dns_table[i].state == DNS_STATE_ASKING) &&
1412 (lwip_strnicmp(name, dns_table[i].name, namelen) == 0) &&
1413 !dns_table[i].name[namelen]) {
1414#if LWIP_IPV4 && LWIP_IPV6
1415 if (dns_table[i].reqaddrtype != dns_addrtype) {
1416 /* requested address types don't match
1417 this can lead to 2 concurrent requests, but mixing the address types
1418 for the same host should not be that common */
1419 continue;
1420 }
1421#endif /* LWIP_IPV4 && LWIP_IPV6 */
1422 /* this is a duplicate entry, find a free request entry */
1423 for (r = 0; r < DNS_MAX_REQUESTS; r++) {
1424 if (dns_requests[r].found == NULL) {
1425 dns_requests[r].found = found;
1426 dns_requests[r].arg = callback_arg;
1427 dns_requests[r].dns_table_idx = i;
1428 LWIP_DNS_SET_ADDRTYPE(dns_requests[r].reqaddrtype, dns_addrtype);
1429 LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": duplicate request\n", name));
1430 return ERR_INPROGRESS;
1431 }
1432 }
1433 }
1434 }
1435 /* no duplicate entries found */
1436#endif
1437
1438 /* search an unused entry, or the oldest one */
1439 lseq = 0;
1440 lseqi = DNS_TABLE_SIZE;
1441 for (i = 0; i < DNS_TABLE_SIZE; ++i) {
1442 entry = &dns_table[i];
1443 /* is it an unused entry ? */
1444 if (entry->state == DNS_STATE_UNUSED) {
1445 break;
1446 }
1447 /* check if this is the oldest completed entry */
1448 if (entry->state == DNS_STATE_DONE) {
1449 u8_t age = (u8_t)(dns_seqno - entry->seqno);
1450 if (age > lseq) {
1451 lseq = age;
1452 lseqi = i;
1453 }
1454 }
1455 }
1456
1457 /* if we don't have found an unused entry, use the oldest completed one */
1458 if (i == DNS_TABLE_SIZE) {
1459 if ((lseqi >= DNS_TABLE_SIZE) || (dns_table[lseqi].state != DNS_STATE_DONE)) {
1460 /* no entry can be used now, table is full */
1461 LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS entries table is full\n", name));
1462 return ERR_MEM;
1463 } else {
1464 /* use the oldest completed one */
1465 i = lseqi;
1466 entry = &dns_table[i];
1467 }
1468 }
1469
1470#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0)
1471 /* find a free request entry */
1472 req = NULL;
1473 for (r = 0; r < DNS_MAX_REQUESTS; r++) {
1474 if (dns_requests[r].found == NULL) {
1475 req = &dns_requests[r];
1476 break;
1477 }
1478 }
1479 if (req == NULL) {
1480 /* no request entry can be used now, table is full */
1481 LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS request entries table is full\n", name));
1482 return ERR_MEM;
1483 }
1484 req->dns_table_idx = i;
1485#else
1486 /* in this configuration, the entry index is the same as the request index */
1487 req = &dns_requests[i];
1488#endif
1489
1490 /* use this entry */
1491 LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS entry %"U16_F"\n", name, (u16_t)(i)));
1492
1493 /* fill the entry */
1494 entry->state = DNS_STATE_NEW;
1495 entry->seqno = dns_seqno;
1496 LWIP_DNS_SET_ADDRTYPE(entry->reqaddrtype, dns_addrtype);
1497 LWIP_DNS_SET_ADDRTYPE(req->reqaddrtype, dns_addrtype);
1498 req->found = found;
1499 req->arg = callback_arg;
1500 MEMCPY(entry->name, name, namelen);
1501 entry->name[namelen] = 0;
1502
1503#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0)
1504 entry->pcb_idx = dns_alloc_pcb();
1505 if (entry->pcb_idx >= DNS_MAX_SOURCE_PORTS) {
1506 /* failed to get a UDP pcb */
1507 LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": failed to allocate a pcb\n", name));
1508 entry->state = DNS_STATE_UNUSED;
1509 req->found = NULL;
1510 return ERR_MEM;
1511 }
1512 LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS pcb %"U16_F"\n", name, (u16_t)(entry->pcb_idx)));
1513#endif
1514
1515#if LWIP_DNS_SUPPORT_MDNS_QUERIES
1516 entry->is_mdns = is_mdns;
1517#endif
1518
1519 dns_seqno++;
1520
1521 /* force to send query without waiting timer */
1522 dns_check_entry(i);
1523
1524 /* dns query is enqueued */
1525 return ERR_INPROGRESS;
1526}
1527
1548err_t
1549dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found,
1550 void *callback_arg)
1551{
1552 return dns_gethostbyname_addrtype(hostname, addr, found, callback_arg, LWIP_DNS_ADDRTYPE_DEFAULT);
1553}
1554
1569err_t
1570dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, dns_found_callback found,
1571 void *callback_arg, u8_t dns_addrtype)
1572{
1573 size_t hostnamelen;
1574#if LWIP_DNS_SUPPORT_MDNS_QUERIES
1575 u8_t is_mdns;
1576#endif
1577 /* not initialized or no valid server yet, or invalid addr pointer
1578 * or invalid hostname or invalid hostname length */
1579 if ((addr == NULL) ||
1580 (!hostname) || (!hostname[0])) {
1581 return ERR_ARG;
1582 }
1583#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) == 0)
1584 if (dns_pcbs[0] == NULL) {
1585 return ERR_ARG;
1586 }
1587#endif
1588 hostnamelen = strlen(hostname);
1589 if (hostname[hostnamelen - 1] == '.') {
1590 hostnamelen--;
1591 }
1592 if (hostnamelen >= DNS_MAX_NAME_LENGTH) {
1593 LWIP_DEBUGF(DNS_DEBUG, ("dns_gethostbyname: name too long to resolve\n"));
1594 return ERR_ARG;
1595 }
1596
1597
1598#if LWIP_HAVE_LOOPIF
1599 if (strcmp(hostname, "localhost") == 0) {
1600 ip_addr_set_loopback(LWIP_DNS_ADDRTYPE_IS_IPV6(dns_addrtype), addr);
1601 return ERR_OK;
1602 }
1603#endif /* LWIP_HAVE_LOOPIF */
1604
1605 /* host name already in octet notation? set ip addr and return ERR_OK */
1606 if (ipaddr_aton(hostname, addr)) {
1607#if LWIP_IPV4 && LWIP_IPV6
1608 if ((IP_IS_V6(addr) && (dns_addrtype != LWIP_DNS_ADDRTYPE_IPV4)) ||
1609 (IP_IS_V4(addr) && (dns_addrtype != LWIP_DNS_ADDRTYPE_IPV6)))
1610#endif /* LWIP_IPV4 && LWIP_IPV6 */
1611 {
1612 return ERR_OK;
1613 }
1614 }
1615 /* already have this address cached? */
1616 if (dns_lookup(hostname, hostnamelen, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)) == ERR_OK) {
1617 return ERR_OK;
1618 }
1619#if LWIP_IPV4 && LWIP_IPV6
1620 if ((dns_addrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) || (dns_addrtype == LWIP_DNS_ADDRTYPE_IPV6_IPV4)) {
1621 /* fallback to 2nd IP type and try again to lookup */
1622 u8_t fallback;
1623 if (dns_addrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) {
1624 fallback = LWIP_DNS_ADDRTYPE_IPV6;
1625 } else {
1626 fallback = LWIP_DNS_ADDRTYPE_IPV4;
1627 }
1628 if (dns_lookup(hostname, hostnamelen, addr LWIP_DNS_ADDRTYPE_ARG(fallback)) == ERR_OK) {
1629 return ERR_OK;
1630 }
1631 }
1632#else /* LWIP_IPV4 && LWIP_IPV6 */
1633 LWIP_UNUSED_ARG(dns_addrtype);
1634#endif /* LWIP_IPV4 && LWIP_IPV6 */
1635
1636#if LWIP_DNS_SUPPORT_MDNS_QUERIES
1637 if (strstr(hostname, ".local") == &hostname[hostnamelen] - 6) {
1638 is_mdns = 1;
1639 } else {
1640 is_mdns = 0;
1641 }
1642
1643 if (!is_mdns)
1644#endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */
1645 {
1646 /* prevent calling found callback if no server is set, return error instead */
1647 if (ip_addr_isany_val(dns_servers[0])) {
1648 return ERR_VAL;
1649 }
1650 }
1651
1652 /* queue query with specified callback */
1653 return dns_enqueue(hostname, hostnamelen, found, callback_arg LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)
1654 LWIP_DNS_ISMDNS_ARG(is_mdns));
1655}
1656
1657#endif /* LWIP_DNS */
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
char * strstr(char *String1, char *String2)
Definition: utclib.c:653
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
static int state
Definition: maze.c:121
char * hostname
Definition: ftp.c:88
#define PP_HTONS(x)
Definition: def.h:90
#define lwip_htons(x)
Definition: def.h:86
#define LWIP_ARRAYSIZE(x)
Definition: def.h:69
#define lwip_ntohl(x)
Definition: def.h:89
#define LWIP_MIN(x, y)
Definition: def.h:66
#define NULL
Definition: types.h:112
unsigned int idx
Definition: utils.c:41
USHORT port
Definition: uri.c:228
#define U16_F
Definition: cc.h:19
#define LWIP_DEBUGF(debug, message)
Definition: debug.h:158
#define LWIP_ASSERT(message, assertion)
Definition: debug.h:116
#define lwip_strerr(x)
Definition: err.h:106
#define ERR_MEM
Definition: fontsub.h:52
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
GLdouble s
Definition: gl.h:2039
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
GLdouble n
Definition: glext.h:7729
GLintptr offset
Definition: glext.h:5920
const GLubyte * c
Definition: glext.h:8905
GLint namelen
Definition: glext.h:7232
GLenum GLenum dst
Definition: glext.h:6340
GLenum const GLvoid * addr
Definition: glext.h:9621
GLfloat GLfloat p
Definition: glext.h:8902
GLenum GLsizei len
Definition: glext.h:6722
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define lwip_tolower(c)
Definition: arch.h:234
uint32_t u32_t
Definition: arch.h:129
uint8_t u8_t
Definition: arch.h:125
#define LWIP_UNUSED_ARG(x)
Definition: arch.h:373
uint16_t u16_t
Definition: arch.h:127
#define LWIP_DBG_LEVEL_WARNING
Definition: debug.h:55
s8_t err_t
Definition: err.h:96
@ ERR_INPROGRESS
Definition: err.h:65
@ ERR_USE
Definition: err.h:71
@ ERR_OK
Definition: err.h:55
@ ERR_VAL
Definition: err.h:67
@ ERR_ARG
Definition: err.h:88
#define IP_ANY_TYPE
Definition: ip_addr.h:461
@ IPADDR_TYPE_ANY
Definition: ip_addr.h:60
#define DNS_DEBUG
Definition: opt.h:3547
#define DNS_TABLE_SIZE
Definition: opt.h:1140
#define DNS_MAX_NAME_LENGTH
Definition: opt.h:1145
#define DNS_MAX_SERVERS
Definition: opt.h:1153
#define DNS_MAX_RETRIES
Definition: opt.h:1158
#define LWIP_DNS_SUPPORT_MDNS_QUERIES
Definition: opt.h:1202
int pbuf_try_get_at(const struct pbuf *p, u16_t offset)
Definition: pbuf.c:1420
struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
Definition: pbuf.c:224
u8_t pbuf_free(struct pbuf *p)
Definition: pbuf.c:727
u16_t pbuf_copy_partial(const struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
Definition: pbuf.c:1058
err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len)
Definition: pbuf.c:1227
err_t pbuf_take_at(struct pbuf *buf, const void *dataptr, u16_t len, u16_t offset)
Definition: pbuf.c:1271
void pbuf_put_at(struct pbuf *p, u16_t offset, u8_t data)
Definition: pbuf.c:1442
@ PBUF_RAM
Definition: pbuf.h:152
@ PBUF_TRANSPORT
Definition: pbuf.h:93
int lwip_stricmp(const char *str1, const char *str2)
Definition: def.c:151
int lwip_strnicmp(const char *str1, const char *str2, size_t len)
Definition: def.c:186
#define ip_addr_copy_from_ip6_packed(dest, src)
Definition: ip_addr.h:362
#define IP_IS_V6_VAL(ipaddr)
Definition: ip_addr.h:348
#define ip_addr_eq(addr1, addr2)
Definition: ip_addr.h:374
#define ip_addr_copy(dest, src)
Definition: ip_addr.h:360
ip6_addr_t ip_addr_t
Definition: ip_addr.h:344
#define ip_addr_set_loopback(is_ipv6, ipaddr)
Definition: ip_addr.h:368
#define ipaddr_aton(cp, addr)
Definition: ip_addr.h:387
#define IP_IS_V6(ipaddr)
Definition: ip_addr.h:350
#define IP_IS_V4(ipaddr)
Definition: ip_addr.h:349
#define ip_addr_debug_print_val(debug, ipaddr)
Definition: ip_addr.h:384
#define ip_addr_isany_val(ipaddr)
Definition: ip_addr.h:378
char hdr[14]
Definition: iptest.cpp:33
uint32_t entry
Definition: isohybrid.c:63
#define MEMCPY(DST, SRC, BYTES)
Definition: macros.h:231
void * memp_malloc(memp_t type)
Definition: memp.c:337
void memp_free(memp_t type, void *mem)
Definition: memp.c:420
#define DNS_RRCLASS_IN
Definition: dns.h:76
#define SIZEOF_DNS_HDR
Definition: dns.h:116
#define DNS_MQUERY_PORT
Definition: dns.h:123
#define DNS_FLAG1_RD
Definition: dns.h:90
#define DNS_RRTYPE_A
Definition: dns.h:55
#define DNS_MQUERY_IPV4_GROUP_INIT
Definition: dns.h:128
#define DNS_SERVER_PORT
Definition: dns.h:51
#define DNS_FLAG1_RESPONSE
Definition: dns.h:84
#define DNS_FLAG2_ERR_MASK
Definition: dns.h:92
#define DNS_RRTYPE_AAAA
Definition: dns.h:71
#define DNS_MQUERY_IPV6_GROUP_INIT
Definition: dns.h:133
typedefPACK_STRUCT_END struct ip6_addr_packed ip6_addr_p_t
Definition: ip6.h:62
#define err(...)
#define memset(x, y, z)
Definition: compat.h:39
struct define * next
Definition: compiler.c:65
Definition: dns.h:103
Definition: name.c:39
Definition: pbuf.h:186
int ret
void * arg
Definition: msvc.h:10