[BACK]Return to getaddrinfo.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libc / net

Annotation of src/lib/libc/net/getaddrinfo.c, Revision 1.77

1.77    ! ginsbach    1: /*     $NetBSD: getaddrinfo.c,v 1.76 2006/02/13 17:16:20 ginsbach Exp $        */
1.48      itojun      2: /*     $KAME: getaddrinfo.c,v 1.29 2000/08/31 17:26:57 itojun Exp $    */
1.6       itojun      3:
1.1       itojun      4: /*
                      5:  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
                      6:  * All rights reserved.
1.42      itojun      7:  *
1.1       itojun      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer in the
                     15:  *    documentation and/or other materials provided with the distribution.
                     16:  * 3. Neither the name of the project nor the names of its contributors
                     17:  *    may be used to endorse or promote products derived from this software
                     18:  *    without specific prior written permission.
1.42      itojun     19:  *
1.1       itojun     20:  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
                     21:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     22:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     23:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
                     24:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     25:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     26:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     27:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     28:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     29:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     30:  * SUCH DAMAGE.
                     31:  */
                     32:
                     33: /*
                     34:  * Issues to be discussed:
                     35:  * - Thread safe-ness must be checked.
                     36:  * - Return values.  There are nonstandard return values defined and used
1.14      itojun     37:  *   in the source code.  This is because RFC2553 is silent about which error
1.1       itojun     38:  *   code must be returned for which situation.
1.27      itojun     39:  * - IPv4 classful (shortened) form.  RFC2553 is silent about it.  XNET 5.2
                     40:  *   says to use inet_aton() to convert IPv4 numeric to binary (alows
                     41:  *   classful form as a result).
                     42:  *   current code - disallow classful form for IPv4 (due to use of inet_pton).
                     43:  * - freeaddrinfo(NULL).  RFC2553 is silent about it.  XNET 5.2 says it is
                     44:  *   invalid.
                     45:  *   current code - SEGV on freeaddrinfo(NULL)
1.14      itojun     46:  * Note:
                     47:  * - We use getipnodebyname() just for thread-safeness.  There's no intent
                     48:  *   to let it do PF_UNSPEC (actually we never pass PF_UNSPEC to
                     49:  *   getipnodebyname().
                     50:  * - The code filters out AFs that are not supported by the kernel,
1.22      itojun     51:  *   when globbing NULL hostname (to loopback, or wildcard).  Is it the right
1.14      itojun     52:  *   thing to do?  What is the relationship with post-RFC2553 AI_ADDRCONFIG
                     53:  *   in ai_flags?
1.30      itojun     54:  * - (post-2553) semantics of AI_ADDRCONFIG itself is too vague.
                     55:  *   (1) what should we do against numeric hostname (2) what should we do
                     56:  *   against NULL hostname (3) what is AI_ADDRCONFIG itself.  AF not ready?
                     57:  *   non-loopback address configured?  global address configured?
1.32      itojun     58:  * - To avoid search order issue, we have a big amount of code duplicate
                     59:  *   from gethnamaddr.c and some other places.  The issues that there's no
                     60:  *   lower layer function to lookup "IPv4 or IPv6" record.  Calling
                     61:  *   gethostbyname2 from getaddrinfo will end up in wrong search order, as
                     62:  *   follows:
                     63:  *     - The code makes use of following calls when asked to resolver with
                     64:  *       ai_family  = PF_UNSPEC:
                     65:  *             getipnodebyname(host, AF_INET6);
                     66:  *             getipnodebyname(host, AF_INET);
                     67:  *       This will result in the following queries if the node is configure to
                     68:  *       prefer /etc/hosts than DNS:
                     69:  *             lookup /etc/hosts for IPv6 address
                     70:  *             lookup DNS for IPv6 address
                     71:  *             lookup /etc/hosts for IPv4 address
                     72:  *             lookup DNS for IPv4 address
                     73:  *       which may not meet people's requirement.
                     74:  *       The right thing to happen is to have underlying layer which does
                     75:  *       PF_UNSPEC lookup (lookup both) and return chain of addrinfos.
                     76:  *       This would result in a bit of code duplicate with _dns_ghbyname() and
                     77:  *       friends.
1.1       itojun     78:  */
1.39      itojun     79:
                     80: #include <sys/cdefs.h>
                     81: #if defined(LIBC_SCCS) && !defined(lint)
1.77    ! ginsbach   82: __RCSID("$NetBSD: getaddrinfo.c,v 1.76 2006/02/13 17:16:20 ginsbach Exp $");
1.39      itojun     83: #endif /* LIBC_SCCS and not lint */
1.1       itojun     84:
1.38      itojun     85: #include "namespace.h"
1.14      itojun     86: #include <sys/types.h>
1.1       itojun     87: #include <sys/param.h>
                     88: #include <sys/socket.h>
1.14      itojun     89: #include <net/if.h>
1.1       itojun     90: #include <netinet/in.h>
                     91: #include <arpa/inet.h>
                     92: #include <arpa/nameser.h>
1.51      lukem      93: #include <assert.h>
                     94: #include <ctype.h>
                     95: #include <errno.h>
1.1       itojun     96: #include <netdb.h>
                     97: #include <resolv.h>
1.51      lukem      98: #include <stddef.h>
                     99: #include <stdio.h>
                    100: #include <stdlib.h>
1.14      itojun    101: #include <string.h>
1.1       itojun    102: #include <unistd.h>
1.14      itojun    103:
1.32      itojun    104: #include <syslog.h>
                    105: #include <stdarg.h>
                    106: #include <nsswitch.h>
                    107:
                    108: #ifdef YP
                    109: #include <rpc/rpc.h>
                    110: #include <rpcsvc/yp_prot.h>
                    111: #include <rpcsvc/ypclnt.h>
1.38      itojun    112: #endif
                    113:
                    114: #ifdef __weak_alias
                    115: __weak_alias(getaddrinfo,_getaddrinfo)
                    116: __weak_alias(freeaddrinfo,_freeaddrinfo)
                    117: __weak_alias(gai_strerror,_gai_strerror)
1.32      itojun    118: #endif
                    119:
1.1       itojun    120: #define SUCCESS 0
                    121: #define ANY 0
                    122: #define YES 1
                    123: #define NO  0
                    124:
                    125: static const char in_addrany[] = { 0, 0, 0, 0 };
1.49      lukem     126: static const char in_loopback[] = { 127, 0, 0, 1 };
                    127: #ifdef INET6
1.1       itojun    128: static const char in6_addrany[] = {
                    129:        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
                    130: };
                    131: static const char in6_loopback[] = {
                    132:        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
                    133: };
