root/source4/heimdal/lib/roken/getaddrinfo.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_port_protocol_socktype
  2. add_one
  3. const_v4
  4. const_v6
  5. get_null
  6. add_hostent
  7. get_number
  8. get_nodes
  9. getaddrinfo

   1 /*
   2  * Copyright (c) 1999 - 2001 Kungliga Tekniska Högskolan
   3  * (Royal Institute of Technology, Stockholm, Sweden).
   4  * All rights reserved.
   5  *
   6  * Redistribution and use in source and binary forms, with or without
   7  * modification, are permitted provided that the following conditions
   8  * are met:
   9  *
  10  * 1. Redistributions of source code must retain the above copyright
  11  *    notice, this list of conditions and the following disclaimer.
  12  *
  13  * 2. Redistributions in binary form must reproduce the above copyright
  14  *    notice, this list of conditions and the following disclaimer in the
  15  *    documentation and/or other materials provided with the distribution.
  16  *
  17  * 3. Neither the name of the Institute nor the names of its contributors
  18  *    may be used to endorse or promote products derived from this software
  19  *    without specific prior written permission.
  20  *
  21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
  22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
  25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31  * SUCH DAMAGE.
  32  */
  33 
  34 #ifdef HAVE_CONFIG_H
  35 #include <config.h>
  36 RCSID("$Id$");
  37 #endif
  38 
  39 #include "roken.h"
  40 
  41 /*
  42  * uses hints->ai_socktype and hints->ai_protocol
  43  */
  44 
  45 static int
  46 get_port_protocol_socktype (const char *servname,
     /* [<][>][^][v][top][bottom][index][help] */
  47                             const struct addrinfo *hints,
  48                             int *port,
  49                             int *protocol,
  50                             int *socktype)
  51 {
  52     struct servent *se;
  53     const char *proto_str = NULL;
  54 
  55     *socktype = 0;
  56 
  57     if (hints != NULL && hints->ai_protocol != 0) {
  58         struct protoent *protoent = getprotobynumber (hints->ai_protocol);
  59 
  60         if (protoent == NULL)
  61             return EAI_SOCKTYPE; /* XXX */
  62 
  63         proto_str = protoent->p_name;
  64         *protocol = protoent->p_proto;
  65     }
  66 
  67     if (hints != NULL)
  68         *socktype = hints->ai_socktype;
  69 
  70     if (*socktype == SOCK_STREAM) {
  71         se = getservbyname (servname, proto_str ? proto_str : "tcp");
  72         if (proto_str == NULL)
  73             *protocol = IPPROTO_TCP;
  74     } else if (*socktype == SOCK_DGRAM) {
  75         se = getservbyname (servname, proto_str ? proto_str : "udp");
  76         if (proto_str == NULL)
  77             *protocol = IPPROTO_UDP;
  78     } else if (*socktype == 0) {
  79         if (proto_str != NULL) {
  80             se = getservbyname (servname, proto_str);
  81         } else {
  82             se = getservbyname (servname, "tcp");
  83             *protocol = IPPROTO_TCP;
  84             *socktype = SOCK_STREAM;
  85             if (se == NULL) {
  86                 se = getservbyname (servname, "udp");
  87                 *protocol = IPPROTO_UDP;
  88                 *socktype = SOCK_DGRAM;
  89             }
  90         }
  91     } else
  92         return EAI_SOCKTYPE;
  93 
  94     if (se == NULL) {
  95         char *endstr;
  96 
  97         *port = htons(strtol (servname, &endstr, 10));
  98         if (servname == endstr)
  99             return EAI_NONAME;
 100     } else {
 101         *port = se->s_port;
 102     }
 103     return 0;
 104 }
 105 
 106 static int
 107 add_one (int port, int protocol, int socktype,
     /* [<][>][^][v][top][bottom][index][help] */
 108          struct addrinfo ***ptr,
 109          int (*func)(struct addrinfo *, void *data, int port),
 110          void *data,
 111          char *canonname)
 112 {
 113     struct addrinfo *a;
 114     int ret;
 115 
 116     a = malloc (sizeof (*a));
 117     if (a == NULL)
 118         return EAI_MEMORY;
 119     memset (a, 0, sizeof(*a));
 120     a->ai_flags     = 0;
 121     a->ai_next      = NULL;
 122     a->ai_protocol  = protocol;
 123     a->ai_socktype  = socktype;
 124     a->ai_canonname = canonname;
 125     ret = (*func)(a, data, port);
 126     if (ret) {
 127         free (a);
 128         return ret;
 129     }
 130     **ptr = a;
 131     *ptr = &a->ai_next;
 132     return 0;
 133 }
 134 
 135 static int
 136 const_v4 (struct addrinfo *a, void *data, int port)
     /* [<][>][^][v][top][bottom][index][help] */
 137 {
 138     struct sockaddr_in *sin4;
 139     struct in_addr *addr = (struct in_addr *)data;
 140 
 141     a->ai_family  = PF_INET;
 142     a->ai_addrlen = sizeof(*sin4);
 143     a->ai_addr    = malloc (sizeof(*sin4));
 144     if (a->ai_addr == NULL)
 145         return EAI_MEMORY;
 146     sin4 = (struct sockaddr_in *)a->ai_addr;
 147     memset (sin4, 0, sizeof(*sin4));
 148     sin4->sin_family = AF_INET;
 149     sin4->sin_port   = port;
 150     sin4->sin_addr   = *addr;
 151     return 0;
 152 }
 153 
 154 #ifdef HAVE_IPV6
 155 static int
 156 const_v6 (struct addrinfo *a, void *data, int port)
     /* [<][>][^][v][top][bottom][index][help] */
 157 {
 158     struct sockaddr_in6 *sin6;
 159     struct in6_addr *addr = (struct in6_addr *)data;
 160 
 161     a->ai_family  = PF_INET6;
 162     a->ai_addrlen = sizeof(*sin6);
 163     a->ai_addr    = malloc (sizeof(*sin6));
 164     if (a->ai_addr == NULL)
 165         return EAI_MEMORY;
 166     sin6 = (struct sockaddr_in6 *)a->ai_addr;
 167     memset (sin6, 0, sizeof(*sin6));
 168     sin6->sin6_family = AF_INET6;
 169     sin6->sin6_port   = port;
 170     sin6->sin6_addr   = *addr;
 171     return 0;
 172 }
 173 #endif
 174 
 175 /* this is mostly a hack for some versions of AIX that has a prototype
 176    for in6addr_loopback but no actual symbol in libc */
 177 #if defined(HAVE_IPV6) && !defined(HAVE_IN6ADDR_LOOPBACK) && defined(IN6ADDR_LOOPBACK_INIT)
 178 #define in6addr_loopback _roken_in6addr_loopback
 179 struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
 180 #endif
 181 
 182 static int
 183 get_null (const struct addrinfo *hints,
     /* [<][>][^][v][top][bottom][index][help] */
 184           int port, int protocol, int socktype,
 185           struct addrinfo **res)
 186 {
 187     struct in_addr v4_addr;
 188 #ifdef HAVE_IPV6
 189     struct in6_addr v6_addr;
 190 #endif
 191     struct addrinfo *first = NULL;
 192     struct addrinfo **current = &first;
 193     int family = PF_UNSPEC;
 194     int ret;
 195 
 196     if (hints != NULL)
 197         family = hints->ai_family;
 198 
 199     if (hints && hints->ai_flags & AI_PASSIVE) {
 200         v4_addr.s_addr = INADDR_ANY;
 201 #ifdef HAVE_IPV6
 202         v6_addr        = in6addr_any;
 203 #endif
 204     } else {
 205         v4_addr.s_addr = htonl(INADDR_LOOPBACK);
 206 #ifdef HAVE_IPV6
 207         v6_addr        = in6addr_loopback;
 208 #endif
 209     }
 210 
 211 #ifdef HAVE_IPV6
 212     if (family == PF_INET6 || family == PF_UNSPEC) {
 213         ret = add_one (port, protocol, socktype,
 214                        &current, const_v6, &v6_addr, NULL);
 215     }
 216 #endif
 217     if (family == PF_INET || family == PF_UNSPEC) {
 218         ret = add_one (port, protocol, socktype,
 219                        &current, const_v4, &v4_addr, NULL);
 220     }
 221     *res = first;
 222     return 0;
 223 }
 224 
 225 static int
 226 add_hostent (int port, int protocol, int socktype,
     /* [<][>][^][v][top][bottom][index][help] */
 227              struct addrinfo ***current,
 228              int (*func)(struct addrinfo *, void *data, int port),
 229              struct hostent *he, int *flags)
 230 {
 231     int ret;
 232     char *canonname = NULL;
 233     char **h;
 234 
 235     if (*flags & AI_CANONNAME) {
 236         struct hostent *he2 = NULL;
 237         const char *tmp_canon;
 238 
 239         tmp_canon = hostent_find_fqdn (he);
 240         if (strchr (tmp_canon, '.') == NULL) {
 241             int error;
 242 
 243             he2 = getipnodebyaddr (he->h_addr_list[0], he->h_length,
 244                                    he->h_addrtype, &error);
 245             if (he2 != NULL) {
 246                 const char *tmp = hostent_find_fqdn (he2);
 247 
 248                 if (strchr (tmp, '.') != NULL)
 249                     tmp_canon = tmp;
 250             }
 251         }
 252 
 253         canonname = strdup (tmp_canon);
 254         if (he2 != NULL)
 255             freehostent (he2);
 256         if (canonname == NULL)
 257             return EAI_MEMORY;
 258     }
 259 
 260     for (h = he->h_addr_list; *h != NULL; ++h) {
 261         ret = add_one (port, protocol, socktype,
 262                        current, func, *h, canonname);
 263         if (ret)
 264             return ret;
 265         if (*flags & AI_CANONNAME) {
 266             *flags &= ~AI_CANONNAME;
 267             canonname = NULL;
 268         }
 269     }
 270     return 0;
 271 }
 272 
 273 static int
 274 get_number (const char *nodename,
     /* [<][>][^][v][top][bottom][index][help] */
 275             const struct addrinfo *hints,
 276             int port, int protocol, int socktype,
 277             struct addrinfo **res)
 278 {
 279     struct addrinfo *first = NULL;
 280     struct addrinfo **current = &first;
 281     int family = PF_UNSPEC;
 282     int ret;
 283 
 284     if (hints != NULL) {
 285         family = hints->ai_family;
 286     }
 287 
 288 #ifdef HAVE_IPV6
 289     if (family == PF_INET6 || family == PF_UNSPEC) {
 290         struct in6_addr v6_addr;
 291 
 292         if (inet_pton (PF_INET6, nodename, &v6_addr) == 1) {
 293             ret = add_one (port, protocol, socktype,
 294                            &current, const_v6, &v6_addr, NULL);
 295             *res = first;
 296             return ret;
 297         }
 298     }
 299 #endif
 300     if (family == PF_INET || family == PF_UNSPEC) {
 301         struct in_addr v4_addr;
 302 
 303         if (inet_pton (PF_INET, nodename, &v4_addr) == 1) {
 304             ret = add_one (port, protocol, socktype,
 305                            &current, const_v4, &v4_addr, NULL);
 306             *res = first;
 307             return ret;
 308         }
 309     }
 310     return EAI_NONAME;
 311 }
 312 
 313 static int
 314 get_nodes (const char *nodename,
     /* [<][>][^][v][top][bottom][index][help] */
 315            const struct addrinfo *hints,
 316            int port, int protocol, int socktype,
 317            struct addrinfo **res)
 318 {
 319     struct addrinfo *first = NULL;
 320     struct addrinfo **current = &first;
 321     int family = PF_UNSPEC;
 322     int flags  = 0;
 323     int ret = EAI_NONAME;
 324     int error;
 325 
 326     if (hints != NULL) {
 327         family = hints->ai_family;
 328         flags  = hints->ai_flags;
 329     }
 330 
 331 #ifdef HAVE_IPV6
 332     if (family == PF_INET6 || family == PF_UNSPEC) {
 333         struct hostent *he;
 334 
 335         he = getipnodebyname (nodename, PF_INET6, 0, &error);
 336 
 337         if (he != NULL) {
 338             ret = add_hostent (port, protocol, socktype,
 339                                &current, const_v6, he, &flags);
 340             freehostent (he);
 341         }
 342     }
 343 #endif
 344     if (family == PF_INET || family == PF_UNSPEC) {
 345         struct hostent *he;
 346 
 347         he = getipnodebyname (nodename, PF_INET, 0, &error);
 348 
 349         if (he != NULL) {
 350             ret = add_hostent (port, protocol, socktype,
 351                                &current, const_v4, he, &flags);
 352             freehostent (he);
 353         }
 354     }
 355     *res = first;
 356     return ret;
 357 }
 358 
 359 /*
 360  * hints:
 361  *
 362  * struct addrinfo {
 363  *     int    ai_flags;
 364  *     int    ai_family;
 365  *     int    ai_socktype;
 366  *     int    ai_protocol;
 367  * ...
 368  * };
 369  */
 370 
 371 int ROKEN_LIB_FUNCTION
 372 getaddrinfo(const char *nodename,
     /* [<][>][^][v][top][bottom][index][help] */
 373             const char *servname,
 374             const struct addrinfo *hints,
 375             struct addrinfo **res)
 376 {
 377     int ret;
 378     int port     = 0;
 379     int protocol = 0;
 380     int socktype = 0;
 381 
 382     *res = NULL;
 383 
 384     if (servname == NULL && nodename == NULL)
 385         return EAI_NONAME;
 386 
 387     if (hints != NULL
 388         && hints->ai_family != PF_UNSPEC
 389         && hints->ai_family != PF_INET
 390 #ifdef HAVE_IPV6
 391         && hints->ai_family != PF_INET6
 392 #endif
 393         )
 394         return EAI_FAMILY;
 395 
 396     if (servname != NULL) {
 397         ret = get_port_protocol_socktype (servname, hints,
 398                                           &port, &protocol, &socktype);
 399         if (ret)
 400             return ret;
 401     }
 402     if (nodename != NULL) {
 403         ret = get_number (nodename, hints, port, protocol, socktype, res);
 404         if (ret) {
 405             if(hints && hints->ai_flags & AI_NUMERICHOST)
 406                 ret = EAI_NONAME;
 407             else
 408                 ret = get_nodes (nodename, hints, port, protocol, socktype,
 409                                  res);
 410         }
 411     } else {
 412         ret = get_null (hints, port, protocol, socktype, res);
 413     }
 414     if (ret)
 415         freeaddrinfo (*res);
 416     return ret;
 417 }

/* [<][>][^][v][top][bottom][index][help] */