Blame gnulib/getaddrinfo.c

Packit Service 392537
/* Get address information (partial implementation).
Packit Service 392537
   Copyright (C) 1997, 2001-2002, 2004-2016 Free Software Foundation, Inc.
Packit Service 392537
   Contributed by Simon Josefsson <simon@josefsson.org>.
Packit Service 392537
Packit Service 392537
   This program is free software; you can redistribute it and/or modify
Packit Service 392537
   it under the terms of the GNU General Public License as published by
Packit Service 392537
   the Free Software Foundation; either version 3, or (at your option)
Packit Service 392537
   any later version.
Packit Service 392537
Packit Service 392537
   This program is distributed in the hope that it will be useful,
Packit Service 392537
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 392537
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 392537
   GNU General Public License for more details.
Packit Service 392537
Packit Service 392537
   You should have received a copy of the GNU General Public License
Packit Service 392537
   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
Packit Service 392537
Packit Service 392537
/* Don't use __attribute__ __nonnull__ in this compilation unit.  Otherwise gcc
Packit Service 392537
   optimizes away the sa == NULL test below.  */
Packit Service 392537
#define _GL_ARG_NONNULL(params)
Packit Service 392537
Packit Service 392537
#include <config.h>
Packit Service 392537
Packit Service 392537
#include <netdb.h>
Packit Service 392537
Packit Service 392537
#if HAVE_NETINET_IN_H
Packit Service 392537
# include <netinet/in.h>
Packit Service 392537
#endif
Packit Service 392537
Packit Service 392537
/* Get inet_ntop.  */
Packit Service 392537
#include <arpa/inet.h>
Packit Service 392537
Packit Service 392537
/* Get calloc. */
Packit Service 392537
#include <stdlib.h>
Packit Service 392537
Packit Service 392537
/* Get memcpy, strdup. */
Packit Service 392537
#include <string.h>
Packit Service 392537
Packit Service 392537
/* Get snprintf. */
Packit Service 392537
#include <stdio.h>
Packit Service 392537
Packit Service 392537
#include <stdbool.h>
Packit Service 392537
Packit Service 392537
#include "gettext.h"
Packit Service 392537
#define _(String) gettext (String)
Packit Service 392537
#define N_(String) String
Packit Service 392537
Packit Service 392537
/* BeOS has AF_INET, but not PF_INET.  */
Packit Service 392537
#ifndef PF_INET
Packit Service 392537
# define PF_INET AF_INET
Packit Service 392537
#endif
Packit Service 392537
/* BeOS also lacks PF_UNSPEC.  */
Packit Service 392537
#ifndef PF_UNSPEC
Packit Service 392537
# define PF_UNSPEC 0
Packit Service 392537
#endif
Packit Service 392537
Packit Service 392537
#if defined _WIN32 || defined __WIN32__
Packit Service 392537
# define WINDOWS_NATIVE
Packit Service 392537
#endif
Packit Service 392537
Packit Service 392537
/* gl_sockets_startup */
Packit Service 392537
#include "sockets.h"
Packit Service 392537
Packit Service 392537
#ifdef WINDOWS_NATIVE
Packit Service 392537
typedef int (WSAAPI *getaddrinfo_func) (const char*, const char*,
Packit Service 392537
                                        const struct addrinfo*,
Packit Service 392537
                                        struct addrinfo**);
Packit Service 392537
typedef void (WSAAPI *freeaddrinfo_func) (struct addrinfo*);
Packit Service 392537
typedef int (WSAAPI *getnameinfo_func) (const struct sockaddr*,
Packit Service 392537
                                        socklen_t, char*, DWORD,
Packit Service 392537
                                        char*, DWORD, int);