1.49      lukem     134: #endif
1.1       itojun    135:
1.14      itojun    136: static const struct afd {
1.1       itojun    137:        int a_af;
                    138:        int a_addrlen;
                    139:        int a_socklen;
                    140:        int a_off;
                    141:        const char *a_addrany;
                    142:        const char *a_loopback;
1.14      itojun    143:        int a_scoped;
1.1       itojun    144: } afdl [] = {
                    145: #ifdef INET6
                    146:        {PF_INET6, sizeof(struct in6_addr),
                    147:         sizeof(struct sockaddr_in6),
                    148:         offsetof(struct sockaddr_in6, sin6_addr),
1.14      itojun    149:         in6_addrany, in6_loopback, 1},
1.1       itojun    150: #endif
                    151:        {PF_INET, sizeof(struct in_addr),
                    152:         sizeof(struct sockaddr_in),
                    153:         offsetof(struct sockaddr_in, sin_addr),
1.14      itojun    154:         in_addrany, in_loopback, 0},
                    155:        {0, 0, 0, 0, NULL, NULL, 0},
                    156: };
                    157:
                    158: struct explore {
                    159:        int e_af;
                    160:        int e_socktype;
                    161:        int e_protocol;
                    162:        const char *e_protostr;
                    163:        int e_wild;
                    164: #define WILD_AF(ex)            ((ex)->e_wild & 0x01)
                    165: #define WILD_SOCKTYPE(ex)      ((ex)->e_wild & 0x02)
                    166: #define WILD_PROTOCOL(ex)      ((ex)->e_wild & 0x04)
                    167: };
                    168:
                    169: static const struct explore explore[] = {
                    170: #if 0
                    171:        { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 },
                    172: #endif
                    173: #ifdef INET6
                    174:        { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
                    175:        { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
                    176:        { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 },
                    177: #endif
                    178:        { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
                    179:        { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
                    180:        { PF_INET, SOCK_RAW, ANY, NULL, 0x05 },
1.32      itojun    181:        { PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
                    182:        { PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
                    183:        { PF_UNSPEC, SOCK_RAW, ANY, NULL, 0x05 },
1.14      itojun    184:        { -1, 0, 0, NULL, 0 },
1.1       itojun    185: };
                    186:
                    187: #ifdef INET6
                    188: #define PTON_MAX       16
                    189: #else
                    190: #define PTON_MAX       4
                    191: #endif
                    192:
1.32      itojun    193: static const ns_src default_dns_files[] = {
                    194:        { NSSRC_FILES,  NS_SUCCESS },
                    195:        { NSSRC_DNS,    NS_SUCCESS },
                    196:        { 0 }
                    197: };
                    198:
1.63      itojun    199: #define MAXPACKET      (64*1024)
1.32      itojun    200:
                    201: typedef union {
                    202:        HEADER hdr;
                    203:        u_char buf[MAXPACKET];
                    204: } querybuf;
                    205:
                    206: struct res_target {
                    207:        struct res_target *next;
                    208:        const char *name;       /* domain name */
1.43      itojun    209:        int qclass, qtype;      /* class and type of query */
1.32      itojun    210:        u_char *answer;         /* buffer to put answer */
                    211:        int anslen;             /* size of answer buffer */
                    212:        int n;                  /* result length */
                    213: };
1.1       itojun    214:
1.70      christos  215: static int str2number(const char *);
                    216: static int explore_fqdn(const struct addrinfo *, const char *,
                    217:        const char *, struct addrinfo **);
                    218: static int explore_null(const struct addrinfo *,
                    219:        const char *, struct addrinfo **);
                    220: static int explore_numeric(const struct addrinfo *, const char *,
                    221:        const char *, struct addrinfo **, const char *);
                    222: static int explore_numeric_scope(const struct addrinfo *, const char *,
                    223:        const char *, struct addrinfo **);
                    224: static int get_canonname(const struct addrinfo *,
                    225:        struct addrinfo *, const char *);
                    226: static struct addrinfo *get_ai(const struct addrinfo *,
                    227:        const struct afd *, const char *);
                    228: static int get_portmatch(const struct addrinfo *, const char *);
1.75      yamt      229: static int get_port(const struct addrinfo *, const char *, int);
1.70      christos  230: static const struct afd *find_afd(int);
1.27      itojun    231: #ifdef INET6
1.70      christos  232: static int ip6_str2scopeid(char *, struct sockaddr_in6 *, u_int32_t *);
1.42      itojun    233: #endif
1.14      itojun    234:
1.70      christos  235: static struct addrinfo *getanswer(const querybuf *, int, const char *, int,
                    236:        const struct addrinfo *);
1.73      tsarna    237: static void aisort(struct addrinfo *s, res_state res);
1.70      christos  238: static int _dns_getaddrinfo(void *, void *, va_list);
                    239: static void _sethtent(FILE **);
                    240: static void _endhtent(FILE **);
                    241: static struct addrinfo *_gethtent(FILE **, const char *,
                    242:     const struct addrinfo *);
                    243: static int _files_getaddrinfo(void *, void *, va_list);
1.32      itojun    244: #ifdef YP
1.70      christos  245: static struct addrinfo *_yphostent(char *, const struct addrinfo *);
                    246: static int _yp_getaddrinfo(void *, void *, va_list);
1.32      itojun    247: #endif
                    248:
1.70      christos  249: static int res_queryN(const char *, struct res_target *, res_state);
1.73      tsarna    250: static int res_searchN(const char *, struct res_target *, res_state);
1.70      christos  251: static int res_querydomainN(const char *, const char *,
                    252:        struct res_target *, res_state);
1.32      itojun    253:
1.53      jdolecek  254: static const char * const ai_errlist[] = {
1.7       lukem     255:        "Success",
                    256:        "Address family for hostname not supported",    /* EAI_ADDRFAMILY */
                    257:        "Temporary failure in name resolution",         /* EAI_AGAIN      */
                    258:        "Invalid value for ai_flags",                   /* EAI_BADFLAGS   */
                    259:        "Non-recoverable failure in name resolution",   /* EAI_FAIL       */
1.2       lukem     260:        "ai_family not supported",                      /* EAI_FAMILY     */
1.7       lukem     261:        "Memory allocation failure",                    /* EAI_MEMORY     */
                    262:        "No address associated with hostname",          /* EAI_NODATA     */
1.14      itojun    263:        "hostname nor servname provided, or not known", /* EAI_NONAME     */
1.2       lukem     264:        "servname not supported for ai_socktype",       /* EAI_SERVICE    */
                    265:        "ai_socktype not supported",                    /* EAI_SOCKTYPE   */
1.7       lukem     266:        "System error returned in errno",               /* EAI_SYSTEM     */
                    267:        "Invalid value for hints",                      /* EAI_BADHINTS   */
                    268:        "Resolved protocol is unknown",                 /* EAI_PROTOCOL   */
1.77    ! ginsbach  269:        "Argument buffer overflow",                     /* EAI_OVERFLOW   */
1.7       lukem     270:        "Unknown error",                                /* EAI_MAX        */
1.1       itojun    271: };
                    272:
1.14      itojun    273: /* XXX macros that make external reference is BAD. */
                    274:
                    275: #define GET_AI(ai, afd, addr) \
                    276: do { \
                    277:        /* external reference: pai, error, and label free */ \
                    278:        (ai) = get_ai(pai, (afd), (addr)); \
                    279:        if ((ai) == NULL) { \
                    280:                error = EAI_MEMORY; \
                    281:                goto free; \
                    282:        } \
1.20      mycroft   283: } while (/*CONSTCOND*/0)
1.14      itojun    284:
                    285: #define GET_PORT(ai, serv) \
                    286: do { \
                    287:        /* external reference: error and label free */ \
                    288:        error = get_port((ai), (serv), 0); \
                    289:        if (error != 0) \
                    290:                goto free; \
1.20      mycroft   291: } while (/*CONSTCOND*/0)
1.14      itojun    292:
1.1       itojun    293: #define GET_CANONNAME(ai, str) \
1.14      itojun    294: do { \
                    295:        /* external reference: pai, error and label free */ \
                    296:        error = get_canonname(pai, (ai), (str)); \
                    297:        if (error != 0) \
                    298:                goto free; \
1.20      mycroft   299: } while (/*CONSTCOND*/0)
1.14      itojun    300:
                    301: #define ERR(err) \
                    302: do { \
                    303:        /* external reference: error, and label bad */ \
                    304:        error = (err); \
                    305:        goto bad; \
1.36      christos  306:        /*NOTREACHED*/ \
1.20      mycroft   307: } while (/*CONSTCOND*/0)
1.14      itojun    308:
                    309: #define MATCH_FAMILY(x, y, w) \
1.20      mycroft   310:        ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC)))
1.14      itojun    311: #define MATCH(x, y, w) \
1.20      mycroft   312:        ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY)))
1.1       itojun    313:
1.70      christos  314: const char *
                    315: gai_strerror(int ecode)
1.1       itojun    316: {
                    317:        if (ecode < 0 || ecode > EAI_MAX)
                    318:                ecode = EAI_MAX;
1.70      christos  319:        return ai_errlist[ecode];
1.1       itojun    320: }
                    321:
                    322: void
1.70      christos  323: freeaddrinfo(struct addrinfo *ai)
1.1       itojun    324: {
                    325:        struct addrinfo *next;
                    326:
1.51      lukem     327:        _DIAGASSERT(ai != NULL);
                    328:
1.26      itojun    329:        do {
1.1       itojun    330:                next = ai->ai_next;
                    331:                if (ai->ai_canonname)
                    332:                        free(ai->ai_canonname);
                    333:                /* no need to free(ai->ai_addr) */
                    334:                free(ai);
1.27      itojun    335:                ai = next;
                    336:        } while (ai);
1.1       itojun    337: }
                    338:
                    339: static int
1.70      christos  340: str2number(const char *p)
1.1       itojun    341: {
1.45      itojun    342:        char *ep;
1.67      itojun    343:        unsigned long v;
1.45      itojun    344:
1.51      lukem     345:        _DIAGASSERT(p != NULL);
                    346:
1.46      itojun    347:        if (*p == '\0')
1.67      itojun    348:                return -1;
1.45      itojun    349:        ep = NULL;
1.59      itojun    350:        errno = 0;
1.67      itojun    351:        v = strtoul(p, &ep, 10);
                    352:        if (errno == 0 && ep && *ep == '\0' && v <= UINT_MAX)
                    353:                return v;
1.45      itojun    354:        else
1.67      itojun    355:                return -1;
1.1       itojun    356: }
                    357:
                    358: int
1.70      christos  359: getaddrinfo(const char *hostname, const char *servname,
                    360:     const struct addrinfo *hints, struct addrinfo **res)
1.1       itojun    361: {
                    362:        struct addrinfo sentinel;
                    363:        struct addrinfo *cur;
1.14      itojun    364:        int error = 0;
1.1       itojun    365:        struct addrinfo ai;
1.14      itojun    366:        struct addrinfo ai0;
1.1       itojun    367:        struct addrinfo *pai;
1.14      itojun    368:        const struct explore *ex;
1.1       itojun    369:
1.51      lukem     370:        /* hostname is allowed to be NULL */
                    371:        /* servname is allowed to be NULL */
                    372:        /* hints is allowed to be NULL */
                    373:        _DIAGASSERT(res != NULL);
                    374:
1.32      itojun    375:        memset(&sentinel, 0, sizeof(sentinel));
1.1       itojun    376:        cur = &sentinel;
                    377:        pai = &ai;
                    378:        pai->ai_flags = 0;
                    379:        pai->ai_family = PF_UNSPEC;
                    380:        pai->ai_socktype = ANY;
                    381:        pai->ai_protocol = ANY;
                    382:        pai->ai_addrlen = 0;
                    383:        pai->ai_canonname = NULL;
                    384:        pai->ai_addr = NULL;
                    385:        pai->ai_next = NULL;
                    386:
                    387:        if (hostname == NULL && servname == NULL)
                    388:                return EAI_NONAME;
                    389:        if (hints) {
                    390:                /* error check for hints */
                    391:                if (hints->ai_addrlen || hints->ai_canonname ||
                    392:                    hints->ai_addr || hints->ai_next)
                    393:                        ERR(EAI_BADHINTS); /* xxx */
                    394:                if (hints->ai_flags & ~AI_MASK)
                    395:                        ERR(EAI_BADFLAGS);
                    396:                switch (hints->ai_family) {
                    397:                case PF_UNSPEC:
                    398:                case PF_INET:
                    399: #ifdef INET6
                    400:                case PF_INET6:
                    401: #endif
                    402:                        break;
                    403:                default:
                    404:                        ERR(EAI_FAMILY);
                    405:                }
                    406:                memcpy(pai, hints, sizeof(*pai));
1.14      itojun    407:
                    408:                /*
                    409:                 * if both socktype/protocol are specified, check if they
                    410:                 * are meaningful combination.
                    411:                 */
                    412:                if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) {
                    413:                        for (ex = explore; ex->e_af >= 0; ex++) {
                    414:                                if (pai->ai_family != ex->e_af)
                    415:                                        continue;
                    416:                                if (ex->e_socktype == ANY)
                    417:                                        continue;
                    418:                                if (ex->e_protocol == ANY)
                    419:                                        continue;
                    420:                                if (pai->ai_socktype == ex->e_socktype
                    421:                                 && pai->ai_protocol != ex->e_protocol) {
                    422:                                        ERR(EAI_BADHINTS);
                    423:                                }
1.1       itojun    424:                        }
                    425:                }
                    426:        }
                    427:
                    428:        /*
1.14      itojun    429:         * check for special cases.  (1) numeric servname is disallowed if
                    430:         * socktype/protocol are left unspecified. (2) servname is disallowed
                    431:         * for raw and other inet{,6} sockets.
1.1       itojun    432:         */
1.14      itojun    433:        if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
1.27      itojun    434: #ifdef PF_INET6
                    435:         || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
                    436: #endif
                    437:            ) {
1.23      itojun    438:                ai0 = *pai;     /* backup *pai */
1.21      mycroft   439:
1.27      itojun    440:                if (pai->ai_family == PF_UNSPEC) {
                    441: #ifdef PF_INET6
1.14      itojun    442:                        pai->ai_family = PF_INET6;
1.27      itojun    443: #else
                    444:                        pai->ai_family = PF_INET;
                    445: #endif
                    446:                }
1.14      itojun    447:                error = get_portmatch(pai, servname);
                    448:                if (error)
                    449:                        ERR(error);
1.21      mycroft   450:
                    451:                *pai = ai0;
1.14      itojun    452:        }
                    453:
                    454:        ai0 = *pai;
                    455:
                    456:        /* NULL hostname, or numeric hostname */
                    457:        for (ex = explore; ex->e_af >= 0; ex++) {
                    458:                *pai = ai0;
                    459:
1.32      itojun    460:                /* PF_UNSPEC entries are prepared for DNS queries only */
                    461:                if (ex->e_af == PF_UNSPEC)
                    462:                        continue;
                    463:
1.14      itojun    464:                if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
                    465:                        continue;
                    466:                if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
                    467:                        continue;
                    468:                if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
                    469:                        continue;
                    470:
                    471:                if (pai->ai_family == PF_UNSPEC)
                    472:                        pai->ai_family = ex->e_af;
                    473:                if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
                    474:                        pai->ai_socktype = ex->e_socktype;
                    475:                if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
                    476:                        pai->ai_protocol = ex->e_protocol;
                    477:
                    478:                if (hostname == NULL)
1.20      mycroft   479:                        error = explore_null(pai, servname, &cur->ai_next);
1.14      itojun    480:                else
1.65      itojun    481:                        error = explore_numeric_scope(pai, hostname, servname,
                    482:                            &cur->ai_next);
1.14      itojun    483:
                    484:                if (error)
                    485:                        goto free;
                    486:
                    487:                while (cur && cur->ai_next)
                    488:                        cur = cur->ai_next;
                    489:        }
                    490:
                    491:        /*
                    492:         * XXX
1.76      ginsbach  493:         * If numeric representation of AF1 can be interpreted as FQDN
1.14      itojun    494:         * representation of AF2, we need to think again about the code below.
                    495:         */
                    496:        if (sentinel.ai_next)
                    497:                goto good;
                    498:
                    499:        if (hostname == NULL)
