EVE 1.0
resolv.c
Go to the documentation of this file.
1 /**
2  * \addtogroup uip
3  * @{
4  */
5 
6 /**
7  * \defgroup uipdns uIP hostname resolver functions
8  * @{
9  *
10  * The uIP DNS resolver functions are used to lookup a hostname and
11  * map it to a numerical IP address. It maintains a list of resolved
12  * hostnames that can be queried with the resolv_lookup()
13  * function. New hostnames can be resolved using the resolv_query()
14  * function.
15  *
16  * The event resolv_event_found is posted when a hostname has been
17  * resolved. It is up to the receiving process to determine if the
18  * correct hostname has been found by calling the resolv_lookup()
19  * function with the hostname.
20  */
21 
22 /**
23  * \file
24  * DNS host name to IP address resolver.
25  * \author Adam Dunkels <adam@dunkels.com>
26  * \author Robert Quattlebaum <darco@deepdarc.com>
27  *
28  * This file implements a DNS host name to IP address resolver,
29  * as well as an MDNS responder and resolver.
30  */
31 
32 /*
33  * Copyright (c) 2002-2003, Adam Dunkels.
34  * All rights reserved.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions
38  * are met:
39  * 1. Redistributions of source code must retain the above copyright
40  * notice, this list of conditions and the following disclaimer.
41  * 2. Redistributions in binary form must reproduce the above copyright
42  * notice, this list of conditions and the following disclaimer in the
43  * documentation and/or other materials provided with the distribution.
44  * 3. The name of the author may not be used to endorse or promote
45  * products derived from this software without specific prior
46  * written permission.
47  *
48  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
49  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
50  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
52  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
54  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
55  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
56  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
57  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
58  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
59  *
60  * This file is part of the uIP TCP/IP stack.
61  *
62  *
63  */
64 
65 #include "net/tcpip.h"
66 #include "net/resolv.h"
67 #include "net/uip-udp-packet.h"
68 #include "lib/random.h"
69 
70 #ifndef DEBUG
71 #define DEBUG CONTIKI_TARGET_COOJA
72 #endif
73 
74 #if UIP_UDP
75 
76 #include <string.h>
77 #include <stdio.h>
78 #include <ctype.h>
79 
80 #ifndef NULL
81 #define NULL (void *)0
82 #endif /* NULL */
83 
84 #if !defined(__SDCC) && defined(SDCC_REVISION)
85 #define __SDCC 1
86 #endif
87 
88 #if VERBOSE_DEBUG
89 #define DEBUG_PRINTF(...) printf(__VA_ARGS__)
90 #else
91 #define DEBUG_PRINTF(...) do { } while(0)
92 #endif
93 
94 #if DEBUG || VERBOSE_DEBUG
95 #define PRINTF(...) printf(__VA_ARGS__)
96 #else
97 #define PRINTF(...) do { } while(0)
98 #endif
99 
100 #ifdef __SDCC
101 static int
102 strncasecmp(const char *s1, const char *s2, size_t n)
103 {
104  /* TODO: Add case support! */
105  return strncmp(s1, s2, n);
106 }
107 static int
108 strcasecmp(const char *s1, const char *s2)
109 {
110  /* TODO: Add case support! */
111  return strcmp(s1, s2);
112 }
113 #endif /* __SDCC */
114 
115 #define UIP_UDP_BUF ((struct uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN])
116 
117 /* If RESOLV_CONF_SUPPORTS_MDNS is set, then queries
118  * for domain names in the local TLD will use mDNS as
119  * described by draft-cheshire-dnsext-multicastdns.
120  */
121 #ifndef RESOLV_CONF_SUPPORTS_MDNS
122 #define RESOLV_CONF_SUPPORTS_MDNS 1
123 #endif
124 
125 #ifndef RESOLV_CONF_MDNS_INCLUDE_GLOBAL_V6_ADDRS
126 #define RESOLV_CONF_MDNS_INCLUDE_GLOBAL_V6_ADDRS 0
127 #endif
128 
129 /** The maximum number of retries when asking for a name. */
130 #ifndef RESOLV_CONF_MAX_RETRIES
131 #define RESOLV_CONF_MAX_RETRIES 4
132 #endif
133 
134 #ifndef RESOLV_CONF_MAX_MDNS_RETRIES
135 #define RESOLV_CONF_MAX_MDNS_RETRIES 3
136 #endif
137 
138 #ifndef RESOLV_CONF_MAX_DOMAIN_NAME_SIZE
139 #define RESOLV_CONF_MAX_DOMAIN_NAME_SIZE 32
140 #endif
141 
142 #ifdef RESOLV_CONF_AUTO_REMOVE_TRAILING_DOTS
143 #define RESOLV_AUTO_REMOVE_TRAILING_DOTS RESOLV_CONF_AUTO_REMOVE_TRAILING_DOTS
144 #else
145 #define RESOLV_AUTO_REMOVE_TRAILING_DOTS RESOLV_CONF_SUPPORTS_MDNS
146 #endif
147 
148 #ifdef RESOLV_CONF_VERIFY_ANSWER_NAMES
149 #define RESOLV_VERIFY_ANSWER_NAMES RESOLV_CONF_VERIFY_ANSWER_NAMES
150 #else
151 #define RESOLV_VERIFY_ANSWER_NAMES RESOLV_CONF_SUPPORTS_MDNS
152 #endif
153 
154 #ifdef RESOLV_CONF_SUPPORTS_RECORD_EXPIRATION
155 #define RESOLV_SUPPORTS_RECORD_EXPIRATION RESOLV_CONF_SUPPORTS_RECORD_EXPIRATION
156 #else
157 #define RESOLV_SUPPORTS_RECORD_EXPIRATION 1
158 #endif
159 
160 #if RESOLV_CONF_SUPPORTS_MDNS && !RESOLV_VERIFY_ANSWER_NAMES
161 #error RESOLV_CONF_SUPPORTS_MDNS cannot be set without RESOLV_CONF_VERIFY_ANSWER_NAMES
162 #endif
163 
164 #if !defined(CONTIKI_TARGET_NAME) && defined(BOARD)
165 #define stringy2(x) #x
166 #define stringy(x) stringy2(x)
167 #define CONTIKI_TARGET_NAME stringy(BOARD)
168 #endif
169 
170 #ifndef CONTIKI_CONF_DEFAULT_HOSTNAME
171 #ifdef CONTIKI_TARGET_NAME
172 #define CONTIKI_CONF_DEFAULT_HOSTNAME "contiki-"CONTIKI_TARGET_NAME
173 #else
174 #define CONTIKI_CONF_DEFAULT_HOSTNAME "contiki"
175 #endif
176 #endif
177 
178 #define DNS_TYPE_A 1
179 #define DNS_TYPE_CNAME 5
180 #define DNS_TYPE_PTR 12
181 #define DNS_TYPE_MX 15
182 #define DNS_TYPE_TXT 16
183 #define DNS_TYPE_AAAA 28
184 #define DNS_TYPE_SRV 33
185 #define DNS_TYPE_ANY 255
186 #define DNS_TYPE_NSEC 47
187 
188 #if UIP_CONF_IPV6
189 #define NATIVE_DNS_TYPE DNS_TYPE_AAAA /* IPv6 */
190 #else
191 #define NATIVE_DNS_TYPE DNS_TYPE_A /* IPv4 */
192 #endif
193 
194 #define DNS_CLASS_IN 1
195 #define DNS_CLASS_ANY 255
196 
197 #ifndef DNS_PORT
198 #define DNS_PORT 53
199 #endif
200 
201 #ifndef MDNS_PORT
202 #define MDNS_PORT 5353
203 #endif
204 
205 #ifndef LLMNR_PORT
206 #define LLMNR_PORT 5355
207 #endif
208 
209 #ifndef MDNS_RESPONDER_PORT
210 #define MDNS_RESPONDER_PORT 5354
211 #endif
212 
213 /** \internal The DNS message header. */
214 struct dns_hdr {
215  uint16_t id;
216  uint8_t flags1, flags2;
217 #define DNS_FLAG1_RESPONSE 0x80
218 #define DNS_FLAG1_OPCODE_STATUS 0x10
219 #define DNS_FLAG1_OPCODE_INVERSE 0x08
220 #define DNS_FLAG1_OPCODE_STANDARD 0x00
221 #define DNS_FLAG1_AUTHORATIVE 0x04
222 #define DNS_FLAG1_TRUNC 0x02
223 #define DNS_FLAG1_RD 0x01
224 #define DNS_FLAG2_RA 0x80
225 #define DNS_FLAG2_ERR_MASK 0x0f
226 #define DNS_FLAG2_ERR_NONE 0x00
227 #define DNS_FLAG2_ERR_NAME 0x03
228  uint16_t numquestions;
229  uint16_t numanswers;
230  uint16_t numauthrr;
231  uint16_t numextrarr;
232 };
233 
234 #define RESOLV_ENCODE_INDEX(i) (uip_htons(i+1))
235 #define RESOLV_DECODE_INDEX(i) (unsigned char)(uip_ntohs(i-1))
236 
237 /** These default values for the DNS server are Google's public DNS:
238  * <https://developers.google.com/speed/public-dns/docs/using>
239  */
240 static uip_ipaddr_t resolv_default_dns_server =
241 #if UIP_CONF_IPV6
242  { { 0x20, 0x01, 0x48, 0x60, 0x48, 0x60, 0x00, 0x00,
243  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x88 } };
244 #else /* UIP_CONF_IPV6 */
245  { { 8, 8, 8, 8 } };
246 #endif /* UIP_CONF_IPV6 */
247 
248 /** \internal The DNS answer message structure. */
249 struct dns_answer {
250  /* DNS answer record starts with either a domain name or a pointer
251  * to a name already present somewhere in the packet. */
252  uint16_t type;
253  uint16_t class;
254  uint16_t ttl[2];
255  uint16_t len;
256 #if UIP_CONF_IPV6
257  uint8_t ipaddr[16];
258 #else
259  uint8_t ipaddr[4];
260 #endif
261 };
262 
263 struct namemap {
264 #define STATE_UNUSED 0
265 #define STATE_ERROR 1
266 #define STATE_NEW 2
267 #define STATE_ASKING 3
268 #define STATE_DONE 4
269  uint8_t state;
270  uint8_t tmr;
271  uint8_t retries;
272  uint8_t seqno;
273 #if RESOLV_SUPPORTS_RECORD_EXPIRATION
274  unsigned long expiration;
275 #endif /* RESOLV_SUPPORTS_RECORD_EXPIRATION */
276  uip_ipaddr_t ipaddr;
277  uint8_t err;
278 #if RESOLV_CONF_SUPPORTS_MDNS
279  int is_mdns:1, is_probe:1;
280 #endif
281  char name[RESOLV_CONF_MAX_DOMAIN_NAME_SIZE + 1];
282 };
283 
284 #ifndef UIP_CONF_RESOLV_ENTRIES
285 #define RESOLV_ENTRIES 4
286 #else /* UIP_CONF_RESOLV_ENTRIES */
287 #define RESOLV_ENTRIES UIP_CONF_RESOLV_ENTRIES
288 #endif /* UIP_CONF_RESOLV_ENTRIES */
289 
290 static struct namemap names[RESOLV_ENTRIES];
291 
292 static uint8_t seqno;
293 
294 static struct uip_udp_conn *resolv_conn = NULL;
295 
296 static struct uip_udp_conn *llmnr_conn = NULL;
297 
298 static struct etimer retry;
299 
300 process_event_t resolv_event_found;
301 
302 PROCESS(resolv_process, "DNS resolver");
303 
304 static void resolv_found(char *name, uip_ipaddr_t * ipaddr);
305 
306 /** \internal The DNS question message structure. */
307 struct dns_question {
308  uint16_t type;
309  uint16_t class;
310 };
311 
312 #if RESOLV_CONF_SUPPORTS_MDNS
313 static char resolv_hostname[RESOLV_CONF_MAX_DOMAIN_NAME_SIZE + 1];
314 
315 enum {
316  MDNS_STATE_WAIT_BEFORE_PROBE,
317  MDNS_STATE_PROBING,
318  MDNS_STATE_READY,
319 };
320 
321 static uint8_t mdns_state;
322 
323 static const uip_ipaddr_t resolv_mdns_addr =
324 #if UIP_CONF_IPV6
325  { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
326  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb } };
327 #include "net/uip-ds6.h"
328 #else /* UIP_CONF_IPV6 */
329  { { 224, 0, 0, 251 } };
330 #endif /* UIP_CONF_IPV6 */
331 static int mdns_needs_host_announce;
332 
333 PROCESS(mdns_probe_process, "mDNS probe");
334 #endif /* RESOLV_CONF_SUPPORTS_MDNS */
335 
336 /*---------------------------------------------------------------------------*/
337 #if RESOLV_VERIFY_ANSWER_NAMES || VERBOSE_DEBUG
338 /** \internal
339  * \brief Decodes a DNS name from the DNS format into the given string.
340  * \return 1 upon success, 0 if the size of the name would be too large.
341  *
342  * \note `dest` must point to a buffer with at least
343  * `RESOLV_CONF_MAX_DOMAIN_NAME_SIZE+1` bytes large.
344  */
345 static uint8_t
346 decode_name(const unsigned char *query, char *dest,
347  const unsigned char *packet)
348 {
349  int len = RESOLV_CONF_MAX_DOMAIN_NAME_SIZE;
350 
351  unsigned char n = *query++;
352 
353  //DEBUG_PRINTF("resolver: decoding name: \"");
354 
355  while(len && n) {
356  if(n & 0xc0) {
357  const uint16_t offset = query[0] + ((n & ~0xC0) << 8);
358 
359  //DEBUG_PRINTF("<skip-to-%d>",offset);
360  query = packet + offset;
361  n = *query++;
362  }
363 
364  if(!n)
365  break;
366 
367  for(; n; --n) {
368  //DEBUG_PRINTF("%c",*query);
369 
370  *dest++ = *query++;
371 
372  if(!--len) {
373  *dest = 0;
374  return 0;
375  }
376  }
377 
378  n = *query++;
379 
380  if(n) {
381  //DEBUG_PRINTF(".");
382  *dest++ = '.';
383  --len;
384  }
385  }
386 
387  //DEBUG_PRINTF("\"\n");
388  *dest = 0;
389  return len != 0;
390 }
391 /*---------------------------------------------------------------------------*/
392 /** \internal
393  */
394 static uint8_t
395 dns_name_isequal(const unsigned char *queryptr, const char *name,
396  const unsigned char *packet)
397 {
398  unsigned char n = *queryptr++;
399 
400  if(*name == 0)
401  return 0;
402 
403  while(n) {
404  if(n & 0xc0) {
405  queryptr = packet + queryptr[0] + ((n & ~0xC0) << 8);
406  n = *queryptr++;
407  }
408 
409  for(; n; --n) {
410  if(!*name) {
411  return 0;
412  }
413 
414  if(tolower((uint8_t) *name++) != tolower((uint8_t) *queryptr++)) {
415  return 0;
416  }
417  }
418 
419  n = *queryptr++;
420 
421  if((n != 0) && (*name++ != '.')) {
422  return 0;
423  }
424  }
425 
426  if(*name == '.')
427  ++name;
428 
429  if (uip_udp_conn == llmnr_conn && strcmp(name, "local") == 0)
430  return 1;
431  return name[0] == 0;
432 }
433 #endif /* RESOLV_VERIFY_ANSWER_NAMES */
434 /*---------------------------------------------------------------------------*/
435 /** \internal
436  */
437 static unsigned char *
438 skip_name(unsigned char *query)
439 {
440  unsigned char n;
441 
442  DEBUG_PRINTF("resolver: skip name: ");
443 
444  do {
445  n = *query;
446  if(n & 0xc0) {
447  DEBUG_PRINTF("<skip-to-%d>", query[0] + ((n & ~0xC0) << 8));
448  ++query;
449  break;
450  }
451 
452  ++query;
453 
454  while(n > 0) {
455  DEBUG_PRINTF("%c", *query);
456  ++query;
457  --n;
458  };
459  DEBUG_PRINTF(".");
460  } while(*query != 0);
461  DEBUG_PRINTF("\n");
462  return query + 1;
463 }
464 /*---------------------------------------------------------------------------*/
465 /** \internal
466  */
467 static unsigned char *
468 encode_name(unsigned char *query, const char *nameptr)
469 {
470  char *nptr;
471  const char *endptr = &nameptr[strlen(nameptr)];
472  if (uip_udp_conn == llmnr_conn) {
473  if (nameptr + 6 <= endptr && memcmp(endptr - 6, ".local", 6) == 0)
474  endptr -= 6;
475  }
476 
477  --nameptr;
478  /* Convert hostname into suitable query format. */
479  do {
480  uint8_t n = 0;
481 
482  ++nameptr;
483  nptr = (char *)query;
484  ++query;
485  for(n = 0; *nameptr != '.' && *nameptr != 0; ++nameptr) {
486  *query = *nameptr;
487  ++query;
488  ++n;
489  }
490  *nptr = n;
491  } while(nameptr != endptr);
492 
493  /* End the the name. */
494  *query++ = 0;
495 
496  return query;
497 }
498 /*---------------------------------------------------------------------------*/
499 #if RESOLV_CONF_SUPPORTS_MDNS
500 /** \internal
501  */
502 static void
503 mdns_announce_requested(void)
504 {
505  mdns_needs_host_announce = 1;
506 }
507 /*---------------------------------------------------------------------------*/
508 /** \internal
509  */
510 static void
511 start_name_collision_check(clock_time_t after)
512 {
513  process_exit(&mdns_probe_process);
514  process_start(&mdns_probe_process, (void *)&after);
515 }
516 /*---------------------------------------------------------------------------*/
517 /** \internal
518  */
519 static unsigned char *
520 mdns_write_announce_records(unsigned char *queryptr, uint8_t *count)
521 {
522  struct dns_answer *ans;
523 
524 #if UIP_CONF_IPV6
525  uint8_t i;
526 
527  for(i = 0; i < UIP_DS6_ADDR_NB; ++i) {
528  if(uip_ds6_if.addr_list[i].isused
529 #if !RESOLV_CONF_MDNS_INCLUDE_GLOBAL_V6_ADDRS
530  && uip_is_addr_link_local(&uip_ds6_if.addr_list[i].ipaddr)
531 #endif
532  ) {
533  if(!*count) {
534  queryptr = encode_name(queryptr, resolv_hostname);
535  } else {
536  /* Use name compression to refer back to the first name */
537  *queryptr++ = 0xc0;
538  *queryptr++ = sizeof(struct dns_hdr);
539  }
540  ans = (struct dns_answer *)queryptr;
541 
542  *queryptr++ = (uint8_t) ((NATIVE_DNS_TYPE) >> 8);
543  *queryptr++ = (uint8_t) ((NATIVE_DNS_TYPE));
544 
545  *queryptr++ = (uint8_t) ((DNS_CLASS_IN | 0x8000) >> 8);
546  *queryptr++ = (uint8_t) ((DNS_CLASS_IN | 0x8000));
547 
548  *queryptr++ = 0;
549  *queryptr++ = 0;
550  *queryptr++ = 0;
551  *queryptr++ = 120;
552 
553  *queryptr++ = 0;
554  *queryptr++ = sizeof(uip_ipaddr_t);
555 
556  uip_ipaddr_copy((uip_ipaddr_t*)queryptr, &uip_ds6_if.addr_list[i].ipaddr);
557  queryptr += sizeof(uip_ipaddr_t);
558  ++(*count);
559  }
560  }
561 #else /* UIP_CONF_IPV6 */
562  queryptr = encode_name(queryptr, resolv_hostname);
563  ans = (struct dns_answer *)queryptr;
564  ans->type = UIP_HTONS(NATIVE_DNS_TYPE);
565  ans->class = UIP_HTONS(DNS_CLASS_IN);
566  if (uip_udp_conn != llmnr_conn)
567  ans->class |= UIP_HTONS(0x8000);
568  ans->ttl[0] = 0;
569  ans->ttl[1] = UIP_HTONS(120);
570  ans->len = UIP_HTONS(sizeof(uip_ipaddr_t));
571  uip_gethostaddr((uip_ipaddr_t *) ans->ipaddr);
572  queryptr = (unsigned char *)ans + sizeof(*ans);
573  ++(*count);
574 #endif /* UIP_CONF_IPV6 */
575  return queryptr;
576 }
577 /*---------------------------------------------------------------------------*/
578 /** \internal
579  * Called when we need to announce ourselves
580  */
581 static size_t
582 mdns_prep_host_announce_packet(void)
583 {
584  static const struct {
585  uint16_t type;
586  uint16_t class;
587  uint16_t ttl[2];
588  uint16_t len;
589  uint8_t data[8];
590 
591  } nsec_record = {
592  UIP_HTONS(DNS_TYPE_NSEC),
593  UIP_HTONS(DNS_CLASS_IN | 0x8000),
594  { 0, UIP_HTONS(120) },
595  UIP_HTONS(8),
596 
597  {
598  0xc0,
599  sizeof(struct dns_hdr), /* Name compression. Re-using the name of first record. */
600  0x00,
601  0x04,
602 
603 #if UIP_CONF_IPV6
604  0x00,
605  0x00,
606  0x00,
607  0x08,
608 #else /* UIP_CONF_IPV6 */
609  0x40,
610  0x00,
611  0x00,
612  0x00,
613 #endif /* UIP_CONF_IPV6 */
614  }
615  };
616 
617  unsigned char *queryptr;
618 
619  uint8_t total_answers = 0;
620 
621  /* struct dns_answer *ans; */
622 
623  /* Be aware that, unless `ARCH_DOESNT_NEED_ALIGNED_STRUCTS` is set,
624  * writing directly to the uint16_t members of this struct is an error. */
625  struct dns_hdr *hdr = (struct dns_hdr *)uip_appdata;
626 
627  if (uip_udp_conn != llmnr_conn) {
628  /* Zero out the header */
629  memset((void *)hdr, 0, sizeof(*hdr));
630 
631  queryptr = (unsigned char *)uip_appdata + sizeof(*hdr);
632  } else {
633  queryptr = (unsigned char *)uip_appdata + uip_len;
634  }
635 
636  hdr->flags1 |= DNS_FLAG1_RESPONSE;
637  if (uip_udp_conn != llmnr_conn)
638  hdr->flags1 |= DNS_FLAG1_AUTHORATIVE;
639 
640  queryptr = mdns_write_announce_records(queryptr, &total_answers);
641 
642  /* We now need to add an NSEC record to indicate
643  * that this is all there is.
644  */
645  if(!total_answers) {
646  queryptr = encode_name(queryptr, resolv_hostname);
647  } else {
648  /* Name compression. Re-using the name of first record. */
649  *queryptr++ = 0xc0;
650  *queryptr++ = sizeof(*hdr);
651  }
652 
653  if (uip_udp_conn != llmnr_conn) {
654  memcpy((void *)queryptr, (void *)&nsec_record, sizeof(nsec_record));
655  queryptr += sizeof(nsec_record);
656  ((uint8_t*)&hdr->numextrarr)[1] = 1;
657  }
658 
659  /* This platform might be picky about alignment. To avoid the possibility
660  * of doing an unaligned write, here and above we are going to do this manually. */
661  ((uint8_t*)&hdr->numanswers)[1] = total_answers;
662 
663  return (queryptr - (unsigned char *)uip_appdata);
664 }
665 #endif /* RESOLV_CONF_SUPPORTS_MDNS */
666 /*---------------------------------------------------------------------------*/
667 /** \internal
668  * Runs through the list of names to see if there are any that have
669  * not yet been queried and, if so, sends out a query.
670  */
671 static void
672 check_entries(void)
673 {
674  volatile uint8_t i;
675 
676  uint8_t *query;
677 
678  register struct dns_hdr *hdr;
679 
680  register struct namemap *namemapptr;
681 
682  for(i = 0; i < RESOLV_ENTRIES; ++i) {
683  namemapptr = &names[i];
684  if(namemapptr->state == STATE_NEW || namemapptr->state == STATE_ASKING) {
685  etimer_set(&retry, CLOCK_SECOND / 4);
686  if(namemapptr->state == STATE_ASKING) {
687  if(--namemapptr->tmr == 0) {
688 #if RESOLV_CONF_SUPPORTS_MDNS
689  if(++namemapptr->retries ==
690  (namemapptr->is_mdns ? RESOLV_CONF_MAX_MDNS_RETRIES :
691  RESOLV_CONF_MAX_RETRIES))
692 #else /* RESOLV_CONF_SUPPORTS_MDNS */
693  if(++namemapptr->retries == RESOLV_CONF_MAX_RETRIES)
694 #endif /* RESOLV_CONF_SUPPORTS_MDNS */
695  {
696  /* STATE_ERROR basically means "not found". */
697  namemapptr->state = STATE_ERROR;
698 
699 #if RESOLV_SUPPORTS_RECORD_EXPIRATION
700  /* Keep the "not found" error valid for 30 seconds */
701  namemapptr->expiration = clock_seconds() + 30;
702 #endif /* RESOLV_SUPPORTS_RECORD_EXPIRATION */
703 
704  resolv_found(namemapptr->name, NULL);
705  continue;
706  }
707  namemapptr->tmr = namemapptr->retries * namemapptr->retries * 3;
708 
709 #if RESOLV_CONF_SUPPORTS_MDNS
710  if(namemapptr->is_probe) {
711  /* Probing retries are much more aggressive, 250ms */
712  namemapptr->tmr = 2;
713  }
714 #endif /* RESOLV_CONF_SUPPORTS_MDNS */
715  } else {
716  /* Its timer has not run out, so we move on to next
717  * entry.
718  */
719  continue;
720  }
721  } else {
722  namemapptr->state = STATE_ASKING;
723  namemapptr->tmr = 1;
724  namemapptr->retries = 0;
725  }
726  hdr = (struct dns_hdr *)uip_appdata;
727  memset(hdr, 0, sizeof(struct dns_hdr));
728  hdr->id = RESOLV_ENCODE_INDEX(i);
729 #if RESOLV_CONF_SUPPORTS_MDNS
730  if(!namemapptr->is_mdns || namemapptr->is_probe) {
731  hdr->flags1 = DNS_FLAG1_RD;
732  }
733  if(namemapptr->is_mdns) {
734  hdr->id = 0;
735  }
736 #else /* RESOLV_CONF_SUPPORTS_MDNS */
737  hdr->flags1 = DNS_FLAG1_RD;
738 #endif /* RESOLV_CONF_SUPPORTS_MDNS */
739  hdr->numquestions = UIP_HTONS(1);
740  query = (unsigned char *)uip_appdata + sizeof(*hdr);
741  query = encode_name(query, namemapptr->name);
742 #if RESOLV_CONF_SUPPORTS_MDNS
743  if(namemapptr->is_probe) {
744  *query++ = (uint8_t) ((DNS_TYPE_ANY) >> 8);
745  *query++ = (uint8_t) ((DNS_TYPE_ANY));
746  } else
747 #endif /* RESOLV_CONF_SUPPORTS_MDNS */
748  {
749  *query++ = (uint8_t) ((NATIVE_DNS_TYPE) >> 8);
750  *query++ = (uint8_t) ((NATIVE_DNS_TYPE));
751  }
752  *query++ = (uint8_t) ((DNS_CLASS_IN) >> 8);
753  *query++ = (uint8_t) ((DNS_CLASS_IN));
754 #if RESOLV_CONF_SUPPORTS_MDNS
755  if(namemapptr->is_mdns) {
756  if(namemapptr->is_probe) {
757  /* This is our conflict detection request.
758  * In order to be in compliance with the MDNS
759  * spec, we need to add the records we are proposing
760  * to the rrauth section.
761  */
762  uint8_t count = 0;
763 
764  query = mdns_write_announce_records(query, &count);
765  hdr->numauthrr = UIP_HTONS(count);
766  }
767  uip_udp_packet_sendto(uip_udp_conn, uip_appdata,
768  (query - (uint8_t *) uip_appdata),
769  &resolv_mdns_addr, UIP_HTONS(MDNS_PORT));
770 
771  PRINTF("resolver: (i=%d) Sent MDNS %s for \"%s\".\n", i,
772  namemapptr->is_probe?"probe":"request",namemapptr->name);
773  } else {
774  uip_udp_packet_sendto(uip_udp_conn, uip_appdata,
775  (query - (uint8_t *) uip_appdata),
776  &resolv_default_dns_server, UIP_HTONS(DNS_PORT));
777 
778  PRINTF("resolver: (i=%d) Sent DNS request for \"%s\".\n", i,
779  namemapptr->name);
780  }
781 #else /* RESOLV_CONF_SUPPORTS_MDNS */
782  uip_udp_packet_sendto(uip_udp_conn, uip_appdata,
783  (query - (uint8_t *) uip_appdata),
784  &resolv_default_dns_server, UIP_HTONS(DNS_PORT));
785  PRINTF("resolver: (i=%d) Sent DNS request for \"%s\".\n", i,
786  namemapptr->name);
787 #endif /* RESOLV_CONF_SUPPORTS_MDNS */
788  break;
789  }
790  }
791 }
792 /*---------------------------------------------------------------------------*/
793 /** \internal
794  * Called when new UDP data arrives.
795  */
796 static void
797 newdata(void)
798 {
799  static uint8_t nquestions, nanswers, nauthrr;
800 
801  static int8_t i;
802 
803  register struct namemap *namemapptr;
804 
805  struct dns_answer *ans;
806 
807  register struct dns_hdr const *hdr = (struct dns_hdr *)uip_appdata;
808 
809  unsigned char *queryptr = (unsigned char *)hdr + sizeof(*hdr);
810 
811  const uint8_t is_request = ((hdr->flags1 & ~1) == 0) && (hdr->flags2 == 0);
812 
813  /* We only care about the question(s) and the answers. The authrr
814  * and the extrarr are simply discarded.
815  */
816  nquestions = (uint8_t) uip_ntohs(hdr->numquestions);
817  nanswers = (uint8_t) uip_ntohs(hdr->numanswers);
818 
819  queryptr = (unsigned char *)hdr + sizeof(*hdr);
820  i = 0;
821 
822  DEBUG_PRINTF
823  ("resolver: flags1=0x%02X flags2=0x%02X nquestions=%d, nanswers=%d, nauthrr=%d, nextrarr=%d\n",
824  hdr->flags1, hdr->flags2, (uint8_t) nquestions, (uint8_t) nanswers,
825  (uint8_t) uip_ntohs(hdr->numauthrr),
826  (uint8_t) uip_ntohs(hdr->numextrarr));
827 
828  if(is_request && (nquestions == 0)) {
829  /* Skip requests with no questions. */
830  DEBUG_PRINTF("resolver: Skipping request with no questions.\n");
831  return;
832  }
833 
834 /** QUESTION HANDLING SECTION ************************************************/
835 
836  for(; nquestions > 0;
837  queryptr = skip_name(queryptr) + sizeof(struct dns_question),
838  --nquestions
839  ) {
840 #if RESOLV_CONF_SUPPORTS_MDNS
841  if(!is_request) {
842  /* If this isn't a request, we don't need to bother
843  * looking at the individual questions. For the most
844  * part, this loop to just used to skip past them.
845  */
846  continue;
847  }
848 
849  {
850  struct dns_question *question = (struct dns_question *)skip_name(queryptr);
851 
852 #if !ARCH_DOESNT_NEED_ALIGNED_STRUCTS
853  static struct dns_question aligned;
854  memcpy(&aligned, question, sizeof(aligned));
855  question = &aligned;
856 #endif /* !ARCH_DOESNT_NEED_ALIGNED_STRUCTS */
857 
858  DEBUG_PRINTF("resolver: Question %d: type=%d class=%d\n", ++i,
859  uip_htons(question->type), uip_htons(question->class));
860 
861  if(((uip_ntohs(question->class) & 0x7FFF) != DNS_CLASS_IN) ||
862  ((question->type != UIP_HTONS(DNS_TYPE_ANY)) &&
863  (question->type != UIP_HTONS(NATIVE_DNS_TYPE)))) {
864  /* Skip unrecognised records. */
865  continue;
866  }
867 
868  if(!dns_name_isequal(queryptr, resolv_hostname, uip_appdata)) {
869  continue;
870  }
871 
872  PRINTF("resolver: THIS IS A REQUEST FOR US!!!\n");
873 
874  if(mdns_state == MDNS_STATE_READY) {
875  /* We only send immediately if this isn't an MDNS request.
876  * Otherwise, we schedule ourselves to send later.
877  */
878  if(UIP_UDP_BUF->srcport == UIP_HTONS(MDNS_PORT)) {
879  mdns_announce_requested();
880  } else {
881  uip_udp_packet_sendto(uip_udp_conn, uip_appdata,
882  mdns_prep_host_announce_packet(),
883  &UIP_UDP_BUF->srcipaddr,
884  UIP_UDP_BUF->srcport);
885  }
886  return;
887  } else {
888  PRINTF("resolver: But we are still probing. Waiting...\n");
889  /* We are still probing. We need to do the mDNS
890  * probe race condition check here and make sure
891  * we don't need to delay probing for a second.
892  */
893  nauthrr = (uint8_t)uip_ntohs(hdr->numauthrr);
894 
895  /* For now, we will always restart the collision check if
896  * there are *any* authority records present.
897  * In the future we should follow the spec more closely,
898  * but this should eventually converge to something reasonable.
899  */
900  if(nauthrr) {
901  start_name_collision_check(CLOCK_SECOND);
902  }
903  }
904  }
905 #endif /* RESOLV_CONF_SUPPORTS_MDNS */
906  }
907 
908 /** ANSWER HANDLING SECTION **************************************************/
909 
910  if(nanswers == 0) {
911  /* Skip responses with no answers. */
912  return;
913  }
914 
915 #if RESOLV_CONF_SUPPORTS_MDNS
916  if((UIP_UDP_BUF->srcport == UIP_HTONS(MDNS_PORT) || uip_udp_conn == llmnr_conn) &&
917  hdr->id == 0) {
918  /* OK, this was from MDNS. Things get a little weird here,
919  * because we can't use the `id` field. We will look up the
920  * appropriate request in a later step. */
921 
922  i = -1;
923  namemapptr = NULL;
924  } else
925 #endif /* RESOLV_CONF_SUPPORTS_MDNS */
926  {
927  /* The ID in the DNS header should be our entry into the name table. */
928  i = RESOLV_DECODE_INDEX(hdr->id);
929 
930  namemapptr = &names[i];
931 
932  if(i >= RESOLV_ENTRIES || i < 0 || namemapptr->state != STATE_ASKING) {
933  PRINTF("resolver: DNS response has bad ID (%04X) \n", uip_ntohs(hdr->id));
934  return;
935  }
936 
937  PRINTF("resolver: Incoming response for \"%s\".\n", namemapptr->name);
938 
939  /* We'll change this to DONE when we find the record. */
940  namemapptr->state = STATE_ERROR;
941 
942  namemapptr->err = hdr->flags2 & DNS_FLAG2_ERR_MASK;
943 
944 #if RESOLV_SUPPORTS_RECORD_EXPIRATION
945  /* If we remain in the error state, keep it cached for 30 seconds. */
946  namemapptr->expiration = clock_seconds() + 30;
947 #endif /* RESOLV_SUPPORTS_RECORD_EXPIRATION */
948 
949  /* Check for error. If so, call callback to inform. */
950  if(namemapptr->err != 0) {
951  namemapptr->state = STATE_ERROR;
952  resolv_found(namemapptr->name, NULL);
953  return;
954  }
955  }
956 
957  i = 0;
958 
959  /* Answer parsing loop */
960  while(nanswers > 0) {
961  ans = (struct dns_answer *)skip_name(queryptr);
962 
963 #if !ARCH_DOESNT_NEED_ALIGNED_STRUCTS
964  {
965  static struct dns_answer aligned;
966  memcpy(&aligned, ans, sizeof(aligned));
967  ans = &aligned;
968  }
969 #endif /* !ARCH_DOESNT_NEED_ALIGNED_STRUCTS */
970 
971 #if VERBOSE_DEBUG
972  static char debug_name[40];
973  decode_name(queryptr, debug_name, uip_appdata);
974  DEBUG_PRINTF("resolver: Answer %d: \"%s\", type %d, class %d, ttl %d, length %d\n",
975  ++i, debug_name, uip_ntohs(ans->type),
976  uip_ntohs(ans->class) & 0x7FFF,
977  (int)((uint32_t) uip_ntohs(ans->ttl[0]) << 16) | (uint32_t)
978  uip_ntohs(ans->ttl[1]), uip_ntohs(ans->len));
979 #endif /* VERBOSE_DEBUG */
980 
981  /* Check the class and length of the answer to make sure
982  * it matches what we are expecting
983  */
984  if(((uip_ntohs(ans->class) & 0x7FFF) != DNS_CLASS_IN) ||
985  (ans->len != UIP_HTONS(sizeof(uip_ipaddr_t)))) {
986  goto skip_to_next_answer;
987  }
988 
989  if(ans->type != UIP_HTONS(NATIVE_DNS_TYPE)) {
990  goto skip_to_next_answer;
991  }
992 
993 #if RESOLV_CONF_SUPPORTS_MDNS
994  if((UIP_UDP_BUF->srcport == UIP_HTONS(MDNS_PORT) || uip_udp_conn == llmnr_conn) &&
995  hdr->id == 0) {
996  int8_t available_i = RESOLV_ENTRIES;
997 
998  DEBUG_PRINTF("resolver: MDNS query.\n");
999 
1000  /* For MDNS, we need to actually look up the name we
1001  * are looking for.
1002  */
1003  for(i = 0; i < RESOLV_ENTRIES; ++i) {
1004  namemapptr = &names[i];
1005  if(dns_name_isequal(queryptr, namemapptr->name, uip_appdata)) {
1006  break;
1007  }
1008  if((namemapptr->state == STATE_UNUSED)
1009 #if RESOLV_SUPPORTS_RECORD_EXPIRATION
1010  || (namemapptr->state == STATE_DONE && clock_seconds() > namemapptr->expiration)
1011 #endif /* RESOLV_SUPPORTS_RECORD_EXPIRATION */
1012  ) {
1013  available_i = i;
1014  }
1015  }
1016  if(i == RESOLV_ENTRIES) {
1017  DEBUG_PRINTF("resolver: Unsolicited MDNS response.\n");
1018  i = available_i;
1019  namemapptr = &names[i];
1020  if(!decode_name(queryptr, namemapptr->name, uip_appdata)) {
1021  DEBUG_PRINTF("resolver: MDNS name too big to cache.\n");
1022  namemapptr = NULL;
1023  goto skip_to_next_answer;
1024  }
1025  }
1026  if(i == RESOLV_ENTRIES) {
1027  DEBUG_PRINTF
1028  ("resolver: Not enough room to keep track of unsolicited MDNS answer.\n");
1029 
1030  if(dns_name_isequal(queryptr, resolv_hostname, uip_appdata)) {
1031  /* Oh snap, they say they are us! We had better report them... */
1032  resolv_found(resolv_hostname, (uip_ipaddr_t *) ans->ipaddr);
1033  }
1034  namemapptr = NULL;
1035  goto skip_to_next_answer;
1036  }
1037  namemapptr = &names[i];
1038 
1039  } else
1040 #endif /* RESOLV_CONF_SUPPORTS_MDNS */
1041  {
1042  /* This will force us to stop even if there are more answers. */
1043  nanswers = 1;
1044  }
1045 
1046 /* This is disabled for now, so that we don't fail on CNAME records.
1047 #if RESOLV_VERIFY_ANSWER_NAMES
1048  if(namemapptr && !dns_name_isequal(queryptr, namemapptr->name, uip_appdata)) {
1049  DEBUG_PRINTF("resolver: Answer name doesn't match question...!\n");
1050  goto skip_to_next_answer;
1051  }
1052 #endif
1053 */
1054 
1055  DEBUG_PRINTF("resolver: Answer for \"%s\" is usable.\n", namemapptr->name);
1056 
1057  namemapptr->state = STATE_DONE;
1058 #if RESOLV_SUPPORTS_RECORD_EXPIRATION
1059  namemapptr->expiration = ans->ttl[1] + (ans->ttl[0] << 8);
1060  namemapptr->expiration += clock_seconds();
1061 #endif /* RESOLV_SUPPORTS_RECORD_EXPIRATION */
1062 
1063  uip_ipaddr_copy(&namemapptr->ipaddr, (uip_ipaddr_t *) ans->ipaddr);
1064 
1065  resolv_found(namemapptr->name, &namemapptr->ipaddr);
1066 
1067  skip_to_next_answer:
1068  queryptr = (unsigned char *)skip_name(queryptr) + 10 + uip_htons(ans->len);
1069  --nanswers;
1070  }
1071 }
1072 /*---------------------------------------------------------------------------*/
1073 #if RESOLV_CONF_SUPPORTS_MDNS
1074 /**
1075  * \brief Changes the local hostname advertised by MDNS.
1076  * \param hostname The new hostname to advertise.
1077  */
1078 void
1079 resolv_set_hostname(const char *hostname)
1080 {
1081  strncpy(resolv_hostname, hostname, RESOLV_CONF_MAX_DOMAIN_NAME_SIZE);
1082 
1083  /* Add the .local suffix if it isn't already there */
1084  if(strlen(resolv_hostname) < 7 ||
1085  strcasecmp(resolv_hostname + strlen(resolv_hostname) - 6, ".local") != 0) {
1086  strncat(resolv_hostname, ".local", RESOLV_CONF_MAX_DOMAIN_NAME_SIZE);
1087  }
1088 
1089  PRINTF("resolver: hostname changed to \"%s\"\n", resolv_hostname);
1090 
1091  start_name_collision_check(0);
1092 }
1093 /*---------------------------------------------------------------------------*/
1094 /**
1095  * \brief Returns the local hostname being advertised via MDNS.
1096  * \return C-string containing the local hostname.
1097  */
1098 const char *
1099 resolv_get_hostname(void)
1100 {
1101  return resolv_hostname;
1102 }
1103 /*---------------------------------------------------------------------------*/
1104 /** \internal
1105  * Process for probing for name conflicts.
1106  */
1107 PROCESS_THREAD(mdns_probe_process, ev, data)
1108 {
1109  static struct etimer delay;
1110 
1111  PROCESS_BEGIN();
1112  mdns_state = MDNS_STATE_WAIT_BEFORE_PROBE;
1113 
1114  PRINTF("mdns-probe: Process (re)started.\n");
1115 
1116  /* Wait extra time if specified in data */
1117  if(NULL != data) {
1118  PRINTF("mdns-probe: Probing will begin in %ld clocks.\n",
1119  (long)*(clock_time_t *) data);
1120  etimer_set(&delay, *(clock_time_t *) data);
1121  PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_TIMER);
1122  }
1123 
1124  /* We need to wait a random (0-250ms) period of time before
1125  * probing to be in compliance with the MDNS spec. */
1126  etimer_set(&delay, CLOCK_SECOND * (random_rand() & 0xFF) / 1024);
1127  PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_TIMER);
1128 
1129  /* Begin searching for our name. */
1130  mdns_state = MDNS_STATE_PROBING;
1131  resolv_query(resolv_hostname);
1132 
1133  do {
1135  } while(strcasecmp(resolv_hostname, data) != 0);
1136 
1137  mdns_state = MDNS_STATE_READY;
1138  mdns_announce_requested();
1139 
1140  PRINTF("mdns-probe: Finished probing.\n");
1141 
1142  PROCESS_END();
1143 #ifdef ECLIPSE_STUB_CODE_ANALYSE
1144  return PT_ENDED;
1145 #endif /* ECLIPSE_STUB_CODE_ANALYSE */
1146 }
1147 #endif /* RESOLV_CONF_SUPPORTS_MDNS */
1148 /*---------------------------------------------------------------------------*/
1149 /** \internal
1150  * The main UDP function.
1151  */
1152 PROCESS_THREAD(resolv_process, ev, data)
1153 {
1154  PROCESS_BEGIN();
1155 
1156  memset(names, 0, sizeof(names));
1157 
1159 
1160  PRINTF("resolver: Process started.\n");
1161 
1162  resolv_conn = udp_new(NULL, 0, NULL);
1163 
1164 #if RESOLV_CONF_SUPPORTS_MDNS
1165  PRINTF("resolver: Supports MDNS.\n");
1166  uip_udp_bind(resolv_conn, UIP_HTONS(MDNS_PORT));
1167 
1168 #if UIP_CONF_IPV6
1169  uip_ds6_maddr_add(&resolv_mdns_addr);
1170 #else
1171  /* TODO: Is there anything we need to do here for IPv4 multicast? */
1172 #endif
1173 
1174  llmnr_conn = udp_new(NULL, 0, NULL);
1175  uip_udp_bind(llmnr_conn, UIP_HTONS(LLMNR_PORT));
1176 
1177  resolv_set_hostname(CONTIKI_CONF_DEFAULT_HOSTNAME);
1178 #endif /* RESOLV_CONF_SUPPORTS_MDNS */
1179 
1180  while(1) {
1182 
1183  if(ev == PROCESS_EVENT_TIMER) {
1184  tcpip_poll_udp(resolv_conn);
1185  } else if(ev == tcpip_event) {
1186  if(uip_udp_conn == resolv_conn || uip_udp_conn == llmnr_conn) {
1187  if(uip_newdata()) {
1188  newdata();
1189  }
1190  if(uip_poll()) {
1191 #if RESOLV_CONF_SUPPORTS_MDNS
1192  if(mdns_needs_host_announce) {
1193  size_t len;
1194 
1195  PRINTF("resolver: Announcing that we are \"%s\".\n",
1196  resolv_hostname);
1197 
1198  memset(uip_appdata, 0, sizeof(struct dns_hdr));
1199 
1200  len = mdns_prep_host_announce_packet();
1201 
1202  uip_udp_packet_sendto(resolv_conn, uip_appdata,
1203  len, &resolv_mdns_addr, UIP_HTONS(MDNS_PORT));
1204 
1205  mdns_needs_host_announce = 0;
1206 
1207  /* Poll again in case this fired
1208  * at the same time the event timer did.
1209  */
1210  tcpip_poll_udp(resolv_conn);
1211  } else
1212 #endif /* RESOLV_CONF_SUPPORTS_MDNS */
1213  {
1214  check_entries();
1215  }
1216  }
1217  }
1218  }
1219 
1220 #if RESOLV_CONF_SUPPORTS_MDNS
1221  if(mdns_needs_host_announce) {
1222  tcpip_poll_udp(resolv_conn);
1223  }
1224 #endif /* RESOLV_CONF_SUPPORTS_MDNS */
1225  }
1226 
1227  PROCESS_END();
1228 #ifdef ECLIPSE_STUB_CODE_ANALYSE
1229  return PT_ENDED;
1230 #endif /* ECLIPSE_STUB_CODE_ANALYSE */
1231 }
1232 /*---------------------------------------------------------------------------*/
1233 #if RESOLV_AUTO_REMOVE_TRAILING_DOTS
1234 static const char *
1235 remove_trailing_dots(const char *name) {
1236  static char dns_name_without_dots[RESOLV_CONF_MAX_DOMAIN_NAME_SIZE + 1];
1237  size_t len = strlen(name);
1238 
1239  if(name[len - 1] == '.') {
1240  strncpy(dns_name_without_dots, name, sizeof(dns_name_without_dots));
1241  while(len && (dns_name_without_dots[len - 1] == '.')) {
1242  dns_name_without_dots[--len] = 0;
1243  }
1244  name = dns_name_without_dots;
1245  }
1246  return name;
1247 }
1248 #else /* RESOLV_AUTO_REMOVE_TRAILING_DOTS */
1249 #define remove_trailing_dots(x) (x)
1250 #endif /* RESOLV_AUTO_REMOVE_TRAILING_DOTS */
1251 /*---------------------------------------------------------------------------*/
1252 /**
1253  * Queues a name so that a question for the name will be sent out.
1254  *
1255  * \param name The hostname that is to be queried.
1256  */
1257 void
1258 resolv_query(const char *name)
1259 {
1260  static uint8_t i;
1261 
1262  static uint8_t lseq, lseqi;
1263 
1264  register struct namemap *nameptr = 0;
1265 
1266  lseq = lseqi = 0;
1267 
1268  /* Remove trailing dots, if present. */
1269  name = remove_trailing_dots(name);
1270 
1271  for(i = 0; i < RESOLV_ENTRIES; ++i) {
1272  nameptr = &names[i];
1273  if(0 == strcasecmp(nameptr->name, name)) {
1274  break;
1275  }
1276  if((nameptr->state == STATE_UNUSED)
1277 #if RESOLV_SUPPORTS_RECORD_EXPIRATION
1278  || (nameptr->state == STATE_DONE && clock_seconds() > nameptr->expiration)
1279 #endif /* RESOLV_SUPPORTS_RECORD_EXPIRATION */
1280  ) {
1281  lseqi = i;
1282  lseq = 255;
1283  } else if(seqno - nameptr->seqno > lseq) {
1284  lseq = seqno - nameptr->seqno;
1285  lseqi = i;
1286  }
1287  }
1288 
1289  if(i == RESOLV_ENTRIES) {
1290  i = lseqi;
1291  nameptr = &names[i];
1292  }
1293 
1294  PRINTF("resolver: Starting query for \"%s\".\n", name);
1295 
1296  memset(nameptr, 0, sizeof(*nameptr));
1297 
1298  strncpy(nameptr->name, name, sizeof(nameptr->name));
1299  nameptr->state = STATE_NEW;
1300  nameptr->seqno = seqno;
1301  ++seqno;
1302 
1303 #if RESOLV_CONF_SUPPORTS_MDNS
1304  {
1305  size_t name_len = strlen(name);
1306 
1307  static const char local_suffix[] = "local";
1308 
1309  if((name_len > (sizeof(local_suffix) - 1)) &&
1310  (0 == strcasecmp(name + name_len - (sizeof(local_suffix) - 1), local_suffix))) {
1311  PRINTF("resolver: Using MDNS to look up \"%s\".\n", name);
1312  nameptr->is_mdns = 1;
1313  } else {
1314  nameptr->is_mdns = 0;
1315  }
1316  }
1317  nameptr->is_probe = (mdns_state == MDNS_STATE_PROBING) &&
1318  (0 == strcmp(nameptr->name, resolv_hostname));
1319 #endif /* RESOLV_CONF_SUPPORTS_MDNS */
1320 
1321  /* Force check_entires() to run on our process. */
1322  process_post(&resolv_process, PROCESS_EVENT_TIMER, 0);
1323 }
1324 /*---------------------------------------------------------------------------*/
1325 /**
1326  * Look up a hostname in the array of known hostnames.
1327  *
1328  * \note This function only looks in the internal array of known
1329  * hostnames, it does not send out a query for the hostname if none
1330  * was found. The function resolv_query() can be used to send a query
1331  * for a hostname.
1332  *
1333  */
1334 resolv_status_t
1335 resolv_lookup(const char *name, uip_ipaddr_t ** ipaddr)
1336 {
1337  resolv_status_t ret = RESOLV_STATUS_UNCACHED;
1338 
1339  static uint8_t i;
1340 
1341  struct namemap *nameptr;
1342 
1343  /* Remove trailing dots, if present. */
1344  name = remove_trailing_dots(name);
1345 
1346 #if UIP_CONF_LOOPBACK_INTERFACE
1347  if(strcmp(name, "localhost")) {
1348  static uip_ipaddr_t loopback =
1349 #if UIP_CONF_IPV6
1350  { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1351  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } };
1352 #else /* UIP_CONF_IPV6 */
1353  { { 127, 0, 0, 1 } };
1354 #endif /* UIP_CONF_IPV6 */
1355  if(ipaddr) {
1356  *ipaddr = &loopback;
1357  }
1358  ret = RESOLV_STATUS_CACHED;
1359  }
1360 #endif /* UIP_CONF_LOOPBACK_INTERFACE */
1361 
1362  /* Walk through the list to see if the name is in there. */
1363  for(i = 0; i < RESOLV_ENTRIES; ++i) {
1364  nameptr = &names[i];
1365 
1366  if(strcasecmp(name, nameptr->name) == 0) {
1367  switch (nameptr->state) {
1368  case STATE_DONE:
1369  ret = RESOLV_STATUS_CACHED;
1370 #if RESOLV_SUPPORTS_RECORD_EXPIRATION
1371  if(clock_seconds() > nameptr->expiration) {
1372  ret = RESOLV_STATUS_EXPIRED;
1373  }
1374 #endif /* RESOLV_SUPPORTS_RECORD_EXPIRATION */
1375  break;
1376  case STATE_NEW:
1377  case STATE_ASKING:
1379  break;
1380  /* Almost certainly a not-found error from server */
1381  case STATE_ERROR:
1383 #if RESOLV_SUPPORTS_RECORD_EXPIRATION
1384  if(clock_seconds() > nameptr->expiration) {
1385  ret = RESOLV_STATUS_UNCACHED;
1386  }
1387 #endif /* RESOLV_SUPPORTS_RECORD_EXPIRATION */
1388  break;
1389  }
1390 
1391  if(ipaddr) {
1392  *ipaddr = &nameptr->ipaddr;
1393  }
1394 
1395  /* Break out of for loop. */
1396  break;
1397  }
1398  }
1399 
1400 #if VERBOSE_DEBUG
1401  switch (ret) {
1402  case RESOLV_STATUS_CACHED:{
1403  PRINTF("resolver: Found \"%s\" in cache.\n", name);
1404  const uip_ipaddr_t *addr = *ipaddr;
1405 
1406  DEBUG_PRINTF
1407  ("resolver: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x \n",
1408  ((uint8_t *) addr)[0], ((uint8_t *) addr)[1], ((uint8_t *) addr)[2],
1409  ((uint8_t *) addr)[3], ((uint8_t *) addr)[4], ((uint8_t *) addr)[5],
1410  ((uint8_t *) addr)[6], ((uint8_t *) addr)[7], ((uint8_t *) addr)[8],
1411  ((uint8_t *) addr)[9], ((uint8_t *) addr)[10],
1412  ((uint8_t *) addr)[11], ((uint8_t *) addr)[12],
1413  ((uint8_t *) addr)[13], ((uint8_t *) addr)[14],
1414  ((uint8_t *) addr)[15]);
1415  break;
1416  }
1417  default:
1418  DEBUG_PRINTF("resolver: \"%s\" is NOT cached.\n", name);
1419  break;
1420  }
1421 #endif /* VERBOSE_DEBUG */
1422 
1423  return ret;
1424 }
1425 /*---------------------------------------------------------------------------*/
1426 /**
1427  * Obtain the currently configured DNS server.
1428  *
1429  * \return A pointer to a 4-byte representation of the IP address of
1430  * the currently configured DNS server or NULL if no DNS server has
1431  * been configured.
1432  */
1433 uip_ipaddr_t *
1434 resolv_getserver(void)
1435 {
1436  return &resolv_default_dns_server;
1437 }
1438 /*---------------------------------------------------------------------------*/
1439 /**
1440  * Configure a DNS server.
1441  *
1442  * \param dnsserver A pointer to a 4-byte representation of the IP
1443  * address of the DNS server to be configured.
1444  */
1445 void
1446 resolv_conf(const uip_ipaddr_t * dnsserver)
1447 {
1448  uip_ipaddr_copy(&resolv_default_dns_server, dnsserver);
1449 }
1450 /*---------------------------------------------------------------------------*/
1451 /** \internal
1452  * Callback function which is called when a hostname is found.
1453  *
1454  */
1455 static void
1456 resolv_found(char *name, uip_ipaddr_t * ipaddr)
1457 {
1458 #if RESOLV_CONF_SUPPORTS_MDNS
1459  if(strncasecmp(resolv_hostname, name, strlen(resolv_hostname)) == 0 &&
1460  ipaddr
1461 #if UIP_CONF_IPV6
1462  && !uip_ds6_is_my_addr(ipaddr)
1463 #else
1464  && uip_ipaddr_cmp(&uip_hostaddr, ipaddr) != 0
1465 #endif
1466  ) {
1467  uint8_t i;
1468 
1469  if(mdns_state == MDNS_STATE_PROBING) {
1470  /* We found this new name while probing.
1471  * We must now rename ourselves.
1472  */
1473  PRINTF("resolver: Name collision detected for \"%s\".\n", name);
1474 
1475  /* Remove the ".local" suffix. */
1476  resolv_hostname[strlen(resolv_hostname) - 6] = 0;
1477 
1478  /* Append the last three hex parts of the link-level address. */
1479  for(i = 0; i < 3; ++i) {
1480  uint8_t val = uip_lladdr.addr[(UIP_LLADDR_LEN - 3) + i];
1481 
1482  char append_str[4] = "-XX";
1483 
1484  append_str[2] = (((val & 0xF) > 9) ? 'a' : '0') + (val & 0xF);
1485  val >>= 4;
1486  append_str[1] = (((val & 0xF) > 9) ? 'a' : '0') + (val & 0xF);
1487  strncat(resolv_hostname, append_str,
1488  sizeof(resolv_hostname) - strlen(resolv_hostname));
1489  }
1490 
1491  /* Re-add the .local suffix */
1492  strncat(resolv_hostname, ".local", RESOLV_CONF_MAX_DOMAIN_NAME_SIZE);
1493 
1494  start_name_collision_check(CLOCK_SECOND * 5);
1495  } else if(mdns_state == MDNS_STATE_READY) {
1496  /* We found a collision after we had already asserted
1497  * that we owned this name. We need to immediately
1498  * and explicitly begin probing.
1499  */
1500  PRINTF("resolver: Possible name collision, probing...\n");
1501  start_name_collision_check(0);
1502  }
1503 
1504  } else
1505 #endif /* RESOLV_CONF_SUPPORTS_MDNS */
1506 
1507 #if VERBOSE_DEBUG
1508  if(ipaddr) {
1509 #if UIP_CONF_IPV6
1510  PRINTF("resolver: Found address for \"%s\".\n", name);
1511  PRINTF
1512  ("resolver: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x \n",
1513  ((uint8_t *) ipaddr)[0], ((uint8_t *) ipaddr)[1],
1514  ((uint8_t *) ipaddr)[2], ((uint8_t *) ipaddr)[3],
1515  ((uint8_t *) ipaddr)[4], ((uint8_t *) ipaddr)[5],
1516  ((uint8_t *) ipaddr)[6], ((uint8_t *) ipaddr)[7],
1517  ((uint8_t *) ipaddr)[8], ((uint8_t *) ipaddr)[9],
1518  ((uint8_t *) ipaddr)[10], ((uint8_t *) ipaddr)[11],
1519  ((uint8_t *) ipaddr)[12], ((uint8_t *) ipaddr)[13],
1520  ((uint8_t *) ipaddr)[14], ((uint8_t *) ipaddr)[15]);
1521 #else
1522  PRINTF("resolver: Found address for \"%s\": %d.%d.%d.%d\n", name,
1523  ipaddr->u8[0], ipaddr->u8[1], ipaddr->u8[2], ipaddr->u8[3]);
1524 #endif // UIP_CONF_IPV6
1525  } else {
1526  PRINTF("resolver: Unable to retrieve address for \"%s\".\n", name);
1527  }
1528 #endif /* VERBOSE_DEBUG */
1529 
1530  process_post(PROCESS_BROADCAST, resolv_event_found, name);
1531 }
1532 /*---------------------------------------------------------------------------*/
1533 #endif /* UIP_UDP */
1534 
1535 /** @} */
1536 /** @} */
#define PROCESS_END()
Definition: process.h:140
#define PROCESS(name, strname)
Definition: process.h:316
void process_start(struct process *p, const char *arg)
Definition: process.c:100
#define uip_gethostaddr(addr)
Definition: uip.h:214
#define PROCESS_WAIT_EVENT_UNTIL(c)
Definition: process.h:166
void process_exit(struct process *p)
Cause a process to exit.
Definition: process.c:203
#define PROCESS_WAIT_EVENT()
Definition: process.h:150
process_event_t process_alloc_event(void)
Allocate a global event number.
Definition: process.c:94
#define UIP_CONF_IPV6
Definition: uipopt.h:291
process_event_t tcpip_event
Definition: tcpip.c:81
uint16_t uip_len
Definition: uip.c:166
int process_post(struct process *p, process_event_t ev, process_data_t data)
Definition: process.c:327
#define PROCESS_BEGIN()
Definition: process.h:129
#define CLOCK_SECOND
Definition: clock.h:81
#define uip_newdata()
Definition: uip.h:745
#define uip_ipaddr_copy(dest, src)
Definition: uip.h:1036
CCIF struct uip_udp_conn * udp_new(const uip_ipaddr_t *ripaddr, uint16_t port, void *appstate)
Definition: etimer.h:77
#define UIP_HTONS(n)
Definition: uip.h:1248
uint8_t data[USBNET_RX_BUF_SIZE]
Definition: usbnet.h:140
void etimer_set(struct etimer *et, clock_time_t interval)
Set an event timer.
Definition: etimer.c:205
#define PROCESS_THREAD(name, ev, data)
Definition: process.h:282
#define uip_udp_bind(conn, port)
Definition: uip.h:895
CCIF process_event_t resolv_event_found
CCIF unsigned long clock_seconds(void)
Definition: clock.c:201
#define uip_poll()
Definition: uip.h:824
uint16_t uip_htons(uint16_t val)
Definition: uip.c:2076
CCIF void tcpip_poll_udp(struct uip_udp_conn *conn)
void * uip_appdata
Definition: uip.c:154