Packit Service 392537
Packit Service 392537
static getaddrinfo_func getaddrinfo_ptr = NULL;
Packit Service 392537
static freeaddrinfo_func freeaddrinfo_ptr = NULL;
Packit Service 392537
static getnameinfo_func getnameinfo_ptr = NULL;
Packit Service 392537
Packit Service 392537
static int
Packit Service 392537
use_win32_p (void)
Packit Service 392537
{
Packit Service 392537
  static int done = 0;
Packit Service 392537
  HMODULE h;
Packit Service 392537
Packit Service 392537
  if (done)
Packit Service 392537
    return getaddrinfo_ptr ? 1 : 0;
Packit Service 392537
Packit Service 392537
  done = 1;
Packit Service 392537
Packit Service 392537
  h = GetModuleHandle ("ws2_32.dll");
Packit Service 392537
Packit Service 392537
  if (h)
Packit Service 392537
    {
Packit Service 392537
      getaddrinfo_ptr = (getaddrinfo_func) GetProcAddress (h, "getaddrinfo");
Packit Service 392537
      freeaddrinfo_ptr = (freeaddrinfo_func) GetProcAddress (h, "freeaddrinfo");
Packit Service 392537
      getnameinfo_ptr = (getnameinfo_func) GetProcAddress (h, "getnameinfo");
Packit Service 392537
    }
Packit Service 392537
Packit Service 392537
  /* If either is missing, something is odd. */
Packit Service 392537
  if (!getaddrinfo_ptr || !freeaddrinfo_ptr || !getnameinfo_ptr)
Packit Service 392537
    {
Packit Service 392537
      getaddrinfo_ptr = NULL;
Packit Service 392537
      freeaddrinfo_ptr = NULL;
Packit Service 392537
      getnameinfo_ptr = NULL;
Packit Service 392537
      return 0;
Packit Service 392537
    }
Packit Service 392537
Packit Service 392537
  gl_sockets_startup (SOCKETS_1_1);
Packit Service 392537
Packit Service 392537
  return 1;
Packit Service 392537
}
Packit Service 392537
#endif
Packit Service 392537
Packit Service 392537
static bool
Packit Service 392537
validate_family (int family)
Packit Service 392537
{
Packit Service 392537
  /* FIXME: Support more families. */
Packit Service 392537
#if HAVE_IPV4
Packit Service 392537
     if (family == PF_INET)
Packit Service 392537
       return true;
Packit Service 392537
#endif
Packit Service 392537
#if HAVE_IPV6
Packit Service 392537
     if (family == PF_INET6)
Packit Service 392537
       return true;
Packit Service 392537
#endif
Packit Service 392537
     if (family == PF_UNSPEC)
Packit Service 392537
       return true;
Packit Service 392537
     return false;
Packit Service 392537
}
Packit Service 392537
Packit Service 392537
/* Translate name of a service location and/or a service name to set of
Packit Service 392537
   socket addresses. */
Packit Service 392537
int
Packit Service 392537
getaddrinfo (const char *restrict nodename,
Packit Service 392537
             const char *restrict servname,
Packit Service 392537
             const struct addrinfo *restrict hints,
Packit Service 392537
             struct addrinfo **restrict res)
