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