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