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