ext/socket/getnameinfo.c


DEFINITIONS

This source file includes following functions.
  1. inet_ntop
  2. getnameinfo


   1  /*
   2   * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
   3   * All rights reserved.
   4   * 
   5   * Redistribution and use in source and binary forms, with or without
   6   * modification, are permitted provided that the following conditions
   7   * are met:
   8   * 1. Redistributions of source code must retain the above copyright
   9   *    notice, this list of conditions and the following disclaimer.
  10   * 2. Redistributions in binary form must reproduce the above copyright
  11   *    notice, this list of conditions and the following disclaimer in the
  12   *    documentation and/or other materials provided with the distribution.
  13   * 3. Neither the name of the project nor the names of its contributors
  14   *    may be used to endorse or promote products derived from this software
  15   *    without specific prior written permission.
  16   * 
  17   * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
  18   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20   * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
  21   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27   * SUCH DAMAGE.
  28   */
  29  
  30  /*
  31   * Issues to be discussed:
  32   * - Thread safe-ness must be checked
  33   * - Return values.  There seems to be no standard for return value (RFC2133)
  34   *   but INRIA implementation returns EAI_xxx defined for getaddrinfo().
  35   */
  36  
  37  #include "config.h"
  38  #include <sys/types.h>
  39  #ifndef NT
  40  #if defined(__BEOS__)
  41  # include <net/socket.h>
  42  #else
  43  # include <sys/socket.h>
  44  #endif
  45  #include <netinet/in.h>
  46  #if defined(HAVE_ARPA_INET_H)
  47  #include <arpa/inet.h>
  48  #endif
  49  #if defined(HAVE_ARPA_NAMESER_H)
  50  #include <arpa/nameser.h>
  51  #endif
  52  #include <netdb.h>
  53  #if defined(HAVE_RESOLV_H)
  54  #include <resolv.h>
  55  #endif
  56  #endif
  57  #ifdef NT
  58  #include <winsock2.h>
  59  #include <stdio.h>
  60  #define snprintf _snprintf
  61  #endif
  62  
  63  #include <string.h>
  64  #include <stddef.h>
  65  
  66  #ifdef SOCKS5
  67  #include <socks.h>
  68  #endif
  69  
  70  #include "addrinfo.h"
  71  #include "sockport.h"
  72  
  73  #define SUCCESS 0
  74  #define ANY 0
  75  #define YES 1
  76  #define NO  0
  77  
  78  struct sockinet {
  79          u_char  si_len;
  80          u_char  si_family;
  81          u_short si_port;
  82  };
  83  
  84  static struct afd {
  85          int a_af;
  86          int a_addrlen;
  87          int a_socklen;
  88          int a_off;
  89  } afdl [] = {
  90  #ifdef INET6
  91  #define N_INET6 0
  92          {PF_INET6, sizeof(struct in6_addr),
  93           sizeof(struct sockaddr_in6),
  94           offsetof(struct sockaddr_in6, sin6_addr)},
  95  #define N_INET  1
  96  #else
  97  #define N_INET  0
  98  #endif
  99          {PF_INET, sizeof(struct in_addr),
 100           sizeof(struct sockaddr_in),
 101           offsetof(struct sockaddr_in, sin_addr)},
 102          {0, 0, 0, 0},
 103  };
 104  
 105  #define ENI_NOSOCKET    0
 106  #define ENI_NOSERVNAME  1
 107  #define ENI_NOHOSTNAME  2
 108  #define ENI_MEMORY      3
 109  #define ENI_SYSTEM      4
 110  #define ENI_FAMILY      5
 111  #define ENI_SALEN       6
 112  
 113  #ifndef HAVE_INET_NTOP
 114  static const char *
 115  inet_ntop(af, addr, numaddr, numaddr_len)
 116          int af;
 117          const void *addr;
 118          char *numaddr;
 119          size_t numaddr_len;
 120  {
 121  #ifdef HAVE_INET_NTOA
 122          struct in_addr in;
 123          memcpy(&in.s_addr, addr, sizeof(in.s_addr));
 124          snprintf(numaddr, numaddr_len, "%s", inet_ntoa(in));
 125  #else
 126          unsigned long x = ntohl(*(unsigned long*)addr);
 127          snprintf(numaddr, numaddr_len, "%d.%d.%d.%d",
 128                   (int) (x>>24) & 0xff, (int) (x>>16) & 0xff,
 129                   (int) (x>> 8) & 0xff, (int) (x>> 0) & 0xff);
 130  #endif
 131          return numaddr;
 132  }
 133  #endif
 134  
 135  int
 136  getnameinfo(sa, salen, host, hostlen, serv, servlen, flags)
 137          const struct sockaddr *sa;
 138          size_t salen;
 139          char *host;
 140          size_t hostlen;
 141          char *serv;
 142          size_t servlen;
 143          int flags;
 144  {
 145          struct afd *afd;
 146          struct servent *sp;
 147          struct hostent *hp;
 148          u_short port;
 149          int family, len, i;
 150          char *addr, *p;
 151          u_long v4a;
 152  #ifdef INET6
 153          u_char pfx;
 154  #endif
 155          int h_error;
 156          char numserv[512];
 157          char numaddr[512];
 158  
 159          if (sa == NULL)
 160                  return ENI_NOSOCKET;
 161  
 162          len = SA_LEN(sa);
 163          if (len != salen) return ENI_SALEN;
 164          
 165          family = sa->sa_family;
 166          for (i = 0; afdl[i].a_af; i++)
 167                  if (afdl[i].a_af == family) {
 168                          afd = &afdl[i];
 169                          goto found;
 170                  }
 171          return ENI_FAMILY;
 172          
 173   found:
 174          if (len != afd->a_socklen) return ENI_SALEN;
 175          
 176          port = ((struct sockinet *)sa)->si_port; /* network byte order */
 177          addr = (char *)sa + afd->a_off;
 178  
 179          if (serv == NULL || servlen == 0) {
 180                  /* what we should do? */
 181          } else if (flags & NI_NUMERICSERV) {
 182                  snprintf(numserv, sizeof(numserv), "%d", ntohs(port));
 183                  if (strlen(numserv) + 1 > servlen)
 184                          return ENI_MEMORY;
 185                  strcpy(serv, numserv);
 186          } else {
 187  #if defined(HAVE_GETSERVBYPORT)
 188                  sp = getservbyport(port, (flags & NI_DGRAM) ? "udp" : "tcp");
 189                  if (sp) {
 190                          if (strlen(sp->s_name) + 1 > servlen)
 191                                  return ENI_MEMORY;
 192                          strcpy(serv, sp->s_name);
 193                  } else
 194                          return ENI_NOSERVNAME;
 195  #else
 196                  return ENI_NOSERVNAME;
 197  #endif
 198          }
 199  
 200          switch (sa->sa_family) {
 201          case AF_INET:
 202                  v4a = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
 203                  if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
 204                          flags |= NI_NUMERICHOST;
 205                  v4a >>= IN_CLASSA_NSHIFT;
 206                  if (v4a == 0)
 207                          flags |= NI_NUMERICHOST;                        
 208                  break;
 209  #ifdef INET6
 210          case AF_INET6:
 211                  pfx = ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr8[0];
 212                  if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
 213                          flags |= NI_NUMERICHOST;
 214                  break;
 215  #endif
 216          }
 217          if (host == NULL || hostlen == 0) {
 218                  /* what should we do? */
 219          } else if (flags & NI_NUMERICHOST) {
 220                  if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
 221                      == NULL)
 222                          return ENI_SYSTEM;
 223                  if (strlen(numaddr) > hostlen)
 224                          return ENI_MEMORY;
 225                  strcpy(host, numaddr);
 226          } else {
 227  #ifdef INET6
 228                  hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
 229  #else
 230                  hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
 231                  h_error = h_errno;
 232  #endif
 233  
 234                  if (hp) {
 235                          if (flags & NI_NOFQDN) {
 236                                  p = strchr(hp->h_name, '.');
 237                                  if (p) *p = '\0';
 238                          }
 239                          if (strlen(hp->h_name) + 1 > hostlen) {
 240  #ifdef INET6
 241                                  freehostent(hp);
 242  #endif
 243                                  return ENI_MEMORY;
 244                          }
 245                          strcpy(host, hp->h_name);
 246  #ifdef INET6
 247                          freehostent(hp);
 248  #endif
 249                  } else {
 250                          if (flags & NI_NAMEREQD)
 251                                  return ENI_NOHOSTNAME;
 252                          if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
 253                              == NULL)
 254                                  return ENI_NOHOSTNAME;
 255                          if (strlen(numaddr) > hostlen)
 256                                  return ENI_MEMORY;
 257                          strcpy(host, numaddr);
 258                  }
 259          }
 260          return SUCCESS;
 261  }