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