rndc.c revision d6a0e00dc3e047f8470b938878926957070def77
c3c6770e537ea916265c78d0294ad108233e17c1Michael Sawyer/*
c3c6770e537ea916265c78d0294ad108233e17c1Michael Sawyer * Copyright (C) 2000-2016 Internet Systems Consortium, Inc. ("ISC")
bf8267aa453e5d2a735ed732a043b77a0b355b20Mark Andrews *
bf8267aa453e5d2a735ed732a043b77a0b355b20Mark Andrews * This Source Code Form is subject to the terms of the Mozilla Public
bf8267aa453e5d2a735ed732a043b77a0b355b20Mark Andrews * License, v. 2.0. If a copy of the MPL was not distributed with this
bf8267aa453e5d2a735ed732a043b77a0b355b20Mark Andrews * file, You can obtain one at http://mozilla.org/MPL/2.0/.
bf8267aa453e5d2a735ed732a043b77a0b355b20Mark Andrews */
bf8267aa453e5d2a735ed732a043b77a0b355b20Mark Andrews
bf8267aa453e5d2a735ed732a043b77a0b355b20Mark Andrews/*! \file */
bf8267aa453e5d2a735ed732a043b77a0b355b20Mark Andrews
bf8267aa453e5d2a735ed732a043b77a0b355b20Mark Andrews/*
bf8267aa453e5d2a735ed732a043b77a0b355b20Mark Andrews * Principal Author: DCL
bf8267aa453e5d2a735ed732a043b77a0b355b20Mark Andrews */
bf8267aa453e5d2a735ed732a043b77a0b355b20Mark Andrews
bf8267aa453e5d2a735ed732a043b77a0b355b20Mark Andrews#include <config.h>
bf8267aa453e5d2a735ed732a043b77a0b355b20Mark Andrews
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews#include <stdlib.h>
1d32b1df372d6be6bac6450739b9e5ea23819995Evan Hunt
c3c6770e537ea916265c78d0294ad108233e17c1Michael Sawyer#include <isc/app.h>
c3c6770e537ea916265c78d0294ad108233e17c1Michael Sawyer#include <isc/buffer.h>
c3c6770e537ea916265c78d0294ad108233e17c1Michael Sawyer#include <isc/commandline.h>
c3c6770e537ea916265c78d0294ad108233e17c1Michael Sawyer#include <isc/file.h>
c3c6770e537ea916265c78d0294ad108233e17c1Michael Sawyer#include <isc/log.h>
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews#include <isc/net.h>
c3c6770e537ea916265c78d0294ad108233e17c1Michael Sawyer#include <isc/mem.h>
30a60d2aff0ec1810262a8b8efc532e28b32bd57Evan Hunt#include <isc/print.h>
30a60d2aff0ec1810262a8b8efc532e28b32bd57Evan Hunt#include <isc/random.h>
30a60d2aff0ec1810262a8b8efc532e28b32bd57Evan Hunt#include <isc/socket.h>
30a60d2aff0ec1810262a8b8efc532e28b32bd57Evan Hunt#include <isc/stdtime.h>
30a60d2aff0ec1810262a8b8efc532e28b32bd57Evan Hunt#include <isc/string.h>
30a60d2aff0ec1810262a8b8efc532e28b32bd57Evan Hunt#include <isc/task.h>
30a60d2aff0ec1810262a8b8efc532e28b32bd57Evan Hunt#include <isc/thread.h>
30a60d2aff0ec1810262a8b8efc532e28b32bd57Evan Hunt#include <isc/util.h>
30a60d2aff0ec1810262a8b8efc532e28b32bd57Evan Hunt
30a60d2aff0ec1810262a8b8efc532e28b32bd57Evan Hunt#include <isccfg/namedconf.h>
30a60d2aff0ec1810262a8b8efc532e28b32bd57Evan Hunt
30a60d2aff0ec1810262a8b8efc532e28b32bd57Evan Hunt#include <isccc/alist.h>
30a60d2aff0ec1810262a8b8efc532e28b32bd57Evan Hunt#include <isccc/base64.h>
30a60d2aff0ec1810262a8b8efc532e28b32bd57Evan Hunt#include <isccc/cc.h>
30a60d2aff0ec1810262a8b8efc532e28b32bd57Evan Hunt#include <isccc/ccmsg.h>
30a60d2aff0ec1810262a8b8efc532e28b32bd57Evan Hunt#include <isccc/result.h>
30a60d2aff0ec1810262a8b8efc532e28b32bd57Evan Hunt#include <isccc/sexpr.h>
30a60d2aff0ec1810262a8b8efc532e28b32bd57Evan Hunt#include <isccc/types.h>
c634c94d673f1bab17e7f65d332f989b683e712cDavid Lawrence#include <isccc/util.h>
c3c6770e537ea916265c78d0294ad108233e17c1Michael Sawyer
c3c6770e537ea916265c78d0294ad108233e17c1Michael Sawyer#include <dns/name.h>
c3c6770e537ea916265c78d0294ad108233e17c1Michael Sawyer
c634c94d673f1bab17e7f65d332f989b683e712cDavid Lawrence#include <bind9/getaddresses.h>
c3c6770e537ea916265c78d0294ad108233e17c1Michael Sawyer
9069215eac23e32f4ef1c8e44ad7ff2865cfcdacEvan Hunt#include "util.h"
c3c6770e537ea916265c78d0294ad108233e17c1Michael Sawyer
c634c94d673f1bab17e7f65d332f989b683e712cDavid Lawrence#define SERVERADDRS 10
c3c6770e537ea916265c78d0294ad108233e17c1Michael Sawyer
c3c6770e537ea916265c78d0294ad108233e17c1Michael Sawyerconst char *progname;
c3c6770e537ea916265c78d0294ad108233e17c1Michael Sawyerisc_boolean_t verbose;
c634c94d673f1bab17e7f65d332f989b683e712cDavid Lawrence
fdebae839745f79a7550aeb49d15a930523ec483David Lawrencestatic const char *admin_conffile;
9069215eac23e32f4ef1c8e44ad7ff2865cfcdacEvan Huntstatic const char *admin_keyfile;
28002bd7cb4baa0eab9f47e1e51069c5ea7ea5d4Andreas Gustafssonstatic const char *version = VERSION;
28002bd7cb4baa0eab9f47e1e51069c5ea7ea5d4Andreas Gustafssonstatic const char *servername = NULL;
1d32b1df372d6be6bac6450739b9e5ea23819995Evan Huntstatic isc_sockaddr_t serveraddrs[SERVERADDRS];
1d32b1df372d6be6bac6450739b9e5ea23819995Evan Huntstatic isc_sockaddr_t local4, local6;
28002bd7cb4baa0eab9f47e1e51069c5ea7ea5d4Andreas Gustafssonstatic isc_boolean_t local4set = ISC_FALSE, local6set = ISC_FALSE;
28002bd7cb4baa0eab9f47e1e51069c5ea7ea5d4Andreas Gustafssonstatic int nserveraddrs;
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Huntstatic int currentaddr = 0;
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Huntstatic unsigned int remoteport = 0;
c3c6770e537ea916265c78d0294ad108233e17c1Michael Sawyerstatic isc_socketmgr_t *socketmgr = NULL;
c634c94d673f1bab17e7f65d332f989b683e712cDavid Lawrencestatic isc_buffer_t *databuf;
c3c6770e537ea916265c78d0294ad108233e17c1Michael Sawyerstatic isccc_ccmsg_t ccmsg;
c3c6770e537ea916265c78d0294ad108233e17c1Michael Sawyerstatic isc_uint32_t algorithm;
c3c6770e537ea916265c78d0294ad108233e17c1Michael Sawyerstatic isccc_region_t secret;
c634c94d673f1bab17e7f65d332f989b683e712cDavid Lawrencestatic isc_boolean_t failed = ISC_FALSE;
c3c6770e537ea916265c78d0294ad108233e17c1Michael Sawyerstatic isc_boolean_t c_flag = ISC_FALSE;
2de413d956c9f065958aaeebf5cd3a420e55939cMichael Sawyerstatic isc_mem_t *rndc_mctx;
c3c6770e537ea916265c78d0294ad108233e17c1Michael Sawyerstatic int sends, recvs, connects;
c634c94d673f1bab17e7f65d332f989b683e712cDavid Lawrencestatic char *command;
c3c6770e537ea916265c78d0294ad108233e17c1Michael Sawyerstatic char *args;
c3c6770e537ea916265c78d0294ad108233e17c1Michael Sawyerstatic char program[256];
c3c6770e537ea916265c78d0294ad108233e17c1Michael Sawyerstatic isc_socket_t *sock = NULL;
9069215eac23e32f4ef1c8e44ad7ff2865cfcdacEvan Huntstatic isc_uint32_t serial;
9069215eac23e32f4ef1c8e44ad7ff2865cfcdacEvan Huntstatic isc_boolean_t quiet = ISC_FALSE;
9069215eac23e32f4ef1c8e44ad7ff2865cfcdacEvan Huntstatic isc_boolean_t showresult = ISC_FALSE;
9069215eac23e32f4ef1c8e44ad7ff2865cfcdacEvan Hunt
9069215eac23e32f4ef1c8e44ad7ff2865cfcdacEvan Huntstatic void rndc_startconnect(isc_sockaddr_t *addr, isc_task_t *task);
9069215eac23e32f4ef1c8e44ad7ff2865cfcdacEvan Hunt
9069215eac23e32f4ef1c8e44ad7ff2865cfcdacEvan HuntISC_PLATFORM_NORETURN_PRE static void
9069215eac23e32f4ef1c8e44ad7ff2865cfcdacEvan Huntusage(int status) ISC_PLATFORM_NORETURN_POST;
9069215eac23e32f4ef1c8e44ad7ff2865cfcdacEvan Hunt
9069215eac23e32f4ef1c8e44ad7ff2865cfcdacEvan Huntstatic void
9069215eac23e32f4ef1c8e44ad7ff2865cfcdacEvan Huntusage(int status) {
9069215eac23e32f4ef1c8e44ad7ff2865cfcdacEvan Hunt fprintf(stderr, "\
9069215eac23e32f4ef1c8e44ad7ff2865cfcdacEvan HuntUsage: %s [-b address] [-c config] [-s server] [-p port]\n\
9069215eac23e32f4ef1c8e44ad7ff2865cfcdacEvan Hunt [-k key-file ] [-y key] [-r] [-V] command\n\
9069215eac23e32f4ef1c8e44ad7ff2865cfcdacEvan Hunt\n\
9069215eac23e32f4ef1c8e44ad7ff2865cfcdacEvan Huntcommand is one of the following:\n\
9069215eac23e32f4ef1c8e44ad7ff2865cfcdacEvan Hunt\n\
9069215eac23e32f4ef1c8e44ad7ff2865cfcdacEvan Hunt addzone zone [class [view]] { zone-options }\n\
9069215eac23e32f4ef1c8e44ad7ff2865cfcdacEvan Hunt Add zone to given view. Requires allow-new-zones option.\n\
9069215eac23e32f4ef1c8e44ad7ff2865cfcdacEvan Hunt delzone [-clean] zone [class [view]]\n\
9069215eac23e32f4ef1c8e44ad7ff2865cfcdacEvan Hunt Removes zone from given view.\n\
9069215eac23e32f4ef1c8e44ad7ff2865cfcdacEvan Hunt dnstap -reopen\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt Close and re-open the DNSTAP output file.\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt dnstap -roll count\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt Close, rename and re-open the DNSTAP output file(s).\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt dumpdb [-all|-cache|-zones|-adb|-bad|-fail] [view ...]\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt Dump cache(s) to the dump file (named_dump.db).\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt flush Flushes all of the server's caches.\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt flush [view] Flushes the server's cache for a view.\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt flushname name [view]\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt Flush the given name from the server's cache(s)\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt flushtree name [view]\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt Flush all names under the given name from the server's cache(s)\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt freeze Suspend updates to all dynamic zones.\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt freeze zone [class [view]]\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt Suspend updates to a dynamic zone.\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt halt Stop the server without saving pending updates.\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt halt -p Stop the server without saving pending updates reporting\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt process id.\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt loadkeys zone [class [view]]\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt Update keys without signing immediately.\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt managed-keys refresh [class [view]]\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt Check trust anchor for RFC 5011 key changes\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt managed-keys status [class [view]]\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt Display RFC 5011 managed keys information\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt managed-keys sync [class [view]]\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt Write RFC 5011 managed keys to disk\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt modzone zone [class [view]] { zone-options }\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt Modify a zone's configuration.\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt Requires allow-new-zones option.\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt notify zone [class [view]]\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt Resend NOTIFY messages for the zone.\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt notrace Set debugging level to 0.\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt nta -dump\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt List all negative trust anchors.\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt nta [-lifetime duration] [-force] domain [view]\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt Set a negative trust anchor, disabling DNSSEC validation\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt for the given domain.\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt Using -lifetime specifies the duration of the NTA, up\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt to one week.\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt Using -force prevents the NTA from expiring before its\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt full lifetime, even if the domain can validate sooner.\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt nta -remove domain [view]\n\
47e70d820ed07895a25e5b3520adf953114ac01eEvan Hunt Remove a negative trust anchor, re-enabling validation\n\
47e70d820ed07895a25e5b3520adf953114ac01eEvan Hunt for the given domain.\n\
47e70d820ed07895a25e5b3520adf953114ac01eEvan Hunt querylog newstate\n\
47e70d820ed07895a25e5b3520adf953114ac01eEvan Hunt Enable / disable query logging.\n\
47e70d820ed07895a25e5b3520adf953114ac01eEvan Hunt reconfig Reload configuration file and new zones only.\n\
47e70d820ed07895a25e5b3520adf953114ac01eEvan Hunt recursing Dump the queries that are currently recursing (named.recursing)\n\
47e70d820ed07895a25e5b3520adf953114ac01eEvan Hunt refresh zone [class [view]]\n\
47e70d820ed07895a25e5b3520adf953114ac01eEvan Hunt Schedule immediate maintenance for a zone.\n\
b5b934a0bb46aded1552a17473652b5a7f4a3274Evan Hunt reload Reload configuration file and zones.\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt reload zone [class [view]]\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt Reload a single zone.\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt retransfer zone [class [view]]\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt Retransfer a single zone without checking serial number.\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt scan Scan available network interfaces for changes.\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt secroots [view ...]\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt Write security roots to the secroots file.\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt showzone zone [class [view]]\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt Print a zone's configuration.\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt sign zone [class [view]]\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt Update zone keys, and sign as needed.\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt signing -clear all zone [class [view]]\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt Remove the private records for all keys that have\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt finished signing the given zone.\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt signing -clear <keyid>/<algorithm> zone [class [view]]\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt Remove the private record that indicating the given key\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt has finished signing the given zone.\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt signing -list zone [class [view]]\n\
2a6d60615cf07b164533dbb6bb1dce84ed2d037dEvan Hunt List the private records showing the state of DNSSEC\n\
2a6d60615cf07b164533dbb6bb1dce84ed2d037dEvan Hunt signing in the given zone.\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt signing -nsec3param hash flags iterations salt zone [class [view]]\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt Add NSEC3 chain to zone if already signed.\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt Prime zone with NSEC3 chain if not yet signed.\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt signing -nsec3param none zone [class [view]]\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt Remove NSEC3 chains from zone.\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt stats Write server statistics to the statistics file.\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt status Display status of the server.\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt stop Save pending updates to master files and stop the server.\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt stop -p Save pending updates to master files and stop the server\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt reporting process id.\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt sync [-clean] Dump changes to all dynamic zones to disk, and optionally\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt remove their journal files.\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt sync [-clean] zone [class [view]]\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt Dump a single zone's changes to disk, and optionally\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt remove its journal file.\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt thaw Enable updates to all dynamic zones and reload them.\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt thaw zone [class [view]]\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt Enable updates to a frozen dynamic zone and reload it.\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt trace Increment debugging level by one.\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt trace level Change the debugging level.\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt tsig-delete keyname [view]\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt Delete a TKEY-negotiated TSIG key.\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt tsig-list List all currently active TSIG keys, including both statically\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt configured and TKEY-negotiated keys.\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt validation newstate [view]\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt Enable / disable DNSSEC validation.\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt zonestatus zone [class [view]]\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt Display the current status of a zone.\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt\n\
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan HuntVersion: %s\n",
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt progname, version);
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt exit(status);
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt}
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Hunt
6de9744cf9c64be2145f663e4051196a4eaa9d45Evan Huntstatic void
cba23be7ba724b527f6a60c14caaeca9502fbc79Evan Huntget_addresses(const char *host, in_port_t port) {
cba23be7ba724b527f6a60c14caaeca9502fbc79Evan Hunt isc_result_t result;
cba23be7ba724b527f6a60c14caaeca9502fbc79Evan Hunt int found = 0, count;
cba23be7ba724b527f6a60c14caaeca9502fbc79Evan Hunt
cba23be7ba724b527f6a60c14caaeca9502fbc79Evan Hunt if (*host == '/') {
cba23be7ba724b527f6a60c14caaeca9502fbc79Evan Hunt result = isc_sockaddr_frompath(&serveraddrs[nserveraddrs],
cba23be7ba724b527f6a60c14caaeca9502fbc79Evan Hunt host);
cba23be7ba724b527f6a60c14caaeca9502fbc79Evan Hunt if (result == ISC_R_SUCCESS)
cba23be7ba724b527f6a60c14caaeca9502fbc79Evan Hunt nserveraddrs++;
cba23be7ba724b527f6a60c14caaeca9502fbc79Evan Hunt } else {
cba23be7ba724b527f6a60c14caaeca9502fbc79Evan Hunt count = SERVERADDRS - nserveraddrs;
cba23be7ba724b527f6a60c14caaeca9502fbc79Evan Hunt result = bind9_getaddresses(host, port,
a69070d8fab55dbc63ba9f96c9d3e34f0ea9119aMark Andrews &serveraddrs[nserveraddrs],
a69070d8fab55dbc63ba9f96c9d3e34f0ea9119aMark Andrews count, &found);
a69070d8fab55dbc63ba9f96c9d3e34f0ea9119aMark Andrews nserveraddrs += found;
a69070d8fab55dbc63ba9f96c9d3e34f0ea9119aMark Andrews }
a69070d8fab55dbc63ba9f96c9d3e34f0ea9119aMark Andrews if (result != ISC_R_SUCCESS)
a69070d8fab55dbc63ba9f96c9d3e34f0ea9119aMark Andrews fatal("couldn't get address for '%s': %s",
a69070d8fab55dbc63ba9f96c9d3e34f0ea9119aMark Andrews host, isc_result_totext(result));
a69070d8fab55dbc63ba9f96c9d3e34f0ea9119aMark Andrews INSIST(nserveraddrs > 0);
a69070d8fab55dbc63ba9f96c9d3e34f0ea9119aMark Andrews}
a69070d8fab55dbc63ba9f96c9d3e34f0ea9119aMark Andrews
a69070d8fab55dbc63ba9f96c9d3e34f0ea9119aMark Andrewsstatic void
a69070d8fab55dbc63ba9f96c9d3e34f0ea9119aMark Andrewsrndc_senddone(isc_task_t *task, isc_event_t *event) {
a69070d8fab55dbc63ba9f96c9d3e34f0ea9119aMark Andrews isc_socketevent_t *sevent = (isc_socketevent_t *)event;
a69070d8fab55dbc63ba9f96c9d3e34f0ea9119aMark Andrews
a69070d8fab55dbc63ba9f96c9d3e34f0ea9119aMark Andrews UNUSED(task);
a69070d8fab55dbc63ba9f96c9d3e34f0ea9119aMark Andrews
a69070d8fab55dbc63ba9f96c9d3e34f0ea9119aMark Andrews sends--;
a69070d8fab55dbc63ba9f96c9d3e34f0ea9119aMark Andrews if (sevent->result != ISC_R_SUCCESS)
a69070d8fab55dbc63ba9f96c9d3e34f0ea9119aMark Andrews fatal("send failed: %s", isc_result_totext(sevent->result));
a69070d8fab55dbc63ba9f96c9d3e34f0ea9119aMark Andrews isc_event_free(&event);
a69070d8fab55dbc63ba9f96c9d3e34f0ea9119aMark Andrews if (sends == 0 && recvs == 0) {
c5272fb3303425f794dab68f734f6a2a45dce01eMichael Sawyer isc_socket_detach(&sock);
c5272fb3303425f794dab68f734f6a2a45dce01eMichael Sawyer isc_task_shutdown(task);
c5272fb3303425f794dab68f734f6a2a45dce01eMichael Sawyer RUNTIME_CHECK(isc_app_shutdown() == ISC_R_SUCCESS);
c5272fb3303425f794dab68f734f6a2a45dce01eMichael Sawyer }
c5272fb3303425f794dab68f734f6a2a45dce01eMichael Sawyer}
c5272fb3303425f794dab68f734f6a2a45dce01eMichael Sawyer
c5272fb3303425f794dab68f734f6a2a45dce01eMichael Sawyerstatic void
c5272fb3303425f794dab68f734f6a2a45dce01eMichael Sawyerrndc_recvdone(isc_task_t *task, isc_event_t *event) {
6b9c29ec578de7fda057bd3b893ccda176378b1bMichael Sawyer isccc_sexpr_t *response = NULL;
6b9c29ec578de7fda057bd3b893ccda176378b1bMichael Sawyer isccc_sexpr_t *data;
6b9c29ec578de7fda057bd3b893ccda176378b1bMichael Sawyer isccc_region_t source;
6b9c29ec578de7fda057bd3b893ccda176378b1bMichael Sawyer char *errormsg = NULL;
6b9c29ec578de7fda057bd3b893ccda176378b1bMichael Sawyer char *textmsg = NULL;
6b9c29ec578de7fda057bd3b893ccda176378b1bMichael Sawyer isc_result_t result;
2de413d956c9f065958aaeebf5cd3a420e55939cMichael Sawyer
6b9c29ec578de7fda057bd3b893ccda176378b1bMichael Sawyer recvs--;
6b9c29ec578de7fda057bd3b893ccda176378b1bMichael Sawyer
6b9c29ec578de7fda057bd3b893ccda176378b1bMichael Sawyer if (ccmsg.result == ISC_R_EOF)
6b9c29ec578de7fda057bd3b893ccda176378b1bMichael Sawyer fatal("connection to remote host closed\n"
dc9c461b27df798ba7c3d9ba1446840c5f85553bMichael Sawyer "This may indicate that\n"
1b003261c2dd3e32778337c7a2788e4829066bd9Andreas Gustafsson "* the remote server is using an older version of"
1b003261c2dd3e32778337c7a2788e4829066bd9Andreas Gustafsson " the command protocol,\n"
1b003261c2dd3e32778337c7a2788e4829066bd9Andreas Gustafsson "* this host is not authorized to connect,\n"
1b003261c2dd3e32778337c7a2788e4829066bd9Andreas Gustafsson "* the clocks are not synchronized, or\n"
3ad7f12f7439471a0922ed3952221e93aef9db69Andreas Gustafsson "* the key is invalid.");
3ad7f12f7439471a0922ed3952221e93aef9db69Andreas Gustafsson
3ad7f12f7439471a0922ed3952221e93aef9db69Andreas Gustafsson if (ccmsg.result != ISC_R_SUCCESS)
3ad7f12f7439471a0922ed3952221e93aef9db69Andreas Gustafsson fatal("recv failed: %s", isc_result_totext(ccmsg.result));
3ad7f12f7439471a0922ed3952221e93aef9db69Andreas Gustafsson
3ad7f12f7439471a0922ed3952221e93aef9db69Andreas Gustafsson source.rstart = isc_buffer_base(&ccmsg.buffer);
3ad7f12f7439471a0922ed3952221e93aef9db69Andreas Gustafsson source.rend = isc_buffer_used(&ccmsg.buffer);
3ad7f12f7439471a0922ed3952221e93aef9db69Andreas Gustafsson
3ad7f12f7439471a0922ed3952221e93aef9db69Andreas Gustafsson DO("parse message",
0759eb6a0dab024873df528b0ffad804ea31615dMichael Sawyer isccc_cc_fromwire(&source, &response, algorithm, &secret));
dc9c461b27df798ba7c3d9ba1446840c5f85553bMichael Sawyer
dc9c461b27df798ba7c3d9ba1446840c5f85553bMichael Sawyer data = isccc_alist_lookup(response, "_data");
dc9c461b27df798ba7c3d9ba1446840c5f85553bMichael Sawyer if (!isccc_alist_alistp(data))
dc9c461b27df798ba7c3d9ba1446840c5f85553bMichael Sawyer fatal("bad or missing data section in response");
dc9c461b27df798ba7c3d9ba1446840c5f85553bMichael Sawyer result = isccc_cc_lookupstring(data, "err", &errormsg);
dc9c461b27df798ba7c3d9ba1446840c5f85553bMichael Sawyer if (result == ISC_R_SUCCESS) {
dc9c461b27df798ba7c3d9ba1446840c5f85553bMichael Sawyer failed = ISC_TRUE;
dc9c461b27df798ba7c3d9ba1446840c5f85553bMichael Sawyer fprintf(stderr, "%s: '%s' failed: %s\n",
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson progname, command, errormsg);
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson }
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson else if (result != ISC_R_NOTFOUND)
9069215eac23e32f4ef1c8e44ad7ff2865cfcdacEvan Hunt fprintf(stderr, "%s: parsing response failed: %s\n",
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson progname, isc_result_totext(result));
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson result = isccc_cc_lookupstring(data, "text", &textmsg);
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson if (result == ISC_R_SUCCESS) {
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson if ((!quiet || failed) && strlen(textmsg) != 0U)
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson fprintf(failed ? stderr : stdout, "%s\n", textmsg);
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson } else if (result != ISC_R_NOTFOUND)
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson fprintf(stderr, "%s: parsing response failed: %s\n",
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson progname, isc_result_totext(result));
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson if (showresult) {
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson isc_result_t eresult;
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson result = isccc_cc_lookupuint32(data, "result", &eresult);
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson if (result == ISC_R_SUCCESS)
9069215eac23e32f4ef1c8e44ad7ff2865cfcdacEvan Hunt printf("%s %u\n", isc_result_toid(eresult), eresult);
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson else
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson printf("NONE -1\n");
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson }
1d32b1df372d6be6bac6450739b9e5ea23819995Evan Hunt
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson isc_event_free(&event);
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson isccc_sexpr_free(&response);
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson if (sends == 0 && recvs == 0) {
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson isc_socket_detach(&sock);
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson isc_task_shutdown(task);
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson RUNTIME_CHECK(isc_app_shutdown() == ISC_R_SUCCESS);
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson }
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson}
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafssonstatic void
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafssonrndc_recvnonce(isc_task_t *task, isc_event_t *event) {
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson isccc_sexpr_t *response = NULL;
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson isccc_sexpr_t *_ctrl;
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson isccc_region_t source;
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson isc_result_t result;
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson isc_uint32_t nonce;
5337a9e53c7df1ef40d70528f2360c5e4cb9a7d1Andreas Gustafsson isccc_sexpr_t *request = NULL;
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews isccc_time_t now;
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews isc_region_t r;
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews isccc_sexpr_t *data;
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews isc_buffer_t b;
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews recvs--;
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews if (ccmsg.result == ISC_R_EOF)
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews fatal("connection to remote host closed\n"
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews "This may indicate that\n"
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews "* the remote server is using an older version of"
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews " the command protocol,\n"
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews "* this host is not authorized to connect,\n"
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews "* the clocks are not synchronized,\n"
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews "* the key signing algorithm is incorrect, or\n"
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews "* the key is invalid.");
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews if (ccmsg.result != ISC_R_SUCCESS)
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews fatal("recv failed: %s", isc_result_totext(ccmsg.result));
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews source.rstart = isc_buffer_base(&ccmsg.buffer);
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews source.rend = isc_buffer_used(&ccmsg.buffer);
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews DO("parse message",
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews isccc_cc_fromwire(&source, &response, algorithm, &secret));
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews _ctrl = isccc_alist_lookup(response, "_ctrl");
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews if (!isccc_alist_alistp(_ctrl))
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews fatal("bad or missing ctrl section in response");
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews nonce = 0;
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews if (isccc_cc_lookupuint32(_ctrl, "_nonce", &nonce) != ISC_R_SUCCESS)
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews nonce = 0;
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews isc_stdtime_get(&now);
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews DO("create message", isccc_cc_createmessage(1, NULL, NULL, ++serial,
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews now, now + 60, &request));
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews data = isccc_alist_lookup(request, "_data");
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews if (data == NULL)
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews fatal("_data section missing");
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews if (isccc_cc_definestring(data, "type", args) == NULL)
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews fatal("out of memory");
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews if (nonce != 0) {
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews _ctrl = isccc_alist_lookup(request, "_ctrl");
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews if (_ctrl == NULL)
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews fatal("_ctrl section missing");
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews if (isccc_cc_defineuint32(_ctrl, "_nonce", nonce) == NULL)
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews fatal("out of memory");
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews }
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews isc_buffer_clear(databuf);
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews /* Skip the length field (4 bytes) */
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews isc_buffer_add(databuf, 4);
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews DO("render message",
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews isccc_cc_towire(request, &databuf, algorithm, &secret));
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews isc_buffer_init(&b, databuf->base, 4);
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews isc_buffer_putuint32(&b, databuf->used - 4);
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews r.base = databuf->base;
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews r.length = databuf->used;
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews isccc_ccmsg_cancelread(&ccmsg);
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews DO("schedule recv", isccc_ccmsg_readmessage(&ccmsg, task,
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews rndc_recvdone, NULL));
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews recvs++;
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews DO("send message", isc_socket_send(sock, &r, task, rndc_senddone,
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews NULL));
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews sends++;
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews isc_event_free(&event);
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews isccc_sexpr_free(&response);
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews return;
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews}
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrewsstatic void
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrewsrndc_connected(isc_task_t *task, isc_event_t *event) {
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews char socktext[ISC_SOCKADDR_FORMATSIZE];
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews isc_socketevent_t *sevent = (isc_socketevent_t *)event;
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews isccc_sexpr_t *request = NULL;
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews isccc_sexpr_t *data;
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews isccc_time_t now;
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews isc_region_t r;
e2f470bebb3a0c107bc4ac86c6920c21e50e83e0Brian Wellington isc_buffer_t b;
9069215eac23e32f4ef1c8e44ad7ff2865cfcdacEvan Hunt isc_result_t result;
e2f470bebb3a0c107bc4ac86c6920c21e50e83e0Brian Wellington
e2f470bebb3a0c107bc4ac86c6920c21e50e83e0Brian Wellington connects--;
e2f470bebb3a0c107bc4ac86c6920c21e50e83e0Brian Wellington
e2f470bebb3a0c107bc4ac86c6920c21e50e83e0Brian Wellington if (sevent->result != ISC_R_SUCCESS) {
e2f470bebb3a0c107bc4ac86c6920c21e50e83e0Brian Wellington isc_sockaddr_format(&serveraddrs[currentaddr], socktext,
f0a1134d331b2aa871306c73d2787960918eaab1Andreas Gustafsson sizeof(socktext));
f0a1134d331b2aa871306c73d2787960918eaab1Andreas Gustafsson if (sevent->result != ISC_R_CANCELED &&
f0a1134d331b2aa871306c73d2787960918eaab1Andreas Gustafsson ++currentaddr < nserveraddrs)
e2f470bebb3a0c107bc4ac86c6920c21e50e83e0Brian Wellington {
e2f470bebb3a0c107bc4ac86c6920c21e50e83e0Brian Wellington notify("connection failed: %s: %s", socktext,
e2f470bebb3a0c107bc4ac86c6920c21e50e83e0Brian Wellington isc_result_totext(sevent->result));
e2f470bebb3a0c107bc4ac86c6920c21e50e83e0Brian Wellington isc_socket_detach(&sock);
e2f470bebb3a0c107bc4ac86c6920c21e50e83e0Brian Wellington isc_event_free(&event);
e2f470bebb3a0c107bc4ac86c6920c21e50e83e0Brian Wellington rndc_startconnect(&serveraddrs[currentaddr], task);
82f0630bae09598209cc37c1db00ff4356efee27Mark Andrews return;
82f0630bae09598209cc37c1db00ff4356efee27Mark Andrews } else
82f0630bae09598209cc37c1db00ff4356efee27Mark Andrews fatal("connect failed: %s: %s", socktext,
82f0630bae09598209cc37c1db00ff4356efee27Mark Andrews isc_result_totext(sevent->result));
82f0630bae09598209cc37c1db00ff4356efee27Mark Andrews }
82f0630bae09598209cc37c1db00ff4356efee27Mark Andrews
82f0630bae09598209cc37c1db00ff4356efee27Mark Andrews isc_stdtime_get(&now);
82f0630bae09598209cc37c1db00ff4356efee27Mark Andrews DO("create message", isccc_cc_createmessage(1, NULL, NULL, ++serial,
82f0630bae09598209cc37c1db00ff4356efee27Mark Andrews now, now + 60, &request));
16cc4a1f56d0f9a300419da7e75e3b72169e608aMark Andrews data = isccc_alist_lookup(request, "_data");
16cc4a1f56d0f9a300419da7e75e3b72169e608aMark Andrews if (data == NULL)
16cc4a1f56d0f9a300419da7e75e3b72169e608aMark Andrews fatal("_data section missing");
16cc4a1f56d0f9a300419da7e75e3b72169e608aMark Andrews if (isccc_cc_definestring(data, "type", "null") == NULL)
16cc4a1f56d0f9a300419da7e75e3b72169e608aMark Andrews fatal("out of memory");
16cc4a1f56d0f9a300419da7e75e3b72169e608aMark Andrews
16cc4a1f56d0f9a300419da7e75e3b72169e608aMark Andrews isc_buffer_clear(databuf);
16cc4a1f56d0f9a300419da7e75e3b72169e608aMark Andrews /* Skip the length field (4 bytes) */
16cc4a1f56d0f9a300419da7e75e3b72169e608aMark Andrews isc_buffer_add(databuf, 4);
16cc4a1f56d0f9a300419da7e75e3b72169e608aMark Andrews
16cc4a1f56d0f9a300419da7e75e3b72169e608aMark Andrews DO("render message",
16cc4a1f56d0f9a300419da7e75e3b72169e608aMark Andrews isccc_cc_towire(request, &databuf, algorithm, &secret));
16cc4a1f56d0f9a300419da7e75e3b72169e608aMark Andrews
ea5334a36ebf7c833ec493345d86e04953041fdcEvan Hunt isc_buffer_init(&b, databuf->base, 4);
16cc4a1f56d0f9a300419da7e75e3b72169e608aMark Andrews isc_buffer_putuint32(&b, databuf->used - 4);
16cc4a1f56d0f9a300419da7e75e3b72169e608aMark Andrews
16cc4a1f56d0f9a300419da7e75e3b72169e608aMark Andrews r.base = databuf->base;
16cc4a1f56d0f9a300419da7e75e3b72169e608aMark Andrews r.length = databuf->used;
8aee18709f238406719768b8a6b843a15c5075f8Mark Andrews
ac21f918f23ce95fd5be807428ee9e2c42319878Evan Hunt isccc_ccmsg_init(rndc_mctx, sock, &ccmsg);
ac21f918f23ce95fd5be807428ee9e2c42319878Evan Hunt isccc_ccmsg_setmaxsize(&ccmsg, 1024 * 1024);
ac21f918f23ce95fd5be807428ee9e2c42319878Evan Hunt
ac21f918f23ce95fd5be807428ee9e2c42319878Evan Hunt DO("schedule recv", isccc_ccmsg_readmessage(&ccmsg, task,
ac21f918f23ce95fd5be807428ee9e2c42319878Evan Hunt rndc_recvnonce, NULL));
ac21f918f23ce95fd5be807428ee9e2c42319878Evan Hunt recvs++;
ac21f918f23ce95fd5be807428ee9e2c42319878Evan Hunt DO("send message", isc_socket_send(sock, &r, task, rndc_senddone,
ac21f918f23ce95fd5be807428ee9e2c42319878Evan Hunt NULL));
ac21f918f23ce95fd5be807428ee9e2c42319878Evan Hunt sends++;
ac21f918f23ce95fd5be807428ee9e2c42319878Evan Hunt isc_event_free(&event);
ac21f918f23ce95fd5be807428ee9e2c42319878Evan Hunt}
ac21f918f23ce95fd5be807428ee9e2c42319878Evan Hunt
f5b7359c5730d39ff6eff24ae87c9c74a04c2e5cMark Andrewsstatic void
f5b7359c5730d39ff6eff24ae87c9c74a04c2e5cMark Andrewsrndc_startconnect(isc_sockaddr_t *addr, isc_task_t *task) {
f5b7359c5730d39ff6eff24ae87c9c74a04c2e5cMark Andrews isc_result_t result;
f5b7359c5730d39ff6eff24ae87c9c74a04c2e5cMark Andrews int pf;
f5b7359c5730d39ff6eff24ae87c9c74a04c2e5cMark Andrews isc_sockettype_t type;
f5b7359c5730d39ff6eff24ae87c9c74a04c2e5cMark Andrews
f5b7359c5730d39ff6eff24ae87c9c74a04c2e5cMark Andrews char socktext[ISC_SOCKADDR_FORMATSIZE];
f5b7359c5730d39ff6eff24ae87c9c74a04c2e5cMark Andrews
f5b7359c5730d39ff6eff24ae87c9c74a04c2e5cMark Andrews isc_sockaddr_format(addr, socktext, sizeof(socktext));
f5b7359c5730d39ff6eff24ae87c9c74a04c2e5cMark Andrews
f5b7359c5730d39ff6eff24ae87c9c74a04c2e5cMark Andrews notify("using server %s (%s)", servername, socktext);
f5b7359c5730d39ff6eff24ae87c9c74a04c2e5cMark Andrews
f5b7359c5730d39ff6eff24ae87c9c74a04c2e5cMark Andrews pf = isc_sockaddr_pf(addr);
f5b7359c5730d39ff6eff24ae87c9c74a04c2e5cMark Andrews if (pf == AF_INET || pf == AF_INET6)
f5b7359c5730d39ff6eff24ae87c9c74a04c2e5cMark Andrews type = isc_sockettype_tcp;
f5b7359c5730d39ff6eff24ae87c9c74a04c2e5cMark Andrews else
f5b7359c5730d39ff6eff24ae87c9c74a04c2e5cMark Andrews type = isc_sockettype_unix;
f5b7359c5730d39ff6eff24ae87c9c74a04c2e5cMark Andrews DO("create socket", isc_socket_create(socketmgr, pf, type, &sock));
f5b7359c5730d39ff6eff24ae87c9c74a04c2e5cMark Andrews switch (isc_sockaddr_pf(addr)) {
f5b7359c5730d39ff6eff24ae87c9c74a04c2e5cMark Andrews case AF_INET:
1e8c2e72e7d0f48ac37b9b15712e638631b3b619Brian Wellington DO("bind socket", isc_socket_bind(sock, &local4, 0));
c3c6770e537ea916265c78d0294ad108233e17c1Michael Sawyer break;
case AF_INET6:
DO("bind socket", isc_socket_bind(sock, &local6, 0));
break;
default:
break;
}
DO("connect", isc_socket_connect(sock, addr, task, rndc_connected,
NULL));
connects++;
}
static void
rndc_start(isc_task_t *task, isc_event_t *event) {
isc_event_free(&event);
currentaddr = 0;
rndc_startconnect(&serveraddrs[currentaddr], task);
}
static void
parse_config(isc_mem_t *mctx, isc_log_t *log, const char *keyname,
cfg_parser_t **pctxp, cfg_obj_t **configp)
{
isc_result_t result;
const char *conffile = admin_conffile;
const cfg_obj_t *addresses = NULL;
const cfg_obj_t *defkey = NULL;
const cfg_obj_t *options = NULL;
const cfg_obj_t *servers = NULL;
const cfg_obj_t *server = NULL;
const cfg_obj_t *keys = NULL;
const cfg_obj_t *key = NULL;
const cfg_obj_t *defport = NULL;
const cfg_obj_t *secretobj = NULL;
const cfg_obj_t *algorithmobj = NULL;
cfg_obj_t *config = NULL;
const cfg_obj_t *address = NULL;
const cfg_listelt_t *elt;
const char *secretstr;
const char *algorithmstr;
static char secretarray[1024];
const cfg_type_t *conftype = &cfg_type_rndcconf;
isc_boolean_t key_only = ISC_FALSE;
const cfg_listelt_t *element;
if (! isc_file_exists(conffile)) {
conffile = admin_keyfile;
conftype = &cfg_type_rndckey;
if (c_flag)
fatal("%s does not exist", admin_conffile);
if (! isc_file_exists(conffile))
fatal("neither %s nor %s was found",
admin_conffile, admin_keyfile);
key_only = ISC_TRUE;
} else if (! c_flag && isc_file_exists(admin_keyfile)) {
fprintf(stderr, "WARNING: key file (%s) exists, but using "
"default configuration file (%s)\n",
admin_keyfile, admin_conffile);
}
DO("create parser", cfg_parser_create(mctx, log, pctxp));
/*
* The parser will output its own errors, so DO() is not used.
*/
result = cfg_parse_file(*pctxp, conffile, conftype, &config);
if (result != ISC_R_SUCCESS)
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) {
const 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);
algorithmstr = cfg_obj_asstring(algorithmobj);
if (strcasecmp(algorithmstr, "hmac-md5") == 0)
algorithm = ISCCC_ALG_HMACMD5;
else if (strcasecmp(algorithmstr, "hmac-sha1") == 0)
algorithm = ISCCC_ALG_HMACSHA1;
else if (strcasecmp(algorithmstr, "hmac-sha224") == 0)
algorithm = ISCCC_ALG_HMACSHA224;
else if (strcasecmp(algorithmstr, "hmac-sha256") == 0)
algorithm = ISCCC_ALG_HMACSHA256;
else if (strcasecmp(algorithmstr, "hmac-sha384") == 0)
algorithm = ISCCC_ALG_HMACSHA384;
else if (strcasecmp(algorithmstr, "hmac-sha512") == 0)
algorithm = ISCCC_ALG_HMACSHA512;
else
fatal("unsupported algorithm: %s", algorithmstr);
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;
const 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_result_t result = ISC_R_SUCCESS;
isc_boolean_t show_final_mem = ISC_FALSE;
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)
memmove(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));
isc_commandline_errprint = ISC_FALSE;
while ((ch = isc_commandline_parse(argc, argv, "b:c:hk:Mmp:qrs: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;
c_flag = ISC_TRUE;
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 'q':
quiet = ISC_TRUE;
break;
case 'r':
showresult = ISC_TRUE;
break;
case 's':
servername = isc_commandline_argument;
break;
case 'V':
verbose = ISC_TRUE;
break;
case 'y':
keyname = isc_commandline_argument;
break;
case '?':
if (isc_commandline_option != '?') {
fprintf(stderr, "%s: invalid argument -%c\n",
program, isc_commandline_option);
usage(1);
}
/* FALLTHROUGH */
case 'h':
usage(0);
break;
default:
fprintf(stderr, "%s: unhandled option -%c\n",
program, isc_commandline_option);
exit(1);
}
}
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, &rndc_mctx));
DO("create socket manager", isc_socketmgr_create(rndc_mctx, &socketmgr));
DO("create task manager", isc_taskmgr_create(rndc_mctx, 1, 0, &taskmgr));
DO("create task", isc_task_create(taskmgr, 0, &task));
DO("create logging context", isc_log_create(rndc_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(rndc_mctx, log, keyname, &pctx, &config);
isccc_result_register();
command = *argv;
DO("allocate data buffer",
isc_buffer_allocate(rndc_mctx, &databuf, 2048));
/*
* 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(rndc_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]);
memmove(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(rndc_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(rndc_mctx, args, argslen);
isccc_ccmsg_invalidate(&ccmsg);
dns_name_destroy();
isc_buffer_free(&databuf);
if (show_final_mem)
isc_mem_stats(rndc_mctx, stderr);
isc_mem_destroy(&rndc_mctx);
if (failed)
return (1);
return (0);
}