1.43      itojun    500:                ERR(EAI_NODATA);
1.64      itojun    501:        if (pai->ai_flags & AI_NUMERICHOST)
                    502:                ERR(EAI_NONAME);
1.14      itojun    503:
                    504:        /*
                    505:         * hostname as alphabetical name.
                    506:         * we would like to prefer AF_INET6 than AF_INET, so we'll make a
                    507:         * outer loop by AFs.
                    508:         */
1.32      itojun    509:        for (ex = explore; ex->e_af >= 0; ex++) {
1.14      itojun    510:                *pai = ai0;
                    511:
1.32      itojun    512:                /* require exact match for family field */
                    513:                if (pai->ai_family != ex->e_af)
1.14      itojun    514:                        continue;
                    515:
1.32      itojun    516:                if (!MATCH(pai->ai_socktype, ex->e_socktype,
                    517:                                WILD_SOCKTYPE(ex))) {
                    518:                        continue;
                    519:                }
                    520:                if (!MATCH(pai->ai_protocol, ex->e_protocol,
                    521:                                WILD_PROTOCOL(ex))) {
                    522:                        continue;
                    523:                }
1.14      itojun    524:
1.32      itojun    525:                if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
                    526:                        pai->ai_socktype = ex->e_socktype;
                    527:                if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
                    528:                        pai->ai_protocol = ex->e_protocol;
1.1       itojun    529:
1.32      itojun    530:                error = explore_fqdn(pai, hostname, servname,
                    531:                        &cur->ai_next);
1.14      itojun    532:
1.32      itojun    533:                while (cur && cur->ai_next)
                    534:                        cur = cur->ai_next;
1.1       itojun    535:        }
1.14      itojun    536:
                    537:        /* XXX */
                    538:        if (sentinel.ai_next)
                    539:                error = 0;
                    540:
                    541:        if (error)
                    542:                goto free;
                    543:        if (error == 0) {
                    544:                if (sentinel.ai_next) {
                    545:  good:
                    546:                        *res = sentinel.ai_next;
                    547:                        return SUCCESS;
                    548:                } else
                    549:                        error = EAI_FAIL;
                    550:        }
                    551:  free:
                    552:  bad:
                    553:        if (sentinel.ai_next)
                    554:                freeaddrinfo(sentinel.ai_next);
                    555:        *res = NULL;
                    556:        return error;
                    557: }
                    558:
                    559: /*
                    560:  * FQDN hostname, DNS lookup
                    561:  */
                    562: static int
1.70      christos  563: explore_fqdn(const struct addrinfo *pai, const char *hostname,
                    564:     const char *servname, struct addrinfo **res)
1.14      itojun    565: {
1.32      itojun    566:        struct addrinfo *result;
                    567:        struct addrinfo *cur;
1.27      itojun    568:        int error = 0;
1.32      itojun    569:        static const ns_dtab dtab[] = {
                    570:                NS_FILES_CB(_files_getaddrinfo, NULL)
                    571:                { NSSRC_DNS, _dns_getaddrinfo, NULL },  /* force -DHESIOD */
                    572:                NS_NIS_CB(_yp_getaddrinfo, NULL)
                    573:                { 0 }
                    574:        };
1.14      itojun    575:
1.51      lukem     576:        _DIAGASSERT(pai != NULL);
                    577:        /* hostname may be NULL */
                    578:        /* servname may be NULL */
                    579:        _DIAGASSERT(res != NULL);
                    580:
1.32      itojun    581:        result = NULL;
1.14      itojun    582:
                    583:        /*
                    584:         * if the servname does not match socktype/protocol, ignore it.
                    585:         */
                    586:        if (get_portmatch(pai, servname) != 0)
                    587:                return 0;
                    588:
1.32      itojun    589:        switch (nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo",
                    590:                        default_dns_files, hostname, pai)) {
                    591:        case NS_TRYAGAIN:
                    592:                error = EAI_AGAIN;
                    593:                goto free;
                    594:        case NS_UNAVAIL:
1.14      itojun    595:                error = EAI_FAIL;
                    596:                goto free;
1.32      itojun    597:        case NS_NOTFOUND:
                    598:                error = EAI_NODATA;
1.15      itojun    599:                goto free;
1.32      itojun    600:        case NS_SUCCESS:
                    601:                error = 0;
                    602:                for (cur = result; cur; cur = cur->ai_next) {
                    603:                        GET_PORT(cur, servname);
                    604:                        /* canonname should be filled already */
1.16      itojun    605:                }
1.32      itojun    606:                break;
1.16      itojun    607:        }
1.15      itojun    608:
1.32      itojun    609:        *res = result;
1.14      itojun    610:
                    611:        return 0;
                    612:
                    613: free:
1.34      itojun    614:        if (result)
                    615:                freeaddrinfo(result);
1.14      itojun    616:        return error;
                    617: }
                    618:
                    619: /*
                    620:  * hostname == NULL.
                    621:  * passive socket -> anyaddr (0.0.0.0 or ::)
                    622:  * non-passive socket -> localhost (127.0.0.1 or ::1)
                    623:  */
                    624: static int
1.70      christos  625: explore_null(const struct addrinfo *pai, const char *servname,
                    626:     struct addrinfo **res)
1.14      itojun    627: {
                    628:        int s;
                    629:        const struct afd *afd;
                    630:        struct addrinfo *cur;
                    631:        struct addrinfo sentinel;
                    632:        int error;
                    633:
1.51      lukem     634:        _DIAGASSERT(pai != NULL);
                    635:        /* servname may be NULL */
                    636:        _DIAGASSERT(res != NULL);
                    637:
1.14      itojun    638:        *res = NULL;
                    639:        sentinel.ai_next = NULL;
                    640:        cur = &sentinel;
                    641:
                    642:        /*
                    643:         * filter out AFs that are not supported by the kernel
                    644:         * XXX errno?
                    645:         */
                    646:        s = socket(pai->ai_family, SOCK_DGRAM, 0);
                    647:        if (s < 0) {
                    648:                if (errno != EMFILE)
                    649:                        return 0;
                    650:        } else
                    651:                close(s);
                    652:
                    653:        /*
                    654:         * if the servname does not match socktype/protocol, ignore it.
                    655:         */
                    656:        if (get_portmatch(pai, servname) != 0)
                    657:                return 0;
                    658:
                    659:        afd = find_afd(pai->ai_family);
1.42      itojun    660:        if (afd == NULL)
                    661:                return 0;
1.14      itojun    662:
                    663:        if (pai->ai_flags & AI_PASSIVE) {
                    664:                GET_AI(cur->ai_next, afd, afd->a_addrany);
                    665:                /* xxx meaningless?
                    666:                 * GET_CANONNAME(cur->ai_next, "anyaddr");
                    667:                 */
                    668:                GET_PORT(cur->ai_next, servname);
                    669:        } else {
                    670:                GET_AI(cur->ai_next, afd, afd->a_loopback);
                    671:                /* xxx meaningless?
                    672:                 * GET_CANONNAME(cur->ai_next, "localhost");
                    673:                 */
                    674:                GET_PORT(cur->ai_next, servname);
                    675:        }
                    676:        cur = cur->ai_next;
                    677:
                    678:        *res = sentinel.ai_next;
                    679:        return 0;
                    680:
                    681: free:
                    682:        if (sentinel.ai_next)
                    683:                freeaddrinfo(sentinel.ai_next);
                    684:        return error;
                    685: }
                    686:
                    687: /*
                    688:  * numeric hostname
                    689:  */
                    690: static int
1.70      christos  691: explore_numeric(const struct addrinfo *pai, const char *hostname,
                    692:     const char *servname, struct addrinfo **res, const char *canonname)
