Path: blob/main/crypto/heimdal/lib/roken/getaddrinfo.c
39507 views
/*1* Copyright (c) 1999 - 2001 Kungliga Tekniska Högskolan2* (Royal Institute of Technology, Stockholm, Sweden).3* All rights reserved.4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8*9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11*12* 2. Redistributions in binary form must reproduce the above copyright13* notice, this list of conditions and the following disclaimer in the14* documentation and/or other materials provided with the distribution.15*16* 3. Neither the name of the Institute nor the names of its contributors17* may be used to endorse or promote products derived from this software18* without specific prior written permission.19*20* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND21* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE22* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE23* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE24* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL25* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS26* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)27* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT28* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY29* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF30* SUCH DAMAGE.31*/3233#include <config.h>3435#include "roken.h"3637/*38* uses hints->ai_socktype and hints->ai_protocol39*/4041static int42get_port_protocol_socktype (const char *servname,43const struct addrinfo *hints,44int *port,45int *protocol,46int *socktype)47{48struct servent *se;49const char *proto_str = NULL;5051*socktype = 0;5253if (hints != NULL && hints->ai_protocol != 0) {54struct protoent *protoent = getprotobynumber (hints->ai_protocol);5556if (protoent == NULL)57return EAI_SOCKTYPE; /* XXX */5859proto_str = protoent->p_name;60*protocol = protoent->p_proto;61}6263if (hints != NULL)64*socktype = hints->ai_socktype;6566if (*socktype == SOCK_STREAM) {67se = getservbyname (servname, proto_str ? proto_str : "tcp");68if (proto_str == NULL)69*protocol = IPPROTO_TCP;70} else if (*socktype == SOCK_DGRAM) {71se = getservbyname (servname, proto_str ? proto_str : "udp");72if (proto_str == NULL)73*protocol = IPPROTO_UDP;74} else if (*socktype == 0) {75if (proto_str != NULL) {76se = getservbyname (servname, proto_str);77} else {78se = getservbyname (servname, "tcp");79*protocol = IPPROTO_TCP;80*socktype = SOCK_STREAM;81if (se == NULL) {82se = getservbyname (servname, "udp");83*protocol = IPPROTO_UDP;84*socktype = SOCK_DGRAM;85}86}87} else88return EAI_SOCKTYPE;8990if (se == NULL) {91char *endstr;9293*port = htons(strtol (servname, &endstr, 10));94if (servname == endstr)95return EAI_NONAME;96} else {97*port = se->s_port;98}99return 0;100}101102static int103add_one (int port, int protocol, int socktype,104struct addrinfo ***ptr,105int (*func)(struct addrinfo *, void *data, int port),106void *data,107char *canonname)108{109struct addrinfo *a;110int ret;111112a = malloc (sizeof (*a));113if (a == NULL)114return EAI_MEMORY;115memset (a, 0, sizeof(*a));116a->ai_flags = 0;117a->ai_next = NULL;118a->ai_protocol = protocol;119a->ai_socktype = socktype;120a->ai_canonname = canonname;121ret = (*func)(a, data, port);122if (ret) {123free (a);124return ret;125}126**ptr = a;127*ptr = &a->ai_next;128return 0;129}130131static int132const_v4 (struct addrinfo *a, void *data, int port)133{134struct sockaddr_in *sin4;135struct in_addr *addr = (struct in_addr *)data;136137a->ai_family = PF_INET;138a->ai_addrlen = sizeof(*sin4);139a->ai_addr = malloc (sizeof(*sin4));140if (a->ai_addr == NULL)141return EAI_MEMORY;142sin4 = (struct sockaddr_in *)a->ai_addr;143memset (sin4, 0, sizeof(*sin4));144sin4->sin_family = AF_INET;145sin4->sin_port = port;146sin4->sin_addr = *addr;147return 0;148}149150#ifdef HAVE_IPV6151static int152const_v6 (struct addrinfo *a, void *data, int port)153{154struct sockaddr_in6 *sin6;155struct in6_addr *addr = (struct in6_addr *)data;156157a->ai_family = PF_INET6;158a->ai_addrlen = sizeof(*sin6);159a->ai_addr = malloc (sizeof(*sin6));160if (a->ai_addr == NULL)161return EAI_MEMORY;162sin6 = (struct sockaddr_in6 *)a->ai_addr;163memset (sin6, 0, sizeof(*sin6));164sin6->sin6_family = AF_INET6;165sin6->sin6_port = port;166sin6->sin6_addr = *addr;167return 0;168}169#endif170171/* this is mostly a hack for some versions of AIX that has a prototype172for in6addr_loopback but no actual symbol in libc */173#if defined(HAVE_IPV6) && !defined(HAVE_IN6ADDR_LOOPBACK) && defined(IN6ADDR_LOOPBACK_INIT)174#define in6addr_loopback _roken_in6addr_loopback175struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;176#endif177178static int179get_null (const struct addrinfo *hints,180int port, int protocol, int socktype,181struct addrinfo **res)182{183struct in_addr v4_addr;184#ifdef HAVE_IPV6185struct in6_addr v6_addr;186#endif187struct addrinfo *first = NULL;188struct addrinfo **current = &first;189int family = PF_UNSPEC;190int ret = 0;191192if (hints != NULL)193family = hints->ai_family;194195if (hints && hints->ai_flags & AI_PASSIVE) {196v4_addr.s_addr = INADDR_ANY;197#ifdef HAVE_IPV6198v6_addr = in6addr_any;199#endif200} else {201v4_addr.s_addr = htonl(INADDR_LOOPBACK);202#ifdef HAVE_IPV6203v6_addr = in6addr_loopback;204#endif205}206207#ifdef HAVE_IPV6208if (family == PF_INET6 || family == PF_UNSPEC) {209ret = add_one (port, protocol, socktype,210¤t, const_v6, &v6_addr, NULL);211if (ret)212return ret;213}214#endif215if (family == PF_INET || family == PF_UNSPEC) {216ret = add_one (port, protocol, socktype,217¤t, const_v4, &v4_addr, NULL);218}219*res = first;220return ret;221}222223static int224add_hostent (int port, int protocol, int socktype,225struct addrinfo ***current,226int (*func)(struct addrinfo *, void *data, int port),227struct hostent *he, int *flags)228{229int ret;230char *canonname = NULL;231char **h;232233if (*flags & AI_CANONNAME) {234struct hostent *he2 = NULL;235const char *tmp_canon;236237tmp_canon = hostent_find_fqdn (he);238if (strchr (tmp_canon, '.') == NULL) {239int error;240241he2 = getipnodebyaddr (he->h_addr_list[0], he->h_length,242he->h_addrtype, &error);243if (he2 != NULL) {244const char *tmp = hostent_find_fqdn (he2);245246if (strchr (tmp, '.') != NULL)247tmp_canon = tmp;248}249}250251canonname = strdup (tmp_canon);252if (he2 != NULL)253freehostent (he2);254if (canonname == NULL)255return EAI_MEMORY;256}257258for (h = he->h_addr_list; *h != NULL; ++h) {259ret = add_one (port, protocol, socktype,260current, func, *h, canonname);261if (ret)262return ret;263if (*flags & AI_CANONNAME) {264*flags &= ~AI_CANONNAME;265canonname = NULL;266}267}268return 0;269}270271static int272get_number (const char *nodename,273const struct addrinfo *hints,274int port, int protocol, int socktype,275struct addrinfo **res)276{277struct addrinfo *first = NULL;278struct addrinfo **current = &first;279int family = PF_UNSPEC;280int ret;281282if (hints != NULL) {283family = hints->ai_family;284}285286#ifdef HAVE_IPV6287if (family == PF_INET6 || family == PF_UNSPEC) {288struct in6_addr v6_addr;289290if (inet_pton (PF_INET6, nodename, &v6_addr) == 1) {291ret = add_one (port, protocol, socktype,292¤t, const_v6, &v6_addr, NULL);293*res = first;294return ret;295}296}297#endif298if (family == PF_INET || family == PF_UNSPEC) {299struct in_addr v4_addr;300301if (inet_pton (PF_INET, nodename, &v4_addr) == 1) {302ret = add_one (port, protocol, socktype,303¤t, const_v4, &v4_addr, NULL);304*res = first;305return ret;306}307}308return EAI_NONAME;309}310311static int312get_nodes (const char *nodename,313const struct addrinfo *hints,314int port, int protocol, int socktype,315struct addrinfo **res)316{317struct addrinfo *first = NULL;318struct addrinfo **current = &first;319int family = PF_UNSPEC;320int flags = 0;321int ret = EAI_NONAME;322int error;323324if (hints != NULL) {325family = hints->ai_family;326flags = hints->ai_flags;327}328329#ifdef HAVE_IPV6330if (family == PF_INET6 || family == PF_UNSPEC) {331struct hostent *he;332333he = getipnodebyname (nodename, PF_INET6, 0, &error);334335if (he != NULL) {336ret = add_hostent (port, protocol, socktype,337¤t, const_v6, he, &flags);338freehostent (he);339}340}341#endif342if (family == PF_INET || family == PF_UNSPEC) {343struct hostent *he;344345he = getipnodebyname (nodename, PF_INET, 0, &error);346347if (he != NULL) {348ret = add_hostent (port, protocol, socktype,349¤t, const_v4, he, &flags);350freehostent (he);351}352}353*res = first;354return ret;355}356357/*358* hints:359*360* struct addrinfo {361* int ai_flags;362* int ai_family;363* int ai_socktype;364* int ai_protocol;365* ...366* };367*/368369ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL370getaddrinfo(const char *nodename,371const char *servname,372const struct addrinfo *hints,373struct addrinfo **res)374{375int ret;376int port = 0;377int protocol = 0;378int socktype = 0;379380*res = NULL;381382if (servname == NULL && nodename == NULL)383return EAI_NONAME;384385if (hints != NULL386&& hints->ai_family != PF_UNSPEC387&& hints->ai_family != PF_INET388#ifdef HAVE_IPV6389&& hints->ai_family != PF_INET6390#endif391)392return EAI_FAMILY;393394if (servname != NULL) {395ret = get_port_protocol_socktype (servname, hints,396&port, &protocol, &socktype);397if (ret)398return ret;399}400if (nodename != NULL) {401ret = get_number (nodename, hints, port, protocol, socktype, res);402if (ret) {403if(hints && hints->ai_flags & AI_NUMERICHOST)404ret = EAI_NONAME;405else406ret = get_nodes (nodename, hints, port, protocol, socktype,407res);408}409} else {410ret = get_null (hints, port, protocol, socktype, res);411}412if (ret)413freeaddrinfo (*res);414return ret;415}416417418