11cb0ef41Sopenharmony_ci/* MIT License
21cb0ef41Sopenharmony_ci *
31cb0ef41Sopenharmony_ci * Copyright (c) 2005, 2013 Dominick Meglio
41cb0ef41Sopenharmony_ci *
51cb0ef41Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
61cb0ef41Sopenharmony_ci * of this software and associated documentation files (the "Software"), to deal
71cb0ef41Sopenharmony_ci * in the Software without restriction, including without limitation the rights
81cb0ef41Sopenharmony_ci * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
91cb0ef41Sopenharmony_ci * copies of the Software, and to permit persons to whom the Software is
101cb0ef41Sopenharmony_ci * furnished to do so, subject to the following conditions:
111cb0ef41Sopenharmony_ci *
121cb0ef41Sopenharmony_ci * The above copyright notice and this permission notice (including the next
131cb0ef41Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
141cb0ef41Sopenharmony_ci * Software.
151cb0ef41Sopenharmony_ci *
161cb0ef41Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
171cb0ef41Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
181cb0ef41Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
191cb0ef41Sopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
201cb0ef41Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
211cb0ef41Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
221cb0ef41Sopenharmony_ci * SOFTWARE.
231cb0ef41Sopenharmony_ci *
241cb0ef41Sopenharmony_ci * SPDX-License-Identifier: MIT
251cb0ef41Sopenharmony_ci */
261cb0ef41Sopenharmony_ci#include "ares_setup.h"
271cb0ef41Sopenharmony_ci
281cb0ef41Sopenharmony_ci#ifdef HAVE_GETSERVBYPORT_R
291cb0ef41Sopenharmony_ci#  if !defined(GETSERVBYPORT_R_ARGS) || (GETSERVBYPORT_R_ARGS < 4) || \
301cb0ef41Sopenharmony_ci    (GETSERVBYPORT_R_ARGS > 6)
311cb0ef41Sopenharmony_ci#    error "you MUST specify a valid number of arguments for getservbyport_r"
321cb0ef41Sopenharmony_ci#  endif
331cb0ef41Sopenharmony_ci#endif
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_ci#ifdef HAVE_NETINET_IN_H
361cb0ef41Sopenharmony_ci#  include <netinet/in.h>
371cb0ef41Sopenharmony_ci#endif
381cb0ef41Sopenharmony_ci#ifdef HAVE_NETDB_H
391cb0ef41Sopenharmony_ci#  include <netdb.h>
401cb0ef41Sopenharmony_ci#endif
411cb0ef41Sopenharmony_ci#ifdef HAVE_ARPA_INET_H
421cb0ef41Sopenharmony_ci#  include <arpa/inet.h>
431cb0ef41Sopenharmony_ci#endif
441cb0ef41Sopenharmony_ci
451cb0ef41Sopenharmony_ci#include "ares_nameser.h"
461cb0ef41Sopenharmony_ci
471cb0ef41Sopenharmony_ci#ifdef HAVE_NET_IF_H
481cb0ef41Sopenharmony_ci#  include <net/if.h>
491cb0ef41Sopenharmony_ci#endif
501cb0ef41Sopenharmony_ci#if defined(USE_WINSOCK) && defined(HAVE_IPHLPAPI_H)
511cb0ef41Sopenharmony_ci#  include <iphlpapi.h>
521cb0ef41Sopenharmony_ci#endif
531cb0ef41Sopenharmony_ci
541cb0ef41Sopenharmony_ci#include "ares.h"
551cb0ef41Sopenharmony_ci#include "ares_ipv6.h"
561cb0ef41Sopenharmony_ci#include "ares_private.h"
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_cistruct nameinfo_query {
591cb0ef41Sopenharmony_ci  ares_nameinfo_callback callback;
601cb0ef41Sopenharmony_ci  void                  *arg;
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_ci  union {
631cb0ef41Sopenharmony_ci    struct sockaddr_in  addr4;
641cb0ef41Sopenharmony_ci    struct sockaddr_in6 addr6;
651cb0ef41Sopenharmony_ci  } addr;
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_ci  int          family;
681cb0ef41Sopenharmony_ci  unsigned int flags;
691cb0ef41Sopenharmony_ci  size_t       timeouts;
701cb0ef41Sopenharmony_ci};
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_ci#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
731cb0ef41Sopenharmony_ci#  define IPBUFSIZ \
741cb0ef41Sopenharmony_ci    (sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") + IF_NAMESIZE)
751cb0ef41Sopenharmony_ci#else
761cb0ef41Sopenharmony_ci#  define IPBUFSIZ (sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"))
771cb0ef41Sopenharmony_ci#endif
781cb0ef41Sopenharmony_ci
791cb0ef41Sopenharmony_cistatic void  nameinfo_callback(void *arg, int status, int timeouts,
801cb0ef41Sopenharmony_ci                               struct hostent *host);
811cb0ef41Sopenharmony_cistatic char *lookup_service(unsigned short port, unsigned int flags, char *buf,
821cb0ef41Sopenharmony_ci                            size_t buflen);
831cb0ef41Sopenharmony_ci#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
841cb0ef41Sopenharmony_cistatic void append_scopeid(const struct sockaddr_in6 *addr6,
851cb0ef41Sopenharmony_ci                           unsigned int scopeid, char *buf, size_t buflen);
861cb0ef41Sopenharmony_ci#endif
871cb0ef41Sopenharmony_cistatic char *ares_striendstr(const char *s1, const char *s2);
881cb0ef41Sopenharmony_ci
891cb0ef41Sopenharmony_cistatic void  ares_getnameinfo_int(ares_channel_t        *channel,
901cb0ef41Sopenharmony_ci                                  const struct sockaddr *sa,
911cb0ef41Sopenharmony_ci                                  ares_socklen_t salen, int flags_int,
921cb0ef41Sopenharmony_ci                                  ares_nameinfo_callback callback, void *arg)
931cb0ef41Sopenharmony_ci{
941cb0ef41Sopenharmony_ci  const struct sockaddr_in  *addr  = NULL;
951cb0ef41Sopenharmony_ci  const struct sockaddr_in6 *addr6 = NULL;
961cb0ef41Sopenharmony_ci  struct nameinfo_query     *niquery;
971cb0ef41Sopenharmony_ci  unsigned short             port  = 0;
981cb0ef41Sopenharmony_ci  unsigned int               flags = (unsigned int)flags_int;
991cb0ef41Sopenharmony_ci
1001cb0ef41Sopenharmony_ci  /* Validate socket address family and length */
1011cb0ef41Sopenharmony_ci  if ((sa->sa_family == AF_INET) && (salen == sizeof(struct sockaddr_in))) {
1021cb0ef41Sopenharmony_ci    addr = CARES_INADDR_CAST(struct sockaddr_in *, sa);
1031cb0ef41Sopenharmony_ci    port = addr->sin_port;
1041cb0ef41Sopenharmony_ci  } else if ((sa->sa_family == AF_INET6) &&
1051cb0ef41Sopenharmony_ci             (salen == sizeof(struct sockaddr_in6))) {
1061cb0ef41Sopenharmony_ci    addr6 = CARES_INADDR_CAST(struct sockaddr_in6 *, sa);
1071cb0ef41Sopenharmony_ci    port  = addr6->sin6_port;
1081cb0ef41Sopenharmony_ci  } else {
1091cb0ef41Sopenharmony_ci    callback(arg, ARES_ENOTIMP, 0, NULL, NULL);
1101cb0ef41Sopenharmony_ci    return;
1111cb0ef41Sopenharmony_ci  }
1121cb0ef41Sopenharmony_ci
1131cb0ef41Sopenharmony_ci  /* If neither, assume they want a host */
1141cb0ef41Sopenharmony_ci  if (!(flags & ARES_NI_LOOKUPSERVICE) && !(flags & ARES_NI_LOOKUPHOST)) {
1151cb0ef41Sopenharmony_ci    flags |= ARES_NI_LOOKUPHOST;
1161cb0ef41Sopenharmony_ci  }
1171cb0ef41Sopenharmony_ci
1181cb0ef41Sopenharmony_ci  /* All they want is a service, no need for DNS */
1191cb0ef41Sopenharmony_ci  if ((flags & ARES_NI_LOOKUPSERVICE) && !(flags & ARES_NI_LOOKUPHOST)) {
1201cb0ef41Sopenharmony_ci    char  buf[33];
1211cb0ef41Sopenharmony_ci    char *service;
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_ci    service =
1241cb0ef41Sopenharmony_ci      lookup_service((unsigned short)(port & 0xffff), flags, buf, sizeof(buf));
1251cb0ef41Sopenharmony_ci    callback(arg, ARES_SUCCESS, 0, NULL, service);
1261cb0ef41Sopenharmony_ci    return;
1271cb0ef41Sopenharmony_ci  }
1281cb0ef41Sopenharmony_ci
1291cb0ef41Sopenharmony_ci  /* They want a host lookup */
1301cb0ef41Sopenharmony_ci  if (flags & ARES_NI_LOOKUPHOST) {
1311cb0ef41Sopenharmony_ci    /* A numeric host can be handled without DNS */
1321cb0ef41Sopenharmony_ci    if (flags & ARES_NI_NUMERICHOST) {
1331cb0ef41Sopenharmony_ci      char  ipbuf[IPBUFSIZ];
1341cb0ef41Sopenharmony_ci      char  srvbuf[33];
1351cb0ef41Sopenharmony_ci      char *service = NULL;
1361cb0ef41Sopenharmony_ci      ipbuf[0]      = 0;
1371cb0ef41Sopenharmony_ci
1381cb0ef41Sopenharmony_ci      /* Specifying not to lookup a host, but then saying a host
1391cb0ef41Sopenharmony_ci       * is required has to be illegal.
1401cb0ef41Sopenharmony_ci       */
1411cb0ef41Sopenharmony_ci      if (flags & ARES_NI_NAMEREQD) {
1421cb0ef41Sopenharmony_ci        callback(arg, ARES_EBADFLAGS, 0, NULL, NULL);
1431cb0ef41Sopenharmony_ci        return;
1441cb0ef41Sopenharmony_ci      }
1451cb0ef41Sopenharmony_ci      if (salen == sizeof(struct sockaddr_in6)) {
1461cb0ef41Sopenharmony_ci        ares_inet_ntop(AF_INET6, &addr6->sin6_addr, ipbuf, IPBUFSIZ);
1471cb0ef41Sopenharmony_ci        /* If the system supports scope IDs, use it */
1481cb0ef41Sopenharmony_ci#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
1491cb0ef41Sopenharmony_ci        append_scopeid(addr6, flags, ipbuf, sizeof(ipbuf));
1501cb0ef41Sopenharmony_ci#endif
1511cb0ef41Sopenharmony_ci      } else {
1521cb0ef41Sopenharmony_ci        ares_inet_ntop(AF_INET, &addr->sin_addr, ipbuf, IPBUFSIZ);
1531cb0ef41Sopenharmony_ci      }
1541cb0ef41Sopenharmony_ci      /* They also want a service */
1551cb0ef41Sopenharmony_ci      if (flags & ARES_NI_LOOKUPSERVICE) {
1561cb0ef41Sopenharmony_ci        service = lookup_service((unsigned short)(port & 0xffff), flags, srvbuf,
1571cb0ef41Sopenharmony_ci                                 sizeof(srvbuf));
1581cb0ef41Sopenharmony_ci      }
1591cb0ef41Sopenharmony_ci      callback(arg, ARES_SUCCESS, 0, ipbuf, service);
1601cb0ef41Sopenharmony_ci      return;
1611cb0ef41Sopenharmony_ci    }
1621cb0ef41Sopenharmony_ci    /* This is where a DNS lookup becomes necessary */
1631cb0ef41Sopenharmony_ci    else {
1641cb0ef41Sopenharmony_ci      niquery = ares_malloc(sizeof(struct nameinfo_query));
1651cb0ef41Sopenharmony_ci      if (!niquery) {
1661cb0ef41Sopenharmony_ci        callback(arg, ARES_ENOMEM, 0, NULL, NULL);
1671cb0ef41Sopenharmony_ci        return;
1681cb0ef41Sopenharmony_ci      }
1691cb0ef41Sopenharmony_ci      niquery->callback = callback;
1701cb0ef41Sopenharmony_ci      niquery->arg      = arg;
1711cb0ef41Sopenharmony_ci      niquery->flags    = flags;
1721cb0ef41Sopenharmony_ci      niquery->timeouts = 0;
1731cb0ef41Sopenharmony_ci      if (sa->sa_family == AF_INET) {
1741cb0ef41Sopenharmony_ci        niquery->family = AF_INET;
1751cb0ef41Sopenharmony_ci        memcpy(&niquery->addr.addr4, addr, sizeof(niquery->addr.addr4));
1761cb0ef41Sopenharmony_ci        ares_gethostbyaddr(channel, &addr->sin_addr, sizeof(struct in_addr),
1771cb0ef41Sopenharmony_ci                           AF_INET, nameinfo_callback, niquery);
1781cb0ef41Sopenharmony_ci      } else {
1791cb0ef41Sopenharmony_ci        niquery->family = AF_INET6;
1801cb0ef41Sopenharmony_ci        memcpy(&niquery->addr.addr6, addr6, sizeof(niquery->addr.addr6));
1811cb0ef41Sopenharmony_ci        ares_gethostbyaddr(channel, &addr6->sin6_addr,
1821cb0ef41Sopenharmony_ci                           sizeof(struct ares_in6_addr), AF_INET6,
1831cb0ef41Sopenharmony_ci                           nameinfo_callback, niquery);
1841cb0ef41Sopenharmony_ci      }
1851cb0ef41Sopenharmony_ci    }
1861cb0ef41Sopenharmony_ci  }
1871cb0ef41Sopenharmony_ci}
1881cb0ef41Sopenharmony_ci
1891cb0ef41Sopenharmony_civoid ares_getnameinfo(ares_channel_t *channel, const struct sockaddr *sa,
1901cb0ef41Sopenharmony_ci                      ares_socklen_t salen, int flags_int,
1911cb0ef41Sopenharmony_ci                      ares_nameinfo_callback callback, void *arg)
1921cb0ef41Sopenharmony_ci{
1931cb0ef41Sopenharmony_ci  if (channel == NULL) {
1941cb0ef41Sopenharmony_ci    return;
1951cb0ef41Sopenharmony_ci  }
1961cb0ef41Sopenharmony_ci
1971cb0ef41Sopenharmony_ci  ares__channel_lock(channel);
1981cb0ef41Sopenharmony_ci  ares_getnameinfo_int(channel, sa, salen, flags_int, callback, arg);
1991cb0ef41Sopenharmony_ci  ares__channel_unlock(channel);
2001cb0ef41Sopenharmony_ci}
2011cb0ef41Sopenharmony_ci
2021cb0ef41Sopenharmony_cistatic void nameinfo_callback(void *arg, int status, int timeouts,
2031cb0ef41Sopenharmony_ci                              struct hostent *host)
2041cb0ef41Sopenharmony_ci{
2051cb0ef41Sopenharmony_ci  struct nameinfo_query *niquery = (struct nameinfo_query *)arg;
2061cb0ef41Sopenharmony_ci  char                   srvbuf[33];
2071cb0ef41Sopenharmony_ci  char                  *service = NULL;
2081cb0ef41Sopenharmony_ci
2091cb0ef41Sopenharmony_ci  niquery->timeouts += (size_t)timeouts;
2101cb0ef41Sopenharmony_ci  if (status == ARES_SUCCESS) {
2111cb0ef41Sopenharmony_ci    /* They want a service too */
2121cb0ef41Sopenharmony_ci    if (niquery->flags & ARES_NI_LOOKUPSERVICE) {
2131cb0ef41Sopenharmony_ci      if (niquery->family == AF_INET) {
2141cb0ef41Sopenharmony_ci        service = lookup_service(niquery->addr.addr4.sin_port, niquery->flags,
2151cb0ef41Sopenharmony_ci                                 srvbuf, sizeof(srvbuf));
2161cb0ef41Sopenharmony_ci      } else {
2171cb0ef41Sopenharmony_ci        service = lookup_service(niquery->addr.addr6.sin6_port, niquery->flags,
2181cb0ef41Sopenharmony_ci                                 srvbuf, sizeof(srvbuf));
2191cb0ef41Sopenharmony_ci      }
2201cb0ef41Sopenharmony_ci    }
2211cb0ef41Sopenharmony_ci    /* NOFQDN means we have to strip off the domain name portion.  We do
2221cb0ef41Sopenharmony_ci       this by determining our own domain name, then searching the string
2231cb0ef41Sopenharmony_ci       for this domain name and removing it.
2241cb0ef41Sopenharmony_ci     */
2251cb0ef41Sopenharmony_ci#ifdef HAVE_GETHOSTNAME
2261cb0ef41Sopenharmony_ci    if (niquery->flags & ARES_NI_NOFQDN) {
2271cb0ef41Sopenharmony_ci      char        buf[255];
2281cb0ef41Sopenharmony_ci      const char *domain;
2291cb0ef41Sopenharmony_ci      gethostname(buf, 255);
2301cb0ef41Sopenharmony_ci      if ((domain = strchr(buf, '.')) != NULL) {
2311cb0ef41Sopenharmony_ci        char *end = ares_striendstr(host->h_name, domain);
2321cb0ef41Sopenharmony_ci        if (end) {
2331cb0ef41Sopenharmony_ci          *end = 0;
2341cb0ef41Sopenharmony_ci        }
2351cb0ef41Sopenharmony_ci      }
2361cb0ef41Sopenharmony_ci    }
2371cb0ef41Sopenharmony_ci#endif
2381cb0ef41Sopenharmony_ci    niquery->callback(niquery->arg, ARES_SUCCESS, (int)niquery->timeouts,
2391cb0ef41Sopenharmony_ci                      host->h_name, service);
2401cb0ef41Sopenharmony_ci    ares_free(niquery);
2411cb0ef41Sopenharmony_ci    return;
2421cb0ef41Sopenharmony_ci  }
2431cb0ef41Sopenharmony_ci  /* We couldn't find the host, but it's OK, we can use the IP */
2441cb0ef41Sopenharmony_ci  else if (status == ARES_ENOTFOUND && !(niquery->flags & ARES_NI_NAMEREQD)) {
2451cb0ef41Sopenharmony_ci    char ipbuf[IPBUFSIZ];
2461cb0ef41Sopenharmony_ci    if (niquery->family == AF_INET) {
2471cb0ef41Sopenharmony_ci      ares_inet_ntop(AF_INET, &niquery->addr.addr4.sin_addr, ipbuf, IPBUFSIZ);
2481cb0ef41Sopenharmony_ci    } else {
2491cb0ef41Sopenharmony_ci      ares_inet_ntop(AF_INET6, &niquery->addr.addr6.sin6_addr, ipbuf, IPBUFSIZ);
2501cb0ef41Sopenharmony_ci#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
2511cb0ef41Sopenharmony_ci      append_scopeid(&niquery->addr.addr6, niquery->flags, ipbuf,
2521cb0ef41Sopenharmony_ci                     sizeof(ipbuf));
2531cb0ef41Sopenharmony_ci#endif
2541cb0ef41Sopenharmony_ci    }
2551cb0ef41Sopenharmony_ci    /* They want a service too */
2561cb0ef41Sopenharmony_ci    if (niquery->flags & ARES_NI_LOOKUPSERVICE) {
2571cb0ef41Sopenharmony_ci      if (niquery->family == AF_INET) {
2581cb0ef41Sopenharmony_ci        service = lookup_service(niquery->addr.addr4.sin_port, niquery->flags,
2591cb0ef41Sopenharmony_ci                                 srvbuf, sizeof(srvbuf));
2601cb0ef41Sopenharmony_ci      } else {
2611cb0ef41Sopenharmony_ci        service = lookup_service(niquery->addr.addr6.sin6_port, niquery->flags,
2621cb0ef41Sopenharmony_ci                                 srvbuf, sizeof(srvbuf));
2631cb0ef41Sopenharmony_ci      }
2641cb0ef41Sopenharmony_ci    }
2651cb0ef41Sopenharmony_ci    niquery->callback(niquery->arg, ARES_SUCCESS, (int)niquery->timeouts, ipbuf,
2661cb0ef41Sopenharmony_ci                      service);
2671cb0ef41Sopenharmony_ci    ares_free(niquery);
2681cb0ef41Sopenharmony_ci    return;
2691cb0ef41Sopenharmony_ci  }
2701cb0ef41Sopenharmony_ci  niquery->callback(niquery->arg, status, (int)niquery->timeouts, NULL, NULL);
2711cb0ef41Sopenharmony_ci  ares_free(niquery);
2721cb0ef41Sopenharmony_ci}
2731cb0ef41Sopenharmony_ci
2741cb0ef41Sopenharmony_cistatic char *lookup_service(unsigned short port, unsigned int flags, char *buf,
2751cb0ef41Sopenharmony_ci                            size_t buflen)
2761cb0ef41Sopenharmony_ci{
2771cb0ef41Sopenharmony_ci  const char     *proto;
2781cb0ef41Sopenharmony_ci  struct servent *sep;
2791cb0ef41Sopenharmony_ci#ifdef HAVE_GETSERVBYPORT_R
2801cb0ef41Sopenharmony_ci  struct servent se;
2811cb0ef41Sopenharmony_ci#endif
2821cb0ef41Sopenharmony_ci  char        tmpbuf[4096];
2831cb0ef41Sopenharmony_ci  const char *name;
2841cb0ef41Sopenharmony_ci  size_t      name_len;
2851cb0ef41Sopenharmony_ci
2861cb0ef41Sopenharmony_ci  if (port) {
2871cb0ef41Sopenharmony_ci    if (flags & ARES_NI_NUMERICSERV) {
2881cb0ef41Sopenharmony_ci      sep = NULL;
2891cb0ef41Sopenharmony_ci    } else {
2901cb0ef41Sopenharmony_ci      if (flags & ARES_NI_UDP) {
2911cb0ef41Sopenharmony_ci        proto = "udp";
2921cb0ef41Sopenharmony_ci      } else if (flags & ARES_NI_SCTP) {
2931cb0ef41Sopenharmony_ci        proto = "sctp";
2941cb0ef41Sopenharmony_ci      } else if (flags & ARES_NI_DCCP) {
2951cb0ef41Sopenharmony_ci        proto = "dccp";
2961cb0ef41Sopenharmony_ci      } else {
2971cb0ef41Sopenharmony_ci        proto = "tcp";
2981cb0ef41Sopenharmony_ci      }
2991cb0ef41Sopenharmony_ci#ifdef HAVE_GETSERVBYPORT_R
3001cb0ef41Sopenharmony_ci      memset(&se, 0, sizeof(se));
3011cb0ef41Sopenharmony_ci      sep = &se;
3021cb0ef41Sopenharmony_ci      memset(tmpbuf, 0, sizeof(tmpbuf));
3031cb0ef41Sopenharmony_ci#  if GETSERVBYPORT_R_ARGS == 6
3041cb0ef41Sopenharmony_ci      if (getservbyport_r(port, proto, &se, (void *)tmpbuf, sizeof(tmpbuf),
3051cb0ef41Sopenharmony_ci                          &sep) != 0) {
3061cb0ef41Sopenharmony_ci        sep = NULL; /* LCOV_EXCL_LINE: buffer large so this never fails */
3071cb0ef41Sopenharmony_ci      }
3081cb0ef41Sopenharmony_ci#  elif GETSERVBYPORT_R_ARGS == 5
3091cb0ef41Sopenharmony_ci      sep = getservbyport_r(port, proto, &se, (void *)tmpbuf, sizeof(tmpbuf));
3101cb0ef41Sopenharmony_ci#  elif GETSERVBYPORT_R_ARGS == 4
3111cb0ef41Sopenharmony_ci      if (getservbyport_r(port, proto, &se, (void *)tmpbuf) != 0) {
3121cb0ef41Sopenharmony_ci        sep = NULL;
3131cb0ef41Sopenharmony_ci      }
3141cb0ef41Sopenharmony_ci#  else
3151cb0ef41Sopenharmony_ci      /* Lets just hope the OS uses TLS! */
3161cb0ef41Sopenharmony_ci      sep = getservbyport(port, proto);
3171cb0ef41Sopenharmony_ci#  endif
3181cb0ef41Sopenharmony_ci#else
3191cb0ef41Sopenharmony_ci      /* Lets just hope the OS uses TLS! */
3201cb0ef41Sopenharmony_ci#  if (defined(NETWARE) && !defined(__NOVELL_LIBC__))
3211cb0ef41Sopenharmony_ci      sep = getservbyport(port, (char *)proto);
3221cb0ef41Sopenharmony_ci#  else
3231cb0ef41Sopenharmony_ci      sep = getservbyport(port, proto);
3241cb0ef41Sopenharmony_ci#  endif
3251cb0ef41Sopenharmony_ci#endif
3261cb0ef41Sopenharmony_ci    }
3271cb0ef41Sopenharmony_ci    if (sep && sep->s_name) {
3281cb0ef41Sopenharmony_ci      /* get service name */
3291cb0ef41Sopenharmony_ci      name = sep->s_name;
3301cb0ef41Sopenharmony_ci    } else {
3311cb0ef41Sopenharmony_ci      /* get port as a string */
3321cb0ef41Sopenharmony_ci      snprintf(tmpbuf, sizeof(tmpbuf), "%u", (unsigned int)ntohs(port));
3331cb0ef41Sopenharmony_ci      name = tmpbuf;
3341cb0ef41Sopenharmony_ci    }
3351cb0ef41Sopenharmony_ci    name_len = ares_strlen(name);
3361cb0ef41Sopenharmony_ci    if (name_len < buflen) {
3371cb0ef41Sopenharmony_ci      /* return it if buffer big enough */
3381cb0ef41Sopenharmony_ci      memcpy(buf, name, name_len + 1);
3391cb0ef41Sopenharmony_ci    } else {
3401cb0ef41Sopenharmony_ci      /* avoid reusing previous one */
3411cb0ef41Sopenharmony_ci      buf[0] = '\0'; /* LCOV_EXCL_LINE: no real service names are too big */
3421cb0ef41Sopenharmony_ci    }
3431cb0ef41Sopenharmony_ci    return buf;
3441cb0ef41Sopenharmony_ci  }
3451cb0ef41Sopenharmony_ci  buf[0] = '\0';
3461cb0ef41Sopenharmony_ci  return NULL;
3471cb0ef41Sopenharmony_ci}
3481cb0ef41Sopenharmony_ci
3491cb0ef41Sopenharmony_ci#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
3501cb0ef41Sopenharmony_cistatic void append_scopeid(const struct sockaddr_in6 *addr6, unsigned int flags,
3511cb0ef41Sopenharmony_ci                           char *buf, size_t buflen)
3521cb0ef41Sopenharmony_ci{
3531cb0ef41Sopenharmony_ci#  ifdef HAVE_IF_INDEXTONAME
3541cb0ef41Sopenharmony_ci  int is_ll;
3551cb0ef41Sopenharmony_ci  int is_mcll;
3561cb0ef41Sopenharmony_ci#  endif
3571cb0ef41Sopenharmony_ci  char   tmpbuf[IF_NAMESIZE + 2];
3581cb0ef41Sopenharmony_ci  size_t bufl;
3591cb0ef41Sopenharmony_ci
3601cb0ef41Sopenharmony_ci  tmpbuf[0] = '%';
3611cb0ef41Sopenharmony_ci
3621cb0ef41Sopenharmony_ci#  ifdef HAVE_IF_INDEXTONAME
3631cb0ef41Sopenharmony_ci  is_ll   = IN6_IS_ADDR_LINKLOCAL(&addr6->sin6_addr);
3641cb0ef41Sopenharmony_ci  is_mcll = IN6_IS_ADDR_MC_LINKLOCAL(&addr6->sin6_addr);
3651cb0ef41Sopenharmony_ci  if ((flags & ARES_NI_NUMERICSCOPE) || (!is_ll && !is_mcll)) {
3661cb0ef41Sopenharmony_ci    snprintf(&tmpbuf[1], sizeof(tmpbuf) - 1, "%lu",
3671cb0ef41Sopenharmony_ci             (unsigned long)addr6->sin6_scope_id);
3681cb0ef41Sopenharmony_ci  } else {
3691cb0ef41Sopenharmony_ci    if (if_indextoname(addr6->sin6_scope_id, &tmpbuf[1]) == NULL) {
3701cb0ef41Sopenharmony_ci      snprintf(&tmpbuf[1], sizeof(tmpbuf) - 1, "%lu",
3711cb0ef41Sopenharmony_ci               (unsigned long)addr6->sin6_scope_id);
3721cb0ef41Sopenharmony_ci    }
3731cb0ef41Sopenharmony_ci  }
3741cb0ef41Sopenharmony_ci#  else
3751cb0ef41Sopenharmony_ci  snprintf(&tmpbuf[1], sizeof(tmpbuf) - 1, "%lu",
3761cb0ef41Sopenharmony_ci           (unsigned long)addr6->sin6_scope_id);
3771cb0ef41Sopenharmony_ci  (void)flags;
3781cb0ef41Sopenharmony_ci#  endif
3791cb0ef41Sopenharmony_ci  tmpbuf[IF_NAMESIZE + 1] = '\0';
3801cb0ef41Sopenharmony_ci  bufl                    = ares_strlen(buf);
3811cb0ef41Sopenharmony_ci
3821cb0ef41Sopenharmony_ci  if (bufl + ares_strlen(tmpbuf) < buflen) {
3831cb0ef41Sopenharmony_ci    /* only append the scopeid string if it fits in the target buffer */
3841cb0ef41Sopenharmony_ci    ares_strcpy(&buf[bufl], tmpbuf, buflen - bufl);
3851cb0ef41Sopenharmony_ci  }
3861cb0ef41Sopenharmony_ci}
3871cb0ef41Sopenharmony_ci#endif
3881cb0ef41Sopenharmony_ci
3891cb0ef41Sopenharmony_ci/* Determines if s1 ends with the string in s2 (case-insensitive) */
3901cb0ef41Sopenharmony_cistatic char *ares_striendstr(const char *s1, const char *s2)
3911cb0ef41Sopenharmony_ci{
3921cb0ef41Sopenharmony_ci  const char *c1;
3931cb0ef41Sopenharmony_ci  const char *c2;
3941cb0ef41Sopenharmony_ci  const char *c1_begin;
3951cb0ef41Sopenharmony_ci  int         lo1;
3961cb0ef41Sopenharmony_ci  int         lo2;
3971cb0ef41Sopenharmony_ci  size_t      s1_len = ares_strlen(s1);
3981cb0ef41Sopenharmony_ci  size_t      s2_len = ares_strlen(s2);
3991cb0ef41Sopenharmony_ci
4001cb0ef41Sopenharmony_ci  if (s1 == NULL || s2 == NULL) {
4011cb0ef41Sopenharmony_ci    return NULL;
4021cb0ef41Sopenharmony_ci  }
4031cb0ef41Sopenharmony_ci
4041cb0ef41Sopenharmony_ci  /* If the substr is longer than the full str, it can't match */
4051cb0ef41Sopenharmony_ci  if (s2_len > s1_len) {
4061cb0ef41Sopenharmony_ci    return NULL;
4071cb0ef41Sopenharmony_ci  }
4081cb0ef41Sopenharmony_ci
4091cb0ef41Sopenharmony_ci  /* Jump to the end of s1 minus the length of s2 */
4101cb0ef41Sopenharmony_ci  c1_begin = s1 + s1_len - s2_len;
4111cb0ef41Sopenharmony_ci  c1       = c1_begin;
4121cb0ef41Sopenharmony_ci  c2       = s2;
4131cb0ef41Sopenharmony_ci  while (c2 < s2 + s2_len) {
4141cb0ef41Sopenharmony_ci    lo1 = TOLOWER(*c1);
4151cb0ef41Sopenharmony_ci    lo2 = TOLOWER(*c2);
4161cb0ef41Sopenharmony_ci    if (lo1 != lo2) {
4171cb0ef41Sopenharmony_ci      return NULL;
4181cb0ef41Sopenharmony_ci    } else {
4191cb0ef41Sopenharmony_ci      c1++;
4201cb0ef41Sopenharmony_ci      c2++;
4211cb0ef41Sopenharmony_ci    }
4221cb0ef41Sopenharmony_ci  }
4231cb0ef41Sopenharmony_ci  /* Cast off const */
4241cb0ef41Sopenharmony_ci  return (char *)((size_t)c1_begin);
4251cb0ef41Sopenharmony_ci}
4261cb0ef41Sopenharmony_ci
4271cb0ef41Sopenharmony_ciares_bool_t ares__is_onion_domain(const char *name)
4281cb0ef41Sopenharmony_ci{
4291cb0ef41Sopenharmony_ci  if (ares_striendstr(name, ".onion")) {
4301cb0ef41Sopenharmony_ci    return ARES_TRUE;
4311cb0ef41Sopenharmony_ci  }
4321cb0ef41Sopenharmony_ci
4331cb0ef41Sopenharmony_ci  if (ares_striendstr(name, ".onion.")) {
4341cb0ef41Sopenharmony_ci    return ARES_TRUE;
4351cb0ef41Sopenharmony_ci  }
4361cb0ef41Sopenharmony_ci
4371cb0ef41Sopenharmony_ci  return ARES_FALSE;
4381cb0ef41Sopenharmony_ci}
439