"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.11.23/bin/named/lwdgabn.c" (7 Sep 2020, 16289 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 "lwdgabn.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: lwdgabn.c,v 1.24 2009/09/02 23:48:01 tbox Exp $ */
   13 
   14 /*! \file */
   15 
   16 #include <config.h>
   17 
   18 #include <stdlib.h>
   19 
   20 #include <isc/netaddr.h>
   21 #include <isc/sockaddr.h>
   22 #include <isc/socket.h>
   23 #include <isc/string.h>     /* Required for HP/UX (and others?) */
   24 #include <isc/util.h>
   25 
   26 #include <dns/adb.h>
   27 #include <dns/events.h>
   28 #include <dns/result.h>
   29 
   30 #include <named/types.h>
   31 #include <named/lwaddr.h>
   32 #include <named/lwdclient.h>
   33 #include <named/lwresd.h>
   34 #include <named/lwsearch.h>
   35 #include <named/sortlist.h>
   36 
   37 #define NEED_V4(c)  ((((c)->find_wanted & LWRES_ADDRTYPE_V4) != 0) \
   38              && ((c)->v4find == NULL))
   39 #define NEED_V6(c)  ((((c)->find_wanted & LWRES_ADDRTYPE_V6) != 0) \
   40              && ((c)->v6find == NULL))
   41 
   42 static isc_result_t start_find(ns_lwdclient_t *);
   43 static void restart_find(ns_lwdclient_t *);
   44 static void init_gabn(ns_lwdclient_t *);
   45 
   46 /*%
   47  * Destroy any finds.  This can be used to "start over from scratch" and
   48  * should only be called when events are _not_ being generated by the finds.
   49  */
   50 static void
   51 cleanup_gabn(ns_lwdclient_t *client) {
   52     ns_lwdclient_log(50, "cleaning up client %p", client);
   53 
   54     if (client->v6find != NULL) {
   55         if (client->v6find == client->v4find)
   56             client->v6find = NULL;
   57         else
   58             dns_adb_destroyfind(&client->v6find);
   59     }
   60     if (client->v4find != NULL)
   61         dns_adb_destroyfind(&client->v4find);
   62 }
   63 
   64 static void
   65 setup_addresses(ns_lwdclient_t *client, dns_adbfind_t *find, unsigned int at) {
   66     dns_adbaddrinfo_t *ai;
   67     lwres_addr_t *addr;
   68     int af;
   69     const struct sockaddr *sa;
   70     isc_result_t result;
   71 
   72     if (at == DNS_ADBFIND_INET)
   73         af = AF_INET;
   74     else
   75         af = AF_INET6;
   76 
   77     ai = ISC_LIST_HEAD(find->list);
   78     while (ai != NULL && client->gabn.naddrs < LWRES_MAX_ADDRS) {
   79         sa = &ai->sockaddr.type.sa;
   80         if (sa->sa_family != af)
   81             goto next;
   82 
   83         addr = &client->addrs[client->gabn.naddrs];
   84 
   85         result = lwaddr_lwresaddr_fromsockaddr(addr, &ai->sockaddr);
   86         if (result != ISC_R_SUCCESS)
   87             goto next;
   88 
   89         ns_lwdclient_log(50, "adding address %p, family %d, length %d",
   90                  addr->address, addr->family, addr->length);
   91 
   92         client->gabn.naddrs++;
   93         REQUIRE(!LWRES_LINK_LINKED(addr, link));
   94         LWRES_LIST_APPEND(client->gabn.addrs, addr, link);
   95 
   96     next:
   97         ai = ISC_LIST_NEXT(ai, publink);
   98     }
   99 }
  100 
  101 typedef struct {
  102     isc_netaddr_t address;
  103     int rank;
  104 } rankedaddress;
  105 
  106 static int
  107 addr_compare(const void *av, const void *bv) {
  108     const rankedaddress *a = (const rankedaddress *) av;
  109     const rankedaddress *b = (const rankedaddress *) bv;
  110     return (a->rank - b->rank);
  111 }
  112 
  113 static void
  114 sort_addresses(ns_lwdclient_t *client) {
  115     unsigned int naddrs;
  116     rankedaddress *addrs;
  117     isc_netaddr_t remote;
  118     dns_addressorderfunc_t order;
  119     const void *arg;
  120     ns_lwresd_t *lwresd = client->clientmgr->listener->manager;
  121     unsigned int i;
  122     isc_result_t result;
  123 
  124     naddrs = client->gabn.naddrs;
  125 
  126     if (naddrs <= 1 || lwresd->view->sortlist == NULL)
  127         return;
  128 
  129     addrs = isc_mem_get(lwresd->mctx, sizeof(rankedaddress) * naddrs);
  130     if (addrs == NULL)
  131         return;
  132 
  133     isc_netaddr_fromsockaddr(&remote, &client->address);
  134     ns_sortlist_byaddrsetup(lwresd->view->sortlist,
  135                 &remote, &order, &arg);
  136     if (order == NULL) {
  137         isc_mem_put(lwresd->mctx, addrs,
  138                 sizeof(rankedaddress) * naddrs);
  139         return;
  140     }
  141     for (i = 0; i < naddrs; i++) {
  142         result = lwaddr_netaddr_fromlwresaddr(&addrs[i].address,
  143                               &client->addrs[i]);
  144         INSIST(result == ISC_R_SUCCESS);
  145         addrs[i].rank = (*order)(&addrs[i].address, arg);
  146     }
  147     qsort(addrs, naddrs, sizeof(rankedaddress), addr_compare);
  148     for (i = 0; i < naddrs; i++) {
  149         result = lwaddr_lwresaddr_fromnetaddr(&client->addrs[i],
  150                               &addrs[i].address);
  151         INSIST(result == ISC_R_SUCCESS);
  152     }
  153 
  154     isc_mem_put(lwresd->mctx, addrs, sizeof(rankedaddress) * naddrs);
  155 }
  156 
  157 static void
  158 generate_reply(ns_lwdclient_t *client) {
  159     isc_result_t result;
  160     int lwres;
  161     isc_region_t r;
  162     lwres_buffer_t lwb;
  163     ns_lwdclientmgr_t *cm;
  164 
  165     cm = client->clientmgr;
  166     lwb.base = NULL;
  167 
  168     ns_lwdclient_log(50, "generating gabn reply for client %p", client);
  169 
  170     /*
  171      * We must make certain the client->find is not still active.
  172      * If it is either the v4 or v6 answer, just set it to NULL and
  173      * let the cleanup code destroy it.  Otherwise, destroy it now.
  174      */
  175     if (client->find == client->v4find || client->find == client->v6find)
  176         client->find = NULL;
  177     else
  178         if (client->find != NULL)
  179             dns_adb_destroyfind(&client->find);
  180 
  181     /*
  182      * perhaps there are some here?
  183      */
  184     if (NEED_V6(client) && client->v4find != NULL)
  185         client->v6find = client->v4find;
  186 
  187     /*
  188      * Run through the finds we have and wire them up to the gabn
  189      * structure.
  190      */
  191     LWRES_LIST_INIT(client->gabn.addrs);
  192     if (client->v4find != NULL)
  193         setup_addresses(client, client->v4find, DNS_ADBFIND_INET);
  194     if (client->v6find != NULL)
  195         setup_addresses(client, client->v6find, DNS_ADBFIND_INET6);
  196 
  197     /*
  198      * If there are no addresses, try the next element in the search
  199      * path, if there are any more.  Otherwise, fall through into
  200      * the error handling code below.
  201      */
  202     if (client->gabn.naddrs == 0) {
  203         do {
  204             result = ns_lwsearchctx_next(&client->searchctx);
  205             if (result == ISC_R_SUCCESS) {
  206                 cleanup_gabn(client);
  207                 result = start_find(client);
  208                 if (result == ISC_R_SUCCESS)
  209                     return;
  210             }
  211         } while (result == ISC_R_SUCCESS);
  212     }
  213 
  214     /*
  215      * Render the packet.
  216      */
  217     client->pkt.recvlength = LWRES_RECVLENGTH;
  218     client->pkt.authtype = 0; /* XXXMLG */
  219     client->pkt.authlength = 0;
  220 
  221     /*
  222      * If there are no addresses, return failure.
  223      */
  224     if (client->gabn.naddrs != 0)
  225         client->pkt.result = LWRES_R_SUCCESS;
  226     else
  227         client->pkt.result = LWRES_R_NOTFOUND;
  228 
  229     sort_addresses(client);
  230 
  231     lwres = lwres_gabnresponse_render(cm->lwctx, &client->gabn,
  232                       &client->pkt, &lwb);
  233     if (lwres != LWRES_R_SUCCESS)
  234         goto out;
  235 
  236     r.base = lwb.base;
  237     r.length = lwb.used;
  238     client->sendbuf = r.base;
  239     client->sendlength = r.length;
  240     result = ns_lwdclient_sendreply(client, &r);
  241     if (result != ISC_R_SUCCESS)
  242         goto out;
  243 
  244     NS_LWDCLIENT_SETSEND(client);
  245 
  246     /*
  247      * All done!
  248      */
  249     cleanup_gabn(client);
  250 
  251     return;
  252 
  253  out:
  254     cleanup_gabn(client);
  255 
  256     if (lwb.base != NULL)
  257         lwres_context_freemem(client->clientmgr->lwctx,
  258                       lwb.base, lwb.length);
  259 
  260     ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE);
  261 }
  262 
  263 /*
  264  * Take the current real name, move it to an alias slot (if any are
  265  * open) then put this new name in as the real name for the target.
  266  *
  267  * Return success if it can be rendered, otherwise failure.  Note that
  268  * not having enough alias slots open is NOT a failure.
  269  */
  270 static isc_result_t
  271 add_alias(ns_lwdclient_t *client) {
  272     isc_buffer_t b;
  273     isc_result_t result;
  274     uint16_t naliases;
  275 
  276     b = client->recv_buffer;
  277 
  278     /*
  279      * Render the new name to the buffer.
  280      */
  281     result = dns_name_totext(dns_fixedname_name(&client->target_name),
  282                  true, &client->recv_buffer);
  283     if (result != ISC_R_SUCCESS)
  284         return (result);
  285 
  286     /*
  287      * Are there any open slots?
  288      */
  289     naliases = client->gabn.naliases;
  290     if (naliases < LWRES_MAX_ALIASES) {
  291         client->gabn.aliases[naliases] = client->gabn.realname;
  292         client->gabn.aliaslen[naliases] = client->gabn.realnamelen;
  293         client->gabn.naliases++;
  294     }
  295 
  296     /*
  297      * Save this name away as the current real name.
  298      */
  299     client->gabn.realname = (char *)(b.base) + b.used;
  300     client->gabn.realnamelen = client->recv_buffer.used - b.used;
  301 
  302     return (ISC_R_SUCCESS);
  303 }
  304 
  305 static isc_result_t
  306 store_realname(ns_lwdclient_t *client) {
  307     isc_buffer_t b;
  308     isc_result_t result;
  309     dns_name_t *tname;
  310 
  311     b = client->recv_buffer;
  312 
  313     tname = dns_fixedname_name(&client->target_name);
  314     result = ns_lwsearchctx_current(&client->searchctx, tname);
  315     if (result != ISC_R_SUCCESS)
  316         return (result);
  317 
  318     /*
  319      * Render the new name to the buffer.
  320      */
  321     result = dns_name_totext(tname, true, &client->recv_buffer);
  322     if (result != ISC_R_SUCCESS)
  323         return (result);
  324 
  325     /*
  326      * Save this name away as the current real name.
  327      */
  328     client->gabn.realname = (char *) b.base + b.used;
  329     client->gabn.realnamelen = client->recv_buffer.used - b.used;
  330 
  331     return (ISC_R_SUCCESS);
  332 }
  333 
  334 static void
  335 process_gabn_finddone(isc_task_t *task, isc_event_t *ev) {
  336     ns_lwdclient_t *client = ev->ev_arg;
  337     isc_eventtype_t evtype;
  338     bool claimed;
  339 
  340     ns_lwdclient_log(50, "find done for task %p, client %p", task, client);
  341 
  342     evtype = ev->ev_type;
  343     isc_event_free(&ev);
  344 
  345     /*
  346      * No more info to be had?  If so, we have all the good stuff
  347      * right now, so we can render things.
  348      */
  349     claimed = false;
  350     if (evtype == DNS_EVENT_ADBNOMOREADDRESSES) {
  351         if (NEED_V4(client)) {
  352             client->v4find = client->find;
  353             claimed = true;
  354         }
  355         if (NEED_V6(client)) {
  356             client->v6find = client->find;
  357             claimed = true;
  358         }
  359         if (client->find != NULL) {
  360             if (claimed)
  361                 client->find = NULL;
  362             else
  363                 dns_adb_destroyfind(&client->find);
  364 
  365         }
  366         generate_reply(client);
  367         return;
  368     }
  369 
  370     /*
  371      * We probably don't need this find anymore.  We're either going to
  372      * reissue it, or an error occurred.  Either way, we're done with
  373      * it.
  374      */
  375     if ((client->find != client->v4find)
  376         && (client->find != client->v6find)) {
  377         dns_adb_destroyfind(&client->find);
  378     } else {
  379         client->find = NULL;
  380     }
  381 
  382     /*
  383      * We have some new information we can gather.  Run off and fetch
  384      * it.
  385      */
  386     if (evtype == DNS_EVENT_ADBMOREADDRESSES) {
  387         restart_find(client);
  388         return;
  389     }
  390 
  391     /*
  392      * An error or other strangeness happened.  Drop this query.
  393      */
  394     cleanup_gabn(client);
  395     ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE);
  396 }
  397 
  398 static void
  399 restart_find(ns_lwdclient_t *client) {
  400     unsigned int options;
  401     isc_result_t result;
  402     bool claimed;
  403 
  404     ns_lwdclient_log(50, "starting find for client %p", client);
  405 
  406     /*
  407      * Issue a find for the name contained in the request.  We won't
  408      * set the bit that says "anything is good enough" -- we want it
  409      * all.
  410      */
  411     options = 0;
  412     options |= DNS_ADBFIND_WANTEVENT;
  413     options |= DNS_ADBFIND_RETURNLAME;
  414 
  415     /*
  416      * Set the bits up here to mark that we want this address family
  417      * and that we do not currently have a find pending.  We will
  418      * set that bit again below if it turns out we will get an event.
  419      */
  420     if (NEED_V4(client))
  421         options |= DNS_ADBFIND_INET;
  422     if (NEED_V6(client))
  423         options |= DNS_ADBFIND_INET6;
  424 
  425  find_again:
  426     INSIST(client->find == NULL);
  427     result = dns_adb_createfind(client->clientmgr->view->adb,
  428                     client->clientmgr->task,
  429                     process_gabn_finddone, client,
  430                     dns_fixedname_name(&client->target_name),
  431                     dns_rootname, 0, options, 0,
  432                     dns_fixedname_name(&client->target_name),
  433                     client->clientmgr->view->dstport,
  434                     &client->find);
  435 
  436     /*
  437      * Did we get an alias?  If so, save it and re-issue the query.
  438      */
  439     if (result == DNS_R_ALIAS) {
  440         ns_lwdclient_log(50, "found alias, restarting query");
  441         dns_adb_destroyfind(&client->find);
  442         cleanup_gabn(client);
  443         result = add_alias(client);
  444         if (result != ISC_R_SUCCESS) {
  445             ns_lwdclient_log(50,
  446                      "out of buffer space adding alias");
  447             ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE);
  448             return;
  449         }
  450         goto find_again;
  451     }
  452 
  453     ns_lwdclient_log(50, "find returned %d (%s)", result,
  454              isc_result_totext(result));
  455 
  456     /*
  457      * Did we get an error?
  458      */
  459     if (result != ISC_R_SUCCESS) {
  460         if (client->find != NULL)
  461             dns_adb_destroyfind(&client->find);
  462         cleanup_gabn(client);
  463         ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE);
  464         return;
  465     }
  466 
  467     claimed = false;
  468 
  469     /*
  470      * Did we get our answer to V4 addresses?
  471      */
  472     if (NEED_V4(client)
  473         && ((client->find->query_pending & DNS_ADBFIND_INET) == 0)) {
  474         ns_lwdclient_log(50, "client %p ipv4 satisfied by find %p",
  475                  client, client->find);
  476         claimed = true;
  477         client->v4find = client->find;
  478     }
  479 
  480     /*
  481      * Did we get our answer to V6 addresses?
  482      */
  483     if (NEED_V6(client)
  484         && ((client->find->query_pending & DNS_ADBFIND_INET6) == 0)) {
  485         ns_lwdclient_log(50, "client %p ipv6 satisfied by find %p",
  486                  client, client->find);
  487         claimed = true;
  488         client->v6find = client->find;
  489     }
  490 
  491     /*
  492      * If we're going to get an event, set our internal pending flag
  493      * and return.  When we get an event back we'll do the right
  494      * thing, basically by calling this function again, perhaps with a
  495      * new target name.
  496      *
  497      * If we have both v4 and v6, and we are still getting an event,
  498      * we have a programming error, so die hard.
  499      */
  500     if ((client->find->options & DNS_ADBFIND_WANTEVENT) != 0) {
  501         ns_lwdclient_log(50, "event will be sent");
  502         INSIST(client->v4find == NULL || client->v6find == NULL);
  503         return;
  504     }
  505     ns_lwdclient_log(50, "no event will be sent");
  506     if (claimed)
  507         client->find = NULL;
  508     else
  509         dns_adb_destroyfind(&client->find);
  510 
  511     /*
  512      * We seem to have everything we asked for, or at least we are
  513      * able to respond with things we've learned.
  514      */
  515 
  516     generate_reply(client);
  517 }
  518 
  519 static isc_result_t
  520 start_find(ns_lwdclient_t *client) {
  521     isc_result_t result;
  522 
  523     /*
  524      * Initialize the real name and alias arrays in the reply we're
  525      * going to build up.
  526      */
  527     init_gabn(client);
  528 
  529     result = store_realname(client);
  530     if (result != ISC_R_SUCCESS)
  531         return (result);
  532     restart_find(client);
  533     return (ISC_R_SUCCESS);
  534 
  535 }
  536 
  537 static void
  538 init_gabn(ns_lwdclient_t *client) {
  539     int i;
  540 
  541     /*
  542      * Initialize the real name and alias arrays in the reply we're
  543      * going to build up.
  544      */
  545     for (i = 0; i < LWRES_MAX_ALIASES; i++) {
  546         client->aliases[i] = NULL;
  547         client->aliaslen[i] = 0;
  548     }
  549     for (i = 0; i < LWRES_MAX_ADDRS; i++) {
  550         client->addrs[i].family = 0;
  551         client->addrs[i].length = 0;
  552         memset(client->addrs[i].address, 0, LWRES_ADDR_MAXLEN);
  553         LWRES_LINK_INIT(&client->addrs[i], link);
  554     }
  555 
  556     client->gabn.naliases = 0;
  557     client->gabn.naddrs = 0;
  558     client->gabn.realname = NULL;
  559     client->gabn.aliases = client->aliases;
  560     client->gabn.realnamelen = 0;
  561     client->gabn.aliaslen = client->aliaslen;
  562     LWRES_LIST_INIT(client->gabn.addrs);
  563     client->gabn.base = NULL;
  564     client->gabn.baselen = 0;
  565 
  566     /*
  567      * Set up the internal buffer to point to the receive region.
  568      */
  569     isc_buffer_init(&client->recv_buffer, client->buffer, LWRES_RECVLENGTH);
  570 }
  571 
  572 /*
  573  * When we are called, we can be assured that:
  574  *
  575  *  client->sockaddr contains the address we need to reply to,
  576  *
  577  *  client->pkt contains the packet header data,
  578  *
  579  *  the packet "checks out" overall -- any MD5 hashes or crypto
  580  *  bits have been verified,
  581  *
  582  *  "b" points to the remaining data after the packet header
  583  *  was parsed off.
  584  *
  585  *  We are in a the RECVDONE state.
  586  *
  587  * From this state we will enter the SEND state if we happen to have
  588  * everything we need or we need to return an error packet, or to the
  589  * FINDWAIT state if we need to look things up.
  590  */
  591 void
  592 ns_lwdclient_processgabn(ns_lwdclient_t *client, lwres_buffer_t *b) {
  593     isc_result_t result;
  594     lwres_gabnrequest_t *req;
  595     ns_lwdclientmgr_t *cm;
  596     isc_buffer_t namebuf;
  597 
  598     REQUIRE(NS_LWDCLIENT_ISRECVDONE(client));
  599 
  600     cm = client->clientmgr;
  601     req = NULL;
  602 
  603     result = lwres_gabnrequest_parse(client->clientmgr->lwctx,
  604                      b, &client->pkt, &req);
  605     if (result != LWRES_R_SUCCESS)
  606         goto out;
  607     if (req->name == NULL)
  608         goto out;
  609 
  610     isc_buffer_init(&namebuf, req->name, req->namelen);
  611     isc_buffer_add(&namebuf, req->namelen);
  612 
  613     dns_fixedname_init(&client->target_name);
  614     dns_fixedname_init(&client->query_name);
  615     result = dns_name_fromtext(dns_fixedname_name(&client->query_name),
  616                    &namebuf, NULL, 0, NULL);
  617     if (result != ISC_R_SUCCESS)
  618         goto out;
  619     ns_lwsearchctx_init(&client->searchctx,
  620                 cm->listener->manager->search,
  621                 dns_fixedname_name(&client->query_name),
  622                 cm->listener->manager->ndots);
  623     ns_lwsearchctx_first(&client->searchctx);
  624 
  625     client->find_wanted = req->addrtypes;
  626     ns_lwdclient_log(50, "client %p looking for addrtypes %08x",
  627              client, client->find_wanted);
  628 
  629     /*
  630      * We no longer need to keep this around.
  631      */
  632     lwres_gabnrequest_free(client->clientmgr->lwctx, &req);
  633 
  634     /*
  635      * Start the find.
  636      */
  637     result = start_find(client);
  638     if (result != ISC_R_SUCCESS)
  639         goto out;
  640 
  641     return;
  642 
  643     /*
  644      * We're screwed.  Return an error packet to our caller.
  645      */
  646  out:
  647     if (req != NULL)
  648         lwres_gabnrequest_free(client->clientmgr->lwctx, &req);
  649 
  650     ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE);
  651 }