Packit Service 392537
{
Packit Service 392537
  struct addrinfo *tmp;
Packit Service 392537
  int port = 0;
Packit Service 392537
  struct hostent *he;
Packit Service 392537
  void *storage;
Packit Service 392537
  size_t size;
Packit Service 392537
#if HAVE_IPV6
Packit Service 392537
  struct v6_pair {
Packit Service 392537
    struct addrinfo addrinfo;
Packit Service 392537
    struct sockaddr_in6 sockaddr_in6;
Packit Service 392537
  };
Packit Service 392537
#endif
Packit Service 392537
#if HAVE_IPV4
Packit Service 392537
  struct v4_pair {
Packit Service 392537
    struct addrinfo addrinfo;
Packit Service 392537
    struct sockaddr_in sockaddr_in;
Packit Service 392537
  };
Packit Service 392537
#endif
Packit Service 392537
Packit Service 392537
#ifdef WINDOWS_NATIVE
Packit Service 392537
  if (use_win32_p ())
Packit Service 392537
    return getaddrinfo_ptr (nodename, servname, hints, res);
Packit Service 392537
#endif
Packit Service 392537
Packit Service 392537
  if (hints && (hints->ai_flags & ~(AI_CANONNAME|AI_PASSIVE)))
Packit Service 392537
    /* FIXME: Support more flags. */
Packit Service 392537
    return EAI_BADFLAGS;
Packit Service 392537
Packit Service 392537
  if (hints && !validate_family (hints->ai_family))
Packit Service 392537
    return EAI_FAMILY;
Packit Service 392537
Packit Service 392537
  if (hints &&
Packit Service 392537
      hints->ai_socktype != SOCK_STREAM && hints->ai_socktype != SOCK_DGRAM)
Packit Service 392537
    /* FIXME: Support other socktype. */
Packit Service 392537
    return EAI_SOCKTYPE; /* FIXME: Better return code? */
Packit Service 392537
Packit Service 392537
  if (!nodename)
Packit Service 392537
    {
Packit Service 392537
      if (!(hints->ai_flags & AI_PASSIVE))
Packit Service 392537
        return EAI_NONAME;
Packit Service 392537
Packit Service 392537
#ifdef HAVE_IPV6
Packit Service 392537
      nodename = (hints->ai_family == AF_INET6) ? "::" : "0.0.0.0";
Packit Service 392537
#else
Packit Service 392537
      nodename = "0.0.0.0";
Packit Service 392537
#endif
Packit Service 392537
    }
Packit Service 392537
Packit Service 392537
  if (servname)
Packit Service 392537
    {
Packit Service 392537
      struct servent *se = NULL;
Packit Service 392537
      const char *proto =
Packit Service 392537
        (hints && hints->ai_socktype == SOCK_DGRAM) ? "udp" : "tcp";
Packit Service 392537
Packit Service 392537
      if (hints == NULL || !(hints->ai_flags & AI_NUMERICSERV))
Packit Service 392537
        /* FIXME: Use getservbyname_r if available. */
Packit Service 392537
        se = getservbyname (servname, proto);
Packit Service 392537
Packit Service 392537
      if (!se)
Packit Service 392537
        {
Packit Service 392537
          char *c;
Packit Service 392537
          if (!(*servname >= '0' && *servname <= '9'))
Packit Service 392537
            return EAI_NONAME;
Packit Service 392537
          port = strtoul (servname, &c, 10);
Packit Service 392537
          if (*c || port > 0xffff)
Packit Service 392537
            return EAI_NONAME;
Packit Service 392537
          port = htons (port);
Packit Service 392537
        }
Packit Service 392537
      else
Packit Service 392537
        port = se->s_port;
Packit Service 392537
    }
Packit Service 392537
Packit Service 392537
  /* FIXME: Use gethostbyname_r if available. */
Packit Service 392537
  he = gethostbyname (nodename);
Packit Service 392537
  if (!he || he->h_addr_list[0] == NULL)
Packit Service 392537
    return EAI_NONAME;
Packit Service 392537
Packit Service 392537
  switch (he->h_addrtype)
Packit Service 392537
    {
Packit Service 392537
#if HAVE_IPV6
Packit Service 392537
    case PF_INET6:
Packit Service 392537
      size = sizeof (struct v6_pair);
Packit Service 392537
      break;
Packit Service 392537
#endif
Packit Service 392537
Packit Service 392537
#if HAVE_IPV4
Packit Service 392537
    case PF_INET:
Packit Service 392537
      size = sizeof (struct v4_pair);
Packit Service 392537
      break;
Packit Service 392537
#endif
Packit Service 392537
Packit Service 392537
    default:
Packit Service 392537
      return EAI_NODATA;
Packit Service 392537
    }
Packit Service 392537
Packit Service 392537
  storage = calloc (1, size);
Packit Service 392537
  if (!storage)
Packit Service 392537
    return EAI_MEMORY;
Packit Service 392537
Packit Service 392537
  switch (he->h_addrtype)
Packit Service 392537
    {
Packit Service 392537
#if HAVE_IPV6
Packit Service 392537
    case PF_INET6:
Packit Service 392537
      {
Packit Service 392537
        struct v6_pair *p = storage;
Packit Service 392537
        struct sockaddr_in6 *sinp = &p->sockaddr_in6;
Packit Service 392537
        tmp = &p->addrinfo;
Packit Service 392537
Packit Service 392537
        if (port)
Packit Service 392537
          sinp->sin6_port = port;
Packit Service 392537
Packit Service 392537
        if (he->h_length != sizeof (sinp->sin6_addr))
Packit Service 392537
          {
Packit Service 392537
            free (storage);
Packit Service 392537
            return EAI_SYSTEM; /* FIXME: Better return code?  Set errno? */
Packit Service 392537
          }
Packit Service 392537
Packit Service 392537
        memcpy (&sinp->sin6_addr, he->h_addr_list[0], sizeof sinp->sin6_addr);
Packit Service 392537
Packit Service 392537
        tmp->ai_addr = (struct sockaddr *) sinp;
Packit Service 392537
        tmp->ai_addrlen = sizeof *sinp;
Packit Service 392537
      }
Packit Service 392537
      break;
Packit Service 392537
#endif
Packit Service 392537
Packit Service 392537
#if HAVE_IPV4
Packit Service 392537
    case PF_INET:
Packit Service 392537
      {
Packit Service 392537
        struct v4_pair *p = storage;
Packit Service 392537
        struct sockaddr_in *sinp = &p->sockaddr_in;
Packit Service 392537
        tmp = &p->addrinfo;
Packit Service 392537
Packit Service 392537
        if (port)
Packit Service 392537
          sinp->sin_port = port;
Packit Service 392537
Packit Service 392537
        if (he->h_length != sizeof (sinp->sin_addr))
Packit Service 392537
          {
Packit Service 392537
            free (storage);
Packit Service 392537
            return EAI_SYSTEM; /* FIXME: Better return code?  Set errno? */
Packit Service 392537
          }
Packit Service 392537
Packit Service 392537
        memcpy (&sinp->sin_addr, he->h_addr_list[0], sizeof sinp->sin_addr);
Packit Service 392537
Packit Service 392537
        tmp->ai_addr = (struct sockaddr *) sinp;
Packit Service 392537
        tmp->ai_addrlen = sizeof *sinp;
Packit Service 392537
      }
Packit Service 392537
      break;
Packit Service 392537
#endif
Packit Service 392537
Packit Service 392537
    default:
Packit Service 392537
      free (storage);
Packit Service 392537
      return EAI_NODATA;
Packit Service 392537
    }
Packit Service 392537
Packit Service 392537
  if (hints && hints->ai_flags & AI_CANONNAME)
Packit Service 392537
    {
Packit Service 392537
      const char *cn;
Packit Service 392537
      if (he->h_name)
Packit Service 392537
        cn = he->h_name;
Packit Service 392537
      else
Packit Service 392537
        cn = nodename;
Packit Service 392537
Packit Service 392537
      tmp->ai_canonname = strdup (cn);
Packit Service 392537
      if (!tmp->ai_canonname)
Packit Service 392537
        {
Packit Service 392537
          free (storage);
Packit Service 392537
          return EAI_MEMORY;
Packit Service 392537
        }
Packit Service 392537
    }
Packit Service 392537
Packit Service 392537
  tmp->ai_protocol = (hints) ? hints->ai_protocol : 0;
Packit Service 392537
  tmp->ai_socktype = (hints) ? hints->ai_socktype : 0;
Packit Service 392537
  tmp->ai_addr->sa_family = he->h_addrtype;
Packit Service 392537
  tmp->ai_family = he->h_addrtype;
Packit Service 392537
Packit Service 392537
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
Packit Service 392537
  switch (he->h_addrtype)
Packit Service 392537
    {
Packit Service 392537
#if HAVE_IPV4
Packit Service 392537
    case AF_INET:
Packit Service 392537
      tmp->ai_addr->sa_len = sizeof (struct sockaddr_in);
Packit Service 392537
      break;
Packit Service 392537
#endif
Packit Service 392537
#if HAVE_IPV6
Packit Service 392537
    case AF_INET6:
Packit Service 392537
      tmp->ai_addr->sa_len = sizeof (struct sockaddr_in6);
Packit Service 392537
      break;
Packit Service 392537
#endif
Packit Service 392537
    }
Packit Service 392537
#endif
Packit Service 392537
Packit Service 392537
  /* FIXME: If more than one address, create linked list of addrinfo's. */
Packit Service 392537
Packit Service 392537
  *res = tmp;
Packit Service 392537
Packit Service 392537
  return 0;
Packit Service 392537
}
Packit Service 392537
Packit Service 392537
/* Free 'addrinfo' structure AI including associated storage.  */
Packit Service 392537
void
Packit Service 392537
freeaddrinfo (struct addrinfo *ai)
Packit Service 392537
{
Packit Service 392537
#ifdef WINDOWS_NATIVE
Packit Service 392537
  if (use_win32_p ())
Packit Service 392537
    {
Packit Service 392537
      freeaddrinfo_ptr (ai);
Packit Service 392537
      return;
Packit Service 392537
    }
Packit Service 392537
#endif
Packit Service 392537
Packit Service 392537
  while (ai)
Packit Service 392537
    {
Packit Service 392537
      struct addrinfo *cur;
Packit Service 392537
Packit Service 392537
      cur = ai;
Packit Service 392537
      ai = ai->ai_next;
Packit Service 392537
Packit Service 392537
      free (cur->ai_canonname);
Packit Service 392537
      free (cur);
Packit Service 392537
    }
Packit Service 392537
}
Packit Service 392537
Packit Service 392537
int
Packit Service 392537
getnameinfo (const struct sockaddr *restrict sa, socklen_t salen,
Packit Service 392537
             char *restrict node, socklen_t nodelen,
Packit Service 392537
             char *restrict service, socklen_t servicelen,
Packit Service 392537
             int flags)
