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