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