Libinfo-330.7.tar.gz
[apple/libinfo.git] / lookup.subproj / mdns_module.c
1 /*
2 * Copyright (c) 2008-2009 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /*
24 * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
25 *
26 * Permission to use, copy, modify, and distribute this software for any
27 * purpose with or without fee is hereby granted, provided that the above
28 * copyright notice and this permission notice appear in all copies.
29 *
30 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
31 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
32 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
33 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
34 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
35 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
36 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
37 * SOFTWARE.
38 */
39 /*
40 * Copyright (c) 1988, 1993
41 * The Regents of the University of California. All rights reserved.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution.
51 * 4. Neither the name of the University nor the names of its contributors
52 * may be used to endorse or promote products derived from this software
53 * without specific prior written permission.
54 *
55 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
56 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
57 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
58 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
59 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
60 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
61 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
62 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
63 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
64 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
65 * SUCH DAMAGE.
66 */
67 /*
68 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
69 *
70 * Permission to use, copy, modify, and distribute this software for any
71 * purpose with or without fee is hereby granted, provided that the above
72 * copyright notice and this permission notice appear in all copies, and that
73 * the name of Digital Equipment Corporation not be used in advertising or
74 * publicity pertaining to distribution of the document or software without
75 * specific, written prior permission.
76 *
77 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
78 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
79 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
80 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
81 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
82 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
83 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
84 * SOFTWARE.
85 */
86
87 #include "ils.h"
88 #include "netdb.h"
89 #include "si_module.h"
90
91 #include <assert.h>
92 #include <arpa/inet.h>
93 #include <arpa/nameser.h>
94 #include <arpa/nameser_compat.h>
95 #include <libkern/OSAtomic.h>
96 #include <netinet/in.h>
97 #include <ctype.h>
98 #include <dns_sd.h>
99 #include <dnsinfo.h>
100 #include <errno.h>
101 #include <nameser.h>
102 #include <notify.h>
103 #include <pthread.h>
104 #include <resolv.h>
105 #include <stdio.h>
106 #include <stdlib.h>
107 #include <string.h>
108 #include <sys/event.h>
109 #include <sys/param.h>
110 #include <sys/time.h>
111 #include <sys/types.h>
112 #include <sys/socket.h>
113 #include <net/if.h>
114 #include <time.h>
115 #include <unistd.h>
116 #include <asl.h>
117 #include <dns.h>
118 #include <dns_util.h>
119 #include <TargetConditionals.h>
120
121 /* from dns_util.c */
122 #define DNS_MAX_RECEIVE_SIZE 65536
123
124 #define INET_NTOP_AF_INET_OFFSET 4
125 #define INET_NTOP_AF_INET6_OFFSET 8
126
127 #define IPPROTO_UNSPEC 0
128
129 static int _mdns_debug = 0;
130
131 // mutex protects DNSServiceProcessResult and DNSServiceRefDeallocate
132 static pthread_mutex_t _mdns_mutex = PTHREAD_MUTEX_INITIALIZER;
133
134 // XXX
135 // Options: timeout:n total_timeout attempts
136
137 /* _dns_config_token: notify token indicating dns config needs refresh
138 */
139 static int _dns_config_token = -1;
140
141 typedef struct {
142 int32_t rc;
143 dns_config_t *dns;
144 dns_resolver_t *primary;
145 uint32_t n_defaults;
146 dns_resolver_t **defaults;
147 char **search_list;
148 int ndots;
149 } mdns_config_t;
150
151 typedef struct {
152 uint16_t priority;
153 uint16_t weight;
154 uint16_t port;
155 uint8_t target[0];
156 } mdns_rr_srv_t;
157
158 typedef struct mdns_srv_t mdns_srv_t;
159 struct mdns_srv_t {
160 si_srv_t srv;
161 mdns_srv_t *next;
162 };
163
164 typedef struct {
165 struct hostent host;
166 int alias_count;
167 int addr_count;
168 } mdns_hostent_t;
169
170 typedef struct {
171 mdns_hostent_t *h4;
172 mdns_hostent_t *h6;
173 mdns_srv_t *srv;
174 uint64_t ttl;
175 uint32_t ifnum;
176 } mdns_reply_t;
177
178 DNSServiceRef _mdns_sdref;
179 DNSServiceRef _mdns_old_sdref;
180
181 static int _mdns_query_mDNSResponder(const char *name, int class, int type,
182 const char *interface, DNSServiceFlags flags,
183 uint8_t *answer, uint32_t *anslen,
184 mdns_reply_t *reply, uint32_t timeout);
185
186 static int _mdns_resolver_get_option(dns_resolver_t *resolver, const char* option);
187 static void _mdns_hostent_clear(mdns_hostent_t *h);
188 static void _mdns_reply_clear(mdns_reply_t *r);
189
190 static const char hexchar[] = "0123456789abcdef";
191
192 #define BILLION 1000000000
193
194 /* length of a reverse DNS IPv6 address query name, e.g. "9.4.a.f.c.e.e.f.e.e.1.5.4.1.4.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa" */
195 #define IPv6_REVERSE_LEN 72
196
197 /* index of the trailing char that must be "8", "9", "A", "a", "b", or "B" */
198 #define IPv6_REVERSE_LINK_LOCAL_TRAILING_CHAR 58
199
200 /* index of low-order nibble of embedded scope id */
201 #define IPv6_REVERSE_LINK_LOCAL_SCOPE_ID_LOW 48
202
203 const static uint8_t hexval[128] = {
204 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 - 15 */
205 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16 - 31 */
206 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 32 - 47 */
207 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 48 - 63 */
208 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 64 - 79 */
209 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 95 */
210 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 96 - 111 */
211 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 112 - 127 */
212 };
213
214 /*
215 * _mdns_create_search_list
216 * Creates a NULL terminated array of strings from the specied resolver's
217 * search list, or from the components of the specified resolver's domain
218 * if search list is empty.
219 * Free the list and elements with free(3) when done.
220 */
221 static char **
222 _mdns_create_search_list(dns_resolver_t *resolver)
223 {
224 int n, m;
225 char *p, *domain;
226 char **list;
227
228 if (resolver == NULL) return NULL;
229
230 // return the search list if present
231 if (resolver->n_search > 0) {
232 list = (char **)calloc(resolver->n_search+1, sizeof(char *));
233 if (list == NULL) return NULL;
234 for (n = 0; n < resolver->n_search; ++n) {
235 list[n] = strdup(resolver->search[n]);
236 }
237 return list;
238 }
239
240 if (resolver->domain == NULL) return NULL;
241 domain = strdup(resolver->domain);
242 if (domain == NULL) return NULL;
243
244 // count dots
245 n = 0;
246 for (p = domain; *p != '\0'; p++) {
247 if (*p == '.') n++;
248 }
249
250 // trim trailing dots
251 for (p--; (p >= domain) && (*p == '.'); p--) {
252 *p = '\0';
253 n--;
254 }
255
256 // make sure the resulting string is not empty
257 if (p < domain) {
258 free(domain);
259 return NULL;
260 }
261
262 // dots are separators, so number of components is one larger
263 n++;
264
265 m = 0;
266 list = (char **)calloc(n+1, sizeof(char *));
267 if (list == NULL) return NULL;
268 // first item in list is domain itself
269 list[m++] = domain;
270
271 // include parent domains with at least LOCALDOMAINPARTS components
272 p = domain;
273 while (n > LOCALDOMAINPARTS) {
274 // find next component
275 while ((*p != '.') && (*p != '\0')) p++;
276 if (*p == '\0') break;
277 p++;
278 // add to the list
279 n--;
280 list[m++] = strdup(p);
281 }
282 return list;
283 }
284
285 /* _mdns_resolver_get_option
286 * Determines whether the specified option is present in the resolver.
287 */
288 static int
289 _mdns_resolver_get_option(dns_resolver_t *resolver, const char* option)
290 {
291 if (resolver == NULL) return 0;
292 int len = strlen(option);
293 char *options = resolver->options;
294 if (options == NULL) return 0;
295 // look for "(^| )option( |:|$)"
296 char *ptr = strstr(options, option);
297 while (ptr) {
298 if (ptr == options || ptr[-1] == ' ') {
299 if (ptr[len] == ' ' || ptr[len] == 0) {
300 return 1;
301 } else if (ptr[len] == ':') {
302 return strtol(&ptr[len+1], NULL, 10);
303 }
304 }
305 ptr = strstr(ptr, option);
306 }
307 return 0;
308 }
309
310 /* _mdns_compare_resolvers
311 * Compares two dns_resolver_t pointers by search order ascending.
312 */
313 static int
314 _mdns_compare_resolvers(const void *a, const void *b)
315 {
316 dns_resolver_t **x = (dns_resolver_t **)a, **y = (dns_resolver_t **)b;
317 return ((*x)->search_order - (*y)->search_order);
318 }
319
320 /* _mdns_create_default_resolvers_list
321 * Returns an array of dns_resolver_t containing only default resolvers.
322 * A resolver is a default resolver if it is the primary resolver or if it
323 * contains the "default" configuration option.
324 */
325 static void
326 _mdns_config_init_default_resolvers(mdns_config_t *config)
327 {
328 uint32_t count = config->dns->n_resolver;
329 if (count == 0) return;
330 config->defaults = calloc(count, sizeof(dns_resolver_t *));
331 if (config->defaults == NULL) return;
332 int m = 0, i, j;
333 if (config->primary) config->defaults[m++] = config->primary;
334 // iterate the resolvers, add any default resolvers that are not
335 // already in the list.
336 for (i = 0; i < count; ++i) {
337 dns_resolver_t *resolver = config->dns->resolver[i];
338 if (_mdns_resolver_get_option(resolver, "default")) {
339 int exists = 0;
340 for (j = 0; j < m; ++j) {
341 if (config->defaults[j] == resolver) {
342 exists = 1;
343 break;
344 }
345 }
346 if (!exists) {
347 config->defaults[m++] = resolver;
348 }
349 }
350 }
351 config->n_defaults = m;
352 // sort list by search order ascending
353 qsort(config->defaults, config->n_defaults, sizeof(dns_resolver_t *), _mdns_compare_resolvers);
354 }
355
356 #if 0
357 static void
358 _mdns_print_dns_resolver(dns_resolver_t *resolver)
359 {
360 printf("resolver = {\n");
361 printf("\tdomain = %s\n", resolver->domain);
362 int j;
363 for (j = 0; j < resolver->n_nameserver; ++j) {
364 int res;
365 char host[255], serv[255];
366 res = getnameinfo(resolver->nameserver[j], resolver->nameserver[j]->sa_len, host, sizeof(host), serv, sizeof(serv), NI_NUMERICHOST | NI_NUMERICSERV);
367 if (res == 0) {
368 printf("\tnameserver[%d] = %s:%s\n", j, host, serv);
369 } else {
370 printf("\tnameserver[%d] = %s\n", j, gai_strerror(res));
371 }
372 }
373 printf("\tport = %d\n", resolver->port);
374 for (j = 0; j < resolver->n_search; ++j) {
375 printf("\tsearch[%d] = %s\n", j, resolver->search[j]);
376 }
377 // sortaddr
378 printf("\tn_sortaddr = %d\n", resolver->n_sortaddr);
379 // options
380 printf("\toptions = %s\n", resolver->options);
381 printf("\ttimeout = %d\n", resolver->timeout);
382 printf("\tsearch_order = %d\n", resolver->search_order);
383 printf("}\n");
384 }
385
386 static void
387 _mdns_print_dns_config(dns_config_t *config)
388 {
389 int i;
390 dns_resolver_t **list = _mdns_create_sorted_resolver_list(config);
391 dns_resolver_t **ptr = list;
392 while (*ptr) {
393 _mdns_print_dns_resolver(*ptr);
394 ptr++;
395 }
396 free(list);
397 }
398
399 static void
400 _mdns_print_hostent(mdns_hostent_t* h)
401 {
402 if (h == NULL) return;
403 printf("hostent[%p] = {\n", h);
404 printf("\thost = {\n");
405 printf("\t\th_name = %s\n", h->host.h_name);
406 printf("\t\th_length = %d\n", h->host.h_length);
407 printf("\t\th_addrtype = %d\n", h->host.h_addrtype);
408 char **alias = h->host.h_aliases;
409 while (alias && *alias) {
410 printf("\t\th_aliases = %s\n", *alias++);
411 }
412 char **addr = h->host.h_addr_list;
413 while (addr && *addr) {
414 printf("\t\th_addr_list = %x\n", ntohl(*(uint32_t*)*addr++));
415 }
416 printf("\t}\n");
417 printf("\talias_count = %d\n", h->alias_count);
418 printf("\taddr_count = %d\n", h->addr_count);
419 printf("}\n");
420 }
421
422 #endif
423
424 /* _mdns_config_retain
425 * Retain the mdns configuration.
426 */
427 static mdns_config_t *
428 _mdns_config_retain(mdns_config_t *config)
429 {
430 int32_t rc;
431
432 if (config == NULL) return NULL;
433 rc = OSAtomicIncrement32Barrier(&config->rc);
434 assert(rc > 1);
435 return config;
436 }
437
438 /* _mdns_config_release
439 * Releases the mdns configuration structure and
440 * frees the data if no references remain.
441 */
442 static void
443 _mdns_config_release(mdns_config_t *config)
444 {
445 int32_t rc;
446
447 if (config == NULL) return;
448 rc = OSAtomicDecrement32Barrier(&config->rc);
449 assert(rc >= 0);
450 if (rc == 0) {
451 if (config->dns) dns_configuration_free(config->dns);
452 free(config->defaults);
453 char **p = config->search_list;
454 while (p && *p) { free(*p++); }
455 free(config->search_list);
456 free(config);
457 }
458 }
459
460 /* _mdns_copy_system_config
461 * Retrieves DNS configuration from SystemConfiguration.framework.
462 * Checks notify notification to determine whether configuration is in need
463 * of a refresh.
464 */
465 static mdns_config_t *
466 _mdns_copy_system_config(void)
467 {
468 // first call needs refresh
469 static mdns_config_t *current_config;
470 mdns_config_t *config = NULL;
471 int refresh = 1;
472 int res;
473
474 pthread_mutex_lock(&_mdns_mutex);
475
476 // check whether the global configuration has changed
477 if (_dns_config_token == -1) {
478 res = notify_register_check(dns_configuration_notify_key(), &_dns_config_token);
479 if (res != NOTIFY_STATUS_OK) _dns_config_token = -1;
480 }
481
482 if (_dns_config_token != -1) {
483 res = notify_check(_dns_config_token, &refresh);
484 if (res != NOTIFY_STATUS_OK) refresh = 1;
485 }
486
487 // return the current configuration if still valid
488 if (refresh == 0) {
489 mdns_config_t *config = _mdns_config_retain(current_config);
490 pthread_mutex_unlock(&_mdns_mutex);
491 return config;
492 }
493
494 // need to allocate a new configuration
495
496 config = calloc(1, sizeof(mdns_config_t));
497 if (config != NULL) config->dns = dns_configuration_copy();
498
499 // failed to get new config, return previous config
500 if (config == NULL || config->dns == NULL) {
501 free(config);
502 config = _mdns_config_retain(current_config);
503 pthread_mutex_unlock(&_mdns_mutex);
504 return config;
505 }
506
507 config->rc = 1;
508 if (config->dns->n_resolver > 0) {
509 // primary resolver is always index 0 and contains the
510 // search domains
511 config->primary = config->dns->resolver[0];
512 config->search_list = _mdns_create_search_list(config->primary);
513 _mdns_config_init_default_resolvers(config);
514 }
515 config->ndots = _mdns_resolver_get_option(config->primary, "ndots");
516
517 // promote the new configuration to current
518 _mdns_config_release(current_config);
519 current_config = config;
520
521 // return the new configuration
522 config = _mdns_config_retain(config);
523 pthread_mutex_unlock(&_mdns_mutex);
524 return config;
525 }
526
527 /* _mdns_timeout_for_name
528 * Returns the appropriate timeout for the specified name based on the
529 * sum of the timeouts of all resolvers that match the name.
530 */
531 static uint32_t
532 _mdns_timeout_for_name(mdns_config_t *config, const char *name)
533 {
534 int i;
535 uint32_t timeout = 0;
536
537 if (name == NULL) return 0;
538
539 // use strncasecmp to ignore a trailing '.' in name
540 int len = strlen(name);
541 if ((len - 1) >= 0 && name[len-1] == '.') --len;
542
543 const char *p = name;
544 while (len > 0) {
545 uint32_t count = config->dns->n_resolver;
546 for (i = 0; i < count; ++i) {
547 dns_resolver_t *resolver = config->dns->resolver[i];
548 if (resolver->domain == NULL) continue;
549 if (strncasecmp(resolver->domain, p, len) == 0) {
550 timeout += resolver->timeout;
551 }
552 }
553 // discard the current label
554 while (len > 0) {
555 ++p;
556 --len;
557 if (p[-1] == '.') break;
558 }
559 }
560 return timeout;
561 }
562
563 /* _mdns_query_unqualified
564 * Performs a query for the name as an unqualified name (appends each
565 * of the default resolver's domains).
566 */
567 static int
568 _mdns_query_unqualified(mdns_config_t *config, const char *name, uint32_t class, uint32_t type, const char *interface, DNSServiceFlags flags, uint8_t *buf, uint32_t *len, mdns_reply_t *reply)
569 {
570 int i, res = -1;
571
572 for (i = 0; i < config->n_defaults; ++i) {
573 dns_resolver_t *resolver = config->defaults[i];
574 char *qname;
575
576 asprintf(&qname, "%s.%s", name, resolver->domain ? resolver->domain : "");
577 res = _mdns_query_mDNSResponder(qname, class, type, interface, flags, buf, len, reply, resolver->timeout);
578 free(qname);
579
580 if (res == 0) break;
581 else _mdns_reply_clear(reply);
582 }
583 return res;
584 }
585
586 /* _mdns_query_absolute
587 * Performs a query for the name as an absolute name (does not qualify with any
588 * additional domains).
589 */
590 static int
591 _mdns_query_absolute(mdns_config_t *config, const char *name, uint32_t class, uint32_t type, const char *interface, DNSServiceFlags flags, uint32_t fqdn, uint8_t *buf, uint32_t *len, mdns_reply_t *reply)
592 {
593 int res = -1;
594 char *qname = (char *)name;
595
596 uint32_t timeout = _mdns_timeout_for_name(config, name);
597
598 if (fqdn == 0) asprintf(&qname, "%s.", name);
599 res = _mdns_query_mDNSResponder(qname, class, type, interface, flags, buf, len, reply, timeout);
600 if (fqdn == 0) free(qname);
601 if (res != 0) _mdns_reply_clear(reply);
602 return res;
603 }
604
605 static int
606 _mdns_search(const char *name, uint32_t class, uint32_t type, const char *interface, DNSServiceFlags flags, uint32_t fqdn, uint32_t recurse, uint8_t *buf, uint32_t *len, mdns_reply_t *reply)
607 {
608 int res = -1;
609 int i, n, ndots;
610 char *dot;
611
612 if (name == NULL) return -1;
613
614 mdns_config_t *config = _mdns_copy_system_config();
615 if (config == NULL) return -1;
616
617 // NDOTS is the threshold for trying a qualified name "as is"
618 ndots = config->ndots;
619 if (ndots == 0) ndots = 1;
620
621 // count the dots, and remember position of the last one
622 n = 0;
623 dot = NULL;
624 for (i = 0; name[i] != '\0'; i++) {
625 if (name[i] == '.') {
626 n++;
627 dot = (char *)(name + i);
628 }
629 }
630 // FQDN has dot for last character
631 if (fqdn == 0 && dot != NULL && dot[1] == '\0') fqdn = 1;
632
633 // if the name has at least ndots, try first as an absolute query.
634 // FQDN and PTR queries are always absolute.
635 if (n >= ndots || fqdn == 1 || type == ns_t_ptr) {
636 res = _mdns_query_absolute(config, name, class, type, interface, flags, fqdn, buf, len, reply);
637 if (res == 0) {
638 _mdns_config_release(config);
639 return res;
640 }
641 }
642
643 // stop if FQDN, PTR, or no recursion requested
644 if (fqdn == 1 || type == ns_t_ptr || recurse == 0) {
645 _mdns_config_release(config);
646 return -1;
647 }
648
649 // Qualify the name with each of the search domains looking for a match.
650 char **search = config->search_list;
651 if (search != NULL) {
652 res = -1;
653 for (i = 0; i < MAXDNSRCH && search[i] != NULL; ++i) {
654 char *qname;
655 asprintf(&qname, "%s.%s", name, search[i]);
656 res = _mdns_search(qname, class, type, interface, flags, 0, 0, buf, len, reply);
657 free(qname);
658 if (res == 0) break;
659 }
660 } else {
661 // The name is not fully qualified and there is no search list.
662 // Try each default resolver, qualifying the name with that
663 // resolver's domain.
664 res = _mdns_query_unqualified(config, name, class, type, interface, flags, buf, len, reply);
665 }
666 _mdns_config_release(config);
667 return res;
668 }
669
670 static char *
671 _mdns_reverse_ipv4(const char *addr)
672 {
673 union
674 {
675 uint32_t a;
676 unsigned char b[4];
677 } ab;
678 char *p;
679
680 if (addr == NULL) return NULL;
681
682 memcpy(&(ab.a), addr, 4);
683
684 asprintf(&p, "%u.%u.%u.%u.in-addr.arpa.", ab.b[3], ab.b[2], ab.b[1], ab.b[0]);
685 return p;
686 }
687
688 static char *
689 _mdns_reverse_ipv6(const char *addr)
690 {
691 char x[65], *p;
692 int i, j;
693 u_int8_t d, hi, lo;
694
695 if (addr == NULL) return NULL;
696
697 x[64] = '\0';
698 j = 63;
699 for (i = 0; i < 16; i++)
700 {
701 d = addr[i];
702 lo = d & 0x0f;
703 hi = d >> 4;
704 x[j--] = '.';
705 x[j--] = hexchar[hi];
706 x[j--] = '.';
707 x[j--] = hexchar[lo];
708 }
709
710 asprintf(&p, "%sip6.arpa.", x);
711
712 return p;
713 }
714
715 /* _mdns_canonicalize
716 * Canonicalize the domain name by converting to lower case and removing the
717 * trailing '.' if present.
718 */
719 static char *
720 _mdns_canonicalize(const char *s)
721 {
722 int i;
723 char *t;
724 if (s == NULL) return NULL;
725 t = strdup(s);
726 if (t == NULL) return NULL;
727 if (t[0] == '\0') return t;
728 for (i = 0; t[i] != '\0'; i++) {
729 if (t[i] >= 'A' && t[i] <= 'Z') t[i] += 32;
730 }
731 if (t[i-1] == '.') t[i-1] = '\0';
732 return t;
733 }
734
735 /* _mdns_hostent_append_alias
736 * Appends an alias to the mdns_hostent_t structure.
737 */
738 static int
739 _mdns_hostent_append_alias(mdns_hostent_t *h, const char *alias)
740 {
741 int i;
742 char *name;
743 if (h == NULL || alias == NULL) return 0;
744 name = _mdns_canonicalize(alias);
745 if (name == NULL) return -1;
746
747 // don't add the name if it matches an existing name
748 if (h->host.h_name && string_equal(h->host.h_name, name)) {
749 free(name);
750 return 0;
751 }
752 for (i = 0; i < h->alias_count; ++i) {
753 if (string_equal(h->host.h_aliases[i], name)) {
754 free(name);
755 return 0;
756 }
757 }
758
759 // add the alias and NULL terminate the list
760 h->host.h_aliases = (char **)reallocf(h->host.h_aliases, (h->alias_count+2) * sizeof(char *));
761 if (h->host.h_aliases == NULL) {
762 h->alias_count = 0;
763 free(name);
764 return -1;
765 }
766 h->host.h_aliases[h->alias_count] = name;
767 ++h->alias_count;
768 h->host.h_aliases[h->alias_count] = NULL;
769 return 0;
770 }
771
772 /* _mdns_hostent_append_addr
773 * Appends an alias to the mdns_hostent_t structure.
774 */
775 static int
776 _mdns_hostent_append_addr(mdns_hostent_t *h, const uint8_t *addr, uint32_t len)
777 {
778 if (h == NULL || addr == NULL || len == 0) return 0;
779
780 // copy the address buffer
781 uint8_t *buf = malloc(len);
782 if (buf == NULL) return -1;
783 memcpy(buf, addr, len);
784
785 // add the address and NULL terminate the list
786 h->host.h_addr_list = (char **)reallocf(h->host.h_addr_list, (h->addr_count+2) * sizeof(char *));
787 if (h->host.h_addr_list == NULL) {
788 h->addr_count = 0;
789 return -1;
790 }
791 h->host.h_addr_list[h->addr_count] = (char*)buf;
792 h->addr_count++;
793 h->host.h_addr_list[h->addr_count] = NULL;
794 return 0;
795 }
796
797 static void
798 _mdns_hostent_clear(mdns_hostent_t *h)
799 {
800 if (h == NULL) return;
801 free(h->host.h_name);
802 h->host.h_name = NULL;
803
804 char **aliases = h->host.h_aliases;
805 while (aliases && *aliases) {
806 free(*aliases++);
807 }
808 free(h->host.h_aliases);
809 h->host.h_aliases = NULL;
810 h->alias_count = 0;
811
812 char **addrs = h->host.h_addr_list;
813 while (addrs && *addrs) {
814 free(*addrs++);
815 }
816 free(h->host.h_addr_list);
817 h->host.h_addr_list = NULL;
818 h->addr_count = 0;
819
820 }
821
822 static void
823 _mdns_reply_clear(mdns_reply_t *r)
824 {
825 if (r == NULL) return;
826 r->ifnum = 0;
827 _mdns_hostent_clear(r->h4);
828 _mdns_hostent_clear(r->h6);
829 mdns_srv_t *srv = r->srv;
830 r->srv = NULL;
831 while (srv) {
832 mdns_srv_t *next = srv->next;
833 free(srv->srv.target);
834 free(srv);
835 srv = next;
836 }
837 }
838
839 static si_item_t *
840 _mdns_hostbyname(si_mod_t *si, const char *name, int af, const char *interface, uint32_t *err)
841 {
842 uint32_t type;
843 mdns_hostent_t h;
844 mdns_reply_t reply;
845 si_item_t *out = NULL;
846 uint64_t bb;
847 int status;
848 DNSServiceFlags flags = 0;
849
850 if (err != NULL) *err = SI_STATUS_NO_ERROR;
851
852 if (name == NULL) {
853 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
854 return NULL;
855 }
856
857 memset(&h, 0, sizeof(h));
858 memset(&reply, 0, sizeof(reply));
859
860 switch (af) {
861 case AF_INET:
862 type = ns_t_a;
863 h.host.h_length = 4;
864 reply.h4 = &h;
865 break;
866 case AF_INET6:
867 type = ns_t_aaaa;
868 h.host.h_length = 16;
869 reply.h6 = &h;
870 break;
871 default:
872 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
873 return NULL;
874 }
875 h.host.h_addrtype = af;
876
877 status = _mdns_search(name, ns_c_in, type, interface, flags, 0, 1, NULL, NULL, &reply);
878 if (status != 0 || h.addr_count == 0) {
879 _mdns_reply_clear(&reply);
880 if (err != NULL) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
881 return NULL;
882 }
883
884 bb = reply.ttl + time(NULL);
885
886 switch (af) {
887 case AF_INET:
888 out = (si_item_t *)LI_ils_create("L4488s*44a", (unsigned long)si, CATEGORY_HOST_IPV4, 1, bb, 0LL, h.host.h_name, h.host.h_aliases, h.host.h_addrtype, h.host.h_length, h.host.h_addr_list);
889 break;
890 case AF_INET6:
891 out = (si_item_t *)LI_ils_create("L4488s*44c", (unsigned long)si, CATEGORY_HOST_IPV6, 1, bb, 0LL, h.host.h_name, h.host.h_aliases, h.host.h_addrtype, h.host.h_length, h.host.h_addr_list);
892 break;
893 }
894
895 _mdns_reply_clear(&reply);
896
897 if (out == NULL && err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
898
899 return out;
900 }
901
902 static si_item_t *
903 _mdns_hostbyaddr(si_mod_t *si, const void *addr, int af, const char *interface, uint32_t *err)
904 {
905 mdns_hostent_t h;
906 mdns_reply_t reply;
907 char *name;
908 si_item_t *out;
909 uint64_t bb;
910 int cat;
911 int status;
912 DNSServiceFlags flags = 0;
913
914 if (err != NULL) *err = SI_STATUS_NO_ERROR;
915
916 if (addr == NULL || si == NULL) {
917 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
918 return NULL;
919 }
920
921 memset(&h, 0, sizeof(h));
922 memset(&reply, 0, sizeof(reply));
923
924 switch (af) {
925 case AF_INET:
926 h.host.h_length = 4;
927 reply.h4 = &h;
928 name = _mdns_reverse_ipv4(addr);
929 cat = CATEGORY_HOST_IPV4;
930 break;
931 case AF_INET6:
932 h.host.h_length = 16;
933 reply.h6 = &h;
934 name = _mdns_reverse_ipv6(addr);
935 cat = CATEGORY_HOST_IPV6;
936 break;
937 default:
938 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
939 return NULL;
940 }
941 h.host.h_addrtype = af;
942
943 status = _mdns_search(name, ns_c_in, ns_t_ptr, interface, flags, 0, 1, NULL, NULL, &reply);
944 free(name);
945 if (status != 0) {
946 _mdns_reply_clear(&reply);
947 if (err != NULL) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
948 return NULL;
949 }
950
951 status = _mdns_hostent_append_addr(&h, addr, h.host.h_length);
952 if (status != 0) {
953 _mdns_hostent_clear(&h);
954 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
955 return NULL;
956 }
957
958 bb = reply.ttl + time(NULL);
959 out = (si_item_t *)LI_ils_create("L4488s*44a", (unsigned long)si, cat, 1, bb, 0LL, h.host.h_name, h.host.h_aliases, h.host.h_addrtype, h.host.h_length, h.host.h_addr_list);
960
961 _mdns_hostent_clear(&h);
962
963 if (out == NULL && err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
964 return out;
965 }
966
967 static si_list_t *
968 _mdns_addrinfo(si_mod_t *si, const void *node, const void *serv, uint32_t family, uint32_t socktype, uint32_t proto, uint32_t flags, const char *interface, uint32_t *err)
969 {
970 int wantv4 = 1;
971 int wantv6 = 1;
972 if (family == AF_INET6) wantv4 = 0;
973 else if (family == AF_INET) wantv6 = 0;
974 else if (family != AF_UNSPEC) return NULL;
975
976 struct in_addr a4;
977 struct in6_addr a6;
978 mdns_hostent_t h4;
979 mdns_hostent_t h6;
980 mdns_reply_t reply;
981 uint32_t type;
982 uint16_t port;
983
984 if (err != NULL) *err = SI_STATUS_NO_ERROR;
985
986 si_list_t *out = NULL;
987
988 memset(&h4, 0, sizeof(h4));
989 memset(&h6, 0, sizeof(h6));
990 memset(&reply, 0, sizeof(reply));
991
992 h4.host.h_addrtype = AF_INET;
993 h4.host.h_length = 4;
994 h6.host.h_addrtype = AF_INET6;
995 h6.host.h_length = 16;
996
997 if (wantv4 && wantv6) {
998 type = 0;
999 reply.h4 = &h4;
1000 reply.h6 = &h6;
1001 } else if (wantv4) {
1002 reply.h4 = &h4;
1003 type = ns_t_a;
1004 } else if (wantv6) {
1005 type = ns_t_aaaa;
1006 reply.h6 = &h6;
1007 } else {
1008 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1009 return NULL;
1010 }
1011
1012 // service lookup
1013 if ((flags & AI_NUMERICSERV) != 0) {
1014 port = *(uint16_t *)serv;
1015 } else {
1016 if (_gai_serv_to_port(serv, proto, &port) != 0) {
1017 if (err) *err = SI_STATUS_EAI_NONAME;
1018 return NULL;
1019 }
1020 }
1021
1022 // host lookup
1023 if ((flags & AI_NUMERICHOST) != 0) {
1024 char *cname = NULL;
1025 struct in_addr *p4 = NULL;
1026 struct in6_addr *p6 = NULL;
1027 if (family == AF_INET) {
1028 p4 = &a4;
1029 memcpy(p4, node, sizeof(a4));
1030 } else if (family == AF_INET6) {
1031 p6 = &a6;
1032 memcpy(p6, node, sizeof(a6));
1033 }
1034 out = si_addrinfo_list(si, socktype, proto, p4, p6, port, 0, cname, cname);
1035 } else {
1036 DNSServiceFlags dns_flags = 0;
1037 if (flags & AI_ADDRCONFIG) {
1038 dns_flags |= kDNSServiceFlagsSuppressUnusable;
1039 }
1040 int res;
1041 res = _mdns_search(node, ns_c_in, type, interface, dns_flags, 0, 1, NULL, NULL, &reply);
1042 if (res == 0 && (h4.addr_count > 0 || h6.addr_count > 0)) {
1043 out = si_addrinfo_list_from_hostent(si, socktype, proto,
1044 port, 0,
1045 (wantv4 ? &h4.host : NULL),
1046 (wantv6 ? &h6.host : NULL));
1047 } else if (err != NULL) {
1048 *err = SI_STATUS_EAI_NONAME;
1049 }
1050 _mdns_reply_clear(&reply);
1051 }
1052 return out;
1053 }
1054
1055 static si_list_t *
1056 _mdns_srv_byname(si_mod_t* si, const char *qname, const char *interface, uint32_t *err)
1057 {
1058 si_list_t *out = NULL;
1059 mdns_reply_t reply;
1060 mdns_srv_t *srv;
1061 int res;
1062 const uint64_t unused = 0;
1063 DNSServiceFlags flags = 0;
1064
1065 if (err != NULL) *err = SI_STATUS_NO_ERROR;
1066
1067 memset(&reply, 0, sizeof(reply));
1068 res = _mdns_search(qname, ns_c_in, ns_t_srv, interface, flags, 0, 1, NULL, NULL, &reply);
1069 if (res == 0) {
1070 srv = reply.srv;
1071 while (srv) {
1072 si_item_t *item;
1073 item = (si_item_t *)LI_ils_create("L4488222s", (unsigned long)si, CATEGORY_SRV, 1, unused, unused, srv->srv.priority, srv->srv.weight, srv->srv.port, srv->srv.target);
1074 out = si_list_add(out, item);
1075 si_item_release(item);
1076 srv = srv->next;
1077 }
1078 }
1079 _mdns_reply_clear(&reply);
1080 return out;
1081 }
1082
1083 /*
1084 * We support dns_async_start / cancel / handle_reply using dns_item_call
1085 */
1086 static si_item_t *
1087 _mdns_item_call(si_mod_t *si, int call, const char *name, const char *ignored, const char *interface, uint32_t class, uint32_t type, uint32_t *err)
1088 {
1089 int res;
1090 uint8_t buf[DNS_MAX_RECEIVE_SIZE];
1091 uint32_t len = sizeof(buf);
1092 mdns_reply_t reply;
1093 mdns_hostent_t h4;
1094 mdns_hostent_t h6;
1095 si_item_t *out;
1096 int norecurse = 0;
1097 DNSServiceFlags flags = 0;
1098
1099 if (err != NULL) *err = SI_STATUS_NO_ERROR;
1100
1101 switch (call) {
1102 case SI_CALL_DNS_QUERY:
1103 norecurse = 1;
1104 break;
1105 case SI_CALL_DNS_SEARCH:
1106 break;
1107 default:
1108 if (err) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1109 return NULL;
1110 break;
1111 }
1112
1113 if (name == NULL) {
1114 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1115 return NULL;
1116 }
1117
1118 memset(&h4, 0, sizeof(h4));
1119 memset(&h6, 0, sizeof(h6));
1120 memset(&reply, 0, sizeof(reply));
1121
1122 h4.host.h_addrtype = AF_INET;
1123 h4.host.h_length = 4;
1124 h6.host.h_addrtype = AF_INET6;
1125 h6.host.h_length = 16;
1126 reply.h4 = &h4;
1127 reply.h6 = &h6;
1128
1129 res = _mdns_search(name, class, type, interface, flags, norecurse, 1, buf, &len, &reply);
1130 if (res != 0 || len <= 0 || len > DNS_MAX_RECEIVE_SIZE) {
1131 _mdns_reply_clear(&reply);
1132 if (err != NULL) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
1133 return NULL;
1134 }
1135
1136 struct sockaddr_in6 from;
1137 uint32_t fromlen = sizeof(from);
1138 memset(&from, 0, fromlen);
1139 from.sin6_len = fromlen;
1140 from.sin6_family = AF_INET6;
1141 from.sin6_addr.__u6_addr.__u6_addr8[15] = 1;
1142 if (reply.ifnum != 0) {
1143 from.sin6_addr.__u6_addr.__u6_addr16[0] = htons(0xfe80);
1144 from.sin6_scope_id = reply.ifnum;
1145 }
1146
1147 out = (si_item_t *)LI_ils_create("L4488@@", (unsigned long)si, CATEGORY_DNSPACKET, 1, 0LL, 0LL, len, buf, fromlen, &from);
1148 if (out == NULL && err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1149
1150 _mdns_reply_clear(&reply);
1151
1152 return out;
1153 }
1154
1155 static int
1156 _mdns_is_valid(si_mod_t *si, si_item_t *item)
1157 {
1158 return 0;
1159 }
1160
1161 static void
1162 _mdns_close(si_mod_t *si)
1163 {
1164 if (_dns_config_token != -1) notify_cancel(_dns_config_token);
1165 //_mdns_dir_token;
1166 }
1167
1168 static void
1169 _mdns_atfork_prepare(void)
1170 {
1171 // acquire our lock so that we know all other threads have "drained"
1172 pthread_mutex_lock(&_mdns_mutex);
1173 }
1174
1175 static void
1176 _mdns_atfork_parent(void)
1177 {
1178 // parent can simply resume
1179 pthread_mutex_unlock(&_mdns_mutex);
1180 }
1181
1182 static void
1183 _mdns_atfork_child(void)
1184 {
1185 // child needs to force re-initialization
1186 _mdns_old_sdref = _mdns_sdref; // for later deallocation
1187 _mdns_sdref = NULL;
1188 _dns_config_token = -1;
1189 pthread_mutex_unlock(&_mdns_mutex);
1190 }
1191
1192 __private_extern__ si_mod_t *
1193 si_module_static_mdns(void)
1194 {
1195 si_mod_t *out = (si_mod_t *)calloc(1, sizeof(si_mod_t));
1196 char *outname = strdup("mdns");
1197
1198 if ((out == NULL) || (outname == NULL))
1199 {
1200 free(out);
1201 free(outname);
1202 return NULL;
1203 }
1204
1205 out->name = outname;
1206 out->vers = 1;
1207 out->refcount = 1;
1208 out->private = NULL;
1209
1210 out->sim_close = _mdns_close;
1211 out->sim_is_valid = _mdns_is_valid;
1212 out->sim_host_byname = _mdns_hostbyname;
1213 out->sim_host_byaddr = _mdns_hostbyaddr;
1214 out->sim_item_call = _mdns_item_call;
1215 out->sim_addrinfo = _mdns_addrinfo;
1216 out->sim_srv_byname = _mdns_srv_byname;
1217
1218 int res;
1219
1220 res = notify_register_check(dns_configuration_notify_key(), &_dns_config_token);
1221 if (res != NOTIFY_STATUS_OK) _dns_config_token = -1;
1222
1223 pthread_atfork(_mdns_atfork_prepare, _mdns_atfork_parent, _mdns_atfork_child);
1224
1225 _mdns_debug = getenv("RES_DEBUG") != NULL;
1226
1227 return out;
1228 }
1229
1230 /*
1231 * _mdns_parse_domain_name
1232 * Combine DNS labels to form a string.
1233 * DNSService API does not return compressed names.
1234 */
1235 static char *
1236 _mdns_parse_domain_name(const uint8_t *data, uint32_t datalen)
1237 {
1238 int i = 0, j = 0;
1239 uint32_t len;
1240 uint32_t domainlen = 0;
1241 char *domain = NULL;
1242
1243 // i: index into input data
1244 // j: index into output string
1245 while (datalen-- > 0) {
1246 len = data[i++];
1247 domainlen += (len + 1);
1248 domain = reallocf(domain, domainlen);
1249 if (domain == NULL) return NULL;
1250 if (len == 0) break; // DNS root (NUL)
1251 if (j > 0) {
1252 domain[j++] = datalen ? '.' : '\0';
1253 }
1254
1255 while ((len-- > 0) && (datalen--)) {
1256 if (data[i] == '.') {
1257 // special case: escape the '.' with a '\'
1258 domain = reallocf(domain, ++domainlen);
1259 if (domain == NULL) return NULL;
1260 domain[j++] = '\\';
1261 }
1262 domain[j++] = data[i++];
1263 }
1264 }
1265 domain[j] = '\0';
1266
1267 return domain;
1268 }
1269
1270 /*
1271 * _mdns_pack_domain_name
1272 * Format the string as packed DNS labels.
1273 * Only used for one string at a time, therefore no need for compression.
1274 */
1275 static int
1276 _mdns_pack_domain_name(const char* str, uint8_t *buf, size_t buflen) {
1277 int i = 0;
1278 while (i < buflen) {
1279 uintptr_t len;
1280 // calculate length to next '.' or '\0'
1281 char *dot = strchr(str, '.');
1282 if (dot == NULL) dot = strchr(str, '\0');
1283 len = (dot - str);
1284 if (len > NS_MAXLABEL) return -1;
1285 // copy data for label
1286 buf[i++] = len;
1287 while (str < dot) {
1288 buf[i++] = *str++;
1289 }
1290 // skip past '.', break if '\0'
1291 if (*str++ == '\0') break;
1292 }
1293 if (i >= buflen) return -1;
1294 buf[i] = '\0';
1295 return i;
1296 }
1297
1298 static int
1299 _is_rev_link_local(const char *name)
1300 {
1301 int len, i;
1302
1303 if (name == NULL) return 0;
1304
1305 len = strlen(name);
1306 if (len == 0) return 0;
1307
1308 /* check for trailing '.' */
1309 if (name[len - 1] == '.') len--;
1310
1311 if (len != IPv6_REVERSE_LEN) return 0;
1312
1313 i = IPv6_REVERSE_LINK_LOCAL_TRAILING_CHAR;
1314 if ((name[i] != '8') && (name[i] != '9') && (name[i] != 'A') && (name[i] != 'a') && (name[i] != 'B') && (name[i] != 'b')) return 0;
1315
1316 i = IPv6_REVERSE_LINK_LOCAL_TRAILING_CHAR + 1;
1317 if (strncasecmp(name + i, ".e.f.ip6.arpa", 13)) return 0;
1318
1319 for (i = 0; i < IPv6_REVERSE_LINK_LOCAL_TRAILING_CHAR; i += 2)
1320 {
1321 if (name[i] < '0') return 0;
1322 if ((name[i] > '9') && (name[i] < 'A')) return 0;
1323 if ((name[i] > 'F') && (name[i] < 'a')) return 0;
1324 if (name[i] > 'f') return 0;
1325 if (name[i + 1] != '.') return 0;
1326 }
1327
1328 return 1;
1329 }
1330
1331 /* _mdns_ipv6_extract_scope_id
1332 * If the input string is a link local IPv6 address with an encoded scope id,
1333 * the scope id is extracted and a new string is constructed with the scope id removed.
1334 */
1335 static char *
1336 _mdns_ipv6_extract_scope_id(const char *name, uint32_t *out_ifnum)
1337 {
1338 char *qname = NULL;
1339 uint16_t nibble;
1340 uint32_t iface;
1341 int i;
1342
1343 if (out_ifnum != NULL) *out_ifnum = 0;
1344
1345 /* examine the address, extract the scope id if present */
1346 if ((name != NULL) && (_is_rev_link_local(name)))
1347 {
1348 /* _is_rev_link_local rejects chars > 127 so it's safe to index into hexval */
1349 i = IPv6_REVERSE_LINK_LOCAL_SCOPE_ID_LOW;
1350 nibble = hexval[(uint32_t)name[i]];
1351 iface = nibble;
1352
1353 i += 2;
1354 nibble = hexval[(uint32_t)name[i]];
1355 iface += (nibble << 4);
1356
1357 i += 2;
1358 nibble = hexval[(uint32_t)name[i]];
1359 iface += (nibble << 8);
1360
1361 i += 2;
1362 nibble = hexval[(uint32_t)name[i]];
1363 iface += (nibble << 12);
1364
1365 if (iface != 0)
1366 {
1367 qname = strdup(name);
1368 if (qname == NULL) return NULL;
1369
1370 i = IPv6_REVERSE_LINK_LOCAL_SCOPE_ID_LOW;
1371 qname[i] = '0';
1372 qname[i + 2] = '0';
1373 qname[i + 4] = '0';
1374 qname[i + 6] = '0';
1375
1376 if (out_ifnum) *out_ifnum = iface;
1377 }
1378 }
1379
1380 return qname;
1381 }
1382
1383 static int
1384 _mdns_make_query(const char* name, int class, int type, uint8_t *buf, uint32_t buflen)
1385 {
1386 uint32_t len = 0;
1387
1388 if (buf == NULL || buflen < (NS_HFIXEDSZ + NS_QFIXEDSZ)) return -1;
1389 memset(buf, 0, NS_HFIXEDSZ);
1390 HEADER *hp = (HEADER *)buf;
1391
1392 len += NS_HFIXEDSZ;
1393 hp->id = arc4random();
1394 hp->qr = 1;
1395 hp->opcode = ns_o_query;
1396 hp->rd = 1;
1397 hp->rcode = ns_r_noerror;
1398 hp->qdcount = htons(1);
1399
1400 int n = _mdns_pack_domain_name(name, &buf[len], buflen - len);
1401 if (n < 0) return -1;
1402
1403 len += n;
1404 uint16_t word;
1405 word = htons(type);
1406 memcpy(&buf[len], &word, sizeof(word));
1407 len += sizeof(word);
1408 word = htons(class);
1409 memcpy(&buf[len], &word, sizeof(word));
1410 len += sizeof(word);
1411 return len;
1412 }
1413
1414 typedef struct {
1415 mdns_reply_t *reply;
1416 mdns_hostent_t *host;
1417 uint8_t *answer; // DNS packet buffer
1418 size_t anslen; // DNS packet buffer current length
1419 size_t ansmaxlen; // DNS packet buffer maximum length
1420 int type; // type of query: A, AAAA, PTR, SRV...
1421 uint16_t last_type; // last type received
1422 DNSServiceRef sd;
1423 DNSServiceFlags flags;
1424 DNSServiceErrorType error;
1425 int kq; // kqueue to notify when callback received
1426 } mdns_query_context_t;
1427
1428 static void
1429 _mdns_query_callback(DNSServiceRef, DNSServiceFlags, uint32_t, DNSServiceErrorType, const char *, uint16_t, uint16_t, uint16_t, const void *, uint32_t, void *);
1430
1431 /* _mdns_query_start
1432 * initializes the context and starts a DNS-SD query.
1433 */
1434 static DNSServiceErrorType
1435 _mdns_query_start(mdns_query_context_t *ctx, mdns_reply_t *reply, uint8_t *answer, uint32_t *anslen, const char* name, int class, int type, const char *interface, DNSServiceFlags flags, int kq)
1436 {
1437 DNSServiceErrorType status;
1438
1439 flags |= kDNSServiceFlagsShareConnection;
1440 flags |= kDNSServiceFlagsReturnIntermediates;
1441
1442 memset(ctx, 0, sizeof(mdns_query_context_t));
1443
1444 if (answer && anslen) {
1445 // build a dummy DNS header to return to the caller
1446 ctx->answer = answer;
1447 ctx->ansmaxlen = *anslen;
1448 ctx->anslen = _mdns_make_query(name, class, type, answer, ctx->ansmaxlen);
1449 if (ctx->anslen <= 0) return -1;
1450 }
1451
1452 ctx->type = type;
1453 ctx->sd = _mdns_sdref;
1454 ctx->kq = kq;
1455 if (reply) {
1456 ctx->reply = reply;
1457 if (type == ns_t_a) ctx->host = reply->h4;
1458 else if (type == ns_t_aaaa) ctx->host = reply->h6;
1459 else if (type == ns_t_ptr && reply->h4) ctx->host = reply->h4;
1460 else if (type == ns_t_ptr && reply->h6) ctx->host = reply->h6;
1461 else if (type != ns_t_srv && type != ns_t_cname) abort();
1462 }
1463
1464 uint32_t iface = 0;
1465 char *qname = _mdns_ipv6_extract_scope_id(name, &iface);
1466 if (qname == NULL) qname = (char *)name;
1467
1468 if (interface != NULL)
1469 {
1470 /* get interface number from name */
1471 int iface2 = if_nametoindex(interface);
1472
1473 /* balk if interface name lookup failed */
1474 if (iface2 == 0) return -1;
1475
1476 /* balk if scope id is set AND interface is given AND they don't match */
1477 if ((iface != 0) && (iface2 != 0) && (iface != iface2)) return -1;
1478 if (iface2 != 0) iface = iface2;
1479 }
1480
1481 if (_mdns_debug) printf(";; mdns query %s %d %d\n", qname, type, class);
1482 status = DNSServiceQueryRecord(&ctx->sd, flags, iface, qname, type, class, _mdns_query_callback, ctx);
1483 if (qname != name) free(qname);
1484 return status;
1485 }
1486
1487 /* _mdns_query_is_complete
1488 * Determines whether the specified query has sufficient information to be
1489 * considered complete.
1490 */
1491 static int
1492 _mdns_query_is_complete(mdns_query_context_t *ctx)
1493 {
1494 if (ctx == NULL) return 1;
1495 //if (ctx->flags & kDNSServiceFlagsMoreComing) return 0;
1496 if (ctx->last_type != ctx->type) return 0;
1497 switch (ctx->type) {
1498 case ns_t_a:
1499 case ns_t_aaaa:
1500 if (ctx->host != NULL && ctx->host->addr_count > 0) {
1501 return 1;
1502 }
1503 break;
1504 case ns_t_ptr:
1505 if (ctx->host != NULL && ctx->host->host.h_name != NULL) {
1506 return 1;
1507 }
1508 break;
1509 case ns_t_srv:
1510 if (ctx->reply != NULL && ctx->reply->srv != NULL) {
1511 return 1;
1512 }
1513 break;
1514 default:
1515 abort();
1516 }
1517 return 0;
1518 }
1519
1520 /* _mdns_query_clear
1521 * Clear out the temporary fields of the context, and clear any result
1522 * structures that are incomplete. Retrns 1 if the query was complete.
1523 */
1524 static int
1525 _mdns_query_clear(mdns_query_context_t *ctx)
1526 {
1527 int complete = _mdns_query_is_complete(ctx);
1528 if (ctx == NULL) return complete;
1529
1530 if (ctx->sd != NULL) {
1531 DNSServiceRefDeallocate(ctx->sd);
1532 ctx->sd = NULL;
1533 }
1534 ctx->flags = 0;
1535 ctx->kq = -1;
1536
1537 if (!complete) {
1538 _mdns_hostent_clear(ctx->host);
1539 ctx->anslen = -1;
1540 }
1541 return complete;
1542 }
1543
1544 static void
1545 _mdns_query_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode, const char *fullname, uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl, void *ctx)
1546 {
1547 mdns_query_context_t *context;
1548 struct in6_addr a6;
1549
1550 context = (mdns_query_context_t *)ctx;
1551
1552 context->flags = flags;
1553 context->error = errorCode;
1554 context->last_type = rrtype;
1555
1556 if (errorCode != kDNSServiceErr_NoError) {
1557 if (_mdns_debug) printf(";; [%s %hu %hu]: error %d\n", fullname, rrtype, rrclass, errorCode);
1558 goto wakeup_kevent;
1559 }
1560
1561 // embed the scope ID into link-local IPv6 addresses
1562 if (rrtype == ns_t_aaaa && rdlen == sizeof(struct in6_addr) &&
1563 IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)rdata)) {
1564 memcpy(&a6, rdata, rdlen);
1565 a6.__u6_addr.__u6_addr16[1] = htons(ifIndex);
1566 rdata = &a6;
1567 }
1568
1569 if (context->reply) {
1570 char *name;
1571 int malformed = 0;
1572 mdns_reply_t *reply = context->reply;
1573
1574 if (reply->ifnum == 0) {
1575 reply->ifnum = ifIndex;
1576 }
1577
1578 _mdns_hostent_append_alias(context->host, fullname);
1579 if (reply->ttl == 0 || ttl < reply->ttl) reply->ttl = ttl;
1580
1581 switch (rrtype) {
1582 case ns_t_a:
1583 case ns_t_aaaa:
1584 if (((rrtype == ns_t_a && context->host->host.h_addrtype == AF_INET) ||
1585 (rrtype == ns_t_aaaa && context->host->host.h_addrtype == AF_INET6)) &&
1586 rdlen >= context->host->host.h_length) {
1587 if (context->host->host.h_name == NULL) {
1588 int i;
1589 mdns_hostent_t *h = context->host;
1590 char *h_name = _mdns_canonicalize(fullname);
1591 context->host->host.h_name = h_name;
1592
1593 // 6863416 remove h_name from h_aliases
1594 for (i = 0; i < h->alias_count; ++i) {
1595 if (h_name == NULL) break;
1596 if (string_equal(h->host.h_aliases[i], h_name)) {
1597 // includes trailing NULL pointer
1598 int sz = sizeof(char *) * (h->alias_count - i);
1599 free(h->host.h_aliases[i]);
1600 memmove(&h->host.h_aliases[i], &h->host.h_aliases[i+1], sz);
1601 h->alias_count -= 1;
1602 break;
1603 }
1604 }
1605 }
1606 _mdns_hostent_append_addr(context->host, rdata, context->host->host.h_length);
1607 } else {
1608 malformed = 1;
1609 }
1610 break;
1611 case ns_t_cname:
1612 name = _mdns_parse_domain_name(rdata, rdlen);
1613 if (!name) malformed = 1;
1614 _mdns_hostent_append_alias(context->host, name);
1615 free(name);
1616 break;
1617 case ns_t_ptr:
1618 name = _mdns_parse_domain_name(rdata, rdlen);
1619 if (!name) malformed = 1;
1620 if (context->host && context->host->host.h_name == NULL) {
1621 context->host->host.h_name = _mdns_canonicalize(name);
1622 }
1623 _mdns_hostent_append_alias(context->host, name);
1624 free(name);
1625 break;
1626 case ns_t_srv: {
1627 mdns_rr_srv_t *p = (mdns_rr_srv_t*)rdata;
1628 mdns_srv_t *srv = calloc(1, sizeof(mdns_srv_t));
1629 if (srv == NULL) break;
1630 if (rdlen < sizeof(mdns_rr_srv_t)) {
1631 malformed = 1;
1632 break;
1633 }
1634 srv->srv.priority = ntohs(p->priority);
1635 srv->srv.weight = ntohs(p->weight);
1636 srv->srv.port = ntohs(p->port);
1637 srv->srv.target = _mdns_parse_domain_name(&p->target[0], rdlen - 3*sizeof(uint16_t));
1638 if (srv->srv.target == NULL) {
1639 malformed = 1;
1640 break;
1641 }
1642 // append to the end of the list
1643 if (reply->srv == NULL) {
1644 reply->srv = srv;
1645 } else {
1646 mdns_srv_t *iter = reply->srv;
1647 while (iter->next) iter = iter->next;
1648 iter->next = srv;
1649 }
1650 break;
1651 }
1652 default:
1653 malformed = _mdns_debug;
1654 break;
1655 }
1656 if (malformed && _mdns_debug) {
1657 printf(";; [%s %hu %hu]: malformed reply\n", fullname, rrtype, rrclass);
1658 goto wakeup_kevent;
1659 }
1660 }
1661
1662 if (context->answer) {
1663 int n;
1664 uint8_t *cp;
1665 HEADER *ans;
1666 size_t buflen = context->ansmaxlen - context->anslen;
1667 if (buflen < NS_HFIXEDSZ)
1668 {
1669 if (_mdns_debug) printf(";; [%s %hu %hu]: malformed reply\n", fullname, rrtype, rrclass);
1670 goto wakeup_kevent;
1671 }
1672
1673 cp = context->answer + context->anslen;
1674
1675 n = _mdns_pack_domain_name(fullname, cp, buflen);
1676 if (n < 0) {
1677 if (_mdns_debug) printf(";; [%s %hu %hu]: name mismatch\n", fullname, rrtype, rrclass);
1678 goto wakeup_kevent;
1679 }
1680
1681 // check that there is enough space in the buffer for the
1682 // resource name (n), the resource record data (rdlen) and
1683 // the resource record header (10).
1684 if (buflen < n + rdlen + 10) {
1685 if (_mdns_debug) printf(";; [%s %hu %hu]: insufficient buffer space for reply\n", fullname, rrtype, rrclass);
1686 goto wakeup_kevent;
1687 }
1688
1689 cp += n;
1690 buflen -= n;
1691
1692 uint16_t word;
1693 uint32_t longword;
1694
1695 word = htons(rrtype);
1696 memcpy(cp, &word, sizeof(word));
1697 cp += sizeof(word);
1698
1699 word = htons(rrclass);
1700 memcpy(cp, &word, sizeof(word));
1701 cp += sizeof(word);
1702
1703 longword = htonl(ttl);
1704 memcpy(cp, &longword, sizeof(longword));
1705 cp += sizeof(longword);
1706
1707 word = htons(rdlen);
1708 memcpy(cp, &word, sizeof(word));
1709 cp += sizeof(word);
1710
1711 memcpy(cp, rdata, rdlen);
1712 cp += rdlen;
1713
1714 ans = (HEADER *)context->answer;
1715 ans->ancount = htons(ntohs(ans->ancount) + 1);
1716
1717 context->anslen = (size_t)(cp - context->answer);
1718 }
1719
1720 if (_mdns_debug) printf(";; [%s %hu %hu]\n", fullname, rrtype, rrclass);
1721
1722 wakeup_kevent:
1723 // Ping the waiting thread in case this callback was invoked on another
1724 if (context->kq != -1) {
1725 struct kevent ev;
1726 EV_SET(&ev, 1, EVFILT_USER, 0, NOTE_TRIGGER, 0, 0);
1727 int res = kevent(context->kq, &ev, 1, NULL, 0, NULL);
1728 if (res && _mdns_debug) printf(";; kevent EV_TRIGGER: %s\n", strerror(errno));
1729 }
1730 }
1731
1732 static void
1733 _mdns_now(struct timespec *now) {
1734 struct timeval tv;
1735 gettimeofday(&tv, NULL);
1736 now->tv_sec = tv.tv_sec;
1737 now->tv_nsec = tv.tv_usec * 1000;
1738 }
1739
1740 static void
1741 _mdns_add_time(struct timespec *sum, const struct timespec *a, const struct timespec *b)
1742 {
1743 sum->tv_sec = a->tv_sec + b->tv_sec;
1744 sum->tv_nsec = a->tv_nsec + b->tv_nsec;
1745 if (sum->tv_nsec > 1000000000) {
1746 sum->tv_sec += (sum->tv_nsec / 1000000000);
1747 sum->tv_nsec %= 1000000000;
1748 }
1749 }
1750
1751 // calculate a deadline from the current time based on the desired timeout
1752 static void
1753 _mdns_deadline(struct timespec *deadline, const struct timespec *delta)
1754 {
1755 struct timespec now;
1756 _mdns_now(&now);
1757 _mdns_add_time(deadline, &now, delta);
1758 }
1759
1760 static void
1761 _mdns_sub_time(struct timespec *delta, const struct timespec *a, const struct timespec *b)
1762 {
1763 delta->tv_sec = a->tv_sec - b->tv_sec;
1764 delta->tv_nsec = a->tv_nsec - b->tv_nsec;
1765 if (delta->tv_nsec < 0) {
1766 delta->tv_nsec += 1000000000;
1767 delta->tv_sec -= 1;
1768 }
1769 }
1770
1771 // calculate a timeout remaining before the given deadline
1772 static void
1773 _mdns_timeout(struct timespec *timeout, const struct timespec *deadline)
1774 {
1775 struct timespec now;
1776 _mdns_now(&now);
1777 _mdns_sub_time(timeout, deadline, &now);
1778 }
1779
1780 int
1781 _mdns_query_mDNSResponder(const char *name, int class, int type, const char *interface, DNSServiceFlags flags, uint8_t *answer, uint32_t *anslen, mdns_reply_t *reply, uint32_t timeout_sec)
1782 {
1783 DNSServiceErrorType err = 0;
1784 int kq, n, wait = 1;
1785 struct kevent ev;
1786 struct timespec start, finish, delta, timeout;
1787 int res = 0;
1788 int i, complete, got_response = 0;
1789 int initialize = 1;
1790
1791 // 2 for A and AAAA parallel queries
1792 int n_ctx = 0;
1793 mdns_query_context_t ctx[2];
1794
1795 if (name == NULL) return -1;
1796
1797 #if TARGET_OS_EMBEDDED
1798 // log a warning for queries from the main thread
1799 if (pthread_main_np()) asl_log(NULL, NULL, ASL_LEVEL_WARNING, "Warning: Libinfo call to mDNSResponder on main thread");
1800 #endif // TARGET_OS_EMBEDDED
1801
1802 // Timeout Logic
1803 // The kevent(2) API timeout parameter is used to enforce the total
1804 // timeout of the DNS query. Each iteraion recalculates the relative
1805 // timeout based on the desired end time (total timeout from origin).
1806 //
1807 // In order to workaround some DNS configurations that do not return
1808 // responses for AAAA queries, parallel queries modify the total
1809 // timeout upon receipt of the first response. The new total timeout is
1810 // set to an effective value of 2N where N is the time taken to receive
1811 // the A response (the original total timeout is preserved if 2N would
1812 // have exceeded it). However, since mDNSResponder caches values, a
1813 // minimum value of 50ms for N is enforced in order to give some time
1814 // for the receipt of a AAAA response.
1815
1816 // determine the maximum time to wait for a result
1817 if (timeout_sec == 0) timeout_sec = RES_MAXRETRANS;
1818 delta.tv_sec = timeout_sec;
1819 delta.tv_nsec = 0;
1820 _mdns_deadline(&finish, &delta);
1821 timeout = delta;
1822 _mdns_now(&start);
1823
1824 // set up the kqueue
1825 kq = kqueue();
1826 EV_SET(&ev, 1, EVFILT_USER, EV_ADD | EV_CLEAR, 0, 0, 0);
1827 n = kevent(kq, &ev, 1, NULL, 0, NULL);
1828 if (n != 0) wait = 0;
1829
1830 while (wait == 1) {
1831 if (initialize) {
1832 initialize = 0;
1833 pthread_mutex_lock(&_mdns_mutex);
1834 // clear any stale contexts
1835 for (i = 0; i < n_ctx; ++i) {
1836 _mdns_query_clear(&ctx[i]);
1837 }
1838 n_ctx = 0;
1839
1840 if (_mdns_sdref == NULL) {
1841 if (_mdns_old_sdref != NULL) {
1842 DNSServiceRefDeallocate(_mdns_old_sdref);
1843 _mdns_old_sdref = NULL;
1844 }
1845 // (re)initialize the shared connection
1846 err = DNSServiceCreateConnection(&_mdns_sdref);
1847 if (err != 0) {
1848 wait = 0;
1849 pthread_mutex_unlock(&_mdns_mutex);
1850 break;
1851 }
1852 }
1853
1854 // issue (or reissue) the queries
1855 // unspecified type: do parallel A and AAAA
1856 if (err == 0) {
1857 err = _mdns_query_start(&ctx[n_ctx++], reply,
1858 answer, anslen,
1859 name, class,
1860 (type == 0) ? ns_t_a : type, interface, flags, kq);
1861 }
1862 if (err == 0 && type == 0) {
1863 err = _mdns_query_start(&ctx[n_ctx++], reply,
1864 answer, anslen,
1865 name, class, ns_t_aaaa, interface, flags, kq);
1866 }
1867 if (err && _mdns_debug) printf(";; initialization error %d\n", err);
1868 // try to reinitialize
1869 if (err == kDNSServiceErr_Unknown ||
1870 err == kDNSServiceErr_ServiceNotRunning ||
1871 err == kDNSServiceErr_BadReference) {
1872 if (_mdns_sdref) {
1873 DNSServiceRefDeallocate(_mdns_sdref);
1874 _mdns_sdref = NULL;
1875 }
1876 err = 0;
1877 initialize = 1;
1878 pthread_mutex_unlock(&_mdns_mutex);
1879 continue;
1880 } else if (err != 0) {
1881 pthread_mutex_unlock(&_mdns_mutex);
1882 break;
1883 }
1884
1885 // (re)register the fd with kqueue
1886 int fd = DNSServiceRefSockFD(_mdns_sdref);
1887 EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
1888 n = kevent(kq, &ev, 1, NULL, 0, NULL);
1889 pthread_mutex_unlock(&_mdns_mutex);
1890 if (err != 0 || n != 0) break;
1891 }
1892
1893 if (_mdns_debug) printf(";; kevent timeout %ld.%ld\n", timeout.tv_sec, timeout.tv_nsec);
1894 n = kevent(kq, NULL, 0, &ev, 1, &timeout);
1895 if (n < 0 && errno != EINTR) {
1896 res = -1;
1897 break;
1898 }
1899
1900 pthread_mutex_lock(&_mdns_mutex);
1901 // DNSServiceProcessResult() is a blocking API
1902 // confirm that there is still data on the socket
1903 const struct timespec notimeout = { 0, 0 };
1904 int m = kevent(kq, NULL, 0, &ev, 1, &notimeout);
1905 if (_mdns_sdref == NULL) {
1906 initialize = 1;
1907 } else if (m > 0 && ev.filter == EVFILT_READ) {
1908 err = DNSServiceProcessResult(_mdns_sdref);
1909 if (err == kDNSServiceErr_ServiceNotRunning ||
1910 err == kDNSServiceErr_BadReference) {
1911 if (_mdns_debug) printf(";; DNSServiceProcessResult status %d\n", err);
1912 err = 0;
1913 // re-initialize the shared connection
1914 DNSServiceRefDeallocate(_mdns_sdref);
1915 _mdns_sdref = NULL;
1916 initialize = 1;
1917 }
1918 }
1919
1920 // Check if all queries are complete (including errors)
1921 complete = 1;
1922 for (i = 0; i < n_ctx; ++i) {
1923 if (_mdns_query_is_complete(&ctx[i]) || ctx[i].error != 0) {
1924 if (ctx[i].type == ns_t_a) {
1925 got_response = 1;
1926 }
1927 } else {
1928 complete = 0;
1929 }
1930 }
1931 pthread_mutex_unlock(&_mdns_mutex);
1932
1933 if (err != 0) {
1934 if (_mdns_debug) printf(";; DNSServiceProcessResult status %d\n", err);
1935 break;
1936 } else if (complete == 1) {
1937 if (_mdns_debug) printf(";; done\n");
1938 break;
1939 } else if (got_response == 1) {
1940 // got A, adjust deadline for AAAA
1941 struct timespec now, tn, ms100;
1942
1943 // delta = now - start
1944 _mdns_now(&now);
1945 _mdns_sub_time(&delta, &now, &start);
1946
1947 // tn = 2 * delta
1948 _mdns_add_time(&tn, &delta, &delta);
1949
1950 // delta = tn + 100ms
1951 ms100.tv_sec = 0;
1952 ms100.tv_nsec = 100000000;
1953 _mdns_add_time(&delta, &tn, &ms100);
1954
1955 // check that delta doesn't exceed our total timeout
1956 _mdns_sub_time(&tn, &timeout, &delta);
1957 if (tn.tv_sec >= 0) {
1958 if (_mdns_debug) printf(";; new timeout (waiting for AAAA) %ld.%ld\n", delta.tv_sec, delta.tv_nsec);
1959 _mdns_deadline(&finish, &delta);
1960 }
1961 }
1962
1963 // calculate remaining timeout
1964 _mdns_timeout(&timeout, &finish);
1965
1966 // check for time remaining
1967 if (timeout.tv_sec < 0) {
1968 if (_mdns_debug) printf(";; timeout\n");
1969 break;
1970 }
1971 }
1972
1973 complete = 0;
1974 pthread_mutex_lock(&_mdns_mutex);
1975 for (i = 0; i < n_ctx; ++i) {
1976 if (err == 0) err = ctx[i].error;
1977 // Only clears hostents if result is incomplete.
1978 complete = _mdns_query_clear(&ctx[i]) || complete;
1979 }
1980 pthread_mutex_unlock(&_mdns_mutex);
1981 // Everything should be done with the kq by now.
1982 close(kq);
1983
1984 // Return error if everything is incomplete
1985 if (complete == 0) {
1986 res = -1;
1987 }
1988
1989 if (anslen) *anslen = ctx[0].anslen;
1990 return res;
1991 }