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