1.14      itojun    693: {
                    694:        const struct afd *afd;
                    695:        struct addrinfo *cur;
                    696:        struct addrinfo sentinel;
                    697:        int error;
                    698:        char pton[PTON_MAX];
                    699:
1.51      lukem     700:        _DIAGASSERT(pai != NULL);
                    701:        /* hostname may be NULL */
                    702:        /* servname may be NULL */
                    703:        _DIAGASSERT(res != NULL);
                    704:
1.14      itojun    705:        *res = NULL;
                    706:        sentinel.ai_next = NULL;
                    707:        cur = &sentinel;
                    708:
                    709:        /*
                    710:         * if the servname does not match socktype/protocol, ignore it.
                    711:         */
                    712:        if (get_portmatch(pai, servname) != 0)
                    713:                return 0;
                    714:
                    715:        afd = find_afd(pai->ai_family);
1.42      itojun    716:        if (afd == NULL)
                    717:                return 0;
1.14      itojun    718:
1.27      itojun    719:        switch (afd->a_af) {
                    720: #if 0 /*X/Open spec*/
                    721:        case AF_INET:
                    722:                if (inet_aton(hostname, (struct in_addr *)pton) == 1) {
                    723:                        if (pai->ai_family == afd->a_af ||
                    724:                            pai->ai_family == PF_UNSPEC /*?*/) {
                    725:                                GET_AI(cur->ai_next, afd, pton);
                    726:                                GET_PORT(cur->ai_next, servname);
1.65      itojun    727:                                if ((pai->ai_flags & AI_CANONNAME)) {
                    728:                                        /*
                    729:                                         * Set the numeric address itself as
                    730:                                         * the canonical name, based on a
                    731:                                         * clarification in rfc2553bis-03.
                    732:                                         */
                    733:                                        GET_CANONNAME(cur->ai_next, canonname);
                    734:                                }
1.27      itojun    735:                                while (cur && cur->ai_next)
                    736:                                        cur = cur->ai_next;
1.42      itojun    737:                        } else
1.27      itojun    738:                                ERR(EAI_FAMILY);        /*xxx*/
                    739:                }
                    740:                break;
                    741: #endif
                    742:        default:
                    743:                if (inet_pton(afd->a_af, hostname, pton) == 1) {
                    744:                        if (pai->ai_family == afd->a_af ||
                    745:                            pai->ai_family == PF_UNSPEC /*?*/) {
                    746:                                GET_AI(cur->ai_next, afd, pton);
                    747:                                GET_PORT(cur->ai_next, servname);
1.65      itojun    748:                                if ((pai->ai_flags & AI_CANONNAME)) {
                    749:                                        /*
                    750:                                         * Set the numeric address itself as
                    751:                                         * the canonical name, based on a
                    752:                                         * clarification in rfc2553bis-03.
                    753:                                         */
                    754:                                        GET_CANONNAME(cur->ai_next, canonname);
                    755:                                }
1.27      itojun    756:                                while (cur && cur->ai_next)
                    757:                                        cur = cur->ai_next;
1.42      itojun    758:                        } else
1.27      itojun    759:                                ERR(EAI_FAMILY);        /*xxx*/
                    760:                }
                    761:                break;
1.1       itojun    762:        }
                    763:
1.14      itojun    764:        *res = sentinel.ai_next;
                    765:        return 0;
                    766:
                    767: free:
                    768: bad:
                    769:        if (sentinel.ai_next)
                    770:                freeaddrinfo(sentinel.ai_next);
                    771:        return error;
                    772: }
                    773:
                    774: /*
                    775:  * numeric hostname with scope
                    776:  */
                    777: static int
1.70      christos  778: explore_numeric_scope(const struct addrinfo *pai, const char *hostname,
                    779:     const char *servname, struct addrinfo **res)
1.14      itojun    780: {
1.29      itojun    781: #if !defined(SCOPE_DELIMITER) || !defined(INET6)
1.65      itojun    782:        return explore_numeric(pai, hostname, servname, res, hostname);
1.14      itojun    783: #else
                    784:        const struct afd *afd;
                    785:        struct addrinfo *cur;
                    786:        int error;
1.30      itojun    787:        char *cp, *hostname2 = NULL, *scope, *addr;
1.14      itojun    788:        struct sockaddr_in6 *sin6;
                    789:
1.51      lukem     790:        _DIAGASSERT(pai != NULL);
                    791:        /* hostname may be NULL */
                    792:        /* servname may be NULL */
                    793:        _DIAGASSERT(res != NULL);
                    794:
1.14      itojun    795:        /*
                    796:         * if the servname does not match socktype/protocol, ignore it.
                    797:         */
                    798:        if (get_portmatch(pai, servname) != 0)
                    799:                return 0;
                    800:
                    801:        afd = find_afd(pai->ai_family);
1.42      itojun    802:        if (afd == NULL)
                    803:                return 0;
                    804:
1.14      itojun    805:        if (!afd->a_scoped)
1.65      itojun    806:                return explore_numeric(pai, hostname, servname, res, hostname);
1.14      itojun    807:
                    808:        cp = strchr(hostname, SCOPE_DELIMITER);
                    809:        if (cp == NULL)
1.65      itojun    810:                return explore_numeric(pai, hostname, servname, res, hostname);
1.14      itojun    811:
1.30      itojun    812:        /*
                    813:         * Handle special case of <scoped_address><delimiter><scope id>
                    814:         */
                    815:        hostname2 = strdup(hostname);
                    816:        if (hostname2 == NULL)
                    817:                return EAI_MEMORY;
                    818:        /* terminate at the delimiter */
                    819:        hostname2[cp - hostname] = '\0';
                    820:        addr = hostname2;
                    821:        scope = cp + 1;
1.1       itojun    822:
1.65      itojun    823:        error = explore_numeric(pai, addr, servname, res, hostname);
1.1       itojun    824:        if (error == 0) {
1.59      itojun    825:                u_int32_t scopeid;
1.27      itojun    826:
1.14      itojun    827:                for (cur = *res; cur; cur = cur->ai_next) {
                    828:                        if (cur->ai_family != AF_INET6)
                    829:                                continue;
1.36      christos  830:                        sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr;
1.60      itojun    831:                        if (ip6_str2scopeid(scope, sin6, &scopeid) == -1) {
1.27      itojun    832:                                free(hostname2);
1.43      itojun    833:                                return(EAI_NODATA); /* XXX: is return OK? */
1.27      itojun    834:                        }
                    835:                        sin6->sin6_scope_id = scopeid;
1.14      itojun    836:                }
1.1       itojun    837:        }
1.14      itojun    838:
                    839:        free(hostname2);
                    840:
1.1       itojun    841:        return error;
1.14      itojun    842: #endif
1.1       itojun    843: }
                    844:
                    845: static int
1.70      christos  846: get_canonname(const struct addrinfo *pai, struct addrinfo *ai, const char *str)
1.1       itojun    847: {
1.51      lukem     848:
                    849:        _DIAGASSERT(pai != NULL);
                    850:        _DIAGASSERT(ai != NULL);
                    851:        _DIAGASSERT(str != NULL);
                    852:
1.14      itojun    853:        if ((pai->ai_flags & AI_CANONNAME) != 0) {
1.66      itojun    854:                ai->ai_canonname = strdup(str);
1.14      itojun    855:                if (ai->ai_canonname == NULL)
                    856:                        return EAI_MEMORY;
                    857:        }
                    858:        return 0;
                    859: }
1.1       itojun    860:
1.14      itojun    861: static struct addrinfo *
1.70      christos  862: get_ai(const struct addrinfo *pai, const struct afd *afd, const char *addr)
1.14      itojun    863: {
                    864:        char *p;
                    865:        struct addrinfo *ai;
1.12      lukem     866:
1.51      lukem     867:        _DIAGASSERT(pai != NULL);
                    868:        _DIAGASSERT(afd != NULL);
                    869:        _DIAGASSERT(addr != NULL);
                    870:
1.14      itojun    871:        ai = (struct addrinfo *)malloc(sizeof(struct addrinfo)
                    872:                + (afd->a_socklen));
                    873:        if (ai == NULL)
                    874:                return NULL;
                    875:
                    876:        memcpy(ai, pai, sizeof(struct addrinfo));
1.36      christos  877:        ai->ai_addr = (struct sockaddr *)(void *)(ai + 1);
1.20      mycroft   878:        memset(ai->ai_addr, 0, (size_t)afd->a_socklen);
1.14      itojun    879:        ai->ai_addr->sa_len = afd->a_socklen;
                    880:        ai->ai_addrlen = afd->a_socklen;
1.55      kleink    881: #if defined (__alpha__) || (defined(__i386__) && defined(_LP64)) || defined(__sparc64__)
                    882:        ai->__ai_pad0 = 0;
                    883: #endif
1.14      itojun    884:        ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
1.36      christos  885:        p = (char *)(void *)(ai->ai_addr);
1.20      mycroft   886:        memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen);
1.14      itojun    887:        return ai;
                    888: }
1.1       itojun    889:
1.14      itojun    890: static int
1.70      christos  891: get_portmatch(const struct addrinfo *ai, const char *servname)
1.14      itojun    892: {
1.4       itojun    893:
1.51      lukem     894:        _DIAGASSERT(ai != NULL);
                    895:        /* servname may be NULL */
                    896:
1.75      yamt      897:        return get_port(ai, servname, 1);
1.1       itojun    898: }
                    899:
                    900: static int
1.75      yamt      901: get_port(const struct addrinfo *ai, const char *servname, int matchonly)
1.1       itojun    902: {
1.14      itojun    903:        const char *proto;
                    904:        struct servent *sp;
                    905:        int port;
                    906:        int allownumeric;
1.12      lukem     907:
1.51      lukem     908:        _DIAGASSERT(ai != NULL);
                    909:        /* servname may be NULL */
                    910:
1.14      itojun    911:        if (servname == NULL)
                    912:                return 0;
1.23      itojun    913:        switch (ai->ai_family) {
                    914:        case AF_INET:
1.27      itojun    915: #ifdef AF_INET6
1.23      itojun    916:        case AF_INET6:
1.27      itojun    917: #endif
1.23      itojun    918:                break;
                    919:        default:
1.14      itojun    920:                return 0;
1.23      itojun    921:        }
1.1       itojun    922:
1.14      itojun    923:        switch (ai->ai_socktype) {
                    924:        case SOCK_RAW:
                    925:                return EAI_SERVICE;
                    926:        case SOCK_DGRAM:
                    927:        case SOCK_STREAM:
                    928:                allownumeric = 1;
                    929:                break;
                    930:        case ANY:
                    931:                allownumeric = 0;
                    932:                break;
                    933:        default:
                    934:                return EAI_SOCKTYPE;
1.1       itojun    935:        }
1.14      itojun    936:
1.67      itojun    937:        port = str2number(servname);
                    938:        if (port >= 0) {
1.14      itojun    939:                if (!allownumeric)
                    940:                        return EAI_SERVICE;
                    941:                if (port < 0 || port > 65535)
                    942:                        return EAI_SERVICE;
1.58      itojun    943:                port = htons(port);
1.14      itojun    944:        } else {
1.67      itojun    945:                if (ai->ai_flags & AI_NUMERICSERV)
                    946:                        return EAI_NONAME;
                    947:
1.14      itojun    948:                switch (ai->ai_socktype) {
                    949:                case SOCK_DGRAM:
                    950:                        proto = "udp";
1.1       itojun    951:                        break;
1.14      itojun    952:                case SOCK_STREAM:
                    953:                        proto = "tcp";
1.1       itojun    954:                        break;
                    955:                default:
1.14      itojun    956:                        proto = NULL;
1.1       itojun    957:                        break;
                    958:                }
1.14      itojun    959:
                    960:                if ((sp = getservbyname(servname, proto)) == NULL)
                    961:                        return EAI_SERVICE;
                    962:                port = sp->s_port;
1.1       itojun    963:        }
                    964:
1.14      itojun    965:        if (!matchonly) {
                    966:                switch (ai->ai_family) {
1.1       itojun    967:                case AF_INET:
1.36      christos  968:                        ((struct sockaddr_in *)(void *)
                    969:                            ai->ai_addr)->sin_port = port;
1.1       itojun    970:                        break;
                    971: #ifdef INET6
1.14      itojun    972:                case AF_INET6:
1.36      christos  973:                        ((struct sockaddr_in6 *)(void *)
                    974:                            ai->ai_addr)->sin6_port = port;
1.1       itojun    975:                        break;
                    976: #endif
                    977:                }
1.14      itojun    978:        }
                    979:
                    980:        return 0;
                    981: }
                    982:
                    983: static const struct afd *
