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