1 /* $NetBSD: nss_mdnsd.c,v 1.4 2014/03/31 02:03:38 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2009 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Tyler C. Sarna 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Multicast DNS ("Bonjour") hosts name service switch 34 * 35 * Documentation links: 36 * 37 * http://developer.apple.com/bonjour/ 38 * http://www.multicastdns.org/ 39 * http://www.dns-sd.org/ 40 */ 41 42 #include <errno.h> 43 #include <nsswitch.h> 44 #include <stdarg.h> 45 #include <stdlib.h> 46 #include <sys/socket.h> 47 #include <sys/param.h> 48 #include <sys/queue.h> 49 #include <netdb.h> 50 #include <netinet/in.h> 51 #include <arpa/nameser.h> 52 #include <resolv.h> 53 #include <dns_sd.h> 54 #include <poll.h> 55 #include <string.h> 56 #include <stdio.h> 57 #include <stdbool.h> 58 #include <pthread.h> 59 #include <fcntl.h> 60 #include <unistd.h> 61 #include <time.h> 62 63 64 #include "hostent.h" 65 66 /* 67 * Pool of mdnsd connections 68 */ 69 static SLIST_HEAD(, svc_ref) conn_list = LIST_HEAD_INITIALIZER(&conn_list); 70 static unsigned int conn_count = 0; 71 static pid_t my_pid; 72 struct timespec last_config; 73 74 typedef struct svc_ref { 75 SLIST_ENTRY(svc_ref) entries; 76 DNSServiceRef sdRef; 77 unsigned int uses; 78 } svc_ref; 79 80 /* 81 * There is a large class of programs that do a few lookups at startup 82 * and then never again (ping, telnet, etc). Keeping a persistent connection 83 * for these would be a waste, so there is a kind of slow start mechanism. 84 * The first SLOWSTART_LOOKUPS times, dispose of the connection after use. 85 * After that we assume the program is a serious consumer of host lookup 86 * services and start keeping connections. 87 */ 88 #define SLOWSTART_LOOKUPS 5 89 static unsigned int svc_puts = 0; 90 91 /* 92 * Age out connections. Free connection instead of putting on the list 93 * if used more than REUSE_TIMES and there are others on the list. 94 */ 95 #define REUSE_TIMES 32 96 97 /* protects above data */ 98 static pthread_mutex_t conn_list_lock = PTHREAD_MUTEX_INITIALIZER; 99 100 extern int __isthreaded; /* libc private -- wish there was a better way */ 101 102 #define LOCK(x) do { if (__isthreaded) pthread_mutex_lock(x); } while (0) 103 #define UNLOCK(x) do { if (__isthreaded) pthread_mutex_unlock(x); } while (0) 104 105 106 #ifndef lint 107 #define UNUSED(a) (void)&a 108 #else 109 #define UNUSED(a) a = a 110 #endif 111 112 #define MAXALIASES 35 113 #define MAXADDRS 35 114 115 typedef struct callback_ctx { 116 bool done; 117 } callback_ctx; 118 119 typedef struct hostent_ctx { 120 callback_ctx cb_ctx; /* must come first */ 121 struct hostent host; 122 char *h_addr_ptrs[MAXADDRS + 1]; 123 char *host_aliases[MAXALIASES]; 124 char addrs[MAXADDRS * 16]; 125 char buf[8192], *next; 126 int naliases, naddrs; 127 } hostent_ctx; 128 129 typedef struct addrinfo_ctx { 130 callback_ctx cb_ctx; /* must come first */ 131 struct addrinfo start, *last; 132 } addrinfo_ctx; 133 134 #define HCTX_BUFLEFT(c) (sizeof((c)->buf) - ((c)->next - (c)->buf)) 135 136 typedef struct res_conf { 137 unsigned int refcount; 138 char **search_domains; 139 char **no_search; 140 short ndots; 141 short timeout; 142 } res_conf; 143 144 static res_conf *cur_res_conf; 145 146 /* protects above data */ 147 static pthread_mutex_t res_conf_lock = PTHREAD_MUTEX_INITIALIZER; 148 149 typedef struct search_iter { 150 res_conf *conf; 151 const char *name; 152 char **next_search; 153 size_t baselen; 154 bool abs_first; 155 bool abs_last; 156 char buf[MAXHOSTNAMELEN]; 157 } search_iter; 158 159 static DNSServiceFlags svc_flags = 0; 160 161 ns_mtab *nss_module_register(const char *, u_int *, nss_module_unregister_fn *); 162 static int load_config(res_state); 163 164 static int _mdns_getaddrinfo(void *, void *, va_list); 165 static int _mdns_gethtbyaddr(void *, void *, va_list); 166 static int _mdns_gethtbyname(void *, void *, va_list); 167 168 static int _mdns_getaddrinfo_abs(const char *, DNSServiceProtocol, 169 svc_ref **, addrinfo_ctx *, short); 170 static void _mdns_addrinfo_init(addrinfo_ctx *, const struct addrinfo *); 171 static void _mdns_addrinfo_add_ai(addrinfo_ctx *, struct addrinfo *); 172 static struct addrinfo *_mdns_addrinfo_done(addrinfo_ctx *); 173 174 static int _mdns_gethtbyname_abs(struct getnamaddr *, struct hostent_ctx *, 175 const char *, int, svc_ref **, short); 176 static void _mdns_hostent_init(hostent_ctx *, int, int); 177 static void _mdns_hostent_add_host(hostent_ctx *, const char *); 178 static void _mdns_hostent_add_addr(hostent_ctx *, const void *, uint16_t); 179 static int _mdns_hostent_done(struct getnamaddr *, hostent_ctx *); 180 181 static void _mdns_addrinfo_cb(DNSServiceRef, DNSServiceFlags, 182 uint32_t, DNSServiceErrorType, const char *, const struct sockaddr *, 183 uint32_t, void *); 184 static void _mdns_hostent_cb(DNSServiceRef, DNSServiceFlags, 185 uint32_t, DNSServiceErrorType, const char *, uint16_t, uint16_t, uint16_t, 186 const void *, uint32_t, void *); 187 static void _mdns_eventloop(svc_ref *, callback_ctx *, short); 188 189 static char *_mdns_rdata2name(const unsigned char *, uint16_t, 190 char *, size_t); 191 192 static int search_init(search_iter *, const char *, const char **); 193 static void search_done(search_iter *); 194 static const char *search_next(search_iter *); 195 static bool searchable_domain(char *); 196 197 static void destroy_svc_ref(svc_ref *); 198 static svc_ref *get_svc_ref(void); 199 static void put_svc_ref(svc_ref *); 200 static bool retry_query(svc_ref **, DNSServiceErrorType); 201 202 static void decref_res_conf(res_conf *); 203 static res_conf *get_res_conf(void); 204 static void put_res_conf(res_conf *); 205 static res_conf *new_res_conf(res_state); 206 static short get_timeout(void); 207 208 static ns_mtab mtab[] = { 209 { NSDB_HOSTS, "getaddrinfo", _mdns_getaddrinfo, NULL }, 210 { NSDB_HOSTS, "gethostbyaddr", _mdns_gethtbyaddr, NULL }, 211 { NSDB_HOSTS, "gethostbyname", _mdns_gethtbyname, NULL }, 212 }; 213 214 215 216 ns_mtab * 217 nss_module_register(const char *source, u_int *nelems, 218 nss_module_unregister_fn *unreg) 219 { 220 *nelems = sizeof(mtab) / sizeof(mtab[0]); 221 *unreg = NULL; 222 223 my_pid = getpid(); 224 225 if (!strcmp(source, "multicast_dns")) { 226 svc_flags = kDNSServiceFlagsForceMulticast; 227 } 228 229 return mtab; 230 } 231 232 233 234 static int 235 _mdns_getaddrinfo(void *cbrv, void *cbdata, va_list ap) 236 { 237 const struct addrinfo *pai; 238 const char *name, *sname; 239 DNSServiceProtocol proto; 240 DNSServiceRef sdRef; 241 addrinfo_ctx ctx; 242 search_iter iter; 243 res_conf *rc; 244 svc_ref *sr; 245 int err; 246 247 UNUSED(cbdata); 248 249 name = va_arg(ap, char *); 250 pai = va_arg(ap, struct addrinfo *); 251 252 switch (pai->ai_family) { 253 case AF_UNSPEC: 254 proto = kDNSServiceProtocol_IPv6 | kDNSServiceProtocol_IPv4; 255 break; 256 257 case AF_INET6: 258 proto = kDNSServiceProtocol_IPv6; 259 break; 260 261 case AF_INET: 262 proto = kDNSServiceProtocol_IPv4; 263 break; 264 265 default: 266 h_errno = NO_RECOVERY; 267 return NS_UNAVAIL; 268 } 269 270 sr = get_svc_ref(); 271 if (!sr) { 272 h_errno = NETDB_INTERNAL; 273 return NS_UNAVAIL; 274 } 275 276 if ((err = search_init(&iter, name, &sname)) != NS_SUCCESS) { 277 put_svc_ref(sr); 278 return err; 279 } 280 281 _mdns_addrinfo_init(&ctx, pai); 282 283 err = NS_NOTFOUND; 284 while (sr && sname && (err != NS_SUCCESS)) { 285 err = _mdns_getaddrinfo_abs(sname, proto, &sr, &ctx, iter.conf->timeout); 286 if (err != NS_SUCCESS) { 287 sname = search_next(&iter); 288 } 289 }; 290 291 search_done(&iter); 292 put_svc_ref(sr); 293 294 if (err == NS_SUCCESS) { 295 *(struct addrinfo **)cbrv = _mdns_addrinfo_done(&ctx); 296 } 297 298 return err; 299 } 300 301 302 303 static int 304 _mdns_getaddrinfo_abs(const char *name, DNSServiceProtocol proto, 305 svc_ref **sr, addrinfo_ctx *ctx, short timeout) 306 { 307 DNSServiceErrorType err = kDNSServiceErr_ServiceNotRunning; 308 DNSServiceRef sdRef; 309 bool retry = true; 310 311 while (*sr && retry) { 312 /* We must always use a copy of the ref when using a shared 313 connection, per kDNSServiceFlagsShareConnection docs */ 314 315 sdRef = (*sr)->sdRef; 316 317 err = DNSServiceGetAddrInfo( 318 &sdRef, 319 svc_flags 320 | kDNSServiceFlagsShareConnection 321 | kDNSServiceFlagsReturnIntermediates, 322 kDNSServiceInterfaceIndexAny, 323 proto, 324 name, 325 _mdns_addrinfo_cb, 326 ctx 327 ); 328 329 retry = retry_query(sr, err); 330 } 331 332 if (err) { 333 h_errno = NETDB_INTERNAL; 334 return NS_UNAVAIL; 335 } 336 337 _mdns_eventloop(*sr, (void *)ctx, timeout); 338 339 DNSServiceRefDeallocate(sdRef); 340 341 if (ctx->start.ai_next) { 342 return NS_SUCCESS; 343 } else { 344 h_errno = HOST_NOT_FOUND; 345 return NS_NOTFOUND; 346 } 347 } 348 349 350 351 static int 352 _mdns_gethtbyaddr(void *cbrv, void *cbdata, va_list ap) 353 { 354 const unsigned char *addr; 355 int addrlen, af; 356 char qbuf[NS_MAXDNAME + 1], *qp, *ep; 357 int advance, n; 358 DNSServiceErrorType err; 359 DNSServiceRef sdRef; 360 svc_ref *sr; 361 bool retry = true; 362 struct getnamaddr *info = cbrv; 363 364 UNUSED(cbdata); 365 366 addr = va_arg(ap, unsigned char *); 367 addrlen = va_arg(ap, int); 368 af = va_arg(ap, int); 369 370 switch (af) { 371 case AF_INET: 372 /* if mcast-only don't bother for non-LinkLocal addrs) */ 373 if (svc_flags & kDNSServiceFlagsForceMulticast) { 374 if ((addr[0] != 169) || (addr[1] != 254)) { 375 *info->he = HOST_NOT_FOUND; 376 return NS_NOTFOUND; 377 } 378 } 379 380 (void)snprintf(qbuf, sizeof(qbuf), "%u.%u.%u.%u.in-addr.arpa", 381 (addr[3] & 0xff), (addr[2] & 0xff), 382 (addr[1] & 0xff), (addr[0] & 0xff)); 383 break; 384 385 case AF_INET6: 386 /* if mcast-only don't bother for non-LinkLocal addrs) */ 387 if (svc_flags & kDNSServiceFlagsForceMulticast) { 388 if ((addr[0] != 0xfe) || ((addr[1] & 0xc0) != 0x80)) { 389 *info->he = HOST_NOT_FOUND; 390 return NS_NOTFOUND; 391 } 392 } 393 394 qp = qbuf; 395 ep = qbuf + sizeof(qbuf) - 1; 396 for (n = IN6ADDRSZ - 1; n >= 0; n--) { 397 advance = snprintf(qp, (size_t)(ep - qp), "%x.%x.", 398 addr[n] & 0xf, 399 ((unsigned int)addr[n] >> 4) & 0xf); 400 if (advance > 0 && qp + advance < ep) 401 qp += advance; 402 else { 403 *info->he = NETDB_INTERNAL; 404 return NS_NOTFOUND; 405 } 406 } 407 if (strlcat(qbuf, "ip6.arpa", sizeof(qbuf)) >= sizeof(qbuf)) { 408 *info->he = NETDB_INTERNAL; 409 return NS_NOTFOUND; 410 } 411 break; 412 413 default: 414 *info->he = NO_RECOVERY; 415 return NS_UNAVAIL; 416 } 417 418 hostent_ctx h_ctx; 419 _mdns_hostent_init(&h_ctx, af, addrlen); 420 _mdns_hostent_add_addr(&h_ctx, addr, addrlen); 421 422 sr = get_svc_ref(); 423 if (!sr) { 424 *info->he = NETDB_INTERNAL; 425 return NS_UNAVAIL; 426 } 427 428 while (sr && retry) { 429 /* We must always use a copy of the ref when using a shared 430 connection, per kDNSServiceFlagsShareConnection docs */ 431 sdRef = sr->sdRef; 432 433 err = DNSServiceQueryRecord( 434 &sdRef, 435 svc_flags 436 | kDNSServiceFlagsShareConnection 437 | kDNSServiceFlagsReturnIntermediates, 438 kDNSServiceInterfaceIndexAny, 439 qbuf, 440 kDNSServiceType_PTR, 441 kDNSServiceClass_IN, 442 _mdns_hostent_cb, 443 &h_ctx 444 ); 445 446 retry = retry_query(&sr, err); 447 } 448 449 if (err) { 450 put_svc_ref(sr); 451 *info->he = NETDB_INTERNAL; 452 return NS_UNAVAIL; 453 } 454 455 _mdns_eventloop(sr, (void *)&h_ctx, get_timeout()); 456 457 DNSServiceRefDeallocate(sdRef); 458 put_svc_ref(sr); 459 460 if (h_ctx.naliases) { 461 return _mdns_hostent_done(info, &h_ctx); 462 } else { 463 *info->he = HOST_NOT_FOUND; 464 return NS_NOTFOUND; 465 } 466 } 467 468 469 470 static int 471 _mdns_gethtbyname(void *cbrv, void *cbdata, va_list ap) 472 { 473 int namelen, af, addrlen, rrtype, err; 474 const char *name, *sname; 475 DNSServiceRef sdRef; 476 search_iter iter; 477 svc_ref *sr; 478 struct getnamaddr *info = cbrv; 479 480 UNUSED(cbdata); 481 482 name = va_arg(ap, char *); 483 namelen = va_arg(ap, int); 484 af = va_arg(ap, int); 485 486 UNUSED(namelen); 487 488 switch (af) { 489 case AF_INET: 490 rrtype = kDNSServiceType_A; 491 addrlen = 4; 492 break; 493 494 case AF_INET6: 495 rrtype = kDNSServiceType_AAAA; 496 addrlen = 16; 497 break; 498 499 default: 500 *info->he = NO_RECOVERY; 501 return NS_UNAVAIL; 502 } 503 504 sr = get_svc_ref(); 505 if (!sr) { 506 *info->he = NETDB_INTERNAL; 507 return NS_UNAVAIL; 508 } 509 510 if ((err = search_init(&iter, name, &sname)) != NS_SUCCESS) { 511 put_svc_ref(sr); 512 return err; 513 } 514 515 hostent_ctx h_ctx; 516 _mdns_hostent_init(&h_ctx, af, addrlen); 517 518 err = NS_NOTFOUND; 519 while (sr && sname && (err != NS_SUCCESS)) { 520 err = _mdns_gethtbyname_abs(info, &h_ctx, sname, rrtype, &sr, 521 iter.conf->timeout); 522 if (err != NS_SUCCESS) { 523 sname = search_next(&iter); 524 } 525 }; 526 527 search_done(&iter); 528 put_svc_ref(sr); 529 530 if (err != NS_SUCCESS) 531 return err; 532 _mdns_hostent_add_host(&h_ctx, sname); 533 _mdns_hostent_add_host(&h_ctx, name); 534 return _mdns_hostent_done(info, &h_ctx); 535 } 536 537 538 539 static int 540 _mdns_gethtbyname_abs(struct getnamaddr *info, struct hostent_ctx *ctx, 541 const char *name, int rrtype, svc_ref **sr, short timeout) 542 { 543 DNSServiceErrorType err = kDNSServiceErr_ServiceNotRunning; 544 DNSServiceRef sdRef; 545 bool retry = true; 546 547 while (*sr && retry) { 548 /* We must always use a copy of the ref when using a shared 549 connection, per kDNSServiceFlagsShareConnection docs */ 550 sdRef = (*sr)->sdRef; 551 552 err = DNSServiceQueryRecord( 553 &sdRef, 554 svc_flags 555 | kDNSServiceFlagsShareConnection 556 | kDNSServiceFlagsReturnIntermediates, 557 kDNSServiceInterfaceIndexAny, 558 name, 559 rrtype, 560 kDNSServiceClass_IN, 561 _mdns_hostent_cb, 562 ctx 563 ); 564 565 retry = retry_query(sr, err); 566 } 567 568 if (err) { 569 *info->he = NETDB_INTERNAL; 570 return NS_UNAVAIL; 571 } 572 573 _mdns_eventloop(*sr, (void *)ctx, timeout); 574 575 DNSServiceRefDeallocate(sdRef); 576 577 if (ctx->naddrs) { 578 return NS_SUCCESS; 579 } else { 580 *info->he = HOST_NOT_FOUND; 581 return NS_NOTFOUND; 582 } 583 } 584 585 586 587 static void 588 _mdns_addrinfo_init(addrinfo_ctx *ctx, const struct addrinfo *ai) 589 { 590 ctx->cb_ctx.done = false; 591 ctx->start = *ai; 592 ctx->start.ai_next = NULL; 593 ctx->start.ai_canonname = NULL; 594 ctx->last = &(ctx->start); 595 } 596 597 598 599 static void 600 _mdns_addrinfo_add_ai(addrinfo_ctx *ctx, struct addrinfo *ai) 601 { 602 ctx->last->ai_next = ai; 603 while (ctx->last->ai_next) 604 ctx->last = ctx->last->ai_next; 605 } 606 607 608 609 static struct addrinfo * 610 _mdns_addrinfo_done(addrinfo_ctx *ctx) 611 { 612 struct addrinfo head, *t, *p; 613 614 /* sort v6 up */ 615 616 t = &head; 617 p = ctx->start.ai_next; 618 619 while (p->ai_next) { 620 if (p->ai_next->ai_family == AF_INET6) { 621 t->ai_next = p->ai_next; 622 t = t->ai_next; 623 p->ai_next = p->ai_next->ai_next; 624 } else { 625 p = p->ai_next; 626 } 627 } 628 629 /* add rest of list and reset start to the new list */ 630 631 t->ai_next = ctx->start.ai_next; 632 ctx->start.ai_next = head.ai_next; 633 634 return ctx->start.ai_next; 635 } 636 637 638 639 static void 640 _mdns_hostent_init(hostent_ctx *ctx, int af, int addrlen) 641 { 642 int i; 643 644 ctx->cb_ctx.done = false; 645 ctx->naliases = ctx->naddrs = 0; 646 ctx->next = ctx->buf; 647 648 ctx->host.h_aliases = ctx->host_aliases; 649 ctx->host.h_addr_list = ctx->h_addr_ptrs; 650 ctx->host.h_name = ctx->host.h_aliases[0] = NULL; 651 ctx->host.h_addrtype = af; 652 ctx->host.h_length = addrlen; 653 654 for (i = 0; i < MAXADDRS; i++) { 655 ctx->host.h_addr_list[i] = &(ctx->addrs[i * 16]); 656 } 657 } 658 659 660 661 static void 662 _mdns_hostent_add_host(hostent_ctx *ctx, const char *name) 663 { 664 size_t len; 665 int i; 666 667 if (name && (len = strlen(name)) 668 && (HCTX_BUFLEFT(ctx) > len) && (ctx->naliases < MAXALIASES)) { 669 if (len && (name[len - 1] == '.')) { 670 len--; 671 } 672 673 /* skip dupe names */ 674 675 if ((ctx->host.h_name) && !strncmp(ctx->host.h_name, name, len) 676 && (strlen(ctx->host.h_name) == len)) { 677 return; 678 } 679 680 for (i = 0; i < ctx->naliases - 1; i++) { 681 if (!strncmp(ctx->host.h_aliases[i], name, len) 682 && (strlen(ctx->host.h_aliases[i]) == len)) { 683 return; 684 } 685 } 686 687 strncpy(ctx->next, name, len); 688 ctx->next[len] = 0; 689 690 if (ctx->naliases == 0) { 691 ctx->host.h_name = ctx->next; 692 } else { 693 ctx->host.h_aliases[ctx->naliases - 1] = ctx->next; 694 } 695 696 ctx->next += (len + 1); 697 ctx->naliases++; 698 } /* else silently ignore */ 699 } 700 701 702 703 static void 704 _mdns_hostent_add_addr(hostent_ctx *ctx, const void *addr, uint16_t len) 705 { 706 if ((len == ctx->host.h_length) && (ctx->naddrs < MAXADDRS)) { 707 memcpy(ctx->host.h_addr_list[ctx->naddrs++], addr, (size_t)len); 708 } /* else wrong address type or out of room... silently skip */ 709 } 710 711 712 713 static int 714 _mdns_hostent_done(struct getnamaddr *info, hostent_ctx *ctx) 715 { 716 int i; 717 char *ptr = info->buf; 718 size_t len = info->buflen; 719 struct hostent *hp = info->hp; 720 struct hostent *chp = &ctx->host; 721 722 hp->h_length = ctx->host.h_length; 723 hp->h_addrtype = ctx->host.h_addrtype; 724 HENT_ARRAY(hp->h_addr_list, ctx->naddrs, ptr, len); 725 HENT_ARRAY(hp->h_aliases, ctx->naliases - 1, ptr, len); 726 727 for (i = 0; i < ctx->naddrs; i++) 728 HENT_COPY(hp->h_addr_list[i], chp->h_addr_list[i], 729 hp->h_length, ptr, len); 730 731 hp->h_addr_list[ctx->naddrs] = NULL; 732 733 HENT_SCOPY(hp->h_name, chp->h_name, ptr, len); 734 735 for (i = 0; i < ctx->naliases - 1; i++) 736 HENT_SCOPY(hp->h_aliases[i], chp->h_aliases[i], ptr, len); 737 hp->h_aliases[ctx->naliases - 1] = NULL; 738 *info->he = 0; 739 return NS_SUCCESS; 740 nospc: 741 *info->he = NETDB_INTERNAL; 742 errno = ENOSPC; 743 return NS_UNAVAIL; 744 } 745 746 747 748 static void 749 _mdns_addrinfo_cb( 750 DNSServiceRef sdRef, 751 DNSServiceFlags flags, 752 uint32_t interfaceIndex, 753 DNSServiceErrorType errorCode, 754 const char *hostname, 755 const struct sockaddr *address, 756 uint32_t ttl, 757 void *context 758 ) { 759 addrinfo_ctx *ctx = context; 760 struct addrinfo *ai; 761 762 UNUSED(sdRef); 763 UNUSED(interfaceIndex); 764 UNUSED(ttl); 765 766 if (errorCode == kDNSServiceErr_NoError) { 767 if (! (flags & kDNSServiceFlagsMoreComing)) { 768 ctx->cb_ctx.done = true; 769 } 770 771 ai = allocaddrinfo((socklen_t)(address->sa_len)); 772 if (ai) { 773 ai->ai_flags = ctx->start.ai_flags; 774 ai->ai_family = address->sa_family; 775 ai->ai_socktype = ctx->start.ai_socktype; 776 ai->ai_protocol = ctx->start.ai_protocol; 777 memcpy(ai->ai_addr, address, (size_t)(address->sa_len)); 778 779 if ((ctx->start.ai_flags & AI_CANONNAME) && hostname) { 780 ai->ai_canonname = strdup(hostname); 781 if (ai->ai_canonname[strlen(ai->ai_canonname) - 1] == '.') { 782 ai->ai_canonname[strlen(ai->ai_canonname) - 1] = '\0'; 783 } 784 } 785 786 _mdns_addrinfo_add_ai(ctx, ai); 787 } 788 } 789 } 790 791 792 793 static void 794 _mdns_hostent_cb( 795 DNSServiceRef sdRef, 796 DNSServiceFlags flags, 797 uint32_t interfaceIndex, 798 DNSServiceErrorType errorCode, 799 const char *fullname, 800 uint16_t rrtype, 801 uint16_t rrclass, 802 uint16_t rdlen, 803 const void *rdata, 804 uint32_t ttl, 805 void *context 806 ) { 807 hostent_ctx *ctx = (hostent_ctx *)context; 808 char buf[NS_MAXDNAME+1]; 809 810 UNUSED(sdRef); 811 UNUSED(interfaceIndex); 812 UNUSED(rrclass); 813 UNUSED(ttl); 814 815 if (! (flags & kDNSServiceFlagsMoreComing)) { 816 ctx->cb_ctx.done = true; 817 } 818 819 if (errorCode == kDNSServiceErr_NoError) { 820 switch (rrtype) { 821 case kDNSServiceType_PTR: 822 if (!_mdns_rdata2name(rdata, rdlen, buf, sizeof(buf))) { 823 /* corrupt response -- skip */ 824 return; 825 } 826 827 _mdns_hostent_add_host(ctx, buf); 828 break; 829 830 case kDNSServiceType_A: 831 if (ctx->host.h_addrtype == AF_INET) { 832 _mdns_hostent_add_host(ctx, fullname); 833 _mdns_hostent_add_addr(ctx, rdata, rdlen); 834 } 835 break; 836 837 case kDNSServiceType_AAAA: 838 if (ctx->host.h_addrtype == AF_INET6) { 839 _mdns_hostent_add_host(ctx, fullname); 840 _mdns_hostent_add_addr(ctx, rdata, rdlen); 841 } 842 break; 843 } 844 } else if (errorCode == kDNSServiceErr_NoSuchRecord) { 845 ctx->cb_ctx.done = true; 846 } 847 } 848 849 850 851 static void 852 _mdns_eventloop(svc_ref *sr, callback_ctx *ctx, short timeout) 853 { 854 struct pollfd fds; 855 int fd, ret; 856 857 fd = DNSServiceRefSockFD(sr->sdRef); 858 fds.fd = fd; 859 fds.events = POLLRDNORM; 860 861 while (!ctx->done) { 862 ret = poll(&fds, 1, timeout * 1000); 863 if (ret > 0) { 864 DNSServiceProcessResult(sr->sdRef); 865 } else { 866 break; 867 } 868 } 869 } 870 871 872 873 static char * 874 _mdns_rdata2name(const unsigned char *rdata, uint16_t rdlen, char *buf, size_t buflen) 875 { 876 unsigned char l; 877 char *r = buf; 878 879 /* illegal 0-size answer or not enough room for even "." */ 880 if ((!rdlen) || (rdlen < 2)) { 881 return NULL; 882 } 883 884 buflen--; /* reserve space for terminating NUL now */ 885 886 /* special case empty as "." */ 887 if ((rdlen == 1) && (!*rdata)) { 888 strcpy(buf, "."); 889 890 return r; 891 } 892 893 while (rdlen && *rdata) { 894 /* label length byte */ 895 l = *rdata++; rdlen--; 896 897 if (l > 63) { 898 /* compression or bitstrings -- shouldn't happen */ 899 return NULL; 900 } else if (l > buflen) { 901 /* not enough space */ 902 return NULL; 903 } else if (l > rdlen) { 904 /* label shouldn't be longer than remaining rdata */ 905 return NULL; 906 } else if (!l) { 907 /* empty label -- should be done */ 908 if (rdlen) { 909 /* but more left!? */ 910 return NULL; 911 } else { 912 break; 913 } 914 } 915 916 memcpy(buf, rdata, (size_t)l); 917 rdata += l; buf += l; 918 rdlen -= l; buflen -= l; 919 920 /* Another label to come? add a separator */ 921 if (rdlen && *rdata) { 922 if (!buflen) { 923 return NULL; 924 } 925 926 *buf++ = '.'; buflen--; 927 } 928 } 929 930 /* we reserved space above, so we know we have space 931 to add this termination */ 932 933 *buf = '\0'; 934 935 return r; 936 } 937 938 939 940 int 941 search_init(search_iter *iter, const char *name, const char **first) 942 { 943 const char *c = name, *cmp; 944 int dots = 0, enddot = 0; 945 size_t len, cl; 946 947 iter->conf = get_res_conf(); 948 if (!iter->conf) { 949 h_errno = NETDB_INTERNAL; 950 return NS_UNAVAIL; 951 } 952 953 iter->name = name; 954 iter->baselen = 0; 955 iter->abs_first = iter->abs_last = false; 956 iter->next_search = iter->conf->search_domains; 957 958 while (*c) { 959 if (*c == '.') { 960 dots++; 961 enddot = 1; 962 } else { 963 enddot = 0; 964 } 965 c++; 966 } 967 968 if (svc_flags & kDNSServiceFlagsForceMulticast) { 969 if (dots) { 970 iter->next_search = iter->conf->no_search; 971 if ((dots - enddot) == 1) { 972 len = strlen(iter->name); 973 cl = strlen(".local") + enddot; 974 if (len > cl) { 975 cmp = enddot ? ".local." : ".local"; 976 c = iter->name + len - cl; 977 978 if (!strcasecmp(c, cmp)) { 979 iter->abs_first = true; 980 } 981 } 982 } 983 } 984 } else { 985 if (dots >= iter->conf->ndots) { 986 iter->abs_first = true; 987 } else { 988 iter->abs_last = true; 989 } 990 991 if (enddot) { 992 /* absolute; don't search */ 993 iter->next_search = iter->conf->no_search; 994 } 995 } 996 997 *first = search_next(iter); 998 if (!first) { 999 search_done(iter); 1000 h_errno = HOST_NOT_FOUND; 1001 return NS_NOTFOUND; 1002 } 1003 1004 return NS_SUCCESS; 1005 } 1006 1007 1008 1009 const char * 1010 search_next(search_iter *iter) 1011 { 1012 const char *a = NULL; 1013 res_state res; 1014 size_t len; 1015 1016 if (iter->abs_first) { 1017 iter->abs_first = false; 1018 return iter->name; 1019 } 1020 1021 while (*(iter->next_search)) { 1022 if (!iter->baselen) { 1023 iter->baselen = strlcpy(iter->buf, iter->name, sizeof(iter->buf)); 1024 if (iter->baselen >= sizeof(iter->buf) - 1) { 1025 /* original is too long, don't try any search domains */ 1026 iter->next_search = iter->conf->no_search; 1027 break; 1028 } 1029 1030 iter->buf[iter->baselen++] = '.'; 1031 } 1032 1033 len = strlcpy(&(iter->buf[iter->baselen]), 1034 *(iter->next_search), 1035 sizeof(iter->buf) - iter->baselen); 1036 1037 iter->next_search++; 1038 1039 if (len >= sizeof(iter->buf) - iter->baselen) { 1040 /* result was too long */ 1041 continue; 1042 } 1043 1044 return iter->buf; 1045 } 1046 1047 if (iter->abs_last) { 1048 iter->abs_last = false; 1049 return iter->name; 1050 } 1051 1052 return NULL; 1053 } 1054 1055 1056 1057 void 1058 search_done(search_iter *iter) 1059 { 1060 if (iter->conf) { 1061 put_res_conf(iter->conf); 1062 iter->conf = NULL; 1063 } 1064 } 1065 1066 1067 1068 /* 1069 * Is domain appropriate to be in the domain search list? 1070 * For mdnsd, take everything. For multicast_dns, only "local" 1071 * if present. 1072 */ 1073 bool 1074 searchable_domain(char *d) 1075 { 1076 if (!(svc_flags & kDNSServiceFlagsForceMulticast)) { 1077 return true; 1078 } 1079 1080 if (!strcasecmp(d, "local") || !strcasecmp(d, "local.")) { 1081 return true; 1082 } 1083 1084 return false; 1085 } 1086 1087 1088 1089 static void 1090 destroy_svc_ref(svc_ref *sr) 1091 { 1092 /* assumes not on conn list */ 1093 1094 if (sr) { 1095 DNSServiceRefDeallocate(sr->sdRef); 1096 free(sr); 1097 } 1098 } 1099 1100 1101 1102 static svc_ref * 1103 get_svc_ref(void) 1104 { 1105 svc_ref *sr; 1106 1107 LOCK(&conn_list_lock); 1108 1109 if (getpid() != my_pid) { 1110 my_pid = getpid(); 1111 1112 /* 1113 * We forked and kept running. We don't want to share 1114 * connections with the parent or we'll garble each others 1115 * comms, so throw away the parent's list and start over 1116 */ 1117 while ((sr = SLIST_FIRST(&conn_list))) { 1118 SLIST_REMOVE_HEAD(&conn_list, entries); 1119 destroy_svc_ref(sr); 1120 } 1121 1122 sr = NULL; 1123 } else { 1124 /* try to recycle a connection */ 1125 sr = SLIST_FIRST(&conn_list); 1126 if (sr) { 1127 SLIST_REMOVE_HEAD(&conn_list, entries); 1128 conn_count--; 1129 } 1130 } 1131 1132 UNLOCK(&conn_list_lock); 1133 1134 if (!sr) { 1135 /* none available, we need a new one */ 1136 1137 sr = calloc(sizeof(svc_ref), 1); 1138 if (sr) { 1139 if (DNSServiceCreateConnection(&(sr->sdRef))) { 1140 free(sr); 1141 return NULL; 1142 } 1143 1144 if (fcntl(DNSServiceRefSockFD(sr->sdRef), F_SETFD, FD_CLOEXEC) < 0) { 1145 destroy_svc_ref(sr); 1146 sr = NULL; 1147 } 1148 } 1149 } 1150 1151 return sr; 1152 } 1153 1154 1155 1156 static void 1157 put_svc_ref(svc_ref *sr) 1158 { 1159 if (sr) { 1160 LOCK(&conn_list_lock); 1161 1162 sr->uses++; 1163 1164 /* if slow start or aged out, destroy */ 1165 if ((svc_puts++ < SLOWSTART_LOOKUPS) 1166 || (conn_count && (sr->uses > REUSE_TIMES))) { 1167 UNLOCK(&conn_list_lock); 1168 destroy_svc_ref(sr); 1169 return; 1170 } 1171 1172 conn_count++; 1173 1174 SLIST_INSERT_HEAD(&conn_list, sr, entries); 1175 1176 UNLOCK(&conn_list_lock); 1177 } 1178 } 1179 1180 1181 1182 /* 1183 * determine if this is a call we should retry with a fresh 1184 * connection, for example if mdnsd went away and came back. 1185 */ 1186 static bool 1187 retry_query(svc_ref **sr, DNSServiceErrorType err) 1188 { 1189 if ((err == kDNSServiceErr_Unknown) 1190 || (err == kDNSServiceErr_ServiceNotRunning)) { 1191 /* these errors might indicate a stale socket */ 1192 if ((*sr)->uses) { 1193 /* this was an old socket, so kill it and get another */ 1194 destroy_svc_ref(*sr); 1195 *sr = get_svc_ref(); 1196 if (*sr) { 1197 /* we can retry */ 1198 return true; 1199 } 1200 } 1201 } 1202 1203 return false; 1204 } 1205 1206 1207 1208 static void 1209 decref_res_conf(res_conf *rc) 1210 { 1211 rc->refcount--; 1212 1213 if (rc->refcount < 1) { 1214 if ((rc->no_search = rc->search_domains)) { 1215 for (; *(rc->no_search); rc->no_search++) { 1216 free(*(rc->no_search)); 1217 } 1218 1219 free(rc->search_domains); 1220 } 1221 1222 free(rc); 1223 } 1224 } 1225 1226 1227 1228 res_conf * 1229 get_res_conf(void) 1230 { 1231 struct timespec last_change; 1232 res_state res; 1233 res_conf *rc; 1234 1235 LOCK(&res_conf_lock); 1236 1237 /* check if resolver config changed */ 1238 1239 res = __res_get_state(); 1240 if (res) { 1241 res_check(res, &last_change); 1242 if (timespeccmp(&last_config, &last_change, <)) { 1243 if (cur_res_conf) { 1244 decref_res_conf(cur_res_conf); 1245 } 1246 cur_res_conf = new_res_conf(res); 1247 if (cur_res_conf) { 1248 last_config = last_change; 1249 } 1250 } 1251 __res_put_state(res); 1252 } 1253 1254 rc = cur_res_conf; 1255 if (rc) { 1256 rc->refcount++; 1257 } 1258 1259 UNLOCK(&res_conf_lock); 1260 1261 return rc; 1262 } 1263 1264 1265 1266 static void 1267 put_res_conf(res_conf *rc) 1268 { 1269 LOCK(&res_conf_lock); 1270 1271 decref_res_conf(rc); 1272 1273 UNLOCK(&res_conf_lock); 1274 } 1275 1276 1277 1278 static res_conf * 1279 new_res_conf(res_state res) 1280 { 1281 res_conf *rc; 1282 int count = 0; 1283 char **sd, *p; 1284 1285 rc = calloc(sizeof(res_conf), 1); 1286 if (rc) { 1287 rc->refcount = 1; 1288 1289 sd = res->dnsrch; 1290 while (*sd) { 1291 if (searchable_domain(*sd)) { 1292 count++; 1293 } 1294 sd++; 1295 } 1296 1297 rc->search_domains = calloc(sizeof(char *), count + 1); 1298 if (!(rc->search_domains)) { 1299 decref_res_conf(rc); 1300 return NULL; 1301 } 1302 1303 sd = res->dnsrch; 1304 rc->no_search = rc->search_domains; 1305 while (*sd) { 1306 if (searchable_domain(*sd)) { 1307 *(rc->no_search) = p = strdup(*sd); 1308 if (!p) { 1309 decref_res_conf(rc); 1310 return NULL; 1311 } 1312 1313 rc->no_search++; 1314 } 1315 sd++; 1316 } 1317 1318 rc->timeout = res->retrans; 1319 1320 if (svc_flags & kDNSServiceFlagsForceMulticast) { 1321 rc->ndots = 1; 1322 if (rc->timeout > 2) { 1323 rc->timeout = 2; 1324 } 1325 } else { 1326 rc->ndots = res->ndots; 1327 } 1328 } 1329 1330 return rc; 1331 } 1332 1333 1334 1335 static short 1336 get_timeout(void) 1337 { 1338 short timeout = 5; 1339 res_conf *rc; 1340 1341 rc = get_res_conf(); 1342 if (rc) { 1343 timeout = rc->timeout; 1344 put_res_conf(rc); 1345 } 1346 1347 return timeout; 1348 } 1349