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