etc/services - sync with NetBSD-8
[minix.git] / external / bsd / bind / dist / bin / rndc / rndc.c
blob2f6c6dabc13b09bfeba977647ddcb14d1142dff7
1 /* $NetBSD: rndc.c,v 1.12 2015/07/08 17:28:55 christos Exp $ */
3 /*
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.
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 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;
86 static char *command;
87 static char *args;
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;
98 static void
99 usage(int status) {
100 fprintf(stderr, "\
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\
123 process id.\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\
129 querylog newstate\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\
183 Version: %s\n",
184 progname, version);
186 exit(status);
189 static void
190 get_addresses(const char *host, in_port_t port) {
191 isc_result_t result;
192 int found = 0, count;
194 if (*host == '/') {
195 result = isc_sockaddr_frompath(&serveraddrs[nserveraddrs],
196 host);
197 if (result == ISC_R_SUCCESS)
198 nserveraddrs++;
199 } else {
200 count = SERVERADDRS - nserveraddrs;
201 result = bind9_getaddresses(host, port,
202 &serveraddrs[nserveraddrs],
203 count, &found);
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);
212 static void
213 rndc_senddone(isc_task_t *task, isc_event_t *event) {
214 isc_socketevent_t *sevent = (isc_socketevent_t *)event;
216 UNUSED(task);
218 sends--;
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);
229 static void
230 rndc_recvdone(isc_task_t *task, isc_event_t *event) {
231 isccc_sexpr_t *response = NULL;
232 isccc_sexpr_t *data;
233 isccc_region_t source;
234 char *errormsg = NULL;
235 char *textmsg = NULL;
236 isc_result_t result;
238 recvs--;
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);
255 DO("parse message",
256 isccc_cc_fromwire(&source, &response, algorithm, &secret));
258 data = isccc_alist_lookup(response, "_data");
259 if (data == NULL)
260 fatal("no data section in response");
261 result = isccc_cc_lookupstring(data, "err", &errormsg);
262 if (result == ISC_R_SUCCESS) {
263 failed = ISC_TRUE;
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);
288 static void
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;
293 isc_result_t result;
294 isc_uint32_t nonce;
295 isccc_sexpr_t *request = NULL;
296 isccc_time_t now;
297 isc_region_t r;
298 isccc_sexpr_t *data;
299 isccc_region_t message;
300 isc_uint32_t len;
301 isc_buffer_t b;
303 recvs--;
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);
321 DO("parse message",
322 isccc_cc_fromwire(&source, &response, algorithm, &secret));
324 _ctrl = isccc_alist_lookup(response, "_ctrl");
325 if (_ctrl == NULL)
326 fatal("_ctrl section missing");
327 nonce = 0;
328 if (isccc_cc_lookupuint32(_ctrl, "_nonce", &nonce) != ISC_R_SUCCESS)
329 nonce = 0;
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");
336 if (data == NULL)
337 fatal("_data section missing");
338 if (isccc_cc_definestring(data, "type", args) == NULL)
339 fatal("out of memory");
340 if (nonce != 0) {
341 _ctrl = isccc_alist_lookup(request, "_ctrl");
342 if (_ctrl == NULL)
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);
349 DO("render message",
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);
354 r.length = len;
355 r.base = databuf;
357 isccc_ccmsg_cancelread(&ccmsg);
358 DO("schedule recv", isccc_ccmsg_readmessage(&ccmsg, task,
359 rndc_recvdone, NULL));
360 recvs++;
361 DO("send message", isc_socket_send(sock, &r, task, rndc_senddone,
362 NULL));
363 sends++;
365 isc_event_free(&event);
366 isccc_sexpr_free(&response);
367 return;
370 static void
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;
375 isccc_sexpr_t *data;
376 isccc_time_t now;
377 isccc_region_t message;
378 isc_region_t r;
379 isc_uint32_t len;
380 isc_buffer_t b;
381 isc_result_t result;
383 connects--;
385 if (sevent->result != ISC_R_SUCCESS) {
386 isc_sockaddr_format(&serveraddrs[currentaddr], socktext,
387 sizeof(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);
396 return;
397 } else
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");
406 if (data == NULL)
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);
412 DO("render message",
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);
417 r.length = len;
418 r.base = databuf;
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));
425 recvs++;
426 DO("send message", isc_socket_send(sock, &r, task, rndc_senddone,
427 NULL));
428 sends++;
429 isc_event_free(&event);
432 static void
433 rndc_startconnect(isc_sockaddr_t *addr, isc_task_t *task) {
434 isc_result_t result;
435 int pf;
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;
447 else
448 type = isc_sockettype_unix;
449 DO("create socket", isc_socket_create(socketmgr, pf, type, &sock));
450 switch (isc_sockaddr_pf(addr)) {
451 case AF_INET:
452 DO("bind socket", isc_socket_bind(sock, &local4, 0));
453 break;
454 case AF_INET6:
455 DO("bind socket", isc_socket_bind(sock, &local6, 0));
456 break;
457 default:
458 break;
460 DO("connect", isc_socket_connect(sock, addr, task, rndc_connected,
461 NULL));
462 connects++;
465 static void
466 rndc_start(isc_task_t *task, isc_event_t *event) {
467 isc_event_free(&event);
469 currentaddr = 0;
470 rndc_startconnect(&serveraddrs[currentaddr], task);
473 static void
474 parse_config(isc_mem_t *mctx, isc_log_t *log, const char *keyname,
475 cfg_parser_t **pctxp, cfg_obj_t **configp)
477 isc_result_t result;
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;
503 if (c_flag)
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);
509 key_only = ISC_TRUE;
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");
525 if (!key_only)
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");
540 if (!key_only) {
541 (void)cfg_map_get(config, "server", &servers);
542 if (servers != NULL) {
543 for (elt = cfg_list_first(servers);
544 elt != NULL;
545 elt = cfg_list_next(elt))
547 const char *name;
548 server = cfg_listelt_value(elt);
549 name = cfg_obj_asstring(cfg_map_getname(server));
550 if (strcasecmp(name, servername) == 0)
551 break;
552 server = NULL;
558 * Look for the name of the key to use.
560 if (keyname != NULL)
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",
567 &defkey));
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.
575 if (key_only)
576 DO("get key", cfg_map_get(config, "key", &key));
577 else {
578 DO("get config key list", cfg_map_get(config, "key", &keys));
579 for (elt = cfg_list_first(keys);
580 elt != NULL;
581 elt = cfg_list_next(elt))
583 key = cfg_listelt_value(elt);
584 if (strcasecmp(cfg_obj_asstring(cfg_map_getname(key)),
585 keyname) == 0)
586 break;
588 if (elt == NULL)
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;
611 else
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.
623 if (remoteport != 0)
624 ; /* Was set on command line, do nothing. */
625 else {
626 if (server != NULL)
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;
638 if (server != NULL)
639 result = cfg_map_get(server, "addresses", &addresses);
640 else
641 result = ISC_R_NOTFOUND;
642 if (result == ISC_R_SUCCESS) {
643 for (element = cfg_list_first(addresses);
644 element != NULL;
645 element = cfg_list_next(element))
647 isc_sockaddr_t sa;
649 address = cfg_listelt_value(element);
650 if (!cfg_obj_issockaddr(address)) {
651 unsigned int myport;
652 const char *name;
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 ||
661 myport == 0)
662 fatal("port %u out of range",
663 myport);
664 } else
665 myport = remoteport;
666 if (nserveraddrs < SERVERADDRS)
667 get_addresses(name, (in_port_t) myport);
668 else
669 fprintf(stderr, "too many address: "
670 "%s: dropped\n", name);
671 continue;
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;
678 else {
679 char socktext[ISC_SOCKADDR_FORMATSIZE];
681 isc_sockaddr_format(&sa, socktext,
682 sizeof(socktext));
683 fprintf(stderr,
684 "too many address: %s: dropped\n",
685 socktext);
690 if (!local4set && server != NULL) {
691 address = 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) {
699 address = 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) {
708 address = 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) {
716 address = 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;
724 *configp = config;
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;
739 struct in_addr in;
740 struct in6_addr in6;
741 char *p;
742 size_t argslen;
743 int ch;
744 int i;
746 result = isc_file_progname(*argv, program, sizeof(program));
747 if (result != ISC_R_SUCCESS)
748 memmove(program, "rndc", 5);
749 progname = program;
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:"))
764 != -1) {
765 switch (ch) {
766 case 'b':
767 if (inet_pton(AF_INET, isc_commandline_argument,
768 &in) == 1) {
769 isc_sockaddr_fromin(&local4, &in, 0);
770 local4set = ISC_TRUE;
771 } else if (inet_pton(AF_INET6, isc_commandline_argument,
772 &in6) == 1) {
773 isc_sockaddr_fromin6(&local6, &in6, 0);
774 local6set = ISC_TRUE;
776 break;
778 case 'c':
779 admin_conffile = isc_commandline_argument;
780 c_flag = ISC_TRUE;
781 break;
783 case 'k':
784 admin_keyfile = isc_commandline_argument;
785 break;
787 case 'M':
788 isc_mem_debugging = ISC_MEM_DEBUGTRACE;
789 break;
791 case 'm':
792 show_final_mem = ISC_TRUE;
793 break;
795 case 'p':
796 remoteport = atoi(isc_commandline_argument);
797 if (remoteport > 65535 || remoteport == 0)
798 fatal("port '%s' out of range",
799 isc_commandline_argument);
800 break;
802 case 'q':
803 quiet = ISC_TRUE;
804 break;
806 case 's':
807 servername = isc_commandline_argument;
808 break;
810 case 'V':
811 verbose = ISC_TRUE;
812 break;
814 case 'y':
815 keyname = isc_commandline_argument;
816 break;
818 case '?':
819 if (isc_commandline_option != '?') {
820 fprintf(stderr, "%s: invalid argument -%c\n",
821 program, isc_commandline_option);
822 usage(1);
824 /* FALLTHROUGH */
825 case 'h':
826 usage(0);
827 break;
828 default:
829 fprintf(stderr, "%s: unhandled option -%c\n",
830 program, isc_commandline_option);
831 exit(1);
835 argc -= isc_commandline_index;
836 argv += isc_commandline_index;
838 if (argc < 1)
839 usage(1);
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",
860 NULL, NULL));
862 parse_config(rndc_mctx, log, keyname, &pctx, &config);
864 isccc_result_register();
866 command = *argv;
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).
873 argslen = 0;
874 for (i = 0; i < argc; i++)
875 argslen += strlen(argv[i]) + 1;
877 args = isc_mem_get(rndc_mctx, argslen);
878 if (args == NULL)
879 DO("isc_mem_get", ISC_R_NOMEMORY);
881 p = args;
882 for (i = 0; i < argc; i++) {
883 size_t len = strlen(argv[i]);
884 memmove(p, argv[i], len);
885 p += len;
886 *p++ = ' ';
889 p--;
890 *p++ = '\0';
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);
922 dns_name_destroy();
924 if (show_final_mem)
925 isc_mem_stats(rndc_mctx, stderr);
927 isc_mem_destroy(&rndc_mctx);
929 if (failed)
930 return (1);
932 return (0);