1 /* $NetBSD: rndc.c,v 1.12 2015/07/08 17:28:55 christos Exp $ */
2
3 /*
4 * Copyright (C) 2004-2015 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2000-2003 Internet Software Consortium.
6 *
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.
10 *
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.
18 */
19
20 /*! \file */
21
22 /*
23 * Principal Author: DCL
24 */
25
26 #include <config.h>
27
28 #include <stdlib.h>
29
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>
44
45 #include <isccfg/namedconf.h>
46
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>
55
56 #include <dns/name.h>
57
58 #include <bind9/getaddresses.h>
59
60 #include "util.h"
61
62 #define SERVERADDRS 10
63
64 const char *progname;
65 isc_boolean_t verbose;
66
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;
92
93 static void rndc_startconnect(isc_sockaddr_t *addr, isc_task_t *task);
94
95 ISC_PLATFORM_NORETURN_PRE static void
96 usage(int status) ISC_PLATFORM_NORETURN_POST;
97
98 static void
usage(int status)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\
103 \n\
104 command is one of the following:\n\
105 \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\
182 \n\
183 Version: %s\n",
184 progname, version);
185
186 exit(status);
187 }
188
189 static void
get_addresses(const char * host,in_port_t port)190 get_addresses(const char *host, in_port_t port) {
191 isc_result_t result;
192 int found = 0, count;
193
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;
205 }
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);
210 }
211
212 static void
rndc_senddone(isc_task_t * task,isc_event_t * event)213 rndc_senddone(isc_task_t *task, isc_event_t *event) {
214 isc_socketevent_t *sevent = (isc_socketevent_t *)event;
215
216 UNUSED(task);
217
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);
226 }
227 }
228
229 static void
rndc_recvdone(isc_task_t * task,isc_event_t * event)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;
237
238 recvs--;
239
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.");
248
249 if (ccmsg.result != ISC_R_SUCCESS)
250 fatal("recv failed: %s", isc_result_totext(ccmsg.result));
251
252 source.rstart = isc_buffer_base(&ccmsg.buffer);
253 source.rend = isc_buffer_used(&ccmsg.buffer);
254
255 DO("parse message",
256 isccc_cc_fromwire(&source, &response, algorithm, &secret));
257
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);
266 }
267 else if (result != ISC_R_NOTFOUND)
268 fprintf(stderr, "%s: parsing response failed: %s\n",
269 progname, isc_result_totext(result));
270
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));
278
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);
285 }
286 }
287
288 static void
rndc_recvnonce(isc_task_t * task,isc_event_t * event)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;
302
303 recvs--;
304
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.");
314
315 if (ccmsg.result != ISC_R_SUCCESS)
316 fatal("recv failed: %s", isc_result_totext(ccmsg.result));
317
318 source.rstart = isc_buffer_base(&ccmsg.buffer);
319 source.rend = isc_buffer_used(&ccmsg.buffer);
320
321 DO("parse message",
322 isccc_cc_fromwire(&source, &response, algorithm, &secret));
323
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;
330
331 isc_stdtime_get(&now);
332
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");
346 }
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;
356
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++;
364
365 isc_event_free(&event);
366 isccc_sexpr_free(&response);
367 return;
368 }
369
370 static void
rndc_connected(isc_task_t * task,isc_event_t * event)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;
382
383 connects--;
384
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)
390 {
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));
400 }
401
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;
419
420 isccc_ccmsg_init(rndc_mctx, sock, &ccmsg);
421 isccc_ccmsg_setmaxsize(&ccmsg, 1024 * 1024);
422
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);
430 }
431
432 static void
rndc_startconnect(isc_sockaddr_t * addr,isc_task_t * task)433 rndc_startconnect(isc_sockaddr_t *addr, isc_task_t *task) {
434 isc_result_t result;
435 int pf;
436 isc_sockettype_t type;
437
438 char socktext[ISC_SOCKADDR_FORMATSIZE];
439
440 isc_sockaddr_format(addr, socktext, sizeof(socktext));
441
442 notify("using server %s (%s)", servername, socktext);
443
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;
459 }
460 DO("connect", isc_socket_connect(sock, addr, task, rndc_connected,
461 NULL));
462 connects++;
463 }
464
465 static void
rndc_start(isc_task_t * task,isc_event_t * event)466 rndc_start(isc_task_t *task, isc_event_t *event) {
467 isc_event_free(&event);
468
469 currentaddr = 0;
470 rndc_startconnect(&serveraddrs[currentaddr], task);
471 }
472
473 static void
parse_config(isc_mem_t * mctx,isc_log_t * log,const char * keyname,cfg_parser_t ** pctxp,cfg_obj_t ** configp)474 parse_config(isc_mem_t *mctx, isc_log_t *log, const char *keyname,
475 cfg_parser_t **pctxp, cfg_obj_t **configp)
476 {
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;
498
499 if (! isc_file_exists(conffile)) {
500 conffile = admin_keyfile;
501 conftype = &cfg_type_rndckey;
502
503 if (c_flag)
504 fatal("%s does not exist", admin_conffile);
505
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);
514 }
515
516 DO("create parser", cfg_parser_create(mctx, log, pctxp));
517
518 /*
519 * The parser will output its own errors, so DO() is not used.
520 */
521 result = cfg_parse_file(*pctxp, conffile, conftype, &config);
522 if (result != ISC_R_SUCCESS)
523 fatal("could not load rndc configuration");
524
525 if (!key_only)
526 (void)cfg_map_get(config, "options", &options);
527
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);
535 }
536
537 if (servername == NULL)
538 fatal("no server specified and no default");
539
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))
546 {
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;
553 }
554 }
555 }
556
557 /*
558 * Look for the name of the key to use.
559 */
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");
571
572 /*
573 * Get the key's definition.
574 */
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))
582 {
583 key = cfg_listelt_value(elt);
584 if (strcasecmp(cfg_obj_asstring(cfg_map_getname(key)),
585 keyname) == 0)
586 break;
587 }
588 if (elt == NULL)
589 fatal("no key definition for name %s", keyname);
590 }
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");
595
596 secretstr = cfg_obj_asstring(secretobj);
597 algorithmstr = cfg_obj_asstring(algorithmobj);
598
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);
613
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;
619
620 /*
621 * Find the port to connect to.
622 */
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);
630 }
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;
637
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))
646 {
647 isc_sockaddr_t sa;
648
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;
654
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;
672 }
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];
680
681 isc_sockaddr_format(&sa, socktext,
682 sizeof(socktext));
683 fprintf(stderr,
684 "too many address: %s: dropped\n",
685 socktext);
686 }
687 }
688 }
689
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;
696 }
697 }
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;
704 }
705 }
706
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;
713 }
714 }
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;
721 }
722 }
723
724 *configp = config;
725 }
726
727 int
main(int argc,char ** argv)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;
745
746 result = isc_file_progname(*argv, program, sizeof(program));
747 if (result != ISC_R_SUCCESS)
748 memmove(program, "rndc", 5);
749 progname = program;
750
751 admin_conffile = RNDC_CONFFILE;
752 admin_keyfile = RNDC_KEYFILE;
753
754 isc_sockaddr_any(&local4);
755 isc_sockaddr_any6(&local6);
756
757 result = isc_app_start();
758 if (result != ISC_R_SUCCESS)
759 fatal("isc_app_start() failed: %s", isc_result_totext(result));
760
761 isc_commandline_errprint = ISC_FALSE;
762
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;
775 }
776 break;
777
778 case 'c':
779 admin_conffile = isc_commandline_argument;
780 c_flag = ISC_TRUE;
781 break;
782
783 case 'k':
784 admin_keyfile = isc_commandline_argument;
785 break;
786
787 case 'M':
788 isc_mem_debugging = ISC_MEM_DEBUGTRACE;
789 break;
790
791 case 'm':
792 show_final_mem = ISC_TRUE;
793 break;
794
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;
801
802 case 'q':
803 quiet = ISC_TRUE;
804 break;
805
806 case 's':
807 servername = isc_commandline_argument;
808 break;
809
810 case 'V':
811 verbose = ISC_TRUE;
812 break;
813
814 case 'y':
815 keyname = isc_commandline_argument;
816 break;
817
818 case '?':
819 if (isc_commandline_option != '?') {
820 fprintf(stderr, "%s: invalid argument -%c\n",
821 program, isc_commandline_option);
822 usage(1);
823 }
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);
832 }
833 }
834
835 argc -= isc_commandline_index;
836 argv += isc_commandline_index;
837
838 if (argc < 1)
839 usage(1);
840
841 isc_random_get(&serial);
842
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));
847
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));
861
862 parse_config(rndc_mctx, log, keyname, &pctx, &config);
863
864 isccc_result_register();
865
866 command = *argv;
867
868 /*
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).
872 */
873 argslen = 0;
874 for (i = 0; i < argc; i++)
875 argslen += strlen(argv[i]) + 1;
876
877 args = isc_mem_get(rndc_mctx, argslen);
878 if (args == NULL)
879 DO("isc_mem_get", ISC_R_NOMEMORY);
880
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++ = ' ';
887 }
888
889 p--;
890 *p++ = '\0';
891 INSIST(p == args + argslen);
892
893 notify("%s", command);
894
895 if (strcmp(command, "restart") == 0)
896 fatal("'%s' is not implemented", command);
897
898 if (nserveraddrs == 0)
899 get_addresses(servername, (in_port_t) remoteport);
900
901 DO("post event", isc_app_onrun(rndc_mctx, task, rndc_start, NULL));
902
903 result = isc_app_run();
904 if (result != ISC_R_SUCCESS)
905 fatal("isc_app_run() failed: %s", isc_result_totext(result));
906
907 if (connects > 0 || sends > 0 || recvs > 0)
908 isc_socket_cancel(sock, task, ISC_SOCKCANCEL_ALL);
909
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);
915
916 cfg_obj_destroy(pctx, &config);
917 cfg_parser_destroy(&pctx);
918
919 isc_mem_put(rndc_mctx, args, argslen);
920 isccc_ccmsg_invalidate(&ccmsg);
921
922 dns_name_destroy();
923
924 if (show_final_mem)
925 isc_mem_stats(rndc_mctx, stderr);
926
927 isc_mem_destroy(&rndc_mctx);
928
929 if (failed)
930 return (1);
931
932 return (0);
933 }
934