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