1.70      christos  984: find_afd(int af)
1.14      itojun    985: {
                    986:        const struct afd *afd;
1.1       itojun    987:
1.14      itojun    988:        if (af == PF_UNSPEC)
                    989:                return NULL;
                    990:        for (afd = afdl; afd->a_af; afd++) {
                    991:                if (afd->a_af == af)
                    992:                        return afd;
1.1       itojun    993:        }
1.14      itojun    994:        return NULL;
1.1       itojun    995: }
1.27      itojun    996:
                    997: #ifdef INET6
                    998: /* convert a string to a scope identifier. XXX: IPv6 specific */
1.60      itojun    999: static int
1.70      christos 1000: ip6_str2scopeid(char *scope, struct sockaddr_in6 *sin6, u_int32_t *scopeid)
1.27      itojun   1001: {
1.59      itojun   1002:        u_long lscopeid;
1.51      lukem    1003:        struct in6_addr *a6;
1.27      itojun   1004:        char *ep;
1.46      itojun   1005:
1.51      lukem    1006:        _DIAGASSERT(scope != NULL);
                   1007:        _DIAGASSERT(sin6 != NULL);
1.60      itojun   1008:        _DIAGASSERT(scopeid != NULL);
1.51      lukem    1009:
                   1010:        a6 = &sin6->sin6_addr;
                   1011:
1.46      itojun   1012:        /* empty scopeid portion is invalid */
                   1013:        if (*scope == '\0')
                   1014:                return -1;
1.27      itojun   1015:
                   1016:        if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) {
                   1017:                /*
                   1018:                 * We currently assume a one-to-one mapping between links
                   1019:                 * and interfaces, so we simply use interface indices for
                   1020:                 * like-local scopes.
                   1021:                 */
1.60      itojun   1022:                *scopeid = if_nametoindex(scope);
                   1023:                if (*scopeid == 0)
1.27      itojun   1024:                        goto trynumeric;
1.60      itojun   1025:                return 0;
1.27      itojun   1026:        }
                   1027:
                   1028:        /* still unclear about literal, allow numeric only - placeholder */
                   1029:        if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6))
                   1030:                goto trynumeric;
                   1031:        if (IN6_IS_ADDR_MC_ORGLOCAL(a6))
                   1032:                goto trynumeric;
                   1033:        else
                   1034:                goto trynumeric;        /* global */
                   1035:
                   1036:        /* try to convert to a numeric id as a last resort */
                   1037:   trynumeric:
1.59      itojun   1038:        errno = 0;
                   1039:        lscopeid = strtoul(scope, &ep, 10);
1.61      itojun   1040:        *scopeid = (u_int32_t)(lscopeid & 0xffffffffUL);
1.60      itojun   1041:        if (errno == 0 && ep && *ep == '\0' && *scopeid == lscopeid)
                   1042:                return 0;
1.27      itojun   1043:        else
                   1044:                return -1;
                   1045: }
1.42      itojun   1046: #endif
1.32      itojun   1047:
                   1048: /* code duplicate with gethnamaddr.c */
                   1049:
                   1050: static const char AskedForGot[] =
                   1051:        "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
                   1052:
                   1053: static struct addrinfo *
1.70      christos 1054: getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
                   1055:     const struct addrinfo *pai)
1.32      itojun   1056: {
                   1057:        struct addrinfo sentinel, *cur;
                   1058:        struct addrinfo ai;
                   1059:        const struct afd *afd;
                   1060:        char *canonname;
                   1061:        const HEADER *hp;
                   1062:        const u_char *cp;
                   1063:        int n;
                   1064:        const u_char *eom;
1.56      itojun   1065:        char *bp, *ep;
                   1066:        int type, class, ancount, qdcount;
1.32      itojun   1067:        int haveanswer, had_error;
                   1068:        char tbuf[MAXDNAME];
1.70      christos 1069:        int (*name_ok) (const char *);
1.32      itojun   1070:        char hostbuf[8*1024];
                   1071:
1.51      lukem    1072:        _DIAGASSERT(answer != NULL);
                   1073:        _DIAGASSERT(qname != NULL);
                   1074:        _DIAGASSERT(pai != NULL);
                   1075:
1.32      itojun   1076:        memset(&sentinel, 0, sizeof(sentinel));
                   1077:        cur = &sentinel;
                   1078:
                   1079:        canonname = NULL;
                   1080:        eom = answer->buf + anslen;
                   1081:        switch (qtype) {
                   1082:        case T_A:
                   1083:        case T_AAAA:
                   1084:        case T_ANY:     /*use T_ANY only for T_A/T_AAAA lookup*/
                   1085:                name_ok = res_hnok;
                   1086:                break;
                   1087:        default:
1.70      christos 1088:                return NULL;    /* XXX should be abort(); */
1.32      itojun   1089:        }
                   1090:        /*
                   1091:         * find first satisfactory answer
                   1092:         */
                   1093:        hp = &answer->hdr;
                   1094:        ancount = ntohs(hp->ancount);
                   1095:        qdcount = ntohs(hp->qdcount);
                   1096:        bp = hostbuf;
1.56      itojun   1097:        ep = hostbuf + sizeof hostbuf;
1.32      itojun   1098:        cp = answer->buf + HFIXEDSZ;
                   1099:        if (qdcount != 1) {
                   1100:                h_errno = NO_RECOVERY;
                   1101:                return (NULL);
                   1102:        }
1.56      itojun   1103:        n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
1.32      itojun   1104:        if ((n < 0) || !(*name_ok)(bp)) {
                   1105:                h_errno = NO_RECOVERY;
                   1106:                return (NULL);
                   1107:        }
                   1108:        cp += n + QFIXEDSZ;
                   1109:        if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) {
                   1110:                /* res_send() has already verified that the query name is the
                   1111:                 * same as the one we sent; this just gets the expanded name
                   1112:                 * (i.e., with the succeeding search-domain tacked on).
                   1113:                 */
                   1114:                n = strlen(bp) + 1;             /* for the \0 */
                   1115:                if (n >= MAXHOSTNAMELEN) {
                   1116:                        h_errno = NO_RECOVERY;
                   1117:                        return (NULL);
                   1118:                }
                   1119:                canonname = bp;
                   1120:                bp += n;
                   1121:                /* The qname can be abbreviated, but h_name is now absolute. */
                   1122:                qname = canonname;
                   1123:        }
                   1124:        haveanswer = 0;
                   1125:        had_error = 0;
                   1126:        while (ancount-- > 0 && cp < eom && !had_error) {
1.56      itojun   1127:                n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
1.32      itojun   1128:                if ((n < 0) || !(*name_ok)(bp)) {
                   1129:                        had_error++;
                   1130:                        continue;
                   1131:                }
                   1132:                cp += n;                        /* name */
                   1133:                type = _getshort(cp);
                   1134:                cp += INT16SZ;                  /* type */
                   1135:                class = _getshort(cp);
                   1136:                cp += INT16SZ + INT32SZ;        /* class, TTL */
                   1137:                n = _getshort(cp);
                   1138:                cp += INT16SZ;                  /* len */
                   1139:                if (class != C_IN) {
                   1140:                        /* XXX - debug? syslog? */
                   1141:                        cp += n;
                   1142:                        continue;               /* XXX - had_error++ ? */
                   1143:                }
                   1144:                if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) &&
                   1145:                    type == T_CNAME) {
                   1146:                        n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
                   1147:                        if ((n < 0) || !(*name_ok)(tbuf)) {
                   1148:                                had_error++;
                   1149:                                continue;
                   1150:                        }
                   1151:                        cp += n;
                   1152:                        /* Get canonical name. */
                   1153:                        n = strlen(tbuf) + 1;   /* for the \0 */
1.56      itojun   1154:                        if (n > ep - bp || n >= MAXHOSTNAMELEN) {
1.32      itojun   1155:                                had_error++;
                   1156:                                continue;
                   1157:                        }
1.66      itojun   1158:                        strlcpy(bp, tbuf, (size_t)(ep - bp));
1.32      itojun   1159:                        canonname = bp;
                   1160:                        bp += n;
                   1161:                        continue;
                   1162:                }
                   1163:                if (qtype == T_ANY) {
                   1164:                        if (!(type == T_A || type == T_AAAA)) {
                   1165:                                cp += n;
                   1166:                                continue;
                   1167:                        }
                   1168:                } else if (type != qtype) {
                   1169:                        if (type != T_KEY && type != T_SIG)
                   1170:                                syslog(LOG_NOTICE|LOG_AUTH,
                   1171:               "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
                   1172:                                       qname, p_class(C_IN), p_type(qtype),
                   1173:                                       p_type(type));
                   1174:                        cp += n;
                   1175:                        continue;               /* XXX - had_error++ ? */
                   1176:                }
                   1177:                switch (type) {
                   1178:                case T_A:
                   1179:                case T_AAAA:
                   1180:                        if (strcasecmp(canonname, bp) != 0) {
                   1181:                                syslog(LOG_NOTICE|LOG_AUTH,
                   1182:                                       AskedForGot, canonname, bp);
                   1183:                                cp += n;
                   1184:                                continue;       /* XXX - had_error++ ? */
                   1185:                        }
                   1186:                        if (type == T_A && n != INADDRSZ) {
                   1187:                                cp += n;
                   1188:                                continue;
                   1189:                        }
                   1190:                        if (type == T_AAAA && n != IN6ADDRSZ) {
                   1191:                                cp += n;
                   1192:                                continue;
1.62      itojun   1193:                        }
                   1194:                        if (type == T_AAAA) {
                   1195:                                struct in6_addr in6;
                   1196:                                memcpy(&in6, cp, IN6ADDRSZ);
                   1197:                                if (IN6_IS_ADDR_V4MAPPED(&in6)) {
                   1198:                                        cp += n;
                   1199:                                        continue;
                   1200:                                }
1.32      itojun   1201:                        }
                   1202:                        if (!haveanswer) {
                   1203:                                int nn;
                   1204:
                   1205:                                canonname = bp;
                   1206:                                nn = strlen(bp) + 1;    /* for the \0 */
                   1207:                                bp += nn;
                   1208:                        }
                   1209:
                   1210:                        /* don't overwrite pai */
                   1211:                        ai = *pai;
                   1212:                        ai.ai_family = (type == T_A) ? AF_INET : AF_INET6;
                   1213:                        afd = find_afd(ai.ai_family);
                   1214:                        if (afd == NULL) {
                   1215:                                cp += n;
                   1216:                                continue;
                   1217:                        }
1.36      christos 1218:                        cur->ai_next = get_ai(&ai, afd, (const char *)cp);
1.32      itojun   1219:                        if (cur->ai_next == NULL)
                   1220:                                had_error++;
                   1221:                        while (cur && cur->ai_next)
                   1222:                                cur = cur->ai_next;
                   1223:                        cp += n;
                   1224:                        break;
                   1225:                default:
                   1226:                        abort();
                   1227:                }
                   1228:                if (!had_error)
                   1229:                        haveanswer++;
                   1230:        }
                   1231:        if (haveanswer) {
                   1232:                if (!canonname)
                   1233:                        (void)get_canonname(pai, sentinel.ai_next, qname);
                   1234:                else
                   1235:                        (void)get_canonname(pai, sentinel.ai_next, canonname);
                   1236:                h_errno = NETDB_SUCCESS;
                   1237:                return sentinel.ai_next;
                   1238:        }
                   1239:
                   1240:        h_errno = NO_RECOVERY;
                   1241:        return NULL;
                   1242: }
                   1243:
