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