1/* 2 * Copyright (c) 2008-2011 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23/* 24 * Portions Copyright (c) 1996-1999 by Internet Software Consortium. 25 * 26 * Permission to use, copy, modify, and distribute this software for any 27 * purpose with or without fee is hereby granted, provided that the above 28 * copyright notice and this permission notice appear in all copies. 29 * 30 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS 31 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 32 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE 33 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 34 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 35 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 36 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 37 * SOFTWARE. 38 */ 39/* 40 * Copyright (c) 1988, 1993 41 * The Regents of the University of California. All rights reserved. 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * 1. Redistributions of source code must retain the above copyright 47 * notice, this list of conditions and the following disclaimer. 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 4. Neither the name of the University nor the names of its contributors 52 * may be used to endorse or promote products derived from this software 53 * without specific prior written permission. 54 * 55 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 56 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 57 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 58 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 59 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 60 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 61 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 62 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 63 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 64 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 65 * SUCH DAMAGE. 66 */ 67/* 68 * Portions Copyright (c) 1993 by Digital Equipment Corporation. 69 * 70 * Permission to use, copy, modify, and distribute this software for any 71 * purpose with or without fee is hereby granted, provided that the above 72 * copyright notice and this permission notice appear in all copies, and that 73 * the name of Digital Equipment Corporation not be used in advertising or 74 * publicity pertaining to distribution of the document or software without 75 * specific, written prior permission. 76 * 77 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL 78 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES 79 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT 80 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 81 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 82 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 83 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 84 * SOFTWARE. 85 */ 86 87#include "ils.h" 88#include "netdb.h" 89#include "si_module.h" 90 91#include <assert.h> 92#include <arpa/inet.h> 93#include <arpa/nameser.h> 94#include <arpa/nameser_compat.h> 95#include <libkern/OSAtomic.h> 96#include <netinet/in.h> 97#include <ctype.h> 98#include <dns_sd.h> 99#include <dnsinfo.h> 100#include <errno.h> 101#include <nameser.h> 102#include <notify.h> 103#include <pthread.h> 104#include <resolv.h> 105#include <stdio.h> 106#include <stdlib.h> 107#include <string.h> 108#include <sys/event.h> 109#include <sys/param.h> 110#include <sys/time.h> 111#include <sys/types.h> 112#include <sys/socket.h> 113#include <net/if.h> 114#include <time.h> 115#include <unistd.h> 116#include <asl.h> 117#include <dns.h> 118#include <dns_util.h> 119#include <TargetConditionals.h> 120#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 136static int _mdns_debug = 0; 137 138// mutex protects DNSServiceProcessResult and DNSServiceRefDeallocate 139static pthread_mutex_t _mdns_mutex = PTHREAD_MUTEX_INITIALIZER; 140 141typedef struct { 142 uint16_t priority; 143 uint16_t weight; 144 uint16_t port; 145 uint8_t target[0]; 146} mdns_rr_srv_t; 147 148typedef struct mdns_srv_t mdns_srv_t; 149struct mdns_srv_t { 150 si_srv_t srv; 151 mdns_srv_t *next; 152}; 153 154typedef struct { 155 struct hostent host; 156 int alias_count; 157 int addr_count; 158} mdns_hostent_t; 159 160typedef struct { 161 mdns_hostent_t *h4; 162 mdns_hostent_t *h6; 163 mdns_srv_t *srv; 164 uint64_t ttl; 165 uint32_t ifnum; 166} mdns_reply_t; 167 168static uint32_t _mdns_generation = 0; 169static DNSServiceRef _mdns_sdref; 170static DNSServiceRef _mdns_old_sdref; 171 172static void _mdns_hostent_clear(mdns_hostent_t *h); 173static void _mdns_reply_clear(mdns_reply_t *r); 174static 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); 175 176static const char hexchar[] = "0123456789abcdef"; 177 178#define BILLION 1000000000 179 180/* 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" */ 181#define IPv6_REVERSE_LEN 72 182 183/* index of the trailing char that must be "8", "9", "A", "a", "b", or "B" */ 184#define IPv6_REVERSE_LINK_LOCAL_TRAILING_CHAR 58 185 186/* index of low-order nibble of embedded scope id */ 187#define IPv6_REVERSE_LINK_LOCAL_SCOPE_ID_LOW 48 188 189const static uint8_t hexval[128] = { 190 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 - 15 */ 191 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16 - 31 */ 192 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 32 - 47 */ 193 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 48 - 63 */ 194 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 64 - 79 */ 195 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 95 */ 196 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 96 - 111 */ 197 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 112 - 127 */ 198}; 199 200static char * 201_mdns_reverse_ipv4(const char *addr) 202{ 203 union 204 { 205 uint32_t a; 206 unsigned char b[4]; 207 } ab; 208 char *p; 209 210 if (addr == NULL) return NULL; 211 212 memcpy(&(ab.a), addr, 4); 213 214 asprintf(&p, "%u.%u.%u.%u.in-addr.arpa.", ab.b[3], ab.b[2], ab.b[1], ab.b[0]); 215 return p; 216} 217 218static char * 219_mdns_reverse_ipv6(const char *addr) 220{ 221 char x[65], *p; 222 int i, j; 223 u_int8_t d, hi, lo; 224 225 if (addr == NULL) return NULL; 226 227 x[64] = '\0'; 228 j = 63; 229 for (i = 0; i < 16; i++) 230 { 231 d = addr[i]; 232 lo = d & 0x0f; 233 hi = d >> 4; 234 x[j--] = '.'; 235 x[j--] = hexchar[hi]; 236 x[j--] = '.'; 237 x[j--] = hexchar[lo]; 238 } 239 240 asprintf(&p, "%sip6.arpa.", x); 241 242 return p; 243} 244 245/* _mdns_canonicalize 246 * Canonicalize the domain name by converting to lower case and removing the 247 * trailing '.' if present. 248 */ 249static char * 250_mdns_canonicalize(const char *s) 251{ 252 int i; 253 char *t; 254 if (s == NULL) return NULL; 255 t = strdup(s); 256 if (t == NULL) return NULL; 257 if (t[0] == '\0') return t; 258 for (i = 0; t[i] != '\0'; i++) { 259 if (t[i] >= 'A' && t[i] <= 'Z') t[i] += 32; 260 } 261 if (t[i-1] == '.') t[i-1] = '\0'; 262 return t; 263} 264 265/* _mdns_hostent_append_alias 266 * Appends an alias to the mdns_hostent_t structure. 267 */ 268static int 269_mdns_hostent_append_alias(mdns_hostent_t *h, const char *alias) 270{ 271 int i; 272 char *name; 273 if (h == NULL || alias == NULL) return 0; 274 name = _mdns_canonicalize(alias); 275 if (name == NULL) return -1; 276 277 // don't add the name if it matches an existing name 278 if (h->host.h_name && string_equal(h->host.h_name, name)) { 279 free(name); 280 return 0; 281 } 282 for (i = 0; i < h->alias_count; ++i) { 283 if (string_equal(h->host.h_aliases[i], name)) { 284 free(name); 285 return 0; 286 } 287 } 288 289 // add the alias and NULL terminate the list 290 h->host.h_aliases = (char **)reallocf(h->host.h_aliases, (h->alias_count+2) * sizeof(char *)); 291 if (h->host.h_aliases == NULL) { 292 h->alias_count = 0; 293 free(name); 294 return -1; 295 } 296 h->host.h_aliases[h->alias_count] = name; 297 ++h->alias_count; 298 h->host.h_aliases[h->alias_count] = NULL; 299 return 0; 300} 301 302/* _mdns_hostent_append_addr 303 * Appends an alias to the mdns_hostent_t structure. 304 */ 305static int 306_mdns_hostent_append_addr(mdns_hostent_t *h, const uint8_t *addr, uint32_t len) 307{ 308 if (h == NULL || addr == NULL || len == 0) return 0; 309 310 // copy the address buffer 311 uint8_t *buf = malloc(len); 312 if (buf == NULL) return -1; 313 memcpy(buf, addr, len); 314 315 // add the address and NULL terminate the list 316 h->host.h_addr_list = (char **)reallocf(h->host.h_addr_list, (h->addr_count+2) * sizeof(char *)); 317 if (h->host.h_addr_list == NULL) { 318 h->addr_count = 0; 319 return -1; 320 } 321 h->host.h_addr_list[h->addr_count] = (char*)buf; 322 h->addr_count++; 323 h->host.h_addr_list[h->addr_count] = NULL; 324 return 0; 325} 326 327static void 328_mdns_hostent_clear(mdns_hostent_t *h) 329{ 330 if (h == NULL) return; 331 free(h->host.h_name); 332 h->host.h_name = NULL; 333 334 char **aliases = h->host.h_aliases; 335 while (aliases && *aliases) { 336 free(*aliases++); 337 } 338 free(h->host.h_aliases); 339 h->host.h_aliases = NULL; 340 h->alias_count = 0; 341 342 char **addrs = h->host.h_addr_list; 343 while (addrs && *addrs) { 344 free(*addrs++); 345 } 346 free(h->host.h_addr_list); 347 h->host.h_addr_list = NULL; 348 h->addr_count = 0; 349 350} 351 352static void 353_mdns_reply_clear(mdns_reply_t *r) 354{ 355 if (r == NULL) return; 356 r->ifnum = 0; 357 _mdns_hostent_clear(r->h4); 358 _mdns_hostent_clear(r->h6); 359 mdns_srv_t *srv = r->srv; 360 r->srv = NULL; 361 while (srv) { 362 mdns_srv_t *next = srv->next; 363 free(srv->srv.target); 364 free(srv); 365 srv = next; 366 } 367} 368 369static si_item_t * 370mdns_hostbyname(si_mod_t *si, const char *name, int af, const char *interface, uint32_t *err) 371{ 372 uint32_t type; 373 mdns_hostent_t h; 374 mdns_reply_t reply; 375 si_item_t *out = NULL; 376 uint64_t bb; 377 int status; 378 DNSServiceFlags flags = 0; 379 380 if (err != NULL) *err = SI_STATUS_NO_ERROR; 381 382 if (name == NULL) { 383 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY; 384 return NULL; 385 } 386 387 memset(&h, 0, sizeof(h)); 388 memset(&reply, 0, sizeof(reply)); 389 390 switch (af) { 391 case AF_INET: 392 type = ns_t_a; 393 h.host.h_length = 4; 394 reply.h4 = &h; 395 break; 396 case AF_INET6: 397 type = ns_t_aaaa; 398 h.host.h_length = 16; 399 reply.h6 = &h; 400 break; 401 default: 402 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY; 403 return NULL; 404 } 405 h.host.h_addrtype = af; 406 407 status = _mdns_search(name, ns_c_in, type, interface, flags, NULL, NULL, &reply); 408 if (status != 0 || h.addr_count == 0) { 409 _mdns_reply_clear(&reply); 410 if (err != NULL) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND; 411 return NULL; 412 } 413 414 bb = reply.ttl + time(NULL); 415 416 switch (af) { 417 case AF_INET: 418 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); 419 break; 420 case AF_INET6: 421 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); 422 break; 423 } 424 425 _mdns_reply_clear(&reply); 426 427 if (out == NULL && err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY; 428 429 return out; 430} 431 432static si_item_t * 433mdns_hostbyaddr(si_mod_t *si, const void *addr, int af, const char *interface, uint32_t *err) 434{ 435 mdns_hostent_t h; 436 mdns_reply_t reply; 437 char *name; 438 si_item_t *out; 439 uint64_t bb; 440 int cat; 441 int status; 442 DNSServiceFlags flags = 0; 443 444 if (err != NULL) *err = SI_STATUS_NO_ERROR; 445 446 if (addr == NULL || si == NULL) { 447 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY; 448 return NULL; 449 } 450 451 memset(&h, 0, sizeof(h)); 452 memset(&reply, 0, sizeof(reply)); 453 454 switch (af) { 455 case AF_INET: 456 h.host.h_length = 4; 457 reply.h4 = &h; 458 name = _mdns_reverse_ipv4(addr); 459 cat = CATEGORY_HOST_IPV4; 460 break; 461 case AF_INET6: 462 h.host.h_length = 16; 463 reply.h6 = &h; 464 name = _mdns_reverse_ipv6(addr); 465 cat = CATEGORY_HOST_IPV6; 466 break; 467 default: 468 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY; 469 return NULL; 470 } 471 h.host.h_addrtype = af; 472 473 status = _mdns_search(name, ns_c_in, ns_t_ptr, interface, flags, NULL, NULL, &reply); 474 free(name); 475 if (status != 0) { 476 _mdns_reply_clear(&reply); 477 if (err != NULL) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND; 478 return NULL; 479 } 480 481 status = _mdns_hostent_append_addr(&h, addr, h.host.h_length); 482 if (status != 0) { 483 _mdns_hostent_clear(&h); 484 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY; 485 return NULL; 486 } 487 488 bb = reply.ttl + time(NULL); 489 out = (si_item_t *)LI_ils_create("L4488s*44a", (unsigned long)si, cat, 1, bb, 0LL, h.host.h_name, h.host.h_aliases, h.host.h_addrtype, h.host.h_length, h.host.h_addr_list); 490 491 _mdns_hostent_clear(&h); 492 493 if (out == NULL && err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY; 494 return out; 495} 496 497static si_list_t * 498mdns_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) 499{ 500 int wantv4 = 1; 501 int wantv6 = 1; 502 struct in_addr a4; 503 struct in6_addr a6; 504 mdns_hostent_t h4; 505 mdns_hostent_t h6; 506 mdns_reply_t reply; 507 uint32_t type; 508 uint16_t port; 509 510 if (family == AF_INET6) 511 { 512 if ((flags & AI_V4MAPPED) == 0) wantv4 = 0; 513 } 514 else if (family == AF_INET) 515 { 516 wantv6 = 0; 517 } 518 else if (family != AF_UNSPEC) 519 { 520 return NULL; 521 } 522 523 if (err != NULL) *err = SI_STATUS_NO_ERROR; 524 525 si_list_t *out = NULL; 526 527 memset(&h4, 0, sizeof(h4)); 528 memset(&h6, 0, sizeof(h6)); 529 memset(&reply, 0, sizeof(reply)); 530 531 h4.host.h_addrtype = AF_INET; 532 h4.host.h_length = 4; 533 h6.host.h_addrtype = AF_INET6; 534 h6.host.h_length = 16; 535 536 if (wantv4 && wantv6) { 537 type = 0; 538 reply.h4 = &h4; 539 reply.h6 = &h6; 540 } else if (wantv4) { 541 reply.h4 = &h4; 542 type = ns_t_a; 543 } else if (wantv6) { 544 type = ns_t_aaaa; 545 reply.h6 = &h6; 546 } else { 547 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY; 548 return NULL; 549 } 550 551 // service lookup 552 if ((flags & AI_NUMERICSERV) != 0) { 553 port = *(uint16_t *)serv; 554 } else { 555 if (_gai_serv_to_port(serv, proto, &port) != 0) { 556 if (err) *err = SI_STATUS_EAI_NONAME; 557 return NULL; 558 } 559 } 560 561 // host lookup 562 if ((flags & AI_NUMERICHOST) != 0) { 563 char *cname = NULL; 564 struct in_addr *p4 = NULL; 565 struct in6_addr *p6 = NULL; 566 if (family == AF_INET) { 567 p4 = &a4; 568 memcpy(p4, node, sizeof(a4)); 569 } else if (family == AF_INET6) { 570 p6 = &a6; 571 memcpy(p6, node, sizeof(a6)); 572 } 573 out = si_addrinfo_list(si, flags, socktype, proto, p4, p6, port, 0, cname, cname); 574 } else { 575 DNSServiceFlags dns_flags = 0; 576 if (flags & AI_ADDRCONFIG) { 577 dns_flags |= kDNSServiceFlagsSuppressUnusable; 578 } 579 int res; 580 res = _mdns_search(node, ns_c_in, type, interface, dns_flags, NULL, NULL, &reply); 581 if (res == 0 && (h4.addr_count > 0 || h6.addr_count > 0)) { 582 out = si_addrinfo_list_from_hostent(si, flags, socktype, proto, 583 port, 0, 584 (wantv4 ? &h4.host : NULL), 585 (wantv6 ? &h6.host : NULL)); 586 } else if (err != NULL) { 587 *err = SI_STATUS_EAI_NONAME; 588 } 589 _mdns_reply_clear(&reply); 590 } 591 return out; 592} 593 594static si_list_t * 595mdns_srv_byname(si_mod_t* si, const char *qname, const char *interface, uint32_t *err) 596{ 597 si_list_t *out = NULL; 598 mdns_reply_t reply; 599 mdns_srv_t *srv; 600 int res; 601 const uint64_t unused = 0; 602 DNSServiceFlags flags = 0; 603 604 if (err != NULL) *err = SI_STATUS_NO_ERROR; 605 606 memset(&reply, 0, sizeof(reply)); 607 res = _mdns_search(qname, ns_c_in, ns_t_srv, interface, flags, NULL, NULL, &reply); 608 if (res == 0) { 609 srv = reply.srv; 610 while (srv) { 611 si_item_t *item; 612 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); 613 out = si_list_add(out, item); 614 si_item_release(item); 615 srv = srv->next; 616 } 617 } 618 _mdns_reply_clear(&reply); 619 return out; 620} 621 622/* 623 * We support dns_async_start / cancel / handle_reply using dns_item_call 624 */ 625static si_item_t * 626mdns_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) 627{ 628 int res; 629 uint8_t buf[DNS_MAX_RECEIVE_SIZE]; 630 uint32_t len = sizeof(buf); 631 mdns_reply_t reply; 632 mdns_hostent_t h4; 633 mdns_hostent_t h6; 634 si_item_t *out; 635 DNSServiceFlags flags = 0; 636 637 if (err != NULL) *err = SI_STATUS_NO_ERROR; 638 639 if (name == NULL) { 640 if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY; 641 return NULL; 642 } 643 644 memset(&h4, 0, sizeof(h4)); 645 memset(&h6, 0, sizeof(h6)); 646 memset(&reply, 0, sizeof(reply)); 647 648 h4.host.h_addrtype = AF_INET; 649 h4.host.h_length = 4; 650 h6.host.h_addrtype = AF_INET6; 651 h6.host.h_length = 16; 652 reply.h4 = &h4; 653 reply.h6 = &h6; 654 655 res = _mdns_search(name, class, type, interface, flags, buf, &len, &reply); 656 if (res != 0 || len <= 0 || len > DNS_MAX_RECEIVE_SIZE) { 657 _mdns_reply_clear(&reply); 658 if (err != NULL) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND; 659 return NULL; 660 } 661 662 struct sockaddr_in6 from; 663 uint32_t fromlen = sizeof(from); 664 memset(&from, 0, fromlen); 665 from.sin6_len = fromlen; 666 from.sin6_family = AF_INET6; 667 from.sin6_addr.__u6_addr.__u6_addr8[15] = 1; 668 if (reply.ifnum != 0) { 669 from.sin6_addr.__u6_addr.__u6_addr16[0] = htons(0xfe80); 670 from.sin6_scope_id = reply.ifnum; 671 } 672 673 out = (si_item_t *)LI_ils_create("L4488@@", (unsigned long)si, CATEGORY_DNSPACKET, 1, 0LL, 0LL, len, buf, fromlen, &from); 674 if (out == NULL && err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY; 675 676 _mdns_reply_clear(&reply); 677 678 return out; 679} 680 681static int 682mdns_is_valid(si_mod_t *si, si_item_t *item) 683{ 684 return 0; 685} 686 687static void 688mdns_close(si_mod_t *si) 689{ 690} 691 692static void 693_mdns_atfork_prepare(void) 694{ 695 // acquire our lock so that we know all other threads have "drained" 696 pthread_mutex_lock(&_mdns_mutex); 697} 698 699static void 700_mdns_atfork_parent(void) 701{ 702 // parent can simply resume 703 pthread_mutex_unlock(&_mdns_mutex); 704} 705 706static void 707_mdns_atfork_child(void) 708{ 709 // child needs to force re-initialization 710 _mdns_old_sdref = _mdns_sdref; // for later deallocation 711 _mdns_sdref = NULL; 712 pthread_mutex_unlock(&_mdns_mutex); 713} 714 715static void 716_mdns_init(void) 717{ 718 pthread_atfork(_mdns_atfork_prepare, _mdns_atfork_parent, _mdns_atfork_child); 719 720 _mdns_debug = getenv("RES_DEBUG") != NULL; 721} 722 723si_mod_t * 724si_module_static_mdns(void) 725{ 726 static const struct si_mod_vtable_s mdns_vtable = 727 { 728 .sim_close = &mdns_close, 729 .sim_is_valid = &mdns_is_valid, 730 .sim_host_byname = &mdns_hostbyname, 731 .sim_host_byaddr = &mdns_hostbyaddr, 732 .sim_item_call = &mdns_item_call, 733 .sim_addrinfo = &mdns_addrinfo, 734 .sim_srv_byname = &mdns_srv_byname, 735 }; 736 737 static si_mod_t si = 738 { 739 .vers = 1, 740 .refcount = 1, 741 .flags = SI_MOD_FLAG_STATIC, 742 743 .private = NULL, 744 .vtable = &mdns_vtable, 745 }; 746 747 static dispatch_once_t once; 748 749 dispatch_once(&once, ^{ 750 si.name = strdup("mdns"); 751 _mdns_init(); 752 }); 753 754 return (si_mod_t*)&si; 755} 756 757/* 758 * _mdns_parse_domain_name 759 * Combine DNS labels to form a string. 760 * DNSService API does not return compressed names. 761 */ 762static char * 763_mdns_parse_domain_name(const uint8_t *data, uint32_t datalen) 764{ 765 int i = 0, j = 0; 766 uint32_t len; 767 uint32_t domainlen = 0; 768 char *domain = NULL; 769 770 if ((data == NULL) || (datalen == 0)) return NULL; 771 772 // i: index into input data 773 // j: index into output string 774 while (datalen-- > 0) { 775 len = data[i++]; 776 domainlen += (len + 1); 777 domain = reallocf(domain, domainlen); 778 if (domain == NULL) return NULL; 779 if (len == 0) break; // DNS root (NUL) 780 if (j > 0) { 781 domain[j++] = datalen ? '.' : '\0'; 782 } 783 784 while ((len-- > 0) && (datalen--)) { 785 if (data[i] == '.') { 786 // special case: escape the '.' with a '\' 787 domain = reallocf(domain, ++domainlen); 788 if (domain == NULL) return NULL; 789 domain[j++] = '\\'; 790 } 791 domain[j++] = data[i++]; 792 } 793 } 794 domain[j] = '\0'; 795 796 return domain; 797} 798 799/* 800 * _mdns_pack_domain_name 801 * Format the string as packed DNS labels. 802 * Only used for one string at a time, therefore no need for compression. 803 */ 804static int 805_mdns_pack_domain_name(const char* str, uint8_t *buf, size_t buflen) { 806 int i = 0; 807 uintptr_t len = 0; 808 809 while (i < buflen) { 810 // calculate length to next '.' or '\0' 811 char *dot = strchr(str, '.'); 812 if (dot == NULL) dot = strchr(str, '\0'); 813 len = (dot - str); 814 if (len > NS_MAXLABEL) return -1; 815 // copy data for label 816 buf[i++] = len; 817 while (str < dot && i < buflen) { 818 buf[i++] = *str++; 819 } 820 // skip past '.', break if '\0' 821 if (*str++ == '\0') break; 822 } 823 824 if (i >= buflen) return -1; 825 826 if (len > 0) { 827 // no trailing dot - add a null label 828 buf[i++] = 0; 829 if (i >= buflen) return -1; 830 } 831 832 buf[i] = '\0'; 833 return i; 834} 835 836static int 837_is_rev_link_local(const char *name) 838{ 839 int len, i; 840 841 if (name == NULL) return 0; 842 843 len = strlen(name); 844 if (len == 0) return 0; 845 846 /* check for trailing '.' */ 847 if (name[len - 1] == '.') len--; 848 849 if (len != IPv6_REVERSE_LEN) return 0; 850 851 i = IPv6_REVERSE_LINK_LOCAL_TRAILING_CHAR; 852 if ((name[i] != '8') && (name[i] != '9') && (name[i] != 'A') && (name[i] != 'a') && (name[i] != 'B') && (name[i] != 'b')) return 0; 853 854 i = IPv6_REVERSE_LINK_LOCAL_TRAILING_CHAR + 1; 855 if (strncasecmp(name + i, ".e.f.ip6.arpa", 13)) return 0; 856 857 for (i = 0; i < IPv6_REVERSE_LINK_LOCAL_TRAILING_CHAR; i += 2) 858 { 859 if (name[i] < '0') return 0; 860 if ((name[i] > '9') && (name[i] < 'A')) return 0; 861 if ((name[i] > 'F') && (name[i] < 'a')) return 0; 862 if (name[i] > 'f') return 0; 863 if (name[i + 1] != '.') return 0; 864 } 865 866 return 1; 867} 868 869/* _mdns_ipv6_extract_scope_id 870 * If the input string is a link local IPv6 address with an encoded scope id, 871 * the scope id is extracted and a new string is constructed with the scope id removed. 872 */ 873static char * 874_mdns_ipv6_extract_scope_id(const char *name, uint32_t *out_ifnum) 875{ 876 char *qname = NULL; 877 uint16_t nibble; 878 uint32_t iface; 879 int i; 880 881 if (out_ifnum != NULL) *out_ifnum = 0; 882 883 /* examine the address, extract the scope id if present */ 884 if ((name != NULL) && (_is_rev_link_local(name))) 885 { 886 /* _is_rev_link_local rejects chars > 127 so it's safe to index into hexval */ 887 i = IPv6_REVERSE_LINK_LOCAL_SCOPE_ID_LOW; 888 nibble = hexval[(uint32_t)name[i]]; 889 iface = nibble; 890 891 i += 2; 892 nibble = hexval[(uint32_t)name[i]]; 893 iface += (nibble << 4); 894 895 i += 2; 896 nibble = hexval[(uint32_t)name[i]]; 897 iface += (nibble << 8); 898 899 i += 2; 900 nibble = hexval[(uint32_t)name[i]]; 901 iface += (nibble << 12); 902 903 if (iface != 0) 904 { 905 qname = strdup(name); 906 if (qname == NULL) return NULL; 907 908 i = IPv6_REVERSE_LINK_LOCAL_SCOPE_ID_LOW; 909 qname[i] = '0'; 910 qname[i + 2] = '0'; 911 qname[i + 4] = '0'; 912 qname[i + 6] = '0'; 913 914 if (out_ifnum) *out_ifnum = iface; 915 } 916 } 917 918 return qname; 919} 920 921static int 922_mdns_make_query(const char* name, int class, int type, uint8_t *buf, uint32_t buflen) 923{ 924 uint32_t len = 0; 925 926 if (buf == NULL || buflen < (NS_HFIXEDSZ + NS_QFIXEDSZ)) return -1; 927 memset(buf, 0, NS_HFIXEDSZ); 928 HEADER *hp = (HEADER *)buf; 929 930 len += NS_HFIXEDSZ; 931 hp->id = arc4random(); 932 hp->qr = 1; 933 hp->opcode = ns_o_query; 934 hp->rd = 1; 935 hp->rcode = ns_r_noerror; 936 hp->qdcount = htons(1); 937 938 int n = _mdns_pack_domain_name(name, &buf[len], buflen - len); 939 if (n < 0) return -1; 940 941 len += n; 942 uint16_t word; 943 word = htons(type); 944 memcpy(&buf[len], &word, sizeof(word)); 945 len += sizeof(word); 946 word = htons(class); 947 memcpy(&buf[len], &word, sizeof(word)); 948 len += sizeof(word); 949 return len; 950} 951 952typedef struct { 953 mdns_reply_t *reply; 954 mdns_hostent_t *host; 955 uint8_t *answer; // DNS packet buffer 956 size_t anslen; // DNS packet buffer current length 957 size_t ansmaxlen; // DNS packet buffer maximum length 958 int type; // type of query: A, AAAA, PTR, SRV... 959 uint16_t last_type; // last type received 960 uint32_t sd_gen; 961 DNSServiceRef sd; 962 DNSServiceFlags flags; 963 DNSServiceErrorType error; 964 int kq; // kqueue to notify when callback received 965} mdns_query_context_t; 966 967static void 968_mdns_query_callback(DNSServiceRef, DNSServiceFlags, uint32_t, DNSServiceErrorType, const char *, uint16_t, uint16_t, uint16_t, const void *, uint32_t, void *); 969 970/* _mdns_query_start 971 * initializes the context and starts a DNS-SD query. 972 */ 973static DNSServiceErrorType 974_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) 975{ 976 DNSServiceErrorType status; 977 978 flags |= kDNSServiceFlagsShareConnection; 979 flags |= kDNSServiceFlagsReturnIntermediates; 980 981 /* <rdar://problem/7428439> mDNSResponder is now responsible for timeouts */ 982 flags |= kDNSServiceFlagsTimeout; 983 984 memset(ctx, 0, sizeof(mdns_query_context_t)); 985 986 if (answer && anslen) { 987 // build a dummy DNS header to return to the caller 988 ctx->answer = answer; 989 ctx->ansmaxlen = *anslen; 990 ctx->anslen = _mdns_make_query(name, class, type, answer, ctx->ansmaxlen); 991 if (ctx->anslen <= 0) return -1; 992 } 993 994 ctx->type = type; 995 ctx->sd = _mdns_sdref; 996 ctx->sd_gen = _mdns_generation; 997 ctx->kq = kq; 998 if (reply) { 999 ctx->reply = reply; 1000 if (type == ns_t_a) ctx->host = reply->h4; 1001 else if (type == ns_t_aaaa) ctx->host = reply->h6; 1002 else if (type == ns_t_ptr && reply->h4) ctx->host = reply->h4; 1003 else if (type == ns_t_ptr && reply->h6) ctx->host = reply->h6; 1004 else if (type != ns_t_srv && type != ns_t_cname) return -1; 1005 } 1006 1007 uint32_t iface = 0; 1008 char *qname = _mdns_ipv6_extract_scope_id(name, &iface); 1009 if (qname == NULL) qname = (char *)name; 1010 1011 if (interface != NULL) 1012 { 1013 /* get interface number from name */ 1014 int iface2 = if_nametoindex(interface); 1015 1016 /* balk if interface name lookup failed */ 1017 if (iface2 == 0) return -1; 1018 1019 /* balk if scope id is set AND interface is given AND they don't match */ 1020 if ((iface != 0) && (iface2 != 0) && (iface != iface2)) return -1; 1021 if (iface2 != 0) iface = iface2; 1022 } 1023 1024 if (_mdns_debug) printf(";; mdns query %s %d %d\n", qname, type, class); 1025 status = DNSServiceQueryRecord(&ctx->sd, flags, iface, qname, type, class, _mdns_query_callback, ctx); 1026 if (qname != name) free(qname); 1027 return status; 1028} 1029 1030/* _mdns_query_is_complete 1031 * Determines whether the specified query has sufficient information to be 1032 * considered complete. 1033 */ 1034static int 1035_mdns_query_is_complete(mdns_query_context_t *ctx) 1036{ 1037 if (ctx == NULL) return 1; 1038 //if (ctx->flags & kDNSServiceFlagsMoreComing) return 0; 1039 if (ctx->last_type != ctx->type) return 0; 1040 switch (ctx->type) { 1041 case ns_t_a: 1042 case ns_t_aaaa: 1043 if (ctx->host != NULL && ctx->host->addr_count > 0) { 1044 return 1; 1045 } 1046 break; 1047 case ns_t_ptr: 1048 if (ctx->host != NULL && ctx->host->host.h_name != NULL) { 1049 return 1; 1050 } 1051 break; 1052 case ns_t_srv: 1053 if (ctx->reply != NULL && ctx->reply->srv != NULL) { 1054 return 1; 1055 } 1056 break; 1057 default: 1058 return 0; 1059 } 1060 return 0; 1061} 1062 1063/* _mdns_query_clear 1064 * Clear out the temporary fields of the context, and clear any result 1065 * structures that are incomplete. Retrns 1 if the query was complete. 1066 */ 1067static int 1068_mdns_query_clear(mdns_query_context_t *ctx) 1069{ 1070 int complete = _mdns_query_is_complete(ctx); 1071 if (ctx == NULL) return complete; 1072 1073 if (ctx->sd != NULL) { 1074 /* only dealloc this DNSServiceRef if the "main" _mdns_sdref has not been deallocated */ 1075 if (ctx->sd != NULL && ctx->sd_gen == _mdns_generation) { 1076 DNSServiceRefDeallocate(ctx->sd); 1077 } 1078 } 1079 1080 ctx->sd = NULL; 1081 ctx->sd_gen = 0; 1082 ctx->flags = 0; 1083 ctx->kq = -1; 1084 1085 if (!complete) { 1086 _mdns_hostent_clear(ctx->host); 1087 ctx->anslen = -1; 1088 } 1089 return complete; 1090} 1091 1092static void 1093_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) 1094{ 1095 mdns_query_context_t *context; 1096 struct in6_addr a6; 1097 1098 context = (mdns_query_context_t *)ctx; 1099 1100 context->flags = flags; 1101 context->error = errorCode; 1102 context->last_type = rrtype; 1103 1104 if (errorCode != kDNSServiceErr_NoError) { 1105 if (_mdns_debug) printf(";; [%s %hu %hu]: error %d\n", fullname, rrtype, rrclass, errorCode); 1106 goto wakeup_kevent; 1107 } 1108 1109 // embed the scope ID into link-local IPv6 addresses 1110 if (rrtype == ns_t_aaaa && rdlen == sizeof(struct in6_addr) && 1111 IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)rdata)) { 1112 memcpy(&a6, rdata, rdlen); 1113 a6.__u6_addr.__u6_addr16[1] = htons(ifIndex); 1114 rdata = &a6; 1115 } 1116 1117 if (context->reply) { 1118 char *name; 1119 int malformed = 0; 1120 mdns_reply_t *reply = context->reply; 1121 1122 if (reply->ifnum == 0) { 1123 reply->ifnum = ifIndex; 1124 } 1125 1126 _mdns_hostent_append_alias(context->host, fullname); 1127 if (reply->ttl == 0 || ttl < reply->ttl) reply->ttl = ttl; 1128 1129 switch (rrtype) { 1130 case ns_t_a: 1131 case ns_t_aaaa: 1132 if (((rrtype == ns_t_a && context->host->host.h_addrtype == AF_INET) || 1133 (rrtype == ns_t_aaaa && context->host->host.h_addrtype == AF_INET6)) && 1134 rdlen >= context->host->host.h_length) { 1135 if (context->host->host.h_name == NULL) { 1136 int i; 1137 mdns_hostent_t *h = context->host; 1138 char *h_name = _mdns_canonicalize(fullname); 1139 context->host->host.h_name = h_name; 1140 1141 // 6863416 remove h_name from h_aliases 1142 for (i = 0; i < h->alias_count; ++i) { 1143 if (h_name == NULL) break; 1144 if (string_equal(h->host.h_aliases[i], h_name)) { 1145 // includes trailing NULL pointer 1146 int sz = sizeof(char *) * (h->alias_count - i); 1147 free(h->host.h_aliases[i]); 1148 memmove(&h->host.h_aliases[i], &h->host.h_aliases[i+1], sz); 1149 h->alias_count -= 1; 1150 break; 1151 } 1152 } 1153 } 1154 _mdns_hostent_append_addr(context->host, rdata, context->host->host.h_length); 1155 } else { 1156 malformed = 1; 1157 } 1158 break; 1159 case ns_t_cname: 1160 name = _mdns_parse_domain_name(rdata, rdlen); 1161 if (!name) malformed = 1; 1162 _mdns_hostent_append_alias(context->host, name); 1163 free(name); 1164 break; 1165 case ns_t_ptr: 1166 name = _mdns_parse_domain_name(rdata, rdlen); 1167 if (!name) malformed = 1; 1168 if (context->host && context->host->host.h_name == NULL) { 1169 context->host->host.h_name = _mdns_canonicalize(name); 1170 } 1171 _mdns_hostent_append_alias(context->host, name); 1172 free(name); 1173 break; 1174 case ns_t_srv: { 1175 mdns_rr_srv_t *p = (mdns_rr_srv_t*)rdata; 1176 mdns_srv_t *srv = calloc(1, sizeof(mdns_srv_t)); 1177 if (srv == NULL) break; 1178 if (rdlen < sizeof(mdns_rr_srv_t)) { 1179 malformed = 1; 1180 break; 1181 } 1182 srv->srv.priority = ntohs(p->priority); 1183 srv->srv.weight = ntohs(p->weight); 1184 srv->srv.port = ntohs(p->port); 1185 srv->srv.target = _mdns_parse_domain_name(&p->target[0], rdlen - 3*sizeof(uint16_t)); 1186 if (srv->srv.target == NULL) { 1187 malformed = 1; 1188 break; 1189 } 1190 // append to the end of the list 1191 if (reply->srv == NULL) { 1192 reply->srv = srv; 1193 } else { 1194 mdns_srv_t *iter = reply->srv; 1195 while (iter->next) iter = iter->next; 1196 iter->next = srv; 1197 } 1198 break; 1199 } 1200 default: 1201 malformed = _mdns_debug; 1202 break; 1203 } 1204 if (malformed && _mdns_debug) { 1205 printf(";; [%s %hu %hu]: malformed reply\n", fullname, rrtype, rrclass); 1206 goto wakeup_kevent; 1207 } 1208 } 1209 1210 if (context->answer) { 1211 int n; 1212 uint8_t *cp; 1213 HEADER *ans; 1214 size_t buflen = context->ansmaxlen - context->anslen; 1215 if (buflen < NS_HFIXEDSZ) 1216 { 1217 if (_mdns_debug) printf(";; [%s %hu %hu]: malformed reply\n", fullname, rrtype, rrclass); 1218 goto wakeup_kevent; 1219 } 1220 1221 cp = context->answer + context->anslen; 1222 1223 n = _mdns_pack_domain_name(fullname, cp, buflen); 1224 if (n < 0) { 1225 if (_mdns_debug) printf(";; [%s %hu %hu]: name mismatch\n", fullname, rrtype, rrclass); 1226 goto wakeup_kevent; 1227 } 1228 1229 // check that there is enough space in the buffer for the 1230 // resource name (n), the resource record data (rdlen) and 1231 // the resource record header (10). 1232 if (buflen < n + rdlen + 10) { 1233 if (_mdns_debug) printf(";; [%s %hu %hu]: insufficient buffer space for reply\n", fullname, rrtype, rrclass); 1234 goto wakeup_kevent; 1235 } 1236 1237 cp += n; 1238 buflen -= n; 1239 1240 uint16_t word; 1241 uint32_t longword; 1242 1243 word = htons(rrtype); 1244 memcpy(cp, &word, sizeof(word)); 1245 cp += sizeof(word); 1246 1247 word = htons(rrclass); 1248 memcpy(cp, &word, sizeof(word)); 1249 cp += sizeof(word); 1250 1251 longword = htonl(ttl); 1252 memcpy(cp, &longword, sizeof(longword)); 1253 cp += sizeof(longword); 1254 1255 word = htons(rdlen); 1256 memcpy(cp, &word, sizeof(word)); 1257 cp += sizeof(word); 1258 1259 memcpy(cp, rdata, rdlen); 1260 cp += rdlen; 1261 1262 ans = (HEADER *)context->answer; 1263 ans->ancount = htons(ntohs(ans->ancount) + 1); 1264 1265 context->anslen = (size_t)(cp - context->answer); 1266 } 1267 1268 if (_mdns_debug) printf(";; [%s %hu %hu]\n", fullname, rrtype, rrclass); 1269 1270wakeup_kevent: 1271 // Ping the waiting thread in case this callback was invoked on another 1272 if (context->kq != -1) { 1273 struct kevent ev; 1274 EV_SET(&ev, 1, EVFILT_USER, 0, NOTE_TRIGGER, 0, 0); 1275 int res = kevent(context->kq, &ev, 1, NULL, 0, NULL); 1276 if (res && _mdns_debug) printf(";; kevent EV_TRIGGER: %s\n", strerror(errno)); 1277 } 1278} 1279 1280static void 1281_mdns_now(struct timespec *now) { 1282 struct timeval tv; 1283 gettimeofday(&tv, NULL); 1284 now->tv_sec = tv.tv_sec; 1285 now->tv_nsec = tv.tv_usec * 1000; 1286} 1287 1288static void 1289_mdns_add_time(struct timespec *sum, const struct timespec *a, const struct timespec *b) 1290{ 1291 sum->tv_sec = a->tv_sec + b->tv_sec; 1292 sum->tv_nsec = a->tv_nsec + b->tv_nsec; 1293 if (sum->tv_nsec > 1000000000) { 1294 sum->tv_sec += (sum->tv_nsec / 1000000000); 1295 sum->tv_nsec %= 1000000000; 1296 } 1297} 1298 1299// calculate a deadline from the current time based on the desired timeout 1300static void 1301_mdns_deadline(struct timespec *deadline, const struct timespec *delta) 1302{ 1303 struct timespec now; 1304 _mdns_now(&now); 1305 _mdns_add_time(deadline, &now, delta); 1306} 1307 1308static void 1309_mdns_sub_time(struct timespec *delta, const struct timespec *a, const struct timespec *b) 1310{ 1311 delta->tv_sec = a->tv_sec - b->tv_sec; 1312 delta->tv_nsec = a->tv_nsec - b->tv_nsec; 1313 if (delta->tv_nsec < 0) { 1314 delta->tv_nsec += 1000000000; 1315 delta->tv_sec -= 1; 1316 } 1317} 1318 1319// calculate a timeout remaining before the given deadline 1320static void 1321_mdns_timeout(struct timespec *timeout, const struct timespec *deadline) 1322{ 1323 struct timespec now; 1324 _mdns_now(&now); 1325 _mdns_sub_time(timeout, deadline, &now); 1326} 1327 1328int 1329_mdns_search(const char *name, int class, int type, const char *interface, DNSServiceFlags flags, uint8_t *answer, uint32_t *anslen, mdns_reply_t *reply) 1330{ 1331 DNSServiceErrorType err = 0; 1332 int kq, n, wait = 1; 1333 struct kevent ev; 1334 struct timespec start, finish, delta, timeout; 1335 int res = 0; 1336 int i, complete, got_a_response = 0; 1337 int initialize = 1; 1338 uint32_t n_iface_4 = 0; 1339 1340 // determine number of IPv4 interfaces (ignore loopback) 1341 si_inet_config(&n_iface_4, NULL); 1342 if (n_iface_4 > 0) n_iface_4--; 1343 1344 // <rdar://problem/7732497> limit the number of initialization retries 1345 int initialize_retries = 3; 1346 1347 // 2 for A and AAAA parallel queries 1348 int n_ctx = 0; 1349 mdns_query_context_t ctx[2]; 1350 1351 if (name == NULL) return -1; 1352 1353#if TARGET_OS_EMBEDDED 1354 // log a warning for queries from the main thread 1355 if (pthread_is_threaded_np() && pthread_main_np()) asl_log(NULL, NULL, ASL_LEVEL_WARNING, "Warning: Libinfo call to mDNSResponder on main thread"); 1356#endif // TARGET_OS_EMBEDDED 1357 1358 // Timeout Logic 1359 // The kevent(2) API timeout parameter is used to enforce the total 1360 // timeout of the DNS query. Each iteraion recalculates the relative 1361 // timeout based on the desired end time (total timeout from origin). 1362 // 1363 // In order to workaround some DNS configurations that do not return 1364 // responses for AAAA queries, parallel queries modify the total 1365 // timeout upon receipt of the first response. The new total timeout is 1366 // set to an effective value of 2N where N is the time taken to receive 1367 // the A response (the original total timeout is preserved if 2N would 1368 // have exceeded it). However, since mDNSResponder caches values, a 1369 // minimum value of 50ms for N is enforced in order to give some time 1370 // for the receipt of a AAAA response. 1371 1372 // determine the maximum time to wait for a result 1373 delta.tv_sec = RES_MAXRETRANS + 5; 1374 delta.tv_nsec = 0; 1375 _mdns_deadline(&finish, &delta); 1376 timeout = delta; 1377 _mdns_now(&start); 1378 1379 for (i = 0; i < 2; ++i) { 1380 memset(&ctx[i], 0 , sizeof(mdns_query_context_t)); 1381 } 1382 1383 // set up the kqueue 1384 kq = kqueue(); 1385 EV_SET(&ev, 1, EVFILT_USER, EV_ADD | EV_CLEAR, 0, 0, 0); 1386 n = kevent(kq, &ev, 1, NULL, 0, NULL); 1387 if (n != 0) wait = 0; 1388 1389 while (wait == 1) { 1390 if (initialize) { 1391 initialize = 0; 1392 pthread_mutex_lock(&_mdns_mutex); 1393 // clear any stale contexts 1394 for (i = 0; i < n_ctx; ++i) { 1395 _mdns_query_clear(&ctx[i]); 1396 } 1397 n_ctx = 0; 1398 1399 if (_mdns_sdref == NULL) { 1400 if (_mdns_old_sdref != NULL) { 1401 _mdns_generation++; 1402 DNSServiceRefDeallocate(_mdns_old_sdref); 1403 _mdns_old_sdref = NULL; 1404 } 1405 // (re)initialize the shared connection 1406 err = DNSServiceCreateConnection(&_mdns_sdref); 1407 1408 // limit the number of retries 1409 if (initialize_retries-- <= 0 && err == 0) { 1410 err = kDNSServiceErr_Unknown; 1411 } 1412 if (err != 0) { 1413 wait = 0; 1414 pthread_mutex_unlock(&_mdns_mutex); 1415 break; 1416 } 1417 } 1418 1419 // issue (or reissue) the queries 1420 // unspecified type: do parallel A and AAAA 1421 if (err == 0) { 1422 err = _mdns_query_start(&ctx[n_ctx++], reply, 1423 answer, anslen, 1424 name, class, 1425 (type == 0) ? ns_t_a : type, interface, flags, kq); 1426 } 1427 if (err == 0 && type == 0) { 1428 err = _mdns_query_start(&ctx[n_ctx++], reply, 1429 answer, anslen, 1430 name, class, ns_t_aaaa, interface, flags, kq); 1431 } 1432 if (err && _mdns_debug) printf(";; initialization error %d\n", err); 1433 // try to reinitialize 1434 if (err == kDNSServiceErr_Unknown || 1435 err == kDNSServiceErr_ServiceNotRunning || 1436 err == kDNSServiceErr_BadReference) { 1437 if (_mdns_sdref) { 1438 _mdns_generation++; 1439 DNSServiceRefDeallocate(_mdns_sdref); 1440 _mdns_sdref = NULL; 1441 } 1442 err = 0; 1443 initialize = 1; 1444 pthread_mutex_unlock(&_mdns_mutex); 1445 continue; 1446 } else if (err != 0) { 1447 pthread_mutex_unlock(&_mdns_mutex); 1448 break; 1449 } 1450 1451 // (re)register the fd with kqueue 1452 int fd = DNSServiceRefSockFD(_mdns_sdref); 1453 EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0); 1454 n = kevent(kq, &ev, 1, NULL, 0, NULL); 1455 pthread_mutex_unlock(&_mdns_mutex); 1456 if (err != 0 || n != 0) break; 1457 } 1458 1459 if (_mdns_debug) printf(";; kevent timeout %ld.%ld\n", timeout.tv_sec, timeout.tv_nsec); 1460 n = kevent(kq, NULL, 0, &ev, 1, &timeout); 1461 if (n < 0 && errno != EINTR) { 1462 res = -1; 1463 break; 1464 } 1465 1466 pthread_mutex_lock(&_mdns_mutex); 1467 // DNSServiceProcessResult() is a blocking API 1468 // confirm that there is still data on the socket 1469 const struct timespec notimeout = { 0, 0 }; 1470 int m = kevent(kq, NULL, 0, &ev, 1, ¬imeout); 1471 if (_mdns_sdref == NULL) { 1472 initialize = 1; 1473 } else if (m > 0 && ev.filter == EVFILT_READ) { 1474 err = DNSServiceProcessResult(_mdns_sdref); 1475 if (err == kDNSServiceErr_ServiceNotRunning || 1476 err == kDNSServiceErr_BadReference) { 1477 if (_mdns_debug) printf(";; DNSServiceProcessResult status %d\n", err); 1478 err = 0; 1479 // re-initialize the shared connection 1480 _mdns_generation++; 1481 DNSServiceRefDeallocate(_mdns_sdref); 1482 _mdns_sdref = NULL; 1483 initialize = 1; 1484 } 1485 } 1486 1487 // Check if all queries are complete (including errors) 1488 complete = 1; 1489 for (i = 0; i < n_ctx; ++i) { 1490 if (_mdns_query_is_complete(&ctx[i]) || ctx[i].error != 0) { 1491 if (ctx[i].type == ns_t_a) { 1492 got_a_response = GOT_DATA; 1493 if (ctx[i].error != 0) got_a_response = GOT_ERROR; 1494 } 1495 } else { 1496 complete = 0; 1497 } 1498 } 1499 pthread_mutex_unlock(&_mdns_mutex); 1500 1501 if (err != 0) { 1502 if (_mdns_debug) printf(";; DNSServiceProcessResult status %d\n", err); 1503 break; 1504 } else if (complete == 1) { 1505 if (_mdns_debug) printf(";; done\n"); 1506 break; 1507 } else if (got_a_response != 0) { 1508 // got A, adjust deadline for AAAA 1509 struct timespec now, tn, extra; 1510 1511 // delta = now - start 1512 _mdns_now(&now); 1513 _mdns_sub_time(&delta, &now, &start); 1514 1515 extra.tv_sec = SHORT_AAAA_EXTRA; 1516 extra.tv_nsec = 0; 1517 1518 // if delta is small (<= 20 milliseconds), we probably got a result from mDNSResponder's cache 1519 if ((delta.tv_sec == 0) && (delta.tv_nsec <= 20000000)) { 1520 extra.tv_sec = MEDIUM_AAAA_EXTRA; 1521 } 1522 else if (n_iface_4 == 0) { 1523 extra.tv_sec = LONG_AAAA_EXTRA; 1524 } else if (got_a_response == GOT_ERROR) { 1525 extra.tv_sec = MEDIUM_AAAA_EXTRA; 1526 } 1527 1528 // tn = 2 * delta 1529 _mdns_add_time(&tn, &delta, &delta); 1530 1531 // delta = tn + extra 1532 _mdns_add_time(&delta, &tn, &extra); 1533 1534 // check that delta doesn't exceed our total timeout 1535 _mdns_sub_time(&tn, &timeout, &delta); 1536 if (tn.tv_sec >= 0) { 1537 if (_mdns_debug) printf(";; new timeout (waiting for AAAA) %ld.%ld\n", delta.tv_sec, delta.tv_nsec); 1538 _mdns_deadline(&finish, &delta); 1539 } 1540 } 1541 1542 // calculate remaining timeout 1543 _mdns_timeout(&timeout, &finish); 1544 1545 // check for time remaining 1546 if (timeout.tv_sec < 0) { 1547 if (_mdns_debug) printf(";; timeout\n"); 1548 break; 1549 } 1550 } 1551 1552 complete = 0; 1553 pthread_mutex_lock(&_mdns_mutex); 1554 for (i = 0; i < n_ctx; ++i) { 1555 if (err == 0) err = ctx[i].error; 1556 // Only clears hostents if result is incomplete. 1557 complete = _mdns_query_clear(&ctx[i]) || complete; 1558 } 1559 pthread_mutex_unlock(&_mdns_mutex); 1560 // Everything should be done with the kq by now. 1561 close(kq); 1562 1563 // Return error if everything is incomplete 1564 if (complete == 0) { 1565 res = -1; 1566 } 1567 1568 if (anslen) *anslen = ctx[0].anslen; 1569 return res; 1570} 1571