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