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