Import bind 9.5.2 vendor sources.
[dragonfly.git] / contrib / bind-9.5.2 / bin / rndc / rndc.c
blob51ed206fb50967d83425aaa169d275529b9e9f43
1 /*
2 * Copyright (C) 2004-2009 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.
18 /* $Id: rndc.c,v 1.118.128.6 2009/01/19 23:47:01 tbox Exp $ */
20 /*! \file */
23 * Principal Author: DCL
26 #include <config.h>
28 #include <stdlib.h>
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>
45 #include <isccfg/namedconf.h>
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>
56 #include <dns/name.h>
58 #include <bind9/getaddresses.h>
60 #include "util.h"
62 #define SERVERADDRS 10
64 const char *progname;
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_mem_t *mctx;
83 static int sends, recvs, connects;
84 static char *command;
85 static char *args;
86 static char program[256];
87 static isc_socket_t *sock = NULL;
88 static isc_uint32_t serial;
90 static void rndc_startconnect(isc_sockaddr_t *addr, isc_task_t *task);
92 static void
93 usage(int status) {
94 fprintf(stderr, "\
95 Usage: %s [-c config] [-s server] [-p port]\n\
96 [-k key-file ] [-y key] [-V] command\n\
97 \n\
98 command is one of the following:\n\
99 \n\
100 reload Reload configuration file and zones.\n\
101 reload zone [class [view]]\n\
102 Reload a single zone.\n\
103 refresh zone [class [view]]\n\
104 Schedule immediate maintenance for a zone.\n\
105 retransfer zone [class [view]]\n\
106 Retransfer a single zone without checking serial number.\n\
107 freeze Suspend updates to all dynamic zones.\n\
108 freeze zone [class [view]]\n\
109 Suspend updates to a dynamic zone.\n\
110 thaw Enable updates to all dynamic zones and reload them.\n\
111 thaw zone [class [view]]\n\
112 Enable updates to a frozen dynamic zone and reload it.\n\
113 notify zone [class [view]]\n\
114 Resend NOTIFY messages for the zone.\n\
115 reconfig Reload configuration file and new zones only.\n\
116 stats Write server statistics to the statistics file.\n\
117 querylog Toggle query logging.\n\
118 dumpdb [-all|-cache|-zones] [view ...]\n\
119 Dump cache(s) to the dump file (named_dump.db).\n\
120 stop Save pending updates to master files and stop the server.\n\
121 stop -p Save pending updates to master files and stop the server\n\
122 reporting process id.\n\
123 halt Stop the server without saving pending updates.\n\
124 halt -p Stop the server without saving pending updates reporting\n\
125 process id.\n\
126 trace Increment debugging level by one.\n\
127 trace level Change the debugging level.\n\
128 notrace Set debugging level to 0.\n\
129 flush Flushes all of the server's caches.\n\
130 flush [view] Flushes the server's cache for a view.\n\
131 flushname name [view]\n\
132 Flush the given name from the server's cache(s)\n\
133 status Display status of the server.\n\
134 recursing Dump the queries that are currently recursing (named.recursing)\n\
135 validation newstate [view]\n\
136 Enable / disable DNSSEC validation.\n\
137 *restart Restart the server.\n\
139 * == not yet implemented\n\
140 Version: %s\n",
141 progname, version);
143 exit(status);
146 static void
147 get_addresses(const char *host, in_port_t port) {
148 isc_result_t result;
149 int found = 0, count;
151 if (*host == '/') {
152 result = isc_sockaddr_frompath(&serveraddrs[nserveraddrs],
153 host);
154 if (result == ISC_R_SUCCESS)
155 nserveraddrs++;
156 } else {
157 count = SERVERADDRS - nserveraddrs;
158 result = bind9_getaddresses(host, port,
159 &serveraddrs[nserveraddrs],
160 count, &found);
161 nserveraddrs += found;
163 if (result != ISC_R_SUCCESS)
164 fatal("couldn't get address for '%s': %s",
165 host, isc_result_totext(result));
166 INSIST(nserveraddrs > 0);
169 static void
170 rndc_senddone(isc_task_t *task, isc_event_t *event) {
171 isc_socketevent_t *sevent = (isc_socketevent_t *)event;
173 UNUSED(task);
175 sends--;
176 if (sevent->result != ISC_R_SUCCESS)
177 fatal("send failed: %s", isc_result_totext(sevent->result));
178 isc_event_free(&event);
179 if (sends == 0 && recvs == 0) {
180 isc_socket_detach(&sock);
181 isc_task_shutdown(task);
182 RUNTIME_CHECK(isc_app_shutdown() == ISC_R_SUCCESS);
186 static void
187 rndc_recvdone(isc_task_t *task, isc_event_t *event) {
188 isccc_sexpr_t *response = NULL;
189 isccc_sexpr_t *data;
190 isccc_region_t source;
191 char *errormsg = NULL;
192 char *textmsg = NULL;
193 isc_result_t result;
195 recvs--;
197 if (ccmsg.result == ISC_R_EOF)
198 fatal("connection to remote host closed\n"
199 "This may indicate that\n"
200 "* the remote server is using an older version of"
201 " the command protocol,\n"
202 "* this host is not authorized to connect,\n"
203 "* the clocks are not synchronized, or\n"
204 "* the key is invalid.");
206 if (ccmsg.result != ISC_R_SUCCESS)
207 fatal("recv failed: %s", isc_result_totext(ccmsg.result));
209 source.rstart = isc_buffer_base(&ccmsg.buffer);
210 source.rend = isc_buffer_used(&ccmsg.buffer);
212 DO("parse message", isccc_cc_fromwire(&source, &response, &secret));
214 data = isccc_alist_lookup(response, "_data");
215 if (data == NULL)
216 fatal("no data section in response");
217 result = isccc_cc_lookupstring(data, "err", &errormsg);
218 if (result == ISC_R_SUCCESS) {
219 failed = ISC_TRUE;
220 fprintf(stderr, "%s: '%s' failed: %s\n",
221 progname, command, errormsg);
223 else if (result != ISC_R_NOTFOUND)
224 fprintf(stderr, "%s: parsing response failed: %s\n",
225 progname, isc_result_totext(result));
227 result = isccc_cc_lookupstring(data, "text", &textmsg);
228 if (result == ISC_R_SUCCESS)
229 printf("%s\n", textmsg);
230 else if (result != ISC_R_NOTFOUND)
231 fprintf(stderr, "%s: parsing response failed: %s\n",
232 progname, isc_result_totext(result));
234 isc_event_free(&event);
235 isccc_sexpr_free(&response);
236 if (sends == 0 && recvs == 0) {
237 isc_socket_detach(&sock);
238 isc_task_shutdown(task);
239 RUNTIME_CHECK(isc_app_shutdown() == ISC_R_SUCCESS);
243 static void
244 rndc_recvnonce(isc_task_t *task, isc_event_t *event) {
245 isccc_sexpr_t *response = NULL;
246 isccc_sexpr_t *_ctrl;
247 isccc_region_t source;
248 isc_result_t result;
249 isc_uint32_t nonce;
250 isccc_sexpr_t *request = NULL;
251 isccc_time_t now;
252 isc_region_t r;
253 isccc_sexpr_t *data;
254 isccc_region_t message;
255 isc_uint32_t len;
256 isc_buffer_t b;
258 recvs--;
260 if (ccmsg.result == ISC_R_EOF)
261 fatal("connection to remote host closed\n"
262 "This may indicate that\n"
263 "* the remote server is using an older version of"
264 " the command protocol,\n"
265 "* this host is not authorized to connect,\n"
266 "* the clocks are not synchronized, or\n"
267 "* the key is invalid.");
269 if (ccmsg.result != ISC_R_SUCCESS)
270 fatal("recv failed: %s", isc_result_totext(ccmsg.result));
272 source.rstart = isc_buffer_base(&ccmsg.buffer);
273 source.rend = isc_buffer_used(&ccmsg.buffer);
275 DO("parse message", isccc_cc_fromwire(&source, &response, &secret));
277 _ctrl = isccc_alist_lookup(response, "_ctrl");
278 if (_ctrl == NULL)
279 fatal("_ctrl section missing");
280 nonce = 0;
281 if (isccc_cc_lookupuint32(_ctrl, "_nonce", &nonce) != ISC_R_SUCCESS)
282 nonce = 0;
284 isc_stdtime_get(&now);
286 DO("create message", isccc_cc_createmessage(1, NULL, NULL, ++serial,
287 now, now + 60, &request));
288 data = isccc_alist_lookup(request, "_data");
289 if (data == NULL)
290 fatal("_data section missing");
291 if (isccc_cc_definestring(data, "type", args) == NULL)
292 fatal("out of memory");
293 if (nonce != 0) {
294 _ctrl = isccc_alist_lookup(request, "_ctrl");
295 if (_ctrl == NULL)
296 fatal("_ctrl section missing");
297 if (isccc_cc_defineuint32(_ctrl, "_nonce", nonce) == NULL)
298 fatal("out of memory");
300 message.rstart = databuf + 4;
301 message.rend = databuf + sizeof(databuf);
302 DO("render message", isccc_cc_towire(request, &message, &secret));
303 len = sizeof(databuf) - REGION_SIZE(message);
304 isc_buffer_init(&b, databuf, 4);
305 isc_buffer_putuint32(&b, len - 4);
306 r.length = len;
307 r.base = databuf;
309 isccc_ccmsg_cancelread(&ccmsg);
310 DO("schedule recv", isccc_ccmsg_readmessage(&ccmsg, task,
311 rndc_recvdone, NULL));
312 recvs++;
313 DO("send message", isc_socket_send(sock, &r, task, rndc_senddone,
314 NULL));
315 sends++;
317 isc_event_free(&event);
318 isccc_sexpr_free(&response);
319 return;
322 static void
323 rndc_connected(isc_task_t *task, isc_event_t *event) {
324 char socktext[ISC_SOCKADDR_FORMATSIZE];
325 isc_socketevent_t *sevent = (isc_socketevent_t *)event;
326 isccc_sexpr_t *request = NULL;
327 isccc_sexpr_t *data;
328 isccc_time_t now;
329 isccc_region_t message;
330 isc_region_t r;
331 isc_uint32_t len;
332 isc_buffer_t b;
333 isc_result_t result;
335 connects--;
337 if (sevent->result != ISC_R_SUCCESS) {
338 isc_sockaddr_format(&serveraddrs[currentaddr], socktext,
339 sizeof(socktext));
340 if (sevent->result != ISC_R_CANCELED &&
341 ++currentaddr < nserveraddrs)
343 notify("connection failed: %s: %s", socktext,
344 isc_result_totext(sevent->result));
345 isc_socket_detach(&sock);
346 isc_event_free(&event);
347 rndc_startconnect(&serveraddrs[currentaddr], task);
348 return;
349 } else
350 fatal("connect failed: %s: %s", socktext,
351 isc_result_totext(sevent->result));
354 isc_stdtime_get(&now);
355 DO("create message", isccc_cc_createmessage(1, NULL, NULL, ++serial,
356 now, now + 60, &request));
357 data = isccc_alist_lookup(request, "_data");
358 if (data == NULL)
359 fatal("_data section missing");
360 if (isccc_cc_definestring(data, "type", "null") == NULL)
361 fatal("out of memory");
362 message.rstart = databuf + 4;
363 message.rend = databuf + sizeof(databuf);
364 DO("render message", isccc_cc_towire(request, &message, &secret));
365 len = sizeof(databuf) - REGION_SIZE(message);
366 isc_buffer_init(&b, databuf, 4);
367 isc_buffer_putuint32(&b, len - 4);
368 r.length = len;
369 r.base = databuf;
371 isccc_ccmsg_init(mctx, sock, &ccmsg);
372 isccc_ccmsg_setmaxsize(&ccmsg, 1024 * 1024);
374 DO("schedule recv", isccc_ccmsg_readmessage(&ccmsg, task,
375 rndc_recvnonce, NULL));
376 recvs++;
377 DO("send message", isc_socket_send(sock, &r, task, rndc_senddone,
378 NULL));
379 sends++;
380 isc_event_free(&event);
383 static void
384 rndc_startconnect(isc_sockaddr_t *addr, isc_task_t *task) {
385 isc_result_t result;
386 int pf;
387 isc_sockettype_t type;
389 char socktext[ISC_SOCKADDR_FORMATSIZE];
391 isc_sockaddr_format(addr, socktext, sizeof(socktext));
393 notify("using server %s (%s)", servername, socktext);
395 pf = isc_sockaddr_pf(addr);
396 if (pf == AF_INET || pf == AF_INET6)
397 type = isc_sockettype_tcp;
398 else
399 type = isc_sockettype_unix;
400 DO("create socket", isc_socket_create(socketmgr, pf, type, &sock));
401 switch (isc_sockaddr_pf(addr)) {
402 case AF_INET:
403 DO("bind socket", isc_socket_bind(sock, &local4, 0));
404 break;
405 case AF_INET6:
406 DO("bind socket", isc_socket_bind(sock, &local6, 0));
407 break;
408 default:
409 break;
411 DO("connect", isc_socket_connect(sock, addr, task, rndc_connected,
412 NULL));
413 connects++;
416 static void
417 rndc_start(isc_task_t *task, isc_event_t *event) {
418 isc_event_free(&event);
420 currentaddr = 0;
421 rndc_startconnect(&serveraddrs[currentaddr], task);
424 static void
425 parse_config(isc_mem_t *mctx, isc_log_t *log, const char *keyname,
426 cfg_parser_t **pctxp, cfg_obj_t **configp)
428 isc_result_t result;
429 const char *conffile = admin_conffile;
430 const cfg_obj_t *addresses = NULL;
431 const cfg_obj_t *defkey = NULL;
432 const cfg_obj_t *options = NULL;
433 const cfg_obj_t *servers = NULL;
434 const cfg_obj_t *server = NULL;
435 const cfg_obj_t *keys = NULL;
436 const cfg_obj_t *key = NULL;
437 const cfg_obj_t *defport = NULL;
438 const cfg_obj_t *secretobj = NULL;
439 const cfg_obj_t *algorithmobj = NULL;
440 cfg_obj_t *config = NULL;
441 const cfg_obj_t *address = NULL;
442 const cfg_listelt_t *elt;
443 const char *secretstr;
444 const char *algorithm;
445 static char secretarray[1024];
446 const cfg_type_t *conftype = &cfg_type_rndcconf;
447 isc_boolean_t key_only = ISC_FALSE;
448 const cfg_listelt_t *element;
450 if (! isc_file_exists(conffile)) {
451 conffile = admin_keyfile;
452 conftype = &cfg_type_rndckey;
454 if (! isc_file_exists(conffile))
455 fatal("neither %s nor %s was found",
456 admin_conffile, admin_keyfile);
457 key_only = ISC_TRUE;
460 DO("create parser", cfg_parser_create(mctx, log, pctxp));
463 * The parser will output its own errors, so DO() is not used.
465 result = cfg_parse_file(*pctxp, conffile, conftype, &config);
466 if (result != ISC_R_SUCCESS)
467 fatal("could not load rndc configuration");
469 if (!key_only)
470 (void)cfg_map_get(config, "options", &options);
472 if (key_only && servername == NULL)
473 servername = "127.0.0.1";
474 else if (servername == NULL && options != NULL) {
475 const cfg_obj_t *defserverobj = NULL;
476 (void)cfg_map_get(options, "default-server", &defserverobj);
477 if (defserverobj != NULL)
478 servername = cfg_obj_asstring(defserverobj);
481 if (servername == NULL)
482 fatal("no server specified and no default");
484 if (!key_only) {
485 (void)cfg_map_get(config, "server", &servers);
486 if (servers != NULL) {
487 for (elt = cfg_list_first(servers);
488 elt != NULL;
489 elt = cfg_list_next(elt))
491 const char *name;
492 server = cfg_listelt_value(elt);
493 name = cfg_obj_asstring(cfg_map_getname(server));
494 if (strcasecmp(name, servername) == 0)
495 break;
496 server = NULL;
502 * Look for the name of the key to use.
504 if (keyname != NULL)
505 ; /* Was set on command line, do nothing. */
506 else if (server != NULL) {
507 DO("get key for server", cfg_map_get(server, "key", &defkey));
508 keyname = cfg_obj_asstring(defkey);
509 } else if (options != NULL) {
510 DO("get default key", cfg_map_get(options, "default-key",
511 &defkey));
512 keyname = cfg_obj_asstring(defkey);
513 } else if (!key_only)
514 fatal("no key for server and no default");
517 * Get the key's definition.
519 if (key_only)
520 DO("get key", cfg_map_get(config, "key", &key));
521 else {
522 DO("get config key list", cfg_map_get(config, "key", &keys));
523 for (elt = cfg_list_first(keys);
524 elt != NULL;
525 elt = cfg_list_next(elt))
527 key = cfg_listelt_value(elt);
528 if (strcasecmp(cfg_obj_asstring(cfg_map_getname(key)),
529 keyname) == 0)
530 break;
532 if (elt == NULL)
533 fatal("no key definition for name %s", keyname);
535 (void)cfg_map_get(key, "secret", &secretobj);
536 (void)cfg_map_get(key, "algorithm", &algorithmobj);
537 if (secretobj == NULL || algorithmobj == NULL)
538 fatal("key must have algorithm and secret");
540 secretstr = cfg_obj_asstring(secretobj);
541 algorithm = cfg_obj_asstring(algorithmobj);
543 if (strcasecmp(algorithm, "hmac-md5") != 0)
544 fatal("unsupported algorithm: %s", algorithm);
546 secret.rstart = (unsigned char *)secretarray;
547 secret.rend = (unsigned char *)secretarray + sizeof(secretarray);
548 DO("decode base64 secret", isccc_base64_decode(secretstr, &secret));
549 secret.rend = secret.rstart;
550 secret.rstart = (unsigned char *)secretarray;
553 * Find the port to connect to.
555 if (remoteport != 0)
556 ; /* Was set on command line, do nothing. */
557 else {
558 if (server != NULL)
559 (void)cfg_map_get(server, "port", &defport);
560 if (defport == NULL && options != NULL)
561 (void)cfg_map_get(options, "default-port", &defport);
563 if (defport != NULL) {
564 remoteport = cfg_obj_asuint32(defport);
565 if (remoteport > 65535 || remoteport == 0)
566 fatal("port %u out of range", remoteport);
567 } else if (remoteport == 0)
568 remoteport = NS_CONTROL_PORT;
570 if (server != NULL)
571 result = cfg_map_get(server, "addresses", &addresses);
572 else
573 result = ISC_R_NOTFOUND;
574 if (result == ISC_R_SUCCESS) {
575 for (element = cfg_list_first(addresses);
576 element != NULL;
577 element = cfg_list_next(element))
579 isc_sockaddr_t sa;
581 address = cfg_listelt_value(element);
582 if (!cfg_obj_issockaddr(address)) {
583 unsigned int myport;
584 const char *name;
585 const cfg_obj_t *obj;
587 obj = cfg_tuple_get(address, "name");
588 name = cfg_obj_asstring(obj);
589 obj = cfg_tuple_get(address, "port");
590 if (cfg_obj_isuint32(obj)) {
591 myport = cfg_obj_asuint32(obj);
592 if (myport > ISC_UINT16_MAX ||
593 myport == 0)
594 fatal("port %u out of range",
595 myport);
596 } else
597 myport = remoteport;
598 if (nserveraddrs < SERVERADDRS)
599 get_addresses(name, (in_port_t) myport);
600 else
601 fprintf(stderr, "too many address: "
602 "%s: dropped\n", name);
603 continue;
605 sa = *cfg_obj_assockaddr(address);
606 if (isc_sockaddr_getport(&sa) == 0)
607 isc_sockaddr_setport(&sa, remoteport);
608 if (nserveraddrs < SERVERADDRS)
609 serveraddrs[nserveraddrs++] = sa;
610 else {
611 char socktext[ISC_SOCKADDR_FORMATSIZE];
613 isc_sockaddr_format(&sa, socktext,
614 sizeof(socktext));
615 fprintf(stderr,
616 "too many address: %s: dropped\n",
617 socktext);
622 if (!local4set && server != NULL) {
623 address = NULL;
624 cfg_map_get(server, "source-address", &address);
625 if (address != NULL) {
626 local4 = *cfg_obj_assockaddr(address);
627 local4set = ISC_TRUE;
630 if (!local4set && options != NULL) {
631 address = NULL;
632 cfg_map_get(options, "default-source-address", &address);
633 if (address != NULL) {
634 local4 = *cfg_obj_assockaddr(address);
635 local4set = ISC_TRUE;
639 if (!local6set && server != NULL) {
640 address = NULL;
641 cfg_map_get(server, "source-address-v6", &address);
642 if (address != NULL) {
643 local6 = *cfg_obj_assockaddr(address);
644 local6set = ISC_TRUE;
647 if (!local6set && options != NULL) {
648 address = NULL;
649 cfg_map_get(options, "default-source-address-v6", &address);
650 if (address != NULL) {
651 local6 = *cfg_obj_assockaddr(address);
652 local6set = ISC_TRUE;
656 *configp = config;
660 main(int argc, char **argv) {
661 isc_boolean_t show_final_mem = ISC_FALSE;
662 isc_result_t result = ISC_R_SUCCESS;
663 isc_taskmgr_t *taskmgr = NULL;
664 isc_task_t *task = NULL;
665 isc_log_t *log = NULL;
666 isc_logconfig_t *logconfig = NULL;
667 isc_logdestination_t logdest;
668 cfg_parser_t *pctx = NULL;
669 cfg_obj_t *config = NULL;
670 const char *keyname = NULL;
671 struct in_addr in;
672 struct in6_addr in6;
673 char *p;
674 size_t argslen;
675 int ch;
676 int i;
678 result = isc_file_progname(*argv, program, sizeof(program));
679 if (result != ISC_R_SUCCESS)
680 memcpy(program, "rndc", 5);
681 progname = program;
683 admin_conffile = RNDC_CONFFILE;
684 admin_keyfile = RNDC_KEYFILE;
686 isc_sockaddr_any(&local4);
687 isc_sockaddr_any6(&local6);
689 result = isc_app_start();
690 if (result != ISC_R_SUCCESS)
691 fatal("isc_app_start() failed: %s", isc_result_totext(result));
693 isc_commandline_errprint = ISC_FALSE;
695 while ((ch = isc_commandline_parse(argc, argv, "b:c:hk:Mmp:s:Vy:"))
696 != -1) {
697 switch (ch) {
698 case 'b':
699 if (inet_pton(AF_INET, isc_commandline_argument,
700 &in) == 1) {
701 isc_sockaddr_fromin(&local4, &in, 0);
702 local4set = ISC_TRUE;
703 } else if (inet_pton(AF_INET6, isc_commandline_argument,
704 &in6) == 1) {
705 isc_sockaddr_fromin6(&local6, &in6, 0);
706 local6set = ISC_TRUE;
708 break;
710 case 'c':
711 admin_conffile = isc_commandline_argument;
712 break;
714 case 'k':
715 admin_keyfile = isc_commandline_argument;
716 break;
718 case 'M':
719 isc_mem_debugging = ISC_MEM_DEBUGTRACE;
720 break;
722 case 'm':
723 show_final_mem = ISC_TRUE;
724 break;
726 case 'p':
727 remoteport = atoi(isc_commandline_argument);
728 if (remoteport > 65535 || remoteport == 0)
729 fatal("port '%s' out of range",
730 isc_commandline_argument);
731 break;
733 case 's':
734 servername = isc_commandline_argument;
735 break;
737 case 'V':
738 verbose = ISC_TRUE;
739 break;
741 case 'y':
742 keyname = isc_commandline_argument;
743 break;
745 case '?':
746 if (isc_commandline_option != '?') {
747 fprintf(stderr, "%s: invalid argument -%c\n",
748 program, isc_commandline_option);
749 usage(1);
751 case 'h':
752 usage(0);
753 break;
754 default:
755 fprintf(stderr, "%s: unhandled option -%c\n",
756 program, isc_commandline_option);
757 exit(1);
761 argc -= isc_commandline_index;
762 argv += isc_commandline_index;
764 if (argc < 1)
765 usage(1);
767 isc_random_get(&serial);
769 DO("create memory context", isc_mem_create(0, 0, &mctx));
770 DO("create socket manager", isc_socketmgr_create(mctx, &socketmgr));
771 DO("create task manager", isc_taskmgr_create(mctx, 1, 0, &taskmgr));
772 DO("create task", isc_task_create(taskmgr, 0, &task));
774 DO("create logging context", isc_log_create(mctx, &log, &logconfig));
775 isc_log_setcontext(log);
776 DO("setting log tag", isc_log_settag(logconfig, progname));
777 logdest.file.stream = stderr;
778 logdest.file.name = NULL;
779 logdest.file.versions = ISC_LOG_ROLLNEVER;
780 logdest.file.maximum_size = 0;
781 DO("creating log channel",
782 isc_log_createchannel(logconfig, "stderr",
783 ISC_LOG_TOFILEDESC, ISC_LOG_INFO, &logdest,
784 ISC_LOG_PRINTTAG|ISC_LOG_PRINTLEVEL));
785 DO("enabling log channel", isc_log_usechannel(logconfig, "stderr",
786 NULL, NULL));
788 parse_config(mctx, log, keyname, &pctx, &config);
790 isccc_result_register();
792 command = *argv;
795 * Convert argc/argv into a space-delimited command string
796 * similar to what the user might enter in interactive mode
797 * (if that were implemented).
799 argslen = 0;
800 for (i = 0; i < argc; i++)
801 argslen += strlen(argv[i]) + 1;
803 args = isc_mem_get(mctx, argslen);
804 if (args == NULL)
805 DO("isc_mem_get", ISC_R_NOMEMORY);
807 p = args;
808 for (i = 0; i < argc; i++) {
809 size_t len = strlen(argv[i]);
810 memcpy(p, argv[i], len);
811 p += len;
812 *p++ = ' ';
815 p--;
816 *p++ = '\0';
817 INSIST(p == args + argslen);
819 notify("%s", command);
821 if (strcmp(command, "restart") == 0)
822 fatal("'%s' is not implemented", command);
824 if (nserveraddrs == 0)
825 get_addresses(servername, (in_port_t) remoteport);
827 DO("post event", isc_app_onrun(mctx, task, rndc_start, NULL));
829 result = isc_app_run();
830 if (result != ISC_R_SUCCESS)
831 fatal("isc_app_run() failed: %s", isc_result_totext(result));
833 if (connects > 0 || sends > 0 || recvs > 0)
834 isc_socket_cancel(sock, task, ISC_SOCKCANCEL_ALL);
836 isc_task_detach(&task);
837 isc_taskmgr_destroy(&taskmgr);
838 isc_socketmgr_destroy(&socketmgr);
839 isc_log_destroy(&log);
840 isc_log_setcontext(NULL);
842 cfg_obj_destroy(pctx, &config);
843 cfg_parser_destroy(&pctx);
845 isc_mem_put(mctx, args, argslen);
846 isccc_ccmsg_invalidate(&ccmsg);
848 dns_name_destroy();
850 if (show_final_mem)
851 isc_mem_stats(mctx, stderr);
853 isc_mem_destroy(&mctx);
855 if (failed)
856 return (1);
858 return (0);