"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.11.23/lib/lwres/context.c" (7 Sep 2020, 13072 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 "context.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * 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 /* $Id: context.c,v 1.55 2009/09/02 23:48:03 tbox Exp $ */
   13 
   14 /*! \file context.c
   15    lwres_context_create() creates a #lwres_context_t structure for use in
   16    lightweight resolver operations. It holds a socket and other data
   17    needed for communicating with a resolver daemon. The new
   18    lwres_context_t is returned through contextp, a pointer to a
   19    lwres_context_t pointer. This lwres_context_t pointer must initially
   20    be NULL, and is modified to point to the newly created
   21    lwres_context_t.
   22 
   23    When the lightweight resolver needs to perform dynamic memory
   24    allocation, it will call malloc_function to allocate memory and
   25    free_function to free it. If malloc_function and free_function are
   26    NULL, memory is allocated using malloc and free. It is not
   27    permitted to have a NULL malloc_function and a non-NULL free_function
   28    or vice versa. arg is passed as the first parameter to the memory
   29    allocation functions. If malloc_function and free_function are NULL,
   30    arg is unused and should be passed as NULL.
   31 
   32    Once memory for the structure has been allocated, it is initialized
   33    using lwres_conf_init() and returned via *contextp.
   34 
   35    lwres_context_destroy() destroys a #lwres_context_t, closing its
   36    socket. contextp is a pointer to a pointer to the context that is to
   37    be destroyed. The pointer will be set to NULL when the context has
   38    been destroyed.
   39 
   40    The context holds a serial number that is used to identify resolver
   41    request packets and associate responses with the corresponding
   42    requests. This serial number is controlled using
   43    lwres_context_initserial() and lwres_context_nextserial().
   44    lwres_context_initserial() sets the serial number for context *ctx to
   45    serial. lwres_context_nextserial() increments the serial number and
   46    returns the previous value.
   47 
   48    Memory for a lightweight resolver context is allocated and freed using
   49    lwres_context_allocmem() and lwres_context_freemem(). These use
   50    whatever allocations were defined when the context was created with
   51    lwres_context_create(). lwres_context_allocmem() allocates len bytes
   52    of memory and if successful returns a pointer to the allocated
   53    storage. lwres_context_freemem() frees len bytes of space starting at
   54    location mem.
   55 
   56    lwres_context_sendrecv() performs I/O for the context ctx. Data are
   57    read and written from the context's socket. It writes data from
   58    sendbase -- typically a lightweight resolver query packet -- and waits
   59    for a reply which is copied to the receive buffer at recvbase. The
   60    number of bytes that were written to this receive buffer is returned
   61    in *recvd_len.
   62 
   63 \section context_return Return Values
   64 
   65    lwres_context_create() returns #LWRES_R_NOMEMORY if memory for the
   66    struct lwres_context could not be allocated, #LWRES_R_SUCCESS
   67    otherwise.
   68 
   69    Successful calls to the memory allocator lwres_context_allocmem()
   70    return a pointer to the start of the allocated space. It returns NULL
   71    if memory could not be allocated.
   72 
   73    #LWRES_R_SUCCESS is returned when lwres_context_sendrecv() completes
   74    successfully. #LWRES_R_IOERROR is returned if an I/O error occurs and
   75    #LWRES_R_TIMEOUT is returned if lwres_context_sendrecv() times out
   76    waiting for a response.
   77 
   78 \section context_see See Also
   79 
   80    lwres_conf_init(), malloc, free.
   81  */
   82 #include <config.h>
   83 
   84 #include <fcntl.h>
   85 #include <inttypes.h>
   86 #include <limits.h>
   87 #include <stdlib.h>
   88 #include <string.h>
   89 #include <time.h>
   90 #include <unistd.h>
   91 
   92 #include <lwres/lwres.h>
   93 #include <lwres/net.h>
   94 #include <lwres/platform.h>
   95 
   96 #ifdef LWRES_PLATFORM_NEEDSYSSELECTH
   97 #include <sys/select.h>
   98 #endif
   99 
  100 #include "context_p.h"
  101 #include "assert_p.h"
  102 
  103 /*!
  104  * Some systems define the socket length argument as an int, some as size_t,
  105  * some as socklen_t.  The last is what the current POSIX standard mandates.
  106  * This definition is here so it can be portable but easily changed if needed.
  107  */
  108 #ifndef LWRES_SOCKADDR_LEN_T
  109 #define LWRES_SOCKADDR_LEN_T unsigned int
  110 #endif
  111 
  112 /*!
  113  * Make a socket nonblocking.
  114  */
  115 #ifndef MAKE_NONBLOCKING
  116 #define MAKE_NONBLOCKING(sd, retval) \
  117 do { \
  118     retval = fcntl(sd, F_GETFL, 0); \
  119     if (retval != -1) { \
  120         retval |= O_NONBLOCK; \
  121         retval = fcntl(sd, F_SETFL, retval); \
  122     } \
  123 } while (0)
  124 #endif
  125 
  126 LIBLWRES_EXTERNAL_DATA uint16_t lwres_udp_port = LWRES_UDP_PORT;
  127 LIBLWRES_EXTERNAL_DATA const char *lwres_resolv_conf = LWRES_RESOLV_CONF;
  128 
  129 static void *
  130 lwres_malloc(void *, size_t);
  131 
  132 static void
  133 lwres_free(void *, void *, size_t);
  134 
  135 /*!
  136  * lwres_result_t
  137  */
  138 static lwres_result_t
  139 context_connect(lwres_context_t *);
  140 
  141 /*%
  142  * Creates a #lwres_context_t structure for use in
  143  *  lightweight resolver operations.
  144  */
  145 lwres_result_t
  146 lwres_context_create(lwres_context_t **contextp, void *arg,
  147              lwres_malloc_t malloc_function,
  148              lwres_free_t free_function,
  149              unsigned int flags)
  150 {
  151     lwres_context_t *ctx;
  152 
  153     REQUIRE(contextp != NULL && *contextp == NULL);
  154 
  155     /*
  156      * If we were not given anything special to use, use our own
  157      * functions.  These are just wrappers around malloc() and free().
  158      */
  159     if (malloc_function == NULL || free_function == NULL) {
  160         REQUIRE(malloc_function == NULL);
  161         REQUIRE(free_function == NULL);
  162         malloc_function = lwres_malloc;
  163         free_function = lwres_free;
  164     }
  165 
  166     ctx = malloc_function(arg, sizeof(lwres_context_t));
  167     if (ctx == NULL)
  168         return (LWRES_R_NOMEMORY);
  169 
  170     /*
  171      * Set up the context.
  172      */
  173     ctx->malloc = malloc_function;
  174     ctx->free = free_function;
  175     ctx->arg = arg;
  176     ctx->sock = -1;
  177 
  178     ctx->timeout = LWRES_DEFAULT_TIMEOUT;
  179 #ifndef WIN32
  180     ctx->serial = time(NULL); /* XXXMLG or BEW */
  181 #else
  182     ctx->serial = _time32(NULL);
  183 #endif
  184 
  185     ctx->use_ipv4 = 1;
  186     ctx->use_ipv6 = 1;
  187     if ((flags & (LWRES_CONTEXT_USEIPV4 | LWRES_CONTEXT_USEIPV6)) ==
  188         LWRES_CONTEXT_USEIPV6) {
  189         ctx->use_ipv4 = 0;
  190     }
  191     if ((flags & (LWRES_CONTEXT_USEIPV4 | LWRES_CONTEXT_USEIPV6)) ==
  192         LWRES_CONTEXT_USEIPV4) {
  193         ctx->use_ipv6 = 0;
  194     }
  195 
  196     /*
  197      * Init resolv.conf bits.
  198      */
  199     lwres_conf_init(ctx);
  200 
  201     *contextp = ctx;
  202     return (LWRES_R_SUCCESS);
  203 }
  204 
  205 /*%
  206 Destroys a #lwres_context_t, closing its socket.
  207 contextp is a pointer to a pointer to the context that is
  208 to be destroyed. The pointer will be set to NULL
  209 when the context has been destroyed.
  210  */
  211 void
  212 lwres_context_destroy(lwres_context_t **contextp) {
  213     lwres_context_t *ctx;
  214 
  215     REQUIRE(contextp != NULL && *contextp != NULL);
  216 
  217     ctx = *contextp;
  218     *contextp = NULL;
  219 
  220     if (ctx->sock != -1) {
  221 #ifdef WIN32
  222         DestroySockets();
  223 #endif
  224         (void)close(ctx->sock);
  225         ctx->sock = -1;
  226     }
  227 
  228     CTXFREE(ctx, sizeof(lwres_context_t));
  229 }
  230 /*% Increments the serial number and returns the previous value. */
  231 uint32_t
  232 lwres_context_nextserial(lwres_context_t *ctx) {
  233     REQUIRE(ctx != NULL);
  234 
  235     return (ctx->serial++);
  236 }
  237 
  238 /*% Sets the serial number for context *ctx to serial. */
  239 void
  240 lwres_context_initserial(lwres_context_t *ctx, uint32_t serial) {
  241     REQUIRE(ctx != NULL);
  242 
  243     ctx->serial = serial;
  244 }
  245 
  246 /*% Frees len bytes of space starting at location mem. */
  247 void
  248 lwres_context_freemem(lwres_context_t *ctx, void *mem, size_t len) {
  249     REQUIRE(mem != NULL);
  250     REQUIRE(len != 0U);
  251 
  252     CTXFREE(mem, len);
  253 }
  254 
  255 /*% Allocates len bytes of memory and if successful returns a pointer to the allocated storage. */
  256 void *
  257 lwres_context_allocmem(lwres_context_t *ctx, size_t len) {
  258     REQUIRE(len != 0U);
  259 
  260     return (CTXMALLOC(len));
  261 }
  262 
  263 static void *
  264 lwres_malloc(void *arg, size_t len) {
  265     void *mem;
  266 
  267     UNUSED(arg);
  268 
  269     mem = malloc(len);
  270     if (mem == NULL)
  271         return (NULL);
  272 
  273     memset(mem, 0xe5, len);
  274 
  275     return (mem);
  276 }
  277 
  278 static void
  279 lwres_free(void *arg, void *mem, size_t len) {
  280     UNUSED(arg);
  281 
  282     memset(mem, 0xa9, len);
  283     free(mem);
  284 }
  285 
  286 static lwres_result_t
  287 context_connect(lwres_context_t *ctx) {
  288 #ifndef WIN32
  289     int s;
  290 #else
  291     SOCKET s;
  292 #endif
  293     int ret;
  294     struct sockaddr_in sin;
  295     struct sockaddr_in6 sin6;
  296     struct sockaddr *sa;
  297     LWRES_SOCKADDR_LEN_T salen;
  298     int domain;
  299 
  300     if (ctx->confdata.lwnext != 0) {
  301         memmove(&ctx->address, &ctx->confdata.lwservers[0],
  302             sizeof(lwres_addr_t));
  303         LWRES_LINK_INIT(&ctx->address, link);
  304     } else {
  305         /* The default is the IPv4 loopback address 127.0.0.1. */
  306         memset(&ctx->address, 0, sizeof(ctx->address));
  307         ctx->address.family = LWRES_ADDRTYPE_V4;
  308         ctx->address.length = 4;
  309         ctx->address.address[0] = 127;
  310         ctx->address.address[1] = 0;
  311         ctx->address.address[2] = 0;
  312         ctx->address.address[3] = 1;
  313     }
  314 
  315     if (ctx->address.family == LWRES_ADDRTYPE_V4) {
  316         memmove(&sin.sin_addr, ctx->address.address,
  317             sizeof(sin.sin_addr));
  318         sin.sin_port = htons(lwres_udp_port);
  319         sin.sin_family = AF_INET;
  320         sa = (struct sockaddr *)&sin;
  321         salen = sizeof(sin);
  322         domain = PF_INET;
  323     } else if (ctx->address.family == LWRES_ADDRTYPE_V6) {
  324         memmove(&sin6.sin6_addr, ctx->address.address,
  325             sizeof(sin6.sin6_addr));
  326         sin6.sin6_port = htons(lwres_udp_port);
  327         sin6.sin6_family = AF_INET6;
  328         sa = (struct sockaddr *)&sin6;
  329         salen = sizeof(sin6);
  330         domain = PF_INET6;
  331     } else
  332         return (LWRES_R_IOERROR);
  333 
  334 #ifdef WIN32
  335     InitSockets();
  336 #endif
  337     s = socket(domain, SOCK_DGRAM, IPPROTO_UDP);
  338 #ifndef WIN32
  339     if (s < 0) {
  340         return (LWRES_R_IOERROR);
  341     }
  342 #else
  343     if (s == INVALID_SOCKET) {
  344         DestroySockets();
  345         return (LWRES_R_IOERROR);
  346     }
  347 #endif
  348 
  349     ret = connect(s, sa, salen);
  350     if (ret != 0) {
  351 #ifdef WIN32
  352         DestroySockets();
  353 #endif
  354         (void)close(s);
  355         return (LWRES_R_IOERROR);
  356     }
  357 
  358     MAKE_NONBLOCKING(s, ret);
  359     if (ret < 0) {
  360 #ifdef WIN32
  361         DestroySockets();
  362 #endif
  363         (void)close(s);
  364         return (LWRES_R_IOERROR);
  365     }
  366 
  367     ctx->sock = (int)s;
  368 
  369     return (LWRES_R_SUCCESS);
  370 }
  371 
  372 int
  373 lwres_context_getsocket(lwres_context_t *ctx) {
  374     return (ctx->sock);
  375 }
  376 
  377 lwres_result_t
  378 lwres_context_send(lwres_context_t *ctx,
  379            void *sendbase, int sendlen) {
  380     int ret;
  381     lwres_result_t lwresult;
  382 
  383     if (ctx->sock == -1) {
  384         lwresult = context_connect(ctx);
  385         if (lwresult != LWRES_R_SUCCESS)
  386             return (lwresult);
  387         INSIST(ctx->sock >= 0);
  388     }
  389 
  390     ret = sendto(ctx->sock, sendbase, sendlen, 0, NULL, 0);
  391     if (ret < 0)
  392         return (LWRES_R_IOERROR);
  393     if (ret != sendlen)
  394         return (LWRES_R_IOERROR);
  395 
  396     return (LWRES_R_SUCCESS);
  397 }
  398 
  399 lwres_result_t
  400 lwres_context_recv(lwres_context_t *ctx,
  401            void *recvbase, int recvlen,
  402            int *recvd_len)
  403 {
  404     LWRES_SOCKADDR_LEN_T fromlen;
  405     struct sockaddr_in sin = { .sin_port = 0 };
  406     struct sockaddr_in6 sin6 = { .sin6_port = 0 };
  407     struct sockaddr *sa;
  408     int ret;
  409 
  410     if (ctx->address.family == LWRES_ADDRTYPE_V4) {
  411         sa = (struct sockaddr *)&sin;
  412         fromlen = sizeof(sin);
  413     } else {
  414         sa = (struct sockaddr *)&sin6;
  415         fromlen = sizeof(sin6);
  416     }
  417 
  418     /*
  419      * The address of fromlen is cast to void * to shut up compiler
  420      * warnings, namely on systems that have the sixth parameter
  421      * prototyped as a signed int when LWRES_SOCKADDR_LEN_T is
  422      * defined as unsigned.
  423      */
  424     ret = recvfrom(ctx->sock, recvbase, recvlen, 0, sa, (void *)&fromlen);
  425 
  426     if (ret < 0)
  427         return (LWRES_R_IOERROR);
  428 
  429     if (ret == recvlen)
  430         return (LWRES_R_TOOLARGE);
  431 
  432     /*
  433      * If we got something other than what we expect, have the caller
  434      * wait for another packet.  This can happen if an old result
  435      * comes in, or if someone is sending us random stuff.
  436      */
  437     if (ctx->address.family == LWRES_ADDRTYPE_V4) {
  438         if (fromlen != sizeof(sin)
  439             || memcmp(&sin.sin_addr, ctx->address.address,
  440                   sizeof(sin.sin_addr)) != 0
  441             || sin.sin_port != htons(lwres_udp_port))
  442             return (LWRES_R_RETRY);
  443     } else {
  444         if (fromlen != sizeof(sin6)
  445             || memcmp(&sin6.sin6_addr, ctx->address.address,
  446                   sizeof(sin6.sin6_addr)) != 0
  447             || sin6.sin6_port != htons(lwres_udp_port))
  448             return (LWRES_R_RETRY);
  449     }
  450 
  451     if (recvd_len != NULL)
  452         *recvd_len = ret;
  453 
  454     return (LWRES_R_SUCCESS);
  455 }
  456 
  457 /*% performs I/O for the context ctx. */
  458 lwres_result_t
  459 lwres_context_sendrecv(lwres_context_t *ctx,
  460                void *sendbase, int sendlen,
  461                void *recvbase, int recvlen,
  462                int *recvd_len)
  463 {
  464     lwres_result_t result;
  465     int ret2;
  466     fd_set readfds;
  467     struct timeval timeout;
  468 
  469     /*
  470      * Type of tv_sec is 32 bits long.
  471      */
  472     if (ctx->timeout <= 0x7FFFFFFFU)
  473         timeout.tv_sec = (int)ctx->timeout;
  474     else
  475         timeout.tv_sec = 0x7FFFFFFF;
  476 
  477     timeout.tv_usec = 0;
  478 
  479     result = lwres_context_send(ctx, sendbase, sendlen);
  480     if (result != LWRES_R_SUCCESS)
  481         return (result);
  482 
  483     /*
  484      * If this is not checked, select() can overflow,
  485      * causing corruption elsewhere.
  486      */
  487     if (ctx->sock >= (int)FD_SETSIZE) {
  488         close(ctx->sock);
  489         ctx->sock = -1;
  490         return (LWRES_R_IOERROR);
  491     }
  492 
  493  again:
  494     FD_ZERO(&readfds);
  495     FD_SET(ctx->sock, &readfds);
  496     ret2 = select(ctx->sock + 1, &readfds, NULL, NULL, &timeout);
  497 
  498     /*
  499      * What happened with select?
  500      */
  501     if (ret2 < 0)
  502         return (LWRES_R_IOERROR);
  503     if (ret2 == 0)
  504         return (LWRES_R_TIMEOUT);
  505 
  506     result = lwres_context_recv(ctx, recvbase, recvlen, recvd_len);
  507     if (result == LWRES_R_RETRY)
  508         goto again;
  509 
  510     return (result);
  511 }