"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.11.23/bin/rndc/rndc.c" (7 Sep 2020, 27669 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 "rndc.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 9.17.4_vs_9.17.5.

    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 /*! \file */
   13 
   14 #include <config.h>
   15 
   16 #include <inttypes.h>
   17 #include <stdbool.h>
   18 #include <stdlib.h>
   19 
   20 #include <isc/app.h>
   21 #include <isc/buffer.h>
   22 #include <isc/commandline.h>
   23 #include <isc/file.h>
   24 #include <isc/log.h>
   25 #include <isc/net.h>
   26 #include <isc/mem.h>
   27 #include <isc/print.h>
   28 #include <isc/random.h>
   29 #include <isc/socket.h>
   30 #include <isc/stdtime.h>
   31 #include <isc/string.h>
   32 #include <isc/task.h>
   33 #include <isc/thread.h>
   34 #include <isc/util.h>
   35 
   36 #include <pk11/site.h>
   37 
   38 #include <isccfg/namedconf.h>
   39 
   40 #include <isccc/alist.h>
   41 #include <isccc/base64.h>
   42 #include <isccc/cc.h>
   43 #include <isccc/ccmsg.h>
   44 #include <isccc/result.h>
   45 #include <isccc/sexpr.h>
   46 #include <isccc/types.h>
   47 #include <isccc/util.h>
   48 
   49 #include <dns/name.h>
   50 
   51 #include <bind9/getaddresses.h>
   52 
   53 #include "util.h"
   54 
   55 #define SERVERADDRS 10
   56 
   57 const char *progname;
   58 bool verbose;
   59 
   60 static const char *admin_conffile;
   61 static const char *admin_keyfile;
   62 static const char *version = VERSION;
   63 static const char *servername = NULL;
   64 static isc_sockaddr_t serveraddrs[SERVERADDRS];
   65 static isc_sockaddr_t local4, local6;
   66 static bool local4set = false, local6set = false;
   67 static int nserveraddrs;
   68 static int currentaddr = 0;
   69 static unsigned int remoteport = 0;
   70 static isc_socketmgr_t *socketmgr = NULL;
   71 static isc_buffer_t *databuf;
   72 static isccc_ccmsg_t ccmsg;
   73 static uint32_t algorithm;
   74 static isccc_region_t secret;
   75 static bool failed = false;
   76 static bool c_flag = false;
   77 static isc_mem_t *rndc_mctx;
   78 static int sends, recvs, connects;
   79 static char *command;
   80 static char *args;
   81 static char program[256];
   82 static isc_socket_t *sock = NULL;
   83 static uint32_t serial;
   84 static bool quiet = false;
   85 static bool showresult = false;
   86 
   87 static void rndc_startconnect(isc_sockaddr_t *addr, isc_task_t *task);
   88 
   89 ISC_PLATFORM_NORETURN_PRE static void
   90 usage(int status) ISC_PLATFORM_NORETURN_POST;
   91 
   92 static void
   93 usage(int status) {
   94     fprintf(stderr, "\
   95 Usage: %s [-b address] [-c config] [-s server] [-p port]\n\
   96     [-k key-file ] [-y key] [-r] [-V] command\n\
   97 \n\
   98 command is one of the following:\n\
   99 \n\
  100   addzone zone [class [view]] { zone-options }\n\
  101         Add zone to given view. Requires allow-new-zones option.\n\
  102   delzone [-clean] zone [class [view]]\n\
  103         Removes zone from given view.\n\
  104   dnstap -reopen\n\
  105         Close, truncate and re-open the DNSTAP output file.\n\
  106   dnstap -roll count\n\
  107         Close, rename and re-open the DNSTAP output file(s).\n\
  108   dumpdb [-all|-cache|-zones|-adb|-bad|-fail] [view ...]\n\
  109         Dump cache(s) to the dump file (named_dump.db).\n\
  110   flush     Flushes all of the server's caches.\n\
  111   flush [view]  Flushes the server's cache for a view.\n\
  112   flushname name [view]\n\
  113         Flush the given name from the server's cache(s)\n\
  114   flushtree name [view]\n\
  115         Flush all names under the given name from the server's cache(s)\n\
  116   freeze    Suspend updates to all dynamic zones.\n\
  117   freeze zone [class [view]]\n\
  118         Suspend updates to a dynamic zone.\n\
  119   halt      Stop the server without saving pending updates.\n\
  120   halt -p   Stop the server without saving pending updates reporting\n\
  121         process id.\n\
  122   loadkeys zone [class [view]]\n\
  123         Update keys without signing immediately.\n\
  124   managed-keys refresh [class [view]]\n\
  125         Check trust anchor for RFC 5011 key changes\n\
  126   managed-keys status [class [view]]\n\
  127         Display RFC 5011 managed keys information\n\
  128   managed-keys sync [class [view]]\n\
  129         Write RFC 5011 managed keys to disk\n\
  130   modzone zone [class [view]] { zone-options }\n\
  131         Modify a zone's configuration.\n\
  132         Requires allow-new-zones option.\n\
  133   notify zone [class [view]]\n\
  134         Resend NOTIFY messages for the zone.\n\
  135   notrace   Set debugging level to 0.\n\
  136   nta -dump\n\
  137         List all negative trust anchors.\n\
  138   nta [-lifetime duration] [-force] domain [view]\n\
  139         Set a negative trust anchor, disabling DNSSEC validation\n\
  140         for the given domain.\n\
  141         Using -lifetime specifies the duration of the NTA, up\n\
  142         to one week.\n\
  143         Using -force prevents the NTA from expiring before its\n\
  144         full lifetime, even if the domain can validate sooner.\n\
  145   nta -remove domain [view]\n\
  146         Remove a negative trust anchor, re-enabling validation\n\
  147         for the given domain.\n\
  148   querylog [ on | off ]\n\
  149         Enable / disable query logging.\n\
  150   reconfig  Reload configuration file and new zones only.\n\
  151   recursing Dump the queries that are currently recursing (named.recursing)\n\
  152   refresh zone [class [view]]\n\
  153         Schedule immediate maintenance for a zone.\n\
  154   reload    Reload configuration file and zones.\n\
  155   reload zone [class [view]]\n\
  156         Reload a single zone.\n\
  157   retransfer zone [class [view]]\n\
  158         Retransfer a single zone without checking serial number.\n\
  159   scan      Scan available network interfaces for changes.\n\
  160   secroots [view ...]\n\
  161         Write security roots to the secroots file.\n\
  162   showzone zone [class [view]]\n\
  163         Print a zone's configuration.\n\
  164   sign zone [class [view]]\n\
  165         Update zone keys, and sign as needed.\n\
  166   signing -clear all zone [class [view]]\n\
  167         Remove the private records for all keys that have\n\
  168         finished signing the given zone.\n\
  169   signing -clear <keyid>/<algorithm> zone [class [view]]\n\
  170         Remove the private record that indicating the given key\n\
  171         has finished signing the given zone.\n\
  172   signing -list zone [class [view]]\n\
  173         List the private records showing the state of DNSSEC\n\
  174         signing in the given zone.\n\
  175   signing -nsec3param hash flags iterations salt zone [class [view]]\n\
  176         Add NSEC3 chain to zone if already signed.\n\
  177         Prime zone with NSEC3 chain if not yet signed.\n\
  178   signing -nsec3param none zone [class [view]]\n\
  179         Remove NSEC3 chains from zone.\n\
  180   signing -serial <value> zone [class [view]]\n\
  181         Set the zones's serial to <value>.\n\
  182   stats     Write server statistics to the statistics file.\n\
  183   status    Display status of the server.\n\
  184   stop      Save pending updates to master files and stop the server.\n\
  185   stop -p   Save pending updates to master files and stop the server\n\
  186         reporting process id.\n\
  187   sync [-clean] Dump changes to all dynamic zones to disk, and optionally\n\
  188         remove their journal files.\n\
  189   sync [-clean] zone [class [view]]\n\
  190         Dump a single zone's changes to disk, and optionally\n\
  191         remove its journal file.\n\
  192   thaw      Enable updates to all dynamic zones and reload them.\n\
  193   thaw zone [class [view]]\n\
  194         Enable updates to a frozen dynamic zone and reload it.\n\
  195   trace     Increment debugging level by one.\n\
  196   trace level   Change the debugging level.\n\
  197   tsig-delete keyname [view]\n\
  198         Delete a TKEY-negotiated TSIG key.\n\
  199   tsig-list List all currently active TSIG keys, including both statically\n\
  200         configured and TKEY-negotiated keys.\n\
  201   validation [ yes | no | status ] [view]\n\
  202         Enable / disable DNSSEC validation.\n\
  203   zonestatus zone [class [view]]\n\
  204         Display the current status of a zone.\n\
  205 \n\
  206 Version: %s\n",
  207         progname, version);
  208 
  209     exit(status);
  210 }
  211 
  212 static void
  213 get_addresses(const char *host, in_port_t port) {
  214     isc_result_t result;
  215     int found = 0, count;
  216 
  217     REQUIRE(host != NULL);
  218 
  219     if (*host == '/') {
  220         result = isc_sockaddr_frompath(&serveraddrs[nserveraddrs],
  221                            host);
  222         if (result == ISC_R_SUCCESS)
  223             nserveraddrs++;
  224     } else {
  225         count = SERVERADDRS - nserveraddrs;
  226         result = bind9_getaddresses(host, port,
  227                         &serveraddrs[nserveraddrs],
  228                         count, &found);
  229         nserveraddrs += found;
  230     }
  231     if (result != ISC_R_SUCCESS)
  232         fatal("couldn't get address for '%s': %s",
  233               host, isc_result_totext(result));
  234     INSIST(nserveraddrs > 0);
  235 }
  236 
  237 static void
  238 rndc_senddone(isc_task_t *task, isc_event_t *event) {
  239     isc_socketevent_t *sevent = (isc_socketevent_t *)event;
  240 
  241     UNUSED(task);
  242 
  243     sends--;
  244     if (sevent->result != ISC_R_SUCCESS)
  245         fatal("send failed: %s", isc_result_totext(sevent->result));
  246     isc_event_free(&event);
  247     if (sends == 0 && recvs == 0) {
  248         isc_socket_detach(&sock);
  249         isc_task_shutdown(task);
  250         RUNTIME_CHECK(isc_app_shutdown() == ISC_R_SUCCESS);
  251     }
  252 }
  253 
  254 static void
  255 rndc_recvdone(isc_task_t *task, isc_event_t *event) {
  256     isccc_sexpr_t *response = NULL;
  257     isccc_sexpr_t *data;
  258     isccc_region_t source;
  259     char *errormsg = NULL;
  260     char *textmsg = NULL;
  261     isc_result_t result;
  262 
  263     recvs--;
  264 
  265     if (ccmsg.result == ISC_R_EOF)
  266         fatal("connection to remote host closed\n"
  267               "This may indicate that\n"
  268               "* the remote server is using an older version of"
  269               " the command protocol,\n"
  270               "* this host is not authorized to connect,\n"
  271               "* the clocks are not synchronized, or\n"
  272               "* the key is invalid.");
  273 
  274     if (ccmsg.result != ISC_R_SUCCESS)
  275         fatal("recv failed: %s", isc_result_totext(ccmsg.result));
  276 
  277     source.rstart = isc_buffer_base(&ccmsg.buffer);
  278     source.rend = isc_buffer_used(&ccmsg.buffer);
  279 
  280     DO("parse message",
  281        isccc_cc_fromwire(&source, &response, algorithm, &secret));
  282 
  283     data = isccc_alist_lookup(response, "_data");
  284     if (!isccc_alist_alistp(data))
  285         fatal("bad or missing data section in response");
  286     result = isccc_cc_lookupstring(data, "err", &errormsg);
  287     if (result == ISC_R_SUCCESS) {
  288         failed = true;
  289         fprintf(stderr, "%s: '%s' failed: %s\n",
  290             progname, command, errormsg);
  291     }
  292     else if (result != ISC_R_NOTFOUND)
  293         fprintf(stderr, "%s: parsing response failed: %s\n",
  294             progname, isc_result_totext(result));
  295 
  296     result = isccc_cc_lookupstring(data, "text", &textmsg);
  297     if (result == ISC_R_SUCCESS) {
  298         if ((!quiet || failed) && strlen(textmsg) != 0U)
  299             fprintf(failed ? stderr : stdout, "%s\n", textmsg);
  300     } else if (result != ISC_R_NOTFOUND)
  301         fprintf(stderr, "%s: parsing response failed: %s\n",
  302             progname, isc_result_totext(result));
  303 
  304     if (showresult) {
  305         isc_result_t eresult;
  306 
  307         result = isccc_cc_lookupuint32(data, "result", &eresult);
  308         if (result == ISC_R_SUCCESS)
  309             printf("%s %u\n", isc_result_toid(eresult), eresult);
  310         else
  311             printf("NONE -1\n");
  312     }
  313 
  314     isc_event_free(&event);
  315     isccc_sexpr_free(&response);
  316     if (sends == 0 && recvs == 0) {
  317         isc_socket_detach(&sock);
  318         isc_task_shutdown(task);
  319         RUNTIME_CHECK(isc_app_shutdown() == ISC_R_SUCCESS);
  320     }
  321 }
  322 
  323 static void
  324 rndc_recvnonce(isc_task_t *task, isc_event_t *event) {
  325     isccc_sexpr_t *response = NULL;
  326     isccc_sexpr_t *_ctrl;
  327     isccc_region_t source;
  328     isc_result_t result;
  329     uint32_t nonce;
  330     isccc_sexpr_t *request = NULL;
  331     isccc_time_t now;
  332     isc_region_t r;
  333     isccc_sexpr_t *data;
  334     isc_buffer_t b;
  335 
  336     recvs--;
  337 
  338     if (ccmsg.result == ISC_R_EOF)
  339         fatal("connection to remote host closed\n"
  340               "This may indicate that\n"
  341               "* the remote server is using an older version of"
  342               " the command protocol,\n"
  343               "* this host is not authorized to connect,\n"
  344               "* the clocks are not synchronized,\n"
  345               "* the key signing algorithm is incorrect, or\n"
  346               "* the key is invalid.");
  347 
  348     if (ccmsg.result != ISC_R_SUCCESS)
  349         fatal("recv failed: %s", isc_result_totext(ccmsg.result));
  350 
  351     source.rstart = isc_buffer_base(&ccmsg.buffer);
  352     source.rend = isc_buffer_used(&ccmsg.buffer);
  353 
  354     DO("parse message",
  355        isccc_cc_fromwire(&source, &response, algorithm, &secret));
  356 
  357     _ctrl = isccc_alist_lookup(response, "_ctrl");
  358     if (!isccc_alist_alistp(_ctrl))
  359         fatal("bad or missing ctrl section in response");
  360     nonce = 0;
  361     if (isccc_cc_lookupuint32(_ctrl, "_nonce", &nonce) != ISC_R_SUCCESS)
  362         nonce = 0;
  363 
  364     isc_stdtime_get(&now);
  365 
  366     DO("create message", isccc_cc_createmessage(1, NULL, NULL, ++serial,
  367                             now, now + 60, &request));
  368     data = isccc_alist_lookup(request, "_data");
  369     if (data == NULL)
  370         fatal("_data section missing");
  371     if (isccc_cc_definestring(data, "type", args) == NULL)
  372         fatal("out of memory");
  373     if (nonce != 0) {
  374         _ctrl = isccc_alist_lookup(request, "_ctrl");
  375         if (_ctrl == NULL)
  376             fatal("_ctrl section missing");
  377         if (isccc_cc_defineuint32(_ctrl, "_nonce", nonce) == NULL)
  378             fatal("out of memory");
  379     }
  380 
  381     isc_buffer_clear(databuf);
  382     /* Skip the length field (4 bytes) */
  383     isc_buffer_add(databuf, 4);
  384 
  385     DO("render message",
  386        isccc_cc_towire(request, &databuf, algorithm, &secret));
  387 
  388     isc_buffer_init(&b, databuf->base, 4);
  389     isc_buffer_putuint32(&b, databuf->used - 4);
  390 
  391     r.base = databuf->base;
  392     r.length = databuf->used;
  393 
  394     isccc_ccmsg_cancelread(&ccmsg);
  395     DO("schedule recv", isccc_ccmsg_readmessage(&ccmsg, task,
  396                             rndc_recvdone, NULL));
  397     recvs++;
  398     DO("send message", isc_socket_send(sock, &r, task, rndc_senddone,
  399                        NULL));
  400     sends++;
  401 
  402     isc_event_free(&event);
  403     isccc_sexpr_free(&response);
  404     isccc_sexpr_free(&request);
  405     return;
  406 }
  407 
  408 static void
  409 rndc_connected(isc_task_t *task, isc_event_t *event) {
  410     char socktext[ISC_SOCKADDR_FORMATSIZE];
  411     isc_socketevent_t *sevent = (isc_socketevent_t *)event;
  412     isccc_sexpr_t *request = NULL;
  413     isccc_sexpr_t *data;
  414     isccc_time_t now;
  415     isc_region_t r;
  416     isc_buffer_t b;
  417     isc_result_t result;
  418 
  419     connects--;
  420 
  421     if (sevent->result != ISC_R_SUCCESS) {
  422         isc_sockaddr_format(&serveraddrs[currentaddr], socktext,
  423                     sizeof(socktext));
  424         if (sevent->result != ISC_R_CANCELED &&
  425             ++currentaddr < nserveraddrs)
  426         {
  427             notify("connection failed: %s: %s", socktext,
  428                    isc_result_totext(sevent->result));
  429             isc_socket_detach(&sock);
  430             isc_event_free(&event);
  431             rndc_startconnect(&serveraddrs[currentaddr], task);
  432             return;
  433         } else
  434             fatal("connect failed: %s: %s", socktext,
  435                   isc_result_totext(sevent->result));
  436     }
  437 
  438     isc_stdtime_get(&now);
  439     DO("create message", isccc_cc_createmessage(1, NULL, NULL, ++serial,
  440                             now, now + 60, &request));
  441     data = isccc_alist_lookup(request, "_data");
  442     if (data == NULL)
  443         fatal("_data section missing");
  444     if (isccc_cc_definestring(data, "type", "null") == NULL)
  445         fatal("out of memory");
  446 
  447     isc_buffer_clear(databuf);
  448     /* Skip the length field (4 bytes) */
  449     isc_buffer_add(databuf, 4);
  450 
  451     DO("render message",
  452        isccc_cc_towire(request, &databuf, algorithm, &secret));
  453 
  454     isc_buffer_init(&b, databuf->base, 4);
  455     isc_buffer_putuint32(&b, databuf->used - 4);
  456 
  457     r.base = databuf->base;
  458     r.length = databuf->used;
  459 
  460     isccc_ccmsg_init(rndc_mctx, sock, &ccmsg);
  461     isccc_ccmsg_setmaxsize(&ccmsg, 1024 * 1024);
  462 
  463     DO("schedule recv", isccc_ccmsg_readmessage(&ccmsg, task,
  464                             rndc_recvnonce, NULL));
  465     recvs++;
  466     DO("send message", isc_socket_send(sock, &r, task, rndc_senddone,
  467                        NULL));
  468     sends++;
  469     isc_event_free(&event);
  470     isccc_sexpr_free(&request);
  471 }
  472 
  473 static void
  474 rndc_startconnect(isc_sockaddr_t *addr, isc_task_t *task) {
  475     isc_result_t result;
  476     int pf;
  477     isc_sockettype_t type;
  478 
  479     char socktext[ISC_SOCKADDR_FORMATSIZE];
  480 
  481     isc_sockaddr_format(addr, socktext, sizeof(socktext));
  482 
  483     notify("using server %s (%s)", servername, socktext);
  484 
  485     pf = isc_sockaddr_pf(addr);
  486     if (pf == AF_INET || pf == AF_INET6)
  487         type = isc_sockettype_tcp;
  488     else
  489         type = isc_sockettype_unix;
  490     DO("create socket", isc_socket_create(socketmgr, pf, type, &sock));
  491     switch (isc_sockaddr_pf(addr)) {
  492     case AF_INET:
  493         DO("bind socket", isc_socket_bind(sock, &local4, 0));
  494         break;
  495     case AF_INET6:
  496         DO("bind socket", isc_socket_bind(sock, &local6, 0));
  497         break;
  498     default:
  499         break;
  500     }
  501     DO("connect", isc_socket_connect(sock, addr, task, rndc_connected,
  502                      NULL));
  503     connects++;
  504 }
  505 
  506 static void
  507 rndc_start(isc_task_t *task, isc_event_t *event) {
  508     isc_event_free(&event);
  509 
  510     currentaddr = 0;
  511     rndc_startconnect(&serveraddrs[currentaddr], task);
  512 }
  513 
  514 static void
  515 parse_config(isc_mem_t *mctx, isc_log_t *log, const char *keyname,
  516          cfg_parser_t **pctxp, cfg_obj_t **configp)
  517 {
  518     isc_result_t result;
  519     const char *conffile = admin_conffile;
  520     const cfg_obj_t *addresses = NULL;
  521     const cfg_obj_t *defkey = NULL;
  522     const cfg_obj_t *options = NULL;
  523     const cfg_obj_t *servers = NULL;
  524     const cfg_obj_t *server = NULL;
  525     const cfg_obj_t *keys = NULL;
  526     const cfg_obj_t *key = NULL;
  527     const cfg_obj_t *defport = NULL;
  528     const cfg_obj_t *secretobj = NULL;
  529     const cfg_obj_t *algorithmobj = NULL;
  530     cfg_obj_t *config = NULL;
  531     const cfg_obj_t *address = NULL;
  532     const cfg_listelt_t *elt;
  533     const char *secretstr;
  534     const char *algorithmstr;
  535     static char secretarray[1024];
  536     const cfg_type_t *conftype = &cfg_type_rndcconf;
  537     bool key_only = false;
  538     const cfg_listelt_t *element;
  539 
  540     if (! isc_file_exists(conffile)) {
  541         conffile = admin_keyfile;
  542         conftype = &cfg_type_rndckey;
  543 
  544         if (c_flag)
  545             fatal("%s does not exist", admin_conffile);
  546 
  547         if (! isc_file_exists(conffile))
  548             fatal("neither %s nor %s was found",
  549                   admin_conffile, admin_keyfile);
  550         key_only = true;
  551     } else if (! c_flag && isc_file_exists(admin_keyfile)) {
  552         fprintf(stderr, "WARNING: key file (%s) exists, but using "
  553             "default configuration file (%s)\n",
  554             admin_keyfile, admin_conffile);
  555     }
  556 
  557     DO("create parser", cfg_parser_create(mctx, log, pctxp));
  558 
  559     /*
  560      * The parser will output its own errors, so DO() is not used.
  561      */
  562     result = cfg_parse_file(*pctxp, conffile, conftype, &config);
  563     if (result != ISC_R_SUCCESS)
  564         fatal("could not load rndc configuration");
  565 
  566     if (!key_only)
  567         (void)cfg_map_get(config, "options", &options);
  568 
  569     if (key_only && servername == NULL)
  570         servername = "127.0.0.1";
  571     else if (servername == NULL && options != NULL) {
  572         const cfg_obj_t *defserverobj = NULL;
  573         (void)cfg_map_get(options, "default-server", &defserverobj);
  574         if (defserverobj != NULL)
  575             servername = cfg_obj_asstring(defserverobj);
  576     }
  577 
  578     if (servername == NULL)
  579         fatal("no server specified and no default");
  580 
  581     if (!key_only) {
  582         (void)cfg_map_get(config, "server", &servers);
  583         if (servers != NULL) {
  584             for (elt = cfg_list_first(servers);
  585                  elt != NULL;
  586                  elt = cfg_list_next(elt))
  587             {
  588                 const char *name;
  589                 server = cfg_listelt_value(elt);
  590                 name = cfg_obj_asstring(cfg_map_getname(server));
  591                 if (strcasecmp(name, servername) == 0)
  592                     break;
  593                 server = NULL;
  594             }
  595         }
  596     }
  597 
  598     /*
  599      * Look for the name of the key to use.
  600      */
  601     if (keyname != NULL)
  602         ;       /* Was set on command line, do nothing. */
  603     else if (server != NULL) {
  604         DO("get key for server", cfg_map_get(server, "key", &defkey));
  605         keyname = cfg_obj_asstring(defkey);
  606     } else if (options != NULL) {
  607         DO("get default key", cfg_map_get(options, "default-key",
  608                           &defkey));
  609         keyname = cfg_obj_asstring(defkey);
  610     } else if (!key_only)
  611         fatal("no key for server and no default");
  612 
  613     /*
  614      * Get the key's definition.
  615      */
  616     if (key_only)
  617         DO("get key", cfg_map_get(config, "key", &key));
  618     else {
  619         DO("get config key list", cfg_map_get(config, "key", &keys));
  620         for (elt = cfg_list_first(keys);
  621              elt != NULL;
  622              elt = cfg_list_next(elt))
  623         {
  624             key = cfg_listelt_value(elt);
  625             if (strcasecmp(cfg_obj_asstring(cfg_map_getname(key)),
  626                        keyname) == 0)
  627                 break;
  628         }
  629         if (elt == NULL)
  630             fatal("no key definition for name %s", keyname);
  631     }
  632     (void)cfg_map_get(key, "secret", &secretobj);
  633     (void)cfg_map_get(key, "algorithm", &algorithmobj);
  634     if (secretobj == NULL || algorithmobj == NULL)
  635         fatal("key must have algorithm and secret");
  636 
  637     secretstr = cfg_obj_asstring(secretobj);
  638     algorithmstr = cfg_obj_asstring(algorithmobj);
  639 
  640 #ifndef PK11_MD5_DISABLE
  641     if (strcasecmp(algorithmstr, "hmac-md5") == 0)
  642         algorithm = ISCCC_ALG_HMACMD5;
  643     else
  644 #endif
  645     if (strcasecmp(algorithmstr, "hmac-sha1") == 0)
  646         algorithm = ISCCC_ALG_HMACSHA1;
  647     else if (strcasecmp(algorithmstr, "hmac-sha224") == 0)
  648         algorithm = ISCCC_ALG_HMACSHA224;
  649     else if (strcasecmp(algorithmstr, "hmac-sha256") == 0)
  650         algorithm = ISCCC_ALG_HMACSHA256;
  651     else if (strcasecmp(algorithmstr, "hmac-sha384") == 0)
  652         algorithm = ISCCC_ALG_HMACSHA384;
  653     else if (strcasecmp(algorithmstr, "hmac-sha512") == 0)
  654         algorithm = ISCCC_ALG_HMACSHA512;
  655     else
  656         fatal("unsupported algorithm: %s", algorithmstr);
  657 
  658     secret.rstart = (unsigned char *)secretarray;
  659     secret.rend = (unsigned char *)secretarray + sizeof(secretarray);
  660     DO("decode base64 secret", isccc_base64_decode(secretstr, &secret));
  661     secret.rend = secret.rstart;
  662     secret.rstart = (unsigned char *)secretarray;
  663 
  664     /*
  665      * Find the port to connect to.
  666      */
  667     if (remoteport != 0)
  668         ;       /* Was set on command line, do nothing. */
  669     else {
  670         if (server != NULL)
  671             (void)cfg_map_get(server, "port", &defport);
  672         if (defport == NULL && options != NULL)
  673             (void)cfg_map_get(options, "default-port", &defport);
  674     }
  675     if (defport != NULL) {
  676         remoteport = cfg_obj_asuint32(defport);
  677         if (remoteport > 65535 || remoteport == 0)
  678             fatal("port %u out of range", remoteport);
  679     } else if (remoteport == 0)
  680         remoteport = NS_CONTROL_PORT;
  681 
  682     if (server != NULL)
  683         result = cfg_map_get(server, "addresses", &addresses);
  684     else
  685         result = ISC_R_NOTFOUND;
  686     if (result == ISC_R_SUCCESS) {
  687         for (element = cfg_list_first(addresses);
  688              element != NULL;
  689              element = cfg_list_next(element))
  690         {
  691             isc_sockaddr_t sa;
  692 
  693             address = cfg_listelt_value(element);
  694             if (!cfg_obj_issockaddr(address)) {
  695                 unsigned int myport;
  696                 const char *name;
  697                 const cfg_obj_t *obj;
  698 
  699                 obj = cfg_tuple_get(address, "name");
  700                 name = cfg_obj_asstring(obj);
  701                 obj = cfg_tuple_get(address, "port");
  702                 if (cfg_obj_isuint32(obj)) {
  703                     myport = cfg_obj_asuint32(obj);
  704                     if (myport > UINT16_MAX ||
  705                         myport == 0)
  706                         fatal("port %u out of range",
  707                               myport);
  708                 } else
  709                     myport = remoteport;
  710                 if (nserveraddrs < SERVERADDRS)
  711                     get_addresses(name, (in_port_t) myport);
  712                 else
  713                     fprintf(stderr, "too many address: "
  714                         "%s: dropped\n", name);
  715                 continue;
  716             }
  717             sa = *cfg_obj_assockaddr(address);
  718             if (isc_sockaddr_getport(&sa) == 0)
  719                 isc_sockaddr_setport(&sa, remoteport);
  720             if (nserveraddrs < SERVERADDRS)
  721                 serveraddrs[nserveraddrs++] = sa;
  722             else {
  723                 char socktext[ISC_SOCKADDR_FORMATSIZE];
  724 
  725                 isc_sockaddr_format(&sa, socktext,
  726                             sizeof(socktext));
  727                 fprintf(stderr,
  728                     "too many address: %s: dropped\n",
  729                     socktext);
  730             }
  731         }
  732     }
  733 
  734     if (!local4set && server != NULL) {
  735         address = NULL;
  736         cfg_map_get(server, "source-address", &address);
  737         if (address != NULL) {
  738             local4 = *cfg_obj_assockaddr(address);
  739             local4set = true;
  740         }
  741     }
  742     if (!local4set && options != NULL) {
  743         address = NULL;
  744         cfg_map_get(options, "default-source-address", &address);
  745         if (address != NULL) {
  746             local4 = *cfg_obj_assockaddr(address);
  747             local4set = true;
  748         }
  749     }
  750 
  751     if (!local6set && server != NULL) {
  752         address = NULL;
  753         cfg_map_get(server, "source-address-v6", &address);
  754         if (address != NULL) {
  755             local6 = *cfg_obj_assockaddr(address);
  756             local6set = true;
  757         }
  758     }
  759     if (!local6set && options != NULL) {
  760         address = NULL;
  761         cfg_map_get(options, "default-source-address-v6", &address);
  762         if (address != NULL) {
  763             local6 = *cfg_obj_assockaddr(address);
  764             local6set = true;
  765         }
  766     }
  767 
  768     *configp = config;
  769 }
  770 
  771 int
  772 main(int argc, char **argv) {
  773     isc_result_t result = ISC_R_SUCCESS;
  774     bool show_final_mem = false;
  775     isc_taskmgr_t *taskmgr = NULL;
  776     isc_task_t *task = NULL;
  777     isc_log_t *log = NULL;
  778     isc_logconfig_t *logconfig = NULL;
  779     isc_logdestination_t logdest;
  780     cfg_parser_t *pctx = NULL;
  781     cfg_obj_t *config = NULL;
  782     const char *keyname = NULL;
  783     struct in_addr in;
  784     struct in6_addr in6;
  785     char *p;
  786     size_t argslen;
  787     int ch;
  788     int i;
  789 
  790     result = isc_file_progname(*argv, program, sizeof(program));
  791     if (result != ISC_R_SUCCESS)
  792         memmove(program, "rndc", 5);
  793     progname = program;
  794 
  795     admin_conffile = RNDC_CONFFILE;
  796     admin_keyfile = RNDC_KEYFILE;
  797 
  798     isc_sockaddr_any(&local4);
  799     isc_sockaddr_any6(&local6);
  800 
  801     result = isc_app_start();
  802     if (result != ISC_R_SUCCESS)
  803         fatal("isc_app_start() failed: %s", isc_result_totext(result));
  804 
  805     isc_commandline_errprint = false;
  806 
  807     while ((ch = isc_commandline_parse(argc, argv, "b:c:hk:Mmp:qrs:Vy:"))
  808            != -1) {
  809         switch (ch) {
  810         case 'b':
  811             if (inet_pton(AF_INET, isc_commandline_argument,
  812                       &in) == 1) {
  813                 isc_sockaddr_fromin(&local4, &in, 0);
  814                 local4set = true;
  815             } else if (inet_pton(AF_INET6, isc_commandline_argument,
  816                          &in6) == 1) {
  817                 isc_sockaddr_fromin6(&local6, &in6, 0);
  818                 local6set = true;
  819             }
  820             break;
  821 
  822         case 'c':
  823             admin_conffile = isc_commandline_argument;
  824             c_flag = true;
  825             break;
  826 
  827         case 'k':
  828             admin_keyfile = isc_commandline_argument;
  829             break;
  830 
  831         case 'M':
  832             isc_mem_debugging = ISC_MEM_DEBUGTRACE;
  833             break;
  834 
  835         case 'm':
  836             show_final_mem = true;
  837             break;
  838 
  839         case 'p':
  840             remoteport = atoi(isc_commandline_argument);
  841             if (remoteport > 65535 || remoteport == 0)
  842                 fatal("port '%s' out of range",
  843                       isc_commandline_argument);
  844             break;
  845 
  846         case 'q':
  847             quiet = true;
  848             break;
  849 
  850         case 'r':
  851             showresult = true;
  852             break;
  853 
  854         case 's':
  855             servername = isc_commandline_argument;
  856             break;
  857 
  858         case 'V':
  859             verbose = true;
  860             break;
  861 
  862         case 'y':
  863             keyname = isc_commandline_argument;
  864             break;
  865 
  866         case '?':
  867             if (isc_commandline_option != '?') {
  868                 fprintf(stderr, "%s: invalid argument -%c\n",
  869                     program, isc_commandline_option);
  870                 usage(1);
  871             }
  872             /* FALLTHROUGH */
  873         case 'h':
  874             usage(0);
  875             break;
  876         default:
  877             fprintf(stderr, "%s: unhandled option -%c\n",
  878                 program, isc_commandline_option);
  879             exit(1);
  880         }
  881     }
  882 
  883     argc -= isc_commandline_index;
  884     argv += isc_commandline_index;
  885 
  886     if (argc < 1)
  887         usage(1);
  888 
  889     isc_random_get(&serial);
  890 
  891     DO("create memory context", isc_mem_create(0, 0, &rndc_mctx));
  892     DO("create socket manager", isc_socketmgr_create(rndc_mctx, &socketmgr));
  893     DO("create task manager", isc_taskmgr_create(rndc_mctx, 1, 0, &taskmgr));
  894     DO("create task", isc_task_create(taskmgr, 0, &task));
  895 
  896     DO("create logging context", isc_log_create(rndc_mctx, &log, &logconfig));
  897     isc_log_setcontext(log);
  898     DO("setting log tag", isc_log_settag(logconfig, progname));
  899     logdest.file.stream = stderr;
  900     logdest.file.name = NULL;
  901     logdest.file.versions = ISC_LOG_ROLLNEVER;
  902     logdest.file.maximum_size = 0;
  903     DO("creating log channel",
  904        isc_log_createchannel(logconfig, "stderr",
  905                  ISC_LOG_TOFILEDESC, ISC_LOG_INFO, &logdest,
  906                  ISC_LOG_PRINTTAG|ISC_LOG_PRINTLEVEL));
  907     DO("enabling log channel", isc_log_usechannel(logconfig, "stderr",
  908                               NULL, NULL));
  909 
  910     parse_config(rndc_mctx, log, keyname, &pctx, &config);
  911 
  912     isccc_result_register();
  913 
  914     command = *argv;
  915 
  916     DO("allocate data buffer",
  917        isc_buffer_allocate(rndc_mctx, &databuf, 2048));
  918 
  919     /*
  920      * Convert argc/argv into a space-delimited command string
  921      * similar to what the user might enter in interactive mode
  922      * (if that were implemented).
  923      */
  924     argslen = 0;
  925     for (i = 0; i < argc; i++)
  926         argslen += strlen(argv[i]) + 1;
  927 
  928     args = isc_mem_get(rndc_mctx, argslen);
  929     if (args == NULL)
  930         DO("isc_mem_get", ISC_R_NOMEMORY);
  931 
  932     p = args;
  933     for (i = 0; i < argc; i++) {
  934         size_t len = strlen(argv[i]);
  935         memmove(p, argv[i], len);
  936         p += len;
  937         *p++ = ' ';
  938     }
  939 
  940     p--;
  941     *p++ = '\0';
  942     INSIST(p == args + argslen);
  943 
  944     notify("%s", command);
  945 
  946     if (strcmp(command, "restart") == 0)
  947         fatal("'%s' is not implemented", command);
  948 
  949     if (nserveraddrs == 0 && servername != NULL) {
  950         get_addresses(servername, (in_port_t) remoteport);
  951     }
  952 
  953     DO("post event", isc_app_onrun(rndc_mctx, task, rndc_start, NULL));
  954 
  955     result = isc_app_run();
  956     if (result != ISC_R_SUCCESS)
  957         fatal("isc_app_run() failed: %s", isc_result_totext(result));
  958 
  959     if (connects > 0 || sends > 0 || recvs > 0)
  960         isc_socket_cancel(sock, task, ISC_SOCKCANCEL_ALL);
  961 
  962     isc_task_detach(&task);
  963     isc_taskmgr_destroy(&taskmgr);
  964     isc_socketmgr_destroy(&socketmgr);
  965     isc_log_destroy(&log);
  966     isc_log_setcontext(NULL);
  967 
  968     cfg_obj_destroy(pctx, &config);
  969     cfg_parser_destroy(&pctx);
  970 
  971     isc_mem_put(rndc_mctx, args, argslen);
  972     isccc_ccmsg_invalidate(&ccmsg);
  973 
  974     dns_name_destroy();
  975 
  976     isc_buffer_free(&databuf);
  977 
  978     if (show_final_mem)
  979         isc_mem_stats(rndc_mctx, stderr);
  980 
  981     isc_mem_destroy(&rndc_mctx);
  982 
  983     if (failed)
  984         return (1);
  985 
  986     return (0);
  987 }