17db96d56Sopenharmony_ci/*
27db96d56Sopenharmony_ci * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
37db96d56Sopenharmony_ci * All rights reserved.
47db96d56Sopenharmony_ci *
57db96d56Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
67db96d56Sopenharmony_ci * modification, are permitted provided that the following conditions
77db96d56Sopenharmony_ci * are met:
87db96d56Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright
97db96d56Sopenharmony_ci *    notice, this list of conditions and the following disclaimer.
107db96d56Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright
117db96d56Sopenharmony_ci *    notice, this list of conditions and the following disclaimer in the
127db96d56Sopenharmony_ci *    documentation and/or other materials provided with the distribution.
137db96d56Sopenharmony_ci * 3. Neither the name of the project nor the names of its contributors
147db96d56Sopenharmony_ci *    may be used to endorse or promote products derived from this software
157db96d56Sopenharmony_ci *    without specific prior written permission.
167db96d56Sopenharmony_ci *
177db96d56Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
187db96d56Sopenharmony_ci * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
197db96d56Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
207db96d56Sopenharmony_ci * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
217db96d56Sopenharmony_ci * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
227db96d56Sopenharmony_ci * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
237db96d56Sopenharmony_ci * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
247db96d56Sopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
257db96d56Sopenharmony_ci * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
267db96d56Sopenharmony_ci * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
277db96d56Sopenharmony_ci * SUCH DAMAGE.
287db96d56Sopenharmony_ci */
297db96d56Sopenharmony_ci
307db96d56Sopenharmony_ci/*
317db96d56Sopenharmony_ci * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator.
327db96d56Sopenharmony_ci *
337db96d56Sopenharmony_ci * Issues to be discussed:
347db96d56Sopenharmony_ci * - Thread safe-ness must be checked.
357db96d56Sopenharmony_ci * - Return values.  There are nonstandard return values defined and used
367db96d56Sopenharmony_ci *   in the source code.  This is because RFC2133 is silent about which error
377db96d56Sopenharmony_ci *   code must be returned for which situation.
387db96d56Sopenharmony_ci * - PF_UNSPEC case would be handled in getipnodebyname() with the AI_ALL flag.
397db96d56Sopenharmony_ci */
407db96d56Sopenharmony_ci
417db96d56Sopenharmony_ci#if 0
427db96d56Sopenharmony_ci#include <sys/types.h>
437db96d56Sopenharmony_ci#include <sys/param.h>
447db96d56Sopenharmony_ci#include <sys/sysctl.h>
457db96d56Sopenharmony_ci#include <sys/socket.h>
467db96d56Sopenharmony_ci#include <netinet/in.h>
477db96d56Sopenharmony_ci#include <arpa/inet.h>
487db96d56Sopenharmony_ci#include <arpa/nameser.h>
497db96d56Sopenharmony_ci#include <netdb.h>
507db96d56Sopenharmony_ci#include <resolv.h>
517db96d56Sopenharmony_ci#include <string.h>
527db96d56Sopenharmony_ci#include <stdlib.h>
537db96d56Sopenharmony_ci#include <stddef.h>
547db96d56Sopenharmony_ci#include <ctype.h>
557db96d56Sopenharmony_ci#include <unistd.h>
567db96d56Sopenharmony_ci
577db96d56Sopenharmony_ci#include "addrinfo.h"
587db96d56Sopenharmony_ci#endif
597db96d56Sopenharmony_ci
607db96d56Sopenharmony_ci#if defined(__KAME__) && defined(ENABLE_IPV6)
617db96d56Sopenharmony_ci# define FAITH
627db96d56Sopenharmony_ci#endif
637db96d56Sopenharmony_ci
647db96d56Sopenharmony_ci#ifdef HAVE_NETDB_H
657db96d56Sopenharmony_ci#define HAVE_GETADDRINFO 1
667db96d56Sopenharmony_ci
677db96d56Sopenharmony_ci#define SUCCESS 0
687db96d56Sopenharmony_ci#define GAI_ANY 0
697db96d56Sopenharmony_ci#define YES 1
707db96d56Sopenharmony_ci#define NO  0
717db96d56Sopenharmony_ci
727db96d56Sopenharmony_ci#ifdef FAITH
737db96d56Sopenharmony_cistatic int translate = NO;
747db96d56Sopenharmony_cistatic struct in6_addr faith_prefix = IN6ADDR_GAI_ANY_INIT;
757db96d56Sopenharmony_ci#endif
767db96d56Sopenharmony_ci
777db96d56Sopenharmony_cistatic const char in_addrany[] = { 0, 0, 0, 0 };
787db96d56Sopenharmony_cistatic const char in6_addrany[] = {
797db96d56Sopenharmony_ci    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
807db96d56Sopenharmony_ci};
817db96d56Sopenharmony_cistatic const char in_loopback[] = { 127, 0, 0, 1 };
827db96d56Sopenharmony_cistatic const char in6_loopback[] = {
837db96d56Sopenharmony_ci    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
847db96d56Sopenharmony_ci};
857db96d56Sopenharmony_ci
867db96d56Sopenharmony_cistruct sockinet {
877db96d56Sopenharmony_ci    u_char      si_len;
887db96d56Sopenharmony_ci    u_char      si_family;
897db96d56Sopenharmony_ci    u_short     si_port;
907db96d56Sopenharmony_ci};
917db96d56Sopenharmony_ci
927db96d56Sopenharmony_cistatic struct gai_afd {
937db96d56Sopenharmony_ci    int a_af;
947db96d56Sopenharmony_ci    int a_addrlen;
957db96d56Sopenharmony_ci    int a_socklen;
967db96d56Sopenharmony_ci    int a_off;
977db96d56Sopenharmony_ci    const char *a_addrany;
987db96d56Sopenharmony_ci    const char *a_loopback;
997db96d56Sopenharmony_ci} gai_afdl [] = {
1007db96d56Sopenharmony_ci#ifdef ENABLE_IPV6
1017db96d56Sopenharmony_ci#define N_INET6 0
1027db96d56Sopenharmony_ci    {PF_INET6, sizeof(struct in6_addr),
1037db96d56Sopenharmony_ci     sizeof(struct sockaddr_in6),
1047db96d56Sopenharmony_ci     offsetof(struct sockaddr_in6, sin6_addr),
1057db96d56Sopenharmony_ci     in6_addrany, in6_loopback},
1067db96d56Sopenharmony_ci#define N_INET  1
1077db96d56Sopenharmony_ci#else
1087db96d56Sopenharmony_ci#define N_INET  0
1097db96d56Sopenharmony_ci#endif
1107db96d56Sopenharmony_ci    {PF_INET, sizeof(struct in_addr),
1117db96d56Sopenharmony_ci     sizeof(struct sockaddr_in),
1127db96d56Sopenharmony_ci     offsetof(struct sockaddr_in, sin_addr),
1137db96d56Sopenharmony_ci     in_addrany, in_loopback},
1147db96d56Sopenharmony_ci    {0, 0, 0, 0, NULL, NULL},
1157db96d56Sopenharmony_ci};
1167db96d56Sopenharmony_ci
1177db96d56Sopenharmony_ci#ifdef ENABLE_IPV6
1187db96d56Sopenharmony_ci#define PTON_MAX        16
1197db96d56Sopenharmony_ci#else
1207db96d56Sopenharmony_ci#define PTON_MAX        4
1217db96d56Sopenharmony_ci#endif
1227db96d56Sopenharmony_ci
1237db96d56Sopenharmony_ci#ifndef IN_MULTICAST
1247db96d56Sopenharmony_ci#define IN_MULTICAST(i)     (((i) & 0xf0000000U) == 0xe0000000U)
1257db96d56Sopenharmony_ci#endif
1267db96d56Sopenharmony_ci
1277db96d56Sopenharmony_ci#ifndef IN_EXPERIMENTAL
1287db96d56Sopenharmony_ci#define IN_EXPERIMENTAL(i)  (((i) & 0xe0000000U) == 0xe0000000U)
1297db96d56Sopenharmony_ci#endif
1307db96d56Sopenharmony_ci
1317db96d56Sopenharmony_ci#ifndef IN_LOOPBACKNET
1327db96d56Sopenharmony_ci#define IN_LOOPBACKNET      127
1337db96d56Sopenharmony_ci#endif
1347db96d56Sopenharmony_ci
1357db96d56Sopenharmony_cistatic int get_name(const char *, struct gai_afd *,
1367db96d56Sopenharmony_ci                          struct addrinfo **, char *, struct addrinfo *,
1377db96d56Sopenharmony_ci                          int);
1387db96d56Sopenharmony_cistatic int get_addr(const char *, int, struct addrinfo **,
1397db96d56Sopenharmony_ci                        struct addrinfo *, int);
1407db96d56Sopenharmony_cistatic int str_isnumber(const char *);
1417db96d56Sopenharmony_ci
1427db96d56Sopenharmony_cistatic const char * const ai_errlist[] = {
1437db96d56Sopenharmony_ci    "success.",
1447db96d56Sopenharmony_ci    "address family for hostname not supported.",       /* EAI_ADDRFAMILY */
1457db96d56Sopenharmony_ci    "temporary failure in name resolution.",            /* EAI_AGAIN      */
1467db96d56Sopenharmony_ci    "invalid value for ai_flags.",                      /* EAI_BADFLAGS   */
1477db96d56Sopenharmony_ci    "non-recoverable failure in name resolution.",      /* EAI_FAIL       */
1487db96d56Sopenharmony_ci    "ai_family not supported.",                         /* EAI_FAMILY     */
1497db96d56Sopenharmony_ci    "memory allocation failure.",                       /* EAI_MEMORY     */
1507db96d56Sopenharmony_ci    "no address associated with hostname.",             /* EAI_NODATA     */
1517db96d56Sopenharmony_ci    "hostname nor servname provided, or not known.",/* EAI_NONAME     */
1527db96d56Sopenharmony_ci    "servname not supported for ai_socktype.",          /* EAI_SERVICE    */
1537db96d56Sopenharmony_ci    "ai_socktype not supported.",                       /* EAI_SOCKTYPE   */
1547db96d56Sopenharmony_ci    "system error returned in errno.",                  /* EAI_SYSTEM     */
1557db96d56Sopenharmony_ci    "invalid value for hints.",                         /* EAI_BADHINTS   */
1567db96d56Sopenharmony_ci    "resolved protocol is unknown.",                    /* EAI_PROTOCOL   */
1577db96d56Sopenharmony_ci    "unknown error.",                                   /* EAI_MAX        */
1587db96d56Sopenharmony_ci};
1597db96d56Sopenharmony_ci
1607db96d56Sopenharmony_ci#define GET_CANONNAME(ai, str) \
1617db96d56Sopenharmony_ciif (pai->ai_flags & AI_CANONNAME) {\
1627db96d56Sopenharmony_ci    if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\
1637db96d56Sopenharmony_ci        strcpy((ai)->ai_canonname, (str));\
1647db96d56Sopenharmony_ci    } else {\
1657db96d56Sopenharmony_ci        error = EAI_MEMORY;\
1667db96d56Sopenharmony_ci        goto free;\
1677db96d56Sopenharmony_ci    }\
1687db96d56Sopenharmony_ci}
1697db96d56Sopenharmony_ci
1707db96d56Sopenharmony_ci#ifdef HAVE_SOCKADDR_SA_LEN
1717db96d56Sopenharmony_ci#define GET_AI(ai, gai_afd, addr, port) {\
1727db96d56Sopenharmony_ci    char *p;\
1737db96d56Sopenharmony_ci    if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\
1747db96d56Sopenharmony_ci                                          ((gai_afd)->a_socklen)))\
1757db96d56Sopenharmony_ci        == NULL) goto free;\
1767db96d56Sopenharmony_ci    memcpy(ai, pai, sizeof(struct addrinfo));\
1777db96d56Sopenharmony_ci    (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\
1787db96d56Sopenharmony_ci    memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\
1797db96d56Sopenharmony_ci    (ai)->ai_addr->sa_len = (ai)->ai_addrlen = (gai_afd)->a_socklen;\
1807db96d56Sopenharmony_ci    (ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\
1817db96d56Sopenharmony_ci    ((struct sockinet *)(ai)->ai_addr)->si_port = port;\
1827db96d56Sopenharmony_ci    p = (char *)((ai)->ai_addr);\
1837db96d56Sopenharmony_ci    memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\
1847db96d56Sopenharmony_ci}
1857db96d56Sopenharmony_ci#else
1867db96d56Sopenharmony_ci#define GET_AI(ai, gai_afd, addr, port) {\
1877db96d56Sopenharmony_ci    char *p;\
1887db96d56Sopenharmony_ci    if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\
1897db96d56Sopenharmony_ci                                          ((gai_afd)->a_socklen)))\
1907db96d56Sopenharmony_ci        == NULL) goto free;\
1917db96d56Sopenharmony_ci    memcpy(ai, pai, sizeof(struct addrinfo));\
1927db96d56Sopenharmony_ci    (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\
1937db96d56Sopenharmony_ci    memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\
1947db96d56Sopenharmony_ci    (ai)->ai_addrlen = (gai_afd)->a_socklen;\
1957db96d56Sopenharmony_ci    (ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\
1967db96d56Sopenharmony_ci    ((struct sockinet *)(ai)->ai_addr)->si_port = port;\
1977db96d56Sopenharmony_ci    p = (char *)((ai)->ai_addr);\
1987db96d56Sopenharmony_ci    memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\
1997db96d56Sopenharmony_ci}
2007db96d56Sopenharmony_ci#endif
2017db96d56Sopenharmony_ci
2027db96d56Sopenharmony_ci#define ERR(err) { error = (err); goto bad; }
2037db96d56Sopenharmony_ci
2047db96d56Sopenharmony_ciconst char *
2057db96d56Sopenharmony_cigai_strerror(int ecode)
2067db96d56Sopenharmony_ci{
2077db96d56Sopenharmony_ci    if (ecode < 0 || ecode > EAI_MAX)
2087db96d56Sopenharmony_ci        ecode = EAI_MAX;
2097db96d56Sopenharmony_ci    return ai_errlist[ecode];
2107db96d56Sopenharmony_ci}
2117db96d56Sopenharmony_ci
2127db96d56Sopenharmony_civoid
2137db96d56Sopenharmony_cifreeaddrinfo(struct addrinfo *ai)
2147db96d56Sopenharmony_ci{
2157db96d56Sopenharmony_ci    struct addrinfo *next;
2167db96d56Sopenharmony_ci
2177db96d56Sopenharmony_ci    do {
2187db96d56Sopenharmony_ci        next = ai->ai_next;
2197db96d56Sopenharmony_ci        if (ai->ai_canonname)
2207db96d56Sopenharmony_ci            free(ai->ai_canonname);
2217db96d56Sopenharmony_ci        /* no need to free(ai->ai_addr) */
2227db96d56Sopenharmony_ci        free(ai);
2237db96d56Sopenharmony_ci    } while ((ai = next) != NULL);
2247db96d56Sopenharmony_ci}
2257db96d56Sopenharmony_ci
2267db96d56Sopenharmony_cistatic int
2277db96d56Sopenharmony_cistr_isnumber(const char *p)
2287db96d56Sopenharmony_ci{
2297db96d56Sopenharmony_ci    unsigned char *q = (unsigned char *)p;
2307db96d56Sopenharmony_ci    while (*q) {
2317db96d56Sopenharmony_ci        if (! isdigit(*q))
2327db96d56Sopenharmony_ci            return NO;
2337db96d56Sopenharmony_ci        q++;
2347db96d56Sopenharmony_ci    }
2357db96d56Sopenharmony_ci    return YES;
2367db96d56Sopenharmony_ci}
2377db96d56Sopenharmony_ci
2387db96d56Sopenharmony_ciint
2397db96d56Sopenharmony_cigetaddrinfo(const char*hostname, const char*servname,
2407db96d56Sopenharmony_ci            const struct addrinfo *hints, struct addrinfo **res)
2417db96d56Sopenharmony_ci{
2427db96d56Sopenharmony_ci    struct addrinfo sentinel;
2437db96d56Sopenharmony_ci    struct addrinfo *top = NULL;
2447db96d56Sopenharmony_ci    struct addrinfo *cur;
2457db96d56Sopenharmony_ci    int i, error = 0;
2467db96d56Sopenharmony_ci    char pton[PTON_MAX];
2477db96d56Sopenharmony_ci    struct addrinfo ai;
2487db96d56Sopenharmony_ci    struct addrinfo *pai;
2497db96d56Sopenharmony_ci    u_short port;
2507db96d56Sopenharmony_ci
2517db96d56Sopenharmony_ci#ifdef FAITH
2527db96d56Sopenharmony_ci    static int firsttime = 1;
2537db96d56Sopenharmony_ci
2547db96d56Sopenharmony_ci    if (firsttime) {
2557db96d56Sopenharmony_ci        /* translator hack */
2567db96d56Sopenharmony_ci        {
2577db96d56Sopenharmony_ci            const char *q = getenv("GAI");
2587db96d56Sopenharmony_ci            if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1)
2597db96d56Sopenharmony_ci                translate = YES;
2607db96d56Sopenharmony_ci        }
2617db96d56Sopenharmony_ci        firsttime = 0;
2627db96d56Sopenharmony_ci    }
2637db96d56Sopenharmony_ci#endif
2647db96d56Sopenharmony_ci
2657db96d56Sopenharmony_ci    /* initialize file static vars */
2667db96d56Sopenharmony_ci    sentinel.ai_next = NULL;
2677db96d56Sopenharmony_ci    cur = &sentinel;
2687db96d56Sopenharmony_ci    pai = &ai;
2697db96d56Sopenharmony_ci    pai->ai_flags = 0;
2707db96d56Sopenharmony_ci    pai->ai_family = PF_UNSPEC;
2717db96d56Sopenharmony_ci    pai->ai_socktype = GAI_ANY;
2727db96d56Sopenharmony_ci    pai->ai_protocol = GAI_ANY;
2737db96d56Sopenharmony_ci    pai->ai_addrlen = 0;
2747db96d56Sopenharmony_ci    pai->ai_canonname = NULL;
2757db96d56Sopenharmony_ci    pai->ai_addr = NULL;
2767db96d56Sopenharmony_ci    pai->ai_next = NULL;
2777db96d56Sopenharmony_ci    port = GAI_ANY;
2787db96d56Sopenharmony_ci
2797db96d56Sopenharmony_ci    if (hostname == NULL && servname == NULL)
2807db96d56Sopenharmony_ci        return EAI_NONAME;
2817db96d56Sopenharmony_ci    if (hints) {
2827db96d56Sopenharmony_ci        /* error check for hints */
2837db96d56Sopenharmony_ci        if (hints->ai_addrlen || hints->ai_canonname ||
2847db96d56Sopenharmony_ci            hints->ai_addr || hints->ai_next)
2857db96d56Sopenharmony_ci            ERR(EAI_BADHINTS); /* xxx */
2867db96d56Sopenharmony_ci        if (hints->ai_flags & ~AI_MASK)
2877db96d56Sopenharmony_ci            ERR(EAI_BADFLAGS);
2887db96d56Sopenharmony_ci        switch (hints->ai_family) {
2897db96d56Sopenharmony_ci        case PF_UNSPEC:
2907db96d56Sopenharmony_ci        case PF_INET:
2917db96d56Sopenharmony_ci#ifdef ENABLE_IPV6
2927db96d56Sopenharmony_ci        case PF_INET6:
2937db96d56Sopenharmony_ci#endif
2947db96d56Sopenharmony_ci            break;
2957db96d56Sopenharmony_ci        default:
2967db96d56Sopenharmony_ci            ERR(EAI_FAMILY);
2977db96d56Sopenharmony_ci        }
2987db96d56Sopenharmony_ci        memcpy(pai, hints, sizeof(*pai));
2997db96d56Sopenharmony_ci        switch (pai->ai_socktype) {
3007db96d56Sopenharmony_ci        case GAI_ANY:
3017db96d56Sopenharmony_ci            switch (pai->ai_protocol) {
3027db96d56Sopenharmony_ci            case GAI_ANY:
3037db96d56Sopenharmony_ci                break;
3047db96d56Sopenharmony_ci            case IPPROTO_UDP:
3057db96d56Sopenharmony_ci                pai->ai_socktype = SOCK_DGRAM;
3067db96d56Sopenharmony_ci                break;
3077db96d56Sopenharmony_ci            case IPPROTO_TCP:
3087db96d56Sopenharmony_ci                pai->ai_socktype = SOCK_STREAM;
3097db96d56Sopenharmony_ci                break;
3107db96d56Sopenharmony_ci            default:
3117db96d56Sopenharmony_ci                pai->ai_socktype = SOCK_RAW;
3127db96d56Sopenharmony_ci                break;
3137db96d56Sopenharmony_ci            }
3147db96d56Sopenharmony_ci            break;
3157db96d56Sopenharmony_ci        case SOCK_RAW:
3167db96d56Sopenharmony_ci            break;
3177db96d56Sopenharmony_ci        case SOCK_DGRAM:
3187db96d56Sopenharmony_ci            if (pai->ai_protocol != IPPROTO_UDP &&
3197db96d56Sopenharmony_ci                pai->ai_protocol != GAI_ANY)
3207db96d56Sopenharmony_ci                ERR(EAI_BADHINTS);                      /*xxx*/
3217db96d56Sopenharmony_ci            pai->ai_protocol = IPPROTO_UDP;
3227db96d56Sopenharmony_ci            break;
3237db96d56Sopenharmony_ci        case SOCK_STREAM:
3247db96d56Sopenharmony_ci            if (pai->ai_protocol != IPPROTO_TCP &&
3257db96d56Sopenharmony_ci                pai->ai_protocol != GAI_ANY)
3267db96d56Sopenharmony_ci                ERR(EAI_BADHINTS);                      /*xxx*/
3277db96d56Sopenharmony_ci            pai->ai_protocol = IPPROTO_TCP;
3287db96d56Sopenharmony_ci            break;
3297db96d56Sopenharmony_ci        default:
3307db96d56Sopenharmony_ci            ERR(EAI_SOCKTYPE);
3317db96d56Sopenharmony_ci            /* unreachable */
3327db96d56Sopenharmony_ci        }
3337db96d56Sopenharmony_ci    }
3347db96d56Sopenharmony_ci
3357db96d56Sopenharmony_ci    /*
3367db96d56Sopenharmony_ci     * service port
3377db96d56Sopenharmony_ci     */
3387db96d56Sopenharmony_ci    if (servname) {
3397db96d56Sopenharmony_ci        if (str_isnumber(servname)) {
3407db96d56Sopenharmony_ci            if (pai->ai_socktype == GAI_ANY) {
3417db96d56Sopenharmony_ci                /* caller accept *GAI_ANY* socktype */
3427db96d56Sopenharmony_ci                pai->ai_socktype = SOCK_DGRAM;
3437db96d56Sopenharmony_ci                pai->ai_protocol = IPPROTO_UDP;
3447db96d56Sopenharmony_ci            }
3457db96d56Sopenharmony_ci            port = htons((u_short)atoi(servname));
3467db96d56Sopenharmony_ci        } else {
3477db96d56Sopenharmony_ci            struct servent *sp;
3487db96d56Sopenharmony_ci            const char *proto;
3497db96d56Sopenharmony_ci
3507db96d56Sopenharmony_ci            proto = NULL;
3517db96d56Sopenharmony_ci            switch (pai->ai_socktype) {
3527db96d56Sopenharmony_ci            case GAI_ANY:
3537db96d56Sopenharmony_ci                proto = NULL;
3547db96d56Sopenharmony_ci                break;
3557db96d56Sopenharmony_ci            case SOCK_DGRAM:
3567db96d56Sopenharmony_ci                proto = "udp";
3577db96d56Sopenharmony_ci                break;
3587db96d56Sopenharmony_ci            case SOCK_STREAM:
3597db96d56Sopenharmony_ci                proto = "tcp";
3607db96d56Sopenharmony_ci                break;
3617db96d56Sopenharmony_ci            default:
3627db96d56Sopenharmony_ci                fprintf(stderr, "panic!\n");
3637db96d56Sopenharmony_ci                break;
3647db96d56Sopenharmony_ci            }
3657db96d56Sopenharmony_ci            if ((sp = getservbyname(servname, proto)) == NULL)
3667db96d56Sopenharmony_ci                ERR(EAI_SERVICE);
3677db96d56Sopenharmony_ci            port = sp->s_port;
3687db96d56Sopenharmony_ci            if (pai->ai_socktype == GAI_ANY) {
3697db96d56Sopenharmony_ci                if (strcmp(sp->s_proto, "udp") == 0) {
3707db96d56Sopenharmony_ci                    pai->ai_socktype = SOCK_DGRAM;
3717db96d56Sopenharmony_ci                    pai->ai_protocol = IPPROTO_UDP;
3727db96d56Sopenharmony_ci                } else if (strcmp(sp->s_proto, "tcp") == 0) {
3737db96d56Sopenharmony_ci                    pai->ai_socktype = SOCK_STREAM;
3747db96d56Sopenharmony_ci                    pai->ai_protocol = IPPROTO_TCP;
3757db96d56Sopenharmony_ci                } else
3767db96d56Sopenharmony_ci                    ERR(EAI_PROTOCOL);                          /*xxx*/
3777db96d56Sopenharmony_ci            }
3787db96d56Sopenharmony_ci        }
3797db96d56Sopenharmony_ci    }
3807db96d56Sopenharmony_ci
3817db96d56Sopenharmony_ci    /*
3827db96d56Sopenharmony_ci     * hostname == NULL.
3837db96d56Sopenharmony_ci     * passive socket -> anyaddr (0.0.0.0 or ::)
3847db96d56Sopenharmony_ci     * non-passive socket -> localhost (127.0.0.1 or ::1)
3857db96d56Sopenharmony_ci     */
3867db96d56Sopenharmony_ci    if (hostname == NULL) {
3877db96d56Sopenharmony_ci        struct gai_afd *gai_afd;
3887db96d56Sopenharmony_ci
3897db96d56Sopenharmony_ci        for (gai_afd = &gai_afdl[0]; gai_afd->a_af; gai_afd++) {
3907db96d56Sopenharmony_ci            if (!(pai->ai_family == PF_UNSPEC
3917db96d56Sopenharmony_ci               || pai->ai_family == gai_afd->a_af)) {
3927db96d56Sopenharmony_ci                continue;
3937db96d56Sopenharmony_ci            }
3947db96d56Sopenharmony_ci
3957db96d56Sopenharmony_ci            if (pai->ai_flags & AI_PASSIVE) {
3967db96d56Sopenharmony_ci                GET_AI(cur->ai_next, gai_afd, gai_afd->a_addrany, port);
3977db96d56Sopenharmony_ci                /* xxx meaningless?
3987db96d56Sopenharmony_ci                 * GET_CANONNAME(cur->ai_next, "anyaddr");
3997db96d56Sopenharmony_ci                 */
4007db96d56Sopenharmony_ci            } else {
4017db96d56Sopenharmony_ci                GET_AI(cur->ai_next, gai_afd, gai_afd->a_loopback,
4027db96d56Sopenharmony_ci                    port);
4037db96d56Sopenharmony_ci                /* xxx meaningless?
4047db96d56Sopenharmony_ci                 * GET_CANONNAME(cur->ai_next, "localhost");
4057db96d56Sopenharmony_ci                 */
4067db96d56Sopenharmony_ci            }
4077db96d56Sopenharmony_ci            cur = cur->ai_next;
4087db96d56Sopenharmony_ci        }
4097db96d56Sopenharmony_ci        top = sentinel.ai_next;
4107db96d56Sopenharmony_ci        if (top)
4117db96d56Sopenharmony_ci            goto good;
4127db96d56Sopenharmony_ci        else
4137db96d56Sopenharmony_ci            ERR(EAI_FAMILY);
4147db96d56Sopenharmony_ci    }
4157db96d56Sopenharmony_ci
4167db96d56Sopenharmony_ci    /* hostname as numeric name */
4177db96d56Sopenharmony_ci    for (i = 0; gai_afdl[i].a_af; i++) {
4187db96d56Sopenharmony_ci        if (inet_pton(gai_afdl[i].a_af, hostname, pton)) {
4197db96d56Sopenharmony_ci            u_long v4a;
4207db96d56Sopenharmony_ci#ifdef ENABLE_IPV6
4217db96d56Sopenharmony_ci            u_char pfx;
4227db96d56Sopenharmony_ci#endif
4237db96d56Sopenharmony_ci
4247db96d56Sopenharmony_ci            switch (gai_afdl[i].a_af) {
4257db96d56Sopenharmony_ci            case AF_INET:
4267db96d56Sopenharmony_ci                v4a = ((struct in_addr *)pton)->s_addr;
4277db96d56Sopenharmony_ci                v4a = ntohl(v4a);
4287db96d56Sopenharmony_ci                if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
4297db96d56Sopenharmony_ci                    pai->ai_flags &= ~AI_CANONNAME;
4307db96d56Sopenharmony_ci                v4a >>= IN_CLASSA_NSHIFT;
4317db96d56Sopenharmony_ci                if (v4a == 0 || v4a == IN_LOOPBACKNET)
4327db96d56Sopenharmony_ci                    pai->ai_flags &= ~AI_CANONNAME;
4337db96d56Sopenharmony_ci                break;
4347db96d56Sopenharmony_ci#ifdef ENABLE_IPV6
4357db96d56Sopenharmony_ci            case AF_INET6:
4367db96d56Sopenharmony_ci                pfx = ((struct in6_addr *)pton)->s6_addr[0];
4377db96d56Sopenharmony_ci                if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
4387db96d56Sopenharmony_ci                    pai->ai_flags &= ~AI_CANONNAME;
4397db96d56Sopenharmony_ci                break;
4407db96d56Sopenharmony_ci#endif
4417db96d56Sopenharmony_ci            }
4427db96d56Sopenharmony_ci
4437db96d56Sopenharmony_ci            if (pai->ai_family == gai_afdl[i].a_af ||
4447db96d56Sopenharmony_ci                pai->ai_family == PF_UNSPEC) {
4457db96d56Sopenharmony_ci                if (! (pai->ai_flags & AI_CANONNAME)) {
4467db96d56Sopenharmony_ci                    GET_AI(top, &gai_afdl[i], pton, port);
4477db96d56Sopenharmony_ci                    goto good;
4487db96d56Sopenharmony_ci                }
4497db96d56Sopenharmony_ci                /*
4507db96d56Sopenharmony_ci                 * if AI_CANONNAME and if reverse lookup
4517db96d56Sopenharmony_ci                 * fail, return ai anyway to pacify
4527db96d56Sopenharmony_ci                 * calling application.
4537db96d56Sopenharmony_ci                 *
4547db96d56Sopenharmony_ci                 * XXX getaddrinfo() is a name->address
4557db96d56Sopenharmony_ci                 * translation function, and it looks strange
4567db96d56Sopenharmony_ci                 * that we do addr->name translation here.
4577db96d56Sopenharmony_ci                 */
4587db96d56Sopenharmony_ci                get_name(pton, &gai_afdl[i], &top, pton, pai, port);
4597db96d56Sopenharmony_ci                goto good;
4607db96d56Sopenharmony_ci            } else
4617db96d56Sopenharmony_ci                ERR(EAI_FAMILY);                        /*xxx*/
4627db96d56Sopenharmony_ci        }
4637db96d56Sopenharmony_ci    }
4647db96d56Sopenharmony_ci
4657db96d56Sopenharmony_ci    if (pai->ai_flags & AI_NUMERICHOST)
4667db96d56Sopenharmony_ci        ERR(EAI_NONAME);
4677db96d56Sopenharmony_ci
4687db96d56Sopenharmony_ci    /* hostname as alphabetical name */
4697db96d56Sopenharmony_ci    error = get_addr(hostname, pai->ai_family, &top, pai, port);
4707db96d56Sopenharmony_ci    if (error == 0) {
4717db96d56Sopenharmony_ci        if (top) {
4727db96d56Sopenharmony_ci good:
4737db96d56Sopenharmony_ci            *res = top;
4747db96d56Sopenharmony_ci            return SUCCESS;
4757db96d56Sopenharmony_ci        } else
4767db96d56Sopenharmony_ci            error = EAI_FAIL;
4777db96d56Sopenharmony_ci    }
4787db96d56Sopenharmony_ci free:
4797db96d56Sopenharmony_ci    if (top)
4807db96d56Sopenharmony_ci        freeaddrinfo(top);
4817db96d56Sopenharmony_ci bad:
4827db96d56Sopenharmony_ci    *res = NULL;
4837db96d56Sopenharmony_ci    return error;
4847db96d56Sopenharmony_ci}
4857db96d56Sopenharmony_ci
4867db96d56Sopenharmony_cistatic int
4877db96d56Sopenharmony_ciget_name(addr, gai_afd, res, numaddr, pai, port0)
4887db96d56Sopenharmony_ci    const char *addr;
4897db96d56Sopenharmony_ci    struct gai_afd *gai_afd;
4907db96d56Sopenharmony_ci    struct addrinfo **res;
4917db96d56Sopenharmony_ci    char *numaddr;
4927db96d56Sopenharmony_ci    struct addrinfo *pai;
4937db96d56Sopenharmony_ci    int port0;
4947db96d56Sopenharmony_ci{
4957db96d56Sopenharmony_ci    u_short port = port0 & 0xffff;
4967db96d56Sopenharmony_ci    struct hostent *hp;
4977db96d56Sopenharmony_ci    struct addrinfo *cur;
4987db96d56Sopenharmony_ci    int error = 0;
4997db96d56Sopenharmony_ci#ifdef ENABLE_IPV6
5007db96d56Sopenharmony_ci    int h_error;
5017db96d56Sopenharmony_ci#endif
5027db96d56Sopenharmony_ci
5037db96d56Sopenharmony_ci#ifdef ENABLE_IPV6
5047db96d56Sopenharmony_ci    hp = getipnodebyaddr(addr, gai_afd->a_addrlen, gai_afd->a_af, &h_error);
5057db96d56Sopenharmony_ci#else
5067db96d56Sopenharmony_ci    hp = gethostbyaddr(addr, gai_afd->a_addrlen, AF_INET);
5077db96d56Sopenharmony_ci#endif
5087db96d56Sopenharmony_ci    if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
5097db96d56Sopenharmony_ci        GET_AI(cur, gai_afd, hp->h_addr_list[0], port);
5107db96d56Sopenharmony_ci        GET_CANONNAME(cur, hp->h_name);
5117db96d56Sopenharmony_ci    } else
5127db96d56Sopenharmony_ci        GET_AI(cur, gai_afd, numaddr, port);
5137db96d56Sopenharmony_ci
5147db96d56Sopenharmony_ci#ifdef ENABLE_IPV6
5157db96d56Sopenharmony_ci    if (hp)
5167db96d56Sopenharmony_ci        freehostent(hp);
5177db96d56Sopenharmony_ci#endif
5187db96d56Sopenharmony_ci    *res = cur;
5197db96d56Sopenharmony_ci    return SUCCESS;
5207db96d56Sopenharmony_ci free:
5217db96d56Sopenharmony_ci    if (cur)
5227db96d56Sopenharmony_ci        freeaddrinfo(cur);
5237db96d56Sopenharmony_ci#ifdef ENABLE_IPV6
5247db96d56Sopenharmony_ci    if (hp)
5257db96d56Sopenharmony_ci        freehostent(hp);
5267db96d56Sopenharmony_ci#endif
5277db96d56Sopenharmony_ci /* bad: */
5287db96d56Sopenharmony_ci    *res = NULL;
5297db96d56Sopenharmony_ci    return error;
5307db96d56Sopenharmony_ci}
5317db96d56Sopenharmony_ci
5327db96d56Sopenharmony_cistatic int
5337db96d56Sopenharmony_ciget_addr(hostname, af, res, pai, port0)
5347db96d56Sopenharmony_ci    const char *hostname;
5357db96d56Sopenharmony_ci    int af;
5367db96d56Sopenharmony_ci    struct addrinfo **res;
5377db96d56Sopenharmony_ci    struct addrinfo *pai;
5387db96d56Sopenharmony_ci    int port0;
5397db96d56Sopenharmony_ci{
5407db96d56Sopenharmony_ci    u_short port = port0 & 0xffff;
5417db96d56Sopenharmony_ci    struct addrinfo sentinel;
5427db96d56Sopenharmony_ci    struct hostent *hp;
5437db96d56Sopenharmony_ci    struct addrinfo *top, *cur;
5447db96d56Sopenharmony_ci    struct gai_afd *gai_afd;
5457db96d56Sopenharmony_ci    int i, error = 0, h_error;
5467db96d56Sopenharmony_ci    char *ap;
5477db96d56Sopenharmony_ci
5487db96d56Sopenharmony_ci    top = NULL;
5497db96d56Sopenharmony_ci    sentinel.ai_next = NULL;
5507db96d56Sopenharmony_ci    cur = &sentinel;
5517db96d56Sopenharmony_ci#ifdef ENABLE_IPV6
5527db96d56Sopenharmony_ci    if (af == AF_UNSPEC) {
5537db96d56Sopenharmony_ci        hp = getipnodebyname(hostname, AF_INET6,
5547db96d56Sopenharmony_ci                        AI_ADDRCONFIG|AI_ALL|AI_V4MAPPED, &h_error);
5557db96d56Sopenharmony_ci    } else
5567db96d56Sopenharmony_ci        hp = getipnodebyname(hostname, af, AI_ADDRCONFIG, &h_error);
5577db96d56Sopenharmony_ci#else
5587db96d56Sopenharmony_ci    hp = gethostbyname(hostname);
5597db96d56Sopenharmony_ci    h_error = h_errno;
5607db96d56Sopenharmony_ci#endif
5617db96d56Sopenharmony_ci    if (hp == NULL) {
5627db96d56Sopenharmony_ci        switch (h_error) {
5637db96d56Sopenharmony_ci        case HOST_NOT_FOUND:
5647db96d56Sopenharmony_ci        case NO_DATA:
5657db96d56Sopenharmony_ci            error = EAI_NODATA;
5667db96d56Sopenharmony_ci            break;
5677db96d56Sopenharmony_ci        case TRY_AGAIN:
5687db96d56Sopenharmony_ci            error = EAI_AGAIN;
5697db96d56Sopenharmony_ci            break;
5707db96d56Sopenharmony_ci        case NO_RECOVERY:
5717db96d56Sopenharmony_ci        default:
5727db96d56Sopenharmony_ci            error = EAI_FAIL;
5737db96d56Sopenharmony_ci            break;
5747db96d56Sopenharmony_ci        }
5757db96d56Sopenharmony_ci        goto free;
5767db96d56Sopenharmony_ci    }
5777db96d56Sopenharmony_ci
5787db96d56Sopenharmony_ci    if ((hp->h_name == NULL) || (hp->h_name[0] == 0) ||
5797db96d56Sopenharmony_ci        (hp->h_addr_list[0] == NULL)) {
5807db96d56Sopenharmony_ci        error = EAI_FAIL;
5817db96d56Sopenharmony_ci        goto free;
5827db96d56Sopenharmony_ci    }
5837db96d56Sopenharmony_ci
5847db96d56Sopenharmony_ci    for (i = 0; (ap = hp->h_addr_list[i]) != NULL; i++) {
5857db96d56Sopenharmony_ci        switch (af) {
5867db96d56Sopenharmony_ci#ifdef ENABLE_IPV6
5877db96d56Sopenharmony_ci        case AF_INET6:
5887db96d56Sopenharmony_ci            gai_afd = &gai_afdl[N_INET6];
5897db96d56Sopenharmony_ci            break;
5907db96d56Sopenharmony_ci#endif
5917db96d56Sopenharmony_ci#ifndef ENABLE_IPV6
5927db96d56Sopenharmony_ci        default:                /* AF_UNSPEC */
5937db96d56Sopenharmony_ci#endif
5947db96d56Sopenharmony_ci        case AF_INET:
5957db96d56Sopenharmony_ci            gai_afd = &gai_afdl[N_INET];
5967db96d56Sopenharmony_ci            break;
5977db96d56Sopenharmony_ci#ifdef ENABLE_IPV6
5987db96d56Sopenharmony_ci        default:                /* AF_UNSPEC */
5997db96d56Sopenharmony_ci            if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
6007db96d56Sopenharmony_ci                ap += sizeof(struct in6_addr) -
6017db96d56Sopenharmony_ci                    sizeof(struct in_addr);
6027db96d56Sopenharmony_ci                gai_afd = &gai_afdl[N_INET];
6037db96d56Sopenharmony_ci            } else
6047db96d56Sopenharmony_ci                gai_afd = &gai_afdl[N_INET6];
6057db96d56Sopenharmony_ci            break;
6067db96d56Sopenharmony_ci#endif
6077db96d56Sopenharmony_ci        }
6087db96d56Sopenharmony_ci#ifdef FAITH
6097db96d56Sopenharmony_ci        if (translate && gai_afd->a_af == AF_INET) {
6107db96d56Sopenharmony_ci            struct in6_addr *in6;
6117db96d56Sopenharmony_ci
6127db96d56Sopenharmony_ci            GET_AI(cur->ai_next, &gai_afdl[N_INET6], ap, port);
6137db96d56Sopenharmony_ci            in6 = &((struct sockaddr_in6 *)cur->ai_next->ai_addr)->sin6_addr;
6147db96d56Sopenharmony_ci            memcpy(&in6->s6_addr32[0], &faith_prefix,
6157db96d56Sopenharmony_ci                sizeof(struct in6_addr) - sizeof(struct in_addr));
6167db96d56Sopenharmony_ci            memcpy(&in6->s6_addr32[3], ap, sizeof(struct in_addr));
6177db96d56Sopenharmony_ci        } else
6187db96d56Sopenharmony_ci#endif /* FAITH */
6197db96d56Sopenharmony_ci        GET_AI(cur->ai_next, gai_afd, ap, port);
6207db96d56Sopenharmony_ci        if (cur == &sentinel) {
6217db96d56Sopenharmony_ci            top = cur->ai_next;
6227db96d56Sopenharmony_ci            GET_CANONNAME(top, hp->h_name);
6237db96d56Sopenharmony_ci        }
6247db96d56Sopenharmony_ci        cur = cur->ai_next;
6257db96d56Sopenharmony_ci    }
6267db96d56Sopenharmony_ci#ifdef ENABLE_IPV6
6277db96d56Sopenharmony_ci    freehostent(hp);
6287db96d56Sopenharmony_ci#endif
6297db96d56Sopenharmony_ci    *res = top;
6307db96d56Sopenharmony_ci    return SUCCESS;
6317db96d56Sopenharmony_ci free:
6327db96d56Sopenharmony_ci    if (top)
6337db96d56Sopenharmony_ci        freeaddrinfo(top);
6347db96d56Sopenharmony_ci#ifdef ENABLE_IPV6
6357db96d56Sopenharmony_ci    if (hp)
6367db96d56Sopenharmony_ci        freehostent(hp);
6377db96d56Sopenharmony_ci#endif
6387db96d56Sopenharmony_ci/* bad: */
6397db96d56Sopenharmony_ci    *res = NULL;
6407db96d56Sopenharmony_ci    return error;
6417db96d56Sopenharmony_ci}
6427db96d56Sopenharmony_ci
6437db96d56Sopenharmony_ci#endif // HAVE_NETDB_H
644