155682Smarkm/* 2178825Sdfr * Copyright (c) 1999 - 2001 Kungliga Tekniska H��gskolan 355682Smarkm * (Royal Institute of Technology, Stockholm, Sweden). 455682Smarkm * All rights reserved. 555682Smarkm * 655682Smarkm * Redistribution and use in source and binary forms, with or without 755682Smarkm * modification, are permitted provided that the following conditions 855682Smarkm * are met: 955682Smarkm * 1055682Smarkm * 1. Redistributions of source code must retain the above copyright 1155682Smarkm * notice, this list of conditions and the following disclaimer. 1255682Smarkm * 1355682Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1455682Smarkm * notice, this list of conditions and the following disclaimer in the 1555682Smarkm * documentation and/or other materials provided with the distribution. 1655682Smarkm * 1755682Smarkm * 3. Neither the name of the Institute nor the names of its contributors 1855682Smarkm * may be used to endorse or promote products derived from this software 1955682Smarkm * without specific prior written permission. 2055682Smarkm * 2155682Smarkm * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 2255682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2355682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2455682Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 2555682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2655682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2755682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2855682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2955682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3055682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3155682Smarkm * SUCH DAMAGE. 3255682Smarkm */ 3355682Smarkm 3455682Smarkm#include <config.h> 3555682Smarkm 36178825Sdfr#include "roken.h" 3755682Smarkm 38178825Sdfr/* 39178825Sdfr * uses hints->ai_socktype and hints->ai_protocol 40178825Sdfr */ 41178825Sdfr 42178825Sdfrstatic int 43178825Sdfrget_port_protocol_socktype (const char *servname, 44178825Sdfr const struct addrinfo *hints, 45178825Sdfr int *port, 46178825Sdfr int *protocol, 47178825Sdfr int *socktype) 48178825Sdfr{ 49178825Sdfr struct servent *se; 50178825Sdfr const char *proto_str = NULL; 51178825Sdfr 52178825Sdfr *socktype = 0; 53178825Sdfr 54178825Sdfr if (hints != NULL && hints->ai_protocol != 0) { 55178825Sdfr struct protoent *protoent = getprotobynumber (hints->ai_protocol); 56178825Sdfr 57178825Sdfr if (protoent == NULL) 58178825Sdfr return EAI_SOCKTYPE; /* XXX */ 59178825Sdfr 60178825Sdfr proto_str = protoent->p_name; 61178825Sdfr *protocol = protoent->p_proto; 62178825Sdfr } 63178825Sdfr 64178825Sdfr if (hints != NULL) 65178825Sdfr *socktype = hints->ai_socktype; 66178825Sdfr 67178825Sdfr if (*socktype == SOCK_STREAM) { 68178825Sdfr se = getservbyname (servname, proto_str ? proto_str : "tcp"); 69178825Sdfr if (proto_str == NULL) 70178825Sdfr *protocol = IPPROTO_TCP; 71178825Sdfr } else if (*socktype == SOCK_DGRAM) { 72178825Sdfr se = getservbyname (servname, proto_str ? proto_str : "udp"); 73178825Sdfr if (proto_str == NULL) 74178825Sdfr *protocol = IPPROTO_UDP; 75178825Sdfr } else if (*socktype == 0) { 76178825Sdfr if (proto_str != NULL) { 77178825Sdfr se = getservbyname (servname, proto_str); 78178825Sdfr } else { 79178825Sdfr se = getservbyname (servname, "tcp"); 80178825Sdfr *protocol = IPPROTO_TCP; 81178825Sdfr *socktype = SOCK_STREAM; 82178825Sdfr if (se == NULL) { 83178825Sdfr se = getservbyname (servname, "udp"); 84178825Sdfr *protocol = IPPROTO_UDP; 85178825Sdfr *socktype = SOCK_DGRAM; 86178825Sdfr } 87178825Sdfr } 88178825Sdfr } else 89178825Sdfr return EAI_SOCKTYPE; 90178825Sdfr 91178825Sdfr if (se == NULL) { 92178825Sdfr char *endstr; 93178825Sdfr 94178825Sdfr *port = htons(strtol (servname, &endstr, 10)); 95178825Sdfr if (servname == endstr) 96178825Sdfr return EAI_NONAME; 97178825Sdfr } else { 98178825Sdfr *port = se->s_port; 99178825Sdfr } 100178825Sdfr return 0; 10155682Smarkm} 10255682Smarkm 10390926Snectarstatic int 10490926Snectaradd_one (int port, int protocol, int socktype, 10555682Smarkm struct addrinfo ***ptr, 10655682Smarkm int (*func)(struct addrinfo *, void *data, int port), 10755682Smarkm void *data, 10855682Smarkm char *canonname) 10955682Smarkm{ 11055682Smarkm struct addrinfo *a; 11155682Smarkm int ret; 11255682Smarkm 11355682Smarkm a = malloc (sizeof (*a)); 11455682Smarkm if (a == NULL) 11555682Smarkm return EAI_MEMORY; 11655682Smarkm memset (a, 0, sizeof(*a)); 11755682Smarkm a->ai_flags = 0; 11855682Smarkm a->ai_next = NULL; 11955682Smarkm a->ai_protocol = protocol; 12055682Smarkm a->ai_socktype = socktype; 12155682Smarkm a->ai_canonname = canonname; 12255682Smarkm ret = (*func)(a, data, port); 12355682Smarkm if (ret) { 12455682Smarkm free (a); 12555682Smarkm return ret; 12655682Smarkm } 12755682Smarkm **ptr = a; 12855682Smarkm *ptr = &a->ai_next; 12955682Smarkm return 0; 13055682Smarkm} 13155682Smarkm 13255682Smarkmstatic int 13355682Smarkmconst_v4 (struct addrinfo *a, void *data, int port) 134178825Sdfr{ 13555682Smarkm struct sockaddr_in *sin4; 13657416Smarkm struct in_addr *addr = (struct in_addr *)data; 13755682Smarkm 13855682Smarkm a->ai_family = PF_INET; 13955682Smarkm a->ai_addrlen = sizeof(*sin4); 14055682Smarkm a->ai_addr = malloc (sizeof(*sin4)); 14155682Smarkm if (a->ai_addr == NULL) 14255682Smarkm return EAI_MEMORY; 14355682Smarkm sin4 = (struct sockaddr_in *)a->ai_addr; 14455682Smarkm memset (sin4, 0, sizeof(*sin4)); 14555682Smarkm sin4->sin_family = AF_INET; 14655682Smarkm sin4->sin_port = port; 14755682Smarkm sin4->sin_addr = *addr; 14855682Smarkm return 0; 14955682Smarkm} 15055682Smarkm 151178825Sdfr#ifdef HAVE_IPV6 15255682Smarkmstatic int 15355682Smarkmconst_v6 (struct addrinfo *a, void *data, int port) 15455682Smarkm{ 15555682Smarkm struct sockaddr_in6 *sin6; 15655682Smarkm struct in6_addr *addr = (struct in6_addr *)data; 15755682Smarkm 15855682Smarkm a->ai_family = PF_INET6; 15990926Snectar a->ai_addrlen = sizeof(*sin6); 16055682Smarkm a->ai_addr = malloc (sizeof(*sin6)); 16155682Smarkm if (a->ai_addr == NULL) 16290926Snectar return EAI_MEMORY; 16390926Snectar sin6 = (struct sockaddr_in6 *)a->ai_addr; 16490926Snectar memset (sin6, 0, sizeof(*sin6)); 16590926Snectar sin6->sin6_family = AF_INET6; 16655682Smarkm sin6->sin6_port = port; 16755682Smarkm sin6->sin6_addr = *addr; 16855682Smarkm return 0; 16955682Smarkm} 17055682Smarkm#endif 17155682Smarkm 17255682Smarkm/* this is mostly a hack for some versions of AIX that has a prototype 173178825Sdfr for in6addr_loopback but no actual symbol in libc */ 17490926Snectar#if defined(HAVE_IPV6) && !defined(HAVE_IN6ADDR_LOOPBACK) && defined(IN6ADDR_LOOPBACK_INIT) 17555682Smarkm#define in6addr_loopback _roken_in6addr_loopback 17655682Smarkmstruct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; 17755682Smarkm#endif 178178825Sdfr 17955682Smarkmstatic int 18055682Smarkmget_null (const struct addrinfo *hints, 18155682Smarkm int port, int protocol, int socktype, 18255682Smarkm struct addrinfo **res) 18355682Smarkm{ 18455682Smarkm struct in_addr v4_addr; 18555682Smarkm#ifdef HAVE_IPV6 186178825Sdfr struct in6_addr v6_addr; 18755682Smarkm#endif 18855682Smarkm struct addrinfo *first = NULL; 18955682Smarkm struct addrinfo **current = &first; 19055682Smarkm int family = PF_UNSPEC; 191102644Snectar int ret; 192102644Snectar 193102644Snectar if (hints != NULL) 194102644Snectar family = hints->ai_family; 195102644Snectar 196102644Snectar if (hints && hints->ai_flags & AI_PASSIVE) { 197102644Snectar v4_addr.s_addr = INADDR_ANY; 198102644Snectar#ifdef HAVE_IPV6 199178825Sdfr v6_addr = in6addr_any; 200102644Snectar#endif 201102644Snectar } else { 202102644Snectar v4_addr.s_addr = htonl(INADDR_LOOPBACK); 203178825Sdfr#ifdef HAVE_IPV6 204102644Snectar v6_addr = in6addr_loopback; 205102644Snectar#endif 206102644Snectar } 207102644Snectar 208102644Snectar#ifdef HAVE_IPV6 20955682Smarkm if (family == PF_INET6 || family == PF_UNSPEC) { 21055682Smarkm ret = add_one (port, protocol, socktype, 21155682Smarkm ¤t, const_v6, &v6_addr, NULL); 21255682Smarkm } 21355682Smarkm#endif 214178825Sdfr if (family == PF_INET || family == PF_UNSPEC) { 21555682Smarkm ret = add_one (port, protocol, socktype, 21655682Smarkm ¤t, const_v4, &v4_addr, NULL); 21755682Smarkm } 21855682Smarkm *res = first; 21955682Smarkm return 0; 22055682Smarkm} 22157416Smarkm 22255682Smarkmstatic int 223102644Snectaradd_hostent (int port, int protocol, int socktype, 22455682Smarkm struct addrinfo ***current, 22555682Smarkm int (*func)(struct addrinfo *, void *data, int port), 22655682Smarkm struct hostent *he, int *flags) 22755682Smarkm{ 228178825Sdfr int ret; 22955682Smarkm char *canonname = NULL; 23055682Smarkm char **h; 23155682Smarkm 23255682Smarkm if (*flags & AI_CANONNAME) { 233102644Snectar struct hostent *he2 = NULL; 234102644Snectar const char *tmp_canon; 235102644Snectar 236102644Snectar tmp_canon = hostent_find_fqdn (he); 237102644Snectar if (strchr (tmp_canon, '.') == NULL) { 238102644Snectar int error; 239102644Snectar 240102644Snectar he2 = getipnodebyaddr (he->h_addr_list[0], he->h_length, 241102644Snectar he->h_addrtype, &error); 242102644Snectar if (he2 != NULL) { 243102644Snectar const char *tmp = hostent_find_fqdn (he2); 244102644Snectar 245102644Snectar if (strchr (tmp, '.') != NULL) 246102644Snectar tmp_canon = tmp; 247102644Snectar } 24855682Smarkm } 24955682Smarkm 25055682Smarkm canonname = strdup (tmp_canon); 251102644Snectar if (he2 != NULL) 252102644Snectar freehostent (he2); 25355682Smarkm if (canonname == NULL) 254102644Snectar return EAI_MEMORY; 255102644Snectar } 256102644Snectar 25755682Smarkm for (h = he->h_addr_list; *h != NULL; ++h) { 25855682Smarkm ret = add_one (port, protocol, socktype, 25955682Smarkm current, func, *h, canonname); 260178825Sdfr if (ret) 261178825Sdfr return ret; 26255682Smarkm if (*flags & AI_CANONNAME) { 26355682Smarkm *flags &= ~AI_CANONNAME; 26455682Smarkm canonname = NULL; 26555682Smarkm } 26655682Smarkm } 26755682Smarkm return 0; 268178825Sdfr} 26955682Smarkm 270178825Sdfrstatic int 27155682Smarkmget_number (const char *nodename, 272178825Sdfr const struct addrinfo *hints, 273178825Sdfr int port, int protocol, int socktype, 27455682Smarkm struct addrinfo **res) 275178825Sdfr{ 276178825Sdfr struct addrinfo *first = NULL; 27778527Sassar struct addrinfo **current = &first; 27878527Sassar int family = PF_UNSPEC; 27978527Sassar int ret; 280178825Sdfr 281178825Sdfr if (hints != NULL) { 28278527Sassar family = hints->ai_family; 28378527Sassar } 284178825Sdfr 285178825Sdfr#ifdef HAVE_IPV6 286178825Sdfr if (family == PF_INET6 || family == PF_UNSPEC) { 287178825Sdfr struct in6_addr v6_addr; 288178825Sdfr 289178825Sdfr if (inet_pton (PF_INET6, nodename, &v6_addr) == 1) { 290178825Sdfr ret = add_one (port, protocol, socktype, 291178825Sdfr ¤t, const_v6, &v6_addr, NULL); 292178825Sdfr *res = first; 293178825Sdfr return ret; 294178825Sdfr } 295178825Sdfr } 296178825Sdfr#endif 297178825Sdfr if (family == PF_INET || family == PF_UNSPEC) { 298178825Sdfr struct in_addr v4_addr; 299178825Sdfr 300178825Sdfr if (inet_pton (PF_INET, nodename, &v4_addr) == 1) { 301178825Sdfr ret = add_one (port, protocol, socktype, 302178825Sdfr ¤t, const_v4, &v4_addr, NULL); 303178825Sdfr *res = first; 304178825Sdfr return ret; 305178825Sdfr } 30655682Smarkm } 30755682Smarkm return EAI_NONAME; 30855682Smarkm} 30955682Smarkm 31055682Smarkmstatic int 311178825Sdfrget_nodes (const char *nodename, 31255682Smarkm const struct addrinfo *hints, 31355682Smarkm int port, int protocol, int socktype, 314178825Sdfr struct addrinfo **res) 31555682Smarkm{ 31655682Smarkm struct addrinfo *first = NULL; 317178825Sdfr struct addrinfo **current = &first; 318178825Sdfr int family = PF_UNSPEC; 319178825Sdfr int flags = 0; 320178825Sdfr int ret = EAI_NONAME; 321178825Sdfr int error; 322178825Sdfr 323178825Sdfr if (hints != NULL) { 324178825Sdfr family = hints->ai_family; 325178825Sdfr flags = hints->ai_flags; 326178825Sdfr } 327178825Sdfr 328178825Sdfr#ifdef HAVE_IPV6 329178825Sdfr if (family == PF_INET6 || family == PF_UNSPEC) { 330178825Sdfr struct hostent *he; 331178825Sdfr 332178825Sdfr he = getipnodebyname (nodename, PF_INET6, 0, &error); 333178825Sdfr 334178825Sdfr if (he != NULL) { 335178825Sdfr ret = add_hostent (port, protocol, socktype, 336178825Sdfr ¤t, const_v6, he, &flags); 337178825Sdfr freehostent (he); 338178825Sdfr } 33955682Smarkm } 340178825Sdfr#endif 34155682Smarkm if (family == PF_INET || family == PF_UNSPEC) { 342178825Sdfr struct hostent *he; 34378527Sassar 34455682Smarkm he = getipnodebyname (nodename, PF_INET, 0, &error); 34578527Sassar 346178825Sdfr if (he != NULL) { 34755682Smarkm ret = add_hostent (port, protocol, socktype, 348178825Sdfr ¤t, const_v4, he, &flags); 349178825Sdfr freehostent (he); 35055682Smarkm } 35155682Smarkm } 352178825Sdfr *res = first; 353178825Sdfr return ret; 354178825Sdfr} 35578527Sassar 35655682Smarkm/* 35778527Sassar * hints: 358178825Sdfr * 35955682Smarkm * struct addrinfo { 360178825Sdfr * int ai_flags; 361178825Sdfr * int ai_family; 36255682Smarkm * int ai_socktype; 36355682Smarkm * int ai_protocol; 36455682Smarkm * ... 36572445Sassar * }; 366178825Sdfr */ 36755682Smarkm 36855682SmarkmROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 36955682Smarkmgetaddrinfo(const char *nodename, 37055682Smarkm const char *servname, 37155682Smarkm const struct addrinfo *hints, 37255682Smarkm struct addrinfo **res) 37355682Smarkm{ 37455682Smarkm int ret; 37555682Smarkm int port = 0; 37655682Smarkm int protocol = 0; 37755682Smarkm int socktype = 0; 37855682Smarkm 37955682Smarkm *res = NULL; 38078527Sassar 38155682Smarkm if (servname == NULL && nodename == NULL) 38255682Smarkm return EAI_NONAME; 38355682Smarkm 38490926Snectar if (hints != NULL 38555682Smarkm && hints->ai_family != PF_UNSPEC 38655682Smarkm && hints->ai_family != PF_INET 38755682Smarkm#ifdef HAVE_IPV6 38855682Smarkm && hints->ai_family != PF_INET6 38955682Smarkm#endif 39055682Smarkm ) 39155682Smarkm return EAI_FAMILY; 39255682Smarkm 39355682Smarkm if (servname != NULL) { 39455682Smarkm ret = get_port_protocol_socktype (servname, hints, 39572445Sassar &port, &protocol, &socktype); 39672445Sassar if (ret) 397178825Sdfr return ret; 39872445Sassar } 39972445Sassar if (nodename != NULL) { 40072445Sassar ret = get_number (nodename, hints, port, protocol, socktype, res); 40155682Smarkm if (ret) { 40255682Smarkm if(hints && hints->ai_flags & AI_NUMERICHOST) 40355682Smarkm ret = EAI_NONAME; 40455682Smarkm else 40555682Smarkm ret = get_nodes (nodename, hints, port, protocol, socktype, 40655682Smarkm res); 40755682Smarkm } 40855682Smarkm } else { 40955682Smarkm ret = get_null (hints, port, protocol, socktype, res); 41055682Smarkm } 41155682Smarkm if (ret) 41255682Smarkm freeaddrinfo (*res); 41355682Smarkm return ret; 41455682Smarkm} 41555682Smarkm