1.73      tsarna   1244: #define SORTEDADDR(p)  (((struct sockaddr_in *)(void *)(p->ai_next->ai_addr))->sin_addr.s_addr)
                   1245: #define SORTMATCH(p, s) ((SORTEDADDR(p) & (s).mask) == (s).addr.s_addr)
                   1246:
                   1247: static void
                   1248: aisort(struct addrinfo *s, res_state res)
                   1249: {
                   1250:        struct addrinfo head, *t, *p;
                   1251:        int i;
                   1252:
                   1253:        head.ai_next = NULL;
                   1254:        t = &head;
                   1255:
                   1256:        for (i = 0; i < res->nsort; i++) {
                   1257:                p = s;
                   1258:                while (p->ai_next) {
                   1259:                        if ((p->ai_next->ai_family != AF_INET)
                   1260:                        || SORTMATCH(p, res->sort_list[i])) {
                   1261:                                t->ai_next = p->ai_next;
                   1262:                                t = t->ai_next;
                   1263:                                p->ai_next = p->ai_next->ai_next;
                   1264:                        } else {
                   1265:                                p = p->ai_next;
                   1266:                        }
                   1267:                }
                   1268:        }
                   1269:
                   1270:        /* add rest of list and reset s to the new list*/
                   1271:        t->ai_next = s->ai_next;
                   1272:        s->ai_next = head.ai_next;
                   1273: }
                   1274:
1.32      itojun   1275: /*ARGSUSED*/
                   1276: static int
1.70      christos 1277: _dns_getaddrinfo(void *rv, void        *cb_data, va_list ap)
1.32      itojun   1278: {
                   1279:        struct addrinfo *ai;
1.63      itojun   1280:        querybuf *buf, *buf2;
1.32      itojun   1281:        const char *name;
                   1282:        const struct addrinfo *pai;
                   1283:        struct addrinfo sentinel, *cur;
                   1284:        struct res_target q, q2;
1.73      tsarna   1285:        res_state res;
1.32      itojun   1286:
                   1287:        name = va_arg(ap, char *);
                   1288:        pai = va_arg(ap, const struct addrinfo *);
                   1289:
                   1290:        memset(&q, 0, sizeof(q2));
                   1291:        memset(&q2, 0, sizeof(q2));
                   1292:        memset(&sentinel, 0, sizeof(sentinel));
                   1293:        cur = &sentinel;
                   1294:
1.63      itojun   1295:        buf = malloc(sizeof(*buf));
                   1296:        if (buf == NULL) {
                   1297:                h_errno = NETDB_INTERNAL;
                   1298:                return NS_NOTFOUND;
                   1299:        }
                   1300:        buf2 = malloc(sizeof(*buf2));
                   1301:        if (buf2 == NULL) {
                   1302:                free(buf);
                   1303:                h_errno = NETDB_INTERNAL;
                   1304:                return NS_NOTFOUND;
                   1305:        }
                   1306:
1.32      itojun   1307:        switch (pai->ai_family) {
                   1308:        case AF_UNSPEC:
                   1309:                /* prefer IPv6 */
1.52      itojun   1310:                q.name = name;
1.43      itojun   1311:                q.qclass = C_IN;
                   1312:                q.qtype = T_AAAA;
1.63      itojun   1313:                q.answer = buf->buf;
                   1314:                q.anslen = sizeof(buf->buf);
1.32      itojun   1315:                q.next = &q2;
1.52      itojun   1316:                q2.name = name;
1.43      itojun   1317:                q2.qclass = C_IN;
                   1318:                q2.qtype = T_A;
1.63      itojun   1319:                q2.answer = buf2->buf;
                   1320:                q2.anslen = sizeof(buf2->buf);
1.32      itojun   1321:                break;
                   1322:        case AF_INET:
1.52      itojun   1323:                q.name = name;
1.43      itojun   1324:                q.qclass = C_IN;
                   1325:                q.qtype = T_A;
1.63      itojun   1326:                q.answer = buf->buf;
                   1327:                q.anslen = sizeof(buf->buf);
1.32      itojun   1328:                break;
                   1329:        case AF_INET6:
1.52      itojun   1330:                q.name = name;
1.43      itojun   1331:                q.qclass = C_IN;
                   1332:                q.qtype = T_AAAA;
1.63      itojun   1333:                q.answer = buf->buf;
                   1334:                q.anslen = sizeof(buf->buf);
1.32      itojun   1335:                break;
                   1336:        default:
1.63      itojun   1337:                free(buf);
                   1338:                free(buf2);
1.32      itojun   1339:                return NS_UNAVAIL;
                   1340:        }
1.73      tsarna   1341:
                   1342:        res = __res_get_state();
                   1343:        if (res == NULL) {
                   1344:                free(buf);
                   1345:                free(buf2);
                   1346:                return NS_NOTFOUND;
                   1347:        }
                   1348:
                   1349:        if (res_searchN(name, &q, res) < 0) {
                   1350:                __res_put_state(res);
1.63      itojun   1351:                free(buf);
                   1352:                free(buf2);
1.32      itojun   1353:                return NS_NOTFOUND;
1.63      itojun   1354:        }
                   1355:        ai = getanswer(buf, q.n, q.name, q.qtype, pai);
1.32      itojun   1356:        if (ai) {
                   1357:                cur->ai_next = ai;
                   1358:                while (cur && cur->ai_next)
                   1359:                        cur = cur->ai_next;
                   1360:        }
                   1361:        if (q.next) {
1.63      itojun   1362:                ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai);
1.32      itojun   1363:                if (ai)
                   1364:                        cur->ai_next = ai;
                   1365:        }
1.63      itojun   1366:        free(buf);
                   1367:        free(buf2);
1.73      tsarna   1368:        if (sentinel.ai_next == NULL) {
                   1369:                __res_put_state(res);
1.32      itojun   1370:                switch (h_errno) {
                   1371:                case HOST_NOT_FOUND:
                   1372:                        return NS_NOTFOUND;
                   1373:                case TRY_AGAIN:
                   1374:                        return NS_TRYAGAIN;
                   1375:                default:
                   1376:                        return NS_UNAVAIL;
                   1377:                }
1.73      tsarna   1378:        }
                   1379:
                   1380:        if (res->nsort)
                   1381:                aisort(&sentinel, res);
                   1382:
                   1383:        __res_put_state(res);
                   1384:
1.32      itojun   1385:        *((struct addrinfo **)rv) = sentinel.ai_next;
                   1386:        return NS_SUCCESS;
                   1387: }
                   1388:
                   1389: static void
1.70      christos 1390: _sethtent(FILE **hostf)
1.32      itojun   1391: {
1.51      lukem    1392:
1.70      christos 1393:        if (!*hostf)
                   1394:                *hostf = fopen(_PATH_HOSTS, "r" );
1.32      itojun   1395:        else
1.70      christos 1396:                rewind(*hostf);
1.32      itojun   1397: }
                   1398:
                   1399: static void
1.70      christos 1400: _endhtent(FILE **hostf)
1.32      itojun   1401: {
1.51      lukem    1402:
1.70      christos 1403:        if (*hostf) {
                   1404:                (void) fclose(*hostf);
                   1405:                *hostf = NULL;
1.32      itojun   1406:        }
                   1407: }
                   1408:
                   1409: static struct addrinfo *
1.70      christos 1410: _gethtent(FILE **hostf, const char *name, const struct addrinfo *pai)
1.32      itojun   1411: {
                   1412:        char *p;
1.48      itojun   1413:        char *cp, *tname, *cname;
1.32      itojun   1414:        struct addrinfo hints, *res0, *res;
                   1415:        int error;
                   1416:        const char *addr;
                   1417:        char hostbuf[8*1024];
                   1418:
1.51      lukem    1419:        _DIAGASSERT(name != NULL);
                   1420:        _DIAGASSERT(pai != NULL);
                   1421:
1.70      christos 1422:        if (!*hostf && !(*hostf = fopen(_PATH_HOSTS, "r" )))
1.32      itojun   1423:                return (NULL);
                   1424:  again:
1.70      christos 1425:        if (!(p = fgets(hostbuf, sizeof hostbuf, *hostf)))
1.32      itojun   1426:                return (NULL);
                   1427:        if (*p == '#')
                   1428:                goto again;
                   1429:        if (!(cp = strpbrk(p, "#\n")))
                   1430:                goto again;
                   1431:        *cp = '\0';
                   1432:        if (!(cp = strpbrk(p, " \t")))
                   1433:                goto again;
                   1434:        *cp++ = '\0';
                   1435:        addr = p;
                   1436:        /* if this is not something we're looking for, skip it. */
1.48      itojun   1437:        cname = NULL;
1.32      itojun   1438:        while (cp && *cp) {
                   1439:                if (*cp == ' ' || *cp == '\t') {
                   1440:                        cp++;
                   1441:                        continue;
                   1442:                }
1.48      itojun   1443:                if (!cname)
                   1444:                        cname = cp;
1.32      itojun   1445:                tname = cp;
                   1446:                if ((cp = strpbrk(cp, " \t")) != NULL)
                   1447:                        *cp++ = '\0';
                   1448:                if (strcasecmp(name, tname) == 0)
                   1449:                        goto found;
                   1450:        }
                   1451:        goto again;
                   1452:
                   1453: found:
                   1454:        hints = *pai;
                   1455:        hints.ai_flags = AI_NUMERICHOST;
                   1456:        error = getaddrinfo(addr, NULL, &hints, &res0);
                   1457:        if (error)
                   1458:                goto again;
                   1459:        for (res = res0; res; res = res->ai_next) {
                   1460:                /* cover it up */
                   1461:                res->ai_flags = pai->ai_flags;
                   1462:
                   1463:                if (pai->ai_flags & AI_CANONNAME) {
1.48      itojun   1464:                        if (get_canonname(pai, res, cname) != 0) {
1.32      itojun   1465:                                freeaddrinfo(res0);
                   1466:                                goto again;
                   1467:                        }
                   1468:                }
                   1469:        }
                   1470:        return res0;
                   1471: }
                   1472:
                   1473: /*ARGSUSED*/
                   1474: static int
