Home | History | Annotate | Line # | Download | only in nss
nss_mdnsd.c revision 1.1
      1  1.1  tsarna /*	$NetBSD: nss_mdnsd.c,v 1.1 2009/10/25 00:17:06 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_domain {
     89  1.1  tsarna     const char *name;
     90  1.1  tsarna     bool        enabled;
     91  1.1  tsarna } search_domain;
     92  1.1  tsarna 
     93  1.1  tsarna typedef struct search_iter {
     94  1.1  tsarna     const char     *name;
     95  1.1  tsarna     search_domain  *next_search;
     96  1.1  tsarna     size_t          baselen;
     97  1.1  tsarna     bool            abs_first;
     98  1.1  tsarna     bool            abs_last;
     99  1.1  tsarna     char            buf[MAXHOSTNAMELEN];
    100  1.1  tsarna } search_iter;
    101  1.1  tsarna 
    102  1.1  tsarna static hostent_ctx h_ctx;
    103  1.1  tsarna static DNSServiceFlags svc_flags = 0;
    104  1.1  tsarna static int ndots = 1, timeout = 1000;
    105  1.1  tsarna static search_domain *search_domains, *no_search;
    106  1.1  tsarna 
    107  1.1  tsarna ns_mtab *nss_module_register(const char *, u_int *, nss_module_unregister_fn *);
    108  1.1  tsarna static int load_config(res_state);
    109  1.1  tsarna 
    110  1.1  tsarna static int _mdns_getaddrinfo(void *, void *, va_list);
    111  1.1  tsarna static int _mdns_gethtbyaddr(void *, void *, va_list);
    112  1.1  tsarna static int _mdns_gethtbyname(void *, void *, va_list);
    113  1.1  tsarna 
    114  1.1  tsarna static int _mdns_getaddrinfo_abs(const char *, DNSServiceProtocol,
    115  1.1  tsarna     DNSServiceRef, addrinfo_ctx *);
    116  1.1  tsarna static void _mdns_addrinfo_init(addrinfo_ctx *, const struct addrinfo *);
    117  1.1  tsarna static void _mdns_addrinfo_add_ai(addrinfo_ctx *, struct addrinfo *);
    118  1.1  tsarna static struct addrinfo *_mdns_addrinfo_done(addrinfo_ctx *);
    119  1.1  tsarna 
    120  1.1  tsarna static int _mdns_gethtbyname_abs(const char *, int, DNSServiceRef);
    121  1.1  tsarna static void _mdns_hostent_init(hostent_ctx *, int, int);
    122  1.1  tsarna static void _mdns_hostent_add_host(hostent_ctx *, const char *);
    123  1.1  tsarna static void _mdns_hostent_add_addr(hostent_ctx *, const void *, uint16_t);
    124  1.1  tsarna static struct hostent *_mdns_hostent_done(hostent_ctx *);
    125  1.1  tsarna 
    126  1.1  tsarna static void _mdns_addrinfo_cb(DNSServiceRef, DNSServiceFlags,
    127  1.1  tsarna     uint32_t, DNSServiceErrorType, const char *, const struct sockaddr *,
    128  1.1  tsarna     uint32_t, void *);
    129  1.1  tsarna static void _mdns_hostent_cb(DNSServiceRef, DNSServiceFlags,
    130  1.1  tsarna     uint32_t, DNSServiceErrorType, const char *, uint16_t, uint16_t, uint16_t,
    131  1.1  tsarna     const void *, uint32_t, void *);
    132  1.1  tsarna static void _mdns_eventloop(DNSServiceRef, callback_ctx *);
    133  1.1  tsarna 
    134  1.1  tsarna static char *_mdns_rdata2name(const unsigned char *, uint16_t,
    135  1.1  tsarna     char *, size_t);
    136  1.1  tsarna 
    137  1.1  tsarna void search_init(search_iter *, const char *);
    138  1.1  tsarna const char *search_next(search_iter *);
    139  1.1  tsarna 
    140  1.1  tsarna 
    141  1.1  tsarna 
    142  1.1  tsarna static ns_mtab mtab[] = {
    143  1.1  tsarna     { NSDB_HOSTS, "getaddrinfo",    _mdns_getaddrinfo, NULL },
    144  1.1  tsarna     { NSDB_HOSTS, "gethostbyaddr",  _mdns_gethtbyaddr, NULL },
    145  1.1  tsarna     { NSDB_HOSTS, "gethostbyname",  _mdns_gethtbyname, NULL },
    146  1.1  tsarna };
    147  1.1  tsarna 
    148  1.1  tsarna 
    149  1.1  tsarna 
    150  1.1  tsarna ns_mtab *
    151  1.1  tsarna nss_module_register(const char *source, u_int *nelems,
    152  1.1  tsarna                     nss_module_unregister_fn *unreg)
    153  1.1  tsarna {
    154  1.1  tsarna     res_state res;
    155  1.1  tsarna 
    156  1.1  tsarna     UNUSED(unreg);
    157  1.1  tsarna 
    158  1.1  tsarna     *nelems = sizeof(mtab) / sizeof(mtab[0]);
    159  1.1  tsarna     *unreg = NULL;
    160  1.1  tsarna 
    161  1.1  tsarna     if (!strcmp(source, "multicast_dns")) {
    162  1.1  tsarna         svc_flags = kDNSServiceFlagsForceMulticast;
    163  1.1  tsarna     }
    164  1.1  tsarna 
    165  1.1  tsarna     res = __res_get_state();
    166  1.1  tsarna     if (res) {
    167  1.1  tsarna         load_config(res);
    168  1.1  tsarna         __res_put_state(res);
    169  1.1  tsarna     }
    170  1.1  tsarna 
    171  1.1  tsarna     return mtab;
    172  1.1  tsarna }
    173  1.1  tsarna 
    174  1.1  tsarna 
    175  1.1  tsarna 
    176  1.1  tsarna static int
    177  1.1  tsarna load_config(res_state res)
    178  1.1  tsarna {
    179  1.1  tsarna     int count = 0;
    180  1.1  tsarna     char **sd;
    181  1.1  tsarna 
    182  1.1  tsarna     ndots = res->ndots;
    183  1.1  tsarna     timeout = res->retrans * 1000; /* retrans in sec to timeout in msec */
    184  1.1  tsarna 
    185  1.1  tsarna     sd = res->dnsrch;
    186  1.1  tsarna     while (*sd) {
    187  1.1  tsarna         count++;
    188  1.1  tsarna         sd++;
    189  1.1  tsarna     }
    190  1.1  tsarna 
    191  1.1  tsarna     search_domains = malloc(sizeof(search_domain) * (count + 1));
    192  1.1  tsarna     if (!search_domains) {
    193  1.1  tsarna         return -1;
    194  1.1  tsarna     }
    195  1.1  tsarna 
    196  1.1  tsarna     sd = res->dnsrch;
    197  1.1  tsarna     no_search = search_domains;
    198  1.1  tsarna     while (*sd) {
    199  1.1  tsarna         no_search->name = *sd;
    200  1.1  tsarna         no_search->enabled =
    201  1.1  tsarna             (svc_flags & kDNSServiceFlagsForceMulticast) ? true : true;
    202  1.1  tsarna         no_search++;
    203  1.1  tsarna         sd++;
    204  1.1  tsarna     }
    205  1.1  tsarna 
    206  1.1  tsarna     /* terminate list */
    207  1.1  tsarna     no_search->name = NULL;
    208  1.1  tsarna }
    209  1.1  tsarna 
    210  1.1  tsarna 
    211  1.1  tsarna 
    212  1.1  tsarna static int
    213  1.1  tsarna _mdns_getaddrinfo(void *cbrv, void *cbdata, va_list ap)
    214  1.1  tsarna {
    215  1.1  tsarna     const struct addrinfo *pai;
    216  1.1  tsarna     const char *name, *sname;
    217  1.1  tsarna     DNSServiceProtocol proto;
    218  1.1  tsarna     int err = NS_UNAVAIL;
    219  1.1  tsarna     DNSServiceRef sdRef;
    220  1.1  tsarna     addrinfo_ctx ctx;
    221  1.1  tsarna     search_iter iter;
    222  1.1  tsarna 
    223  1.1  tsarna     UNUSED(cbdata);
    224  1.1  tsarna 
    225  1.1  tsarna     name = va_arg(ap, char *);
    226  1.1  tsarna     pai = va_arg(ap, struct addrinfo *);
    227  1.1  tsarna 
    228  1.1  tsarna     switch (pai->ai_family) {
    229  1.1  tsarna     case AF_UNSPEC:
    230  1.1  tsarna         proto = kDNSServiceProtocol_IPv6 | kDNSServiceProtocol_IPv4;
    231  1.1  tsarna         break;
    232  1.1  tsarna 
    233  1.1  tsarna     case AF_INET6:
    234  1.1  tsarna         proto = kDNSServiceProtocol_IPv6;
    235  1.1  tsarna         break;
    236  1.1  tsarna 
    237  1.1  tsarna     case AF_INET:
    238  1.1  tsarna         proto = kDNSServiceProtocol_IPv4;
    239  1.1  tsarna         break;
    240  1.1  tsarna 
    241  1.1  tsarna     default:
    242  1.1  tsarna         h_errno = NO_RECOVERY;
    243  1.1  tsarna         return NS_UNAVAIL;
    244  1.1  tsarna     }
    245  1.1  tsarna 
    246  1.1  tsarna     /* use one connection for all searches */
    247  1.1  tsarna     if (DNSServiceCreateConnection(&sdRef)) {
    248  1.1  tsarna         h_errno = NETDB_INTERNAL;
    249  1.1  tsarna         return NS_UNAVAIL;
    250  1.1  tsarna     }
    251  1.1  tsarna 
    252  1.1  tsarna     _mdns_addrinfo_init(&ctx, pai);
    253  1.1  tsarna     search_init(&iter, name);
    254  1.1  tsarna     sname = search_next(&iter);
    255  1.1  tsarna 
    256  1.1  tsarna     while (sname && (err != NS_SUCCESS)) {
    257  1.1  tsarna         err = _mdns_getaddrinfo_abs(sname, proto, sdRef, &ctx);
    258  1.1  tsarna         if (err != NS_SUCCESS) {
    259  1.1  tsarna             sname = search_next(&iter);
    260  1.1  tsarna         }
    261  1.1  tsarna     };
    262  1.1  tsarna 
    263  1.1  tsarna     DNSServiceRefDeallocate(sdRef);
    264  1.1  tsarna 
    265  1.1  tsarna     if (err == NS_SUCCESS) {
    266  1.1  tsarna         *(struct addrinfo **)cbrv = _mdns_addrinfo_done(&ctx);
    267  1.1  tsarna     }
    268  1.1  tsarna 
    269  1.1  tsarna     return err;
    270  1.1  tsarna }
    271  1.1  tsarna 
    272  1.1  tsarna 
    273  1.1  tsarna 
    274  1.1  tsarna static int
    275  1.1  tsarna _mdns_getaddrinfo_abs(const char *name, DNSServiceProtocol proto,
    276  1.1  tsarna     DNSServiceRef sdRef, addrinfo_ctx *ctx)
    277  1.1  tsarna {
    278  1.1  tsarna     DNSServiceErrorType err;
    279  1.1  tsarna 
    280  1.1  tsarna     err = DNSServiceGetAddrInfo(
    281  1.1  tsarna         &sdRef,
    282  1.1  tsarna         svc_flags,
    283  1.1  tsarna         kDNSServiceInterfaceIndexAny,
    284  1.1  tsarna         proto,
    285  1.1  tsarna         name,
    286  1.1  tsarna         _mdns_addrinfo_cb,
    287  1.1  tsarna         ctx
    288  1.1  tsarna     );
    289  1.1  tsarna 
    290  1.1  tsarna     if (err) {
    291  1.1  tsarna         h_errno = NETDB_INTERNAL;
    292  1.1  tsarna         return NS_UNAVAIL;
    293  1.1  tsarna     }
    294  1.1  tsarna 
    295  1.1  tsarna     _mdns_eventloop(sdRef, (void *)ctx);
    296  1.1  tsarna 
    297  1.1  tsarna     DNSServiceRefDeallocate(sdRef);
    298  1.1  tsarna 
    299  1.1  tsarna     if (ctx->start.ai_next) {
    300  1.1  tsarna         return NS_SUCCESS;
    301  1.1  tsarna     } else {
    302  1.1  tsarna         h_errno = HOST_NOT_FOUND;
    303  1.1  tsarna         return NS_NOTFOUND;
    304  1.1  tsarna     }
    305  1.1  tsarna }
    306  1.1  tsarna 
    307  1.1  tsarna 
    308  1.1  tsarna 
    309  1.1  tsarna static int
    310  1.1  tsarna _mdns_gethtbyaddr(void *cbrv, void *cbdata, va_list ap)
    311  1.1  tsarna {
    312  1.1  tsarna     const unsigned char *addr;
    313  1.1  tsarna     int addrlen, af;
    314  1.1  tsarna     char qbuf[NS_MAXDNAME + 1], *qp, *ep;
    315  1.1  tsarna     int advance, n;
    316  1.1  tsarna     DNSServiceErrorType err;
    317  1.1  tsarna     DNSServiceRef sdRef;
    318  1.1  tsarna 
    319  1.1  tsarna     UNUSED(cbdata);
    320  1.1  tsarna 
    321  1.1  tsarna     addr = va_arg(ap, unsigned char *);
    322  1.1  tsarna     addrlen = va_arg(ap, int);
    323  1.1  tsarna     af = va_arg(ap, int);
    324  1.1  tsarna 
    325  1.1  tsarna     switch (af) {
    326  1.1  tsarna     case AF_INET:
    327  1.1  tsarna         (void)snprintf(qbuf, sizeof(qbuf), "%u.%u.%u.%u.in-addr.arpa",
    328  1.1  tsarna             (addr[3] & 0xff), (addr[2] & 0xff),
    329  1.1  tsarna             (addr[1] & 0xff), (addr[0] & 0xff));
    330  1.1  tsarna         break;
    331  1.1  tsarna 
    332  1.1  tsarna     case AF_INET6:
    333  1.1  tsarna         qp = qbuf;
    334  1.1  tsarna         ep = qbuf + sizeof(qbuf) - 1;
    335  1.1  tsarna         for (n = IN6ADDRSZ - 1; n >= 0; n--) {
    336  1.1  tsarna             advance = snprintf(qp, (size_t)(ep - qp), "%x.%x.",
    337  1.1  tsarna                 addr[n] & 0xf,
    338  1.1  tsarna                 ((unsigned int)addr[n] >> 4) & 0xf);
    339  1.1  tsarna             if (advance > 0 && qp + advance < ep)
    340  1.1  tsarna                 qp += advance;
    341  1.1  tsarna             else {
    342  1.1  tsarna                 h_errno = NETDB_INTERNAL;
    343  1.1  tsarna                 return NS_NOTFOUND;
    344  1.1  tsarna             }
    345  1.1  tsarna         }
    346  1.1  tsarna         if (strlcat(qbuf, "ip6.arpa", sizeof(qbuf)) >= sizeof(qbuf)) {
    347  1.1  tsarna             h_errno = NETDB_INTERNAL;
    348  1.1  tsarna             return NS_NOTFOUND;
    349  1.1  tsarna         }
    350  1.1  tsarna         break;
    351  1.1  tsarna 
    352  1.1  tsarna     default:
    353  1.1  tsarna         h_errno = NO_RECOVERY;
    354  1.1  tsarna         return NS_UNAVAIL;
    355  1.1  tsarna     }
    356  1.1  tsarna 
    357  1.1  tsarna     _mdns_hostent_init(&h_ctx, af, addrlen);
    358  1.1  tsarna     _mdns_hostent_add_addr(&h_ctx, addr, addrlen);
    359  1.1  tsarna 
    360  1.1  tsarna     err = DNSServiceQueryRecord(
    361  1.1  tsarna         &sdRef,
    362  1.1  tsarna         svc_flags,
    363  1.1  tsarna         kDNSServiceInterfaceIndexAny,
    364  1.1  tsarna         qbuf,
    365  1.1  tsarna         kDNSServiceType_PTR,
    366  1.1  tsarna         kDNSServiceClass_IN,
    367  1.1  tsarna         _mdns_hostent_cb,
    368  1.1  tsarna         &h_ctx
    369  1.1  tsarna     );
    370  1.1  tsarna 
    371  1.1  tsarna     if (err) {
    372  1.1  tsarna         h_errno = NETDB_INTERNAL;
    373  1.1  tsarna         return NS_UNAVAIL;
    374  1.1  tsarna     }
    375  1.1  tsarna 
    376  1.1  tsarna     _mdns_eventloop(sdRef, (void *)&h_ctx);
    377  1.1  tsarna 
    378  1.1  tsarna     DNSServiceRefDeallocate(sdRef);
    379  1.1  tsarna 
    380  1.1  tsarna     if (h_ctx.naliases) {
    381  1.1  tsarna         *(struct hostent **)cbrv = _mdns_hostent_done(&h_ctx);
    382  1.1  tsarna 
    383  1.1  tsarna         return NS_SUCCESS;
    384  1.1  tsarna     } else {
    385  1.1  tsarna         h_errno = HOST_NOT_FOUND;
    386  1.1  tsarna         return NS_NOTFOUND;
    387  1.1  tsarna     }
    388  1.1  tsarna }
    389  1.1  tsarna 
    390  1.1  tsarna 
    391  1.1  tsarna 
    392  1.1  tsarna static int
    393  1.1  tsarna _mdns_gethtbyname(void *cbrv, void *cbdata, va_list ap)
    394  1.1  tsarna {
    395  1.1  tsarna     int namelen, af, addrlen, rrtype, err = NS_UNAVAIL;
    396  1.1  tsarna     const char *name, *sname;
    397  1.1  tsarna     DNSServiceRef sdRef;
    398  1.1  tsarna     search_iter iter;
    399  1.1  tsarna 
    400  1.1  tsarna     UNUSED(cbdata);
    401  1.1  tsarna 
    402  1.1  tsarna     name = va_arg(ap, char *);
    403  1.1  tsarna     namelen = va_arg(ap, int);
    404  1.1  tsarna     af = va_arg(ap, int);
    405  1.1  tsarna 
    406  1.1  tsarna     UNUSED(namelen);
    407  1.1  tsarna 
    408  1.1  tsarna     switch (af) {
    409  1.1  tsarna     case AF_INET:
    410  1.1  tsarna         rrtype = kDNSServiceType_A;
    411  1.1  tsarna         addrlen = 4;
    412  1.1  tsarna         break;
    413  1.1  tsarna 
    414  1.1  tsarna     case AF_INET6:
    415  1.1  tsarna         rrtype = kDNSServiceType_AAAA;
    416  1.1  tsarna         addrlen = 16;
    417  1.1  tsarna         break;
    418  1.1  tsarna 
    419  1.1  tsarna     default:
    420  1.1  tsarna         h_errno = NETDB_INTERNAL;
    421  1.1  tsarna         return NS_NOTFOUND;
    422  1.1  tsarna     }
    423  1.1  tsarna 
    424  1.1  tsarna     /* use one connection for all searches */
    425  1.1  tsarna     if (DNSServiceCreateConnection(&sdRef)) {
    426  1.1  tsarna         h_errno = NETDB_INTERNAL;
    427  1.1  tsarna         return NS_UNAVAIL;
    428  1.1  tsarna     }
    429  1.1  tsarna 
    430  1.1  tsarna     _mdns_hostent_init(&h_ctx, af, addrlen);
    431  1.1  tsarna     search_init(&iter, name);
    432  1.1  tsarna     sname = search_next(&iter);
    433  1.1  tsarna 
    434  1.1  tsarna     while (sname && (err != NS_SUCCESS)) {
    435  1.1  tsarna         err = _mdns_gethtbyname_abs(sname, rrtype, sdRef);
    436  1.1  tsarna         if (err != NS_SUCCESS) {
    437  1.1  tsarna             sname = search_next(&iter);
    438  1.1  tsarna         }
    439  1.1  tsarna     };
    440  1.1  tsarna 
    441  1.1  tsarna     DNSServiceRefDeallocate(sdRef);
    442  1.1  tsarna 
    443  1.1  tsarna     if (err == NS_SUCCESS) {
    444  1.1  tsarna         _mdns_hostent_add_host(&h_ctx, sname);
    445  1.1  tsarna         _mdns_hostent_add_host(&h_ctx, name);
    446  1.1  tsarna         *(struct hostent **)cbrv = _mdns_hostent_done(&h_ctx);
    447  1.1  tsarna     }
    448  1.1  tsarna 
    449  1.1  tsarna     return err;
    450  1.1  tsarna }
    451  1.1  tsarna 
    452  1.1  tsarna 
    453  1.1  tsarna 
    454  1.1  tsarna static int
    455  1.1  tsarna _mdns_gethtbyname_abs(const char *name, int rrtype, DNSServiceRef sdRef)
    456  1.1  tsarna {
    457  1.1  tsarna     DNSServiceErrorType err;
    458  1.1  tsarna 
    459  1.1  tsarna     err = DNSServiceQueryRecord(
    460  1.1  tsarna         &sdRef,
    461  1.1  tsarna         svc_flags,
    462  1.1  tsarna         kDNSServiceInterfaceIndexAny,
    463  1.1  tsarna         name,
    464  1.1  tsarna         rrtype,
    465  1.1  tsarna         kDNSServiceClass_IN,
    466  1.1  tsarna         _mdns_hostent_cb,
    467  1.1  tsarna         &h_ctx
    468  1.1  tsarna     );
    469  1.1  tsarna 
    470  1.1  tsarna     if (err) {
    471  1.1  tsarna         h_errno = NETDB_INTERNAL;
    472  1.1  tsarna         return NS_UNAVAIL;
    473  1.1  tsarna     }
    474  1.1  tsarna 
    475  1.1  tsarna     _mdns_eventloop(sdRef, (void *)&h_ctx);
    476  1.1  tsarna 
    477  1.1  tsarna     DNSServiceRefDeallocate(sdRef);
    478  1.1  tsarna 
    479  1.1  tsarna     if (h_ctx.naddrs) {
    480  1.1  tsarna         return NS_SUCCESS;
    481  1.1  tsarna     } else {
    482  1.1  tsarna         h_errno = HOST_NOT_FOUND;
    483  1.1  tsarna         return NS_NOTFOUND;
    484  1.1  tsarna     }
    485  1.1  tsarna }
    486  1.1  tsarna 
    487  1.1  tsarna 
    488  1.1  tsarna 
    489  1.1  tsarna static void
    490  1.1  tsarna _mdns_addrinfo_init(addrinfo_ctx *ctx, const struct addrinfo *ai)
    491  1.1  tsarna {
    492  1.1  tsarna     ctx->cb_ctx.done = false;
    493  1.1  tsarna     ctx->start = *ai;
    494  1.1  tsarna     ctx->start.ai_next = NULL;
    495  1.1  tsarna     ctx->start.ai_canonname = NULL;
    496  1.1  tsarna     ctx->last = &(ctx->start);
    497  1.1  tsarna }
    498  1.1  tsarna 
    499  1.1  tsarna 
    500  1.1  tsarna 
    501  1.1  tsarna static void
    502  1.1  tsarna _mdns_addrinfo_add_ai(addrinfo_ctx *ctx, struct addrinfo *ai)
    503  1.1  tsarna {
    504  1.1  tsarna     ctx->last->ai_next = ai;
    505  1.1  tsarna     while (ctx->last->ai_next)
    506  1.1  tsarna         ctx->last = ctx->last->ai_next;
    507  1.1  tsarna }
    508  1.1  tsarna 
    509  1.1  tsarna 
    510  1.1  tsarna 
    511  1.1  tsarna static struct addrinfo *
    512  1.1  tsarna _mdns_addrinfo_done(addrinfo_ctx *ctx)
    513  1.1  tsarna {
    514  1.1  tsarna     struct addrinfo head, *t, *p;
    515  1.1  tsarna 
    516  1.1  tsarna     /* sort v6 up */
    517  1.1  tsarna 
    518  1.1  tsarna     t = &head;
    519  1.1  tsarna     p = ctx->start.ai_next;
    520  1.1  tsarna 
    521  1.1  tsarna     while (p->ai_next) {
    522  1.1  tsarna         if (p->ai_next->ai_family == AF_INET6) {
    523  1.1  tsarna             t->ai_next = p->ai_next;
    524  1.1  tsarna             t = t->ai_next;
    525  1.1  tsarna             p->ai_next = p->ai_next->ai_next;
    526  1.1  tsarna         } else {
    527  1.1  tsarna             p = p->ai_next;
    528  1.1  tsarna         }
    529  1.1  tsarna     }
    530  1.1  tsarna 
    531  1.1  tsarna     /* add rest of list and reset start to the new list */
    532  1.1  tsarna 
    533  1.1  tsarna     t->ai_next = ctx->start.ai_next;
    534  1.1  tsarna     ctx->start.ai_next = head.ai_next;
    535  1.1  tsarna 
    536  1.1  tsarna     return ctx->start.ai_next;
    537  1.1  tsarna }
    538  1.1  tsarna 
    539  1.1  tsarna 
    540  1.1  tsarna 
    541  1.1  tsarna static void
    542  1.1  tsarna _mdns_hostent_init(hostent_ctx *ctx, int af, int addrlen)
    543  1.1  tsarna {
    544  1.1  tsarna     int i;
    545  1.1  tsarna 
    546  1.1  tsarna     ctx->cb_ctx.done = false;
    547  1.1  tsarna     ctx->naliases = ctx->naddrs = 0;
    548  1.1  tsarna     ctx->next = ctx->buf;
    549  1.1  tsarna 
    550  1.1  tsarna     ctx->host.h_aliases = ctx->host_aliases;
    551  1.1  tsarna     ctx->host.h_addr_list = ctx->h_addr_ptrs;
    552  1.1  tsarna     ctx->host.h_name = ctx->host.h_aliases[0] = NULL;
    553  1.1  tsarna     ctx->host.h_addrtype = af;
    554  1.1  tsarna     ctx->host.h_length = addrlen;
    555  1.1  tsarna 
    556  1.1  tsarna     for (i = 0; i < MAXADDRS; i++) {
    557  1.1  tsarna         ctx->host.h_addr_list[i] = &(ctx->addrs[i * 16]);
    558  1.1  tsarna     }
    559  1.1  tsarna }
    560  1.1  tsarna 
    561  1.1  tsarna 
    562  1.1  tsarna 
    563  1.1  tsarna static void
    564  1.1  tsarna _mdns_hostent_add_host(hostent_ctx *ctx, const char *name)
    565  1.1  tsarna {
    566  1.1  tsarna     size_t len;
    567  1.1  tsarna     int i;
    568  1.1  tsarna 
    569  1.1  tsarna     if (name && (len = strlen(name))
    570  1.1  tsarna     && (HCTX_BUFLEFT(ctx) > len) && (ctx->naliases < MAXALIASES)) {
    571  1.1  tsarna         if (len && (name[len - 1] == '.')) {
    572  1.1  tsarna             len--;
    573  1.1  tsarna         }
    574  1.1  tsarna 
    575  1.1  tsarna         /* skip dupe names */
    576  1.1  tsarna 
    577  1.1  tsarna         if ((ctx->host.h_name) && !strncmp(ctx->host.h_name, name, len)
    578  1.1  tsarna         && (strlen(ctx->host.h_name) == len)) {
    579  1.1  tsarna             return;
    580  1.1  tsarna         }
    581  1.1  tsarna 
    582  1.1  tsarna         for (i = 0; i < ctx->naliases - 1; i++) {
    583  1.1  tsarna             if (!strncmp(ctx->host.h_aliases[i], name, len)
    584  1.1  tsarna             && (strlen(ctx->host.h_aliases[i]) == len)) {
    585  1.1  tsarna                 return;
    586  1.1  tsarna             }
    587  1.1  tsarna         }
    588  1.1  tsarna 
    589  1.1  tsarna         strncpy(ctx->next, name, len);
    590  1.1  tsarna         ctx->next[len] = 0;
    591  1.1  tsarna 
    592  1.1  tsarna         if (ctx->naliases == 0) {
    593  1.1  tsarna             ctx->host.h_name = ctx->next;
    594  1.1  tsarna         } else {
    595  1.1  tsarna             ctx->host.h_aliases[ctx->naliases - 1] = ctx->next;
    596  1.1  tsarna         }
    597  1.1  tsarna 
    598  1.1  tsarna         ctx->next += (len + 1);
    599  1.1  tsarna         ctx->naliases++;
    600  1.1  tsarna     } /* else silently ignore */
    601  1.1  tsarna }
    602  1.1  tsarna 
    603  1.1  tsarna 
    604  1.1  tsarna 
    605  1.1  tsarna static void
    606  1.1  tsarna _mdns_hostent_add_addr(hostent_ctx *ctx, const void *addr, uint16_t len)
    607  1.1  tsarna {
    608  1.1  tsarna     if ((len == ctx->host.h_length) && (ctx->naddrs < MAXADDRS)) {
    609  1.1  tsarna         memcpy(ctx->host.h_addr_list[ctx->naddrs++], addr, (size_t)len);
    610  1.1  tsarna     } /* else wrong address type or out of room... silently skip */
    611  1.1  tsarna }
    612  1.1  tsarna 
    613  1.1  tsarna 
    614  1.1  tsarna 
    615  1.1  tsarna static struct hostent *
    616  1.1  tsarna _mdns_hostent_done(hostent_ctx *ctx)
    617  1.1  tsarna {
    618  1.1  tsarna     if (ctx->naliases) {
    619  1.1  tsarna         /* terminate array */
    620  1.1  tsarna         ctx->host.h_aliases[ctx->naliases - 1] = NULL;
    621  1.1  tsarna         ctx->host.h_addr_list[ctx->naddrs] = NULL;
    622  1.1  tsarna     }
    623  1.1  tsarna 
    624  1.1  tsarna     return &(ctx->host);
    625  1.1  tsarna }
    626  1.1  tsarna 
    627  1.1  tsarna 
    628  1.1  tsarna 
    629  1.1  tsarna static void
    630  1.1  tsarna _mdns_addrinfo_cb(
    631  1.1  tsarna     DNSServiceRef           sdRef,
    632  1.1  tsarna     DNSServiceFlags         flags,
    633  1.1  tsarna     uint32_t                interfaceIndex,
    634  1.1  tsarna     DNSServiceErrorType     errorCode,
    635  1.1  tsarna     const char             *hostname,
    636  1.1  tsarna     const struct sockaddr  *address,
    637  1.1  tsarna     uint32_t                ttl,
    638  1.1  tsarna     void                   *context
    639  1.1  tsarna ) {
    640  1.1  tsarna     addrinfo_ctx *ctx = context;
    641  1.1  tsarna     struct addrinfo *ai;
    642  1.1  tsarna 
    643  1.1  tsarna     UNUSED(sdRef);
    644  1.1  tsarna     UNUSED(interfaceIndex);
    645  1.1  tsarna     UNUSED(hostname);
    646  1.1  tsarna     UNUSED(ttl);
    647  1.1  tsarna 
    648  1.1  tsarna     if (errorCode == kDNSServiceErr_NoError) {
    649  1.1  tsarna         if (! (flags & kDNSServiceFlagsMoreComing)) {
    650  1.1  tsarna             ctx->cb_ctx.done = true;
    651  1.1  tsarna         }
    652  1.1  tsarna 
    653  1.1  tsarna         ai = allocaddrinfo((socklen_t)(address->sa_len));
    654  1.1  tsarna         if (ai) {
    655  1.1  tsarna             ai->ai_flags = ctx->start.ai_flags;
    656  1.1  tsarna             ai->ai_family = address->sa_family;
    657  1.1  tsarna             ai->ai_socktype = ctx->start.ai_socktype;
    658  1.1  tsarna             ai->ai_protocol = ctx->start.ai_protocol;
    659  1.1  tsarna             memcpy(ai->ai_addr, address, (size_t)(address->sa_len));
    660  1.1  tsarna 
    661  1.1  tsarna             if ((ctx->start.ai_flags & AI_CANONNAME) && hostname) {
    662  1.1  tsarna                 ai->ai_canonname = strdup(hostname);
    663  1.1  tsarna                 if (ai->ai_canonname[strlen(ai->ai_canonname) - 1] == '.') {
    664  1.1  tsarna                     ai->ai_canonname[strlen(ai->ai_canonname) - 1] = '\0';
    665  1.1  tsarna                 }
    666  1.1  tsarna             }
    667  1.1  tsarna 
    668  1.1  tsarna             _mdns_addrinfo_add_ai(ctx, ai);
    669  1.1  tsarna         }
    670  1.1  tsarna     }
    671  1.1  tsarna }
    672  1.1  tsarna 
    673  1.1  tsarna 
    674  1.1  tsarna 
    675  1.1  tsarna static void
    676  1.1  tsarna _mdns_hostent_cb(
    677  1.1  tsarna     DNSServiceRef           sdRef,
    678  1.1  tsarna     DNSServiceFlags         flags,
    679  1.1  tsarna     uint32_t                interfaceIndex,
    680  1.1  tsarna     DNSServiceErrorType     errorCode,
    681  1.1  tsarna     const char             *fullname,
    682  1.1  tsarna     uint16_t                rrtype,
    683  1.1  tsarna     uint16_t                rrclass,
    684  1.1  tsarna     uint16_t                rdlen,
    685  1.1  tsarna     const void             *rdata,
    686  1.1  tsarna     uint32_t                ttl,
    687  1.1  tsarna     void                   *context
    688  1.1  tsarna ) {
    689  1.1  tsarna     hostent_ctx *ctx = (hostent_ctx *)context;
    690  1.1  tsarna     char buf[NS_MAXDNAME+1];
    691  1.1  tsarna 
    692  1.1  tsarna     UNUSED(sdRef);
    693  1.1  tsarna     UNUSED(interfaceIndex);
    694  1.1  tsarna     UNUSED(rrclass);
    695  1.1  tsarna     UNUSED(ttl);
    696  1.1  tsarna 
    697  1.1  tsarna     if (! (flags & kDNSServiceFlagsMoreComing)) {
    698  1.1  tsarna         ctx->cb_ctx.done = true;
    699  1.1  tsarna     }
    700  1.1  tsarna 
    701  1.1  tsarna     if (errorCode == kDNSServiceErr_NoError) {
    702  1.1  tsarna         switch (rrtype) {
    703  1.1  tsarna         case kDNSServiceType_PTR:
    704  1.1  tsarna             if (!_mdns_rdata2name(rdata, rdlen, buf, sizeof(buf))) {
    705  1.1  tsarna                 /* corrupt response -- skip */
    706  1.1  tsarna                 return;
    707  1.1  tsarna             }
    708  1.1  tsarna 
    709  1.1  tsarna             _mdns_hostent_add_host(ctx, buf);
    710  1.1  tsarna             break;
    711  1.1  tsarna 
    712  1.1  tsarna         case kDNSServiceType_A:
    713  1.1  tsarna             if (ctx->host.h_addrtype == AF_INET) {
    714  1.1  tsarna                 _mdns_hostent_add_host(ctx, fullname);
    715  1.1  tsarna                 _mdns_hostent_add_addr(ctx, rdata, rdlen);
    716  1.1  tsarna             }
    717  1.1  tsarna             break;
    718  1.1  tsarna 
    719  1.1  tsarna         case kDNSServiceType_AAAA:
    720  1.1  tsarna             if (ctx->host.h_addrtype == AF_INET6) {
    721  1.1  tsarna                 _mdns_hostent_add_host(ctx, fullname);
    722  1.1  tsarna                 _mdns_hostent_add_addr(ctx, rdata, rdlen);
    723  1.1  tsarna             }
    724  1.1  tsarna             break;
    725  1.1  tsarna         }
    726  1.1  tsarna     }
    727  1.1  tsarna }
    728  1.1  tsarna 
    729  1.1  tsarna 
    730  1.1  tsarna 
    731  1.1  tsarna static void
    732  1.1  tsarna _mdns_eventloop(DNSServiceRef sdRef, callback_ctx *ctx)
    733  1.1  tsarna {
    734  1.1  tsarna     struct pollfd fds;
    735  1.1  tsarna     int fd, ret;
    736  1.1  tsarna 
    737  1.1  tsarna     fd = DNSServiceRefSockFD(sdRef);
    738  1.1  tsarna     fds.fd = fd;
    739  1.1  tsarna     fds.events = POLLRDNORM;
    740  1.1  tsarna 
    741  1.1  tsarna     while (!ctx->done) {
    742  1.1  tsarna         ret = poll(&fds, 1, timeout);
    743  1.1  tsarna         if (ret > 0) {
    744  1.1  tsarna             DNSServiceProcessResult(sdRef);
    745  1.1  tsarna         } else {
    746  1.1  tsarna             break;
    747  1.1  tsarna         }
    748  1.1  tsarna     }
    749  1.1  tsarna }
    750  1.1  tsarna 
    751  1.1  tsarna 
    752  1.1  tsarna 
    753  1.1  tsarna static char *
    754  1.1  tsarna _mdns_rdata2name(const unsigned char *rdata, uint16_t rdlen, char *buf, size_t buflen)
    755  1.1  tsarna {
    756  1.1  tsarna     unsigned char l;
    757  1.1  tsarna     char *r = buf;
    758  1.1  tsarna 
    759  1.1  tsarna     /* illegal 0-size answer or not enough room for even "." */
    760  1.1  tsarna     if ((!rdlen) || (rdlen < 2)) {
    761  1.1  tsarna         return NULL;
    762  1.1  tsarna     }
    763  1.1  tsarna 
    764  1.1  tsarna     buflen--; /* reserve space for terminating NUL now */
    765  1.1  tsarna 
    766  1.1  tsarna     /* special case empty as "." */
    767  1.1  tsarna     if ((rdlen == 1) && (!*rdata)) {
    768  1.1  tsarna         strcpy(buf, ".");
    769  1.1  tsarna 
    770  1.1  tsarna         return r;
    771  1.1  tsarna     }
    772  1.1  tsarna 
    773  1.1  tsarna     while (rdlen && *rdata) {
    774  1.1  tsarna         /* label length byte */
    775  1.1  tsarna         l = *rdata++; rdlen--;
    776  1.1  tsarna 
    777  1.1  tsarna         if (l > 63) {
    778  1.1  tsarna             /* compression or bitstrings -- shouldn't happen */
    779  1.1  tsarna             return NULL;
    780  1.1  tsarna         } else if (l > buflen) {
    781  1.1  tsarna             /* not enough space */
    782  1.1  tsarna             return NULL;
    783  1.1  tsarna         } else if (l > rdlen) {
    784  1.1  tsarna             /* label shouldn't be longer than remaining rdata */
    785  1.1  tsarna             return NULL;
    786  1.1  tsarna         } else if (!l) {
    787  1.1  tsarna             /* empty label -- should be done */
    788  1.1  tsarna             if (rdlen) {
    789  1.1  tsarna                 /* but more left!? */
    790  1.1  tsarna                 return NULL;
    791  1.1  tsarna             } else {
    792  1.1  tsarna                 break;
    793  1.1  tsarna             }
    794  1.1  tsarna         }
    795  1.1  tsarna 
    796  1.1  tsarna         memcpy(buf, rdata, (size_t)l);
    797  1.1  tsarna         rdata += l; buf += l;
    798  1.1  tsarna         rdlen -= l; buflen -= l;
    799  1.1  tsarna 
    800  1.1  tsarna         /* Another label to come? add a separator */
    801  1.1  tsarna         if (rdlen && *rdata) {
    802  1.1  tsarna             if (!buflen) {
    803  1.1  tsarna                 return NULL;
    804  1.1  tsarna             }
    805  1.1  tsarna 
    806  1.1  tsarna             *buf++ = '.'; buflen--;
    807  1.1  tsarna         }
    808  1.1  tsarna     }
    809  1.1  tsarna 
    810  1.1  tsarna     /* we reserved space above, so we know we have space
    811  1.1  tsarna        to add this termination */
    812  1.1  tsarna 
    813  1.1  tsarna     *buf = '\0';
    814  1.1  tsarna 
    815  1.1  tsarna     return r;
    816  1.1  tsarna }
    817  1.1  tsarna 
    818  1.1  tsarna 
    819  1.1  tsarna 
    820  1.1  tsarna void
    821  1.1  tsarna search_init(search_iter *iter, const char *name)
    822  1.1  tsarna {
    823  1.1  tsarna     const char *c = name;
    824  1.1  tsarna     bool enddot = false;
    825  1.1  tsarna     int dots = 0;
    826  1.1  tsarna 
    827  1.1  tsarna     iter->name = name;
    828  1.1  tsarna     iter->baselen = 0;
    829  1.1  tsarna 
    830  1.1  tsarna     while (*c) {
    831  1.1  tsarna         if (*c == '.') {
    832  1.1  tsarna             dots++;
    833  1.1  tsarna             enddot = true;
    834  1.1  tsarna         } else {
    835  1.1  tsarna             enddot = false;
    836  1.1  tsarna         }
    837  1.1  tsarna         c++;
    838  1.1  tsarna     }
    839  1.1  tsarna 
    840  1.1  tsarna     if (dots >= ndots) {
    841  1.1  tsarna         iter->abs_first = true;
    842  1.1  tsarna         iter->abs_last = false;
    843  1.1  tsarna     } else {
    844  1.1  tsarna         iter->abs_first = false;
    845  1.1  tsarna         iter->abs_last = true;
    846  1.1  tsarna     }
    847  1.1  tsarna 
    848  1.1  tsarna     if (enddot) {
    849  1.1  tsarna         iter->next_search = no_search;
    850  1.1  tsarna     } else {
    851  1.1  tsarna         iter->next_search = search_domains;
    852  1.1  tsarna     }
    853  1.1  tsarna }
    854  1.1  tsarna 
    855  1.1  tsarna 
    856  1.1  tsarna 
    857  1.1  tsarna const char *
    858  1.1  tsarna search_next(search_iter *iter)
    859  1.1  tsarna {
    860  1.1  tsarna     const char *a = NULL;
    861  1.1  tsarna     res_state res;
    862  1.1  tsarna     size_t len;
    863  1.1  tsarna 
    864  1.1  tsarna     if (iter->abs_first) {
    865  1.1  tsarna         iter->abs_first = false;
    866  1.1  tsarna         return iter->name;
    867  1.1  tsarna     }
    868  1.1  tsarna 
    869  1.1  tsarna     while (iter->next_search->name) {
    870  1.1  tsarna         if (iter->next_search->enabled) {
    871  1.1  tsarna             if (!iter->baselen) {
    872  1.1  tsarna                 iter->baselen = strlcpy(iter->buf, iter->name, sizeof(iter->buf));
    873  1.1  tsarna                 if (iter->baselen >= sizeof(iter->buf) - 1) {
    874  1.1  tsarna                     /* original is too long, don't try any search domains */
    875  1.1  tsarna                     iter->next_search = no_search;
    876  1.1  tsarna                     break;
    877  1.1  tsarna                 }
    878  1.1  tsarna 
    879  1.1  tsarna                 iter->buf[iter->baselen++] = '.';
    880  1.1  tsarna             }
    881  1.1  tsarna 
    882  1.1  tsarna             len = strlcpy(&(iter->buf[iter->baselen]),
    883  1.1  tsarna                 iter->next_search->name,
    884  1.1  tsarna                 sizeof(iter->buf) - iter->baselen);
    885  1.1  tsarna 
    886  1.1  tsarna             iter->next_search++;
    887  1.1  tsarna 
    888  1.1  tsarna             if (len >= sizeof(iter->buf) - iter->baselen) {
    889  1.1  tsarna                 /* result would be too long */
    890  1.1  tsarna                 continue;
    891  1.1  tsarna             }
    892  1.1  tsarna 
    893  1.1  tsarna             return iter->buf;
    894  1.1  tsarna         } else {
    895  1.1  tsarna             iter->next_search++;
    896  1.1  tsarna         }
    897  1.1  tsarna     }
    898  1.1  tsarna 
    899  1.1  tsarna     if (iter->abs_last) {
    900  1.1  tsarna         iter->abs_last = false;
    901  1.1  tsarna         return iter->name;
    902  1.1  tsarna     }
    903  1.1  tsarna 
    904  1.1  tsarna     return NULL;
    905  1.1  tsarna }
    906