Libinfo-330.3.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 static si_list_t *
965 _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)
966 {
967 int wantv4 = 1;
968 int wantv6 = 1;
969 if (family == AF_INET6) wantv4 = 0;
970 else if (family == AF_INET) wantv6 = 0;
971 else if (family != AF_UNSPEC) return NULL;
972
973 struct in_addr a4;
974 struct in6_addr a6;
975 mdns_hostent_t h4;
976 mdns_hostent_t h6;
977 mdns_reply_t reply;
978 uint32_t type;
979 uint16_t port;
980
981 if (err != NULL) *err = SI_STATUS_NO_ERROR;
982
983 si_list_t *out = NULL;
984
985 memset(&h4, 0, sizeof(h4));
986 memset(&h6, 0, sizeof(h6));
987 memset(&reply, 0, sizeof(reply));
988
989 h4.host.h_addrtype = AF_INET;
990 h4.host.h_length = 4;
991 h6.host.h_addrtype = AF_INET6;
992 h6.host.h_length = 16;
993
994 if (wantv4 && wantv6) {
995 type = 0;
996 reply.h4 = &h4;
997 reply.h6 = &h6;
998 } else if (wantv4) {
999 reply.h4 = &h4;
1000 type = ns_t_a;
1001 } else if (wantv6) {
1002 type = ns_t_aaaa;
1003 reply.h6 = &h6;
1004 } else {
1005 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1006 return NULL;
1007 }
1008
1009 // service lookup
1010 if ((flags & AI_NUMERICSERV) != 0) {
1011 port = *(uint16_t *)serv;
1012 } else {
1013 if (_gai_serv_to_port(serv, proto, &port) != 0) {
1014 if (err) *err = SI_STATUS_EAI_NONAME;
1015 return NULL;
1016 }
1017 }
1018
1019 // host lookup
1020 if ((flags & AI_NUMERICHOST) != 0) {
1021 char *cname = NULL;
1022 struct in_addr *p4 = NULL;
1023 struct in6_addr *p6 = NULL;
1024 if (family == AF_INET) {
1025 p4 = &a4;
1026 memcpy(p4, node, sizeof(a4));
1027 } else if (family == AF_INET6) {
1028 p6 = &a6;
1029 memcpy(p6, node, sizeof(a6));
1030 }
1031 out = si_addrinfo_list(si, socktype, proto, p4, p6, port, 0, cname, cname);
1032 } else {
1033 int res;
1034 res = _mdns_search(node, ns_c_in, type, interface, 0, 1, NULL, NULL, &reply);
1035 if (res == 0 && (h4.addr_count > 0 || h6.addr_count > 0)) {
1036 out = si_addrinfo_list_from_hostent(si, socktype, proto,
1037 port, 0,
1038 (wantv4 ? &h4.host : NULL),
1039 (wantv6 ? &h6.host : NULL));
1040 } else if (err != NULL) {
1041 *err = SI_STATUS_EAI_NONAME;
1042 }
1043 _mdns_reply_clear(&reply);
1044 }
1045 return out;
1046 }
1047
1048 static si_list_t *
1049 _mdns_srv_byname(si_mod_t* si, const char *qname, const char *interface, uint32_t *err)
1050 {
1051 si_list_t *out = NULL;
1052 mdns_reply_t reply;
1053 mdns_srv_t *srv;
1054 int res;
1055 const uint64_t unused = 0;
1056
1057 if (err != NULL) *err = SI_STATUS_NO_ERROR;
1058
1059 memset(&reply, 0, sizeof(reply));
1060 res = _mdns_search(qname, ns_c_in, ns_t_srv, interface, 0, 1, NULL, NULL, &reply);
1061 if (res == 0) {
1062 srv = reply.srv;
1063 while (srv) {
1064 si_item_t *item;
1065 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);
1066 out = si_list_add(out, item);
1067 si_item_release(item);
1068 srv = srv->next;
1069 }
1070 }
1071 _mdns_reply_clear(&reply);
1072 return out;
1073 }
1074
1075 /*
1076 * We support dns_async_start / cancel / handle_reply using dns_item_call
1077 */
1078 static si_item_t *
1079 _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)
1080 {
1081 int res;
1082 uint8_t buf[DNS_MAX_RECEIVE_SIZE];
1083 uint32_t len = sizeof(buf);
1084 mdns_reply_t reply;
1085 mdns_hostent_t h4;
1086 mdns_hostent_t h6;
1087 si_item_t *out;
1088 int norecurse = 0;
1089
1090 if (err != NULL) *err = SI_STATUS_NO_ERROR;
1091
1092 switch (call) {
1093 case SI_CALL_DNS_QUERY:
1094 norecurse = 1;
1095 break;
1096 case SI_CALL_DNS_SEARCH:
1097 break;
1098 default:
1099 if (err) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1100 return NULL;
1101 break;
1102 }
1103
1104 if (name == NULL) {
1105 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1106 return NULL;
1107 }
1108
1109 memset(&h4, 0, sizeof(h4));
1110 memset(&h6, 0, sizeof(h6));
1111 memset(&reply, 0, sizeof(reply));
1112
1113 h4.host.h_addrtype = AF_INET;
1114 h4.host.h_length = 4;
1115 h6.host.h_addrtype = AF_INET6;
1116 h6.host.h_length = 16;
1117 reply.h4 = &h4;
1118 reply.h6 = &h6;
1119
1120 res = _mdns_search(name, class, type, interface, norecurse, 1, buf, &len, &reply);
1121 if (res != 0 || len <= 0 || len > DNS_MAX_RECEIVE_SIZE) {
1122 _mdns_reply_clear(&reply);
1123 if (err != NULL) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND;
1124 return NULL;
1125 }
1126
1127 struct sockaddr_in6 from;
1128 uint32_t fromlen = sizeof(from);
1129 memset(&from, 0, fromlen);
1130 from.sin6_len = fromlen;
1131 from.sin6_family = AF_INET6;
1132 from.sin6_addr.__u6_addr.__u6_addr8[15] = 1;
1133 if (reply.ifnum != 0) {
1134 from.sin6_addr.__u6_addr.__u6_addr16[0] = htons(0xfe80);
1135 from.sin6_scope_id = reply.ifnum;
1136 }
1137
1138 out = (si_item_t *)LI_ils_create("L4488@@", (unsigned long)si, CATEGORY_DNSPACKET, 1, 0LL, 0LL, len, buf, fromlen, &from);
1139 if (out == NULL && err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
1140
1141 _mdns_reply_clear(&reply);
1142
1143 return out;
1144 }
1145
1146 static int
1147 _mdns_is_valid(si_mod_t *si, si_item_t *item)
1148 {
1149 return 0;
1150 }
1151
1152 static void
1153 _mdns_close(si_mod_t *si)
1154 {
1155 if (_dns_config_token != -1) notify_cancel(_dns_config_token);
1156 //_mdns_dir_token;
1157 }
1158
1159 static void
1160 _mdns_atfork_prepare(void)
1161 {
1162 // acquire our lock so that we know all other threads have "drained"
1163 pthread_mutex_lock(&_mdns_mutex);
1164 }
1165
1166 static void
1167 _mdns_atfork_parent(void)
1168 {
1169 // parent can simply resume
1170 pthread_mutex_unlock(&_mdns_mutex);
1171 }
1172
1173 static void
1174 _mdns_atfork_child(void)
1175 {
1176 // child needs to force re-initialization
1177 _mdns_old_sdref = _mdns_sdref; // for later deallocation
1178 _mdns_sdref = NULL;
1179 _dns_config_token = -1;
1180 pthread_mutex_unlock(&_mdns_mutex);
1181 }
1182
1183 __private_extern__ si_mod_t *
1184 si_module_static_mdns(void)
1185 {
1186 si_mod_t *out = (si_mod_t *)calloc(1, sizeof(si_mod_t));
1187 char *outname = strdup("mdns");
1188
1189 if ((out == NULL) || (outname == NULL))
1190 {
1191 free(out);
1192 free(outname);
1193 return NULL;
1194 }
1195
1196 out->name = outname;
1197 out->vers = 1;
1198 out->refcount = 1;
1199 out->private = NULL;
1200
1201 out->sim_close = _mdns_close;
1202 out->sim_is_valid = _mdns_is_valid;
1203 out->sim_host_byname = _mdns_hostbyname;
1204 out->sim_host_byaddr = _mdns_hostbyaddr;
1205 out->sim_item_call = _mdns_item_call;
1206 out->sim_addrinfo = _mdns_addrinfo;
1207 out->sim_srv_byname = _mdns_srv_byname;
1208
1209 int res;
1210
1211 res = notify_register_check(dns_configuration_notify_key(), &_dns_config_token);
1212 if (res != NOTIFY_STATUS_OK) _dns_config_token = -1;
1213
1214 pthread_atfork(_mdns_atfork_prepare, _mdns_atfork_parent, _mdns_atfork_child);
1215
1216 _mdns_debug = getenv("RES_DEBUG") != NULL;
1217
1218 return out;
1219 }
1220
1221 /*
1222 * _mdns_parse_domain_name
1223 * Combine DNS labels to form a string.
1224 * DNSService API does not return compressed names.
1225 */
1226 static char *
1227 _mdns_parse_domain_name(const uint8_t *data, uint32_t datalen)
1228 {
1229 int i = 0, j = 0;
1230 uint32_t len;
1231 uint32_t domainlen = 0;
1232 char *domain = NULL;
1233
1234 // i: index into input data
1235 // j: index into output string
1236 while (datalen-- > 0) {
1237 len = data[i++];
1238 domainlen += (len + 1);
1239 domain = reallocf(domain, domainlen);
1240 if (domain == NULL) return NULL;
1241 if (len == 0) break; // DNS root (NUL)
1242 if (j > 0) {
1243 domain[j++] = datalen ? '.' : '\0';
1244 }
1245
1246 while ((len-- > 0) && (datalen--)) {
1247 if (data[i] == '.') {
1248 // special case: escape the '.' with a '\'
1249 domain = reallocf(domain, ++domainlen);
1250 if (domain == NULL) return NULL;
1251 domain[j++] = '\\';
1252 }
1253 domain[j++] = data[i++];
1254 }
1255 }
1256 domain[j] = '\0';
1257
1258 return domain;
1259 }
1260
1261 /*
1262 * _mdns_pack_domain_name
1263 * Format the string as packed DNS labels.
1264 * Only used for one string at a time, therefore no need for compression.
1265 */
1266 static int
1267 _mdns_pack_domain_name(const char* str, uint8_t *buf, size_t buflen) {
1268 int i = 0;
1269 while (i < buflen) {
1270 uintptr_t len;
1271 // calculate length to next '.' or '\0'
1272 char *dot = strchr(str, '.');
1273 if (dot == NULL) dot = strchr(str, '\0');
1274 len = (dot - str);
1275 if (len > NS_MAXLABEL) return -1;
1276 // copy data for label
1277 buf[i++] = len;
1278 while (str < dot) {
1279 buf[i++] = *str++;
1280 }
1281 // skip past '.', break if '\0'
1282 if (*str++ == '\0') break;
1283 }
1284 if (i >= buflen) return -1;
1285 buf[i] = '\0';
1286 return i;
1287 }
1288
1289 static int
1290 _is_rev_link_local(const char *name)
1291 {
1292 int len, i;
1293
1294 if (name == NULL) return 0;
1295
1296 len = strlen(name);
1297 if (len == 0) return 0;
1298
1299 /* check for trailing '.' */
1300 if (name[len - 1] == '.') len--;
1301
1302 if (len != IPv6_REVERSE_LEN) return 0;
1303
1304 i = IPv6_REVERSE_LINK_LOCAL_TRAILING_CHAR;
1305 if ((name[i] != '8') && (name[i] != '9') && (name[i] != 'A') && (name[i] != 'a') && (name[i] != 'B') && (name[i] != 'b')) return 0;
1306
1307 i = IPv6_REVERSE_LINK_LOCAL_TRAILING_CHAR + 1;
1308 if (strncasecmp(name + i, ".e.f.ip6.arpa", 13)) return 0;
1309
1310 for (i = 0; i < IPv6_REVERSE_LINK_LOCAL_TRAILING_CHAR; i += 2)
1311 {
1312 if (name[i] < '0') return 0;
1313 if ((name[i] > '9') && (name[i] < 'A')) return 0;
1314 if ((name[i] > 'F') && (name[i] < 'a')) return 0;
1315 if (name[i] > 'f') return 0;
1316 if (name[i + 1] != '.') return 0;
1317 }
1318
1319 return 1;
1320 }
1321
1322 /* _mdns_ipv6_extract_scope_id
1323 * If the input string is a link local IPv6 address with an encoded scope id,
1324 * the scope id is extracted and a new string is constructed with the scope id removed.
1325 */
1326 static char *
1327 _mdns_ipv6_extract_scope_id(const char *name, uint32_t *out_ifnum)
1328 {
1329 char *qname = NULL;
1330 uint16_t nibble;
1331 uint32_t iface;
1332 int i;
1333
1334 if (out_ifnum != NULL) *out_ifnum = 0;
1335
1336 /* examine the address, extract the scope id if present */
1337 if ((name != NULL) && (_is_rev_link_local(name)))
1338 {
1339 /* _is_rev_link_local rejects chars > 127 so it's safe to index into hexval */
1340 i = IPv6_REVERSE_LINK_LOCAL_SCOPE_ID_LOW;
1341 nibble = hexval[(uint32_t)name[i]];
1342 iface = nibble;
1343
1344 i += 2;
1345 nibble = hexval[(uint32_t)name[i]];
1346 iface += (nibble << 4);
1347
1348 i += 2;
1349 nibble = hexval[(uint32_t)name[i]];
1350 iface += (nibble << 8);
1351
1352 i += 2;
1353 nibble = hexval[(uint32_t)name[i]];
1354 iface += (nibble << 12);
1355
1356 if (iface != 0)
1357 {
1358 qname = strdup(name);
1359 if (qname == NULL) return NULL;
1360
1361 i = IPv6_REVERSE_LINK_LOCAL_SCOPE_ID_LOW;
1362 qname[i] = '0';
1363 qname[i + 2] = '0';
1364 qname[i + 4] = '0';
1365 qname[i + 6] = '0';
1366
1367 if (out_ifnum) *out_ifnum = iface;
1368 }
1369 }
1370
1371 return qname;
1372 }
1373
1374 static int
1375 _mdns_make_query(const char* name, int class, int type, uint8_t *buf, uint32_t buflen)
1376 {
1377 uint32_t len = 0;
1378
1379 if (buf == NULL || buflen < (NS_HFIXEDSZ + NS_QFIXEDSZ)) return -1;
1380 memset(buf, 0, NS_HFIXEDSZ);
1381 HEADER *hp = (HEADER *)buf;
1382
1383 len += NS_HFIXEDSZ;
1384 hp->id = arc4random();
1385 hp->qr = 1;
1386 hp->opcode = ns_o_query;
1387 hp->rd = 1;
1388 hp->rcode = ns_r_noerror;
1389 hp->qdcount = htons(1);
1390
1391 int n = _mdns_pack_domain_name(name, &buf[len], buflen - len);
1392 if (n < 0) return -1;
1393
1394 len += n;
1395 uint16_t word;
1396 word = htons(type);
1397 memcpy(&buf[len], &word, sizeof(word));
1398 len += sizeof(word);
1399 word = htons(class);
1400 memcpy(&buf[len], &word, sizeof(word));
1401 len += sizeof(word);
1402 return len;
1403 }
1404
1405 typedef struct {
1406 mdns_reply_t *reply;
1407 mdns_hostent_t *host;
1408 uint8_t *answer; // DNS packet buffer
1409 size_t anslen; // DNS packet buffer current length
1410 size_t ansmaxlen; // DNS packet buffer maximum length
1411 int type; // type of query: A, AAAA, PTR, SRV...
1412 uint16_t last_type; // last type received
1413 DNSServiceRef sd;
1414 DNSServiceFlags flags;
1415 DNSServiceErrorType error;
1416 int kq; // kqueue to notify when callback received
1417 } mdns_query_context_t;
1418
1419 static void
1420 _mdns_query_callback(DNSServiceRef, DNSServiceFlags, uint32_t, DNSServiceErrorType, const char *, uint16_t, uint16_t, uint16_t, const void *, uint32_t, void *);
1421
1422 /* _mdns_query_start
1423 * initializes the context and starts a DNS-SD query.
1424 */
1425 static DNSServiceErrorType
1426 _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)
1427 {
1428 DNSServiceErrorType status;
1429
1430 int dns_flags = kDNSServiceFlagsShareConnection | kDNSServiceFlagsReturnIntermediates;
1431
1432 memset(ctx, 0, sizeof(mdns_query_context_t));
1433
1434 if (answer && anslen) {
1435 // build a dummy DNS header to return to the caller
1436 ctx->answer = answer;
1437 ctx->ansmaxlen = *anslen;
1438 ctx->anslen = _mdns_make_query(name, class, type, answer, ctx->ansmaxlen);
1439 if (ctx->anslen <= 0) return -1;
1440 }
1441
1442 ctx->type = type;
1443 ctx->sd = _mdns_sdref;
1444 ctx->kq = kq;
1445 if (reply) {
1446 ctx->reply = reply;
1447 if (type == ns_t_a) ctx->host = reply->h4;
1448 else if (type == ns_t_aaaa) ctx->host = reply->h6;
1449 else if (type == ns_t_ptr && reply->h4) ctx->host = reply->h4;
1450 else if (type == ns_t_ptr && reply->h6) ctx->host = reply->h6;
1451 else if (type != ns_t_srv && type != ns_t_cname) abort();
1452 }
1453
1454 uint32_t iface = 0;
1455 char *qname = _mdns_ipv6_extract_scope_id(name, &iface);
1456 if (qname == NULL) qname = (char *)name;
1457
1458 if (interface != NULL)
1459 {
1460 /* get interface number from name */
1461 int iface2 = if_nametoindex(interface);
1462
1463 /* balk if interface name lookup failed */
1464 if (iface2 == 0) return -1;
1465
1466 /* balk if scope id is set AND interface is given AND they don't match */
1467 if ((iface != 0) && (iface2 != 0) && (iface != iface2)) return -1;
1468 if (iface2 != 0) iface = iface2;
1469 }
1470
1471 if (_mdns_debug) printf(";; mdns query %s %d %d\n", qname, type, class);
1472 status = DNSServiceQueryRecord(&ctx->sd, dns_flags, iface, qname, type, class, _mdns_query_callback, ctx);
1473 if (qname != name) free(qname);
1474 return status;
1475 }
1476
1477 /* _mdns_query_is_complete
1478 * Determines whether the specified query has sufficient information to be
1479 * considered complete.
1480 */
1481 static int
1482 _mdns_query_is_complete(mdns_query_context_t *ctx)
1483 {
1484 if (ctx == NULL) return 1;
1485 //if (ctx->flags & kDNSServiceFlagsMoreComing) return 0;
1486 if (ctx->last_type != ctx->type) return 0;
1487 switch (ctx->type) {
1488 case ns_t_a:
1489 case ns_t_aaaa:
1490 if (ctx->host != NULL && ctx->host->addr_count > 0) {
1491 return 1;
1492 }
1493 break;
1494 case ns_t_ptr:
1495 if (ctx->host != NULL && ctx->host->host.h_name != NULL) {
1496 return 1;
1497 }
1498 break;
1499 case ns_t_srv:
1500 if (ctx->reply != NULL && ctx->reply->srv != NULL) {
1501 return 1;
1502 }
1503 break;
1504 default:
1505 abort();
1506 }
1507 return 0;
1508 }
1509
1510 /* _mdns_query_clear
1511 * Clear out the temporary fields of the context, and clear any result
1512 * structures that are incomplete. Retrns 1 if the query was complete.
1513 */
1514 static int
1515 _mdns_query_clear(mdns_query_context_t *ctx)
1516 {
1517 int complete = _mdns_query_is_complete(ctx);
1518 if (ctx == NULL) return complete;
1519
1520 if (ctx->sd != NULL) {
1521 DNSServiceRefDeallocate(ctx->sd);
1522 ctx->sd = NULL;
1523 }
1524 ctx->flags = 0;
1525 ctx->kq = -1;
1526
1527 if (!complete) {
1528 _mdns_hostent_clear(ctx->host);
1529 ctx->anslen = -1;
1530 }
1531 return complete;
1532 }
1533
1534 static void
1535 _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)
1536 {
1537 mdns_query_context_t *context;
1538 struct in6_addr a6;
1539
1540 context = (mdns_query_context_t *)ctx;
1541
1542 context->flags = flags;
1543 context->error = errorCode;
1544 context->last_type = rrtype;
1545
1546 if (errorCode != kDNSServiceErr_NoError) {
1547 if (_mdns_debug) printf(";; [%s %hu %hu]: error %d\n", fullname, rrtype, rrclass, errorCode);
1548 goto wakeup_kevent;
1549 }
1550
1551 // embed the scope ID into link-local IPv6 addresses
1552 if (rrtype == ns_t_aaaa && rdlen == sizeof(struct in6_addr) &&
1553 IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)rdata)) {
1554 memcpy(&a6, rdata, rdlen);
1555 a6.__u6_addr.__u6_addr16[1] = htons(ifIndex);
1556 rdata = &a6;
1557 }
1558
1559 if (context->reply) {
1560 char *name;
1561 int malformed = 0;
1562 mdns_reply_t *reply = context->reply;
1563
1564 if (reply->ifnum == 0) {
1565 reply->ifnum = ifIndex;
1566 }
1567
1568 _mdns_hostent_append_alias(context->host, fullname);
1569 if (reply->ttl == 0 || ttl < reply->ttl) reply->ttl = ttl;
1570
1571 switch (rrtype) {
1572 case ns_t_a:
1573 case ns_t_aaaa:
1574 if (((rrtype == ns_t_a && context->host->host.h_addrtype == AF_INET) ||
1575 (rrtype == ns_t_aaaa && context->host->host.h_addrtype == AF_INET6)) &&
1576 rdlen >= context->host->host.h_length) {
1577 if (context->host->host.h_name == NULL) {
1578 int i;
1579 mdns_hostent_t *h = context->host;
1580 char *h_name = _mdns_canonicalize(fullname);
1581 context->host->host.h_name = h_name;
1582
1583 // 6863416 remove h_name from h_aliases
1584 for (i = 0; i < h->alias_count; ++i) {
1585 if (h_name == NULL) break;
1586 if (string_equal(h->host.h_aliases[i], h_name)) {
1587 // includes trailing NULL pointer
1588 int sz = sizeof(char *) * (h->alias_count - i);
1589 free(h->host.h_aliases[i]);
1590 memmove(&h->host.h_aliases[i], &h->host.h_aliases[i+1], sz);
1591 h->alias_count -= 1;
1592 break;
1593 }
1594 }
1595 }
1596 _mdns_hostent_append_addr(context->host, rdata, context->host->host.h_length);
1597 } else {
1598 malformed = 1;
1599 }
1600 break;
1601 case ns_t_cname:
1602 name = _mdns_parse_domain_name(rdata, rdlen);
1603 if (!name) malformed = 1;
1604 _mdns_hostent_append_alias(context->host, name);
1605 free(name);
1606 break;
1607 case ns_t_ptr:
1608 name = _mdns_parse_domain_name(rdata, rdlen);
1609 if (!name) malformed = 1;
1610 if (context->host && context->host->host.h_name == NULL) {
1611 context->host->host.h_name = _mdns_canonicalize(name);
1612 }
1613 _mdns_hostent_append_alias(context->host, name);
1614 free(name);
1615 break;
1616 case ns_t_srv: {
1617 mdns_rr_srv_t *p = (mdns_rr_srv_t*)rdata;
1618 mdns_srv_t *srv = calloc(1, sizeof(mdns_srv_t));
1619 if (srv == NULL) break;
1620 if (rdlen < sizeof(mdns_rr_srv_t)) {
1621 malformed = 1;
1622 break;
1623 }
1624 srv->srv.priority = ntohs(p->priority);
1625 srv->srv.weight = ntohs(p->weight);
1626 srv->srv.port = ntohs(p->port);
1627 srv->srv.target = _mdns_parse_domain_name(&p->target[0], rdlen - 3*sizeof(uint16_t));
1628 if (srv->srv.target == NULL) {
1629 malformed = 1;
1630 break;
1631 }
1632 // append to the end of the list
1633 if (reply->srv == NULL) {
1634 reply->srv = srv;
1635 } else {
1636 mdns_srv_t *iter = reply->srv;
1637 while (iter->next) iter = iter->next;
1638 iter->next = srv;
1639 }
1640 break;
1641 }
1642 default:
1643 malformed = _mdns_debug;
1644 break;
1645 }
1646 if (malformed && _mdns_debug) {
1647 printf(";; [%s %hu %hu]: malformed reply\n", fullname, rrtype, rrclass);
1648 goto wakeup_kevent;
1649 }
1650 }
1651
1652 if (context->answer) {
1653 int n;
1654 uint8_t *cp;
1655 HEADER *ans;
1656 size_t buflen = context->ansmaxlen - context->anslen;
1657 if (buflen < NS_HFIXEDSZ)
1658 {
1659 if (_mdns_debug) printf(";; [%s %hu %hu]: malformed reply\n", fullname, rrtype, rrclass);
1660 goto wakeup_kevent;
1661 }
1662
1663 cp = context->answer + context->anslen;
1664
1665 n = _mdns_pack_domain_name(fullname, cp, buflen);
1666 if (n < 0) {
1667 if (_mdns_debug) printf(";; [%s %hu %hu]: name mismatch\n", fullname, rrtype, rrclass);
1668 goto wakeup_kevent;
1669 }
1670
1671 // check that there is enough space in the buffer for the
1672 // resource name (n), the resource record data (rdlen) and
1673 // the resource record header (10).
1674 if (buflen < n + rdlen + 10) {
1675 if (_mdns_debug) printf(";; [%s %hu %hu]: insufficient buffer space for reply\n", fullname, rrtype, rrclass);
1676 goto wakeup_kevent;
1677 }
1678
1679 cp += n;
1680 buflen -= n;
1681
1682 uint16_t word;
1683 uint32_t longword;
1684
1685 word = htons(rrtype);
1686 memcpy(cp, &word, sizeof(word));
1687 cp += sizeof(word);
1688
1689 word = htons(rrclass);
1690 memcpy(cp, &word, sizeof(word));
1691 cp += sizeof(word);
1692
1693 longword = htonl(ttl);
1694 memcpy(cp, &longword, sizeof(longword));
1695 cp += sizeof(longword);
1696
1697 word = htons(rdlen);
1698 memcpy(cp, &word, sizeof(word));
1699 cp += sizeof(word);
1700
1701 memcpy(cp, rdata, rdlen);
1702 cp += rdlen;
1703
1704 ans = (HEADER *)context->answer;
1705 ans->ancount = htons(ntohs(ans->ancount) + 1);
1706
1707 context->anslen = (size_t)(cp - context->answer);
1708 }
1709
1710 if (_mdns_debug) printf(";; [%s %hu %hu]\n", fullname, rrtype, rrclass);
1711
1712 wakeup_kevent:
1713 // Ping the waiting thread in case this callback was invoked on another
1714 if (context->kq != -1) {
1715 struct kevent ev;
1716 EV_SET(&ev, 1, EVFILT_USER, 0, NOTE_TRIGGER, 0, 0);
1717 int res = kevent(context->kq, &ev, 1, NULL, 0, NULL);
1718 if (res && _mdns_debug) printf(";; kevent EV_TRIGGER: %s\n", strerror(errno));
1719 }
1720 }
1721
1722 static void
1723 _mdns_now(struct timespec *now) {
1724 struct timeval tv;
1725 gettimeofday(&tv, NULL);
1726 now->tv_sec = tv.tv_sec;
1727 now->tv_nsec = tv.tv_usec * 1000;
1728 }
1729
1730 static void
1731 _mdns_add_time(struct timespec *sum, const struct timespec *a, const struct timespec *b)
1732 {
1733 sum->tv_sec = a->tv_sec + b->tv_sec;
1734 sum->tv_nsec = a->tv_nsec + b->tv_nsec;
1735 if (sum->tv_nsec > 1000000000) {
1736 sum->tv_sec += (sum->tv_nsec / 1000000000);
1737 sum->tv_nsec %= 1000000000;
1738 }
1739 }
1740
1741 // calculate a deadline from the current time based on the desired timeout
1742 static void
1743 _mdns_deadline(struct timespec *deadline, const struct timespec *delta)
1744 {
1745 struct timespec now;
1746 _mdns_now(&now);
1747 _mdns_add_time(deadline, &now, delta);
1748 }
1749
1750 static void
1751 _mdns_sub_time(struct timespec *delta, const struct timespec *a, const struct timespec *b)
1752 {
1753 delta->tv_sec = a->tv_sec - b->tv_sec;
1754 delta->tv_nsec = a->tv_nsec - b->tv_nsec;
1755 if (delta->tv_nsec < 0) {
1756 delta->tv_nsec += 1000000000;
1757 delta->tv_sec -= 1;
1758 }
1759 }
1760
1761 // calculate a timeout remaining before the given deadline
1762 static void
1763 _mdns_timeout(struct timespec *timeout, const struct timespec *deadline)
1764 {
1765 struct timespec now;
1766 _mdns_now(&now);
1767 _mdns_sub_time(timeout, deadline, &now);
1768 }
1769
1770 int
1771 _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)
1772 {
1773 DNSServiceErrorType err = 0;
1774 int kq, n, wait = 1;
1775 struct kevent ev;
1776 struct timespec start, finish, delta, timeout;
1777 int res = 0;
1778 int i, complete, got_response = 0;
1779 int initialize = 1;
1780
1781 // 2 for A and AAAA parallel queries
1782 int n_ctx = 0;
1783 mdns_query_context_t ctx[2];
1784
1785 if (name == NULL) return -1;
1786
1787 #if TARGET_OS_EMBEDDED
1788 // log a warning for queries from the main thread
1789 if (pthread_main_np()) asl_log(NULL, NULL, ASL_LEVEL_WARNING, "Warning: Libinfo call to mDNSResponder on main thread");
1790 #endif // TARGET_OS_EMBEDDED
1791
1792 // Timeout Logic
1793 // The kevent(2) API timeout parameter is used to enforce the total
1794 // timeout of the DNS query. Each iteraion recalculates the relative
1795 // timeout based on the desired end time (total timeout from origin).
1796 //
1797 // In order to workaround some DNS configurations that do not return
1798 // responses for AAAA queries, parallel queries modify the total
1799 // timeout upon receipt of the first response. The new total timeout is
1800 // set to an effective value of 2N where N is the time taken to receive
1801 // the A response (the original total timeout is preserved if 2N would
1802 // have exceeded it). However, since mDNSResponder caches values, a
1803 // minimum value of 50ms for N is enforced in order to give some time
1804 // for the receipt of a AAAA response.
1805
1806 // determine the maximum time to wait for a result
1807 if (timeout_sec == 0) timeout_sec = RES_MAXRETRANS;
1808 delta.tv_sec = timeout_sec;
1809 delta.tv_nsec = 0;
1810 _mdns_deadline(&finish, &delta);
1811 timeout = delta;
1812 _mdns_now(&start);
1813
1814 // set up the kqueue
1815 kq = kqueue();
1816 EV_SET(&ev, 1, EVFILT_USER, EV_ADD | EV_CLEAR, 0, 0, 0);
1817 n = kevent(kq, &ev, 1, NULL, 0, NULL);
1818 if (n != 0) wait = 0;
1819
1820 while (wait == 1) {
1821 if (initialize) {
1822 initialize = 0;
1823 pthread_mutex_lock(&_mdns_mutex);
1824 // clear any stale contexts
1825 for (i = 0; i < n_ctx; ++i) {
1826 _mdns_query_clear(&ctx[i]);
1827 }
1828 n_ctx = 0;
1829
1830 if (_mdns_sdref == NULL) {
1831 if (_mdns_old_sdref != NULL) {
1832 DNSServiceRefDeallocate(_mdns_old_sdref);
1833 _mdns_old_sdref = NULL;
1834 }
1835 // (re)initialize the shared connection
1836 err = DNSServiceCreateConnection(&_mdns_sdref);
1837 if (err != 0) {
1838 wait = 0;
1839 pthread_mutex_unlock(&_mdns_mutex);
1840 break;
1841 }
1842 }
1843
1844 // issue (or reissue) the queries
1845 // unspecified type: do parallel A and AAAA
1846 if (err == 0) {
1847 err = _mdns_query_start(&ctx[n_ctx++], reply,
1848 answer, anslen,
1849 name, class,
1850 (type == 0) ? ns_t_a : type, interface, kq);
1851 }
1852 if (err == 0 && type == 0) {
1853 err = _mdns_query_start(&ctx[n_ctx++], reply,
1854 answer, anslen,
1855 name, class, ns_t_aaaa, interface, kq);
1856 }
1857 if (err && _mdns_debug) printf(";; initialization error %d\n", err);
1858 // try to reinitialize
1859 if (err == kDNSServiceErr_Unknown ||
1860 err == kDNSServiceErr_ServiceNotRunning ||
1861 err == kDNSServiceErr_BadReference) {
1862 if (_mdns_sdref) {
1863 DNSServiceRefDeallocate(_mdns_sdref);
1864 _mdns_sdref = NULL;
1865 }
1866 err = 0;
1867 initialize = 1;
1868 pthread_mutex_unlock(&_mdns_mutex);
1869 continue;
1870 } else if (err != 0) {
1871 pthread_mutex_unlock(&_mdns_mutex);
1872 break;
1873 }
1874
1875 // (re)register the fd with kqueue
1876 int fd = DNSServiceRefSockFD(_mdns_sdref);
1877 EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
1878 n = kevent(kq, &ev, 1, NULL, 0, NULL);
1879 pthread_mutex_unlock(&_mdns_mutex);
1880 if (err != 0 || n != 0) break;
1881 }
1882
1883 if (_mdns_debug) printf(";; kevent timeout %ld.%ld\n", timeout.tv_sec, timeout.tv_nsec);
1884 n = kevent(kq, NULL, 0, &ev, 1, &timeout);
1885 if (n < 0 && errno != EINTR) {
1886 res = -1;
1887 break;
1888 }
1889
1890 pthread_mutex_lock(&_mdns_mutex);
1891 // DNSServiceProcessResult() is a blocking API
1892 // confirm that there is still data on the socket
1893 const struct timespec notimeout = { 0, 0 };
1894 int m = kevent(kq, NULL, 0, &ev, 1, &notimeout);
1895 if (_mdns_sdref == NULL) {
1896 initialize = 1;
1897 } else if (m > 0 && ev.filter == EVFILT_READ) {
1898 err = DNSServiceProcessResult(_mdns_sdref);
1899 if (err == kDNSServiceErr_ServiceNotRunning ||
1900 err == kDNSServiceErr_BadReference) {
1901 if (_mdns_debug) printf(";; DNSServiceProcessResult status %d\n", err);
1902 err = 0;
1903 // re-initialize the shared connection
1904 DNSServiceRefDeallocate(_mdns_sdref);
1905 _mdns_sdref = NULL;
1906 initialize = 1;
1907 }
1908 }
1909
1910 // Check if all queries are complete (including errors)
1911 complete = 1;
1912 for (i = 0; i < n_ctx; ++i) {
1913 if (_mdns_query_is_complete(&ctx[i]) || ctx[i].error) {
1914 if (ctx[i].type == ns_t_a) {
1915 got_response = 1;
1916 }
1917 } else {
1918 complete = 0;
1919 }
1920 }
1921 pthread_mutex_unlock(&_mdns_mutex);
1922
1923 if (err != 0) {
1924 if (_mdns_debug) printf(";; DNSServiceProcessResult status %d\n", err);
1925 break;
1926 } else if (complete == 1) {
1927 if (_mdns_debug) printf(";; done\n");
1928 break;
1929 } else if (got_response == 1) {
1930 // got A, adjust deadline for AAAA
1931 struct timespec now;
1932 _mdns_now(&now);
1933 _mdns_sub_time(&delta, &now, &start); // delta = N
1934 // minimum N of 50ms
1935 if (delta.tv_sec == 0 && delta.tv_nsec < 50000000) {
1936 delta.tv_nsec = 50000000;
1937 }
1938
1939 // only move deadline if timeout > 2N
1940 _mdns_sub_time(&now, &timeout, &delta);
1941 if (now.tv_sec >= 0) {
1942 if (_mdns_debug) printf(";; new timeout %ld.%ld\n", delta.tv_sec, delta.tv_nsec);
1943 _mdns_deadline(&finish, &delta);
1944 }
1945 }
1946
1947 // calculate remaining timeout
1948 _mdns_timeout(&timeout, &finish);
1949 // no time remaining
1950 if (timeout.tv_sec < 0) {
1951 if (_mdns_debug) printf(";; timeout\n");
1952 break;
1953 }
1954 }
1955
1956 complete = 0;
1957 pthread_mutex_lock(&_mdns_mutex);
1958 for (i = 0; i < n_ctx; ++i) {
1959 if (err == 0) err = ctx[i].error;
1960 // Only clears hostents if result is incomplete.
1961 complete = _mdns_query_clear(&ctx[i]) || complete;
1962 }
1963 pthread_mutex_unlock(&_mdns_mutex);
1964 // Everything should be done with the kq by now.
1965 close(kq);
1966
1967 // Return error if everything is incomplete
1968 if (complete == 0) {
1969 res = -1;
1970 }
1971
1972 if (anslen) *anslen = ctx[0].anslen;
1973 return res;
1974 }