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