1 1.15 christos /* $NetBSD: rndc.c,v 1.15 2026/04/08 00:15:45 christos Exp $ */ 2 1.1 christos 3 1.1 christos /* 4 1.1 christos * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 1.1 christos * 6 1.8 christos * SPDX-License-Identifier: MPL-2.0 7 1.8 christos * 8 1.1 christos * This Source Code Form is subject to the terms of the Mozilla Public 9 1.1 christos * License, v. 2.0. If a copy of the MPL was not distributed with this 10 1.6 christos * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 1.1 christos * 12 1.1 christos * See the COPYRIGHT file distributed with this work for additional 13 1.1 christos * information regarding copyright ownership. 14 1.1 christos */ 15 1.1 christos 16 1.1 christos /*! \file */ 17 1.1 christos 18 1.3 christos #include <inttypes.h> 19 1.3 christos #include <stdbool.h> 20 1.1 christos #include <stdlib.h> 21 1.1 christos 22 1.11 christos #include <isc/attributes.h> 23 1.1 christos #include <isc/buffer.h> 24 1.1 christos #include <isc/commandline.h> 25 1.1 christos #include <isc/file.h> 26 1.13 christos #include <isc/getaddresses.h> 27 1.1 christos #include <isc/log.h> 28 1.13 christos #include <isc/loop.h> 29 1.7 christos #include <isc/managers.h> 30 1.4 christos #include <isc/mem.h> 31 1.1 christos #include <isc/net.h> 32 1.11 christos #include <isc/netmgr.h> 33 1.1 christos #include <isc/random.h> 34 1.4 christos #include <isc/refcount.h> 35 1.11 christos #include <isc/result.h> 36 1.1 christos #include <isc/stdtime.h> 37 1.1 christos #include <isc/string.h> 38 1.1 christos #include <isc/thread.h> 39 1.1 christos #include <isc/util.h> 40 1.1 christos 41 1.4 christos #include <dns/name.h> 42 1.1 christos 43 1.1 christos #include <isccc/alist.h> 44 1.1 christos #include <isccc/base64.h> 45 1.1 christos #include <isccc/cc.h> 46 1.1 christos #include <isccc/ccmsg.h> 47 1.1 christos #include <isccc/sexpr.h> 48 1.1 christos #include <isccc/types.h> 49 1.1 christos #include <isccc/util.h> 50 1.1 christos 51 1.4 christos #include <isccfg/namedconf.h> 52 1.1 christos 53 1.1 christos #include "util.h" 54 1.1 christos 55 1.11 christos #define SERVERADDRS 10 56 1.11 christos #define RNDC_TIMEOUT 60 * 1000 57 1.1 christos 58 1.11 christos const char *progname = NULL; 59 1.3 christos bool verbose; 60 1.1 christos 61 1.11 christos static isc_nm_t *netmgr = NULL; 62 1.13 christos static isc_loopmgr_t *loopmgr = NULL; 63 1.11 christos 64 1.11 christos static const char *admin_conffile = NULL; 65 1.11 christos static const char *admin_keyfile = NULL; 66 1.11 christos static const char *version = PACKAGE_VERSION; 67 1.1 christos static const char *servername = NULL; 68 1.1 christos static isc_sockaddr_t serveraddrs[SERVERADDRS]; 69 1.1 christos static isc_sockaddr_t local4, local6; 70 1.3 christos static bool local4set = false, local6set = false; 71 1.1 christos static int nserveraddrs; 72 1.1 christos static int currentaddr = 0; 73 1.1 christos static unsigned int remoteport = 0; 74 1.11 christos static isc_buffer_t *databuf = NULL; 75 1.11 christos static isccc_ccmsg_t rndc_ccmsg; 76 1.3 christos static uint32_t algorithm; 77 1.1 christos static isccc_region_t secret; 78 1.3 christos static bool failed = false; 79 1.3 christos static bool c_flag = false; 80 1.11 christos static isc_mem_t *rndc_mctx = NULL; 81 1.11 christos static char *command = NULL; 82 1.11 christos static char *args = NULL; 83 1.1 christos static char program[256]; 84 1.3 christos static uint32_t serial; 85 1.3 christos static bool quiet = false; 86 1.3 christos static bool showresult = false; 87 1.13 christos static int32_t timeout = RNDC_TIMEOUT; 88 1.1 christos 89 1.4 christos static void 90 1.11 christos rndc_startconnect(isc_sockaddr_t *addr); 91 1.1 christos 92 1.11 christos noreturn static void 93 1.11 christos usage(int status); 94 1.1 christos 95 1.1 christos static void 96 1.1 christos usage(int status) { 97 1.1 christos fprintf(stderr, "\ 98 1.1 christos Usage: %s [-b address] [-c config] [-s server] [-p port]\n\ 99 1.1 christos [-k key-file ] [-y key] [-r] [-V] [-4 | -6] command\n\ 100 1.1 christos \n\ 101 1.1 christos command is one of the following:\n\ 102 1.1 christos \n\ 103 1.1 christos addzone zone [class [view]] { zone-options }\n\ 104 1.1 christos Add zone to given view. Requires allow-new-zones option.\n\ 105 1.1 christos delzone [-clean] zone [class [view]]\n\ 106 1.1 christos Removes zone from given view.\n\ 107 1.6 christos dnssec -checkds [-key id [-alg algorithm]] [-when time] (published|withdrawn) zone [class [view]]\n\ 108 1.6 christos Mark the DS record for the KSK of the given zone as seen\n\ 109 1.6 christos in the parent. If the zone has multiple KSKs, select a\n\ 110 1.6 christos specific key by providing the keytag with -key id and\n\ 111 1.6 christos optionally the key's algorithm with -alg algorithm.\n\ 112 1.6 christos Requires the zone to have a dnssec-policy.\n\ 113 1.6 christos dnssec -rollover -key id [-alg algorithm] [-when time] zone [class [view]]\n\ 114 1.6 christos Rollover key with id of the given zone. Requires the zone\n\ 115 1.6 christos to have a dnssec-policy.\n\ 116 1.5 christos dnssec -status zone [class [view]]\n\ 117 1.5 christos Show the DNSSEC signing state for the specified zone.\n\ 118 1.5 christos Requires the zone to have a dnssec-policy.\n\ 119 1.15 christos dnssec -step zone [class [view]]\n\ 120 1.15 christos Run the key manager for a zone configured with a\n\ 121 1.15 christos dnssec-policy in manual mode, executing the operations that\n\ 122 1.15 christos had previously been blocked (if any).\n\ 123 1.1 christos dnstap -reopen\n\ 124 1.1 christos Close, truncate and re-open the DNSTAP output file.\n\ 125 1.10 christos dnstap -roll [count]\n\ 126 1.1 christos Close, rename and re-open the DNSTAP output file(s).\n\ 127 1.6 christos dumpdb [-all|-cache|-zones|-adb|-bad|-expired|-fail] [view ...]\n\ 128 1.1 christos Dump cache(s) to the dump file (named_dump.db).\n\ 129 1.14 christos fetchlimit [view]\n\ 130 1.14 christos Show servers and domains currently rate-limited to fetch limits.\n\ 131 1.11 christos flush Flushes all of the server's caches.\n\ 132 1.1 christos flush [view] Flushes the server's cache for a view.\n\ 133 1.1 christos flushname name [view]\n\ 134 1.1 christos Flush the given name from the server's cache(s)\n\ 135 1.1 christos flushtree name [view]\n\ 136 1.1 christos Flush all names under the given name from the server's cache(s)\n\ 137 1.1 christos freeze Suspend updates to all dynamic zones.\n\ 138 1.1 christos freeze zone [class [view]]\n\ 139 1.1 christos Suspend updates to a dynamic zone.\n\ 140 1.1 christos halt Stop the server without saving pending updates.\n\ 141 1.1 christos halt -p Stop the server without saving pending updates reporting\n\ 142 1.1 christos process id.\n\ 143 1.13 christos skr -import file zone [class [view]]\n\ 144 1.13 christos Import a SKR file for the specified zone, for offline KSK\n\ 145 1.13 christos signing.\n\ 146 1.1 christos loadkeys zone [class [view]]\n\ 147 1.1 christos Update keys without signing immediately.\n\ 148 1.1 christos managed-keys refresh [class [view]]\n\ 149 1.1 christos Check trust anchor for RFC 5011 key changes\n\ 150 1.1 christos managed-keys status [class [view]]\n\ 151 1.1 christos Display RFC 5011 managed keys information\n\ 152 1.1 christos managed-keys sync [class [view]]\n\ 153 1.1 christos Write RFC 5011 managed keys to disk\n\ 154 1.14 christos memprof [ on | off | dump ]\n\ 155 1.14 christos Enable / disable memory profiling or dump the profile.\n\ 156 1.14 christos Requires named to built with jemalloc and run with the relevant\n\ 157 1.14 christos MALLOC_CONF environment variables.\n\ 158 1.1 christos modzone zone [class [view]] { zone-options }\n\ 159 1.1 christos Modify a zone's configuration.\n\ 160 1.1 christos Requires allow-new-zones option.\n\ 161 1.1 christos notify zone [class [view]]\n\ 162 1.1 christos Resend NOTIFY messages for the zone.\n\ 163 1.1 christos notrace Set debugging level to 0.\n\ 164 1.1 christos nta -dump\n\ 165 1.1 christos List all negative trust anchors.\n\ 166 1.1 christos nta [-lifetime duration] [-force] domain [view]\n\ 167 1.1 christos Set a negative trust anchor, disabling DNSSEC validation\n\ 168 1.1 christos for the given domain.\n\ 169 1.1 christos Using -lifetime specifies the duration of the NTA, up\n\ 170 1.1 christos to one week.\n\ 171 1.1 christos Using -force prevents the NTA from expiring before its\n\ 172 1.1 christos full lifetime, even if the domain can validate sooner.\n\ 173 1.1 christos nta -remove domain [view]\n\ 174 1.1 christos Remove a negative trust anchor, re-enabling validation\n\ 175 1.1 christos for the given domain.\n\ 176 1.1 christos querylog [ on | off ]\n\ 177 1.1 christos Enable / disable query logging.\n\ 178 1.1 christos reconfig Reload configuration file and new zones only.\n\ 179 1.1 christos recursing Dump the queries that are currently recursing (named.recursing)\n\ 180 1.1 christos refresh zone [class [view]]\n\ 181 1.1 christos Schedule immediate maintenance for a zone.\n\ 182 1.1 christos reload Reload configuration file and zones.\n\ 183 1.1 christos reload zone [class [view]]\n\ 184 1.1 christos Reload a single zone.\n\ 185 1.14 christos reset-stats <counter-name ...>\n\ 186 1.14 christos Reset the requested statistics counter(s).\n\ 187 1.14 christos responselog [ on | off ]\n\ 188 1.14 christos Enable / disable response logging.\n\ 189 1.1 christos retransfer zone [class [view]]\n\ 190 1.1 christos Retransfer a single zone without checking serial number.\n\ 191 1.1 christos scan Scan available network interfaces for changes.\n\ 192 1.1 christos secroots [view ...]\n\ 193 1.1 christos Write security roots to the secroots file.\n\ 194 1.4 christos serve-stale [ on | off | reset | status ] [class [view]]\n\ 195 1.1 christos Control whether stale answers are returned\n\ 196 1.1 christos showzone zone [class [view]]\n\ 197 1.1 christos Print a zone's configuration.\n\ 198 1.1 christos sign zone [class [view]]\n\ 199 1.1 christos Update zone keys, and sign as needed.\n\ 200 1.1 christos signing -clear all zone [class [view]]\n\ 201 1.1 christos Remove the private records for all keys that have\n\ 202 1.1 christos finished signing the given zone.\n\ 203 1.1 christos signing -clear <keyid>/<algorithm> zone [class [view]]\n\ 204 1.1 christos Remove the private record that indicating the given key\n\ 205 1.1 christos has finished signing the given zone.\n\ 206 1.1 christos signing -list zone [class [view]]\n\ 207 1.1 christos List the private records showing the state of DNSSEC\n\ 208 1.1 christos signing in the given zone.\n\ 209 1.1 christos signing -nsec3param hash flags iterations salt zone [class [view]]\n\ 210 1.1 christos Add NSEC3 chain to zone if already signed.\n\ 211 1.1 christos Prime zone with NSEC3 chain if not yet signed.\n\ 212 1.1 christos signing -nsec3param none zone [class [view]]\n\ 213 1.1 christos Remove NSEC3 chains from zone.\n\ 214 1.1 christos signing -serial <value> zone [class [view]]\n\ 215 1.1 christos Set the zones's serial to <value>.\n\ 216 1.1 christos stats Write server statistics to the statistics file.\n\ 217 1.1 christos status Display status of the server.\n\ 218 1.1 christos stop Save pending updates to master files and stop the server.\n\ 219 1.1 christos stop -p Save pending updates to master files and stop the server\n\ 220 1.1 christos reporting process id.\n\ 221 1.1 christos sync [-clean] Dump changes to all dynamic zones to disk, and optionally\n\ 222 1.1 christos remove their journal files.\n\ 223 1.1 christos sync [-clean] zone [class [view]]\n\ 224 1.1 christos Dump a single zone's changes to disk, and optionally\n\ 225 1.1 christos remove its journal file.\n\ 226 1.1 christos tcp-timeouts Display the tcp-*-timeout option values\n\ 227 1.1 christos tcp-timeouts initial idle keepalive advertised\n\ 228 1.1 christos Update the tcp-*-timeout option values\n\ 229 1.1 christos thaw Enable updates to all dynamic zones and reload them.\n\ 230 1.1 christos thaw zone [class [view]]\n\ 231 1.1 christos Enable updates to a frozen dynamic zone and reload it.\n\ 232 1.1 christos trace Increment debugging level by one.\n\ 233 1.1 christos trace level Change the debugging level.\n\ 234 1.4 christos validation [ on | off | status ] [view]\n\ 235 1.1 christos Enable / disable DNSSEC validation.\n\ 236 1.1 christos zonestatus zone [class [view]]\n\ 237 1.1 christos Display the current status of a zone.\n\ 238 1.1 christos \n\ 239 1.1 christos Version: %s\n", 240 1.1 christos progname, version); 241 1.1 christos 242 1.1 christos exit(status); 243 1.1 christos } 244 1.1 christos 245 1.13 christos #define CMDLINE_FLAGS "46b:c:hk:Mmp:qrs:t:Vy:" 246 1.1 christos 247 1.1 christos static void 248 1.1 christos preparse_args(int argc, char **argv) { 249 1.3 christos bool ipv4only = false, ipv6only = false; 250 1.1 christos int ch; 251 1.1 christos 252 1.1 christos while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) { 253 1.1 christos switch (ch) { 254 1.1 christos case '4': 255 1.1 christos if (ipv6only) { 256 1.1 christos fatal("only one of -4 and -6 allowed"); 257 1.1 christos } 258 1.3 christos ipv4only = true; 259 1.1 christos break; 260 1.1 christos case '6': 261 1.1 christos if (ipv4only) { 262 1.1 christos fatal("only one of -4 and -6 allowed"); 263 1.1 christos } 264 1.3 christos ipv6only = true; 265 1.1 christos break; 266 1.1 christos default: 267 1.1 christos break; 268 1.1 christos } 269 1.1 christos } 270 1.1 christos 271 1.3 christos isc_commandline_reset = true; 272 1.1 christos isc_commandline_index = 1; 273 1.1 christos } 274 1.1 christos 275 1.1 christos static void 276 1.1 christos get_addresses(const char *host, in_port_t port) { 277 1.1 christos isc_result_t result; 278 1.1 christos int found = 0, count; 279 1.1 christos 280 1.4 christos REQUIRE(host != NULL); 281 1.4 christos 282 1.13 christos count = SERVERADDRS - nserveraddrs; 283 1.13 christos result = isc_getaddresses(host, port, &serveraddrs[nserveraddrs], count, 284 1.13 christos &found); 285 1.13 christos nserveraddrs += found; 286 1.13 christos 287 1.4 christos if (result != ISC_R_SUCCESS) { 288 1.4 christos fatal("couldn't get address for '%s': %s", host, 289 1.4 christos isc_result_totext(result)); 290 1.4 christos } 291 1.1 christos INSIST(nserveraddrs > 0); 292 1.1 christos } 293 1.1 christos 294 1.1 christos static void 295 1.13 christos rndc_senddone(isc_nmhandle_t *handle ISC_ATTR_UNUSED, isc_result_t result, 296 1.13 christos void *arg ISC_ATTR_UNUSED) { 297 1.11 christos if (result != ISC_R_SUCCESS) { 298 1.11 christos fatal("send failed: %s", isc_result_totext(result)); 299 1.4 christos } 300 1.1 christos } 301 1.1 christos 302 1.1 christos static void 303 1.11 christos rndc_recvdone(isc_nmhandle_t *handle, isc_result_t result, void *arg) { 304 1.11 christos isccc_ccmsg_t *ccmsg = (isccc_ccmsg_t *)arg; 305 1.1 christos isccc_sexpr_t *response = NULL; 306 1.11 christos isccc_sexpr_t *data = NULL; 307 1.1 christos isccc_region_t source; 308 1.1 christos char *errormsg = NULL; 309 1.1 christos char *textmsg = NULL; 310 1.1 christos 311 1.13 christos REQUIRE(handle != NULL); 312 1.11 christos REQUIRE(ccmsg != NULL); 313 1.1 christos 314 1.13 christos if (result == ISC_R_EOF) { 315 1.11 christos fatal("connection to remote host closed.\n" 316 1.11 christos "* This may indicate that the\n" 317 1.11 christos "* remote server is using an older\n" 318 1.11 christos "* version of the command protocol,\n" 319 1.1 christos "* this host is not authorized to connect,\n" 320 1.11 christos "* the clocks are not synchronized,\n" 321 1.11 christos "* the key signing algorithm is incorrect,\n" 322 1.11 christos "* or the key is invalid."); 323 1.11 christos } else if (result != ISC_R_SUCCESS) { 324 1.11 christos fatal("recv failed: %s", isc_result_totext(result)); 325 1.4 christos } 326 1.1 christos 327 1.13 christos isccc_ccmsg_toregion(ccmsg, &source); 328 1.1 christos 329 1.1 christos DO("parse message", 330 1.1 christos isccc_cc_fromwire(&source, &response, algorithm, &secret)); 331 1.1 christos 332 1.1 christos data = isccc_alist_lookup(response, "_data"); 333 1.4 christos if (!isccc_alist_alistp(data)) { 334 1.1 christos fatal("bad or missing data section in response"); 335 1.4 christos } 336 1.1 christos result = isccc_cc_lookupstring(data, "err", &errormsg); 337 1.1 christos if (result == ISC_R_SUCCESS) { 338 1.3 christos failed = true; 339 1.4 christos fprintf(stderr, "%s: '%s' failed: %s\n", progname, command, 340 1.4 christos errormsg); 341 1.4 christos } else if (result != ISC_R_NOTFOUND) { 342 1.4 christos fprintf(stderr, "%s: parsing response failed: %s\n", progname, 343 1.4 christos isc_result_totext(result)); 344 1.1 christos } 345 1.1 christos 346 1.1 christos result = isccc_cc_lookupstring(data, "text", &textmsg); 347 1.1 christos if (result == ISC_R_SUCCESS) { 348 1.4 christos if ((!quiet || failed) && strlen(textmsg) != 0U) { 349 1.1 christos fprintf(failed ? stderr : stdout, "%s\n", textmsg); 350 1.4 christos } 351 1.4 christos } else if (result != ISC_R_NOTFOUND) { 352 1.4 christos fprintf(stderr, "%s: parsing response failed: %s\n", progname, 353 1.4 christos isc_result_totext(result)); 354 1.4 christos } 355 1.1 christos 356 1.1 christos if (showresult) { 357 1.1 christos isc_result_t eresult; 358 1.1 christos 359 1.1 christos result = isccc_cc_lookupuint32(data, "result", &eresult); 360 1.4 christos if (result == ISC_R_SUCCESS) { 361 1.1 christos printf("%s %u\n", isc_result_toid(eresult), eresult); 362 1.4 christos } else { 363 1.1 christos printf("NONE -1\n"); 364 1.4 christos } 365 1.1 christos } 366 1.1 christos 367 1.1 christos isccc_sexpr_free(&response); 368 1.11 christos 369 1.13 christos isccc_ccmsg_disconnect(ccmsg); 370 1.13 christos isc_loopmgr_shutdown(loopmgr); 371 1.1 christos } 372 1.1 christos 373 1.1 christos static void 374 1.13 christos rndc_recvnonce(isc_nmhandle_t *handle ISC_ATTR_UNUSED, isc_result_t result, 375 1.13 christos void *arg) { 376 1.11 christos isccc_ccmsg_t *ccmsg = (isccc_ccmsg_t *)arg; 377 1.1 christos isccc_sexpr_t *response = NULL; 378 1.11 christos isccc_sexpr_t *_ctrl = NULL; 379 1.1 christos isccc_region_t source; 380 1.3 christos uint32_t nonce; 381 1.1 christos isccc_sexpr_t *request = NULL; 382 1.13 christos isccc_time_t now = isc_stdtime_now(); 383 1.1 christos isc_region_t r; 384 1.11 christos isccc_sexpr_t *data = NULL; 385 1.1 christos isc_buffer_t b; 386 1.1 christos 387 1.11 christos REQUIRE(ccmsg != NULL); 388 1.1 christos 389 1.13 christos if (result == ISC_R_EOF) { 390 1.11 christos fatal("connection to remote host closed.\n" 391 1.11 christos "* This may indicate that the\n" 392 1.11 christos "* remote server is using an older\n" 393 1.11 christos "* version of the command protocol,\n" 394 1.1 christos "* this host is not authorized to connect,\n" 395 1.1 christos "* the clocks are not synchronized,\n" 396 1.11 christos "* the key signing algorithm is incorrect\n" 397 1.11 christos "* or the key is invalid."); 398 1.11 christos } else if (result != ISC_R_SUCCESS) { 399 1.11 christos fatal("recv failed: %s", isc_result_totext(result)); 400 1.4 christos } 401 1.1 christos 402 1.13 christos isccc_ccmsg_toregion(ccmsg, &source); 403 1.1 christos 404 1.1 christos DO("parse message", 405 1.1 christos isccc_cc_fromwire(&source, &response, algorithm, &secret)); 406 1.1 christos 407 1.1 christos _ctrl = isccc_alist_lookup(response, "_ctrl"); 408 1.4 christos if (!isccc_alist_alistp(_ctrl)) { 409 1.1 christos fatal("bad or missing ctrl section in response"); 410 1.4 christos } 411 1.1 christos nonce = 0; 412 1.4 christos if (isccc_cc_lookupuint32(_ctrl, "_nonce", &nonce) != ISC_R_SUCCESS) { 413 1.1 christos nonce = 0; 414 1.4 christos } 415 1.1 christos 416 1.1 christos DO("create message", isccc_cc_createmessage(1, NULL, NULL, ++serial, 417 1.1 christos now, now + 60, &request)); 418 1.1 christos data = isccc_alist_lookup(request, "_data"); 419 1.4 christos if (data == NULL) { 420 1.1 christos fatal("_data section missing"); 421 1.4 christos } 422 1.4 christos if (isccc_cc_definestring(data, "type", args) == NULL) { 423 1.1 christos fatal("out of memory"); 424 1.4 christos } 425 1.1 christos if (nonce != 0) { 426 1.1 christos _ctrl = isccc_alist_lookup(request, "_ctrl"); 427 1.4 christos if (_ctrl == NULL) { 428 1.1 christos fatal("_ctrl section missing"); 429 1.4 christos } 430 1.4 christos if (isccc_cc_defineuint32(_ctrl, "_nonce", nonce) == NULL) { 431 1.1 christos fatal("out of memory"); 432 1.4 christos } 433 1.1 christos } 434 1.1 christos 435 1.1 christos isc_buffer_clear(databuf); 436 1.1 christos /* Skip the length field (4 bytes) */ 437 1.1 christos isc_buffer_add(databuf, 4); 438 1.1 christos 439 1.1 christos DO("render message", 440 1.1 christos isccc_cc_towire(request, &databuf, algorithm, &secret)); 441 1.1 christos 442 1.1 christos isc_buffer_init(&b, databuf->base, 4); 443 1.1 christos isc_buffer_putuint32(&b, databuf->used - 4); 444 1.1 christos 445 1.1 christos r.base = databuf->base; 446 1.1 christos r.length = databuf->used; 447 1.1 christos 448 1.11 christos isccc_ccmsg_readmessage(ccmsg, rndc_recvdone, ccmsg); 449 1.13 christos isccc_ccmsg_sendmessage(ccmsg, &r, rndc_senddone, NULL); 450 1.1 christos 451 1.1 christos isccc_sexpr_free(&response); 452 1.1 christos isccc_sexpr_free(&request); 453 1.1 christos return; 454 1.1 christos } 455 1.1 christos 456 1.1 christos static void 457 1.11 christos rndc_connected(isc_nmhandle_t *handle, isc_result_t result, void *arg) { 458 1.11 christos isccc_ccmsg_t *ccmsg = (isccc_ccmsg_t *)arg; 459 1.1 christos char socktext[ISC_SOCKADDR_FORMATSIZE]; 460 1.1 christos isccc_sexpr_t *request = NULL; 461 1.11 christos isccc_sexpr_t *data = NULL; 462 1.13 christos isccc_time_t now = isc_stdtime_now(); 463 1.1 christos isc_region_t r; 464 1.1 christos isc_buffer_t b; 465 1.1 christos 466 1.11 christos REQUIRE(ccmsg != NULL); 467 1.1 christos 468 1.11 christos if (result != ISC_R_SUCCESS) { 469 1.1 christos isc_sockaddr_format(&serveraddrs[currentaddr], socktext, 470 1.1 christos sizeof(socktext)); 471 1.11 christos if (++currentaddr < nserveraddrs) { 472 1.1 christos notify("connection failed: %s: %s", socktext, 473 1.11 christos isc_result_totext(result)); 474 1.11 christos rndc_startconnect(&serveraddrs[currentaddr]); 475 1.1 christos return; 476 1.4 christos } 477 1.11 christos 478 1.11 christos fatal("connect failed: %s: %s", socktext, 479 1.11 christos isc_result_totext(result)); 480 1.1 christos } 481 1.1 christos 482 1.1 christos DO("create message", isccc_cc_createmessage(1, NULL, NULL, ++serial, 483 1.1 christos now, now + 60, &request)); 484 1.1 christos data = isccc_alist_lookup(request, "_data"); 485 1.4 christos if (data == NULL) { 486 1.1 christos fatal("_data section missing"); 487 1.4 christos } 488 1.4 christos if (isccc_cc_definestring(data, "type", "null") == NULL) { 489 1.1 christos fatal("out of memory"); 490 1.4 christos } 491 1.1 christos 492 1.1 christos isc_buffer_clear(databuf); 493 1.1 christos /* Skip the length field (4 bytes) */ 494 1.1 christos isc_buffer_add(databuf, 4); 495 1.1 christos 496 1.1 christos DO("render message", 497 1.1 christos isccc_cc_towire(request, &databuf, algorithm, &secret)); 498 1.1 christos 499 1.1 christos isc_buffer_init(&b, databuf->base, 4); 500 1.1 christos isc_buffer_putuint32(&b, databuf->used - 4); 501 1.1 christos 502 1.1 christos r.base = databuf->base; 503 1.1 christos r.length = databuf->used; 504 1.1 christos 505 1.13 christos /* isccc_ccmsg_init() attaches to the handle */ 506 1.11 christos isccc_ccmsg_init(rndc_mctx, handle, ccmsg); 507 1.11 christos isccc_ccmsg_setmaxsize(ccmsg, 1024 * 1024); 508 1.1 christos 509 1.11 christos isccc_ccmsg_readmessage(ccmsg, rndc_recvnonce, ccmsg); 510 1.13 christos isccc_ccmsg_sendmessage(ccmsg, &r, rndc_senddone, NULL); 511 1.11 christos 512 1.1 christos isccc_sexpr_free(&request); 513 1.1 christos } 514 1.1 christos 515 1.1 christos static void 516 1.11 christos rndc_startconnect(isc_sockaddr_t *addr) { 517 1.1 christos char socktext[ISC_SOCKADDR_FORMATSIZE]; 518 1.11 christos isc_sockaddr_t *local = NULL; 519 1.1 christos 520 1.1 christos isc_sockaddr_format(addr, socktext, sizeof(socktext)); 521 1.1 christos 522 1.1 christos notify("using server %s (%s)", servername, socktext); 523 1.1 christos 524 1.1 christos switch (isc_sockaddr_pf(addr)) { 525 1.1 christos case AF_INET: 526 1.11 christos local = &local4; 527 1.1 christos break; 528 1.1 christos case AF_INET6: 529 1.11 christos local = &local6; 530 1.1 christos break; 531 1.1 christos default: 532 1.11 christos UNREACHABLE(); 533 1.1 christos } 534 1.11 christos 535 1.11 christos isc_nm_tcpconnect(netmgr, local, addr, rndc_connected, &rndc_ccmsg, 536 1.13 christos timeout); 537 1.1 christos } 538 1.1 christos 539 1.1 christos static void 540 1.13 christos rndc_start(void *arg) { 541 1.13 christos UNUSED(arg); 542 1.11 christos 543 1.1 christos currentaddr = 0; 544 1.11 christos rndc_startconnect(&serveraddrs[currentaddr]); 545 1.1 christos } 546 1.1 christos 547 1.1 christos static void 548 1.1 christos parse_config(isc_mem_t *mctx, isc_log_t *log, const char *keyname, 549 1.4 christos cfg_parser_t **pctxp, cfg_obj_t **configp) { 550 1.1 christos isc_result_t result; 551 1.1 christos const char *conffile = admin_conffile; 552 1.1 christos const cfg_obj_t *addresses = NULL; 553 1.1 christos const cfg_obj_t *defkey = NULL; 554 1.1 christos const cfg_obj_t *options = NULL; 555 1.1 christos const cfg_obj_t *servers = NULL; 556 1.1 christos const cfg_obj_t *server = NULL; 557 1.1 christos const cfg_obj_t *keys = NULL; 558 1.1 christos const cfg_obj_t *key = NULL; 559 1.1 christos const cfg_obj_t *defport = NULL; 560 1.1 christos const cfg_obj_t *secretobj = NULL; 561 1.1 christos const cfg_obj_t *algorithmobj = NULL; 562 1.1 christos cfg_obj_t *config = NULL; 563 1.1 christos const cfg_obj_t *address = NULL; 564 1.1 christos const cfg_listelt_t *elt; 565 1.1 christos const char *secretstr; 566 1.1 christos const char *algorithmstr; 567 1.1 christos static char secretarray[1024]; 568 1.1 christos const cfg_type_t *conftype = &cfg_type_rndcconf; 569 1.3 christos bool key_only = false; 570 1.1 christos const cfg_listelt_t *element; 571 1.1 christos 572 1.4 christos if (!isc_file_exists(conffile)) { 573 1.1 christos conffile = admin_keyfile; 574 1.1 christos conftype = &cfg_type_rndckey; 575 1.1 christos 576 1.4 christos if (c_flag) { 577 1.1 christos fatal("%s does not exist", admin_conffile); 578 1.4 christos } 579 1.1 christos 580 1.4 christos if (!isc_file_exists(conffile)) { 581 1.4 christos fatal("neither %s nor %s was found", admin_conffile, 582 1.4 christos admin_keyfile); 583 1.4 christos } 584 1.3 christos key_only = true; 585 1.4 christos } else if (!c_flag && isc_file_exists(admin_keyfile)) { 586 1.4 christos fprintf(stderr, 587 1.4 christos "WARNING: key file (%s) exists, but using " 588 1.1 christos "default configuration file (%s)\n", 589 1.1 christos admin_keyfile, admin_conffile); 590 1.1 christos } 591 1.1 christos 592 1.1 christos DO("create parser", cfg_parser_create(mctx, log, pctxp)); 593 1.1 christos 594 1.1 christos /* 595 1.1 christos * The parser will output its own errors, so DO() is not used. 596 1.1 christos */ 597 1.1 christos result = cfg_parse_file(*pctxp, conffile, conftype, &config); 598 1.4 christos if (result != ISC_R_SUCCESS) { 599 1.1 christos fatal("could not load rndc configuration"); 600 1.4 christos } 601 1.1 christos 602 1.4 christos if (!key_only) { 603 1.1 christos (void)cfg_map_get(config, "options", &options); 604 1.4 christos } 605 1.1 christos 606 1.4 christos if (key_only && servername == NULL) { 607 1.1 christos servername = "127.0.0.1"; 608 1.4 christos } else if (servername == NULL && options != NULL) { 609 1.1 christos const cfg_obj_t *defserverobj = NULL; 610 1.1 christos (void)cfg_map_get(options, "default-server", &defserverobj); 611 1.4 christos if (defserverobj != NULL) { 612 1.1 christos servername = cfg_obj_asstring(defserverobj); 613 1.4 christos } 614 1.1 christos } 615 1.1 christos 616 1.4 christos if (servername == NULL) { 617 1.1 christos fatal("no server specified and no default"); 618 1.4 christos } 619 1.1 christos 620 1.1 christos if (!key_only) { 621 1.1 christos (void)cfg_map_get(config, "server", &servers); 622 1.1 christos if (servers != NULL) { 623 1.4 christos for (elt = cfg_list_first(servers); elt != NULL; 624 1.9 christos elt = cfg_list_next(elt)) 625 1.9 christos { 626 1.11 christos const char *name = NULL; 627 1.1 christos server = cfg_listelt_value(elt); 628 1.4 christos name = cfg_obj_asstring( 629 1.4 christos cfg_map_getname(server)); 630 1.4 christos if (strcasecmp(name, servername) == 0) { 631 1.1 christos break; 632 1.4 christos } 633 1.1 christos server = NULL; 634 1.1 christos } 635 1.1 christos } 636 1.1 christos } 637 1.1 christos 638 1.1 christos /* 639 1.1 christos * Look for the name of the key to use. 640 1.1 christos */ 641 1.4 christos if (keyname != NULL) { 642 1.4 christos /* Was set on command line, do nothing. */ 643 1.4 christos } else if (server != NULL) { 644 1.1 christos DO("get key for server", cfg_map_get(server, "key", &defkey)); 645 1.1 christos keyname = cfg_obj_asstring(defkey); 646 1.1 christos } else if (options != NULL) { 647 1.4 christos DO("get default key", 648 1.4 christos cfg_map_get(options, "default-key", &defkey)); 649 1.1 christos keyname = cfg_obj_asstring(defkey); 650 1.4 christos } else if (!key_only) { 651 1.1 christos fatal("no key for server and no default"); 652 1.4 christos } 653 1.1 christos 654 1.1 christos /* 655 1.1 christos * Get the key's definition. 656 1.1 christos */ 657 1.4 christos if (key_only) { 658 1.1 christos DO("get key", cfg_map_get(config, "key", &key)); 659 1.4 christos } else { 660 1.1 christos DO("get config key list", cfg_map_get(config, "key", &keys)); 661 1.4 christos for (elt = cfg_list_first(keys); elt != NULL; 662 1.9 christos elt = cfg_list_next(elt)) 663 1.9 christos { 664 1.11 christos const char *name = NULL; 665 1.11 christos 666 1.1 christos key = cfg_listelt_value(elt); 667 1.11 christos name = cfg_obj_asstring(cfg_map_getname(key)); 668 1.11 christos if (strcasecmp(name, keyname) == 0) { 669 1.1 christos break; 670 1.4 christos } 671 1.1 christos } 672 1.4 christos if (elt == NULL) { 673 1.1 christos fatal("no key definition for name %s", keyname); 674 1.4 christos } 675 1.1 christos } 676 1.1 christos (void)cfg_map_get(key, "secret", &secretobj); 677 1.1 christos (void)cfg_map_get(key, "algorithm", &algorithmobj); 678 1.4 christos if (secretobj == NULL || algorithmobj == NULL) { 679 1.1 christos fatal("key must have algorithm and secret"); 680 1.4 christos } 681 1.1 christos 682 1.1 christos secretstr = cfg_obj_asstring(secretobj); 683 1.1 christos algorithmstr = cfg_obj_asstring(algorithmobj); 684 1.1 christos 685 1.3 christos if (strcasecmp(algorithmstr, "hmac-md5") == 0) { 686 1.1 christos algorithm = ISCCC_ALG_HMACMD5; 687 1.3 christos } else if (strcasecmp(algorithmstr, "hmac-sha1") == 0) { 688 1.1 christos algorithm = ISCCC_ALG_HMACSHA1; 689 1.3 christos } else if (strcasecmp(algorithmstr, "hmac-sha224") == 0) { 690 1.1 christos algorithm = ISCCC_ALG_HMACSHA224; 691 1.3 christos } else if (strcasecmp(algorithmstr, "hmac-sha256") == 0) { 692 1.1 christos algorithm = ISCCC_ALG_HMACSHA256; 693 1.3 christos } else if (strcasecmp(algorithmstr, "hmac-sha384") == 0) { 694 1.1 christos algorithm = ISCCC_ALG_HMACSHA384; 695 1.3 christos } else if (strcasecmp(algorithmstr, "hmac-sha512") == 0) { 696 1.1 christos algorithm = ISCCC_ALG_HMACSHA512; 697 1.3 christos } else { 698 1.1 christos fatal("unsupported algorithm: %s", algorithmstr); 699 1.3 christos } 700 1.1 christos 701 1.1 christos secret.rstart = (unsigned char *)secretarray; 702 1.1 christos secret.rend = (unsigned char *)secretarray + sizeof(secretarray); 703 1.1 christos DO("decode base64 secret", isccc_base64_decode(secretstr, &secret)); 704 1.1 christos secret.rend = secret.rstart; 705 1.1 christos secret.rstart = (unsigned char *)secretarray; 706 1.1 christos 707 1.1 christos /* 708 1.1 christos * Find the port to connect to. 709 1.1 christos */ 710 1.4 christos if (remoteport != 0) { 711 1.4 christos /* Was set on command line, do nothing. */ 712 1.4 christos } else { 713 1.4 christos if (server != NULL) { 714 1.1 christos (void)cfg_map_get(server, "port", &defport); 715 1.4 christos } 716 1.4 christos if (defport == NULL && options != NULL) { 717 1.1 christos (void)cfg_map_get(options, "default-port", &defport); 718 1.4 christos } 719 1.1 christos } 720 1.1 christos if (defport != NULL) { 721 1.1 christos remoteport = cfg_obj_asuint32(defport); 722 1.4 christos if (remoteport > 65535 || remoteport == 0) { 723 1.1 christos fatal("port %u out of range", remoteport); 724 1.4 christos } 725 1.4 christos } else if (remoteport == 0) { 726 1.1 christos remoteport = NS_CONTROL_PORT; 727 1.4 christos } 728 1.1 christos 729 1.4 christos if (server != NULL) { 730 1.1 christos result = cfg_map_get(server, "addresses", &addresses); 731 1.4 christos } else { 732 1.1 christos result = ISC_R_NOTFOUND; 733 1.4 christos } 734 1.1 christos if (result == ISC_R_SUCCESS) { 735 1.4 christos for (element = cfg_list_first(addresses); element != NULL; 736 1.1 christos element = cfg_list_next(element)) 737 1.1 christos { 738 1.1 christos isc_sockaddr_t sa; 739 1.1 christos 740 1.1 christos address = cfg_listelt_value(element); 741 1.1 christos if (!cfg_obj_issockaddr(address)) { 742 1.1 christos unsigned int myport; 743 1.1 christos const char *name; 744 1.1 christos const cfg_obj_t *obj; 745 1.1 christos 746 1.1 christos obj = cfg_tuple_get(address, "name"); 747 1.1 christos name = cfg_obj_asstring(obj); 748 1.1 christos obj = cfg_tuple_get(address, "port"); 749 1.1 christos if (cfg_obj_isuint32(obj)) { 750 1.1 christos myport = cfg_obj_asuint32(obj); 751 1.4 christos if (myport > UINT16_MAX || myport == 0) 752 1.4 christos { 753 1.1 christos fatal("port %u out of range", 754 1.1 christos myport); 755 1.4 christos } 756 1.4 christos } else { 757 1.1 christos myport = remoteport; 758 1.4 christos } 759 1.4 christos if (nserveraddrs < SERVERADDRS) { 760 1.4 christos get_addresses(name, (in_port_t)myport); 761 1.4 christos } else { 762 1.4 christos fprintf(stderr, 763 1.4 christos "too many address: " 764 1.4 christos "%s: dropped\n", 765 1.4 christos name); 766 1.4 christos } 767 1.1 christos continue; 768 1.1 christos } 769 1.1 christos sa = *cfg_obj_assockaddr(address); 770 1.4 christos if (isc_sockaddr_getport(&sa) == 0) { 771 1.1 christos isc_sockaddr_setport(&sa, remoteport); 772 1.4 christos } 773 1.4 christos if (nserveraddrs < SERVERADDRS) { 774 1.1 christos serveraddrs[nserveraddrs++] = sa; 775 1.4 christos } else { 776 1.1 christos char socktext[ISC_SOCKADDR_FORMATSIZE]; 777 1.1 christos 778 1.1 christos isc_sockaddr_format(&sa, socktext, 779 1.1 christos sizeof(socktext)); 780 1.1 christos fprintf(stderr, 781 1.1 christos "too many address: %s: dropped\n", 782 1.1 christos socktext); 783 1.1 christos } 784 1.1 christos } 785 1.1 christos } 786 1.1 christos 787 1.1 christos if (!local4set && server != NULL) { 788 1.1 christos address = NULL; 789 1.1 christos cfg_map_get(server, "source-address", &address); 790 1.1 christos if (address != NULL) { 791 1.1 christos local4 = *cfg_obj_assockaddr(address); 792 1.3 christos local4set = true; 793 1.1 christos } 794 1.1 christos } 795 1.1 christos if (!local4set && options != NULL) { 796 1.1 christos address = NULL; 797 1.1 christos cfg_map_get(options, "default-source-address", &address); 798 1.1 christos if (address != NULL) { 799 1.1 christos local4 = *cfg_obj_assockaddr(address); 800 1.3 christos local4set = true; 801 1.1 christos } 802 1.1 christos } 803 1.1 christos 804 1.1 christos if (!local6set && server != NULL) { 805 1.1 christos address = NULL; 806 1.1 christos cfg_map_get(server, "source-address-v6", &address); 807 1.1 christos if (address != NULL) { 808 1.1 christos local6 = *cfg_obj_assockaddr(address); 809 1.3 christos local6set = true; 810 1.1 christos } 811 1.1 christos } 812 1.1 christos if (!local6set && options != NULL) { 813 1.1 christos address = NULL; 814 1.1 christos cfg_map_get(options, "default-source-address-v6", &address); 815 1.1 christos if (address != NULL) { 816 1.1 christos local6 = *cfg_obj_assockaddr(address); 817 1.3 christos local6set = true; 818 1.1 christos } 819 1.1 christos } 820 1.1 christos 821 1.1 christos *configp = config; 822 1.1 christos } 823 1.1 christos 824 1.1 christos int 825 1.1 christos main(int argc, char **argv) { 826 1.1 christos isc_result_t result = ISC_R_SUCCESS; 827 1.3 christos bool show_final_mem = false; 828 1.1 christos isc_log_t *log = NULL; 829 1.1 christos isc_logconfig_t *logconfig = NULL; 830 1.1 christos isc_logdestination_t logdest; 831 1.1 christos cfg_parser_t *pctx = NULL; 832 1.1 christos cfg_obj_t *config = NULL; 833 1.1 christos const char *keyname = NULL; 834 1.1 christos struct in_addr in; 835 1.1 christos struct in6_addr in6; 836 1.13 christos char *p = NULL; 837 1.1 christos size_t argslen; 838 1.1 christos int ch; 839 1.1 christos int i; 840 1.1 christos 841 1.1 christos result = isc_file_progname(*argv, program, sizeof(program)); 842 1.4 christos if (result != ISC_R_SUCCESS) { 843 1.1 christos memmove(program, "rndc", 5); 844 1.4 christos } 845 1.1 christos progname = program; 846 1.1 christos 847 1.1 christos admin_conffile = RNDC_CONFFILE; 848 1.1 christos admin_keyfile = RNDC_KEYFILE; 849 1.1 christos 850 1.1 christos isc_sockaddr_any(&local4); 851 1.1 christos isc_sockaddr_any6(&local6); 852 1.1 christos 853 1.3 christos isc_commandline_errprint = false; 854 1.1 christos 855 1.1 christos preparse_args(argc, argv); 856 1.1 christos 857 1.1 christos while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) { 858 1.1 christos switch (ch) { 859 1.1 christos case '4': 860 1.1 christos if (isc_net_probeipv4() != ISC_R_SUCCESS) { 861 1.1 christos fatal("can't find IPv4 networking"); 862 1.1 christos } 863 1.1 christos isc_net_disableipv6(); 864 1.1 christos break; 865 1.1 christos case '6': 866 1.1 christos if (isc_net_probeipv6() != ISC_R_SUCCESS) { 867 1.1 christos fatal("can't find IPv6 networking"); 868 1.1 christos } 869 1.1 christos isc_net_disableipv4(); 870 1.1 christos break; 871 1.1 christos case 'b': 872 1.4 christos if (inet_pton(AF_INET, isc_commandline_argument, &in) == 873 1.9 christos 1) 874 1.9 christos { 875 1.1 christos isc_sockaddr_fromin(&local4, &in, 0); 876 1.3 christos local4set = true; 877 1.1 christos } else if (inet_pton(AF_INET6, isc_commandline_argument, 878 1.9 christos &in6) == 1) 879 1.9 christos { 880 1.1 christos isc_sockaddr_fromin6(&local6, &in6, 0); 881 1.3 christos local6set = true; 882 1.1 christos } 883 1.1 christos break; 884 1.1 christos 885 1.1 christos case 'c': 886 1.1 christos admin_conffile = isc_commandline_argument; 887 1.3 christos c_flag = true; 888 1.1 christos break; 889 1.1 christos 890 1.1 christos case 'k': 891 1.1 christos admin_keyfile = isc_commandline_argument; 892 1.1 christos break; 893 1.1 christos 894 1.1 christos case 'M': 895 1.1 christos isc_mem_debugging = ISC_MEM_DEBUGTRACE; 896 1.1 christos break; 897 1.1 christos 898 1.1 christos case 'm': 899 1.3 christos show_final_mem = true; 900 1.1 christos break; 901 1.1 christos 902 1.1 christos case 'p': 903 1.1 christos remoteport = atoi(isc_commandline_argument); 904 1.4 christos if (remoteport > 65535 || remoteport == 0) { 905 1.1 christos fatal("port '%s' out of range", 906 1.1 christos isc_commandline_argument); 907 1.4 christos } 908 1.1 christos break; 909 1.1 christos 910 1.1 christos case 'q': 911 1.3 christos quiet = true; 912 1.1 christos break; 913 1.1 christos 914 1.1 christos case 'r': 915 1.3 christos showresult = true; 916 1.1 christos break; 917 1.1 christos 918 1.1 christos case 's': 919 1.1 christos servername = isc_commandline_argument; 920 1.1 christos break; 921 1.1 christos 922 1.13 christos case 't': 923 1.13 christos timeout = strtol(isc_commandline_argument, &p, 10); 924 1.13 christos if (*p != '\0' || timeout < 0 || timeout > 86400) { 925 1.13 christos fatal("invalid timeout '%s'", 926 1.13 christos isc_commandline_argument); 927 1.13 christos } 928 1.13 christos timeout *= 1000; 929 1.13 christos break; 930 1.13 christos 931 1.1 christos case 'V': 932 1.3 christos verbose = true; 933 1.1 christos break; 934 1.1 christos 935 1.1 christos case 'y': 936 1.1 christos keyname = isc_commandline_argument; 937 1.1 christos break; 938 1.1 christos 939 1.1 christos case '?': 940 1.1 christos if (isc_commandline_option != '?') { 941 1.1 christos fprintf(stderr, "%s: invalid argument -%c\n", 942 1.1 christos program, isc_commandline_option); 943 1.1 christos usage(1); 944 1.1 christos } 945 1.8 christos FALLTHROUGH; 946 1.1 christos case 'h': 947 1.1 christos usage(0); 948 1.1 christos break; 949 1.1 christos default: 950 1.4 christos fprintf(stderr, "%s: unhandled option -%c\n", program, 951 1.4 christos isc_commandline_option); 952 1.12 christos exit(EXIT_FAILURE); 953 1.1 christos } 954 1.1 christos } 955 1.1 christos 956 1.1 christos argc -= isc_commandline_index; 957 1.1 christos argv += isc_commandline_index; 958 1.1 christos 959 1.11 christos if (argv[0] == NULL) { 960 1.1 christos usage(1); 961 1.11 christos } else { 962 1.11 christos command = argv[0]; 963 1.11 christos if (strcmp(command, "restart") == 0) { 964 1.11 christos fatal("'%s' is not implemented", command); 965 1.11 christos } 966 1.11 christos notify("%s", command); 967 1.4 christos } 968 1.1 christos 969 1.3 christos serial = isc_random32(); 970 1.1 christos 971 1.13 christos isc_managers_create(&rndc_mctx, 1, &loopmgr, &netmgr); 972 1.13 christos isc_loopmgr_setup(loopmgr, rndc_start, NULL); 973 1.11 christos 974 1.13 christos isc_nm_settimeouts(netmgr, timeout, timeout, timeout, 0); 975 1.1 christos 976 1.4 christos isc_log_create(rndc_mctx, &log, &logconfig); 977 1.1 christos isc_log_setcontext(log); 978 1.4 christos isc_log_settag(logconfig, progname); 979 1.1 christos logdest.file.stream = stderr; 980 1.1 christos logdest.file.name = NULL; 981 1.1 christos logdest.file.versions = ISC_LOG_ROLLNEVER; 982 1.1 christos logdest.file.maximum_size = 0; 983 1.4 christos isc_log_createchannel(logconfig, "stderr", ISC_LOG_TOFILEDESC, 984 1.4 christos ISC_LOG_INFO, &logdest, 985 1.4 christos ISC_LOG_PRINTTAG | ISC_LOG_PRINTLEVEL); 986 1.4 christos DO("enabling log channel", 987 1.4 christos isc_log_usechannel(logconfig, "stderr", NULL, NULL)); 988 1.1 christos 989 1.1 christos parse_config(rndc_mctx, log, keyname, &pctx, &config); 990 1.1 christos 991 1.4 christos isc_buffer_allocate(rndc_mctx, &databuf, 2048); 992 1.1 christos 993 1.1 christos /* 994 1.1 christos * Convert argc/argv into a space-delimited command string 995 1.1 christos * similar to what the user might enter in interactive mode 996 1.1 christos * (if that were implemented). 997 1.1 christos */ 998 1.1 christos argslen = 0; 999 1.4 christos for (i = 0; i < argc; i++) { 1000 1.1 christos argslen += strlen(argv[i]) + 1; 1001 1.4 christos } 1002 1.1 christos 1003 1.1 christos args = isc_mem_get(rndc_mctx, argslen); 1004 1.1 christos 1005 1.1 christos p = args; 1006 1.1 christos for (i = 0; i < argc; i++) { 1007 1.1 christos size_t len = strlen(argv[i]); 1008 1.1 christos memmove(p, argv[i], len); 1009 1.1 christos p += len; 1010 1.1 christos *p++ = ' '; 1011 1.1 christos } 1012 1.1 christos 1013 1.1 christos p--; 1014 1.1 christos *p++ = '\0'; 1015 1.1 christos INSIST(p == args + argslen); 1016 1.1 christos 1017 1.4 christos if (nserveraddrs == 0 && servername != NULL) { 1018 1.4 christos get_addresses(servername, (in_port_t)remoteport); 1019 1.4 christos } 1020 1.1 christos 1021 1.13 christos isc_loopmgr_run(loopmgr); 1022 1.11 christos 1023 1.11 christos isccc_ccmsg_invalidate(&rndc_ccmsg); 1024 1.1 christos 1025 1.1 christos isc_log_destroy(&log); 1026 1.1 christos isc_log_setcontext(NULL); 1027 1.1 christos 1028 1.1 christos cfg_obj_destroy(pctx, &config); 1029 1.1 christos cfg_parser_destroy(&pctx); 1030 1.1 christos 1031 1.1 christos isc_mem_put(rndc_mctx, args, argslen); 1032 1.1 christos 1033 1.1 christos isc_buffer_free(&databuf); 1034 1.1 christos 1035 1.4 christos if (show_final_mem) { 1036 1.1 christos isc_mem_stats(rndc_mctx, stderr); 1037 1.4 christos } 1038 1.1 christos 1039 1.13 christos isc_managers_destroy(&rndc_mctx, &loopmgr, &netmgr); 1040 1.1 christos 1041 1.4 christos if (failed) { 1042 1.13 christos return 1; 1043 1.4 christos } 1044 1.1 christos 1045 1.13 christos return 0; 1046 1.1 christos } 1047