155682Smarkm/* 290926Snectar * 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#ifdef HAVE_CONFIG_H 3555682Smarkm#include <config.h> 36178825SdfrRCSID("$Id: getaddrinfo.c 15417 2005-06-16 17:49:29Z lha $"); 3755682Smarkm#endif 3855682Smarkm 3955682Smarkm#include "roken.h" 4055682Smarkm 4155682Smarkm/* 4255682Smarkm * uses hints->ai_socktype and hints->ai_protocol 4355682Smarkm */ 4455682Smarkm 4555682Smarkmstatic int 4655682Smarkmget_port_protocol_socktype (const char *servname, 4755682Smarkm const struct addrinfo *hints, 4855682Smarkm int *port, 4955682Smarkm int *protocol, 5055682Smarkm int *socktype) 5155682Smarkm{ 5255682Smarkm struct servent *se; 5355682Smarkm const char *proto_str = NULL; 5455682Smarkm 5555682Smarkm *socktype = 0; 5655682Smarkm 5755682Smarkm if (hints != NULL && hints->ai_protocol != 0) { 5855682Smarkm struct protoent *protoent = getprotobynumber (hints->ai_protocol); 5955682Smarkm 6055682Smarkm if (protoent == NULL) 6155682Smarkm return EAI_SOCKTYPE; /* XXX */ 6255682Smarkm 6355682Smarkm proto_str = protoent->p_name; 6455682Smarkm *protocol = protoent->p_proto; 6555682Smarkm } 6655682Smarkm 6755682Smarkm if (hints != NULL) 6855682Smarkm *socktype = hints->ai_socktype; 6955682Smarkm 7055682Smarkm if (*socktype == SOCK_STREAM) { 7155682Smarkm se = getservbyname (servname, proto_str ? proto_str : "tcp"); 7255682Smarkm if (proto_str == NULL) 7355682Smarkm *protocol = IPPROTO_TCP; 7455682Smarkm } else if (*socktype == SOCK_DGRAM) { 7555682Smarkm se = getservbyname (servname, proto_str ? proto_str : "udp"); 7655682Smarkm if (proto_str == NULL) 7755682Smarkm *protocol = IPPROTO_UDP; 7855682Smarkm } else if (*socktype == 0) { 7955682Smarkm if (proto_str != NULL) { 8055682Smarkm se = getservbyname (servname, proto_str); 8155682Smarkm } else { 8255682Smarkm se = getservbyname (servname, "tcp"); 8355682Smarkm *protocol = IPPROTO_TCP; 8455682Smarkm *socktype = SOCK_STREAM; 8555682Smarkm if (se == NULL) { 8655682Smarkm se = getservbyname (servname, "udp"); 8755682Smarkm *protocol = IPPROTO_UDP; 8855682Smarkm *socktype = SOCK_DGRAM; 8955682Smarkm } 9055682Smarkm } 9155682Smarkm } else 9255682Smarkm return EAI_SOCKTYPE; 9355682Smarkm 9455682Smarkm if (se == NULL) { 9555682Smarkm char *endstr; 9655682Smarkm 9755682Smarkm *port = htons(strtol (servname, &endstr, 10)); 9855682Smarkm if (servname == endstr) 9955682Smarkm return EAI_NONAME; 10055682Smarkm } else { 10155682Smarkm *port = se->s_port; 10255682Smarkm } 10355682Smarkm return 0; 10455682Smarkm} 10555682Smarkm 10655682Smarkmstatic int 10755682Smarkmadd_one (int port, int protocol, int socktype, 10855682Smarkm struct addrinfo ***ptr, 10955682Smarkm int (*func)(struct addrinfo *, void *data, int port), 11055682Smarkm void *data, 11155682Smarkm char *canonname) 11255682Smarkm{ 11355682Smarkm struct addrinfo *a; 11455682Smarkm int ret; 11555682Smarkm 11655682Smarkm a = malloc (sizeof (*a)); 11755682Smarkm if (a == NULL) 11855682Smarkm return EAI_MEMORY; 11955682Smarkm memset (a, 0, sizeof(*a)); 12055682Smarkm a->ai_flags = 0; 12155682Smarkm a->ai_next = NULL; 12255682Smarkm a->ai_protocol = protocol; 12355682Smarkm a->ai_socktype = socktype; 12455682Smarkm a->ai_canonname = canonname; 12555682Smarkm ret = (*func)(a, data, port); 12655682Smarkm if (ret) { 12755682Smarkm free (a); 12855682Smarkm return ret; 12955682Smarkm } 13055682Smarkm **ptr = a; 13155682Smarkm *ptr = &a->ai_next; 13255682Smarkm return 0; 13355682Smarkm} 13455682Smarkm 13555682Smarkmstatic int 13655682Smarkmconst_v4 (struct addrinfo *a, void *data, int port) 13755682Smarkm{ 138178825Sdfr struct sockaddr_in *sin4; 13955682Smarkm struct in_addr *addr = (struct in_addr *)data; 14055682Smarkm 14155682Smarkm a->ai_family = PF_INET; 142178825Sdfr a->ai_addrlen = sizeof(*sin4); 143178825Sdfr a->ai_addr = malloc (sizeof(*sin4)); 14455682Smarkm if (a->ai_addr == NULL) 14555682Smarkm return EAI_MEMORY; 146178825Sdfr sin4 = (struct sockaddr_in *)a->ai_addr; 147178825Sdfr memset (sin4, 0, sizeof(*sin4)); 148178825Sdfr sin4->sin_family = AF_INET; 149178825Sdfr sin4->sin_port = port; 150178825Sdfr sin4->sin_addr = *addr; 15155682Smarkm return 0; 15255682Smarkm} 15355682Smarkm 15455682Smarkm#ifdef HAVE_IPV6 15555682Smarkmstatic int 15655682Smarkmconst_v6 (struct addrinfo *a, void *data, int port) 15755682Smarkm{ 15855682Smarkm struct sockaddr_in6 *sin6; 15955682Smarkm struct in6_addr *addr = (struct in6_addr *)data; 16055682Smarkm 16155682Smarkm a->ai_family = PF_INET6; 16255682Smarkm a->ai_addrlen = sizeof(*sin6); 16355682Smarkm a->ai_addr = malloc (sizeof(*sin6)); 16455682Smarkm if (a->ai_addr == NULL) 16555682Smarkm return EAI_MEMORY; 16655682Smarkm sin6 = (struct sockaddr_in6 *)a->ai_addr; 16755682Smarkm memset (sin6, 0, sizeof(*sin6)); 16855682Smarkm sin6->sin6_family = AF_INET6; 16955682Smarkm sin6->sin6_port = port; 17055682Smarkm sin6->sin6_addr = *addr; 17155682Smarkm return 0; 17255682Smarkm} 17355682Smarkm#endif 17455682Smarkm 17590926Snectar/* this is mostly a hack for some versions of AIX that has a prototype 17690926Snectar for in6addr_loopback but no actual symbol in libc */ 17790926Snectar#if defined(HAVE_IPV6) && !defined(HAVE_IN6ADDR_LOOPBACK) && defined(IN6ADDR_LOOPBACK_INIT) 17890926Snectar#define in6addr_loopback _roken_in6addr_loopback 17990926Snectarstruct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; 18090926Snectar#endif 18190926Snectar 18255682Smarkmstatic int 18355682Smarkmget_null (const struct addrinfo *hints, 18455682Smarkm int port, int protocol, int socktype, 18555682Smarkm struct addrinfo **res) 18655682Smarkm{ 18755682Smarkm struct in_addr v4_addr; 18855682Smarkm#ifdef HAVE_IPV6 18955682Smarkm struct in6_addr v6_addr; 19055682Smarkm#endif 19155682Smarkm struct addrinfo *first = NULL; 19255682Smarkm struct addrinfo **current = &first; 19355682Smarkm int family = PF_UNSPEC; 19455682Smarkm int ret; 19555682Smarkm 19655682Smarkm if (hints != NULL) 19755682Smarkm family = hints->ai_family; 19855682Smarkm 19955682Smarkm if (hints && hints->ai_flags & AI_PASSIVE) { 20055682Smarkm v4_addr.s_addr = INADDR_ANY; 20155682Smarkm#ifdef HAVE_IPV6 20255682Smarkm v6_addr = in6addr_any; 20355682Smarkm#endif 20455682Smarkm } else { 20555682Smarkm v4_addr.s_addr = htonl(INADDR_LOOPBACK); 20655682Smarkm#ifdef HAVE_IPV6 20755682Smarkm v6_addr = in6addr_loopback; 20855682Smarkm#endif 20955682Smarkm } 21055682Smarkm 21155682Smarkm#ifdef HAVE_IPV6 21255682Smarkm if (family == PF_INET6 || family == PF_UNSPEC) { 21355682Smarkm ret = add_one (port, protocol, socktype, 21455682Smarkm ¤t, const_v6, &v6_addr, NULL); 21555682Smarkm } 21655682Smarkm#endif 21755682Smarkm if (family == PF_INET || family == PF_UNSPEC) { 21855682Smarkm ret = add_one (port, protocol, socktype, 21955682Smarkm ¤t, const_v4, &v4_addr, NULL); 22055682Smarkm } 22155682Smarkm *res = first; 22255682Smarkm return 0; 22355682Smarkm} 22455682Smarkm 22555682Smarkmstatic int 22655682Smarkmadd_hostent (int port, int protocol, int socktype, 22755682Smarkm struct addrinfo ***current, 22855682Smarkm int (*func)(struct addrinfo *, void *data, int port), 22955682Smarkm struct hostent *he, int *flags) 23055682Smarkm{ 23155682Smarkm int ret; 23255682Smarkm char *canonname = NULL; 23372445Sassar char **h; 23455682Smarkm 23555682Smarkm if (*flags & AI_CANONNAME) { 23672445Sassar struct hostent *he2 = NULL; 23790926Snectar const char *tmp_canon; 23855682Smarkm 23990926Snectar tmp_canon = hostent_find_fqdn (he); 24090926Snectar if (strchr (tmp_canon, '.') == NULL) { 24172445Sassar int error; 24272445Sassar 24372445Sassar he2 = getipnodebyaddr (he->h_addr_list[0], he->h_length, 24472445Sassar he->h_addrtype, &error); 24572445Sassar if (he2 != NULL) { 24690926Snectar const char *tmp = hostent_find_fqdn (he2); 24772445Sassar 24872445Sassar if (strchr (tmp, '.') != NULL) 24990926Snectar tmp_canon = tmp; 25055682Smarkm } 25172445Sassar } 25272445Sassar 25390926Snectar canonname = strdup (tmp_canon); 25472445Sassar if (he2 != NULL) 25572445Sassar freehostent (he2); 25655682Smarkm if (canonname == NULL) 25755682Smarkm return EAI_MEMORY; 25855682Smarkm } 25955682Smarkm 26055682Smarkm for (h = he->h_addr_list; *h != NULL; ++h) { 26155682Smarkm ret = add_one (port, protocol, socktype, 26255682Smarkm current, func, *h, canonname); 26355682Smarkm if (ret) 26455682Smarkm return ret; 26555682Smarkm if (*flags & AI_CANONNAME) { 26655682Smarkm *flags &= ~AI_CANONNAME; 26755682Smarkm canonname = NULL; 26855682Smarkm } 26955682Smarkm } 27055682Smarkm return 0; 27155682Smarkm} 27255682Smarkm 27355682Smarkmstatic int 27455682Smarkmget_number (const char *nodename, 27555682Smarkm const struct addrinfo *hints, 27655682Smarkm int port, int protocol, int socktype, 27755682Smarkm struct addrinfo **res) 27855682Smarkm{ 27955682Smarkm struct addrinfo *first = NULL; 28055682Smarkm struct addrinfo **current = &first; 28155682Smarkm int family = PF_UNSPEC; 28255682Smarkm int ret; 28355682Smarkm 28455682Smarkm if (hints != NULL) { 28555682Smarkm family = hints->ai_family; 28655682Smarkm } 28755682Smarkm 28855682Smarkm#ifdef HAVE_IPV6 28955682Smarkm if (family == PF_INET6 || family == PF_UNSPEC) { 29055682Smarkm struct in6_addr v6_addr; 29155682Smarkm 29255682Smarkm if (inet_pton (PF_INET6, nodename, &v6_addr) == 1) { 29355682Smarkm ret = add_one (port, protocol, socktype, 29455682Smarkm ¤t, const_v6, &v6_addr, NULL); 29555682Smarkm *res = first; 29655682Smarkm return ret; 29755682Smarkm } 29855682Smarkm } 29955682Smarkm#endif 30055682Smarkm if (family == PF_INET || family == PF_UNSPEC) { 30155682Smarkm struct in_addr v4_addr; 30255682Smarkm 30355682Smarkm if (inet_pton (PF_INET, nodename, &v4_addr) == 1) { 30455682Smarkm ret = add_one (port, protocol, socktype, 30555682Smarkm ¤t, const_v4, &v4_addr, NULL); 30655682Smarkm *res = first; 30755682Smarkm return ret; 30855682Smarkm } 30955682Smarkm } 31055682Smarkm return EAI_NONAME; 31155682Smarkm} 31255682Smarkm 31355682Smarkmstatic int 31455682Smarkmget_nodes (const char *nodename, 31555682Smarkm const struct addrinfo *hints, 31655682Smarkm int port, int protocol, int socktype, 31755682Smarkm struct addrinfo **res) 31855682Smarkm{ 31955682Smarkm struct addrinfo *first = NULL; 32055682Smarkm struct addrinfo **current = &first; 32155682Smarkm int family = PF_UNSPEC; 32255682Smarkm int flags = 0; 32355682Smarkm int ret = EAI_NONAME; 32455682Smarkm int error; 32555682Smarkm 32655682Smarkm if (hints != NULL) { 32755682Smarkm family = hints->ai_family; 32855682Smarkm flags = hints->ai_flags; 32955682Smarkm } 33055682Smarkm 33155682Smarkm#ifdef HAVE_IPV6 33255682Smarkm if (family == PF_INET6 || family == PF_UNSPEC) { 33355682Smarkm struct hostent *he; 33455682Smarkm 33555682Smarkm he = getipnodebyname (nodename, PF_INET6, 0, &error); 33655682Smarkm 33755682Smarkm if (he != NULL) { 33855682Smarkm ret = add_hostent (port, protocol, socktype, 33955682Smarkm ¤t, const_v6, he, &flags); 34055682Smarkm freehostent (he); 34155682Smarkm } 34255682Smarkm } 34355682Smarkm#endif 34455682Smarkm if (family == PF_INET || family == PF_UNSPEC) { 34555682Smarkm struct hostent *he; 34655682Smarkm 34755682Smarkm he = getipnodebyname (nodename, PF_INET, 0, &error); 34855682Smarkm 34955682Smarkm if (he != NULL) { 35055682Smarkm ret = add_hostent (port, protocol, socktype, 35155682Smarkm ¤t, const_v4, he, &flags); 35255682Smarkm freehostent (he); 35355682Smarkm } 35455682Smarkm } 35555682Smarkm *res = first; 35655682Smarkm return ret; 35755682Smarkm} 35855682Smarkm 35955682Smarkm/* 36055682Smarkm * hints: 36155682Smarkm * 36255682Smarkm * struct addrinfo { 36355682Smarkm * int ai_flags; 36455682Smarkm * int ai_family; 36555682Smarkm * int ai_socktype; 36655682Smarkm * int ai_protocol; 36755682Smarkm * ... 36855682Smarkm * }; 36955682Smarkm */ 37055682Smarkm 371178825Sdfrint ROKEN_LIB_FUNCTION 37255682Smarkmgetaddrinfo(const char *nodename, 37355682Smarkm const char *servname, 37455682Smarkm const struct addrinfo *hints, 37555682Smarkm struct addrinfo **res) 37655682Smarkm{ 37755682Smarkm int ret; 37855682Smarkm int port = 0; 37955682Smarkm int protocol = 0; 38055682Smarkm int socktype = 0; 38155682Smarkm 38255682Smarkm *res = NULL; 38355682Smarkm 38455682Smarkm if (servname == NULL && nodename == NULL) 38555682Smarkm return EAI_NONAME; 38655682Smarkm 38755682Smarkm if (hints != NULL 38855682Smarkm && hints->ai_family != PF_UNSPEC 38955682Smarkm && hints->ai_family != PF_INET 39055682Smarkm#ifdef HAVE_IPV6 39155682Smarkm && hints->ai_family != PF_INET6 39255682Smarkm#endif 39355682Smarkm ) 39455682Smarkm return EAI_FAMILY; 39555682Smarkm 39655682Smarkm if (servname != NULL) { 39755682Smarkm ret = get_port_protocol_socktype (servname, hints, 39855682Smarkm &port, &protocol, &socktype); 39955682Smarkm if (ret) 40055682Smarkm return ret; 40155682Smarkm } 40255682Smarkm if (nodename != NULL) { 40355682Smarkm ret = get_number (nodename, hints, port, protocol, socktype, res); 40455682Smarkm if (ret) { 40555682Smarkm if(hints && hints->ai_flags & AI_NUMERICHOST) 40655682Smarkm ret = EAI_NONAME; 40755682Smarkm else 40855682Smarkm ret = get_nodes (nodename, hints, port, protocol, socktype, 40955682Smarkm res); 41055682Smarkm } 41155682Smarkm } else { 41255682Smarkm ret = get_null (hints, port, protocol, socktype, res); 41355682Smarkm } 41455682Smarkm if (ret) 41555682Smarkm freeaddrinfo (*res); 41655682Smarkm return ret; 41755682Smarkm} 418