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