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