(root)/
Python-3.12.0/
Modules/
getaddrinfo.c
       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   * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator.
      32   *
      33   * Issues to be discussed:
      34   * - Thread safe-ness must be checked.
      35   * - Return values.  There are nonstandard return values defined and used
      36   *   in the source code.  This is because RFC2133 is silent about which error
      37   *   code must be returned for which situation.
      38   * - PF_UNSPEC case would be handled in getipnodebyname() with the AI_ALL flag.
      39   */
      40  
      41  #if 0
      42  #include <sys/types.h>
      43  #include <sys/param.h>
      44  #include <sys/sysctl.h>
      45  #include <sys/socket.h>
      46  #include <netinet/in.h>
      47  #include <arpa/inet.h>
      48  #include <arpa/nameser.h>
      49  #include <netdb.h>
      50  #include <resolv.h>
      51  #include <string.h>
      52  #include <stdlib.h>
      53  #include <stddef.h>
      54  #include <ctype.h>
      55  #include <unistd.h>
      56  
      57  #include "addrinfo.h"
      58  #endif
      59  
      60  #if defined(__KAME__) && defined(ENABLE_IPV6)
      61  # define FAITH
      62  #endif
      63  
      64  #ifdef HAVE_NETDB_H
      65  #define HAVE_GETADDRINFO 1
      66  
      67  #define SUCCESS 0
      68  #define GAI_ANY 0
      69  #define YES 1
      70  #define NO  0
      71  
      72  #ifdef FAITH
      73  static int translate = NO;
      74  static struct in6_addr faith_prefix = IN6ADDR_GAI_ANY_INIT;
      75  #endif
      76  
      77  static const char in_addrany[] = { 0, 0, 0, 0 };
      78  static const char in6_addrany[] = {
      79      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
      80  };
      81  static const char in_loopback[] = { 127, 0, 0, 1 };
      82  static const char in6_loopback[] = {
      83      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
      84  };
      85  
      86  struct sockinet {
      87      u_char      si_len;
      88      u_char      si_family;
      89      u_short     si_port;
      90  };
      91  
      92  static struct gai_afd {
      93      int a_af;
      94      int a_addrlen;
      95      int a_socklen;
      96      int a_off;
      97      const char *a_addrany;
      98      const char *a_loopback;
      99  } gai_afdl [] = {
     100  #ifdef ENABLE_IPV6
     101  #define N_INET6 0
     102      {PF_INET6, sizeof(struct in6_addr),
     103       sizeof(struct sockaddr_in6),
     104       offsetof(struct sockaddr_in6, sin6_addr),
     105       in6_addrany, in6_loopback},
     106  #define N_INET  1
     107  #else
     108  #define N_INET  0
     109  #endif
     110      {PF_INET, sizeof(struct in_addr),
     111       sizeof(struct sockaddr_in),
     112       offsetof(struct sockaddr_in, sin_addr),
     113       in_addrany, in_loopback},
     114      {0, 0, 0, 0, NULL, NULL},
     115  };
     116  
     117  #ifdef ENABLE_IPV6
     118  #define PTON_MAX        16
     119  #else
     120  #define PTON_MAX        4
     121  #endif
     122  
     123  #ifndef IN_MULTICAST
     124  #define IN_MULTICAST(i)     (((i) & 0xf0000000U) == 0xe0000000U)
     125  #endif
     126  
     127  #ifndef IN_EXPERIMENTAL
     128  #define IN_EXPERIMENTAL(i)  (((i) & 0xe0000000U) == 0xe0000000U)
     129  #endif
     130  
     131  #ifndef IN_LOOPBACKNET
     132  #define IN_LOOPBACKNET      127
     133  #endif
     134  
     135  static int get_name(const char *, struct gai_afd *,
     136                            struct addrinfo **, char *, struct addrinfo *,
     137                            int);
     138  static int get_addr(const char *, int, struct addrinfo **,
     139                          struct addrinfo *, int);
     140  static int str_isnumber(const char *);
     141  
     142  static const char * const ai_errlist[] = {
     143      "success.",
     144      "address family for hostname not supported.",       /* EAI_ADDRFAMILY */
     145      "temporary failure in name resolution.",            /* EAI_AGAIN      */
     146      "invalid value for ai_flags.",                      /* EAI_BADFLAGS   */
     147      "non-recoverable failure in name resolution.",      /* EAI_FAIL       */
     148      "ai_family not supported.",                         /* EAI_FAMILY     */
     149      "memory allocation failure.",                       /* EAI_MEMORY     */
     150      "no address associated with hostname.",             /* EAI_NODATA     */
     151      "hostname nor servname provided, or not known.",/* EAI_NONAME     */
     152      "servname not supported for ai_socktype.",          /* EAI_SERVICE    */
     153      "ai_socktype not supported.",                       /* EAI_SOCKTYPE   */
     154      "system error returned in errno.",                  /* EAI_SYSTEM     */
     155      "invalid value for hints.",                         /* EAI_BADHINTS   */
     156      "resolved protocol is unknown.",                    /* EAI_PROTOCOL   */
     157      "unknown error.",                                   /* EAI_MAX        */
     158  };
     159  
     160  #define GET_CANONNAME(ai, str) \
     161  if (pai->ai_flags & AI_CANONNAME) {\
     162      if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\
     163          strcpy((ai)->ai_canonname, (str));\
     164      } else {\
     165          error = EAI_MEMORY;\
     166          goto free;\
     167      }\
     168  }
     169  
     170  #ifdef HAVE_SOCKADDR_SA_LEN
     171  #define GET_AI(ai, gai_afd, addr, port) {\
     172      char *p;\
     173      if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\
     174                                            ((gai_afd)->a_socklen)))\
     175          == NULL) goto free;\
     176      memcpy(ai, pai, sizeof(struct addrinfo));\
     177      (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\
     178      memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\
     179      (ai)->ai_addr->sa_len = (ai)->ai_addrlen = (gai_afd)->a_socklen;\
     180      (ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\
     181      ((struct sockinet *)(ai)->ai_addr)->si_port = port;\
     182      p = (char *)((ai)->ai_addr);\
     183      memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\
     184  }
     185  #else
     186  #define GET_AI(ai, gai_afd, addr, port) {\
     187      char *p;\
     188      if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\
     189                                            ((gai_afd)->a_socklen)))\
     190          == NULL) goto free;\
     191      memcpy(ai, pai, sizeof(struct addrinfo));\
     192      (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\
     193      memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\
     194      (ai)->ai_addrlen = (gai_afd)->a_socklen;\
     195      (ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\
     196      ((struct sockinet *)(ai)->ai_addr)->si_port = port;\
     197      p = (char *)((ai)->ai_addr);\
     198      memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\
     199  }
     200  #endif
     201  
     202  #define ERR(err) { error = (err); goto bad; }
     203  
     204  const char *
     205  gai_strerror(int ecode)
     206  {
     207      if (ecode < 0 || ecode > EAI_MAX)
     208          ecode = EAI_MAX;
     209      return ai_errlist[ecode];
     210  }
     211  
     212  void
     213  freeaddrinfo(struct addrinfo *ai)
     214  {
     215      struct addrinfo *next;
     216  
     217      do {
     218          next = ai->ai_next;
     219          if (ai->ai_canonname)
     220              free(ai->ai_canonname);
     221          /* no need to free(ai->ai_addr) */
     222          free(ai);
     223      } while ((ai = next) != NULL);
     224  }
     225  
     226  static int
     227  str_isnumber(const char *p)
     228  {
     229      unsigned char *q = (unsigned char *)p;
     230      while (*q) {
     231          if (! isdigit(*q))
     232              return NO;
     233          q++;
     234      }
     235      return YES;
     236  }
     237  
     238  int
     239  getaddrinfo(const char*hostname, const char*servname,
     240              const struct addrinfo *hints, struct addrinfo **res)
     241  {
     242      struct addrinfo sentinel;
     243      struct addrinfo *top = NULL;
     244      struct addrinfo *cur;
     245      int i, error = 0;
     246      char pton[PTON_MAX];
     247      struct addrinfo ai;
     248      struct addrinfo *pai;
     249      u_short port;
     250  
     251  #ifdef FAITH
     252      static int firsttime = 1;
     253  
     254      if (firsttime) {
     255          /* translator hack */
     256          {
     257              const char *q = getenv("GAI");
     258              if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1)
     259                  translate = YES;
     260          }
     261          firsttime = 0;
     262      }
     263  #endif
     264  
     265      /* initialize file static vars */
     266      sentinel.ai_next = NULL;
     267      cur = &sentinel;
     268      pai = &ai;
     269      pai->ai_flags = 0;
     270      pai->ai_family = PF_UNSPEC;
     271      pai->ai_socktype = GAI_ANY;
     272      pai->ai_protocol = GAI_ANY;
     273      pai->ai_addrlen = 0;
     274      pai->ai_canonname = NULL;
     275      pai->ai_addr = NULL;
     276      pai->ai_next = NULL;
     277      port = GAI_ANY;
     278  
     279      if (hostname == NULL && servname == NULL)
     280          return EAI_NONAME;
     281      if (hints) {
     282          /* error check for hints */
     283          if (hints->ai_addrlen || hints->ai_canonname ||
     284              hints->ai_addr || hints->ai_next)
     285              ERR(EAI_BADHINTS); /* xxx */
     286          if (hints->ai_flags & ~AI_MASK)
     287              ERR(EAI_BADFLAGS);
     288          switch (hints->ai_family) {
     289          case PF_UNSPEC:
     290          case PF_INET:
     291  #ifdef ENABLE_IPV6
     292          case PF_INET6:
     293  #endif
     294              break;
     295          default:
     296              ERR(EAI_FAMILY);
     297          }
     298          memcpy(pai, hints, sizeof(*pai));
     299          switch (pai->ai_socktype) {
     300          case GAI_ANY:
     301              switch (pai->ai_protocol) {
     302              case GAI_ANY:
     303                  break;
     304              case IPPROTO_UDP:
     305                  pai->ai_socktype = SOCK_DGRAM;
     306                  break;
     307              case IPPROTO_TCP:
     308                  pai->ai_socktype = SOCK_STREAM;
     309                  break;
     310              default:
     311                  pai->ai_socktype = SOCK_RAW;
     312                  break;
     313              }
     314              break;
     315          case SOCK_RAW:
     316              break;
     317          case SOCK_DGRAM:
     318              if (pai->ai_protocol != IPPROTO_UDP &&
     319                  pai->ai_protocol != GAI_ANY)
     320                  ERR(EAI_BADHINTS);                      /*xxx*/
     321              pai->ai_protocol = IPPROTO_UDP;
     322              break;
     323          case SOCK_STREAM:
     324              if (pai->ai_protocol != IPPROTO_TCP &&
     325                  pai->ai_protocol != GAI_ANY)
     326                  ERR(EAI_BADHINTS);                      /*xxx*/
     327              pai->ai_protocol = IPPROTO_TCP;
     328              break;
     329          default:
     330              ERR(EAI_SOCKTYPE);
     331              /* unreachable */
     332          }
     333      }
     334  
     335      /*
     336       * service port
     337       */
     338      if (servname) {
     339          if (str_isnumber(servname)) {
     340              if (pai->ai_socktype == GAI_ANY) {
     341                  /* caller accept *GAI_ANY* socktype */
     342                  pai->ai_socktype = SOCK_DGRAM;
     343                  pai->ai_protocol = IPPROTO_UDP;
     344              }
     345              long maybe_port = strtol(servname, NULL, 10);
     346              if (maybe_port < 0 || maybe_port > 0xffff) {
     347                  ERR(EAI_SERVICE);
     348              }
     349              port = htons((u_short)maybe_port);
     350          } else {
     351              struct servent *sp;
     352              const char *proto;
     353  
     354              proto = NULL;
     355              switch (pai->ai_socktype) {
     356              case GAI_ANY:
     357                  proto = NULL;
     358                  break;
     359              case SOCK_DGRAM:
     360                  proto = "udp";
     361                  break;
     362              case SOCK_STREAM:
     363                  proto = "tcp";
     364                  break;
     365              default:
     366                  fprintf(stderr, "panic!\n");
     367                  break;
     368              }
     369              if ((sp = getservbyname(servname, proto)) == NULL)
     370                  ERR(EAI_SERVICE);
     371              port = sp->s_port;
     372              if (pai->ai_socktype == GAI_ANY) {
     373                  if (strcmp(sp->s_proto, "udp") == 0) {
     374                      pai->ai_socktype = SOCK_DGRAM;
     375                      pai->ai_protocol = IPPROTO_UDP;
     376                  } else if (strcmp(sp->s_proto, "tcp") == 0) {
     377                      pai->ai_socktype = SOCK_STREAM;
     378                      pai->ai_protocol = IPPROTO_TCP;
     379                  } else
     380                      ERR(EAI_PROTOCOL);                          /*xxx*/
     381              }
     382          }
     383      }
     384  
     385      /*
     386       * hostname == NULL.
     387       * passive socket -> anyaddr (0.0.0.0 or ::)
     388       * non-passive socket -> localhost (127.0.0.1 or ::1)
     389       */
     390      if (hostname == NULL) {
     391          struct gai_afd *gai_afd;
     392  
     393          for (gai_afd = &gai_afdl[0]; gai_afd->a_af; gai_afd++) {
     394              if (!(pai->ai_family == PF_UNSPEC
     395                 || pai->ai_family == gai_afd->a_af)) {
     396                  continue;
     397              }
     398  
     399              if (pai->ai_flags & AI_PASSIVE) {
     400                  GET_AI(cur->ai_next, gai_afd, gai_afd->a_addrany, port);
     401                  /* xxx meaningless?
     402                   * GET_CANONNAME(cur->ai_next, "anyaddr");
     403                   */
     404              } else {
     405                  GET_AI(cur->ai_next, gai_afd, gai_afd->a_loopback,
     406                      port);
     407                  /* xxx meaningless?
     408                   * GET_CANONNAME(cur->ai_next, "localhost");
     409                   */
     410              }
     411              cur = cur->ai_next;
     412          }
     413          top = sentinel.ai_next;
     414          if (top)
     415              goto good;
     416          else
     417              ERR(EAI_FAMILY);
     418      }
     419  
     420      /* hostname as numeric name */
     421      for (i = 0; gai_afdl[i].a_af; i++) {
     422          if (inet_pton(gai_afdl[i].a_af, hostname, pton)) {
     423              u_long v4a;
     424  #ifdef ENABLE_IPV6
     425              u_char pfx;
     426  #endif
     427  
     428              switch (gai_afdl[i].a_af) {
     429              case AF_INET:
     430                  v4a = ((struct in_addr *)pton)->s_addr;
     431                  v4a = ntohl(v4a);
     432                  if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
     433                      pai->ai_flags &= ~AI_CANONNAME;
     434                  v4a >>= IN_CLASSA_NSHIFT;
     435                  if (v4a == 0 || v4a == IN_LOOPBACKNET)
     436                      pai->ai_flags &= ~AI_CANONNAME;
     437                  break;
     438  #ifdef ENABLE_IPV6
     439              case AF_INET6:
     440                  pfx = ((struct in6_addr *)pton)->s6_addr[0];
     441                  if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
     442                      pai->ai_flags &= ~AI_CANONNAME;
     443                  break;
     444  #endif
     445              }
     446  
     447              if (pai->ai_family == gai_afdl[i].a_af ||
     448                  pai->ai_family == PF_UNSPEC) {
     449                  if (! (pai->ai_flags & AI_CANONNAME)) {
     450                      GET_AI(top, &gai_afdl[i], pton, port);
     451                      goto good;
     452                  }
     453                  /*
     454                   * if AI_CANONNAME and if reverse lookup
     455                   * fail, return ai anyway to pacify
     456                   * calling application.
     457                   *
     458                   * XXX getaddrinfo() is a name->address
     459                   * translation function, and it looks strange
     460                   * that we do addr->name translation here.
     461                   */
     462                  get_name(pton, &gai_afdl[i], &top, pton, pai, port);
     463                  goto good;
     464              } else
     465                  ERR(EAI_FAMILY);                        /*xxx*/
     466          }
     467      }
     468  
     469      if (pai->ai_flags & AI_NUMERICHOST)
     470          ERR(EAI_NONAME);
     471  
     472      /* hostname as alphabetical name */
     473      error = get_addr(hostname, pai->ai_family, &top, pai, port);
     474      if (error == 0) {
     475          if (top) {
     476   good:
     477              *res = top;
     478              return SUCCESS;
     479          } else
     480              error = EAI_FAIL;
     481      }
     482   free:
     483      if (top)
     484          freeaddrinfo(top);
     485   bad:
     486      *res = NULL;
     487      return error;
     488  }
     489  
     490  static int
     491  get_name(addr, gai_afd, res, numaddr, pai, port0)
     492      const char *addr;
     493      struct gai_afd *gai_afd;
     494      struct addrinfo **res;
     495      char *numaddr;
     496      struct addrinfo *pai;
     497      int port0;
     498  {
     499      u_short port = port0 & 0xffff;
     500      struct hostent *hp;
     501      struct addrinfo *cur;
     502      int error = 0;
     503  #ifdef ENABLE_IPV6
     504      int h_error;
     505  #endif
     506  
     507  #ifdef ENABLE_IPV6
     508      hp = getipnodebyaddr(addr, gai_afd->a_addrlen, gai_afd->a_af, &h_error);
     509  #else
     510      hp = gethostbyaddr(addr, gai_afd->a_addrlen, AF_INET);
     511  #endif
     512      if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
     513          GET_AI(cur, gai_afd, hp->h_addr_list[0], port);
     514          GET_CANONNAME(cur, hp->h_name);
     515      } else
     516          GET_AI(cur, gai_afd, numaddr, port);
     517  
     518  #ifdef ENABLE_IPV6
     519      if (hp)
     520          freehostent(hp);
     521  #endif
     522      *res = cur;
     523      return SUCCESS;
     524   free:
     525      if (cur)
     526          freeaddrinfo(cur);
     527  #ifdef ENABLE_IPV6
     528      if (hp)
     529          freehostent(hp);
     530  #endif
     531   /* bad: */
     532      *res = NULL;
     533      return error;
     534  }
     535  
     536  static int
     537  get_addr(hostname, af, res, pai, port0)
     538      const char *hostname;
     539      int af;
     540      struct addrinfo **res;
     541      struct addrinfo *pai;
     542      int port0;
     543  {
     544      u_short port = port0 & 0xffff;
     545      struct addrinfo sentinel;
     546      struct hostent *hp;
     547      struct addrinfo *top, *cur;
     548      struct gai_afd *gai_afd;
     549      int i, error = 0, h_error;
     550      char *ap;
     551  
     552      top = NULL;
     553      sentinel.ai_next = NULL;
     554      cur = &sentinel;
     555  #ifdef ENABLE_IPV6
     556      if (af == AF_UNSPEC) {
     557          hp = getipnodebyname(hostname, AF_INET6,
     558                          AI_ADDRCONFIG|AI_ALL|AI_V4MAPPED, &h_error);
     559      } else
     560          hp = getipnodebyname(hostname, af, AI_ADDRCONFIG, &h_error);
     561  #else
     562      hp = gethostbyname(hostname);
     563      h_error = h_errno;
     564  #endif
     565      if (hp == NULL) {
     566          switch (h_error) {
     567          case HOST_NOT_FOUND:
     568          case NO_DATA:
     569              error = EAI_NODATA;
     570              break;
     571          case TRY_AGAIN:
     572              error = EAI_AGAIN;
     573              break;
     574          case NO_RECOVERY:
     575          default:
     576              error = EAI_FAIL;
     577              break;
     578          }
     579          goto free;
     580      }
     581  
     582      if ((hp->h_name == NULL) || (hp->h_name[0] == 0) ||
     583          (hp->h_addr_list[0] == NULL)) {
     584          error = EAI_FAIL;
     585          goto free;
     586      }
     587  
     588      for (i = 0; (ap = hp->h_addr_list[i]) != NULL; i++) {
     589          switch (af) {
     590  #ifdef ENABLE_IPV6
     591          case AF_INET6:
     592              gai_afd = &gai_afdl[N_INET6];
     593              break;
     594  #endif
     595  #ifndef ENABLE_IPV6
     596          default:                /* AF_UNSPEC */
     597  #endif
     598          case AF_INET:
     599              gai_afd = &gai_afdl[N_INET];
     600              break;
     601  #ifdef ENABLE_IPV6
     602          default:                /* AF_UNSPEC */
     603              if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
     604                  ap += sizeof(struct in6_addr) -
     605                      sizeof(struct in_addr);
     606                  gai_afd = &gai_afdl[N_INET];
     607              } else
     608                  gai_afd = &gai_afdl[N_INET6];
     609              break;
     610  #endif
     611          }
     612  #ifdef FAITH
     613          if (translate && gai_afd->a_af == AF_INET) {
     614              struct in6_addr *in6;
     615  
     616              GET_AI(cur->ai_next, &gai_afdl[N_INET6], ap, port);
     617              in6 = &((struct sockaddr_in6 *)cur->ai_next->ai_addr)->sin6_addr;
     618              memcpy(&in6->s6_addr32[0], &faith_prefix,
     619                  sizeof(struct in6_addr) - sizeof(struct in_addr));
     620              memcpy(&in6->s6_addr32[3], ap, sizeof(struct in_addr));
     621          } else
     622  #endif /* FAITH */
     623          GET_AI(cur->ai_next, gai_afd, ap, port);
     624          if (cur == &sentinel) {
     625              top = cur->ai_next;
     626              GET_CANONNAME(top, hp->h_name);
     627          }
     628          cur = cur->ai_next;
     629      }
     630  #ifdef ENABLE_IPV6
     631      freehostent(hp);
     632  #endif
     633      *res = top;
     634      return SUCCESS;
     635   free:
     636      if (top)
     637          freeaddrinfo(top);
     638  #ifdef ENABLE_IPV6
     639      if (hp)
     640          freehostent(hp);
     641  #endif
     642  /* bad: */
     643      *res = NULL;
     644      return error;
     645  }
     646  
     647  #endif // HAVE_NETDB_H