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