1.70      christos 1475: _files_getaddrinfo(void *rv, void *cb_data, va_list ap)
1.32      itojun   1476: {
                   1477:        const char *name;
                   1478:        const struct addrinfo *pai;
                   1479:        struct addrinfo sentinel, *cur;
                   1480:        struct addrinfo *p;
1.70      christos 1481: #ifndef _REENTRANT
                   1482:        static
                   1483: #endif
                   1484:        FILE *hostf = NULL;
1.32      itojun   1485:
                   1486:        name = va_arg(ap, char *);
                   1487:        pai = va_arg(ap, struct addrinfo *);
                   1488:
                   1489:        memset(&sentinel, 0, sizeof(sentinel));
                   1490:        cur = &sentinel;
                   1491:
1.70      christos 1492:        _sethtent(&hostf);
                   1493:        while ((p = _gethtent(&hostf, name, pai)) != NULL) {
1.32      itojun   1494:                cur->ai_next = p;
                   1495:                while (cur && cur->ai_next)
                   1496:                        cur = cur->ai_next;
                   1497:        }
1.70      christos 1498:        _endhtent(&hostf);
1.32      itojun   1499:
                   1500:        *((struct addrinfo **)rv) = sentinel.ai_next;
                   1501:        if (sentinel.ai_next == NULL)
                   1502:                return NS_NOTFOUND;
                   1503:        return NS_SUCCESS;
                   1504: }
                   1505:
                   1506: #ifdef YP
                   1507: /*ARGSUSED*/
                   1508: static struct addrinfo *
1.70      christos 1509: _yphostent(char *line, const struct addrinfo *pai)
1.32      itojun   1510: {
                   1511:        struct addrinfo sentinel, *cur;
                   1512:        struct addrinfo hints, *res, *res0;
                   1513:        int error;
1.51      lukem    1514:        char *p;
1.32      itojun   1515:        const char *addr, *canonname;
                   1516:        char *nextline;
                   1517:        char *cp;
                   1518:
1.51      lukem    1519:        _DIAGASSERT(line != NULL);
                   1520:        _DIAGASSERT(pai != NULL);
                   1521:
                   1522:        p = line;
1.32      itojun   1523:        addr = canonname = NULL;
                   1524:
1.36      christos 1525:        memset(&sentinel, 0, sizeof(sentinel));
                   1526:        cur = &sentinel;
                   1527:
1.32      itojun   1528: nextline:
                   1529:        /* terminate line */
                   1530:        cp = strchr(p, '\n');
                   1531:        if (cp) {
                   1532:                *cp++ = '\0';
                   1533:                nextline = cp;
                   1534:        } else
                   1535:                nextline = NULL;
                   1536:
                   1537:        cp = strpbrk(p, " \t");
                   1538:        if (cp == NULL) {
                   1539:                if (canonname == NULL)
                   1540:                        return (NULL);
                   1541:                else
                   1542:                        goto done;
                   1543:        }
                   1544:        *cp++ = '\0';
                   1545:
                   1546:        addr = p;
                   1547:
                   1548:        while (cp && *cp) {
                   1549:                if (*cp == ' ' || *cp == '\t') {
                   1550:                        cp++;
                   1551:                        continue;
                   1552:                }
                   1553:                if (!canonname)
                   1554:                        canonname = cp;
                   1555:                if ((cp = strpbrk(cp, " \t")) != NULL)
                   1556:                        *cp++ = '\0';
                   1557:        }
                   1558:
                   1559:        hints = *pai;
                   1560:        hints.ai_flags = AI_NUMERICHOST;
                   1561:        error = getaddrinfo(addr, NULL, &hints, &res0);
                   1562:        if (error == 0) {
                   1563:                for (res = res0; res; res = res->ai_next) {
                   1564:                        /* cover it up */
                   1565:                        res->ai_flags = pai->ai_flags;
                   1566:
                   1567:                        if (pai->ai_flags & AI_CANONNAME)
                   1568:                                (void)get_canonname(pai, res, canonname);
                   1569:                }
1.37      itojun   1570:        } else
                   1571:                res0 = NULL;
1.32      itojun   1572:        if (res0) {
                   1573:                cur->ai_next = res0;
                   1574:                while (cur && cur->ai_next)
                   1575:                        cur = cur->ai_next;
                   1576:        }
                   1577:
                   1578:        if (nextline) {
                   1579:                p = nextline;
                   1580:                goto nextline;
                   1581:        }
                   1582:
                   1583: done:
                   1584:        return sentinel.ai_next;
                   1585: }
                   1586:
                   1587: /*ARGSUSED*/
                   1588: static int
1.70      christos 1589: _yp_getaddrinfo(void *rv, void *cb_data, va_list ap)
1.32      itojun   1590: {
                   1591:        struct addrinfo sentinel, *cur;
                   1592:        struct addrinfo *ai = NULL;
1.72      christos 1593:        char *ypbuf;
                   1594:        int ypbuflen, r;
1.32      itojun   1595:        const char *name;
                   1596:        const struct addrinfo *pai;
1.72      christos 1597:        char *ypdomain;
                   1598:
                   1599:        if (_yp_check(&ypdomain) == 0)
                   1600:                return NS_UNAVAIL;
1.32      itojun   1601:
                   1602:        name = va_arg(ap, char *);
                   1603:        pai = va_arg(ap, const struct addrinfo *);
                   1604:
                   1605:        memset(&sentinel, 0, sizeof(sentinel));
                   1606:        cur = &sentinel;
                   1607:
                   1608:        /* hosts.byname is only for IPv4 (Solaris8) */
1.33      itojun   1609:        if (pai->ai_family == PF_UNSPEC || pai->ai_family == PF_INET) {
1.72      christos 1610:                r = yp_match(ypdomain, "hosts.byname", name,
                   1611:                        (int)strlen(name), &ypbuf, &ypbuflen);
1.33      itojun   1612:                if (r == 0) {
                   1613:                        struct addrinfo ai4;
                   1614:
                   1615:                        ai4 = *pai;
                   1616:                        ai4.ai_family = AF_INET;
1.72      christos 1617:                        ai = _yphostent(ypbuf, &ai4);
1.33      itojun   1618:                        if (ai) {
                   1619:                                cur->ai_next = ai;
                   1620:                                while (cur && cur->ai_next)
                   1621:                                        cur = cur->ai_next;
                   1622:                        }
1.32      itojun   1623:                }
1.72      christos 1624:                free(ypbuf);
1.32      itojun   1625:        }
                   1626:
                   1627:        /* ipnodes.byname can hold both IPv4/v6 */
1.72      christos 1628:        r = yp_match(ypdomain, "ipnodes.byname", name,
                   1629:                (int)strlen(name), &ypbuf, &ypbuflen);
1.32      itojun   1630:        if (r == 0) {
1.72      christos 1631:                ai = _yphostent(ypbuf, pai);
                   1632:                if (ai)
1.32      itojun   1633:                        cur->ai_next = ai;
1.72      christos 1634:                free(ypbuf);
1.32      itojun   1635:        }
                   1636:
                   1637:        if (sentinel.ai_next == NULL) {
                   1638:                h_errno = HOST_NOT_FOUND;
                   1639:                return NS_NOTFOUND;
                   1640:        }
                   1641:        *((struct addrinfo **)rv) = sentinel.ai_next;
                   1642:        return NS_SUCCESS;
                   1643: }
                   1644: #endif
                   1645:
                   1646: /* resolver logic */
                   1647:
                   1648: /*
                   1649:  * Formulate a normal query, send, and await answer.
                   1650:  * Returned answer is placed in supplied buffer "answer".
                   1651:  * Perform preliminary check of answer, returning success only
                   1652:  * if no error is indicated and the answer count is nonzero.
                   1653:  * Return the size of the response on success, -1 on error.
                   1654:  * Error number is left in h_errno.
                   1655:  *
                   1656:  * Caller must parse answer and determine whether it answers the question.
                   1657:  */
                   1658: static int
1.70      christos 1659: res_queryN(const char *name, /* domain name */ struct res_target *target,
                   1660:     res_state res)
