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