Home | History | Annotate | Line # | Download | only in nss
nss_mdnsd.c revision 1.2
      1  1.2  tsarna /*	$NetBSD: nss_mdnsd.c,v 1.2 2009/10/26 00:46:19 tsarna Exp $	*/
      2  1.1  tsarna 
      3  1.1  tsarna /*-
      4  1.1  tsarna  * Copyright (c) 2009 The NetBSD Foundation, Inc.
      5  1.1  tsarna  * All rights reserved.
      6  1.1  tsarna  *
      7  1.1  tsarna  * This code is derived from software contributed to The NetBSD Foundation
      8  1.1  tsarna  * by Tyler C. Sarna
      9  1.1  tsarna  *
     10  1.1  tsarna  * Redistribution and use in source and binary forms, with or without
     11  1.1  tsarna  * modification, are permitted provided that the following conditions
     12  1.1  tsarna  * are met:
     13  1.1  tsarna  * 1. Redistributions of source code must retain the above copyright
     14  1.1  tsarna  *    notice, this list of conditions and the following disclaimer.
     15  1.1  tsarna  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.1  tsarna  *    notice, this list of conditions and the following disclaimer in the
     17  1.1  tsarna  *    documentation and/or other materials provided with the distribution.
     18  1.1  tsarna  *
     19  1.1  tsarna  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  1.1  tsarna  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  1.1  tsarna  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  1.1  tsarna  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  1.1  tsarna  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  1.1  tsarna  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  1.1  tsarna  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  1.1  tsarna  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  1.1  tsarna  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  1.1  tsarna  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  1.1  tsarna  * POSSIBILITY OF SUCH DAMAGE.
     30  1.1  tsarna  */
     31  1.1  tsarna 
     32  1.1  tsarna /*
     33  1.1  tsarna  * Multicast DNS ("Bonjour") hosts name service switch
     34  1.1  tsarna  *
     35  1.1  tsarna  * Documentation links:
     36  1.1  tsarna  *
     37  1.1  tsarna  * http://developer.apple.com/bonjour/
     38  1.1  tsarna  * http://www.multicastdns.org/
     39  1.1  tsarna  * http://www.dns-sd.org/
     40  1.1  tsarna  */
     41  1.1  tsarna 
     42  1.1  tsarna #include <errno.h>
     43  1.1  tsarna #include <nsswitch.h>
     44  1.1  tsarna #include <stdarg.h>
     45  1.1  tsarna #include <stdlib.h>
     46  1.1  tsarna #include <sys/socket.h>
     47  1.1  tsarna #include <sys/param.h>
     48  1.1  tsarna #include <netdb.h>
     49  1.1  tsarna #include <netinet/in.h>
     50  1.1  tsarna #include <arpa/nameser.h>
     51  1.1  tsarna #include <resolv.h>
     52  1.1  tsarna #include <dns_sd.h>
     53  1.1  tsarna #include <poll.h>
     54  1.1  tsarna #include <string.h>
     55  1.1  tsarna #include <stdio.h>
     56  1.1  tsarna #include <stdbool.h>
     57  1.1  tsarna 
     58  1.1  tsarna #ifndef lint
     59  1.1  tsarna #define UNUSED(a)       (void)&a
     60  1.1  tsarna #else
     61  1.1  tsarna #define UNUSED(a)       a = a
     62  1.1  tsarna #endif
     63  1.1  tsarna 
     64  1.1  tsarna #define MAXALIASES      35
     65  1.1  tsarna #define MAXADDRS        35
     66  1.1  tsarna 
     67  1.1  tsarna typedef struct callback_ctx {
     68  1.1  tsarna     bool done;
     69  1.1  tsarna } callback_ctx;
     70  1.1  tsarna 
     71  1.1  tsarna typedef struct hostent_ctx {
     72  1.1  tsarna     callback_ctx cb_ctx;    /* must come first */
     73  1.1  tsarna     struct hostent host;
     74  1.1  tsarna     char *h_addr_ptrs[MAXADDRS + 1];
     75  1.1  tsarna     char *host_aliases[MAXALIASES];
     76  1.1  tsarna     char addrs[MAXADDRS * 16];
     77  1.1  tsarna     char buf[8192], *next;
     78  1.1  tsarna     int naliases, naddrs;
     79  1.1  tsarna } hostent_ctx;
     80  1.1  tsarna 
     81  1.1  tsarna typedef struct addrinfo_ctx {
     82  1.1  tsarna     callback_ctx cb_ctx;    /* must come first */
     83  1.1  tsarna     struct addrinfo start, *last;
     84  1.1  tsarna } addrinfo_ctx;
     85  1.1  tsarna 
     86  1.1  tsarna #define HCTX_BUFLEFT(c) (sizeof((c)->buf) - ((c)->next - (c)->buf))
     87  1.1  tsarna 
     88  1.1  tsarna typedef struct search_iter {
     89  1.1  tsarna     const char     *name;
     90  1.2  tsarna     char           **next_search;
     91  1.1  tsarna     size_t          baselen;
     92  1.1  tsarna     bool            abs_first;
     93  1.1  tsarna     bool            abs_last;
     94  1.1  tsarna     char            buf[MAXHOSTNAMELEN];
     95  1.1  tsarna } search_iter;
     96  1.1  tsarna 
     97  1.1  tsarna static hostent_ctx h_ctx;
     98  1.1  tsarna static DNSServiceFlags svc_flags = 0;
     99  1.1  tsarna static int ndots = 1, timeout = 1000;
    100  1.2  tsarna static char **search_domains, **no_search;
    101  1.1  tsarna 
    102  1.1  tsarna ns_mtab *nss_module_register(const char *, u_int *, nss_module_unregister_fn *);
    103  1.1  tsarna static int load_config(res_state);
    104  1.1  tsarna 
    105  1.1  tsarna static int _mdns_getaddrinfo(void *, void *, va_list);
    106  1.1  tsarna static int _mdns_gethtbyaddr(void *, void *, va_list);
    107  1.1  tsarna static int _mdns_gethtbyname(void *, void *, va_list);
    108  1.1  tsarna 
    109  1.1  tsarna static int _mdns_getaddrinfo_abs(const char *, DNSServiceProtocol,
    110  1.1  tsarna     DNSServiceRef, addrinfo_ctx *);
    111  1.1  tsarna static void _mdns_addrinfo_init(addrinfo_ctx *, const struct addrinfo *);
    112  1.1  tsarna static void _mdns_addrinfo_add_ai(addrinfo_ctx *, struct addrinfo *);
    113  1.1  tsarna static struct addrinfo *_mdns_addrinfo_done(addrinfo_ctx *);
    114  1.1  tsarna 
    115  1.1  tsarna static int _mdns_gethtbyname_abs(const char *, int, DNSServiceRef);
    116  1.1  tsarna static void _mdns_hostent_init(hostent_ctx *, int, int);
    117  1.1  tsarna static void _mdns_hostent_add_host(hostent_ctx *, const char *);
    118  1.1  tsarna static void _mdns_hostent_add_addr(hostent_ctx *, const void *, uint16_t);
    119  1.1  tsarna static struct hostent *_mdns_hostent_done(hostent_ctx *);
    120  1.1  tsarna 
    121  1.1  tsarna static void _mdns_addrinfo_cb(DNSServiceRef, DNSServiceFlags,
    122  1.1  tsarna     uint32_t, DNSServiceErrorType, const char *, const struct sockaddr *,
    123  1.1  tsarna     uint32_t, void *);
    124  1.1  tsarna static void _mdns_hostent_cb(DNSServiceRef, DNSServiceFlags,
    125  1.1  tsarna     uint32_t, DNSServiceErrorType, const char *, uint16_t, uint16_t, uint16_t,
    126  1.1  tsarna     const void *, uint32_t, void *);
    127  1.1  tsarna static void _mdns_eventloop(DNSServiceRef, callback_ctx *);
    128  1.1  tsarna 
    129  1.1  tsarna static char *_mdns_rdata2name(const unsigned char *, uint16_t,
    130  1.1  tsarna     char *, size_t);
    131  1.1  tsarna 
    132  1.1  tsarna void search_init(search_iter *, const char *);
    133  1.1  tsarna const char *search_next(search_iter *);
    134  1.2  tsarna bool searchable_domain(char *);
    135  1.1  tsarna 
    136  1.1  tsarna 
    137  1.1  tsarna 
    138  1.1  tsarna static ns_mtab mtab[] = {
    139  1.1  tsarna     { NSDB_HOSTS, "getaddrinfo",    _mdns_getaddrinfo, NULL },
    140  1.1  tsarna     { NSDB_HOSTS, "gethostbyaddr",  _mdns_gethtbyaddr, NULL },
    141  1.1  tsarna     { NSDB_HOSTS, "gethostbyname",  _mdns_gethtbyname, NULL },
    142  1.1  tsarna };
    143  1.1  tsarna 
    144  1.1  tsarna 
    145  1.1  tsarna 
    146  1.1  tsarna ns_mtab *
    147  1.1  tsarna nss_module_register(const char *source, u_int *nelems,
    148  1.1  tsarna                     nss_module_unregister_fn *unreg)
    149  1.1  tsarna {
    150  1.1  tsarna     res_state res;
    151  1.1  tsarna 
    152  1.1  tsarna     *nelems = sizeof(mtab) / sizeof(mtab[0]);
    153  1.1  tsarna     *unreg = NULL;
    154  1.1  tsarna 
    155  1.1  tsarna     if (!strcmp(source, "multicast_dns")) {
    156  1.1  tsarna         svc_flags = kDNSServiceFlagsForceMulticast;
    157  1.1  tsarna     }
    158  1.1  tsarna 
    159  1.1  tsarna     res = __res_get_state();
    160  1.1  tsarna     if (res) {
    161  1.1  tsarna         load_config(res);
    162  1.1  tsarna         __res_put_state(res);
    163  1.1  tsarna     }
    164  1.1  tsarna 
    165  1.1  tsarna     return mtab;
    166  1.1  tsarna }
    167  1.1  tsarna 
    168  1.1  tsarna 
    169  1.1  tsarna 
    170  1.1  tsarna static int
    171  1.1  tsarna load_config(res_state res)
    172  1.1  tsarna {
    173  1.1  tsarna     int count = 0;
    174  1.1  tsarna     char **sd;
    175  1.1  tsarna 
    176  1.2  tsarna     /* free old search list, if any */
    177  1.2  tsarna 
    178  1.2  tsarna     if ((no_search = search_domains)) {
    179  1.2  tsarna         for (; *no_search; no_search++) {
    180  1.2  tsarna             free(*no_search);
    181  1.2  tsarna         }
    182  1.2  tsarna 
    183  1.2  tsarna         free(search_domains);
    184  1.2  tsarna     }
    185  1.1  tsarna 
    186  1.2  tsarna     /* new search list */
    187  1.2  tsarna 
    188  1.1  tsarna     sd = res->dnsrch;
    189  1.1  tsarna     while (*sd) {
    190  1.2  tsarna         if (searchable_domain(*sd)) {
    191  1.2  tsarna             count++;
    192  1.2  tsarna         }
    193  1.1  tsarna         sd++;
    194  1.1  tsarna     }
    195  1.1  tsarna 
    196  1.2  tsarna     search_domains = calloc(sizeof(char *), count + 1);
    197  1.1  tsarna     if (!search_domains) {
    198  1.1  tsarna         return -1;
    199  1.1  tsarna     }
    200  1.1  tsarna 
    201  1.1  tsarna     sd = res->dnsrch;
    202  1.1  tsarna     no_search = search_domains;
    203  1.1  tsarna     while (*sd) {
    204  1.2  tsarna         if (searchable_domain(*sd)) {
    205  1.2  tsarna             *no_search = strdup(*sd);
    206  1.2  tsarna             no_search++;
    207  1.2  tsarna         }
    208  1.1  tsarna         sd++;
    209  1.1  tsarna     }
    210  1.1  tsarna 
    211  1.2  tsarna     /* retrans in sec to timeout in msec */
    212  1.2  tsarna     timeout = res->retrans * 1000;
    213  1.2  tsarna 
    214  1.2  tsarna     if (svc_flags & kDNSServiceFlagsForceMulticast) {
    215  1.2  tsarna         ndots = 1;
    216  1.2  tsarna         if (timeout > 2000) {
    217  1.2  tsarna             timeout = 2000;
    218  1.2  tsarna         }
    219  1.2  tsarna     } else {
    220  1.2  tsarna         ndots = res->ndots;
    221  1.2  tsarna     }
    222  1.1  tsarna }
    223  1.1  tsarna 
    224  1.1  tsarna 
    225  1.1  tsarna 
    226  1.1  tsarna static int
    227  1.1  tsarna _mdns_getaddrinfo(void *cbrv, void *cbdata, va_list ap)
    228  1.1  tsarna {
    229  1.1  tsarna     const struct addrinfo *pai;
    230  1.1  tsarna     const char *name, *sname;
    231  1.1  tsarna     DNSServiceProtocol proto;
    232  1.1  tsarna     int err = NS_UNAVAIL;
    233  1.1  tsarna     DNSServiceRef sdRef;
    234  1.1  tsarna     addrinfo_ctx ctx;
    235  1.1  tsarna     search_iter iter;
    236  1.1  tsarna 
    237  1.1  tsarna     UNUSED(cbdata);
    238  1.1  tsarna 
    239  1.1  tsarna     name = va_arg(ap, char *);
    240  1.1  tsarna     pai = va_arg(ap, struct addrinfo *);
    241  1.1  tsarna 
    242  1.1  tsarna     switch (pai->ai_family) {
    243  1.1  tsarna     case AF_UNSPEC:
    244  1.1  tsarna         proto = kDNSServiceProtocol_IPv6 | kDNSServiceProtocol_IPv4;
    245  1.1  tsarna         break;
    246  1.1  tsarna 
    247  1.1  tsarna     case AF_INET6:
    248  1.1  tsarna         proto = kDNSServiceProtocol_IPv6;
    249  1.1  tsarna         break;
    250  1.1  tsarna 
    251  1.1  tsarna     case AF_INET:
    252  1.1  tsarna         proto = kDNSServiceProtocol_IPv4;
    253  1.1  tsarna         break;
    254  1.1  tsarna 
    255  1.1  tsarna     default:
    256  1.1  tsarna         h_errno = NO_RECOVERY;
    257  1.1  tsarna         return NS_UNAVAIL;
    258  1.1  tsarna     }
    259  1.1  tsarna 
    260  1.2  tsarna     search_init(&iter, name);
    261  1.2  tsarna     sname = search_next(&iter);
    262  1.2  tsarna 
    263  1.2  tsarna     if (!sname) {
    264  1.2  tsarna         h_errno = HOST_NOT_FOUND;
    265  1.2  tsarna         return NS_NOTFOUND;
    266  1.2  tsarna     }
    267  1.2  tsarna 
    268  1.1  tsarna     /* use one connection for all searches */
    269  1.1  tsarna     if (DNSServiceCreateConnection(&sdRef)) {
    270  1.1  tsarna         h_errno = NETDB_INTERNAL;
    271  1.1  tsarna         return NS_UNAVAIL;
    272  1.1  tsarna     }
    273  1.1  tsarna 
    274  1.1  tsarna     _mdns_addrinfo_init(&ctx, pai);
    275  1.2  tsarna 
    276  1.1  tsarna     while (sname && (err != NS_SUCCESS)) {
    277  1.1  tsarna         err = _mdns_getaddrinfo_abs(sname, proto, sdRef, &ctx);
    278  1.1  tsarna         if (err != NS_SUCCESS) {
    279  1.1  tsarna             sname = search_next(&iter);
    280  1.1  tsarna         }
    281  1.1  tsarna     };
    282  1.1  tsarna 
    283  1.1  tsarna     DNSServiceRefDeallocate(sdRef);
    284  1.1  tsarna 
    285  1.1  tsarna     if (err == NS_SUCCESS) {
    286  1.1  tsarna         *(struct addrinfo **)cbrv = _mdns_addrinfo_done(&ctx);
    287  1.1  tsarna     }
    288  1.1  tsarna 
    289  1.1  tsarna     return err;
    290  1.1  tsarna }
    291  1.1  tsarna 
    292  1.1  tsarna 
    293  1.1  tsarna 
    294  1.1  tsarna static int
    295  1.1  tsarna _mdns_getaddrinfo_abs(const char *name, DNSServiceProtocol proto,
    296  1.1  tsarna     DNSServiceRef sdRef, addrinfo_ctx *ctx)
    297  1.1  tsarna {
    298  1.1  tsarna     DNSServiceErrorType err;
    299  1.1  tsarna 
    300  1.1  tsarna     err = DNSServiceGetAddrInfo(
    301  1.1  tsarna         &sdRef,
    302  1.2  tsarna         svc_flags | kDNSServiceFlagsReturnIntermediates,
    303  1.1  tsarna         kDNSServiceInterfaceIndexAny,
    304  1.1  tsarna         proto,
    305  1.1  tsarna         name,
    306  1.1  tsarna         _mdns_addrinfo_cb,
    307  1.1  tsarna         ctx
    308  1.1  tsarna     );
    309  1.1  tsarna 
    310  1.1  tsarna     if (err) {
    311  1.1  tsarna         h_errno = NETDB_INTERNAL;
    312  1.1  tsarna         return NS_UNAVAIL;
    313  1.1  tsarna     }
    314  1.1  tsarna     _mdns_eventloop(sdRef, (void *)ctx);
    315  1.1  tsarna 
    316  1.1  tsarna     DNSServiceRefDeallocate(sdRef);
    317  1.1  tsarna 
    318  1.1  tsarna     if (ctx->start.ai_next) {
    319  1.1  tsarna         return NS_SUCCESS;
    320  1.1  tsarna     } else {
    321  1.1  tsarna         h_errno = HOST_NOT_FOUND;
    322  1.1  tsarna         return NS_NOTFOUND;
    323  1.1  tsarna     }
    324  1.1  tsarna }
    325  1.1  tsarna 
    326  1.1  tsarna 
    327  1.1  tsarna 
    328  1.1  tsarna static int
    329  1.1  tsarna _mdns_gethtbyaddr(void *cbrv, void *cbdata, va_list ap)
    330  1.1  tsarna {
    331  1.1  tsarna     const unsigned char *addr;
    332  1.1  tsarna     int addrlen, af;
    333  1.1  tsarna     char qbuf[NS_MAXDNAME + 1], *qp, *ep;
    334  1.1  tsarna     int advance, n;
    335  1.1  tsarna     DNSServiceErrorType err;
    336  1.1  tsarna     DNSServiceRef sdRef;
    337  1.1  tsarna 
    338  1.1  tsarna     UNUSED(cbdata);
    339  1.1  tsarna 
    340  1.1  tsarna     addr = va_arg(ap, unsigned char *);
    341  1.1  tsarna     addrlen = va_arg(ap, int);
    342  1.1  tsarna     af = va_arg(ap, int);
    343  1.1  tsarna 
    344  1.1  tsarna     switch (af) {
    345  1.1  tsarna     case AF_INET:
    346  1.2  tsarna         /* if mcast-only don't bother for non-LinkLocal addrs) */
    347  1.2  tsarna         if (svc_flags & kDNSServiceFlagsForceMulticast) {
    348  1.2  tsarna             if ((addr[0] != 169) || (addr[1] != 254)) {
    349  1.2  tsarna                 h_errno = HOST_NOT_FOUND;
    350  1.2  tsarna                 return NS_NOTFOUND;
    351  1.2  tsarna             }
    352  1.2  tsarna         }
    353  1.2  tsarna 
    354  1.1  tsarna         (void)snprintf(qbuf, sizeof(qbuf), "%u.%u.%u.%u.in-addr.arpa",
    355  1.1  tsarna             (addr[3] & 0xff), (addr[2] & 0xff),
    356  1.1  tsarna             (addr[1] & 0xff), (addr[0] & 0xff));
    357  1.1  tsarna         break;
    358  1.1  tsarna 
    359  1.1  tsarna     case AF_INET6:
    360  1.2  tsarna         /* if mcast-only don't bother for non-LinkLocal addrs) */
    361  1.2  tsarna         if (svc_flags & kDNSServiceFlagsForceMulticast) {
    362  1.2  tsarna             if ((addr[0] != 0xfe) || ((addr[1] & 0xc0) != 0x80)) {
    363  1.2  tsarna                 h_errno = HOST_NOT_FOUND;
    364  1.2  tsarna                 return NS_NOTFOUND;
    365  1.2  tsarna             }
    366  1.2  tsarna         }
    367  1.2  tsarna 
    368  1.1  tsarna         qp = qbuf;
    369  1.1  tsarna         ep = qbuf + sizeof(qbuf) - 1;
    370  1.1  tsarna         for (n = IN6ADDRSZ - 1; n >= 0; n--) {
    371  1.1  tsarna             advance = snprintf(qp, (size_t)(ep - qp), "%x.%x.",
    372  1.1  tsarna                 addr[n] & 0xf,
    373  1.1  tsarna                 ((unsigned int)addr[n] >> 4) & 0xf);
    374  1.1  tsarna             if (advance > 0 && qp + advance < ep)
    375  1.1  tsarna                 qp += advance;
    376  1.1  tsarna             else {
    377  1.1  tsarna                 h_errno = NETDB_INTERNAL;
    378  1.1  tsarna                 return NS_NOTFOUND;
    379  1.1  tsarna             }
    380  1.1  tsarna         }
    381  1.1  tsarna         if (strlcat(qbuf, "ip6.arpa", sizeof(qbuf)) >= sizeof(qbuf)) {
    382  1.1  tsarna             h_errno = NETDB_INTERNAL;
    383  1.1  tsarna             return NS_NOTFOUND;
    384  1.1  tsarna         }
    385  1.1  tsarna         break;
    386  1.1  tsarna 
    387  1.1  tsarna     default:
    388  1.1  tsarna         h_errno = NO_RECOVERY;
    389  1.1  tsarna         return NS_UNAVAIL;
    390  1.1  tsarna     }
    391  1.1  tsarna 
    392  1.1  tsarna     _mdns_hostent_init(&h_ctx, af, addrlen);
    393  1.1  tsarna     _mdns_hostent_add_addr(&h_ctx, addr, addrlen);
    394  1.1  tsarna 
    395  1.1  tsarna     err = DNSServiceQueryRecord(
    396  1.1  tsarna         &sdRef,
    397  1.1  tsarna         svc_flags,
    398  1.1  tsarna         kDNSServiceInterfaceIndexAny,
    399  1.1  tsarna         qbuf,
    400  1.1  tsarna         kDNSServiceType_PTR,
    401  1.1  tsarna         kDNSServiceClass_IN,
    402  1.1  tsarna         _mdns_hostent_cb,
    403  1.1  tsarna         &h_ctx
    404  1.1  tsarna     );
    405  1.1  tsarna 
    406  1.1  tsarna     if (err) {
    407  1.1  tsarna         h_errno = NETDB_INTERNAL;
    408  1.1  tsarna         return NS_UNAVAIL;
    409  1.1  tsarna     }
    410  1.1  tsarna 
    411  1.1  tsarna     _mdns_eventloop(sdRef, (void *)&h_ctx);
    412  1.1  tsarna 
    413  1.1  tsarna     DNSServiceRefDeallocate(sdRef);
    414  1.1  tsarna 
    415  1.1  tsarna     if (h_ctx.naliases) {
    416  1.1  tsarna         *(struct hostent **)cbrv = _mdns_hostent_done(&h_ctx);
    417  1.1  tsarna 
    418  1.1  tsarna         return NS_SUCCESS;
    419  1.1  tsarna     } else {
    420  1.1  tsarna         h_errno = HOST_NOT_FOUND;
    421  1.1  tsarna         return NS_NOTFOUND;
    422  1.1  tsarna     }
    423  1.1  tsarna }
    424  1.1  tsarna 
    425  1.1  tsarna 
    426  1.1  tsarna 
    427  1.1  tsarna static int
    428  1.1  tsarna _mdns_gethtbyname(void *cbrv, void *cbdata, va_list ap)
    429  1.1  tsarna {
    430  1.1  tsarna     int namelen, af, addrlen, rrtype, err = NS_UNAVAIL;
    431  1.1  tsarna     const char *name, *sname;
    432  1.1  tsarna     DNSServiceRef sdRef;
    433  1.1  tsarna     search_iter iter;
    434  1.1  tsarna 
    435  1.1  tsarna     UNUSED(cbdata);
    436  1.1  tsarna 
    437  1.1  tsarna     name = va_arg(ap, char *);
    438  1.1  tsarna     namelen = va_arg(ap, int);
    439  1.1  tsarna     af = va_arg(ap, int);
    440  1.1  tsarna 
    441  1.1  tsarna     UNUSED(namelen);
    442  1.1  tsarna 
    443  1.1  tsarna     switch (af) {
    444  1.1  tsarna     case AF_INET:
    445  1.1  tsarna         rrtype = kDNSServiceType_A;
    446  1.1  tsarna         addrlen = 4;
    447  1.1  tsarna         break;
    448  1.1  tsarna 
    449  1.1  tsarna     case AF_INET6:
    450  1.1  tsarna         rrtype = kDNSServiceType_AAAA;
    451  1.1  tsarna         addrlen = 16;
    452  1.1  tsarna         break;
    453  1.1  tsarna 
    454  1.1  tsarna     default:
    455  1.2  tsarna         h_errno = NO_RECOVERY;
    456  1.2  tsarna         return NS_UNAVAIL;
    457  1.2  tsarna     }
    458  1.2  tsarna 
    459  1.2  tsarna     search_init(&iter, name);
    460  1.2  tsarna     sname = search_next(&iter);
    461  1.2  tsarna 
    462  1.2  tsarna     if (!sname) {
    463  1.2  tsarna         h_errno = HOST_NOT_FOUND;
    464  1.1  tsarna         return NS_NOTFOUND;
    465  1.1  tsarna     }
    466  1.1  tsarna 
    467  1.1  tsarna     /* use one connection for all searches */
    468  1.1  tsarna     if (DNSServiceCreateConnection(&sdRef)) {
    469  1.1  tsarna         h_errno = NETDB_INTERNAL;
    470  1.1  tsarna         return NS_UNAVAIL;
    471  1.1  tsarna     }
    472  1.1  tsarna 
    473  1.1  tsarna     _mdns_hostent_init(&h_ctx, af, addrlen);
    474  1.2  tsarna 
    475  1.1  tsarna     while (sname && (err != NS_SUCCESS)) {
    476  1.1  tsarna         err = _mdns_gethtbyname_abs(sname, rrtype, sdRef);
    477  1.1  tsarna         if (err != NS_SUCCESS) {
    478  1.1  tsarna             sname = search_next(&iter);
    479  1.1  tsarna         }
    480  1.1  tsarna     };
    481  1.1  tsarna 
    482  1.1  tsarna     DNSServiceRefDeallocate(sdRef);
    483  1.1  tsarna 
    484  1.1  tsarna     if (err == NS_SUCCESS) {
    485  1.1  tsarna         _mdns_hostent_add_host(&h_ctx, sname);
    486  1.1  tsarna         _mdns_hostent_add_host(&h_ctx, name);
    487  1.1  tsarna         *(struct hostent **)cbrv = _mdns_hostent_done(&h_ctx);
    488  1.1  tsarna     }
    489  1.1  tsarna 
    490  1.1  tsarna     return err;
    491  1.1  tsarna }
    492  1.1  tsarna 
    493  1.1  tsarna 
    494  1.1  tsarna 
    495  1.1  tsarna static int
    496  1.1  tsarna _mdns_gethtbyname_abs(const char *name, int rrtype, DNSServiceRef sdRef)
    497  1.1  tsarna {
    498  1.1  tsarna     DNSServiceErrorType err;
    499  1.1  tsarna 
    500  1.1  tsarna     err = DNSServiceQueryRecord(
    501  1.1  tsarna         &sdRef,
    502  1.2  tsarna         svc_flags | kDNSServiceFlagsReturnIntermediates,
    503  1.1  tsarna         kDNSServiceInterfaceIndexAny,
    504  1.1  tsarna         name,
    505  1.1  tsarna         rrtype,
    506  1.1  tsarna         kDNSServiceClass_IN,
    507  1.1  tsarna         _mdns_hostent_cb,
    508  1.1  tsarna         &h_ctx
    509  1.1  tsarna     );
    510  1.1  tsarna 
    511  1.1  tsarna     if (err) {
    512  1.1  tsarna         h_errno = NETDB_INTERNAL;
    513  1.1  tsarna         return NS_UNAVAIL;
    514  1.1  tsarna     }
    515  1.1  tsarna 
    516  1.1  tsarna     _mdns_eventloop(sdRef, (void *)&h_ctx);
    517  1.1  tsarna 
    518  1.1  tsarna     DNSServiceRefDeallocate(sdRef);
    519  1.1  tsarna 
    520  1.1  tsarna     if (h_ctx.naddrs) {
    521  1.1  tsarna         return NS_SUCCESS;
    522  1.1  tsarna     } else {
    523  1.1  tsarna         h_errno = HOST_NOT_FOUND;
    524  1.1  tsarna         return NS_NOTFOUND;
    525  1.1  tsarna     }
    526  1.1  tsarna }
    527  1.1  tsarna 
    528  1.1  tsarna 
    529  1.1  tsarna 
    530  1.1  tsarna static void
    531  1.1  tsarna _mdns_addrinfo_init(addrinfo_ctx *ctx, const struct addrinfo *ai)
    532  1.1  tsarna {
    533  1.1  tsarna     ctx->cb_ctx.done = false;
    534  1.1  tsarna     ctx->start = *ai;
    535  1.1  tsarna     ctx->start.ai_next = NULL;
    536  1.1  tsarna     ctx->start.ai_canonname = NULL;
    537  1.1  tsarna     ctx->last = &(ctx->start);
    538  1.1  tsarna }
    539  1.1  tsarna 
    540  1.1  tsarna 
    541  1.1  tsarna 
    542  1.1  tsarna static void
    543  1.1  tsarna _mdns_addrinfo_add_ai(addrinfo_ctx *ctx, struct addrinfo *ai)
    544  1.1  tsarna {
    545  1.1  tsarna     ctx->last->ai_next = ai;
    546  1.1  tsarna     while (ctx->last->ai_next)
    547  1.1  tsarna         ctx->last = ctx->last->ai_next;
    548  1.1  tsarna }
    549  1.1  tsarna 
    550  1.1  tsarna 
    551  1.1  tsarna 
    552  1.1  tsarna static struct addrinfo *
    553  1.1  tsarna _mdns_addrinfo_done(addrinfo_ctx *ctx)
    554  1.1  tsarna {
    555  1.1  tsarna     struct addrinfo head, *t, *p;
    556  1.1  tsarna 
    557  1.1  tsarna     /* sort v6 up */
    558  1.1  tsarna 
    559  1.1  tsarna     t = &head;
    560  1.1  tsarna     p = ctx->start.ai_next;
    561  1.1  tsarna 
    562  1.1  tsarna     while (p->ai_next) {
    563  1.1  tsarna         if (p->ai_next->ai_family == AF_INET6) {
    564  1.1  tsarna             t->ai_next = p->ai_next;
    565  1.1  tsarna             t = t->ai_next;
    566  1.1  tsarna             p->ai_next = p->ai_next->ai_next;
    567  1.1  tsarna         } else {
    568  1.1  tsarna             p = p->ai_next;
    569  1.1  tsarna         }
    570  1.1  tsarna     }
    571  1.1  tsarna 
    572  1.1  tsarna     /* add rest of list and reset start to the new list */
    573  1.1  tsarna 
    574  1.1  tsarna     t->ai_next = ctx->start.ai_next;
    575  1.1  tsarna     ctx->start.ai_next = head.ai_next;
    576  1.1  tsarna 
    577  1.1  tsarna     return ctx->start.ai_next;
    578  1.1  tsarna }
    579  1.1  tsarna 
    580  1.1  tsarna 
    581  1.1  tsarna 
    582  1.1  tsarna static void
    583  1.1  tsarna _mdns_hostent_init(hostent_ctx *ctx, int af, int addrlen)
    584  1.1  tsarna {
    585  1.1  tsarna     int i;
    586  1.1  tsarna 
    587  1.1  tsarna     ctx->cb_ctx.done = false;
    588  1.1  tsarna     ctx->naliases = ctx->naddrs = 0;
    589  1.1  tsarna     ctx->next = ctx->buf;
    590  1.1  tsarna 
    591  1.1  tsarna     ctx->host.h_aliases = ctx->host_aliases;
    592  1.1  tsarna     ctx->host.h_addr_list = ctx->h_addr_ptrs;
    593  1.1  tsarna     ctx->host.h_name = ctx->host.h_aliases[0] = NULL;
    594  1.1  tsarna     ctx->host.h_addrtype = af;
    595  1.1  tsarna     ctx->host.h_length = addrlen;
    596  1.1  tsarna 
    597  1.1  tsarna     for (i = 0; i < MAXADDRS; i++) {
    598  1.1  tsarna         ctx->host.h_addr_list[i] = &(ctx->addrs[i * 16]);
    599  1.1  tsarna     }
    600  1.1  tsarna }
    601  1.1  tsarna 
    602  1.1  tsarna 
    603  1.1  tsarna 
    604  1.1  tsarna static void
    605  1.1  tsarna _mdns_hostent_add_host(hostent_ctx *ctx, const char *name)
    606  1.1  tsarna {
    607  1.1  tsarna     size_t len;
    608  1.1  tsarna     int i;
    609  1.1  tsarna 
    610  1.1  tsarna     if (name && (len = strlen(name))
    611  1.1  tsarna     && (HCTX_BUFLEFT(ctx) > len) && (ctx->naliases < MAXALIASES)) {
    612  1.1  tsarna         if (len && (name[len - 1] == '.')) {
    613  1.1  tsarna             len--;
    614  1.1  tsarna         }
    615  1.1  tsarna 
    616  1.1  tsarna         /* skip dupe names */
    617  1.1  tsarna 
    618  1.1  tsarna         if ((ctx->host.h_name) && !strncmp(ctx->host.h_name, name, len)
    619  1.1  tsarna         && (strlen(ctx->host.h_name) == len)) {
    620  1.1  tsarna             return;
    621  1.1  tsarna         }
    622  1.1  tsarna 
    623  1.1  tsarna         for (i = 0; i < ctx->naliases - 1; i++) {
    624  1.1  tsarna             if (!strncmp(ctx->host.h_aliases[i], name, len)
    625  1.1  tsarna             && (strlen(ctx->host.h_aliases[i]) == len)) {
    626  1.1  tsarna                 return;
    627  1.1  tsarna             }
    628  1.1  tsarna         }
    629  1.1  tsarna 
    630  1.1  tsarna         strncpy(ctx->next, name, len);
    631  1.1  tsarna         ctx->next[len] = 0;
    632  1.1  tsarna 
    633  1.1  tsarna         if (ctx->naliases == 0) {
    634  1.1  tsarna             ctx->host.h_name = ctx->next;
    635  1.1  tsarna         } else {
    636  1.1  tsarna             ctx->host.h_aliases[ctx->naliases - 1] = ctx->next;
    637  1.1  tsarna         }
    638  1.1  tsarna 
    639  1.1  tsarna         ctx->next += (len + 1);
    640  1.1  tsarna         ctx->naliases++;
    641  1.1  tsarna     } /* else silently ignore */
    642  1.1  tsarna }
    643  1.1  tsarna 
    644  1.1  tsarna 
    645  1.1  tsarna 
    646  1.1  tsarna static void
    647  1.1  tsarna _mdns_hostent_add_addr(hostent_ctx *ctx, const void *addr, uint16_t len)
    648  1.1  tsarna {
    649  1.1  tsarna     if ((len == ctx->host.h_length) && (ctx->naddrs < MAXADDRS)) {
    650  1.1  tsarna         memcpy(ctx->host.h_addr_list[ctx->naddrs++], addr, (size_t)len);
    651  1.1  tsarna     } /* else wrong address type or out of room... silently skip */
    652  1.1  tsarna }
    653  1.1  tsarna 
    654  1.1  tsarna 
    655  1.1  tsarna 
    656  1.1  tsarna static struct hostent *
    657  1.1  tsarna _mdns_hostent_done(hostent_ctx *ctx)
    658  1.1  tsarna {
    659  1.1  tsarna     if (ctx->naliases) {
    660  1.1  tsarna         /* terminate array */
    661  1.1  tsarna         ctx->host.h_aliases[ctx->naliases - 1] = NULL;
    662  1.1  tsarna         ctx->host.h_addr_list[ctx->naddrs] = NULL;
    663  1.1  tsarna     }
    664  1.1  tsarna 
    665  1.1  tsarna     return &(ctx->host);
    666  1.1  tsarna }
    667  1.1  tsarna 
    668  1.1  tsarna 
    669  1.1  tsarna 
    670  1.1  tsarna static void
    671  1.1  tsarna _mdns_addrinfo_cb(
    672  1.1  tsarna     DNSServiceRef           sdRef,
    673  1.1  tsarna     DNSServiceFlags         flags,
    674  1.1  tsarna     uint32_t                interfaceIndex,
    675  1.1  tsarna     DNSServiceErrorType     errorCode,
    676  1.1  tsarna     const char             *hostname,
    677  1.1  tsarna     const struct sockaddr  *address,
    678  1.1  tsarna     uint32_t                ttl,
    679  1.1  tsarna     void                   *context
    680  1.1  tsarna ) {
    681  1.1  tsarna     addrinfo_ctx *ctx = context;
    682  1.1  tsarna     struct addrinfo *ai;
    683  1.1  tsarna 
    684  1.1  tsarna     UNUSED(sdRef);
    685  1.1  tsarna     UNUSED(interfaceIndex);
    686  1.1  tsarna     UNUSED(ttl);
    687  1.1  tsarna 
    688  1.1  tsarna     if (errorCode == kDNSServiceErr_NoError) {
    689  1.1  tsarna         if (! (flags & kDNSServiceFlagsMoreComing)) {
    690  1.1  tsarna             ctx->cb_ctx.done = true;
    691  1.1  tsarna         }
    692  1.1  tsarna 
    693  1.1  tsarna         ai = allocaddrinfo((socklen_t)(address->sa_len));
    694  1.1  tsarna         if (ai) {
    695  1.1  tsarna             ai->ai_flags = ctx->start.ai_flags;
    696  1.1  tsarna             ai->ai_family = address->sa_family;
    697  1.1  tsarna             ai->ai_socktype = ctx->start.ai_socktype;
    698  1.1  tsarna             ai->ai_protocol = ctx->start.ai_protocol;
    699  1.1  tsarna             memcpy(ai->ai_addr, address, (size_t)(address->sa_len));
    700  1.1  tsarna 
    701  1.1  tsarna             if ((ctx->start.ai_flags & AI_CANONNAME) && hostname) {
    702  1.1  tsarna                 ai->ai_canonname = strdup(hostname);
    703  1.1  tsarna                 if (ai->ai_canonname[strlen(ai->ai_canonname) - 1] == '.') {
    704  1.1  tsarna                     ai->ai_canonname[strlen(ai->ai_canonname) - 1] = '\0';
    705  1.1  tsarna                 }
    706  1.1  tsarna             }
    707  1.1  tsarna 
    708  1.1  tsarna             _mdns_addrinfo_add_ai(ctx, ai);
    709  1.1  tsarna         }
    710  1.1  tsarna     }
    711  1.1  tsarna }
    712  1.1  tsarna 
    713  1.1  tsarna 
    714  1.1  tsarna 
    715  1.1  tsarna static void
    716  1.1  tsarna _mdns_hostent_cb(
    717  1.1  tsarna     DNSServiceRef           sdRef,
    718  1.1  tsarna     DNSServiceFlags         flags,
    719  1.1  tsarna     uint32_t                interfaceIndex,
    720  1.1  tsarna     DNSServiceErrorType     errorCode,
    721  1.1  tsarna     const char             *fullname,
    722  1.1  tsarna     uint16_t                rrtype,
    723  1.1  tsarna     uint16_t                rrclass,
    724  1.1  tsarna     uint16_t                rdlen,
    725  1.1  tsarna     const void             *rdata,
    726  1.1  tsarna     uint32_t                ttl,
    727  1.1  tsarna     void                   *context
    728  1.1  tsarna ) {
    729  1.1  tsarna     hostent_ctx *ctx = (hostent_ctx *)context;
    730  1.1  tsarna     char buf[NS_MAXDNAME+1];
    731  1.1  tsarna 
    732  1.1  tsarna     UNUSED(sdRef);
    733  1.1  tsarna     UNUSED(interfaceIndex);
    734  1.1  tsarna     UNUSED(rrclass);
    735  1.1  tsarna     UNUSED(ttl);
    736  1.1  tsarna 
    737  1.1  tsarna     if (! (flags & kDNSServiceFlagsMoreComing)) {
    738  1.1  tsarna         ctx->cb_ctx.done = true;
    739  1.1  tsarna     }
    740  1.1  tsarna 
    741  1.1  tsarna     if (errorCode == kDNSServiceErr_NoError) {
    742  1.1  tsarna         switch (rrtype) {
    743  1.1  tsarna         case kDNSServiceType_PTR:
    744  1.1  tsarna             if (!_mdns_rdata2name(rdata, rdlen, buf, sizeof(buf))) {
    745  1.1  tsarna                 /* corrupt response -- skip */
    746  1.1  tsarna                 return;
    747  1.1  tsarna             }
    748  1.1  tsarna 
    749  1.1  tsarna             _mdns_hostent_add_host(ctx, buf);
    750  1.1  tsarna             break;
    751  1.1  tsarna 
    752  1.1  tsarna         case kDNSServiceType_A:
    753  1.1  tsarna             if (ctx->host.h_addrtype == AF_INET) {
    754  1.1  tsarna                 _mdns_hostent_add_host(ctx, fullname);
    755  1.1  tsarna                 _mdns_hostent_add_addr(ctx, rdata, rdlen);
    756  1.1  tsarna             }
    757  1.1  tsarna             break;
    758  1.1  tsarna 
    759  1.1  tsarna         case kDNSServiceType_AAAA:
    760  1.1  tsarna             if (ctx->host.h_addrtype == AF_INET6) {
    761  1.1  tsarna                 _mdns_hostent_add_host(ctx, fullname);
    762  1.1  tsarna                 _mdns_hostent_add_addr(ctx, rdata, rdlen);
    763  1.1  tsarna             }
    764  1.1  tsarna             break;
    765  1.1  tsarna         }
    766  1.2  tsarna     } else if (errorCode == kDNSServiceErr_NoSuchRecord) {
    767  1.2  tsarna         ctx->cb_ctx.done = true;
    768  1.1  tsarna     }
    769  1.1  tsarna }
    770  1.1  tsarna 
    771  1.1  tsarna 
    772  1.1  tsarna 
    773  1.1  tsarna static void
    774  1.1  tsarna _mdns_eventloop(DNSServiceRef sdRef, callback_ctx *ctx)
    775  1.1  tsarna {
    776  1.1  tsarna     struct pollfd fds;
    777  1.1  tsarna     int fd, ret;
    778  1.1  tsarna 
    779  1.1  tsarna     fd = DNSServiceRefSockFD(sdRef);
    780  1.1  tsarna     fds.fd = fd;
    781  1.1  tsarna     fds.events = POLLRDNORM;
    782  1.1  tsarna 
    783  1.1  tsarna     while (!ctx->done) {
    784  1.1  tsarna         ret = poll(&fds, 1, timeout);
    785  1.1  tsarna         if (ret > 0) {
    786  1.1  tsarna             DNSServiceProcessResult(sdRef);
    787  1.1  tsarna         } else {
    788  1.1  tsarna             break;
    789  1.1  tsarna         }
    790  1.1  tsarna     }
    791  1.1  tsarna }
    792  1.1  tsarna 
    793  1.1  tsarna 
    794  1.1  tsarna 
    795  1.1  tsarna static char *
    796  1.1  tsarna _mdns_rdata2name(const unsigned char *rdata, uint16_t rdlen, char *buf, size_t buflen)
    797  1.1  tsarna {
    798  1.1  tsarna     unsigned char l;
    799  1.1  tsarna     char *r = buf;
    800  1.1  tsarna 
    801  1.1  tsarna     /* illegal 0-size answer or not enough room for even "." */
    802  1.1  tsarna     if ((!rdlen) || (rdlen < 2)) {
    803  1.1  tsarna         return NULL;
    804  1.1  tsarna     }
    805  1.1  tsarna 
    806  1.1  tsarna     buflen--; /* reserve space for terminating NUL now */
    807  1.1  tsarna 
    808  1.1  tsarna     /* special case empty as "." */
    809  1.1  tsarna     if ((rdlen == 1) && (!*rdata)) {
    810  1.1  tsarna         strcpy(buf, ".");
    811  1.1  tsarna 
    812  1.1  tsarna         return r;
    813  1.1  tsarna     }
    814  1.1  tsarna 
    815  1.1  tsarna     while (rdlen && *rdata) {
    816  1.1  tsarna         /* label length byte */
    817  1.1  tsarna         l = *rdata++; rdlen--;
    818  1.1  tsarna 
    819  1.1  tsarna         if (l > 63) {
    820  1.1  tsarna             /* compression or bitstrings -- shouldn't happen */
    821  1.1  tsarna             return NULL;
    822  1.1  tsarna         } else if (l > buflen) {
    823  1.1  tsarna             /* not enough space */
    824  1.1  tsarna             return NULL;
    825  1.1  tsarna         } else if (l > rdlen) {
    826  1.1  tsarna             /* label shouldn't be longer than remaining rdata */
    827  1.1  tsarna             return NULL;
    828  1.1  tsarna         } else if (!l) {
    829  1.1  tsarna             /* empty label -- should be done */
    830  1.1  tsarna             if (rdlen) {
    831  1.1  tsarna                 /* but more left!? */
    832  1.1  tsarna                 return NULL;
    833  1.1  tsarna             } else {
    834  1.1  tsarna                 break;
    835  1.1  tsarna             }
    836  1.1  tsarna         }
    837  1.1  tsarna 
    838  1.1  tsarna         memcpy(buf, rdata, (size_t)l);
    839  1.1  tsarna         rdata += l; buf += l;
    840  1.1  tsarna         rdlen -= l; buflen -= l;
    841  1.1  tsarna 
    842  1.1  tsarna         /* Another label to come? add a separator */
    843  1.1  tsarna         if (rdlen && *rdata) {
    844  1.1  tsarna             if (!buflen) {
    845  1.1  tsarna                 return NULL;
    846  1.1  tsarna             }
    847  1.1  tsarna 
    848  1.1  tsarna             *buf++ = '.'; buflen--;
    849  1.1  tsarna         }
    850  1.1  tsarna     }
    851  1.1  tsarna 
    852  1.1  tsarna     /* we reserved space above, so we know we have space
    853  1.1  tsarna        to add this termination */
    854  1.1  tsarna 
    855  1.1  tsarna     *buf = '\0';
    856  1.1  tsarna 
    857  1.1  tsarna     return r;
    858  1.1  tsarna }
    859  1.1  tsarna 
    860  1.1  tsarna 
    861  1.1  tsarna 
    862  1.1  tsarna void
    863  1.1  tsarna search_init(search_iter *iter, const char *name)
    864  1.1  tsarna {
    865  1.2  tsarna     const char *c = name, *cmp;
    866  1.2  tsarna     int dots = 0, enddot = 0;
    867  1.2  tsarna     size_t len, cl;
    868  1.1  tsarna 
    869  1.1  tsarna     iter->name = name;
    870  1.1  tsarna     iter->baselen = 0;
    871  1.2  tsarna     iter->abs_first = iter->abs_last = false;
    872  1.2  tsarna     iter->next_search = search_domains;
    873  1.1  tsarna 
    874  1.1  tsarna     while (*c) {
    875  1.1  tsarna         if (*c == '.') {
    876  1.1  tsarna             dots++;
    877  1.2  tsarna             enddot = 1;
    878  1.1  tsarna         } else {
    879  1.2  tsarna             enddot = 0;
    880  1.1  tsarna         }
    881  1.1  tsarna         c++;
    882  1.1  tsarna     }
    883  1.1  tsarna 
    884  1.2  tsarna     if (svc_flags & kDNSServiceFlagsForceMulticast) {
    885  1.2  tsarna         if (dots) {
    886  1.2  tsarna             iter->next_search = no_search;
    887  1.2  tsarna             if ((dots - enddot) == 1) {
    888  1.2  tsarna                 len = strlen(iter->name);
    889  1.2  tsarna                 cl = strlen(".local") + enddot;
    890  1.2  tsarna                 if (len > cl) {
    891  1.2  tsarna                     cmp = enddot ? ".local." : ".local";
    892  1.2  tsarna                     c = iter->name + len - cl;
    893  1.2  tsarna 
    894  1.2  tsarna                     if (!strcasecmp(c, cmp)) {
    895  1.2  tsarna                         iter->abs_first = true;
    896  1.2  tsarna                     }
    897  1.2  tsarna                 }
    898  1.2  tsarna             }
    899  1.2  tsarna         }
    900  1.1  tsarna     } else {
    901  1.2  tsarna         if (dots >= ndots) {
    902  1.2  tsarna             iter->abs_first = true;
    903  1.2  tsarna         } else {
    904  1.2  tsarna             iter->abs_last = true;
    905  1.2  tsarna         }
    906  1.1  tsarna 
    907  1.2  tsarna         if (enddot) {
    908  1.2  tsarna             /* absolute; don't search */
    909  1.2  tsarna             iter->next_search = no_search;
    910  1.2  tsarna         }
    911  1.1  tsarna     }
    912  1.1  tsarna }
    913  1.1  tsarna 
    914  1.1  tsarna 
    915  1.1  tsarna 
    916  1.1  tsarna const char *
    917  1.1  tsarna search_next(search_iter *iter)
    918  1.1  tsarna {
    919  1.1  tsarna     const char *a = NULL;
    920  1.1  tsarna     res_state res;
    921  1.1  tsarna     size_t len;
    922  1.1  tsarna 
    923  1.1  tsarna     if (iter->abs_first) {
    924  1.1  tsarna         iter->abs_first = false;
    925  1.1  tsarna         return iter->name;
    926  1.1  tsarna     }
    927  1.1  tsarna 
    928  1.2  tsarna     while (*(iter->next_search)) {
    929  1.2  tsarna         if (!iter->baselen) {
    930  1.2  tsarna             iter->baselen = strlcpy(iter->buf, iter->name, sizeof(iter->buf));
    931  1.2  tsarna             if (iter->baselen >= sizeof(iter->buf) - 1) {
    932  1.2  tsarna                 /* original is too long, don't try any search domains */
    933  1.2  tsarna                 iter->next_search = no_search;
    934  1.2  tsarna                 break;
    935  1.1  tsarna             }
    936  1.2  tsarna 
    937  1.2  tsarna             iter->buf[iter->baselen++] = '.';
    938  1.2  tsarna         }
    939  1.2  tsarna 
    940  1.2  tsarna         len = strlcpy(&(iter->buf[iter->baselen]),
    941  1.2  tsarna             *(iter->next_search),
    942  1.2  tsarna             sizeof(iter->buf) - iter->baselen);
    943  1.2  tsarna 
    944  1.2  tsarna         iter->next_search++;
    945  1.2  tsarna 
    946  1.2  tsarna         if (len >= sizeof(iter->buf) - iter->baselen) {
    947  1.2  tsarna             /* result was too long */
    948  1.2  tsarna             continue;
    949  1.1  tsarna         }
    950  1.2  tsarna 
    951  1.2  tsarna         return iter->buf;
    952  1.1  tsarna     }
    953  1.1  tsarna 
    954  1.1  tsarna     if (iter->abs_last) {
    955  1.1  tsarna         iter->abs_last = false;
    956  1.1  tsarna         return iter->name;
    957  1.1  tsarna     }
    958  1.1  tsarna 
    959  1.1  tsarna     return NULL;
    960  1.1  tsarna }
    961  1.2  tsarna 
    962  1.2  tsarna 
    963  1.2  tsarna 
    964  1.2  tsarna /*
    965  1.2  tsarna  * Is domain appropriate to be in the domain search list?
    966  1.2  tsarna  * For mdnsd, take everything. For multicast_dns, only "local"
    967  1.2  tsarna  * if present.
    968  1.2  tsarna  */
    969  1.2  tsarna bool
    970  1.2  tsarna searchable_domain(char *d)
    971  1.2  tsarna {
    972  1.2  tsarna     if (!(svc_flags & kDNSServiceFlagsForceMulticast)) {
    973  1.2  tsarna         return true;
    974  1.2  tsarna     }
    975  1.2  tsarna 
    976  1.2  tsarna     if (!strcasecmp(d, "local") || !strcasecmp(d, "local.")) {
    977  1.2  tsarna         return true;
    978  1.2  tsarna     }
    979  1.2  tsarna 
    980  1.2  tsarna     return false;
    981  1.2  tsarna }
    982