1 /* $NetBSD: rndc.c,v 1.12 2015/07/08 17:28:55 christos Exp $ */
4 * Copyright (C) 2004-2015 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.
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 isc_uint32_t algorithm
;
81 static isccc_region_t secret
;
82 static isc_boolean_t failed
= ISC_FALSE
;
83 static isc_boolean_t c_flag
= ISC_FALSE
;
84 static isc_mem_t
*rndc_mctx
;
85 static int sends
, recvs
, connects
;
88 static char program
[256];
89 static isc_socket_t
*sock
= NULL
;
90 static isc_uint32_t serial
;
91 static isc_boolean_t quiet
= ISC_FALSE
;
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
;
101 Usage: %s [-b address] [-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 addzone zone [class [view]] { zone-options }\n\
107 Add zone to given view. Requires new-zone-file option.\n\
108 delzone [-clean] zone [class [view]]\n\
109 Removes zone from given view. Requires new-zone-file option.\n\
110 dumpdb [-all|-cache|-zones] [view ...]\n\
111 Dump cache(s) to the dump file (named_dump.db).\n\
112 flush Flushes all of the server's caches.\n\
113 flush [view] Flushes the server's cache for a view.\n\
114 flushname name [view]\n\
115 Flush the given name from the server's cache(s)\n\
116 flushtree name [view]\n\
117 Flush all names under the given name from the server's cache(s)\n\
118 freeze Suspend updates to all dynamic zones.\n\
119 freeze zone [class [view]]\n\
120 Suspend updates to a dynamic zone.\n\
121 halt Stop the server without saving pending updates.\n\
122 halt -p Stop the server without saving pending updates reporting\n\
124 loadkeys zone [class [view]]\n\
125 Update keys without signing immediately.\n\
126 notify zone [class [view]]\n\
127 Resend NOTIFY messages for the zone.\n\
128 notrace Set debugging level to 0.\n\
130 Enable / disable query logging.\n\
131 reconfig Reload configuration file and new zones only.\n\
132 recursing Dump the queries that are currently recursing (named.recursing)\n\
133 refresh zone [class [view]]\n\
134 Schedule immediate maintenance for a zone.\n\
135 reload Reload configuration file and zones.\n\
136 reload zone [class [view]]\n\
137 Reload a single zone.\n\
138 retransfer zone [class [view]]\n\
139 Retransfer a single zone without checking serial number.\n\
140 scan Scan available network interfaces for changes.\n\
141 secroots [view ...]\n\
142 Write security roots to the secroots file.\n\
143 sign zone [class [view]]\n\
144 Update zone keys, and sign as needed.\n\
145 signing -clear all zone [class [view]]\n\
146 Remove the private records for all keys that have\n\
147 finished signing the given zone.\n\
148 signing -clear <keyid>/<algorithm> zone [class [view]]\n\
149 Remove the private record that indicating the given key\n\
150 has finished signing the given zone.\n\
151 signing -list zone [class [view]]\n\
152 List the private records showing the state of DNSSEC\n\
153 signing in the given zone.\n\
154 signing -nsec3param hash flags iterations salt zone [class [view]]\n\
155 Add NSEC3 chain to zone if already signed.\n\
156 Prime zone with NSEC3 chain if not yet signed.\n\
157 signing -nsec3param none zone [class [view]]\n\
158 Remove NSEC3 chains from zone.\n\
159 stats Write server statistics to the statistics file.\n\
160 status Display status of the server.\n\
161 stop Save pending updates to master files and stop the server.\n\
162 stop -p Save pending updates to master files and stop the server\n\
163 reporting process id.\n\
164 sync [-clean] Dump changes to all dynamic zones to disk, and optionally\n\
165 remove their journal files.\n\
166 sync [-clean] zone [class [view]]\n\
167 Dump a single zone's changes to disk, and optionally\n\
168 remove its journal file.\n\
169 thaw Enable updates to all dynamic zones and reload them.\n\
170 thaw zone [class [view]]\n\
171 Enable updates to a frozen dynamic zone and reload it.\n\
172 trace Increment debugging level by one.\n\
173 trace level Change the debugging level.\n\
174 tsig-delete keyname [view]\n\
175 Delete a TKEY-negotiated TSIG key.\n\
176 tsig-list List all currently active TSIG keys, including both statically\n\
177 configured and TKEY-negotiated keys.\n\
178 validation newstate [view]\n\
179 Enable / disable DNSSEC validation.\n\
180 zonestatus zone [class [view]]\n\
181 Display the current status of a zone.\n\
190 get_addresses(const char *host
, in_port_t port
) {
192 int found
= 0, count
;
195 result
= isc_sockaddr_frompath(&serveraddrs
[nserveraddrs
],
197 if (result
== ISC_R_SUCCESS
)
200 count
= SERVERADDRS
- nserveraddrs
;
201 result
= bind9_getaddresses(host
, port
,
202 &serveraddrs
[nserveraddrs
],
204 nserveraddrs
+= found
;
206 if (result
!= ISC_R_SUCCESS
)
207 fatal("couldn't get address for '%s': %s",
208 host
, isc_result_totext(result
));
209 INSIST(nserveraddrs
> 0);
213 rndc_senddone(isc_task_t
*task
, isc_event_t
*event
) {
214 isc_socketevent_t
*sevent
= (isc_socketevent_t
*)event
;
219 if (sevent
->result
!= ISC_R_SUCCESS
)
220 fatal("send failed: %s", isc_result_totext(sevent
->result
));
221 isc_event_free(&event
);
222 if (sends
== 0 && recvs
== 0) {
223 isc_socket_detach(&sock
);
224 isc_task_shutdown(task
);
225 RUNTIME_CHECK(isc_app_shutdown() == ISC_R_SUCCESS
);
230 rndc_recvdone(isc_task_t
*task
, isc_event_t
*event
) {
231 isccc_sexpr_t
*response
= NULL
;
233 isccc_region_t source
;
234 char *errormsg
= NULL
;
235 char *textmsg
= NULL
;
240 if (ccmsg
.result
== ISC_R_EOF
)
241 fatal("connection to remote host closed\n"
242 "This may indicate that\n"
243 "* the remote server is using an older version of"
244 " the command protocol,\n"
245 "* this host is not authorized to connect,\n"
246 "* the clocks are not synchronized, or\n"
247 "* the key is invalid.");
249 if (ccmsg
.result
!= ISC_R_SUCCESS
)
250 fatal("recv failed: %s", isc_result_totext(ccmsg
.result
));
252 source
.rstart
= isc_buffer_base(&ccmsg
.buffer
);
253 source
.rend
= isc_buffer_used(&ccmsg
.buffer
);
256 isccc_cc_fromwire(&source
, &response
, algorithm
, &secret
));
258 data
= isccc_alist_lookup(response
, "_data");
260 fatal("no data section in response");
261 result
= isccc_cc_lookupstring(data
, "err", &errormsg
);
262 if (result
== ISC_R_SUCCESS
) {
264 fprintf(stderr
, "%s: '%s' failed: %s\n",
265 progname
, command
, errormsg
);
267 else if (result
!= ISC_R_NOTFOUND
)
268 fprintf(stderr
, "%s: parsing response failed: %s\n",
269 progname
, isc_result_totext(result
));
271 result
= isccc_cc_lookupstring(data
, "text", &textmsg
);
272 if (result
== ISC_R_SUCCESS
) {
273 if ((!quiet
|| failed
) && strlen(textmsg
) != 0U)
274 fprintf(failed
? stderr
: stdout
, "%s\n", textmsg
);
275 } else if (result
!= ISC_R_NOTFOUND
)
276 fprintf(stderr
, "%s: parsing response failed: %s\n",
277 progname
, isc_result_totext(result
));
279 isc_event_free(&event
);
280 isccc_sexpr_free(&response
);
281 if (sends
== 0 && recvs
== 0) {
282 isc_socket_detach(&sock
);
283 isc_task_shutdown(task
);
284 RUNTIME_CHECK(isc_app_shutdown() == ISC_R_SUCCESS
);
289 rndc_recvnonce(isc_task_t
*task
, isc_event_t
*event
) {
290 isccc_sexpr_t
*response
= NULL
;
291 isccc_sexpr_t
*_ctrl
;
292 isccc_region_t source
;
295 isccc_sexpr_t
*request
= NULL
;
299 isccc_region_t message
;
305 if (ccmsg
.result
== ISC_R_EOF
)
306 fatal("connection to remote host closed\n"
307 "This may indicate that\n"
308 "* the remote server is using an older version of"
309 " the command protocol,\n"
310 "* this host is not authorized to connect,\n"
311 "* the clocks are not synchronized,\n"
312 "* the the key signing algorithm is incorrect, or\n"
313 "* the key is invalid.");
315 if (ccmsg
.result
!= ISC_R_SUCCESS
)
316 fatal("recv failed: %s", isc_result_totext(ccmsg
.result
));
318 source
.rstart
= isc_buffer_base(&ccmsg
.buffer
);
319 source
.rend
= isc_buffer_used(&ccmsg
.buffer
);
322 isccc_cc_fromwire(&source
, &response
, algorithm
, &secret
));
324 _ctrl
= isccc_alist_lookup(response
, "_ctrl");
326 fatal("_ctrl section missing");
328 if (isccc_cc_lookupuint32(_ctrl
, "_nonce", &nonce
) != ISC_R_SUCCESS
)
331 isc_stdtime_get(&now
);
333 DO("create message", isccc_cc_createmessage(1, NULL
, NULL
, ++serial
,
334 now
, now
+ 60, &request
));
335 data
= isccc_alist_lookup(request
, "_data");
337 fatal("_data section missing");
338 if (isccc_cc_definestring(data
, "type", args
) == NULL
)
339 fatal("out of memory");
341 _ctrl
= isccc_alist_lookup(request
, "_ctrl");
343 fatal("_ctrl section missing");
344 if (isccc_cc_defineuint32(_ctrl
, "_nonce", nonce
) == NULL
)
345 fatal("out of memory");
347 message
.rstart
= databuf
+ 4;
348 message
.rend
= databuf
+ sizeof(databuf
);
350 isccc_cc_towire(request
, &message
, algorithm
, &secret
));
351 len
= sizeof(databuf
) - REGION_SIZE(message
);
352 isc_buffer_init(&b
, databuf
, 4);
353 isc_buffer_putuint32(&b
, len
- 4);
357 isccc_ccmsg_cancelread(&ccmsg
);
358 DO("schedule recv", isccc_ccmsg_readmessage(&ccmsg
, task
,
359 rndc_recvdone
, NULL
));
361 DO("send message", isc_socket_send(sock
, &r
, task
, rndc_senddone
,
365 isc_event_free(&event
);
366 isccc_sexpr_free(&response
);
371 rndc_connected(isc_task_t
*task
, isc_event_t
*event
) {
372 char socktext
[ISC_SOCKADDR_FORMATSIZE
];
373 isc_socketevent_t
*sevent
= (isc_socketevent_t
*)event
;
374 isccc_sexpr_t
*request
= NULL
;
377 isccc_region_t message
;
385 if (sevent
->result
!= ISC_R_SUCCESS
) {
386 isc_sockaddr_format(&serveraddrs
[currentaddr
], socktext
,
388 if (sevent
->result
!= ISC_R_CANCELED
&&
389 ++currentaddr
< nserveraddrs
)
391 notify("connection failed: %s: %s", socktext
,
392 isc_result_totext(sevent
->result
));
393 isc_socket_detach(&sock
);
394 isc_event_free(&event
);
395 rndc_startconnect(&serveraddrs
[currentaddr
], task
);
398 fatal("connect failed: %s: %s", socktext
,
399 isc_result_totext(sevent
->result
));
402 isc_stdtime_get(&now
);
403 DO("create message", isccc_cc_createmessage(1, NULL
, NULL
, ++serial
,
404 now
, now
+ 60, &request
));
405 data
= isccc_alist_lookup(request
, "_data");
407 fatal("_data section missing");
408 if (isccc_cc_definestring(data
, "type", "null") == NULL
)
409 fatal("out of memory");
410 message
.rstart
= databuf
+ 4;
411 message
.rend
= databuf
+ sizeof(databuf
);
413 isccc_cc_towire(request
, &message
, algorithm
, &secret
));
414 len
= sizeof(databuf
) - REGION_SIZE(message
);
415 isc_buffer_init(&b
, databuf
, 4);
416 isc_buffer_putuint32(&b
, len
- 4);
420 isccc_ccmsg_init(rndc_mctx
, sock
, &ccmsg
);
421 isccc_ccmsg_setmaxsize(&ccmsg
, 1024 * 1024);
423 DO("schedule recv", isccc_ccmsg_readmessage(&ccmsg
, task
,
424 rndc_recvnonce
, NULL
));
426 DO("send message", isc_socket_send(sock
, &r
, task
, rndc_senddone
,
429 isc_event_free(&event
);
433 rndc_startconnect(isc_sockaddr_t
*addr
, isc_task_t
*task
) {
436 isc_sockettype_t type
;
438 char socktext
[ISC_SOCKADDR_FORMATSIZE
];
440 isc_sockaddr_format(addr
, socktext
, sizeof(socktext
));
442 notify("using server %s (%s)", servername
, socktext
);
444 pf
= isc_sockaddr_pf(addr
);
445 if (pf
== AF_INET
|| pf
== AF_INET6
)
446 type
= isc_sockettype_tcp
;
448 type
= isc_sockettype_unix
;
449 DO("create socket", isc_socket_create(socketmgr
, pf
, type
, &sock
));
450 switch (isc_sockaddr_pf(addr
)) {
452 DO("bind socket", isc_socket_bind(sock
, &local4
, 0));
455 DO("bind socket", isc_socket_bind(sock
, &local6
, 0));
460 DO("connect", isc_socket_connect(sock
, addr
, task
, rndc_connected
,
466 rndc_start(isc_task_t
*task
, isc_event_t
*event
) {
467 isc_event_free(&event
);
470 rndc_startconnect(&serveraddrs
[currentaddr
], task
);
474 parse_config(isc_mem_t
*mctx
, isc_log_t
*log
, const char *keyname
,
475 cfg_parser_t
**pctxp
, cfg_obj_t
**configp
)
478 const char *conffile
= admin_conffile
;
479 const cfg_obj_t
*addresses
= NULL
;
480 const cfg_obj_t
*defkey
= NULL
;
481 const cfg_obj_t
*options
= NULL
;
482 const cfg_obj_t
*servers
= NULL
;
483 const cfg_obj_t
*server
= NULL
;
484 const cfg_obj_t
*keys
= NULL
;
485 const cfg_obj_t
*key
= NULL
;
486 const cfg_obj_t
*defport
= NULL
;
487 const cfg_obj_t
*secretobj
= NULL
;
488 const cfg_obj_t
*algorithmobj
= NULL
;
489 cfg_obj_t
*config
= NULL
;
490 const cfg_obj_t
*address
= NULL
;
491 const cfg_listelt_t
*elt
;
492 const char *secretstr
;
493 const char *algorithmstr
;
494 static char secretarray
[1024];
495 const cfg_type_t
*conftype
= &cfg_type_rndcconf
;
496 isc_boolean_t key_only
= ISC_FALSE
;
497 const cfg_listelt_t
*element
;
499 if (! isc_file_exists(conffile
)) {
500 conffile
= admin_keyfile
;
501 conftype
= &cfg_type_rndckey
;
504 fatal("%s does not exist", admin_conffile
);
506 if (! isc_file_exists(conffile
))
507 fatal("neither %s nor %s was found",
508 admin_conffile
, admin_keyfile
);
510 } else if (! c_flag
&& isc_file_exists(admin_keyfile
)) {
511 fprintf(stderr
, "WARNING: key file (%s) exists, but using "
512 "default configuration file (%s)\n",
513 admin_keyfile
, admin_conffile
);
516 DO("create parser", cfg_parser_create(mctx
, log
, pctxp
));
519 * The parser will output its own errors, so DO() is not used.
521 result
= cfg_parse_file(*pctxp
, conffile
, conftype
, &config
);
522 if (result
!= ISC_R_SUCCESS
)
523 fatal("could not load rndc configuration");
526 (void)cfg_map_get(config
, "options", &options
);
528 if (key_only
&& servername
== NULL
)
529 servername
= "127.0.0.1";
530 else if (servername
== NULL
&& options
!= NULL
) {
531 const cfg_obj_t
*defserverobj
= NULL
;
532 (void)cfg_map_get(options
, "default-server", &defserverobj
);
533 if (defserverobj
!= NULL
)
534 servername
= cfg_obj_asstring(defserverobj
);
537 if (servername
== NULL
)
538 fatal("no server specified and no default");
541 (void)cfg_map_get(config
, "server", &servers
);
542 if (servers
!= NULL
) {
543 for (elt
= cfg_list_first(servers
);
545 elt
= cfg_list_next(elt
))
548 server
= cfg_listelt_value(elt
);
549 name
= cfg_obj_asstring(cfg_map_getname(server
));
550 if (strcasecmp(name
, servername
) == 0)
558 * Look for the name of the key to use.
561 ; /* Was set on command line, do nothing. */
562 else if (server
!= NULL
) {
563 DO("get key for server", cfg_map_get(server
, "key", &defkey
));
564 keyname
= cfg_obj_asstring(defkey
);
565 } else if (options
!= NULL
) {
566 DO("get default key", cfg_map_get(options
, "default-key",
568 keyname
= cfg_obj_asstring(defkey
);
569 } else if (!key_only
)
570 fatal("no key for server and no default");
573 * Get the key's definition.
576 DO("get key", cfg_map_get(config
, "key", &key
));
578 DO("get config key list", cfg_map_get(config
, "key", &keys
));
579 for (elt
= cfg_list_first(keys
);
581 elt
= cfg_list_next(elt
))
583 key
= cfg_listelt_value(elt
);
584 if (strcasecmp(cfg_obj_asstring(cfg_map_getname(key
)),
589 fatal("no key definition for name %s", keyname
);
591 (void)cfg_map_get(key
, "secret", &secretobj
);
592 (void)cfg_map_get(key
, "algorithm", &algorithmobj
);
593 if (secretobj
== NULL
|| algorithmobj
== NULL
)
594 fatal("key must have algorithm and secret");
596 secretstr
= cfg_obj_asstring(secretobj
);
597 algorithmstr
= cfg_obj_asstring(algorithmobj
);
599 if (strcasecmp(algorithmstr
, "hmac-md5") == 0)
600 algorithm
= ISCCC_ALG_HMACMD5
;
601 else if (strcasecmp(algorithmstr
, "hmac-sha1") == 0)
602 algorithm
= ISCCC_ALG_HMACSHA1
;
603 else if (strcasecmp(algorithmstr
, "hmac-sha224") == 0)
604 algorithm
= ISCCC_ALG_HMACSHA224
;
605 else if (strcasecmp(algorithmstr
, "hmac-sha256") == 0)
606 algorithm
= ISCCC_ALG_HMACSHA256
;
607 else if (strcasecmp(algorithmstr
, "hmac-sha384") == 0)
608 algorithm
= ISCCC_ALG_HMACSHA384
;
609 else if (strcasecmp(algorithmstr
, "hmac-sha512") == 0)
610 algorithm
= ISCCC_ALG_HMACSHA512
;
612 fatal("unsupported algorithm: %s", algorithmstr
);
614 secret
.rstart
= (unsigned char *)secretarray
;
615 secret
.rend
= (unsigned char *)secretarray
+ sizeof(secretarray
);
616 DO("decode base64 secret", isccc_base64_decode(secretstr
, &secret
));
617 secret
.rend
= secret
.rstart
;
618 secret
.rstart
= (unsigned char *)secretarray
;
621 * Find the port to connect to.
624 ; /* Was set on command line, do nothing. */
627 (void)cfg_map_get(server
, "port", &defport
);
628 if (defport
== NULL
&& options
!= NULL
)
629 (void)cfg_map_get(options
, "default-port", &defport
);
631 if (defport
!= NULL
) {
632 remoteport
= cfg_obj_asuint32(defport
);
633 if (remoteport
> 65535 || remoteport
== 0)
634 fatal("port %u out of range", remoteport
);
635 } else if (remoteport
== 0)
636 remoteport
= NS_CONTROL_PORT
;
639 result
= cfg_map_get(server
, "addresses", &addresses
);
641 result
= ISC_R_NOTFOUND
;
642 if (result
== ISC_R_SUCCESS
) {
643 for (element
= cfg_list_first(addresses
);
645 element
= cfg_list_next(element
))
649 address
= cfg_listelt_value(element
);
650 if (!cfg_obj_issockaddr(address
)) {
653 const cfg_obj_t
*obj
;
655 obj
= cfg_tuple_get(address
, "name");
656 name
= cfg_obj_asstring(obj
);
657 obj
= cfg_tuple_get(address
, "port");
658 if (cfg_obj_isuint32(obj
)) {
659 myport
= cfg_obj_asuint32(obj
);
660 if (myport
> ISC_UINT16_MAX
||
662 fatal("port %u out of range",
666 if (nserveraddrs
< SERVERADDRS
)
667 get_addresses(name
, (in_port_t
) myport
);
669 fprintf(stderr
, "too many address: "
670 "%s: dropped\n", name
);
673 sa
= *cfg_obj_assockaddr(address
);
674 if (isc_sockaddr_getport(&sa
) == 0)
675 isc_sockaddr_setport(&sa
, remoteport
);
676 if (nserveraddrs
< SERVERADDRS
)
677 serveraddrs
[nserveraddrs
++] = sa
;
679 char socktext
[ISC_SOCKADDR_FORMATSIZE
];
681 isc_sockaddr_format(&sa
, socktext
,
684 "too many address: %s: dropped\n",
690 if (!local4set
&& server
!= NULL
) {
692 cfg_map_get(server
, "source-address", &address
);
693 if (address
!= NULL
) {
694 local4
= *cfg_obj_assockaddr(address
);
695 local4set
= ISC_TRUE
;
698 if (!local4set
&& options
!= NULL
) {
700 cfg_map_get(options
, "default-source-address", &address
);
701 if (address
!= NULL
) {
702 local4
= *cfg_obj_assockaddr(address
);
703 local4set
= ISC_TRUE
;
707 if (!local6set
&& server
!= NULL
) {
709 cfg_map_get(server
, "source-address-v6", &address
);
710 if (address
!= NULL
) {
711 local6
= *cfg_obj_assockaddr(address
);
712 local6set
= ISC_TRUE
;
715 if (!local6set
&& options
!= NULL
) {
717 cfg_map_get(options
, "default-source-address-v6", &address
);
718 if (address
!= NULL
) {
719 local6
= *cfg_obj_assockaddr(address
);
720 local6set
= ISC_TRUE
;
728 main(int argc
, char **argv
) {
729 isc_result_t result
= ISC_R_SUCCESS
;
730 isc_boolean_t show_final_mem
= ISC_FALSE
;
731 isc_taskmgr_t
*taskmgr
= NULL
;
732 isc_task_t
*task
= NULL
;
733 isc_log_t
*log
= NULL
;
734 isc_logconfig_t
*logconfig
= NULL
;
735 isc_logdestination_t logdest
;
736 cfg_parser_t
*pctx
= NULL
;
737 cfg_obj_t
*config
= NULL
;
738 const char *keyname
= NULL
;
746 result
= isc_file_progname(*argv
, program
, sizeof(program
));
747 if (result
!= ISC_R_SUCCESS
)
748 memmove(program
, "rndc", 5);
751 admin_conffile
= RNDC_CONFFILE
;
752 admin_keyfile
= RNDC_KEYFILE
;
754 isc_sockaddr_any(&local4
);
755 isc_sockaddr_any6(&local6
);
757 result
= isc_app_start();
758 if (result
!= ISC_R_SUCCESS
)
759 fatal("isc_app_start() failed: %s", isc_result_totext(result
));
761 isc_commandline_errprint
= ISC_FALSE
;
763 while ((ch
= isc_commandline_parse(argc
, argv
, "b:c:hk:Mmp:qs:Vy:"))
767 if (inet_pton(AF_INET
, isc_commandline_argument
,
769 isc_sockaddr_fromin(&local4
, &in
, 0);
770 local4set
= ISC_TRUE
;
771 } else if (inet_pton(AF_INET6
, isc_commandline_argument
,
773 isc_sockaddr_fromin6(&local6
, &in6
, 0);
774 local6set
= ISC_TRUE
;
779 admin_conffile
= isc_commandline_argument
;
784 admin_keyfile
= isc_commandline_argument
;
788 isc_mem_debugging
= ISC_MEM_DEBUGTRACE
;
792 show_final_mem
= ISC_TRUE
;
796 remoteport
= atoi(isc_commandline_argument
);
797 if (remoteport
> 65535 || remoteport
== 0)
798 fatal("port '%s' out of range",
799 isc_commandline_argument
);
807 servername
= isc_commandline_argument
;
815 keyname
= isc_commandline_argument
;
819 if (isc_commandline_option
!= '?') {
820 fprintf(stderr
, "%s: invalid argument -%c\n",
821 program
, isc_commandline_option
);
829 fprintf(stderr
, "%s: unhandled option -%c\n",
830 program
, isc_commandline_option
);
835 argc
-= isc_commandline_index
;
836 argv
+= isc_commandline_index
;
841 isc_random_get(&serial
);
843 DO("create memory context", isc_mem_create(0, 0, &rndc_mctx
));
844 DO("create socket manager", isc_socketmgr_create(rndc_mctx
, &socketmgr
));
845 DO("create task manager", isc_taskmgr_create(rndc_mctx
, 1, 0, &taskmgr
));
846 DO("create task", isc_task_create(taskmgr
, 0, &task
));
848 DO("create logging context", isc_log_create(rndc_mctx
, &log
, &logconfig
));
849 isc_log_setcontext(log
);
850 DO("setting log tag", isc_log_settag(logconfig
, progname
));
851 logdest
.file
.stream
= stderr
;
852 logdest
.file
.name
= NULL
;
853 logdest
.file
.versions
= ISC_LOG_ROLLNEVER
;
854 logdest
.file
.maximum_size
= 0;
855 DO("creating log channel",
856 isc_log_createchannel(logconfig
, "stderr",
857 ISC_LOG_TOFILEDESC
, ISC_LOG_INFO
, &logdest
,
858 ISC_LOG_PRINTTAG
|ISC_LOG_PRINTLEVEL
));
859 DO("enabling log channel", isc_log_usechannel(logconfig
, "stderr",
862 parse_config(rndc_mctx
, log
, keyname
, &pctx
, &config
);
864 isccc_result_register();
869 * Convert argc/argv into a space-delimited command string
870 * similar to what the user might enter in interactive mode
871 * (if that were implemented).
874 for (i
= 0; i
< argc
; i
++)
875 argslen
+= strlen(argv
[i
]) + 1;
877 args
= isc_mem_get(rndc_mctx
, argslen
);
879 DO("isc_mem_get", ISC_R_NOMEMORY
);
882 for (i
= 0; i
< argc
; i
++) {
883 size_t len
= strlen(argv
[i
]);
884 memmove(p
, argv
[i
], len
);
891 INSIST(p
== args
+ argslen
);
893 notify("%s", command
);
895 if (strcmp(command
, "restart") == 0)
896 fatal("'%s' is not implemented", command
);
898 if (nserveraddrs
== 0)
899 get_addresses(servername
, (in_port_t
) remoteport
);
901 DO("post event", isc_app_onrun(rndc_mctx
, task
, rndc_start
, NULL
));
903 result
= isc_app_run();
904 if (result
!= ISC_R_SUCCESS
)
905 fatal("isc_app_run() failed: %s", isc_result_totext(result
));
907 if (connects
> 0 || sends
> 0 || recvs
> 0)
908 isc_socket_cancel(sock
, task
, ISC_SOCKCANCEL_ALL
);
910 isc_task_detach(&task
);
911 isc_taskmgr_destroy(&taskmgr
);
912 isc_socketmgr_destroy(&socketmgr
);
913 isc_log_destroy(&log
);
914 isc_log_setcontext(NULL
);
916 cfg_obj_destroy(pctx
, &config
);
917 cfg_parser_destroy(&pctx
);
919 isc_mem_put(rndc_mctx
, args
, argslen
);
920 isccc_ccmsg_invalidate(&ccmsg
);
925 isc_mem_stats(rndc_mctx
, stderr
);
927 isc_mem_destroy(&rndc_mctx
);