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