Packit Service 392537
{
Packit Service 392537
#ifdef WINDOWS_NATIVE
Packit Service 392537
  if (use_win32_p ())
Packit Service 392537
    return getnameinfo_ptr (sa, salen, node, nodelen,
Packit Service 392537
                            service, servicelen, flags);
Packit Service 392537
#endif
Packit Service 392537
Packit Service 392537
  /* FIXME: Support other flags. */
Packit Service 392537
  if ((node && nodelen > 0 && !(flags & NI_NUMERICHOST)) ||
Packit Service 392537
      (service && servicelen > 0 && !(flags & NI_NUMERICHOST)) ||
Packit Service 392537
      (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV)))
Packit Service 392537
    return EAI_BADFLAGS;
Packit Service 392537
Packit Service 392537
  if (sa == NULL || salen < sizeof (sa->sa_family))
Packit Service 392537
    return EAI_FAMILY;
Packit Service 392537
Packit Service 392537
  switch (sa->sa_family)
Packit Service 392537
    {
Packit Service 392537
#if HAVE_IPV4
Packit Service 392537
    case AF_INET:
Packit Service 392537
      if (salen < sizeof (struct sockaddr_in))
Packit Service 392537
        return EAI_FAMILY;
Packit Service 392537
      break;
Packit Service 392537
#endif
Packit Service 392537
#if HAVE_IPV6
Packit Service 392537
    case AF_INET6:
Packit Service 392537
      if (salen < sizeof (struct sockaddr_in6))
Packit Service 392537
        return EAI_FAMILY;
Packit Service 392537
      break;
Packit Service 392537
#endif
Packit Service 392537
    default:
Packit Service 392537
      return EAI_FAMILY;
Packit Service 392537
    }
