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