1.32      itojun   1661: {
                   1662:        u_char buf[MAXPACKET];
                   1663:        HEADER *hp;
                   1664:        int n;
                   1665:        struct res_target *t;
                   1666:        int rcode;
                   1667:        int ancount;
                   1668:
1.51      lukem    1669:        _DIAGASSERT(name != NULL);
                   1670:        /* XXX: target may be NULL??? */
                   1671:
1.32      itojun   1672:        rcode = NOERROR;
                   1673:        ancount = 0;
                   1674:
                   1675:        for (t = target; t; t = t->next) {
                   1676:                int class, type;
                   1677:                u_char *answer;
                   1678:                int anslen;
                   1679:
                   1680:                hp = (HEADER *)(void *)t->answer;
                   1681:                hp->rcode = NOERROR;    /* default */
                   1682:
                   1683:                /* make it easier... */
1.43      itojun   1684:                class = t->qclass;
                   1685:                type = t->qtype;
1.32      itojun   1686:                answer = t->answer;
                   1687:                anslen = t->anslen;
                   1688: #ifdef DEBUG
1.70      christos 1689:                if (res->options & RES_DEBUG)
                   1690:                        printf(";; res_nquery(%s, %d, %d)\n", name, class, type);
1.32      itojun   1691: #endif
                   1692:
1.70      christos 1693:                n = res_nmkquery(res, QUERY, name, class, type, NULL, 0, NULL,
1.32      itojun   1694:                    buf, sizeof(buf));
1.47      itojun   1695: #ifdef RES_USE_EDNS0
1.70      christos 1696:                if (n > 0 && (res->options & RES_USE_EDNS0) != 0)
                   1697:                        n = res_nopt(res, n, buf, sizeof(buf), anslen);
1.47      itojun   1698: #endif
1.32      itojun   1699:                if (n <= 0) {
                   1700: #ifdef DEBUG
1.70      christos 1701:                        if (res->options & RES_DEBUG)
                   1702:                                printf(";; res_nquery: mkquery failed\n");
1.32      itojun   1703: #endif
                   1704:                        h_errno = NO_RECOVERY;
1.70      christos 1705:                        return n;
1.32      itojun   1706:                }
1.70      christos 1707:                n = res_nsend(res, buf, n, answer, anslen);
1.35      itojun   1708: #if 0
1.32      itojun   1709:                if (n < 0) {
                   1710: #ifdef DEBUG
1.70      christos 1711:                        if (res->options & RES_DEBUG)
1.32      itojun   1712:                                printf(";; res_query: send error\n");
                   1713: #endif
                   1714:                        h_errno = TRY_AGAIN;
1.70      christos 1715:                        return n;
1.32      itojun   1716:                }
1.35      itojun   1717: #endif
1.32      itojun   1718:
1.35      itojun   1719:                if (n < 0 || hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
1.32      itojun   1720:                        rcode = hp->rcode;      /* record most recent error */
                   1721: #ifdef DEBUG
1.70      christos 1722:                        if (res->options & RES_DEBUG)
1.57      itojun   1723:                                printf(";; rcode = %u, ancount=%u\n", hp->rcode,
1.32      itojun   1724:                                    ntohs(hp->ancount));
                   1725: #endif
                   1726:                        continue;
                   1727:                }
                   1728:
                   1729:                ancount += ntohs(hp->ancount);
                   1730:
                   1731:                t->n = n;
                   1732:        }
                   1733:
                   1734:        if (ancount == 0) {
                   1735:                switch (rcode) {
                   1736:                case NXDOMAIN:
                   1737:                        h_errno = HOST_NOT_FOUND;
                   1738:                        break;
                   1739:                case SERVFAIL:
                   1740:                        h_errno = TRY_AGAIN;
                   1741:                        break;
                   1742:                case NOERROR:
                   1743:                        h_errno = NO_DATA;
                   1744:                        break;
                   1745:                case FORMERR:
                   1746:                case NOTIMP:
                   1747:                case REFUSED:
                   1748:                default:
                   1749:                        h_errno = NO_RECOVERY;
                   1750:                        break;
                   1751:                }
1.70      christos 1752:                return -1;
1.32      itojun   1753:        }
1.70      christos 1754:        return ancount;
1.32      itojun   1755: }
                   1756:
                   1757: /*
                   1758:  * Formulate a normal query, send, and retrieve answer in supplied buffer.
                   1759:  * Return the size of the response on success, -1 on error.
                   1760:  * If enabled, implement search rules until answer or unrecoverable failure
                   1761:  * is detected.  Error code, if any, is left in h_errno.
                   1762:  */
                   1763: static int
1.73      tsarna   1764: res_searchN(const char *name, struct res_target *target, res_state res)
1.32      itojun   1765: {
                   1766:        const char *cp, * const *domain;
1.51      lukem    1767:        HEADER *hp;
1.32      itojun   1768:        u_int dots;
                   1769:        int trailing_dot, ret, saved_herrno;
                   1770:        int got_nodata = 0, got_servfail = 0, tried_as_is = 0;
1.71      christos 1771:
1.51      lukem    1772:        _DIAGASSERT(name != NULL);
                   1773:        _DIAGASSERT(target != NULL);
                   1774:
                   1775:        hp = (HEADER *)(void *)target->answer;  /*XXX*/
                   1776:
1.32      itojun   1777:        errno = 0;
                   1778:        h_errno = HOST_NOT_FOUND;       /* default, if we never query */
                   1779:        dots = 0;
                   1780:        for (cp = name; *cp; cp++)
                   1781:                dots += (*cp == '.');
                   1782:        trailing_dot = 0;
                   1783:        if (cp > name && *--cp == '.')
                   1784:                trailing_dot++;
                   1785:
                   1786:        /*
                   1787:         * if there aren't any dots, it could be a user-level alias
                   1788:         */
1.70      christos 1789:        if (!dots && (cp = __hostalias(name)) != NULL) {
                   1790:                ret = res_queryN(cp, target, res);
                   1791:                return ret;
                   1792:        }
1.32      itojun   1793:
                   1794:        /*
                   1795:         * If there are dots in the name already, let's just give it a try
                   1796:         * 'as is'.  The threshold can be set with the "ndots" option.
                   1797:         */
                   1798:        saved_herrno = -1;
1.70      christos 1799:        if (dots >= res->ndots) {
                   1800:                ret = res_querydomainN(name, NULL, target, res);
1.73      tsarna   1801:                if (ret > 0)
1.32      itojun   1802:                        return (ret);
                   1803:                saved_herrno = h_errno;
                   1804:                tried_as_is++;
                   1805:        }
                   1806:
                   1807:        /*
                   1808:         * We do at least one level of search if
                   1809:         *      - there is no dot and RES_DEFNAME is set, or
                   1810:         *      - there is at least one dot, there is no trailing dot,
                   1811:         *        and RES_DNSRCH is set.
                   1812:         */
1.70      christos 1813:        if ((!dots && (res->options & RES_DEFNAMES)) ||
                   1814:            (dots && !trailing_dot && (res->options & RES_DNSRCH))) {
1.32      itojun   1815:                int done = 0;
                   1816:
1.70      christos 1817:                for (domain = (const char * const *)res->dnsrch;
1.32      itojun   1818:                   *domain && !done;
                   1819:                   domain++) {
                   1820:
1.70      christos 1821:                        ret = res_querydomainN(name, *domain, target, res);
1.73      tsarna   1822:                        if (ret > 0)
1.70      christos 1823:                                return ret;
1.32      itojun   1824:
                   1825:                        /*
                   1826:                         * If no server present, give up.
                   1827:                         * If name isn't found in this domain,
                   1828:                         * keep trying higher domains in the search list
                   1829:                         * (if that's enabled).
                   1830:                         * On a NO_DATA error, keep trying, otherwise
                   1831:                         * a wildcard entry of another type could keep us
                   1832:                         * from finding this entry higher in the domain.
                   1833:                         * If we get some other error (negative answer or
                   1834:                         * server failure), then stop searching up,
                   1835:                         * but try the input name below in case it's
                   1836:                         * fully-qualified.
                   1837:                         */
                   1838:                        if (errno == ECONNREFUSED) {
                   1839:                                h_errno = TRY_AGAIN;
1.70      christos 1840:                                return -1;
1.32      itojun   1841:                        }
                   1842:
                   1843:                        switch (h_errno) {
                   1844:                        case NO_DATA:
                   1845:                                got_nodata++;
                   1846:                                /* FALLTHROUGH */
                   1847:                        case HOST_NOT_FOUND:
                   1848:                                /* keep trying */
                   1849:                                break;
                   1850:                        case TRY_AGAIN:
                   1851:                                if (hp->rcode == SERVFAIL) {
                   1852:                                        /* try next search element, if any */
                   1853:                                        got_servfail++;
                   1854:                                        break;
                   1855:                                }
                   1856:                                /* FALLTHROUGH */
                   1857:                        default:
                   1858:                                /* anything else implies that we're done */
                   1859:                                done++;
                   1860:                        }
                   1861:                        /*
                   1862:                         * if we got here for some reason other than DNSRCH,
                   1863:                         * we only wanted one iteration of the loop, so stop.
                   1864:                         */
1.70      christos 1865:                        if (!(res->options & RES_DNSRCH))
1.32      itojun   1866:                                done++;
                   1867:                }
                   1868:        }
                   1869:
                   1870:        /*
                   1871:         * if we have not already tried the name "as is", do that now.
                   1872:         * note that we do this regardless of how many dots were in the
                   1873:         * name or whether it ends with a dot.
                   1874:         */
                   1875:        if (!tried_as_is) {
1.70      christos 1876:                ret = res_querydomainN(name, NULL, target, res);
1.73      tsarna   1877:                if (ret > 0)
1.70      christos 1878:                        return ret;
1.32      itojun   1879:        }
                   1880:
                   1881:        /*
                   1882:         * if we got here, we didn't satisfy the search.
                   1883:         * if we did an initial full query, return that query's h_errno
                   1884:         * (note that we wouldn't be here if that query had succeeded).
                   1885:         * else if we ever got a nodata, send that back as the reason.
                   1886:         * else send back meaningless h_errno, that being the one from
                   1887:         * the last DNSRCH we did.
                   1888:         */
                   1889:        if (saved_herrno != -1)
                   1890:                h_errno = saved_herrno;
                   1891:        else if (got_nodata)
                   1892:                h_errno = NO_DATA;
                   1893:        else if (got_servfail)
                   1894:                h_errno = TRY_AGAIN;
1.70      christos 1895:        return -1;
1.32      itojun   1896: }
                   1897:
                   1898: /*
                   1899:  * Perform a call on res_query on the concatenation of name and domain,
                   1900:  * removing a trailing dot from name if domain is NULL.
                   1901:  */
                   1902: static int
1.73      tsarna   1903: res_querydomainN(const char *name, const char *domain,
1.70      christos 1904:     struct res_target *target, res_state res)
1.32      itojun   1905: {
                   1906:        char nbuf[MAXDNAME];
                   1907:        const char *longname = nbuf;
                   1908:        size_t n, d;
1.51      lukem    1909:
                   1910:        _DIAGASSERT(name != NULL);
                   1911:        /* XXX: target may be NULL??? */
1.32      itojun   1912:
                   1913: #ifdef DEBUG
1.70      christos 1914:        if (res->options & RES_DEBUG)
1.32      itojun   1915:                printf(";; res_querydomain(%s, %s)\n",
                   1916:                        name, domain?domain:"<Nil>");
                   1917: #endif
                   1918:        if (domain == NULL) {
                   1919:                /*
                   1920:                 * Check for trailing '.';
                   1921:                 * copy without '.' if present.
                   1922:                 */
                   1923:                n = strlen(name);
1.63      itojun   1924:                if (n + 1 > sizeof(nbuf)) {
1.32      itojun   1925:                        h_errno = NO_RECOVERY;
1.70      christos 1926:                        return -1;
1.32      itojun   1927:                }
1.40      itojun   1928:                if (n > 0 && name[--n] == '.') {
1.32      itojun   1929:                        strncpy(nbuf, name, n);
                   1930:                        nbuf[n] = '\0';
                   1931:                } else
                   1932:                        longname = name;
                   1933:        } else {
                   1934:                n = strlen(name);
                   1935:                d = strlen(domain);
1.63      itojun   1936:                if (n + 1 + d + 1 > sizeof(nbuf)) {
1.32      itojun   1937:                        h_errno = NO_RECOVERY;
1.70      christos 1938:                        return -1;
1.32      itojun   1939:                }
1.54      itojun   1940:                snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain);
1.32      itojun   1941:        }
1.70      christos 1942:        return res_queryN(longname, target, res);
1.32      itojun   1943: }

CVSweb <webmaster@jp.NetBSD.org>