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