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