"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.11.23/lib/lwres/getnameinfo.c" (7 Sep 2020, 9582 Bytes) of package /linux/misc/dns/bind9/9.11.23/bind-9.11.23.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "getnameinfo.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC")
    3  *
    4  * This Source Code Form is subject to the terms of the Mozilla Public
    5  * License, v. 2.0. If a copy of the MPL was not distributed with this
    6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
    7  *
    8  * See the COPYRIGHT file distributed with this work for additional
    9  * information regarding copyright ownership.
   10  */
   11 
   12 /*! \file */
   13 
   14 /*
   15  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
   16  * All rights reserved.
   17  *
   18  * Redistribution and use in source and binary forms, with or without
   19  * modification, are permitted provided that the following conditions
   20  * are met:
   21  * 1. Redistributions of source code must retain the above copyright
   22  *    notice, this list of conditions and the following disclaimer.
   23  * 2. Redistributions in binary form must reproduce the above copyright
   24  *    notice, this list of conditions and the following disclaimer in the
   25  *    documentation and/or other materials provided with the distribution.
   26  * 3. Neither the name of the project nor the names of its contributors
   27  *    may be used to endorse or promote products derived from this software
   28  *    without specific prior written permission.
   29  *
   30  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
   31  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   32  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   33  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
   34  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   35  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   36  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   37  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   38  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   39  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   40  * SUCH DAMAGE.
   41  */
   42 
   43 /*
   44  * XXX
   45  * Issues to be discussed:
   46  * - Return values.  There seems to be no standard for return value (RFC2553)
   47  *   but INRIA implementation returns EAI_xxx defined for getaddrinfo().
   48  */
   49 
   50 
   51 /**
   52  *    This function is equivalent to the getnameinfo(3) function defined in
   53  *    RFC2133. lwres_getnameinfo() returns the hostname for the struct
   54  *    sockaddr sa which is salen bytes long. The hostname is of length
   55  *    hostlen and is returned via *host. The maximum length of the hostname
   56  *    is 1025 bytes: #NI_MAXHOST.
   57  *
   58  *    The name of the service associated with the port number in sa is
   59  *    returned in *serv. It is servlen bytes long. The maximum length of the
   60  *    service name is #NI_MAXSERV - 32 bytes.
   61  *
   62  *    The flags argument sets the following bits:
   63  *
   64  * \li   #NI_NOFQDN:
   65  *           A fully qualified domain name is not required for local hosts.
   66  *           The local part of the fully qualified domain name is returned
   67  *           instead.
   68  *
   69  * \li   #NI_NUMERICHOST
   70  *           Return the address in numeric form, as if calling inet_ntop(),
   71  *           instead of a host name.
   72  *
   73  * \li   #NI_NAMEREQD
   74  *           A name is required. If the hostname cannot be found in the DNS
   75  *           and this flag is set, a non-zero error code is returned. If the
   76  *           hostname is not found and the flag is not set, the address is
   77  *           returned in numeric form.
   78  *
   79  * \li   #NI_NUMERICSERV
   80  *           The service name is returned as a digit string representing the
   81  *           port number.
   82  *
   83  * \li   #NI_DGRAM
   84  *           Specifies that the service being looked up is a datagram
   85  *           service, and causes getservbyport() to be called with a second
   86  *           argument of "udp" instead of its default of "tcp". This is
   87  *           required for the few ports (512-514) that have different
   88  *           services for UDP and TCP.
   89  *
   90  * \section getnameinfo_return Return Values
   91  *
   92  *    lwres_getnameinfo() returns 0 on success or a non-zero error code if
   93  *    an error occurs.
   94  *
   95  * \section getname_see See Also
   96  *
   97  *    RFC2133, getservbyport(),
   98  *    lwres_getnamebyaddr(). lwres_net_ntop().
   99  *
  100  * \section getnameinfo_bugs Bugs
  101  *
  102  *    RFC2133 fails to define what the nonzero return values of
  103  *    getnameinfo() are.
  104  */
  105 
  106 #include <config.h>
  107 
  108 #include <inttypes.h>
  109 #include <stdio.h>
  110 #include <string.h>
  111 
  112 #include <lwres/lwres.h>
  113 #include <lwres/net.h>
  114 #include <lwres/netdb.h>
  115 #include "print_p.h"
  116 
  117 #include "assert_p.h"
  118 #include "unreachable_p.h"
  119 
  120 #define SUCCESS 0
  121 
  122 /*% afd structure definition */
  123 static struct afd {
  124     int a_af;
  125     size_t a_addrlen;
  126     size_t a_socklen;
  127 } afdl [] = {
  128     /*!
  129      * First entry is linked last...
  130      */
  131     { AF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in) },
  132     { AF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6) },
  133     {0, 0, 0},
  134 };
  135 
  136 #define ENI_NOSERVNAME  1
  137 #define ENI_NOHOSTNAME  2
  138 #define ENI_MEMORY  3
  139 #define ENI_SYSTEM  4
  140 #define ENI_FAMILY  5
  141 #define ENI_SALEN   6
  142 #define ENI_NOSOCKET    7
  143 
  144 /*!
  145  * The test against 0 is there to keep the Solaris compiler
  146  * from complaining about "end-of-loop code not reached".
  147  */
  148 #define ERR(code) \
  149     do { result = (code);           \
  150         if (result != 0) goto cleanup;  \
  151     } while (0)
  152 
  153 /*% lightweight resolver socket address structure to hostname and service name */
  154 int
  155 lwres_getnameinfo(const struct sockaddr *sa, size_t salen, char *host,
  156           size_t hostlen, char *serv, size_t servlen, int flags)
  157 {
  158     struct afd *afd = NULL;
  159     struct servent *sp;
  160     unsigned short port;
  161 #ifdef LWRES_PLATFORM_HAVESALEN
  162     size_t len;
  163 #endif
  164     int family, i;
  165     const void *addr;
  166 #if 0
  167     unsigned long v4a;
  168     unsigned char pfx;
  169 #endif
  170     char numserv[sizeof("65000")];
  171     char numaddr[sizeof("abcd:abcd:abcd:abcd:abcd:abcd:255.255.255.255")
  172             + 1 + sizeof("4294967295")];
  173     const char *proto;
  174     uint32_t lwf = 0;
  175     lwres_context_t *lwrctx = NULL;
  176     lwres_gnbaresponse_t *by = NULL;
  177     int result = SUCCESS;
  178     int n;
  179 
  180     if (sa == NULL)
  181         ERR(ENI_NOSOCKET);
  182 
  183 #ifdef LWRES_PLATFORM_HAVESALEN
  184     len = sa->sa_len;
  185     if (len != salen)
  186         ERR(ENI_SALEN);
  187 #endif
  188 
  189     family = sa->sa_family;
  190     for (i = 0; afdl[i].a_af; i++)
  191         if (afdl[i].a_af == family) {
  192             afd = &afdl[i];
  193             goto found;
  194         }
  195     ERR(ENI_FAMILY);
  196 
  197  found:
  198     if (salen != afd->a_socklen)
  199         ERR(ENI_SALEN);
  200 
  201     switch (family) {
  202     case AF_INET:
  203         port = ((const struct sockaddr_in *)sa)->sin_port;
  204         addr = &((const struct sockaddr_in *)sa)->sin_addr.s_addr;
  205         break;
  206 
  207     case AF_INET6:
  208         port = ((const struct sockaddr_in6 *)sa)->sin6_port;
  209         addr = ((const struct sockaddr_in6 *)sa)->sin6_addr.s6_addr;
  210         break;
  211 
  212     default:
  213         port = 0;
  214         addr = NULL;
  215         POST(port); POST(addr);
  216         INSIST(0);
  217     }
  218     proto = (flags & NI_DGRAM) ? "udp" : "tcp";
  219 
  220     if (serv == NULL || servlen == 0U) {
  221         /*
  222          * Caller does not want service.
  223          */
  224     } else if ((flags & NI_NUMERICSERV) != 0 ||
  225            (sp = getservbyport(port, proto)) == NULL) {
  226         snprintf(numserv, sizeof(numserv), "%d", ntohs(port));
  227         if ((strlen(numserv) + 1) > servlen)
  228             ERR(ENI_MEMORY);
  229         strcpy(serv, numserv);
  230     } else {
  231         if ((strlen(sp->s_name) + 1) > servlen)
  232             ERR(ENI_MEMORY);
  233         strcpy(serv, sp->s_name);
  234     }
  235 
  236 #if 0
  237     switch (sa->sa_family) {
  238     case AF_INET:
  239         v4a = ((struct sockaddr_in *)sa)->sin_addr.s_addr;
  240         if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
  241             flags |= NI_NUMERICHOST;
  242         v4a >>= IN_CLASSA_NSHIFT;
  243         if (v4a == 0 || v4a == IN_LOOPBACKNET)
  244             flags |= NI_NUMERICHOST;
  245         break;
  246 
  247     case AF_INET6:
  248         pfx = ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[0];
  249         if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
  250             flags |= NI_NUMERICHOST;
  251         break;
  252     }
  253 #endif
  254 
  255     if (host == NULL || hostlen == 0U) {
  256         /*
  257          * What should we do?
  258          */
  259     } else if (flags & NI_NUMERICHOST) {
  260         if (lwres_net_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
  261             == NULL)
  262             ERR(ENI_SYSTEM);
  263 #if defined(LWRES_HAVE_SIN6_SCOPE_ID)
  264         if (afd->a_af == AF_INET6 &&
  265             ((const struct sockaddr_in6 *)sa)->sin6_scope_id) {
  266             char *p = numaddr + strlen(numaddr);
  267             const char *stringscope = NULL;
  268 #if 0
  269             if ((flags & NI_NUMERICSCOPE) == 0) {
  270                 /*
  271                  * Vendors may want to add support for
  272                  * non-numeric scope identifier.
  273                  */
  274                 stringscope = foo;
  275             }
  276 #endif
  277             if (stringscope == NULL) {
  278                 snprintf(p, sizeof(numaddr) - (p - numaddr),
  279                     "%%%u",
  280                     ((const struct sockaddr_in6 *)sa)->sin6_scope_id);
  281             } else {
  282                 snprintf(p, sizeof(numaddr) - (p - numaddr),
  283                     "%%%s", stringscope);
  284             }
  285         }
  286 #endif
  287         if (strlen(numaddr) + 1 > hostlen)
  288             ERR(ENI_MEMORY);
  289         strcpy(host, numaddr);
  290     } else {
  291         switch (family) {
  292         case AF_INET:
  293             lwf = LWRES_ADDRTYPE_V4;
  294             break;
  295         case AF_INET6:
  296             lwf = LWRES_ADDRTYPE_V6;
  297             break;
  298         default:
  299             INSIST(0);
  300             ISC_UNREACHABLE();
  301         }
  302 
  303         n = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
  304         if (n == 0) {
  305             (void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
  306 
  307             n = lwres_getnamebyaddr(lwrctx, lwf,
  308                         (uint16_t)afd->a_addrlen,
  309                         addr, &by);
  310         }
  311         if (n == 0) {
  312             if (flags & NI_NOFQDN) {
  313                 char *p = strchr(by->realname, '.');
  314                 if (p)
  315                     *p = '\0';
  316             }
  317             if ((strlen(by->realname) + 1) > hostlen)
  318                 ERR(ENI_MEMORY);
  319             strcpy(host, by->realname);
  320         } else {
  321             if (flags & NI_NAMEREQD)
  322                 ERR(ENI_NOHOSTNAME);
  323             if (lwres_net_ntop(afd->a_af, addr, numaddr,
  324                        sizeof(numaddr))
  325                 == NULL)
  326                 ERR(ENI_NOHOSTNAME);
  327             if ((strlen(numaddr) + 1) > hostlen)
  328                 ERR(ENI_MEMORY);
  329             strcpy(host, numaddr);
  330         }
  331     }
  332     result = SUCCESS;
  333  cleanup:
  334     if (by != NULL)
  335         lwres_gnbaresponse_free(lwrctx, &by);
  336     if (lwrctx != NULL) {
  337         lwres_conf_clear(lwrctx);
  338         lwres_context_destroy(&lwrctx);
  339     }
  340     return (result);
  341 }