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