xref: /netbsd-src/external/mpl/bind/dist/bin/rndc/rndc.c (revision 5dd36a3bc8bf2a9dec29ceb6349550414570c447)
1 /*	$NetBSD: rndc.c,v 1.3 2019/01/09 16:55:00 christos 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