Packit Service 392537
Packit Service 392537
  if (node && nodelen > 0 && flags & NI_NUMERICHOST)
Packit Service 392537
    {
Packit Service 392537
      switch (sa->sa_family)
Packit Service 392537
        {
Packit Service 392537
#if HAVE_IPV4
Packit Service 392537
        case AF_INET:
Packit Service 392537
          if (!inet_ntop (AF_INET,
Packit Service 392537
                          &(((const struct sockaddr_in *) sa)->sin_addr),
Packit Service 392537
                          node, nodelen))
Packit Service 392537
            return EAI_SYSTEM;
Packit Service 392537
          break;
Packit Service 392537
#endif
Packit Service 392537
Packit Service 392537
#if HAVE_IPV6
Packit Service 392537
        case AF_INET6:
Packit Service 392537
          if (!inet_ntop (AF_INET6,
Packit Service 392537
                          &(((const struct sockaddr_in6 *) sa)->sin6_addr),
Packit Service 392537
                          node, nodelen))
Packit Service 392537
            return EAI_SYSTEM;
Packit Service 392537
          break;
Packit Service 392537
#endif
Packit Service 392537
Packit Service 392537
        default:
Packit Service 392537
          return EAI_FAMILY;
Packit Service 392537
        }
Packit Service 392537
    }
Packit Service 392537
Packit Service 392537
  if (service && servicelen > 0 && flags & NI_NUMERICSERV)
Packit Service 392537
    switch (sa->sa_family)
Packit Service 392537
      {
Packit Service 392537
#if HAVE_IPV4
Packit Service 392537
      case AF_INET:
Packit Service 392537
#endif
Packit Service 392537
#if HAVE_IPV6
Packit Service 392537
      case AF_INET6:
Packit Service 392537
#endif
Packit Service 392537
        {
Packit Service 392537
          unsigned short int port
Packit Service 392537
            = ntohs (((const struct sockaddr_in *) sa)->sin_port);
Packit Service 392537
          if (servicelen <= snprintf (service, servicelen, "%u", port))
Packit Service 392537
            return EAI_OVERFLOW;
Packit Service 392537
        }
Packit Service 392537
        break;
Packit Service 392537
      }
Packit Service 392537
Packit Service 392537
  return 0;
Packit Service 392537
}