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