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