rndc.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2015  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 2000-2003  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /*! \file */
00019 
00020 /*
00021  * Principal Author: DCL
00022  */
00023 
00024 #include <config.h>
00025 
00026 #include <stdlib.h>
00027 
00028 #include <isc/app.h>
00029 #include <isc/buffer.h>
00030 #include <isc/commandline.h>
00031 #include <isc/file.h>
00032 #include <isc/log.h>
00033 #include <isc/net.h>
00034 #include <isc/mem.h>
00035 #include <isc/random.h>
00036 #include <isc/socket.h>
00037 #include <isc/stdtime.h>
00038 #include <isc/string.h>
00039 #include <isc/task.h>
00040 #include <isc/thread.h>
00041 #include <isc/util.h>
00042 
00043 #include <isccfg/namedconf.h>
00044 
00045 #include <isccc/alist.h>
00046 #include <isccc/base64.h>
00047 #include <isccc/cc.h>
00048 #include <isccc/ccmsg.h>
00049 #include <isccc/result.h>
00050 #include <isccc/sexpr.h>
00051 #include <isccc/types.h>
00052 #include <isccc/util.h>
00053 
00054 #include <dns/name.h>
00055 
00056 #include <bind9/getaddresses.h>
00057 
00058 #include "util.h"
00059 
00060 #define SERVERADDRS 10
00061 
00062 const char *progname;
00063 isc_boolean_t verbose;
00064 
00065 static const char *admin_conffile;
00066 static const char *admin_keyfile;
00067 static const char *version = VERSION;
00068 static const char *servername = NULL;
00069 static isc_sockaddr_t serveraddrs[SERVERADDRS];
00070 static isc_sockaddr_t local4, local6;
00071 static isc_boolean_t local4set = ISC_FALSE, local6set = ISC_FALSE;
00072 static int nserveraddrs;
00073 static int currentaddr = 0;
00074 static unsigned int remoteport = 0;
00075 static isc_socketmgr_t *socketmgr = NULL;
00076 static isc_buffer_t *databuf;
00077 static isccc_ccmsg_t ccmsg;
00078 static isc_uint32_t algorithm;
00079 static isccc_region_t secret;
00080 static isc_boolean_t failed = ISC_FALSE;
00081 static isc_boolean_t c_flag = ISC_FALSE;
00082 static isc_mem_t *rndc_mctx;
00083 static int sends, recvs, connects;
00084 static char *command;
00085 static char *args;
00086 static char program[256];
00087 static isc_socket_t *sock = NULL;
00088 static isc_uint32_t serial;
00089 static isc_boolean_t quiet = ISC_FALSE;
00090 
00091 static void rndc_startconnect(isc_sockaddr_t *addr, isc_task_t *task);
00092 
00093 ISC_PLATFORM_NORETURN_PRE static void
00094 usage(int status) ISC_PLATFORM_NORETURN_POST;
00095 
00096 static void
00097 usage(int status) {
00098         fprintf(stderr, "\
00099 Usage: %s [-b address] [-c config] [-s server] [-p port]\n\
00100         [-k key-file ] [-y key] [-V] command\n\
00101 \n\
00102 command is one of the following:\n\
00103 \n\
00104   addzone zone [class [view]] { zone-options }\n\
00105                 Add zone to given view. Requires new-zone-file option.\n\
00106   delzone [-clean] zone [class [view]]\n\
00107                 Removes zone from given view. Requires new-zone-file option.\n\
00108   dumpdb [-all|-cache|-zones] [view ...]\n\
00109                 Dump cache(s) to the dump file (named_dump.db).\n\
00110   flush         Flushes all of the server's caches.\n\
00111   flush [view]  Flushes the server's cache for a view.\n\
00112   flushname name [view]\n\
00113                 Flush the given name from the server's cache(s)\n\
00114   flushtree name [view]\n\
00115                 Flush all names under the given name from the server's cache(s)\n\
00116   freeze        Suspend updates to all dynamic zones.\n\
00117   freeze zone [class [view]]\n\
00118                 Suspend updates to a dynamic zone.\n\
00119   halt          Stop the server without saving pending updates.\n\
00120   halt -p       Stop the server without saving pending updates reporting\n\
00121                 process id.\n\
00122   loadkeys zone [class [view]]\n\
00123                 Update keys without signing immediately.\n\
00124   notify zone [class [view]]\n\
00125                 Resend NOTIFY messages for the zone.\n\
00126   notrace       Set debugging level to 0.\n\
00127   nta -dump\n\
00128                 List all negative trust anchors.\n\
00129   nta [-lifetime duration] [-force] domain [view]\n\
00130                 Set a negative trust anchor, disabling DNSSEC validation\n\
00131                 for the given domain.\n\
00132                 Using -lifetime specifies the duration of the NTA, up\n\
00133                 to one day.\n\
00134                 Using -force prevents the NTA from expiring before its\n\
00135                 full lifetime, even if the domain can validate sooner.\n\
00136   nta -remove domain [view]\n\
00137                 Remove a negative trust anchor, re-enabling validation\n\
00138                 for the given domain.\n\
00139   querylog newstate\n\
00140                 Enable / disable query logging.\n\
00141   reconfig      Reload configuration file and new zones only.\n\
00142   recursing     Dump the queries that are currently recursing (named.recursing)\n\
00143   refresh zone [class [view]]\n\
00144                 Schedule immediate maintenance for a zone.\n\
00145   reload        Reload configuration file and zones.\n\
00146   reload zone [class [view]]\n\
00147                 Reload a single zone.\n\
00148   retransfer zone [class [view]]\n\
00149                 Retransfer a single zone without checking serial number.\n\
00150   scan          Scan available network interfaces for changes.\n\
00151   secroots [view ...]\n\
00152                 Write security roots to the secroots file.\n\
00153   sign zone [class [view]]\n\
00154                 Update zone keys, and sign as needed.\n\
00155   signing -clear all zone [class [view]]\n\
00156                 Remove the private records for all keys that have\n\
00157                 finished signing the given zone.\n\
00158   signing -clear <keyid>/<algorithm> zone [class [view]]\n\
00159                 Remove the private record that indicating the given key\n\
00160                 has finished signing the given zone.\n\
00161   signing -list zone [class [view]]\n\
00162                 List the private records showing the state of DNSSEC\n\
00163                 signing in the given zone.\n\
00164   signing -nsec3param hash flags iterations salt zone [class [view]]\n\
00165                 Add NSEC3 chain to zone if already signed.\n\
00166                 Prime zone with NSEC3 chain if not yet signed.\n\
00167   signing -nsec3param none zone [class [view]]\n\
00168                 Remove NSEC3 chains from zone.\n\
00169   stats         Write server statistics to the statistics file.\n\
00170   status        Display status of the server.\n\
00171   stop          Save pending updates to master files and stop the server.\n\
00172   stop -p       Save pending updates to master files and stop the server\n\
00173                 reporting process id.\n\
00174   sync [-clean] Dump changes to all dynamic zones to disk, and optionally\n\
00175                 remove their journal files.\n\
00176   sync [-clean] zone [class [view]]\n\
00177                 Dump a single zone's changes to disk, and optionally\n\
00178                 remove its journal file.\n\
00179   thaw          Enable updates to all dynamic zones and reload them.\n\
00180   thaw zone [class [view]]\n\
00181                 Enable updates to a frozen dynamic zone and reload it.\n\
00182   trace         Increment debugging level by one.\n\
00183   trace level   Change the debugging level.\n\
00184   tsig-delete keyname [view]\n\
00185                 Delete a TKEY-negotiated TSIG key.\n\
00186   tsig-list     List all currently active TSIG keys, including both statically\n\
00187                 configured and TKEY-negotiated keys.\n\
00188   validation newstate [view]\n\
00189                 Enable / disable DNSSEC validation.\n\
00190   zonestatus zone [class [view]]\n\
00191                 Display the current status of a zone.\n\
00192 \n\
00193 Version: %s\n",
00194                 progname, version);
00195 
00196         exit(status);
00197 }
00198 
00199 static void
00200 get_addresses(const char *host, in_port_t port) {
00201         isc_result_t result;
00202         int found = 0, count;
00203 
00204         if (*host == '/') {
00205                 result = isc_sockaddr_frompath(&serveraddrs[nserveraddrs],
00206                                                host);
00207                 if (result == ISC_R_SUCCESS)
00208                         nserveraddrs++;
00209         } else {
00210                 count = SERVERADDRS - nserveraddrs;
00211                 result = bind9_getaddresses(host, port,
00212                                             &serveraddrs[nserveraddrs],
00213                                             count, &found);
00214                 nserveraddrs += found;
00215         }
00216         if (result != ISC_R_SUCCESS)
00217                 fatal("couldn't get address for '%s': %s",
00218                       host, isc_result_totext(result));
00219         INSIST(nserveraddrs > 0);
00220 }
00221 
00222 static void
00223 rndc_senddone(isc_task_t *task, isc_event_t *event) {
00224         isc_socketevent_t *sevent = (isc_socketevent_t *)event;
00225 
00226         UNUSED(task);
00227 
00228         sends--;
00229         if (sevent->result != ISC_R_SUCCESS)
00230                 fatal("send failed: %s", isc_result_totext(sevent->result));
00231         isc_event_free(&event);
00232         if (sends == 0 && recvs == 0) {
00233                 isc_socket_detach(&sock);
00234                 isc_task_shutdown(task);
00235                 RUNTIME_CHECK(isc_app_shutdown() == ISC_R_SUCCESS);
00236         }
00237 }
00238 
00239 static void
00240 rndc_recvdone(isc_task_t *task, isc_event_t *event) {
00241         isccc_sexpr_t *response = NULL;
00242         isccc_sexpr_t *data;
00243         isccc_region_t source;
00244         char *errormsg = NULL;
00245         char *textmsg = NULL;
00246         isc_result_t result;
00247 
00248         recvs--;
00249 
00250         if (ccmsg.result == ISC_R_EOF)
00251                 fatal("connection to remote host closed\n"
00252                       "This may indicate that\n"
00253                       "* the remote server is using an older version of"
00254                       " the command protocol,\n"
00255                       "* this host is not authorized to connect,\n"
00256                       "* the clocks are not synchronized, or\n"
00257                       "* the key is invalid.");
00258 
00259         if (ccmsg.result != ISC_R_SUCCESS)
00260                 fatal("recv failed: %s", isc_result_totext(ccmsg.result));
00261 
00262         source.rstart = isc_buffer_base(&ccmsg.buffer);
00263         source.rend = isc_buffer_used(&ccmsg.buffer);
00264 
00265         DO("parse message",
00266            isccc_cc_fromwire(&source, &response, algorithm, &secret));
00267 
00268         data = isccc_alist_lookup(response, "_data");
00269         if (data == NULL)
00270                 fatal("no data section in response");
00271         result = isccc_cc_lookupstring(data, "err", &errormsg);
00272         if (result == ISC_R_SUCCESS) {
00273                 failed = ISC_TRUE;
00274                 fprintf(stderr, "%s: '%s' failed: %s\n",
00275                         progname, command, errormsg);
00276         }
00277         else if (result != ISC_R_NOTFOUND)
00278                 fprintf(stderr, "%s: parsing response failed: %s\n",
00279                         progname, isc_result_totext(result));
00280 
00281         result = isccc_cc_lookupstring(data, "text", &textmsg);
00282         if (result == ISC_R_SUCCESS) {
00283                 if ((!quiet || failed) && strlen(textmsg) != 0U)
00284                         fprintf(failed ? stderr : stdout, "%s\n", textmsg);
00285         } else if (result != ISC_R_NOTFOUND)
00286                 fprintf(stderr, "%s: parsing response failed: %s\n",
00287                         progname, isc_result_totext(result));
00288 
00289         isc_event_free(&event);
00290         isccc_sexpr_free(&response);
00291         if (sends == 0 && recvs == 0) {
00292                 isc_socket_detach(&sock);
00293                 isc_task_shutdown(task);
00294                 RUNTIME_CHECK(isc_app_shutdown() == ISC_R_SUCCESS);
00295         }
00296 }
00297 
00298 static void
00299 rndc_recvnonce(isc_task_t *task, isc_event_t *event) {
00300         isccc_sexpr_t *response = NULL;
00301         isccc_sexpr_t *_ctrl;
00302         isccc_region_t source;
00303         isc_result_t result;
00304         isc_uint32_t nonce;
00305         isccc_sexpr_t *request = NULL;
00306         isccc_time_t now;
00307         isc_region_t r;
00308         isccc_sexpr_t *data;
00309         isc_buffer_t b;
00310 
00311         recvs--;
00312 
00313         if (ccmsg.result == ISC_R_EOF)
00314                 fatal("connection to remote host closed\n"
00315                       "This may indicate that\n"
00316                       "* the remote server is using an older version of"
00317                       " the command protocol,\n"
00318                       "* this host is not authorized to connect,\n"
00319                       "* the clocks are not synchronized,\n"
00320                       "* the the key signing algorithm is incorrect, or\n"
00321                       "* the key is invalid.");
00322 
00323         if (ccmsg.result != ISC_R_SUCCESS)
00324                 fatal("recv failed: %s", isc_result_totext(ccmsg.result));
00325 
00326         source.rstart = isc_buffer_base(&ccmsg.buffer);
00327         source.rend = isc_buffer_used(&ccmsg.buffer);
00328 
00329         DO("parse message",
00330            isccc_cc_fromwire(&source, &response, algorithm, &secret));
00331 
00332         _ctrl = isccc_alist_lookup(response, "_ctrl");
00333         if (_ctrl == NULL)
00334                 fatal("_ctrl section missing");
00335         nonce = 0;
00336         if (isccc_cc_lookupuint32(_ctrl, "_nonce", &nonce) != ISC_R_SUCCESS)
00337                 nonce = 0;
00338 
00339         isc_stdtime_get(&now);
00340 
00341         DO("create message", isccc_cc_createmessage(1, NULL, NULL, ++serial,
00342                                                     now, now + 60, &request));
00343         data = isccc_alist_lookup(request, "_data");
00344         if (data == NULL)
00345                 fatal("_data section missing");
00346         if (isccc_cc_definestring(data, "type", args) == NULL)
00347                 fatal("out of memory");
00348         if (nonce != 0) {
00349                 _ctrl = isccc_alist_lookup(request, "_ctrl");
00350                 if (_ctrl == NULL)
00351                         fatal("_ctrl section missing");
00352                 if (isccc_cc_defineuint32(_ctrl, "_nonce", nonce) == NULL)
00353                         fatal("out of memory");
00354         }
00355 
00356         isc_buffer_clear(databuf);
00357         /* Skip the length field (4 bytes) */
00358         isc_buffer_add(databuf, 4);
00359 
00360         DO("render message",
00361            isccc_cc_towire(request, &databuf, algorithm, &secret));
00362 
00363         isc_buffer_init(&b, databuf->base, 4);
00364         isc_buffer_putuint32(&b, databuf->used - 4);
00365 
00366         r.base = databuf->base;
00367         r.length = databuf->used;
00368 
00369         isccc_ccmsg_cancelread(&ccmsg);
00370         DO("schedule recv", isccc_ccmsg_readmessage(&ccmsg, task,
00371                                                     rndc_recvdone, NULL));
00372         recvs++;
00373         DO("send message", isc_socket_send(sock, &r, task, rndc_senddone,
00374                                            NULL));
00375         sends++;
00376 
00377         isc_event_free(&event);
00378         isccc_sexpr_free(&response);
00379         return;
00380 }
00381 
00382 static void
00383 rndc_connected(isc_task_t *task, isc_event_t *event) {
00384         char socktext[ISC_SOCKADDR_FORMATSIZE];
00385         isc_socketevent_t *sevent = (isc_socketevent_t *)event;
00386         isccc_sexpr_t *request = NULL;
00387         isccc_sexpr_t *data;
00388         isccc_time_t now;
00389         isc_region_t r;
00390         isc_buffer_t b;
00391         isc_result_t result;
00392 
00393         connects--;
00394 
00395         if (sevent->result != ISC_R_SUCCESS) {
00396                 isc_sockaddr_format(&serveraddrs[currentaddr], socktext,
00397                                     sizeof(socktext));
00398                 if (sevent->result != ISC_R_CANCELED &&
00399                     ++currentaddr < nserveraddrs)
00400                 {
00401                         notify("connection failed: %s: %s", socktext,
00402                                isc_result_totext(sevent->result));
00403                         isc_socket_detach(&sock);
00404                         isc_event_free(&event);
00405                         rndc_startconnect(&serveraddrs[currentaddr], task);
00406                         return;
00407                 } else
00408                         fatal("connect failed: %s: %s", socktext,
00409                               isc_result_totext(sevent->result));
00410         }
00411 
00412         isc_stdtime_get(&now);
00413         DO("create message", isccc_cc_createmessage(1, NULL, NULL, ++serial,
00414                                                     now, now + 60, &request));
00415         data = isccc_alist_lookup(request, "_data");
00416         if (data == NULL)
00417                 fatal("_data section missing");
00418         if (isccc_cc_definestring(data, "type", "null") == NULL)
00419                 fatal("out of memory");
00420 
00421         isc_buffer_clear(databuf);
00422         /* Skip the length field (4 bytes) */
00423         isc_buffer_add(databuf, 4);
00424 
00425         DO("render message",
00426            isccc_cc_towire(request, &databuf, algorithm, &secret));
00427 
00428         isc_buffer_init(&b, databuf->base, 4);
00429         isc_buffer_putuint32(&b, databuf->used - 4);
00430 
00431         r.base = databuf->base;
00432         r.length = databuf->used;
00433 
00434         isccc_ccmsg_init(rndc_mctx, sock, &ccmsg);
00435         isccc_ccmsg_setmaxsize(&ccmsg, 1024 * 1024);
00436 
00437         DO("schedule recv", isccc_ccmsg_readmessage(&ccmsg, task,
00438                                                     rndc_recvnonce, NULL));
00439         recvs++;
00440         DO("send message", isc_socket_send(sock, &r, task, rndc_senddone,
00441                                            NULL));
00442         sends++;
00443         isc_event_free(&event);
00444 }
00445 
00446 static void
00447 rndc_startconnect(isc_sockaddr_t *addr, isc_task_t *task) {
00448         isc_result_t result;
00449         int pf;
00450         isc_sockettype_t type;
00451 
00452         char socktext[ISC_SOCKADDR_FORMATSIZE];
00453 
00454         isc_sockaddr_format(addr, socktext, sizeof(socktext));
00455 
00456         notify("using server %s (%s)", servername, socktext);
00457 
00458         pf = isc_sockaddr_pf(addr);
00459         if (pf == AF_INET || pf == AF_INET6)
00460                 type = isc_sockettype_tcp;
00461         else
00462                 type = isc_sockettype_unix;
00463         DO("create socket", isc_socket_create(socketmgr, pf, type, &sock));
00464         switch (isc_sockaddr_pf(addr)) {
00465         case AF_INET:
00466                 DO("bind socket", isc_socket_bind(sock, &local4, 0));
00467                 break;
00468         case AF_INET6:
00469                 DO("bind socket", isc_socket_bind(sock, &local6, 0));
00470                 break;
00471         default:
00472                 break;
00473         }
00474         DO("connect", isc_socket_connect(sock, addr, task, rndc_connected,
00475                                          NULL));
00476         connects++;
00477 }
00478 
00479 static void
00480 rndc_start(isc_task_t *task, isc_event_t *event) {
00481         isc_event_free(&event);
00482 
00483         currentaddr = 0;
00484         rndc_startconnect(&serveraddrs[currentaddr], task);
00485 }
00486 
00487 static void
00488 parse_config(isc_mem_t *mctx, isc_log_t *log, const char *keyname,
00489              cfg_parser_t **pctxp, cfg_obj_t **configp)
00490 {
00491         isc_result_t result;
00492         const char *conffile = admin_conffile;
00493         const cfg_obj_t *addresses = NULL;
00494         const cfg_obj_t *defkey = NULL;
00495         const cfg_obj_t *options = NULL;
00496         const cfg_obj_t *servers = NULL;
00497         const cfg_obj_t *server = NULL;
00498         const cfg_obj_t *keys = NULL;
00499         const cfg_obj_t *key = NULL;
00500         const cfg_obj_t *defport = NULL;
00501         const cfg_obj_t *secretobj = NULL;
00502         const cfg_obj_t *algorithmobj = NULL;
00503         cfg_obj_t *config = NULL;
00504         const cfg_obj_t *address = NULL;
00505         const cfg_listelt_t *elt;
00506         const char *secretstr;
00507         const char *algorithmstr;
00508         static char secretarray[1024];
00509         const cfg_type_t *conftype = &cfg_type_rndcconf;
00510         isc_boolean_t key_only = ISC_FALSE;
00511         const cfg_listelt_t *element;
00512 
00513         if (! isc_file_exists(conffile)) {
00514                 conffile = admin_keyfile;
00515                 conftype = &cfg_type_rndckey;
00516 
00517                 if (c_flag)
00518                         fatal("%s does not exist", admin_conffile);
00519 
00520                 if (! isc_file_exists(conffile))
00521                         fatal("neither %s nor %s was found",
00522                               admin_conffile, admin_keyfile);
00523                 key_only = ISC_TRUE;
00524         } else if (! c_flag && isc_file_exists(admin_keyfile)) {
00525                 fprintf(stderr, "WARNING: key file (%s) exists, but using "
00526                         "default configuration file (%s)\n",
00527                         admin_keyfile, admin_conffile);
00528         }
00529 
00530         DO("create parser", cfg_parser_create(mctx, log, pctxp));
00531 
00532         /*
00533          * The parser will output its own errors, so DO() is not used.
00534          */
00535         result = cfg_parse_file(*pctxp, conffile, conftype, &config);
00536         if (result != ISC_R_SUCCESS)
00537                 fatal("could not load rndc configuration");
00538 
00539         if (!key_only)
00540                 (void)cfg_map_get(config, "options", &options);
00541 
00542         if (key_only && servername == NULL)
00543                 servername = "127.0.0.1";
00544         else if (servername == NULL && options != NULL) {
00545                 const cfg_obj_t *defserverobj = NULL;
00546                 (void)cfg_map_get(options, "default-server", &defserverobj);
00547                 if (defserverobj != NULL)
00548                         servername = cfg_obj_asstring(defserverobj);
00549         }
00550 
00551         if (servername == NULL)
00552                 fatal("no server specified and no default");
00553 
00554         if (!key_only) {
00555                 (void)cfg_map_get(config, "server", &servers);
00556                 if (servers != NULL) {
00557                         for (elt = cfg_list_first(servers);
00558                              elt != NULL;
00559                              elt = cfg_list_next(elt))
00560                         {
00561                                 const char *name;
00562                                 server = cfg_listelt_value(elt);
00563                                 name = cfg_obj_asstring(cfg_map_getname(server));
00564                                 if (strcasecmp(name, servername) == 0)
00565                                         break;
00566                                 server = NULL;
00567                         }
00568                 }
00569         }
00570 
00571         /*
00572          * Look for the name of the key to use.
00573          */
00574         if (keyname != NULL)
00575                 ;               /* Was set on command line, do nothing. */
00576         else if (server != NULL) {
00577                 DO("get key for server", cfg_map_get(server, "key", &defkey));
00578                 keyname = cfg_obj_asstring(defkey);
00579         } else if (options != NULL) {
00580                 DO("get default key", cfg_map_get(options, "default-key",
00581                                                   &defkey));
00582                 keyname = cfg_obj_asstring(defkey);
00583         } else if (!key_only)
00584                 fatal("no key for server and no default");
00585 
00586         /*
00587          * Get the key's definition.
00588          */
00589         if (key_only)
00590                 DO("get key", cfg_map_get(config, "key", &key));
00591         else {
00592                 DO("get config key list", cfg_map_get(config, "key", &keys));
00593                 for (elt = cfg_list_first(keys);
00594                      elt != NULL;
00595                      elt = cfg_list_next(elt))
00596                 {
00597                         key = cfg_listelt_value(elt);
00598                         if (strcasecmp(cfg_obj_asstring(cfg_map_getname(key)),
00599                                        keyname) == 0)
00600                                 break;
00601                 }
00602                 if (elt == NULL)
00603                         fatal("no key definition for name %s", keyname);
00604         }
00605         (void)cfg_map_get(key, "secret", &secretobj);
00606         (void)cfg_map_get(key, "algorithm", &algorithmobj);
00607         if (secretobj == NULL || algorithmobj == NULL)
00608                 fatal("key must have algorithm and secret");
00609 
00610         secretstr = cfg_obj_asstring(secretobj);
00611         algorithmstr = cfg_obj_asstring(algorithmobj);
00612 
00613         if (strcasecmp(algorithmstr, "hmac-md5") == 0)
00614                 algorithm = ISCCC_ALG_HMACMD5;
00615         else if (strcasecmp(algorithmstr, "hmac-sha1") == 0)
00616                 algorithm = ISCCC_ALG_HMACSHA1;
00617         else if (strcasecmp(algorithmstr, "hmac-sha224") == 0)
00618                 algorithm = ISCCC_ALG_HMACSHA224;
00619         else if (strcasecmp(algorithmstr, "hmac-sha256") == 0)
00620                 algorithm = ISCCC_ALG_HMACSHA256;
00621         else if (strcasecmp(algorithmstr, "hmac-sha384") == 0)
00622                 algorithm = ISCCC_ALG_HMACSHA384;
00623         else if (strcasecmp(algorithmstr, "hmac-sha512") == 0)
00624                 algorithm = ISCCC_ALG_HMACSHA512;
00625         else
00626                 fatal("unsupported algorithm: %s", algorithmstr);
00627 
00628         secret.rstart = (unsigned char *)secretarray;
00629         secret.rend = (unsigned char *)secretarray + sizeof(secretarray);
00630         DO("decode base64 secret", isccc_base64_decode(secretstr, &secret));
00631         secret.rend = secret.rstart;
00632         secret.rstart = (unsigned char *)secretarray;
00633 
00634         /*
00635          * Find the port to connect to.
00636          */
00637         if (remoteport != 0)
00638                 ;               /* Was set on command line, do nothing. */
00639         else {
00640                 if (server != NULL)
00641                         (void)cfg_map_get(server, "port", &defport);
00642                 if (defport == NULL && options != NULL)
00643                         (void)cfg_map_get(options, "default-port", &defport);
00644         }
00645         if (defport != NULL) {
00646                 remoteport = cfg_obj_asuint32(defport);
00647                 if (remoteport > 65535 || remoteport == 0)
00648                         fatal("port %u out of range", remoteport);
00649         } else if (remoteport == 0)
00650                 remoteport = NS_CONTROL_PORT;
00651 
00652         if (server != NULL)
00653                 result = cfg_map_get(server, "addresses", &addresses);
00654         else
00655                 result = ISC_R_NOTFOUND;
00656         if (result == ISC_R_SUCCESS) {
00657                 for (element = cfg_list_first(addresses);
00658                      element != NULL;
00659                      element = cfg_list_next(element))
00660                 {
00661                         isc_sockaddr_t sa;
00662 
00663                         address = cfg_listelt_value(element);
00664                         if (!cfg_obj_issockaddr(address)) {
00665                                 unsigned int myport;
00666                                 const char *name;
00667                                 const cfg_obj_t *obj;
00668 
00669                                 obj = cfg_tuple_get(address, "name");
00670                                 name = cfg_obj_asstring(obj);
00671                                 obj = cfg_tuple_get(address, "port");
00672                                 if (cfg_obj_isuint32(obj)) {
00673                                         myport = cfg_obj_asuint32(obj);
00674                                         if (myport > ISC_UINT16_MAX ||
00675                                             myport == 0)
00676                                                 fatal("port %u out of range",
00677                                                       myport);
00678                                 } else
00679                                         myport = remoteport;
00680                                 if (nserveraddrs < SERVERADDRS)
00681                                         get_addresses(name, (in_port_t) myport);
00682                                 else
00683                                         fprintf(stderr, "too many address: "
00684                                                 "%s: dropped\n", name);
00685                                 continue;
00686                         }
00687                         sa = *cfg_obj_assockaddr(address);
00688                         if (isc_sockaddr_getport(&sa) == 0)
00689                                 isc_sockaddr_setport(&sa, remoteport);
00690                         if (nserveraddrs < SERVERADDRS)
00691                                 serveraddrs[nserveraddrs++] = sa;
00692                         else {
00693                                 char socktext[ISC_SOCKADDR_FORMATSIZE];
00694 
00695                                 isc_sockaddr_format(&sa, socktext,
00696                                                     sizeof(socktext));
00697                                 fprintf(stderr,
00698                                         "too many address: %s: dropped\n",
00699                                         socktext);
00700                         }
00701                 }
00702         }
00703 
00704         if (!local4set && server != NULL) {
00705                 address = NULL;
00706                 cfg_map_get(server, "source-address", &address);
00707                 if (address != NULL) {
00708                         local4 = *cfg_obj_assockaddr(address);
00709                         local4set = ISC_TRUE;
00710                 }
00711         }
00712         if (!local4set && options != NULL) {
00713                 address = NULL;
00714                 cfg_map_get(options, "default-source-address", &address);
00715                 if (address != NULL) {
00716                         local4 = *cfg_obj_assockaddr(address);
00717                         local4set = ISC_TRUE;
00718                 }
00719         }
00720 
00721         if (!local6set && server != NULL) {
00722                 address = NULL;
00723                 cfg_map_get(server, "source-address-v6", &address);
00724                 if (address != NULL) {
00725                         local6 = *cfg_obj_assockaddr(address);
00726                         local6set = ISC_TRUE;
00727                 }
00728         }
00729         if (!local6set && options != NULL) {
00730                 address = NULL;
00731                 cfg_map_get(options, "default-source-address-v6", &address);
00732                 if (address != NULL) {
00733                         local6 = *cfg_obj_assockaddr(address);
00734                         local6set = ISC_TRUE;
00735                 }
00736         }
00737 
00738         *configp = config;
00739 }
00740 
00741 int
00742 main(int argc, char **argv) {
00743         isc_result_t result = ISC_R_SUCCESS;
00744         isc_boolean_t show_final_mem = ISC_FALSE;
00745         isc_taskmgr_t *taskmgr = NULL;
00746         isc_task_t *task = NULL;
00747         isc_log_t *log = NULL;
00748         isc_logconfig_t *logconfig = NULL;
00749         isc_logdestination_t logdest;
00750         cfg_parser_t *pctx = NULL;
00751         cfg_obj_t *config = NULL;
00752         const char *keyname = NULL;
00753         struct in_addr in;
00754         struct in6_addr in6;
00755         char *p;
00756         size_t argslen;
00757         int ch;
00758         int i;
00759 
00760         result = isc_file_progname(*argv, program, sizeof(program));
00761         if (result != ISC_R_SUCCESS)
00762                 memmove(program, "rndc", 5);
00763         progname = program;
00764 
00765         admin_conffile = RNDC_CONFFILE;
00766         admin_keyfile = RNDC_KEYFILE;
00767 
00768         isc_sockaddr_any(&local4);
00769         isc_sockaddr_any6(&local6);
00770 
00771         result = isc_app_start();
00772         if (result != ISC_R_SUCCESS)
00773                 fatal("isc_app_start() failed: %s", isc_result_totext(result));
00774 
00775         isc_commandline_errprint = ISC_FALSE;
00776 
00777         while ((ch = isc_commandline_parse(argc, argv, "b:c:hk:Mmp:qs:Vy:"))
00778                != -1) {
00779                 switch (ch) {
00780                 case 'b':
00781                         if (inet_pton(AF_INET, isc_commandline_argument,
00782                                       &in) == 1) {
00783                                 isc_sockaddr_fromin(&local4, &in, 0);
00784                                 local4set = ISC_TRUE;
00785                         } else if (inet_pton(AF_INET6, isc_commandline_argument,
00786                                              &in6) == 1) {
00787                                 isc_sockaddr_fromin6(&local6, &in6, 0);
00788                                 local6set = ISC_TRUE;
00789                         }
00790                         break;
00791 
00792                 case 'c':
00793                         admin_conffile = isc_commandline_argument;
00794                         c_flag = ISC_TRUE;
00795                         break;
00796 
00797                 case 'k':
00798                         admin_keyfile = isc_commandline_argument;
00799                         break;
00800 
00801                 case 'M':
00802                         isc_mem_debugging = ISC_MEM_DEBUGTRACE;
00803                         break;
00804 
00805                 case 'm':
00806                         show_final_mem = ISC_TRUE;
00807                         break;
00808 
00809                 case 'p':
00810                         remoteport = atoi(isc_commandline_argument);
00811                         if (remoteport > 65535 || remoteport == 0)
00812                                 fatal("port '%s' out of range",
00813                                       isc_commandline_argument);
00814                         break;
00815 
00816                 case 'q':
00817                         quiet = ISC_TRUE;
00818                         break;
00819 
00820                 case 's':
00821                         servername = isc_commandline_argument;
00822                         break;
00823 
00824                 case 'V':
00825                         verbose = ISC_TRUE;
00826                         break;
00827 
00828                 case 'y':
00829                         keyname = isc_commandline_argument;
00830                         break;
00831 
00832                 case '?':
00833                         if (isc_commandline_option != '?') {
00834                                 fprintf(stderr, "%s: invalid argument -%c\n",
00835                                         program, isc_commandline_option);
00836                                 usage(1);
00837                         }
00838                         /* FALLTHROUGH */
00839                 case 'h':
00840                         usage(0);
00841                         break;
00842                 default:
00843                         fprintf(stderr, "%s: unhandled option -%c\n",
00844                                 program, isc_commandline_option);
00845                         exit(1);
00846                 }
00847         }
00848 
00849         argc -= isc_commandline_index;
00850         argv += isc_commandline_index;
00851 
00852         if (argc < 1)
00853                 usage(1);
00854 
00855         isc_random_get(&serial);
00856 
00857         DO("create memory context", isc_mem_create(0, 0, &rndc_mctx));
00858         DO("create socket manager", isc_socketmgr_create(rndc_mctx, &socketmgr));
00859         DO("create task manager", isc_taskmgr_create(rndc_mctx, 1, 0, &taskmgr));
00860         DO("create task", isc_task_create(taskmgr, 0, &task));
00861 
00862         DO("create logging context", isc_log_create(rndc_mctx, &log, &logconfig));
00863         isc_log_setcontext(log);
00864         DO("setting log tag", isc_log_settag(logconfig, progname));
00865         logdest.file.stream = stderr;
00866         logdest.file.name = NULL;
00867         logdest.file.versions = ISC_LOG_ROLLNEVER;
00868         logdest.file.maximum_size = 0;
00869         DO("creating log channel",
00870            isc_log_createchannel(logconfig, "stderr",
00871                                  ISC_LOG_TOFILEDESC, ISC_LOG_INFO, &logdest,
00872                                  ISC_LOG_PRINTTAG|ISC_LOG_PRINTLEVEL));
00873         DO("enabling log channel", isc_log_usechannel(logconfig, "stderr",
00874                                                       NULL, NULL));
00875 
00876         parse_config(rndc_mctx, log, keyname, &pctx, &config);
00877 
00878         isccc_result_register();
00879 
00880         command = *argv;
00881 
00882         DO("allocate data buffer",
00883            isc_buffer_allocate(rndc_mctx, &databuf, 2048));
00884 
00885         /*
00886          * Convert argc/argv into a space-delimited command string
00887          * similar to what the user might enter in interactive mode
00888          * (if that were implemented).
00889          */
00890         argslen = 0;
00891         for (i = 0; i < argc; i++)
00892                 argslen += strlen(argv[i]) + 1;
00893 
00894         args = isc_mem_get(rndc_mctx, argslen);
00895         if (args == NULL)
00896                 DO("isc_mem_get", ISC_R_NOMEMORY);
00897 
00898         p = args;
00899         for (i = 0; i < argc; i++) {
00900                 size_t len = strlen(argv[i]);
00901                 memmove(p, argv[i], len);
00902                 p += len;
00903                 *p++ = ' ';
00904         }
00905 
00906         p--;
00907         *p++ = '\0';
00908         INSIST(p == args + argslen);
00909 
00910         notify("%s", command);
00911 
00912         if (strcmp(command, "restart") == 0)
00913                 fatal("'%s' is not implemented", command);
00914 
00915         if (nserveraddrs == 0)
00916                 get_addresses(servername, (in_port_t) remoteport);
00917 
00918         DO("post event", isc_app_onrun(rndc_mctx, task, rndc_start, NULL));
00919 
00920         result = isc_app_run();
00921         if (result != ISC_R_SUCCESS)
00922                 fatal("isc_app_run() failed: %s", isc_result_totext(result));
00923 
00924         if (connects > 0 || sends > 0 || recvs > 0)
00925                 isc_socket_cancel(sock, task, ISC_SOCKCANCEL_ALL);
00926 
00927         isc_task_detach(&task);
00928         isc_taskmgr_destroy(&taskmgr);
00929         isc_socketmgr_destroy(&socketmgr);
00930         isc_log_destroy(&log);
00931         isc_log_setcontext(NULL);
00932 
00933         cfg_obj_destroy(pctx, &config);
00934         cfg_parser_destroy(&pctx);
00935 
00936         isc_mem_put(rndc_mctx, args, argslen);
00937         isccc_ccmsg_invalidate(&ccmsg);
00938 
00939         dns_name_destroy();
00940 
00941         isc_buffer_free(&databuf);
00942 
00943         if (show_final_mem)
00944                 isc_mem_stats(rndc_mctx, stderr);
00945 
00946         isc_mem_destroy(&rndc_mctx);
00947 
00948         if (failed)
00949                 return (1);
00950 
00951         return (0);
00952 }

Generated on Tue Apr 28 17:40:55 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha