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