2 * Copyright (C) 2004-2014 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000-2003 Internet Software Consortium.
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.
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.
23 * Principal Author: DCL
31 #include <isc/buffer.h>
32 #include <isc/commandline.h>
37 #include <isc/random.h>
38 #include <isc/socket.h>
39 #include <isc/stdtime.h>
40 #include <isc/string.h>
42 #include <isc/thread.h>
45 #include <isccfg/namedconf.h>
47 #include <isccc/alist.h>
48 #include <isccc/base64.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>
58 #include <bind9/getaddresses.h>
62 #define SERVERADDRS 10
65 isc_boolean_t verbose;
67 static const char *admin_conffile;
68 static const char *admin_keyfile;
69 static const char *version = VERSION;
70 static const char *servername = NULL;
71 static isc_sockaddr_t serveraddrs[SERVERADDRS];
72 static isc_sockaddr_t local4, local6;
73 static isc_boolean_t local4set = ISC_FALSE, local6set = ISC_FALSE;
74 static int nserveraddrs;
75 static int currentaddr = 0;
76 static unsigned int remoteport = 0;
77 static isc_socketmgr_t *socketmgr = NULL;
78 static unsigned char databuf[2048];
79 static isccc_ccmsg_t ccmsg;
80 static isccc_region_t secret;
81 static isc_boolean_t failed = ISC_FALSE;
82 static isc_boolean_t c_flag = ISC_FALSE;
83 static isc_mem_t *mctx;
84 static int sends, recvs, connects;
87 static char program[256];
88 static isc_socket_t *sock = NULL;
89 static isc_uint32_t serial;
91 static void rndc_startconnect(isc_sockaddr_t *addr, isc_task_t *task);
93 ISC_PLATFORM_NORETURN_PRE static void
94 usage(int status) ISC_PLATFORM_NORETURN_POST;
99 Usage: %s [-b address] [-c config] [-s server] [-p port]\n\
100 [-k key-file ] [-y key] [-V] command\n\
102 command is one of the following:\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\
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\
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\
179 * == not yet implemented\n\
187 get_addresses(const char *host, in_port_t port) {
189 int found = 0, count;
192 result = isc_sockaddr_frompath(&serveraddrs[nserveraddrs],
194 if (result == ISC_R_SUCCESS)
197 count = SERVERADDRS - nserveraddrs;
198 result = bind9_getaddresses(host, port,
199 &serveraddrs[nserveraddrs],
201 nserveraddrs += found;
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);
210 rndc_senddone(isc_task_t *task, isc_event_t *event) {
211 isc_socketevent_t *sevent = (isc_socketevent_t *)event;
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);
227 rndc_recvdone(isc_task_t *task, isc_event_t *event) {
228 isccc_sexpr_t *response = NULL;
230 isccc_region_t source;
231 char *errormsg = NULL;
232 char *textmsg = NULL;
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.");
246 if (ccmsg.result != ISC_R_SUCCESS)
247 fatal("recv failed: %s", isc_result_totext(ccmsg.result));
249 source.rstart = isc_buffer_base(&ccmsg.buffer);
250 source.rend = isc_buffer_used(&ccmsg.buffer);
252 DO("parse message", isccc_cc_fromwire(&source, &response, &secret));
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) {
260 fprintf(stderr, "%s: '%s' failed: %s\n",
261 progname, command, errormsg);
263 else if (result != ISC_R_NOTFOUND)
264 fprintf(stderr, "%s: parsing response failed: %s\n",
265 progname, isc_result_totext(result));
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));
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);
285 rndc_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;
291 isccc_sexpr_t *request = NULL;
295 isccc_region_t message;
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.");
310 if (ccmsg.result != ISC_R_SUCCESS)
311 fatal("recv failed: %s", isc_result_totext(ccmsg.result));
313 source.rstart = isc_buffer_base(&ccmsg.buffer);
314 source.rend = isc_buffer_used(&ccmsg.buffer);
316 DO("parse message", isccc_cc_fromwire(&source, &response, &secret));
318 _ctrl = isccc_alist_lookup(response, "_ctrl");
319 if (!isccc_alist_alistp(_ctrl))
320 fatal("bad or missing ctrl section in response");
322 if (isccc_cc_lookupuint32(_ctrl, "_nonce", &nonce) != ISC_R_SUCCESS)
325 isc_stdtime_get(&now);
327 DO("create message", isccc_cc_createmessage(1, NULL, NULL, ++serial,
328 now, now + 60, &request));
329 data = isccc_alist_lookup(request, "_data");
331 fatal("_data section missing");
332 if (isccc_cc_definestring(data, "type", args) == NULL)
333 fatal("out of memory");
335 _ctrl = isccc_alist_lookup(request, "_ctrl");
337 fatal("_ctrl section missing");
338 if (isccc_cc_defineuint32(_ctrl, "_nonce", nonce) == NULL)
339 fatal("out of memory");
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);
350 isccc_ccmsg_cancelread(&ccmsg);
351 DO("schedule recv", isccc_ccmsg_readmessage(&ccmsg, task,
352 rndc_recvdone, NULL));
354 DO("send message", isc_socket_send(sock, &r, task, rndc_senddone,
358 isc_event_free(&event);
359 isccc_sexpr_free(&response);
364 rndc_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;
370 isccc_region_t message;
378 if (sevent->result != ISC_R_SUCCESS) {
379 isc_sockaddr_format(&serveraddrs[currentaddr], socktext,
381 if (sevent->result != ISC_R_CANCELED &&
382 ++currentaddr < nserveraddrs)
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);
391 fatal("connect failed: %s: %s", socktext,
392 isc_result_totext(sevent->result));
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");
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);
412 isccc_ccmsg_init(mctx, sock, &ccmsg);
413 isccc_ccmsg_setmaxsize(&ccmsg, 1024 * 1024);
415 DO("schedule recv", isccc_ccmsg_readmessage(&ccmsg, task,
416 rndc_recvnonce, NULL));
418 DO("send message", isc_socket_send(sock, &r, task, rndc_senddone,
421 isc_event_free(&event);
425 rndc_startconnect(isc_sockaddr_t *addr, isc_task_t *task) {
428 isc_sockettype_t type;
430 char socktext[ISC_SOCKADDR_FORMATSIZE];
432 isc_sockaddr_format(addr, socktext, sizeof(socktext));
434 notify("using server %s (%s)", servername, socktext);
436 pf = isc_sockaddr_pf(addr);
437 if (pf == AF_INET || pf == AF_INET6)
438 type = isc_sockettype_tcp;
440 type = isc_sockettype_unix;
441 DO("create socket", isc_socket_create(socketmgr, pf, type, &sock));
442 switch (isc_sockaddr_pf(addr)) {
444 DO("bind socket", isc_socket_bind(sock, &local4, 0));
447 DO("bind socket", isc_socket_bind(sock, &local6, 0));
452 DO("connect", isc_socket_connect(sock, addr, task, rndc_connected,
458 rndc_start(isc_task_t *task, isc_event_t *event) {
459 isc_event_free(&event);
462 rndc_startconnect(&serveraddrs[currentaddr], task);
466 parse_config(isc_mem_t *mctx, isc_log_t *log, const char *keyname,
467 cfg_parser_t **pctxp, cfg_obj_t **configp)
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;
491 if (! isc_file_exists(conffile)) {
492 conffile = admin_keyfile;
493 conftype = &cfg_type_rndckey;
496 fatal("%s does not exist", admin_conffile);
498 if (! isc_file_exists(conffile))
499 fatal("neither %s nor %s was found",
500 admin_conffile, admin_keyfile);
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);
508 DO("create parser", cfg_parser_create(mctx, log, pctxp));
511 * The parser will output its own errors, so DO() is not used.
513 result = cfg_parse_file(*pctxp, conffile, conftype, &config);
514 if (result != ISC_R_SUCCESS)
515 fatal("could not load rndc configuration");
518 (void)cfg_map_get(config, "options", &options);
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);
529 if (servername == NULL)
530 fatal("no server specified and no default");
533 (void)cfg_map_get(config, "server", &servers);
534 if (servers != NULL) {
535 for (elt = cfg_list_first(servers);
537 elt = cfg_list_next(elt))
540 server = cfg_listelt_value(elt);
541 name = cfg_obj_asstring(cfg_map_getname(server));
542 if (strcasecmp(name, servername) == 0)
550 * Look for the name of the key to use.
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",
560 keyname = cfg_obj_asstring(defkey);
561 } else if (!key_only)
562 fatal("no key for server and no default");
565 * Get the key's definition.
568 DO("get key", cfg_map_get(config, "key", &key));
570 DO("get config key list", cfg_map_get(config, "key", &keys));
571 for (elt = cfg_list_first(keys);
573 elt = cfg_list_next(elt))
575 key = cfg_listelt_value(elt);
576 if (strcasecmp(cfg_obj_asstring(cfg_map_getname(key)),
581 fatal("no key definition for name %s", keyname);
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");
588 secretstr = cfg_obj_asstring(secretobj);
589 algorithm = cfg_obj_asstring(algorithmobj);
591 if (strcasecmp(algorithm, "hmac-md5") != 0)
592 fatal("unsupported algorithm: %s", algorithm);
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;
601 * Find the port to connect to.
604 ; /* Was set on command line, do nothing. */
607 (void)cfg_map_get(server, "port", &defport);
608 if (defport == NULL && options != NULL)
609 (void)cfg_map_get(options, "default-port", &defport);
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;
619 result = cfg_map_get(server, "addresses", &addresses);
621 result = ISC_R_NOTFOUND;
622 if (result == ISC_R_SUCCESS) {
623 for (element = cfg_list_first(addresses);
625 element = cfg_list_next(element))
629 address = cfg_listelt_value(element);
630 if (!cfg_obj_issockaddr(address)) {
633 const cfg_obj_t *obj;
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 ||
642 fatal("port %u out of range",
646 if (nserveraddrs < SERVERADDRS)
647 get_addresses(name, (in_port_t) myport);
649 fprintf(stderr, "too many address: "
650 "%s: dropped\n", name);
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;
659 char socktext[ISC_SOCKADDR_FORMATSIZE];
661 isc_sockaddr_format(&sa, socktext,
664 "too many address: %s: dropped\n",
670 if (!local4set && server != NULL) {
672 cfg_map_get(server, "source-address", &address);
673 if (address != NULL) {
674 local4 = *cfg_obj_assockaddr(address);
675 local4set = ISC_TRUE;
678 if (!local4set && options != NULL) {
680 cfg_map_get(options, "default-source-address", &address);
681 if (address != NULL) {
682 local4 = *cfg_obj_assockaddr(address);
683 local4set = ISC_TRUE;
687 if (!local6set && server != NULL) {
689 cfg_map_get(server, "source-address-v6", &address);
690 if (address != NULL) {
691 local6 = *cfg_obj_assockaddr(address);
692 local6set = ISC_TRUE;
695 if (!local6set && options != 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;
708 main(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;
726 result = isc_file_progname(*argv, program, sizeof(program));
727 if (result != ISC_R_SUCCESS)
728 memmove(program, "rndc", 5);
731 admin_conffile = RNDC_CONFFILE;
732 admin_keyfile = RNDC_KEYFILE;
734 isc_sockaddr_any(&local4);
735 isc_sockaddr_any6(&local6);
737 result = isc_app_start();
738 if (result != ISC_R_SUCCESS)
739 fatal("isc_app_start() failed: %s", isc_result_totext(result));
741 isc_commandline_errprint = ISC_FALSE;
743 while ((ch = isc_commandline_parse(argc, argv, "b:c:hk:Mmp:s:Vy:"))
747 if (inet_pton(AF_INET, isc_commandline_argument,
749 isc_sockaddr_fromin(&local4, &in, 0);
750 local4set = ISC_TRUE;
751 } else if (inet_pton(AF_INET6, isc_commandline_argument,
753 isc_sockaddr_fromin6(&local6, &in6, 0);
754 local6set = ISC_TRUE;
759 admin_conffile = isc_commandline_argument;
764 admin_keyfile = isc_commandline_argument;
768 isc_mem_debugging = ISC_MEM_DEBUGTRACE;
772 show_final_mem = ISC_TRUE;
776 remoteport = atoi(isc_commandline_argument);
777 if (remoteport > 65535 || remoteport == 0)
778 fatal("port '%s' out of range",
779 isc_commandline_argument);
783 servername = isc_commandline_argument;
791 keyname = isc_commandline_argument;
795 if (isc_commandline_option != '?') {
796 fprintf(stderr, "%s: invalid argument -%c\n",
797 program, isc_commandline_option);
805 fprintf(stderr, "%s: unhandled option -%c\n",
806 program, isc_commandline_option);
811 argc -= isc_commandline_index;
812 argv += isc_commandline_index;
817 isc_random_get(&serial);
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));
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",
838 parse_config(mctx, log, keyname, &pctx, &config);
840 isccc_result_register();
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).
850 for (i = 0; i < argc; i++)
851 argslen += strlen(argv[i]) + 1;
853 args = isc_mem_get(mctx, argslen);
855 DO("isc_mem_get", ISC_R_NOMEMORY);
858 for (i = 0; i < argc; i++) {
859 size_t len = strlen(argv[i]);
860 memmove(p, argv[i], len);
867 INSIST(p == args + argslen);
869 notify("%s", command);
871 if (strcmp(command, "restart") == 0)
872 fatal("'%s' is not implemented", command);
874 if (nserveraddrs == 0)
875 get_addresses(servername, (in_port_t) remoteport);
877 DO("post event", isc_app_onrun(mctx, task, rndc_start, NULL));
879 result = isc_app_run();
880 if (result != ISC_R_SUCCESS)
881 fatal("isc_app_run() failed: %s", isc_result_totext(result));
883 if (connects > 0 || sends > 0 || recvs > 0)
884 isc_socket_cancel(sock, task, ISC_SOCKCANCEL_ALL);
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);
892 cfg_obj_destroy(pctx, &config);
893 cfg_parser_destroy(&pctx);
895 isc_mem_put(mctx, args, argslen);
896 isccc_ccmsg_invalidate(&ccmsg);
901 isc_mem_stats(mctx, stderr);
903 isc_mem_destroy(&mctx);