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