rndc.c revision b326d7e3a3a50eb65dd06db007d2fddc62606bbf
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews/*
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
0add14467b53f33ace931f9a4790113cb8b5e45dTinderbox User * Copyright (C) 2000-2003 Internet Software Consortium.
bf8267aa453e5d2a735ed732a043b77a0b355b20Mark Andrews *
bf8267aa453e5d2a735ed732a043b77a0b355b20Mark Andrews * Permission to use, copy, modify, and distribute this software for any
bf8267aa453e5d2a735ed732a043b77a0b355b20Mark Andrews * purpose with or without fee is hereby granted, provided that the above
bf8267aa453e5d2a735ed732a043b77a0b355b20Mark Andrews * copyright notice and this permission notice appear in all copies.
bf8267aa453e5d2a735ed732a043b77a0b355b20Mark Andrews *
bf8267aa453e5d2a735ed732a043b77a0b355b20Mark Andrews * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
bf8267aa453e5d2a735ed732a043b77a0b355b20Mark Andrews * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
bf8267aa453e5d2a735ed732a043b77a0b355b20Mark Andrews * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
bf8267aa453e5d2a735ed732a043b77a0b355b20Mark Andrews * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
bf8267aa453e5d2a735ed732a043b77a0b355b20Mark Andrews * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
bf8267aa453e5d2a735ed732a043b77a0b355b20Mark Andrews * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
bf8267aa453e5d2a735ed732a043b77a0b355b20Mark Andrews * PERFORMANCE OF THIS SOFTWARE.
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews */
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews/* $Id: rndc.c,v 1.104 2005/03/14 23:55:57 marka Exp $ */
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews
68116c5a5fd36fef812fc207de3b7714db2994d5Evan Hunt/*
68116c5a5fd36fef812fc207de3b7714db2994d5Evan Hunt * Principal Author: DCL
68116c5a5fd36fef812fc207de3b7714db2994d5Evan Hunt */
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews#include <config.h>
95de316a5d99b09804eda3223d1a41623d7ed611Evan Hunt
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Hunt#include <stdlib.h>
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Hunt
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Hunt#include <isc/app.h>
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Hunt#include <isc/buffer.h>
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Hunt#include <isc/commandline.h>
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Hunt#include <isc/file.h>
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews#include <isc/log.h>
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews#include <isc/net.h>
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews#include <isc/mem.h>
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Hunt#include <isc/random.h>
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt#include <isc/socket.h>
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt#include <isc/stdtime.h>
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Hunt#include <isc/string.h>
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Hunt#include <isc/task.h>
68116c5a5fd36fef812fc207de3b7714db2994d5Evan Hunt#include <isc/thread.h>
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt#include <isc/util.h>
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Hunt
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Hunt#include <isccfg/namedconf.h>
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Hunt
89740699cd2191d9b84e67716c281b2dfeba5e56Evan Hunt#include <isccc/alist.h>
89740699cd2191d9b84e67716c281b2dfeba5e56Evan Hunt#include <isccc/base64.h>
89740699cd2191d9b84e67716c281b2dfeba5e56Evan Hunt#include <isccc/cc.h>
ab6fd5e89266a29efdafee3784d2cb06f8624b1bMark Andrews#include <isccc/ccmsg.h>
89740699cd2191d9b84e67716c281b2dfeba5e56Evan Hunt#include <isccc/result.h>
89740699cd2191d9b84e67716c281b2dfeba5e56Evan Hunt#include <isccc/sexpr.h>
89740699cd2191d9b84e67716c281b2dfeba5e56Evan Hunt#include <isccc/types.h>
68116c5a5fd36fef812fc207de3b7714db2994d5Evan Hunt#include <isccc/util.h>
89740699cd2191d9b84e67716c281b2dfeba5e56Evan Hunt
ab6fd5e89266a29efdafee3784d2cb06f8624b1bMark Andrews#include <bind9/getaddresses.h>
89740699cd2191d9b84e67716c281b2dfeba5e56Evan Hunt
89740699cd2191d9b84e67716c281b2dfeba5e56Evan Hunt#include "util.h"
89740699cd2191d9b84e67716c281b2dfeba5e56Evan Hunt
89740699cd2191d9b84e67716c281b2dfeba5e56Evan Hunt#define SERVERADDRS 10
89740699cd2191d9b84e67716c281b2dfeba5e56Evan Hunt
89740699cd2191d9b84e67716c281b2dfeba5e56Evan Huntchar *progname;
89740699cd2191d9b84e67716c281b2dfeba5e56Evan Huntisc_boolean_t verbose;
89740699cd2191d9b84e67716c281b2dfeba5e56Evan Hunt
89740699cd2191d9b84e67716c281b2dfeba5e56Evan Huntstatic const char *admin_conffile;
89740699cd2191d9b84e67716c281b2dfeba5e56Evan Huntstatic const char *admin_keyfile;
89740699cd2191d9b84e67716c281b2dfeba5e56Evan Huntstatic const char *version = VERSION;
89740699cd2191d9b84e67716c281b2dfeba5e56Evan Huntstatic const char *servername = NULL;
89740699cd2191d9b84e67716c281b2dfeba5e56Evan Huntstatic isc_sockaddr_t serveraddrs[SERVERADDRS];
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Huntstatic isc_sockaddr_t local4, local6;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrewsstatic isc_boolean_t local4set = ISC_FALSE, local6set = ISC_FALSE;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrewsstatic int nserveraddrs;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrewsstatic int currentaddr = 0;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrewsstatic unsigned int remoteport = 0;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Huntstatic isc_socketmgr_t *socketmgr = NULL;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrewsstatic unsigned char databuf[2048];
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Huntstatic isccc_ccmsg_t ccmsg;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Huntstatic isccc_region_t secret;
6643b0dd91249ace16218ef667967c87b291992cMark Andrewsstatic isc_boolean_t failed = ISC_FALSE;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Huntstatic isc_mem_t *mctx;
68116c5a5fd36fef812fc207de3b7714db2994d5Evan Huntstatic int sends, recvs, connects;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Huntstatic char *command;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Huntstatic char *args;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Huntstatic char program[256];
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Huntstatic isc_socket_t *sock = NULL;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Huntstatic isc_uint32_t serial;
6643b0dd91249ace16218ef667967c87b291992cMark Andrews
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Huntstatic void rndc_startconnect(isc_sockaddr_t *addr, isc_task_t *task);
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Huntstatic void
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Huntusage(int status) {
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt fprintf(stderr, "\
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan HuntUsage: %s [-c config] [-s server] [-p port]\n\
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt [-k key-file ] [-y key] [-V] command\n\
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt\n\
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Huntcommand is one of the following:\n\
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt\n\
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt reload Reload configuration file and zones.\n\
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt reload zone [class [view]]\n\
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt Reload a single zone.\n\
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt refresh zone [class [view]]\n\
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt Schedule immediate maintenance for a zone.\n\
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt retransfer zone [class [view]]\n\
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt Retransfer a single zone without checking serial number.\n\
6643b0dd91249ace16218ef667967c87b291992cMark Andrews freeze Suspend updates to all dynamic zones.\n\
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt freeze zone [class [view]]\n\
68116c5a5fd36fef812fc207de3b7714db2994d5Evan Hunt Suspend updates to a dynamic zone.\n\
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt thaw Enable updates to all dynamic zones and reload them.\n\
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt thaw zone [class [view]]\n\
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt Enable updates to a frozen dynamic zone and reload it.\n\
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt notify zone [class [view]]\n\
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt Resend NOTIFY messages for the zone.\n\
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews reconfig Reload configuration file and new zones only.\n\
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt stats Write server statistics to the statistics file.\n\
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt querylog Toggle query logging.\n\
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt dumpdb [-all|-cache|-zones] [view ...]\n\
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt Dump cache(s) to the dump file (named_dump.db).\n\
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt stop Save pending updates to master files and stop the server.\n\
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt stop -p Save pending updates to master files and stop the server\n\
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt reporting process id.\n\
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews halt Stop the server without saving pending updates.\n\
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews halt -p Stop the server without saving pending updates reporting\n\
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt process id.\n\
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews trace Increment debugging level by one.\n\
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews trace level Change the debugging level.\n\
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews notrace Set debugging level to 0.\n\
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews flush Flushes all of the server's caches.\n\
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews flush [view] Flushes the server's cache for a view.\n\
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews flushname name [view]\n\
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews Flush the given name from the server's cache(s)\n\
68116c5a5fd36fef812fc207de3b7714db2994d5Evan Hunt status Display status of the server.\n\
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews recursing Dump the queries that are currently recursing (named.recursing)\n\
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews *restart Restart the server.\n\
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews\n\
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews* == not yet implemented\n\
d76ed813a51465e5c47d521ab09ea20c06f1428dMark AndrewsVersion: %s\n",
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews progname, version);
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews exit(status);
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews}
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrewsstatic void
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrewsget_addresses(const char *host, in_port_t port) {
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews isc_result_t result;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews int found = 0, count;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews if (*host == '/') {
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews result = isc_sockaddr_frompath(&serveraddrs[nserveraddrs],
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews host);
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews if (result == ISC_R_SUCCESS)
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews nserveraddrs++;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews } else {
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Hunt count = SERVERADDRS - nserveraddrs;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt result = bind9_getaddresses(host, port,
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Hunt &serveraddrs[nserveraddrs],
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Hunt count, &found);
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Hunt nserveraddrs += found;
68116c5a5fd36fef812fc207de3b7714db2994d5Evan Hunt }
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt if (result != ISC_R_SUCCESS)
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Hunt fatal("couldn't get address for '%s': %s",
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Hunt host, isc_result_totext(result));
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Hunt INSIST(nserveraddrs > 0);
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Hunt}
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrewsstatic void
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrewsrndc_senddone(isc_task_t *task, isc_event_t *event) {
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews isc_socketevent_t *sevent = (isc_socketevent_t *)event;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews UNUSED(task);
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt sends--;
6643b0dd91249ace16218ef667967c87b291992cMark Andrews if (sevent->result != ISC_R_SUCCESS)
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt fatal("send failed: %s", isc_result_totext(sevent->result));
68116c5a5fd36fef812fc207de3b7714db2994d5Evan Hunt isc_event_free(&event);
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt}
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Huntstatic void
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Huntrndc_recvdone(isc_task_t *task, isc_event_t *event) {
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt isccc_sexpr_t *response = NULL;
6643b0dd91249ace16218ef667967c87b291992cMark Andrews isccc_sexpr_t *data;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt isccc_region_t source;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt char *errormsg = NULL;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt char *textmsg = NULL;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt isc_result_t result;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt recvs--;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt if (ccmsg.result == ISC_R_EOF)
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt fatal("connection to remote host closed\n"
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt "This may indicate that\n"
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt "* the remote server is using an older version of"
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt " the command protocol,\n"
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt "* this host is not authorized to connect,\n"
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt "* the clocks are not syncronized, or\n"
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt "* the key is invalid.");
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt if (ccmsg.result != ISC_R_SUCCESS)
6643b0dd91249ace16218ef667967c87b291992cMark Andrews fatal("recv failed: %s", isc_result_totext(ccmsg.result));
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt
68116c5a5fd36fef812fc207de3b7714db2994d5Evan Hunt source.rstart = isc_buffer_base(&ccmsg.buffer);
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt source.rend = isc_buffer_used(&ccmsg.buffer);
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt DO("parse message", isccc_cc_fromwire(&source, &response, &secret));
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt data = isccc_alist_lookup(response, "_data");
6643b0dd91249ace16218ef667967c87b291992cMark Andrews if (data == NULL)
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt fatal("no data section in response");
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt result = isccc_cc_lookupstring(data, "err", &errormsg);
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt if (result == ISC_R_SUCCESS) {
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt failed = ISC_TRUE;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt fprintf(stderr, "%s: '%s' failed: %s\n",
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt progname, command, errormsg);
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt }
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews else if (result != ISC_R_NOTFOUND)
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews fprintf(stderr, "%s: parsing response failed: %s\n",
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews progname, isc_result_totext(result));
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews result = isccc_cc_lookupstring(data, "text", &textmsg);
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews if (result == ISC_R_SUCCESS)
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews printf("%s\n", textmsg);
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews else if (result != ISC_R_NOTFOUND)
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews fprintf(stderr, "%s: parsing response failed: %s\n",
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews progname, isc_result_totext(result));
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews
68116c5a5fd36fef812fc207de3b7714db2994d5Evan Hunt isc_event_free(&event);
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews isccc_sexpr_free(&response);
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews isc_socket_detach(&sock);
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews isc_task_shutdown(task);
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews RUNTIME_CHECK(isc_app_shutdown() == ISC_R_SUCCESS);
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews}
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrewsstatic void
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrewsrndc_recvnonce(isc_task_t *task, isc_event_t *event) {
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews isccc_sexpr_t *response = NULL;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews isccc_sexpr_t *_ctrl;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews isccc_region_t source;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews isc_result_t result;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews isc_uint32_t nonce;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews isccc_sexpr_t *request = NULL;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews isccc_time_t now;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews isc_region_t r;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews isccc_sexpr_t *data;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews isccc_region_t message;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews isc_uint32_t len;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews isc_buffer_t b;
60988462e5d6db53205851d056e3482a29239be9Evan Hunt
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews recvs--;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews if (ccmsg.result == ISC_R_EOF)
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews fatal("connection to remote host closed\n"
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews "This may indicate that\n"
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews "* the remote server is using an older version of"
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews " the command protocol,\n"
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews "* this host is not authorized to connect,\n"
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews "* the clocks are not syncronized, or\n"
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews "* the key is invalid.");
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews
60988462e5d6db53205851d056e3482a29239be9Evan Hunt if (ccmsg.result != ISC_R_SUCCESS)
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews fatal("recv failed: %s", isc_result_totext(ccmsg.result));
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews source.rstart = isc_buffer_base(&ccmsg.buffer);
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews source.rend = isc_buffer_used(&ccmsg.buffer);
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Hunt
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt DO("parse message", isccc_cc_fromwire(&source, &response, &secret));
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Hunt _ctrl = isccc_alist_lookup(response, "_ctrl");
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Hunt if (_ctrl == NULL)
68116c5a5fd36fef812fc207de3b7714db2994d5Evan Hunt fatal("_ctrl section missing");
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt nonce = 0;
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Hunt if (isccc_cc_lookupuint32(_ctrl, "_nonce", &nonce) != ISC_R_SUCCESS)
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Hunt nonce = 0;
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Hunt
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Hunt isc_stdtime_get(&now);
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews DO("create message", isccc_cc_createmessage(1, NULL, NULL, ++serial,
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews now, now + 60, &request));
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews data = isccc_alist_lookup(request, "_data");
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt if (data == NULL)
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews fatal("_data section missing");
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt if (isccc_cc_definestring(data, "type", args) == NULL)
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt fatal("out of memory");
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews if (nonce != 0) {
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt _ctrl = isccc_alist_lookup(request, "_ctrl");
68116c5a5fd36fef812fc207de3b7714db2994d5Evan Hunt if (_ctrl == NULL)
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt fatal("_ctrl section missing");
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt if (isccc_cc_defineuint32(_ctrl, "_nonce", nonce) == NULL)
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt fatal("out of memory");
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt }
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt message.rstart = databuf + 4;
6643b0dd91249ace16218ef667967c87b291992cMark Andrews message.rend = databuf + sizeof(databuf);
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt DO("render message", isccc_cc_towire(request, &message, &secret));
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt len = sizeof(databuf) - REGION_SIZE(message);
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt isc_buffer_init(&b, databuf, 4);
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt isc_buffer_putuint32(&b, len - 4);
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt r.length = len;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt r.base = databuf;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt isccc_ccmsg_cancelread(&ccmsg);
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt DO("schedule recv", isccc_ccmsg_readmessage(&ccmsg, task,
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt rndc_recvdone, NULL));
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt recvs++;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt DO("send message", isc_socket_send(sock, &r, task, rndc_senddone,
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt NULL));
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt sends++;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt isc_event_free(&event);
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt isccc_sexpr_free(&response);
6643b0dd91249ace16218ef667967c87b291992cMark Andrews return;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt}
68116c5a5fd36fef812fc207de3b7714db2994d5Evan Hunt
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Huntstatic void
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Huntrndc_connected(isc_task_t *task, isc_event_t *event) {
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt isc_socketevent_t *sevent = (isc_socketevent_t *)event;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt isccc_sexpr_t *request = NULL;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt isccc_sexpr_t *data;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews isccc_time_t now;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt isccc_region_t message;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt isc_region_t r;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt isc_uint32_t len;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt isc_buffer_t b;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt isc_result_t result;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt connects--;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews if (sevent->result != ISC_R_SUCCESS) {
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews if (sevent->result != ISC_R_CANCELED &&
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt currentaddr < nserveraddrs)
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews {
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews notify("connection failed: %s",
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews isc_result_totext(sevent->result));
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews isc_socket_detach(&sock);
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews isc_event_free(&event);
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews rndc_startconnect(&serveraddrs[currentaddr++], task);
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews return;
68116c5a5fd36fef812fc207de3b7714db2994d5Evan Hunt } else
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews fatal("connect failed: %s",
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews isc_result_totext(sevent->result));
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews }
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews isc_stdtime_get(&now);
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews DO("create message", isccc_cc_createmessage(1, NULL, NULL, ++serial,
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews now, now + 60, &request));
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews data = isccc_alist_lookup(request, "_data");
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews if (data == NULL)
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews fatal("_data section missing");
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews if (isccc_cc_definestring(data, "type", "null") == NULL)
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews fatal("out of memory");
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews message.rstart = databuf + 4;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews message.rend = databuf + sizeof(databuf);
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews DO("render message", isccc_cc_towire(request, &message, &secret));
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews len = sizeof(databuf) - REGION_SIZE(message);
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews isc_buffer_init(&b, databuf, 4);
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews isc_buffer_putuint32(&b, len - 4);
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews r.length = len;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews r.base = databuf;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Hunt isccc_ccmsg_init(mctx, sock, &ccmsg);
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt isccc_ccmsg_setmaxsize(&ccmsg, 1024);
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Hunt
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Hunt DO("schedule recv", isccc_ccmsg_readmessage(&ccmsg, task,
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Hunt rndc_recvnonce, NULL));
68116c5a5fd36fef812fc207de3b7714db2994d5Evan Hunt recvs++;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt DO("send message", isc_socket_send(sock, &r, task, rndc_senddone,
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Hunt NULL));
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Hunt sends++;
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Hunt isc_event_free(&event);
66e50468dde42a9757ac489e738d8b2db8fd7f80Evan Hunt}
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrewsstatic void
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrewsrndc_startconnect(isc_sockaddr_t *addr, isc_task_t *task) {
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews isc_result_t result;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt int pf;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews isc_sockettype_t type;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt
68116c5a5fd36fef812fc207de3b7714db2994d5Evan Hunt char socktext[ISC_SOCKADDR_FORMATSIZE];
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt isc_sockaddr_format(addr, socktext, sizeof(socktext));
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt notify("using server %s (%s)", servername, socktext);
68116c5a5fd36fef812fc207de3b7714db2994d5Evan Hunt
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt pf = isc_sockaddr_pf(addr);
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt if (pf == AF_INET || pf == AF_INET6)
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt type = isc_sockettype_tcp;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt else
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt type = isc_sockettype_unix;
6643b0dd91249ace16218ef667967c87b291992cMark Andrews DO("create socket", isc_socket_create(socketmgr, pf, type, &sock));
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt switch (isc_sockaddr_pf(addr)) {
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt case AF_INET:
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt DO("bind socket", isc_socket_bind(sock, &local4));
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt break;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt case AF_INET6:
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt DO("bind socket", isc_socket_bind(sock, &local6));
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt break;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt default:
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt break;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt }
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt DO("connect", isc_socket_connect(sock, addr, task, rndc_connected,
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt NULL));
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt connects++;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt}
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Huntstatic void
68116c5a5fd36fef812fc207de3b7714db2994d5Evan Huntrndc_start(isc_task_t *task, isc_event_t *event) {
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt isc_event_free(&event);
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt
6643b0dd91249ace16218ef667967c87b291992cMark Andrews currentaddr = 0;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt rndc_startconnect(&serveraddrs[currentaddr++], task);
68116c5a5fd36fef812fc207de3b7714db2994d5Evan Hunt}
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Huntstatic void
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Huntparse_config(isc_mem_t *mctx, isc_log_t *log, const char *keyname,
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt cfg_parser_t **pctxp, cfg_obj_t **configp)
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt{
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews isc_result_t result;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt const char *conffile = admin_conffile;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt cfg_obj_t *addresses = NULL;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt cfg_obj_t *defkey = NULL;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt cfg_obj_t *options = NULL;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt cfg_obj_t *servers = NULL;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt cfg_obj_t *server = NULL;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt cfg_obj_t *keys = NULL;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews cfg_obj_t *key = NULL;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews cfg_obj_t *defport = NULL;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews cfg_obj_t *secretobj = NULL;
56c9fcf07580457442b80ac32bdb7c07aa0df870Evan Hunt cfg_obj_t *algorithmobj = NULL;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews cfg_obj_t *config = NULL;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews cfg_obj_t *address = NULL;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews cfg_listelt_t *elt;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews const char *secretstr;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews const char *algorithm;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews static char secretarray[1024];
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews const cfg_type_t *conftype = &cfg_type_rndcconf;
68116c5a5fd36fef812fc207de3b7714db2994d5Evan Hunt isc_boolean_t key_only = ISC_FALSE;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews cfg_listelt_t *element;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews if (! isc_file_exists(conffile)) {
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews conffile = admin_keyfile;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews conftype = &cfg_type_rndckey;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews if (! isc_file_exists(conffile))
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews fatal("neither %s nor %s was found",
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews admin_conffile, admin_keyfile);
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews key_only = ISC_TRUE;
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews }
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews DO("create parser", cfg_parser_create(mctx, log, pctxp));
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews /*
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews * The parser will output its own errors, so DO() is not used.
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews */
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews result = cfg_parse_file(*pctxp, conffile, conftype, &config);
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews if (result != ISC_R_SUCCESS)
d76ed813a51465e5c47d521ab09ea20c06f1428dMark Andrews fatal("could not load rndc configuration");
if (!key_only)
(void)cfg_map_get(config, "options", &options);
if (key_only && servername == NULL)
servername = "127.0.0.1";
else if (servername == NULL && options != NULL) {
cfg_obj_t *defserverobj = NULL;
(void)cfg_map_get(options, "default-server", &defserverobj);
if (defserverobj != NULL)
servername = cfg_obj_asstring(defserverobj);
}
if (servername == NULL)
fatal("no server specified and no default");
if (!key_only) {
(void)cfg_map_get(config, "server", &servers);
if (servers != NULL) {
for (elt = cfg_list_first(servers);
elt != NULL;
elt = cfg_list_next(elt))
{
const char *name;
server = cfg_listelt_value(elt);
name = cfg_obj_asstring(cfg_map_getname(server));
if (strcasecmp(name, servername) == 0)
break;
server = NULL;
}
}
}
/*
* Look for the name of the key to use.
*/
if (keyname != NULL)
; /* Was set on command line, do nothing. */
else if (server != NULL) {
DO("get key for server", cfg_map_get(server, "key", &defkey));
keyname = cfg_obj_asstring(defkey);
} else if (options != NULL) {
DO("get default key", cfg_map_get(options, "default-key",
&defkey));
keyname = cfg_obj_asstring(defkey);
} else if (!key_only)
fatal("no key for server and no default");
/*
* Get the key's definition.
*/
if (key_only)
DO("get key", cfg_map_get(config, "key", &key));
else {
DO("get config key list", cfg_map_get(config, "key", &keys));
for (elt = cfg_list_first(keys);
elt != NULL;
elt = cfg_list_next(elt))
{
key = cfg_listelt_value(elt);
if (strcasecmp(cfg_obj_asstring(cfg_map_getname(key)),
keyname) == 0)
break;
}
if (elt == NULL)
fatal("no key definition for name %s", keyname);
}
(void)cfg_map_get(key, "secret", &secretobj);
(void)cfg_map_get(key, "algorithm", &algorithmobj);
if (secretobj == NULL || algorithmobj == NULL)
fatal("key must have algorithm and secret");
secretstr = cfg_obj_asstring(secretobj);
algorithm = cfg_obj_asstring(algorithmobj);
if (strcasecmp(algorithm, "hmac-md5") != 0)
fatal("unsupported algorithm: %s", algorithm);
secret.rstart = (unsigned char *)secretarray;
secret.rend = (unsigned char *)secretarray + sizeof(secretarray);
DO("decode base64 secret", isccc_base64_decode(secretstr, &secret));
secret.rend = secret.rstart;
secret.rstart = (unsigned char *)secretarray;
/*
* Find the port to connect to.
*/
if (remoteport != 0)
; /* Was set on command line, do nothing. */
else {
if (server != NULL)
(void)cfg_map_get(server, "port", &defport);
if (defport == NULL && options != NULL)
(void)cfg_map_get(options, "default-port", &defport);
}
if (defport != NULL) {
remoteport = cfg_obj_asuint32(defport);
if (remoteport > 65535 || remoteport == 0)
fatal("port %u out of range", remoteport);
} else if (remoteport == 0)
remoteport = NS_CONTROL_PORT;
if (server != NULL)
result = cfg_map_get(server, "addresses", &addresses);
else
result = ISC_R_NOTFOUND;
if (result == ISC_R_SUCCESS) {
for (element = cfg_list_first(addresses);
element != NULL;
element = cfg_list_next(element))
{
isc_sockaddr_t sa;
address = cfg_listelt_value(element);
if (!cfg_obj_issockaddr(address)) {
unsigned int myport;
const char *name;
cfg_obj_t *obj;
obj = cfg_tuple_get(address, "name");
name = cfg_obj_asstring(obj);
obj = cfg_tuple_get(address, "port");
if (cfg_obj_isuint32(obj)) {
myport = cfg_obj_asuint32(obj);
if (myport > ISC_UINT16_MAX ||
myport == 0)
fatal("port %u out of range",
myport);
} else
myport = remoteport;
if (nserveraddrs < SERVERADDRS)
get_addresses(name, (in_port_t) myport);
else
fprintf(stderr, "too many address: "
"%s: dropped\n", name);
continue;
}
sa = *cfg_obj_assockaddr(address);
if (isc_sockaddr_getport(&sa) == 0)
isc_sockaddr_setport(&sa, remoteport);
if (nserveraddrs < SERVERADDRS)
serveraddrs[nserveraddrs++] = sa;
else {
char socktext[ISC_SOCKADDR_FORMATSIZE];
isc_sockaddr_format(&sa, socktext,
sizeof(socktext));
fprintf(stderr,
"too many address: %s: dropped\n",
socktext);
}
}
}
if (!local4set && server != NULL) {
address = NULL;
cfg_map_get(server, "source-address", &address);
if (address != NULL) {
local4 = *cfg_obj_assockaddr(address);
local4set = ISC_TRUE;
}
}
if (!local4set && options != NULL) {
address = NULL;
cfg_map_get(options, "default-source-address", &address);
if (address != NULL) {
local4 = *cfg_obj_assockaddr(address);
local4set = ISC_TRUE;
}
}
if (!local6set && server != NULL) {
address = NULL;
cfg_map_get(server, "source-address-v6", &address);
if (address != NULL) {
local6 = *cfg_obj_assockaddr(address);
local6set = ISC_TRUE;
}
}
if (!local6set && options != NULL) {
address = NULL;
cfg_map_get(options, "default-source-address-v6", &address);
if (address != NULL) {
local6 = *cfg_obj_assockaddr(address);
local6set = ISC_TRUE;
}
}
*configp = config;
}
int
main(int argc, char **argv) {
isc_boolean_t show_final_mem = ISC_FALSE;
isc_result_t result = ISC_R_SUCCESS;
isc_taskmgr_t *taskmgr = NULL;
isc_task_t *task = NULL;
isc_log_t *log = NULL;
isc_logconfig_t *logconfig = NULL;
isc_logdestination_t logdest;
cfg_parser_t *pctx = NULL;
cfg_obj_t *config = NULL;
const char *keyname = NULL;
struct in_addr in;
struct in6_addr in6;
char *p;
size_t argslen;
int ch;
int i;
result = isc_file_progname(*argv, program, sizeof(program));
if (result != ISC_R_SUCCESS)
memcpy(program, "rndc", 5);
progname = program;
admin_conffile = RNDC_CONFFILE;
admin_keyfile = RNDC_KEYFILE;
isc_sockaddr_any(&local4);
isc_sockaddr_any6(&local6);
result = isc_app_start();
if (result != ISC_R_SUCCESS)
fatal("isc_app_start() failed: %s", isc_result_totext(result));
while ((ch = isc_commandline_parse(argc, argv, "b:c:k:Mmp:s:Vy:"))
!= -1) {
switch (ch) {
case 'b':
if (inet_pton(AF_INET, isc_commandline_argument,
&in) == 1) {
isc_sockaddr_fromin(&local4, &in, 0);
local4set = ISC_TRUE;
} else if (inet_pton(AF_INET6, isc_commandline_argument,
&in6) == 1) {
isc_sockaddr_fromin6(&local6, &in6, 0);
local6set = ISC_TRUE;
}
break;
case 'c':
admin_conffile = isc_commandline_argument;
break;
case 'k':
admin_keyfile = isc_commandline_argument;
break;
case 'M':
isc_mem_debugging = ISC_MEM_DEBUGTRACE;
break;
case 'm':
show_final_mem = ISC_TRUE;
break;
case 'p':
remoteport = atoi(isc_commandline_argument);
if (remoteport > 65535 || remoteport == 0)
fatal("port '%s' out of range",
isc_commandline_argument);
break;
case 's':
servername = isc_commandline_argument;
break;
case 'V':
verbose = ISC_TRUE;
break;
case 'y':
keyname = isc_commandline_argument;
break;
case '?':
usage(0);
break;
default:
fatal("unexpected error parsing command arguments: "
"got %c\n", ch);
break;
}
}
argc -= isc_commandline_index;
argv += isc_commandline_index;
if (argc < 1)
usage(1);
isc_random_get(&serial);
DO("create memory context", isc_mem_create(0, 0, &mctx));
DO("create socket manager", isc_socketmgr_create(mctx, &socketmgr));
DO("create task manager", isc_taskmgr_create(mctx, 1, 0, &taskmgr));
DO("create task", isc_task_create(taskmgr, 0, &task));
DO("create logging context", isc_log_create(mctx, &log, &logconfig));
isc_log_setcontext(log);
DO("setting log tag", isc_log_settag(logconfig, progname));
logdest.file.stream = stderr;
logdest.file.name = NULL;
logdest.file.versions = ISC_LOG_ROLLNEVER;
logdest.file.maximum_size = 0;
DO("creating log channel",
isc_log_createchannel(logconfig, "stderr",
ISC_LOG_TOFILEDESC, ISC_LOG_INFO, &logdest,
ISC_LOG_PRINTTAG|ISC_LOG_PRINTLEVEL));
DO("enabling log channel", isc_log_usechannel(logconfig, "stderr",
NULL, NULL));
parse_config(mctx, log, keyname, &pctx, &config);
isccc_result_register();
command = *argv;
/*
* Convert argc/argv into a space-delimited command string
* similar to what the user might enter in interactive mode
* (if that were implemented).
*/
argslen = 0;
for (i = 0; i < argc; i++)
argslen += strlen(argv[i]) + 1;
args = isc_mem_get(mctx, argslen);
if (args == NULL)
DO("isc_mem_get", ISC_R_NOMEMORY);
p = args;
for (i = 0; i < argc; i++) {
size_t len = strlen(argv[i]);
memcpy(p, argv[i], len);
p += len;
*p++ = ' ';
}
p--;
*p++ = '\0';
INSIST(p == args + argslen);
notify("%s", command);
if (strcmp(command, "restart") == 0)
fatal("'%s' is not implemented", command);
if (nserveraddrs == 0)
get_addresses(servername, (in_port_t) remoteport);
DO("post event", isc_app_onrun(mctx, task, rndc_start, NULL));
result = isc_app_run();
if (result != ISC_R_SUCCESS)
fatal("isc_app_run() failed: %s", isc_result_totext(result));
if (connects > 0 || sends > 0 || recvs > 0)
isc_socket_cancel(sock, task, ISC_SOCKCANCEL_ALL);
isc_task_detach(&task);
isc_taskmgr_destroy(&taskmgr);
isc_socketmgr_destroy(&socketmgr);
isc_log_destroy(&log);
isc_log_setcontext(NULL);
cfg_obj_destroy(pctx, &config);
cfg_parser_destroy(&pctx);
isc_mem_put(mctx, args, argslen);
isccc_ccmsg_invalidate(&ccmsg);
if (show_final_mem)
isc_mem_stats(mctx, stderr);
isc_mem_destroy(&mctx);
if (failed)
return (1);
return (0);
}