nsupdate.c revision 135446
1135446Strhodes/* 2135446Strhodes * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 2000-2003 Internet Software Consortium. 4135446Strhodes * 5135446Strhodes * Permission to use, copy, modify, and distribute this software for any 6135446Strhodes * purpose with or without fee is hereby granted, provided that the above 7135446Strhodes * copyright notice and this permission notice appear in all copies. 8135446Strhodes * 9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11135446Strhodes * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15135446Strhodes * PERFORMANCE OF THIS SOFTWARE. 16135446Strhodes */ 17135446Strhodes 18135446Strhodes/* $Id: nsupdate.c,v 1.103.2.15.2.16 2004/06/17 01:00:38 sra Exp $ */ 19135446Strhodes 20135446Strhodes#include <config.h> 21135446Strhodes 22135446Strhodes#include <ctype.h> 23135446Strhodes#include <errno.h> 24135446Strhodes#include <limits.h> 25135446Strhodes#include <stdlib.h> 26135446Strhodes#include <unistd.h> 27135446Strhodes 28135446Strhodes#include <isc/app.h> 29135446Strhodes#include <isc/base64.h> 30135446Strhodes#include <isc/buffer.h> 31135446Strhodes#include <isc/commandline.h> 32135446Strhodes#include <isc/entropy.h> 33135446Strhodes#include <isc/event.h> 34135446Strhodes#include <isc/hash.h> 35135446Strhodes#include <isc/lex.h> 36135446Strhodes#include <isc/mem.h> 37135446Strhodes#include <isc/parseint.h> 38135446Strhodes#include <isc/region.h> 39135446Strhodes#include <isc/sockaddr.h> 40135446Strhodes#include <isc/socket.h> 41135446Strhodes#include <isc/stdio.h> 42135446Strhodes#include <isc/string.h> 43135446Strhodes#include <isc/task.h> 44135446Strhodes#include <isc/timer.h> 45135446Strhodes#include <isc/types.h> 46135446Strhodes#include <isc/util.h> 47135446Strhodes 48135446Strhodes#include <dns/callbacks.h> 49135446Strhodes#include <dns/dispatch.h> 50135446Strhodes#include <dns/dnssec.h> 51135446Strhodes#include <dns/events.h> 52135446Strhodes#include <dns/fixedname.h> 53135446Strhodes#include <dns/masterdump.h> 54135446Strhodes#include <dns/message.h> 55135446Strhodes#include <dns/name.h> 56135446Strhodes#include <dns/rcode.h> 57135446Strhodes#include <dns/rdata.h> 58135446Strhodes#include <dns/rdataclass.h> 59135446Strhodes#include <dns/rdatalist.h> 60135446Strhodes#include <dns/rdataset.h> 61135446Strhodes#include <dns/rdatastruct.h> 62135446Strhodes#include <dns/rdatatype.h> 63135446Strhodes#include <dns/request.h> 64135446Strhodes#include <dns/result.h> 65135446Strhodes#include <dns/tsig.h> 66135446Strhodes 67135446Strhodes#include <dst/dst.h> 68135446Strhodes 69135446Strhodes#include <lwres/lwres.h> 70135446Strhodes#include <lwres/net.h> 71135446Strhodes 72135446Strhodes#include <bind9/getaddresses.h> 73135446Strhodes 74135446Strhodes#ifdef HAVE_ADDRINFO 75135446Strhodes#ifdef HAVE_GETADDRINFO 76135446Strhodes#ifdef HAVE_GAISTRERROR 77135446Strhodes#define USE_GETADDRINFO 78135446Strhodes#endif 79135446Strhodes#endif 80135446Strhodes#endif 81135446Strhodes 82135446Strhodes#ifndef USE_GETADDRINFO 83135446Strhodes#ifndef ISC_PLATFORM_NONSTDHERRNO 84135446Strhodesextern int h_errno; 85135446Strhodes#endif 86135446Strhodes#endif 87135446Strhodes 88135446Strhodes#define MAXCMD (4 * 1024) 89135446Strhodes#define MAXWIRE (64 * 1024) 90135446Strhodes#define PACKETSIZE ((64 * 1024) - 1) 91135446Strhodes#define INITTEXT (2 * 1024) 92135446Strhodes#define MAXTEXT (128 * 1024) 93135446Strhodes#define FIND_TIMEOUT 5 94135446Strhodes#define TTL_MAX 2147483647U /* Maximum signed 32 bit integer. */ 95135446Strhodes 96135446Strhodes#define DNSDEFAULTPORT 53 97135446Strhodes 98135446Strhodes#ifndef RESOLV_CONF 99135446Strhodes#define RESOLV_CONF "/etc/resolv.conf" 100135446Strhodes#endif 101135446Strhodes 102135446Strhodesstatic isc_boolean_t debugging = ISC_FALSE, ddebugging = ISC_FALSE; 103135446Strhodesstatic isc_boolean_t memdebugging = ISC_FALSE; 104135446Strhodesstatic isc_boolean_t have_ipv4 = ISC_FALSE; 105135446Strhodesstatic isc_boolean_t have_ipv6 = ISC_FALSE; 106135446Strhodesstatic isc_boolean_t is_dst_up = ISC_FALSE; 107135446Strhodesstatic isc_boolean_t usevc = ISC_FALSE; 108135446Strhodesstatic isc_taskmgr_t *taskmgr = NULL; 109135446Strhodesstatic isc_task_t *global_task = NULL; 110135446Strhodesstatic isc_event_t *global_event = NULL; 111135446Strhodesstatic isc_mem_t *mctx = NULL; 112135446Strhodesstatic dns_dispatchmgr_t *dispatchmgr = NULL; 113135446Strhodesstatic dns_requestmgr_t *requestmgr = NULL; 114135446Strhodesstatic isc_socketmgr_t *socketmgr = NULL; 115135446Strhodesstatic isc_timermgr_t *timermgr = NULL; 116135446Strhodesstatic dns_dispatch_t *dispatchv4 = NULL; 117135446Strhodesstatic dns_dispatch_t *dispatchv6 = NULL; 118135446Strhodesstatic dns_message_t *updatemsg = NULL; 119135446Strhodesstatic dns_fixedname_t fuserzone; 120135446Strhodesstatic dns_name_t *userzone = NULL; 121135446Strhodesstatic dns_tsigkey_t *tsigkey = NULL; 122135446Strhodesstatic dst_key_t *sig0key; 123135446Strhodesstatic lwres_context_t *lwctx = NULL; 124135446Strhodesstatic lwres_conf_t *lwconf; 125135446Strhodesstatic isc_sockaddr_t *servers; 126135446Strhodesstatic int ns_inuse = 0; 127135446Strhodesstatic int ns_total = 0; 128135446Strhodesstatic isc_sockaddr_t *userserver = NULL; 129135446Strhodesstatic isc_sockaddr_t *localaddr = NULL; 130135446Strhodesstatic char *keystr = NULL, *keyfile = NULL; 131135446Strhodesstatic isc_entropy_t *entp = NULL; 132135446Strhodesstatic isc_boolean_t shuttingdown = ISC_FALSE; 133135446Strhodesstatic FILE *input; 134135446Strhodesstatic isc_boolean_t interactive = ISC_TRUE; 135135446Strhodesstatic isc_boolean_t seenerror = ISC_FALSE; 136135446Strhodesstatic const dns_master_style_t *style; 137135446Strhodesstatic int requests = 0; 138135446Strhodesstatic unsigned int timeout = 300; 139135446Strhodesstatic unsigned int udp_timeout = 3; 140135446Strhodesstatic unsigned int udp_retries = 3; 141135446Strhodesstatic dns_rdataclass_t defaultclass = dns_rdataclass_in; 142135446Strhodesstatic dns_rdataclass_t zoneclass = dns_rdataclass_none; 143135446Strhodesstatic dns_message_t *answer = NULL; 144135446Strhodes 145135446Strhodestypedef struct nsu_requestinfo { 146135446Strhodes dns_message_t *msg; 147135446Strhodes isc_sockaddr_t *addr; 148135446Strhodes} nsu_requestinfo_t; 149135446Strhodes 150135446Strhodesstatic void 151135446Strhodessendrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, 152135446Strhodes dns_message_t *msg, dns_request_t **request); 153135446Strhodesstatic void 154135446Strhodesfatal(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); 155135446Strhodes 156135446Strhodesstatic void 157135446Strhodesdebug(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); 158135446Strhodes 159135446Strhodesstatic void 160135446Strhodesddebug(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); 161135446Strhodes 162135446Strhodes#define STATUS_MORE (isc_uint16_t)0 163135446Strhodes#define STATUS_SEND (isc_uint16_t)1 164135446Strhodes#define STATUS_QUIT (isc_uint16_t)2 165135446Strhodes#define STATUS_SYNTAX (isc_uint16_t)3 166135446Strhodes 167135446Strhodesstatic dns_rdataclass_t 168135446Strhodesgetzoneclass(void) { 169135446Strhodes if (zoneclass == dns_rdataclass_none) 170135446Strhodes zoneclass = defaultclass; 171135446Strhodes return (zoneclass); 172135446Strhodes} 173135446Strhodes 174135446Strhodesstatic isc_boolean_t 175135446Strhodessetzoneclass(dns_rdataclass_t rdclass) { 176135446Strhodes if (zoneclass == dns_rdataclass_none || 177135446Strhodes rdclass == dns_rdataclass_none) 178135446Strhodes zoneclass = rdclass; 179135446Strhodes if (zoneclass != rdclass) 180135446Strhodes return (ISC_FALSE); 181135446Strhodes return (ISC_TRUE); 182135446Strhodes} 183135446Strhodes 184135446Strhodesstatic void 185135446Strhodesfatal(const char *format, ...) { 186135446Strhodes va_list args; 187135446Strhodes 188135446Strhodes va_start(args, format); 189135446Strhodes vfprintf(stderr, format, args); 190135446Strhodes va_end(args); 191135446Strhodes fprintf(stderr, "\n"); 192135446Strhodes exit(1); 193135446Strhodes} 194135446Strhodes 195135446Strhodesstatic void 196135446Strhodesdebug(const char *format, ...) { 197135446Strhodes va_list args; 198135446Strhodes 199135446Strhodes if (debugging) { 200135446Strhodes va_start(args, format); 201135446Strhodes vfprintf(stderr, format, args); 202135446Strhodes va_end(args); 203135446Strhodes fprintf(stderr, "\n"); 204135446Strhodes } 205135446Strhodes} 206135446Strhodes 207135446Strhodesstatic void 208135446Strhodesddebug(const char *format, ...) { 209135446Strhodes va_list args; 210135446Strhodes 211135446Strhodes if (ddebugging) { 212135446Strhodes va_start(args, format); 213135446Strhodes vfprintf(stderr, format, args); 214135446Strhodes va_end(args); 215135446Strhodes fprintf(stderr, "\n"); 216135446Strhodes } 217135446Strhodes} 218135446Strhodes 219135446Strhodesstatic inline void 220135446Strhodescheck_result(isc_result_t result, const char *msg) { 221135446Strhodes if (result != ISC_R_SUCCESS) 222135446Strhodes fatal("%s: %s", msg, isc_result_totext(result)); 223135446Strhodes} 224135446Strhodes 225135446Strhodesstatic void * 226135446Strhodesmem_alloc(void *arg, size_t size) { 227135446Strhodes return (isc_mem_get(arg, size)); 228135446Strhodes} 229135446Strhodes 230135446Strhodesstatic void 231135446Strhodesmem_free(void *arg, void *mem, size_t size) { 232135446Strhodes isc_mem_put(arg, mem, size); 233135446Strhodes} 234135446Strhodes 235135446Strhodesstatic char * 236135446Strhodesnsu_strsep(char **stringp, const char *delim) { 237135446Strhodes char *string = *stringp; 238135446Strhodes char *s; 239135446Strhodes const char *d; 240135446Strhodes char sc, dc; 241135446Strhodes 242135446Strhodes if (string == NULL) 243135446Strhodes return (NULL); 244135446Strhodes 245135446Strhodes for (; *string != '\0'; string++) { 246135446Strhodes sc = *string; 247135446Strhodes for (d = delim; (dc = *d) != '\0'; d++) { 248135446Strhodes if (sc == dc) 249135446Strhodes break; 250135446Strhodes } 251135446Strhodes if (dc == 0) 252135446Strhodes break; 253135446Strhodes } 254135446Strhodes 255135446Strhodes for (s = string; *s != '\0'; s++) { 256135446Strhodes sc = *s; 257135446Strhodes for (d = delim; (dc = *d) != '\0'; d++) { 258135446Strhodes if (sc == dc) { 259135446Strhodes *s++ = '\0'; 260135446Strhodes *stringp = s; 261135446Strhodes return (string); 262135446Strhodes } 263135446Strhodes } 264135446Strhodes } 265135446Strhodes *stringp = NULL; 266135446Strhodes return (string); 267135446Strhodes} 268135446Strhodes 269135446Strhodesstatic void 270135446Strhodesreset_system(void) { 271135446Strhodes isc_result_t result; 272135446Strhodes 273135446Strhodes ddebug("reset_system()"); 274135446Strhodes /* If the update message is still around, destroy it */ 275135446Strhodes if (updatemsg != NULL) 276135446Strhodes dns_message_reset(updatemsg, DNS_MESSAGE_INTENTRENDER); 277135446Strhodes else { 278135446Strhodes result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, 279135446Strhodes &updatemsg); 280135446Strhodes check_result(result, "dns_message_create"); 281135446Strhodes } 282135446Strhodes updatemsg->opcode = dns_opcode_update; 283135446Strhodes} 284135446Strhodes 285135446Strhodesstatic void 286135446Strhodessetup_keystr(void) { 287135446Strhodes unsigned char *secret = NULL; 288135446Strhodes int secretlen; 289135446Strhodes isc_buffer_t secretbuf; 290135446Strhodes isc_result_t result; 291135446Strhodes isc_buffer_t keynamesrc; 292135446Strhodes char *secretstr; 293135446Strhodes char *s; 294135446Strhodes dns_fixedname_t fkeyname; 295135446Strhodes dns_name_t *keyname; 296135446Strhodes 297135446Strhodes dns_fixedname_init(&fkeyname); 298135446Strhodes keyname = dns_fixedname_name(&fkeyname); 299135446Strhodes 300135446Strhodes debug("Creating key..."); 301135446Strhodes 302135446Strhodes s = strchr(keystr, ':'); 303135446Strhodes if (s == NULL || s == keystr || *s == 0) 304135446Strhodes fatal("key option must specify keyname:secret"); 305135446Strhodes secretstr = s + 1; 306135446Strhodes 307135446Strhodes isc_buffer_init(&keynamesrc, keystr, s - keystr); 308135446Strhodes isc_buffer_add(&keynamesrc, s - keystr); 309135446Strhodes 310135446Strhodes debug("namefromtext"); 311135446Strhodes result = dns_name_fromtext(keyname, &keynamesrc, dns_rootname, 312135446Strhodes ISC_FALSE, NULL); 313135446Strhodes check_result(result, "dns_name_fromtext"); 314135446Strhodes 315135446Strhodes secretlen = strlen(secretstr) * 3 / 4; 316135446Strhodes secret = isc_mem_allocate(mctx, secretlen); 317135446Strhodes if (secret == NULL) 318135446Strhodes fatal("out of memory"); 319135446Strhodes 320135446Strhodes isc_buffer_init(&secretbuf, secret, secretlen); 321135446Strhodes result = isc_base64_decodestring(secretstr, &secretbuf); 322135446Strhodes if (result != ISC_R_SUCCESS) { 323135446Strhodes fprintf(stderr, "could not create key from %s: %s\n", 324135446Strhodes keystr, isc_result_totext(result)); 325135446Strhodes goto failure; 326135446Strhodes } 327135446Strhodes 328135446Strhodes secretlen = isc_buffer_usedlength(&secretbuf); 329135446Strhodes 330135446Strhodes debug("keycreate"); 331135446Strhodes result = dns_tsigkey_create(keyname, dns_tsig_hmacmd5_name, 332135446Strhodes secret, secretlen, ISC_TRUE, NULL, 333135446Strhodes 0, 0, mctx, NULL, &tsigkey); 334135446Strhodes if (result != ISC_R_SUCCESS) 335135446Strhodes fprintf(stderr, "could not create key from %s: %s\n", 336135446Strhodes keystr, dns_result_totext(result)); 337135446Strhodes failure: 338135446Strhodes if (secret != NULL) 339135446Strhodes isc_mem_free(mctx, secret); 340135446Strhodes} 341135446Strhodes 342135446Strhodesstatic void 343135446Strhodessetup_keyfile(void) { 344135446Strhodes dst_key_t *dstkey = NULL; 345135446Strhodes isc_result_t result; 346135446Strhodes 347135446Strhodes debug("Creating key..."); 348135446Strhodes 349135446Strhodes result = dst_key_fromnamedfile(keyfile, 350135446Strhodes DST_TYPE_PRIVATE | DST_TYPE_KEY, mctx, 351135446Strhodes &dstkey); 352135446Strhodes if (result != ISC_R_SUCCESS) { 353135446Strhodes fprintf(stderr, "could not read key from %s: %s\n", 354135446Strhodes keyfile, isc_result_totext(result)); 355135446Strhodes return; 356135446Strhodes } 357135446Strhodes if (dst_key_alg(dstkey) == DST_ALG_HMACMD5) { 358135446Strhodes result = dns_tsigkey_createfromkey(dst_key_name(dstkey), 359135446Strhodes dns_tsig_hmacmd5_name, 360135446Strhodes dstkey, ISC_FALSE, NULL, 361135446Strhodes 0, 0, mctx, NULL, &tsigkey); 362135446Strhodes if (result != ISC_R_SUCCESS) { 363135446Strhodes fprintf(stderr, "could not create key from %s: %s\n", 364135446Strhodes keyfile, isc_result_totext(result)); 365135446Strhodes dst_key_free(&dstkey); 366135446Strhodes return; 367135446Strhodes } 368135446Strhodes } else 369135446Strhodes sig0key = dstkey; 370135446Strhodes} 371135446Strhodes 372135446Strhodesstatic void 373135446Strhodesdoshutdown(void) { 374135446Strhodes isc_task_detach(&global_task); 375135446Strhodes 376135446Strhodes if (userserver != NULL) 377135446Strhodes isc_mem_put(mctx, userserver, sizeof(isc_sockaddr_t)); 378135446Strhodes 379135446Strhodes if (localaddr != NULL) 380135446Strhodes isc_mem_put(mctx, localaddr, sizeof(isc_sockaddr_t)); 381135446Strhodes 382135446Strhodes if (tsigkey != NULL) { 383135446Strhodes ddebug("Freeing TSIG key"); 384135446Strhodes dns_tsigkey_detach(&tsigkey); 385135446Strhodes } 386135446Strhodes 387135446Strhodes if (sig0key != NULL) { 388135446Strhodes ddebug("Freeing SIG(0) key"); 389135446Strhodes dst_key_free(&sig0key); 390135446Strhodes } 391135446Strhodes 392135446Strhodes if (updatemsg != NULL) 393135446Strhodes dns_message_destroy(&updatemsg); 394135446Strhodes 395135446Strhodes if (is_dst_up) { 396135446Strhodes ddebug("Destroy DST lib"); 397135446Strhodes dst_lib_destroy(); 398135446Strhodes is_dst_up = ISC_FALSE; 399135446Strhodes } 400135446Strhodes 401135446Strhodes if (entp != NULL) { 402135446Strhodes ddebug("Detach from entropy"); 403135446Strhodes isc_entropy_detach(&entp); 404135446Strhodes } 405135446Strhodes 406135446Strhodes lwres_conf_clear(lwctx); 407135446Strhodes lwres_context_destroy(&lwctx); 408135446Strhodes 409135446Strhodes isc_mem_put(mctx, servers, ns_total * sizeof(isc_sockaddr_t)); 410135446Strhodes 411135446Strhodes ddebug("Destroying request manager"); 412135446Strhodes dns_requestmgr_detach(&requestmgr); 413135446Strhodes 414135446Strhodes ddebug("Freeing the dispatchers"); 415135446Strhodes if (have_ipv4) 416135446Strhodes dns_dispatch_detach(&dispatchv4); 417135446Strhodes if (have_ipv6) 418135446Strhodes dns_dispatch_detach(&dispatchv6); 419135446Strhodes 420135446Strhodes ddebug("Shutting down dispatch manager"); 421135446Strhodes dns_dispatchmgr_destroy(&dispatchmgr); 422135446Strhodes 423135446Strhodes} 424135446Strhodes 425135446Strhodesstatic void 426135446Strhodesmaybeshutdown(void) { 427135446Strhodes ddebug("Shutting down request manager"); 428135446Strhodes dns_requestmgr_shutdown(requestmgr); 429135446Strhodes 430135446Strhodes if (requests != 0) 431135446Strhodes return; 432135446Strhodes 433135446Strhodes doshutdown(); 434135446Strhodes} 435135446Strhodes 436135446Strhodesstatic void 437135446Strhodesshutdown_program(isc_task_t *task, isc_event_t *event) { 438135446Strhodes REQUIRE(task == global_task); 439135446Strhodes UNUSED(task); 440135446Strhodes 441135446Strhodes ddebug("shutdown_program()"); 442135446Strhodes isc_event_free(&event); 443135446Strhodes 444135446Strhodes shuttingdown = ISC_TRUE; 445135446Strhodes maybeshutdown(); 446135446Strhodes} 447135446Strhodes 448135446Strhodesstatic void 449135446Strhodessetup_system(void) { 450135446Strhodes isc_result_t result; 451135446Strhodes isc_sockaddr_t bind_any, bind_any6; 452135446Strhodes lwres_result_t lwresult; 453135446Strhodes unsigned int attrs, attrmask; 454135446Strhodes int i; 455135446Strhodes 456135446Strhodes ddebug("setup_system()"); 457135446Strhodes 458135446Strhodes dns_result_register(); 459135446Strhodes 460135446Strhodes result = isc_net_probeipv4(); 461135446Strhodes if (result == ISC_R_SUCCESS) 462135446Strhodes have_ipv4 = ISC_TRUE; 463135446Strhodes 464135446Strhodes result = isc_net_probeipv6(); 465135446Strhodes if (result == ISC_R_SUCCESS) 466135446Strhodes have_ipv6 = ISC_TRUE; 467135446Strhodes 468135446Strhodes if (!have_ipv4 && !have_ipv6) 469135446Strhodes fatal("could not find either IPv4 or IPv6"); 470135446Strhodes 471135446Strhodes result = isc_mem_create(0, 0, &mctx); 472135446Strhodes check_result(result, "isc_mem_create"); 473135446Strhodes 474135446Strhodes lwresult = lwres_context_create(&lwctx, mctx, mem_alloc, mem_free, 1); 475135446Strhodes if (lwresult != LWRES_R_SUCCESS) 476135446Strhodes fatal("lwres_context_create failed"); 477135446Strhodes 478135446Strhodes (void)lwres_conf_parse(lwctx, RESOLV_CONF); 479135446Strhodes lwconf = lwres_conf_get(lwctx); 480135446Strhodes 481135446Strhodes ns_total = lwconf->nsnext; 482135446Strhodes if (ns_total <= 0) { 483135446Strhodes /* No name servers in resolv.conf; default to loopback. */ 484135446Strhodes struct in_addr localhost; 485135446Strhodes ns_total = 1; 486135446Strhodes servers = isc_mem_get(mctx, ns_total * sizeof(isc_sockaddr_t)); 487135446Strhodes if (servers == NULL) 488135446Strhodes fatal("out of memory"); 489135446Strhodes localhost.s_addr = htonl(INADDR_LOOPBACK); 490135446Strhodes isc_sockaddr_fromin(&servers[0], &localhost, DNSDEFAULTPORT); 491135446Strhodes } else { 492135446Strhodes servers = isc_mem_get(mctx, ns_total * sizeof(isc_sockaddr_t)); 493135446Strhodes if (servers == NULL) 494135446Strhodes fatal("out of memory"); 495135446Strhodes for (i = 0; i < ns_total; i++) { 496135446Strhodes if (lwconf->nameservers[i].family == LWRES_ADDRTYPE_V4) { 497135446Strhodes struct in_addr in4; 498135446Strhodes memcpy(&in4, lwconf->nameservers[i].address, 4); 499135446Strhodes isc_sockaddr_fromin(&servers[i], &in4, DNSDEFAULTPORT); 500135446Strhodes } else { 501135446Strhodes struct in6_addr in6; 502135446Strhodes memcpy(&in6, lwconf->nameservers[i].address, 16); 503135446Strhodes isc_sockaddr_fromin6(&servers[i], &in6, 504135446Strhodes DNSDEFAULTPORT); 505135446Strhodes } 506135446Strhodes } 507135446Strhodes } 508135446Strhodes 509135446Strhodes result = isc_entropy_create(mctx, &entp); 510135446Strhodes check_result(result, "isc_entropy_create"); 511135446Strhodes 512135446Strhodes result = isc_hash_create(mctx, entp, DNS_NAME_MAXWIRE); 513135446Strhodes check_result(result, "isc_hash_create"); 514135446Strhodes isc_hash_init(); 515135446Strhodes 516135446Strhodes result = dns_dispatchmgr_create(mctx, entp, &dispatchmgr); 517135446Strhodes check_result(result, "dns_dispatchmgr_create"); 518135446Strhodes 519135446Strhodes result = isc_socketmgr_create(mctx, &socketmgr); 520135446Strhodes check_result(result, "dns_socketmgr_create"); 521135446Strhodes 522135446Strhodes result = isc_timermgr_create(mctx, &timermgr); 523135446Strhodes check_result(result, "dns_timermgr_create"); 524135446Strhodes 525135446Strhodes result = isc_taskmgr_create(mctx, 1, 0, &taskmgr); 526135446Strhodes check_result(result, "isc_taskmgr_create"); 527135446Strhodes 528135446Strhodes result = isc_task_create(taskmgr, 0, &global_task); 529135446Strhodes check_result(result, "isc_task_create"); 530135446Strhodes 531135446Strhodes result = isc_task_onshutdown(global_task, shutdown_program, NULL); 532135446Strhodes check_result(result, "isc_task_onshutdown"); 533135446Strhodes 534135446Strhodes result = dst_lib_init(mctx, entp, 0); 535135446Strhodes check_result(result, "dst_lib_init"); 536135446Strhodes is_dst_up = ISC_TRUE; 537135446Strhodes 538135446Strhodes attrmask = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP; 539135446Strhodes attrmask |= DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6; 540135446Strhodes 541135446Strhodes if (have_ipv6) { 542135446Strhodes attrs = DNS_DISPATCHATTR_UDP; 543135446Strhodes attrs |= DNS_DISPATCHATTR_MAKEQUERY; 544135446Strhodes attrs |= DNS_DISPATCHATTR_IPV6; 545135446Strhodes isc_sockaddr_any6(&bind_any6); 546135446Strhodes result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, 547135446Strhodes &bind_any6, PACKETSIZE, 548135446Strhodes 4, 2, 3, 5, 549135446Strhodes attrs, attrmask, &dispatchv6); 550135446Strhodes check_result(result, "dns_dispatch_getudp (v6)"); 551135446Strhodes } 552135446Strhodes 553135446Strhodes if (have_ipv4) { 554135446Strhodes attrs = DNS_DISPATCHATTR_UDP; 555135446Strhodes attrs |= DNS_DISPATCHATTR_MAKEQUERY; 556135446Strhodes attrs |= DNS_DISPATCHATTR_IPV4; 557135446Strhodes isc_sockaddr_any(&bind_any); 558135446Strhodes result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, 559135446Strhodes &bind_any, PACKETSIZE, 560135446Strhodes 4, 2, 3, 5, 561135446Strhodes attrs, attrmask, &dispatchv4); 562135446Strhodes check_result(result, "dns_dispatch_getudp (v4)"); 563135446Strhodes } 564135446Strhodes 565135446Strhodes result = dns_requestmgr_create(mctx, timermgr, 566135446Strhodes socketmgr, taskmgr, dispatchmgr, 567135446Strhodes dispatchv4, dispatchv6, &requestmgr); 568135446Strhodes check_result(result, "dns_requestmgr_create"); 569135446Strhodes 570135446Strhodes if (keystr != NULL) 571135446Strhodes setup_keystr(); 572135446Strhodes else if (keyfile != NULL) 573135446Strhodes setup_keyfile(); 574135446Strhodes} 575135446Strhodes 576135446Strhodesstatic void 577135446Strhodesget_address(char *host, in_port_t port, isc_sockaddr_t *sockaddr) { 578135446Strhodes int count; 579135446Strhodes isc_result_t result; 580135446Strhodes 581135446Strhodes isc_app_block(); 582135446Strhodes result = bind9_getaddresses(host, port, sockaddr, 1, &count); 583135446Strhodes isc_app_unblock(); 584135446Strhodes if (result != ISC_R_SUCCESS) 585135446Strhodes fatal("couldn't get address for '%s': %s", 586135446Strhodes host, isc_result_totext(result)); 587135446Strhodes INSIST(count == 1); 588135446Strhodes} 589135446Strhodes 590135446Strhodesstatic void 591135446Strhodesparse_args(int argc, char **argv) { 592135446Strhodes int ch; 593135446Strhodes isc_result_t result; 594135446Strhodes 595135446Strhodes debug("parse_args"); 596135446Strhodes while ((ch = isc_commandline_parse(argc, argv, "dDMy:vk:r:t:u:")) != -1) 597135446Strhodes { 598135446Strhodes switch (ch) { 599135446Strhodes case 'd': 600135446Strhodes debugging = ISC_TRUE; 601135446Strhodes break; 602135446Strhodes case 'D': /* was -dd */ 603135446Strhodes debugging = ISC_TRUE; 604135446Strhodes ddebugging = ISC_TRUE; 605135446Strhodes break; 606135446Strhodes case 'M': /* was -dm */ 607135446Strhodes debugging = ISC_TRUE; 608135446Strhodes ddebugging = ISC_TRUE; 609135446Strhodes memdebugging = ISC_TRUE; 610135446Strhodes isc_mem_debugging = ISC_MEM_DEBUGTRACE | 611135446Strhodes ISC_MEM_DEBUGRECORD; 612135446Strhodes break; 613135446Strhodes case 'y': 614135446Strhodes keystr = isc_commandline_argument; 615135446Strhodes break; 616135446Strhodes case 'v': 617135446Strhodes usevc = ISC_TRUE; 618135446Strhodes break; 619135446Strhodes case 'k': 620135446Strhodes keyfile = isc_commandline_argument; 621135446Strhodes break; 622135446Strhodes case 't': 623135446Strhodes result = isc_parse_uint32(&timeout, 624135446Strhodes isc_commandline_argument, 10); 625135446Strhodes if (result != ISC_R_SUCCESS) { 626135446Strhodes fprintf(stderr, "bad timeout '%s'\n", isc_commandline_argument); 627135446Strhodes exit(1); 628135446Strhodes } 629135446Strhodes if (timeout == 0) 630135446Strhodes timeout = ULONG_MAX; 631135446Strhodes break; 632135446Strhodes case 'u': 633135446Strhodes result = isc_parse_uint32(&udp_timeout, 634135446Strhodes isc_commandline_argument, 10); 635135446Strhodes if (result != ISC_R_SUCCESS) { 636135446Strhodes fprintf(stderr, "bad udp timeout '%s'\n", isc_commandline_argument); 637135446Strhodes exit(1); 638135446Strhodes } 639135446Strhodes if (udp_timeout == 0) 640135446Strhodes udp_timeout = ULONG_MAX; 641135446Strhodes break; 642135446Strhodes case 'r': 643135446Strhodes result = isc_parse_uint32(&udp_retries, 644135446Strhodes isc_commandline_argument, 10); 645135446Strhodes if (result != ISC_R_SUCCESS) { 646135446Strhodes fprintf(stderr, "bad udp retries '%s'\n", isc_commandline_argument); 647135446Strhodes exit(1); 648135446Strhodes } 649135446Strhodes break; 650135446Strhodes default: 651135446Strhodes fprintf(stderr, "%s: invalid argument -%c\n", 652135446Strhodes argv[0], ch); 653135446Strhodes fprintf(stderr, "usage: nsupdate [-d] " 654135446Strhodes "[-y keyname:secret | -k keyfile] [-v] " 655135446Strhodes "[filename]\n"); 656135446Strhodes exit(1); 657135446Strhodes } 658135446Strhodes } 659135446Strhodes if (keyfile != NULL && keystr != NULL) { 660135446Strhodes fprintf(stderr, "%s: cannot specify both -k and -y\n", 661135446Strhodes argv[0]); 662135446Strhodes exit(1); 663135446Strhodes } 664135446Strhodes 665135446Strhodes if (argv[isc_commandline_index] != NULL) { 666135446Strhodes if (strcmp(argv[isc_commandline_index], "-") == 0) { 667135446Strhodes input = stdin; 668135446Strhodes } else { 669135446Strhodes result = isc_stdio_open(argv[isc_commandline_index], 670135446Strhodes "r", &input); 671135446Strhodes if (result != ISC_R_SUCCESS) { 672135446Strhodes fprintf(stderr, "could not open '%s': %s\n", 673135446Strhodes argv[isc_commandline_index], 674135446Strhodes isc_result_totext(result)); 675135446Strhodes exit(1); 676135446Strhodes } 677135446Strhodes } 678135446Strhodes interactive = ISC_FALSE; 679135446Strhodes } 680135446Strhodes} 681135446Strhodes 682135446Strhodesstatic isc_uint16_t 683135446Strhodesparse_name(char **cmdlinep, dns_message_t *msg, dns_name_t **namep) { 684135446Strhodes isc_result_t result; 685135446Strhodes char *word; 686135446Strhodes isc_buffer_t *namebuf = NULL; 687135446Strhodes isc_buffer_t source; 688135446Strhodes 689135446Strhodes word = nsu_strsep(cmdlinep, " \t\r\n"); 690135446Strhodes if (*word == 0) { 691135446Strhodes fprintf(stderr, "could not read owner name\n"); 692135446Strhodes return (STATUS_SYNTAX); 693135446Strhodes } 694135446Strhodes 695135446Strhodes result = dns_message_gettempname(msg, namep); 696135446Strhodes check_result(result, "dns_message_gettempname"); 697135446Strhodes result = isc_buffer_allocate(mctx, &namebuf, DNS_NAME_MAXWIRE); 698135446Strhodes check_result(result, "isc_buffer_allocate"); 699135446Strhodes dns_name_init(*namep, NULL); 700135446Strhodes dns_name_setbuffer(*namep, namebuf); 701135446Strhodes dns_message_takebuffer(msg, &namebuf); 702135446Strhodes isc_buffer_init(&source, word, strlen(word)); 703135446Strhodes isc_buffer_add(&source, strlen(word)); 704135446Strhodes result = dns_name_fromtext(*namep, &source, dns_rootname, 705135446Strhodes ISC_FALSE, NULL); 706135446Strhodes check_result(result, "dns_name_fromtext"); 707135446Strhodes isc_buffer_invalidate(&source); 708135446Strhodes return (STATUS_MORE); 709135446Strhodes} 710135446Strhodes 711135446Strhodesstatic isc_uint16_t 712135446Strhodesparse_rdata(char **cmdlinep, dns_rdataclass_t rdataclass, 713135446Strhodes dns_rdatatype_t rdatatype, dns_message_t *msg, 714135446Strhodes dns_rdata_t *rdata) 715135446Strhodes{ 716135446Strhodes char *cmdline = *cmdlinep; 717135446Strhodes isc_buffer_t source, *buf = NULL, *newbuf = NULL; 718135446Strhodes isc_region_t r; 719135446Strhodes isc_lex_t *lex = NULL; 720135446Strhodes dns_rdatacallbacks_t callbacks; 721135446Strhodes isc_result_t result; 722135446Strhodes 723135446Strhodes while (*cmdline != 0 && isspace((unsigned char)*cmdline)) 724135446Strhodes cmdline++; 725135446Strhodes 726135446Strhodes if (*cmdline != 0) { 727135446Strhodes dns_rdatacallbacks_init(&callbacks); 728135446Strhodes result = isc_lex_create(mctx, strlen(cmdline), &lex); 729135446Strhodes check_result(result, "isc_lex_create"); 730135446Strhodes isc_buffer_init(&source, cmdline, strlen(cmdline)); 731135446Strhodes isc_buffer_add(&source, strlen(cmdline)); 732135446Strhodes result = isc_lex_openbuffer(lex, &source); 733135446Strhodes check_result(result, "isc_lex_openbuffer"); 734135446Strhodes result = isc_buffer_allocate(mctx, &buf, MAXWIRE); 735135446Strhodes check_result(result, "isc_buffer_allocate"); 736135446Strhodes result = dns_rdata_fromtext(rdata, rdataclass, rdatatype, lex, 737135446Strhodes dns_rootname, 0, mctx, buf, 738135446Strhodes &callbacks); 739135446Strhodes isc_lex_destroy(&lex); 740135446Strhodes if (result == ISC_R_SUCCESS) { 741135446Strhodes isc_buffer_usedregion(buf, &r); 742135446Strhodes result = isc_buffer_allocate(mctx, &newbuf, r.length); 743135446Strhodes check_result(result, "isc_buffer_allocate"); 744135446Strhodes isc_buffer_putmem(newbuf, r.base, r.length); 745135446Strhodes isc_buffer_usedregion(newbuf, &r); 746135446Strhodes dns_rdata_fromregion(rdata, rdataclass, rdatatype, &r); 747135446Strhodes isc_buffer_free(&buf); 748135446Strhodes dns_message_takebuffer(msg, &newbuf); 749135446Strhodes } else { 750135446Strhodes fprintf(stderr, "invalid rdata format: %s\n", 751135446Strhodes isc_result_totext(result)); 752135446Strhodes isc_buffer_free(&buf); 753135446Strhodes return (STATUS_SYNTAX); 754135446Strhodes } 755135446Strhodes } else { 756135446Strhodes rdata->flags = DNS_RDATA_UPDATE; 757135446Strhodes } 758135446Strhodes *cmdlinep = cmdline; 759135446Strhodes return (STATUS_MORE); 760135446Strhodes} 761135446Strhodes 762135446Strhodesstatic isc_uint16_t 763135446Strhodesmake_prereq(char *cmdline, isc_boolean_t ispositive, isc_boolean_t isrrset) { 764135446Strhodes isc_result_t result; 765135446Strhodes char *word; 766135446Strhodes dns_name_t *name = NULL; 767135446Strhodes isc_textregion_t region; 768135446Strhodes dns_rdataset_t *rdataset = NULL; 769135446Strhodes dns_rdatalist_t *rdatalist = NULL; 770135446Strhodes dns_rdataclass_t rdataclass; 771135446Strhodes dns_rdatatype_t rdatatype; 772135446Strhodes dns_rdata_t *rdata = NULL; 773135446Strhodes isc_uint16_t retval; 774135446Strhodes 775135446Strhodes ddebug("make_prereq()"); 776135446Strhodes 777135446Strhodes /* 778135446Strhodes * Read the owner name 779135446Strhodes */ 780135446Strhodes retval = parse_name(&cmdline, updatemsg, &name); 781135446Strhodes if (retval != STATUS_MORE) 782135446Strhodes return (retval); 783135446Strhodes 784135446Strhodes /* 785135446Strhodes * If this is an rrset prereq, read the class or type. 786135446Strhodes */ 787135446Strhodes if (isrrset) { 788135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 789135446Strhodes if (*word == 0) { 790135446Strhodes fprintf(stderr, "could not read class or type\n"); 791135446Strhodes goto failure; 792135446Strhodes } 793135446Strhodes region.base = word; 794135446Strhodes region.length = strlen(word); 795135446Strhodes result = dns_rdataclass_fromtext(&rdataclass, ®ion); 796135446Strhodes if (result == ISC_R_SUCCESS) { 797135446Strhodes if (!setzoneclass(rdataclass)) { 798135446Strhodes fprintf(stderr, "class mismatch: %s\n", word); 799135446Strhodes goto failure; 800135446Strhodes } 801135446Strhodes /* 802135446Strhodes * Now read the type. 803135446Strhodes */ 804135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 805135446Strhodes if (*word == 0) { 806135446Strhodes fprintf(stderr, "could not read type\n"); 807135446Strhodes goto failure; 808135446Strhodes } 809135446Strhodes region.base = word; 810135446Strhodes region.length = strlen(word); 811135446Strhodes result = dns_rdatatype_fromtext(&rdatatype, ®ion); 812135446Strhodes if (result != ISC_R_SUCCESS) { 813135446Strhodes fprintf(stderr, "invalid type: %s\n", word); 814135446Strhodes goto failure; 815135446Strhodes } 816135446Strhodes } else { 817135446Strhodes rdataclass = getzoneclass(); 818135446Strhodes result = dns_rdatatype_fromtext(&rdatatype, ®ion); 819135446Strhodes if (result != ISC_R_SUCCESS) { 820135446Strhodes fprintf(stderr, "invalid type: %s\n", word); 821135446Strhodes goto failure; 822135446Strhodes } 823135446Strhodes } 824135446Strhodes } else 825135446Strhodes rdatatype = dns_rdatatype_any; 826135446Strhodes 827135446Strhodes result = dns_message_gettemprdata(updatemsg, &rdata); 828135446Strhodes check_result(result, "dns_message_gettemprdata"); 829135446Strhodes 830135446Strhodes rdata->data = NULL; 831135446Strhodes rdata->length = 0; 832135446Strhodes 833135446Strhodes if (isrrset && ispositive) { 834135446Strhodes retval = parse_rdata(&cmdline, rdataclass, rdatatype, 835135446Strhodes updatemsg, rdata); 836135446Strhodes if (retval != STATUS_MORE) 837135446Strhodes goto failure; 838135446Strhodes } else 839135446Strhodes rdata->flags = DNS_RDATA_UPDATE; 840135446Strhodes 841135446Strhodes result = dns_message_gettemprdatalist(updatemsg, &rdatalist); 842135446Strhodes check_result(result, "dns_message_gettemprdatalist"); 843135446Strhodes result = dns_message_gettemprdataset(updatemsg, &rdataset); 844135446Strhodes check_result(result, "dns_message_gettemprdataset"); 845135446Strhodes dns_rdatalist_init(rdatalist); 846135446Strhodes rdatalist->type = rdatatype; 847135446Strhodes if (ispositive) { 848135446Strhodes if (isrrset && rdata->data != NULL) 849135446Strhodes rdatalist->rdclass = rdataclass; 850135446Strhodes else 851135446Strhodes rdatalist->rdclass = dns_rdataclass_any; 852135446Strhodes } else 853135446Strhodes rdatalist->rdclass = dns_rdataclass_none; 854135446Strhodes rdatalist->covers = 0; 855135446Strhodes rdatalist->ttl = 0; 856135446Strhodes rdata->rdclass = rdatalist->rdclass; 857135446Strhodes rdata->type = rdatatype; 858135446Strhodes ISC_LIST_INIT(rdatalist->rdata); 859135446Strhodes ISC_LIST_APPEND(rdatalist->rdata, rdata, link); 860135446Strhodes dns_rdataset_init(rdataset); 861135446Strhodes dns_rdatalist_tordataset(rdatalist, rdataset); 862135446Strhodes ISC_LIST_INIT(name->list); 863135446Strhodes ISC_LIST_APPEND(name->list, rdataset, link); 864135446Strhodes dns_message_addname(updatemsg, name, DNS_SECTION_PREREQUISITE); 865135446Strhodes return (STATUS_MORE); 866135446Strhodes 867135446Strhodes failure: 868135446Strhodes if (name != NULL) 869135446Strhodes dns_message_puttempname(updatemsg, &name); 870135446Strhodes return (STATUS_SYNTAX); 871135446Strhodes} 872135446Strhodes 873135446Strhodesstatic isc_uint16_t 874135446Strhodesevaluate_prereq(char *cmdline) { 875135446Strhodes char *word; 876135446Strhodes isc_boolean_t ispositive, isrrset; 877135446Strhodes 878135446Strhodes ddebug("evaluate_prereq()"); 879135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 880135446Strhodes if (*word == 0) { 881135446Strhodes fprintf(stderr, "could not read operation code\n"); 882135446Strhodes return (STATUS_SYNTAX); 883135446Strhodes } 884135446Strhodes if (strcasecmp(word, "nxdomain") == 0) { 885135446Strhodes ispositive = ISC_FALSE; 886135446Strhodes isrrset = ISC_FALSE; 887135446Strhodes } else if (strcasecmp(word, "yxdomain") == 0) { 888135446Strhodes ispositive = ISC_TRUE; 889135446Strhodes isrrset = ISC_FALSE; 890135446Strhodes } else if (strcasecmp(word, "nxrrset") == 0) { 891135446Strhodes ispositive = ISC_FALSE; 892135446Strhodes isrrset = ISC_TRUE; 893135446Strhodes } else if (strcasecmp(word, "yxrrset") == 0) { 894135446Strhodes ispositive = ISC_TRUE; 895135446Strhodes isrrset = ISC_TRUE; 896135446Strhodes } else { 897135446Strhodes fprintf(stderr, "incorrect operation code: %s\n", word); 898135446Strhodes return (STATUS_SYNTAX); 899135446Strhodes } 900135446Strhodes return (make_prereq(cmdline, ispositive, isrrset)); 901135446Strhodes} 902135446Strhodes 903135446Strhodesstatic isc_uint16_t 904135446Strhodesevaluate_server(char *cmdline) { 905135446Strhodes char *word, *server; 906135446Strhodes long port; 907135446Strhodes 908135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 909135446Strhodes if (*word == 0) { 910135446Strhodes fprintf(stderr, "could not read server name\n"); 911135446Strhodes return (STATUS_SYNTAX); 912135446Strhodes } 913135446Strhodes server = word; 914135446Strhodes 915135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 916135446Strhodes if (*word == 0) 917135446Strhodes port = DNSDEFAULTPORT; 918135446Strhodes else { 919135446Strhodes char *endp; 920135446Strhodes port = strtol(word, &endp, 10); 921135446Strhodes if (*endp != 0) { 922135446Strhodes fprintf(stderr, "port '%s' is not numeric\n", word); 923135446Strhodes return (STATUS_SYNTAX); 924135446Strhodes } else if (port < 1 || port > 65535) { 925135446Strhodes fprintf(stderr, "port '%s' is out of range " 926135446Strhodes "(1 to 65535)\n", word); 927135446Strhodes return (STATUS_SYNTAX); 928135446Strhodes } 929135446Strhodes } 930135446Strhodes 931135446Strhodes if (userserver == NULL) { 932135446Strhodes userserver = isc_mem_get(mctx, sizeof(isc_sockaddr_t)); 933135446Strhodes if (userserver == NULL) 934135446Strhodes fatal("out of memory"); 935135446Strhodes } 936135446Strhodes 937135446Strhodes get_address(server, (in_port_t)port, userserver); 938135446Strhodes 939135446Strhodes return (STATUS_MORE); 940135446Strhodes} 941135446Strhodes 942135446Strhodesstatic isc_uint16_t 943135446Strhodesevaluate_local(char *cmdline) { 944135446Strhodes char *word, *local; 945135446Strhodes long port; 946135446Strhodes struct in_addr in4; 947135446Strhodes struct in6_addr in6; 948135446Strhodes 949135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 950135446Strhodes if (*word == 0) { 951135446Strhodes fprintf(stderr, "could not read server name\n"); 952135446Strhodes return (STATUS_SYNTAX); 953135446Strhodes } 954135446Strhodes local = word; 955135446Strhodes 956135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 957135446Strhodes if (*word == 0) 958135446Strhodes port = 0; 959135446Strhodes else { 960135446Strhodes char *endp; 961135446Strhodes port = strtol(word, &endp, 10); 962135446Strhodes if (*endp != 0) { 963135446Strhodes fprintf(stderr, "port '%s' is not numeric\n", word); 964135446Strhodes return (STATUS_SYNTAX); 965135446Strhodes } else if (port < 1 || port > 65535) { 966135446Strhodes fprintf(stderr, "port '%s' is out of range " 967135446Strhodes "(1 to 65535)\n", word); 968135446Strhodes return (STATUS_SYNTAX); 969135446Strhodes } 970135446Strhodes } 971135446Strhodes 972135446Strhodes if (localaddr == NULL) { 973135446Strhodes localaddr = isc_mem_get(mctx, sizeof(isc_sockaddr_t)); 974135446Strhodes if (localaddr == NULL) 975135446Strhodes fatal("out of memory"); 976135446Strhodes } 977135446Strhodes 978135446Strhodes if (have_ipv6 && inet_pton(AF_INET6, local, &in6) == 1) 979135446Strhodes isc_sockaddr_fromin6(localaddr, &in6, (in_port_t)port); 980135446Strhodes else if (have_ipv4 && inet_pton(AF_INET, local, &in4) == 1) 981135446Strhodes isc_sockaddr_fromin(localaddr, &in4, (in_port_t)port); 982135446Strhodes else { 983135446Strhodes fprintf(stderr, "invalid address %s", local); 984135446Strhodes return (STATUS_SYNTAX); 985135446Strhodes } 986135446Strhodes 987135446Strhodes return (STATUS_MORE); 988135446Strhodes} 989135446Strhodes 990135446Strhodesstatic isc_uint16_t 991135446Strhodesevaluate_key(char *cmdline) { 992135446Strhodes char *namestr; 993135446Strhodes char *secretstr; 994135446Strhodes isc_buffer_t b; 995135446Strhodes isc_result_t result; 996135446Strhodes dns_fixedname_t fkeyname; 997135446Strhodes dns_name_t *keyname; 998135446Strhodes int secretlen; 999135446Strhodes unsigned char *secret = NULL; 1000135446Strhodes isc_buffer_t secretbuf; 1001135446Strhodes 1002135446Strhodes namestr = nsu_strsep(&cmdline, " \t\r\n"); 1003135446Strhodes if (*namestr == 0) { 1004135446Strhodes fprintf(stderr, "could not read key name\n"); 1005135446Strhodes return (STATUS_SYNTAX); 1006135446Strhodes } 1007135446Strhodes 1008135446Strhodes dns_fixedname_init(&fkeyname); 1009135446Strhodes keyname = dns_fixedname_name(&fkeyname); 1010135446Strhodes 1011135446Strhodes isc_buffer_init(&b, namestr, strlen(namestr)); 1012135446Strhodes isc_buffer_add(&b, strlen(namestr)); 1013135446Strhodes result = dns_name_fromtext(keyname, &b, dns_rootname, ISC_FALSE, NULL); 1014135446Strhodes if (result != ISC_R_SUCCESS) { 1015135446Strhodes fprintf(stderr, "could not parse key name\n"); 1016135446Strhodes return (STATUS_SYNTAX); 1017135446Strhodes } 1018135446Strhodes 1019135446Strhodes secretstr = nsu_strsep(&cmdline, "\r\n"); 1020135446Strhodes if (*secretstr == 0) { 1021135446Strhodes fprintf(stderr, "could not read key secret\n"); 1022135446Strhodes return (STATUS_SYNTAX); 1023135446Strhodes } 1024135446Strhodes secretlen = strlen(secretstr) * 3 / 4; 1025135446Strhodes secret = isc_mem_allocate(mctx, secretlen); 1026135446Strhodes if (secret == NULL) 1027135446Strhodes fatal("out of memory"); 1028135446Strhodes 1029135446Strhodes isc_buffer_init(&secretbuf, secret, secretlen); 1030135446Strhodes result = isc_base64_decodestring(secretstr, &secretbuf); 1031135446Strhodes if (result != ISC_R_SUCCESS) { 1032135446Strhodes fprintf(stderr, "could not create key from %s: %s\n", 1033135446Strhodes secretstr, isc_result_totext(result)); 1034135446Strhodes isc_mem_free(mctx, secret); 1035135446Strhodes return (STATUS_SYNTAX); 1036135446Strhodes } 1037135446Strhodes secretlen = isc_buffer_usedlength(&secretbuf); 1038135446Strhodes 1039135446Strhodes if (tsigkey != NULL) 1040135446Strhodes dns_tsigkey_detach(&tsigkey); 1041135446Strhodes result = dns_tsigkey_create(keyname, dns_tsig_hmacmd5_name, 1042135446Strhodes secret, secretlen, ISC_TRUE, NULL, 0, 0, 1043135446Strhodes mctx, NULL, &tsigkey); 1044135446Strhodes isc_mem_free(mctx, secret); 1045135446Strhodes if (result != ISC_R_SUCCESS) { 1046135446Strhodes fprintf(stderr, "could not create key from %s %s: %s\n", 1047135446Strhodes namestr, secretstr, dns_result_totext(result)); 1048135446Strhodes return (STATUS_SYNTAX); 1049135446Strhodes } 1050135446Strhodes return (STATUS_MORE); 1051135446Strhodes} 1052135446Strhodes 1053135446Strhodesstatic isc_uint16_t 1054135446Strhodesevaluate_zone(char *cmdline) { 1055135446Strhodes char *word; 1056135446Strhodes isc_buffer_t b; 1057135446Strhodes isc_result_t result; 1058135446Strhodes 1059135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1060135446Strhodes if (*word == 0) { 1061135446Strhodes fprintf(stderr, "could not read zone name\n"); 1062135446Strhodes return (STATUS_SYNTAX); 1063135446Strhodes } 1064135446Strhodes 1065135446Strhodes dns_fixedname_init(&fuserzone); 1066135446Strhodes userzone = dns_fixedname_name(&fuserzone); 1067135446Strhodes isc_buffer_init(&b, word, strlen(word)); 1068135446Strhodes isc_buffer_add(&b, strlen(word)); 1069135446Strhodes result = dns_name_fromtext(userzone, &b, dns_rootname, ISC_FALSE, 1070135446Strhodes NULL); 1071135446Strhodes if (result != ISC_R_SUCCESS) { 1072135446Strhodes userzone = NULL; /* Lest it point to an invalid name */ 1073135446Strhodes fprintf(stderr, "could not parse zone name\n"); 1074135446Strhodes return (STATUS_SYNTAX); 1075135446Strhodes } 1076135446Strhodes 1077135446Strhodes return (STATUS_MORE); 1078135446Strhodes} 1079135446Strhodes 1080135446Strhodesstatic isc_uint16_t 1081135446Strhodesevaluate_class(char *cmdline) { 1082135446Strhodes char *word; 1083135446Strhodes isc_textregion_t r; 1084135446Strhodes isc_result_t result; 1085135446Strhodes dns_rdataclass_t rdclass; 1086135446Strhodes 1087135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1088135446Strhodes if (*word == 0) { 1089135446Strhodes fprintf(stderr, "could not read class name\n"); 1090135446Strhodes return (STATUS_SYNTAX); 1091135446Strhodes } 1092135446Strhodes 1093135446Strhodes r.base = word; 1094135446Strhodes r.length = strlen(word); 1095135446Strhodes result = dns_rdataclass_fromtext(&rdclass, &r); 1096135446Strhodes if (result != ISC_R_SUCCESS) { 1097135446Strhodes fprintf(stderr, "could not parse class name: %s\n", word); 1098135446Strhodes return (STATUS_SYNTAX); 1099135446Strhodes } 1100135446Strhodes switch (rdclass) { 1101135446Strhodes case dns_rdataclass_none: 1102135446Strhodes case dns_rdataclass_any: 1103135446Strhodes case dns_rdataclass_reserved0: 1104135446Strhodes fprintf(stderr, "bad default class: %s\n", word); 1105135446Strhodes return (STATUS_SYNTAX); 1106135446Strhodes default: 1107135446Strhodes defaultclass = rdclass; 1108135446Strhodes } 1109135446Strhodes 1110135446Strhodes return (STATUS_MORE); 1111135446Strhodes} 1112135446Strhodes 1113135446Strhodesstatic isc_uint16_t 1114135446Strhodesupdate_addordelete(char *cmdline, isc_boolean_t isdelete) { 1115135446Strhodes isc_result_t result; 1116135446Strhodes dns_name_t *name = NULL; 1117135446Strhodes isc_uint32_t ttl; 1118135446Strhodes char *word; 1119135446Strhodes dns_rdataclass_t rdataclass; 1120135446Strhodes dns_rdatatype_t rdatatype; 1121135446Strhodes dns_rdata_t *rdata = NULL; 1122135446Strhodes dns_rdatalist_t *rdatalist = NULL; 1123135446Strhodes dns_rdataset_t *rdataset = NULL; 1124135446Strhodes isc_textregion_t region; 1125135446Strhodes isc_uint16_t retval; 1126135446Strhodes 1127135446Strhodes ddebug("update_addordelete()"); 1128135446Strhodes 1129135446Strhodes /* 1130135446Strhodes * Read the owner name. 1131135446Strhodes */ 1132135446Strhodes retval = parse_name(&cmdline, updatemsg, &name); 1133135446Strhodes if (retval != STATUS_MORE) 1134135446Strhodes return (retval); 1135135446Strhodes 1136135446Strhodes result = dns_message_gettemprdata(updatemsg, &rdata); 1137135446Strhodes check_result(result, "dns_message_gettemprdata"); 1138135446Strhodes 1139135446Strhodes rdata->rdclass = 0; 1140135446Strhodes rdata->type = 0; 1141135446Strhodes rdata->data = NULL; 1142135446Strhodes rdata->length = 0; 1143135446Strhodes 1144135446Strhodes /* 1145135446Strhodes * If this is an add, read the TTL and verify that it's in range. 1146135446Strhodes * If it's a delete, ignore a TTL if present (for compatibility). 1147135446Strhodes */ 1148135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1149135446Strhodes if (*word == 0) { 1150135446Strhodes if (!isdelete) { 1151135446Strhodes fprintf(stderr, "could not read owner ttl\n"); 1152135446Strhodes goto failure; 1153135446Strhodes } 1154135446Strhodes else { 1155135446Strhodes ttl = 0; 1156135446Strhodes rdataclass = dns_rdataclass_any; 1157135446Strhodes rdatatype = dns_rdatatype_any; 1158135446Strhodes rdata->flags = DNS_RDATA_UPDATE; 1159135446Strhodes goto doneparsing; 1160135446Strhodes } 1161135446Strhodes } 1162135446Strhodes result = isc_parse_uint32(&ttl, word, 10); 1163135446Strhodes if (result != ISC_R_SUCCESS) { 1164135446Strhodes if (isdelete) { 1165135446Strhodes ttl = 0; 1166135446Strhodes goto parseclass; 1167135446Strhodes } else { 1168135446Strhodes fprintf(stderr, "ttl '%s': %s\n", word, 1169135446Strhodes isc_result_totext(result)); 1170135446Strhodes goto failure; 1171135446Strhodes } 1172135446Strhodes } 1173135446Strhodes 1174135446Strhodes if (isdelete) 1175135446Strhodes ttl = 0; 1176135446Strhodes else if (ttl > TTL_MAX) { 1177135446Strhodes fprintf(stderr, "ttl '%s' is out of range (0 to %u)\n", 1178135446Strhodes word, TTL_MAX); 1179135446Strhodes goto failure; 1180135446Strhodes } 1181135446Strhodes 1182135446Strhodes /* 1183135446Strhodes * Read the class or type. 1184135446Strhodes */ 1185135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1186135446Strhodes parseclass: 1187135446Strhodes if (*word == 0) { 1188135446Strhodes if (isdelete) { 1189135446Strhodes rdataclass = dns_rdataclass_any; 1190135446Strhodes rdatatype = dns_rdatatype_any; 1191135446Strhodes rdata->flags = DNS_RDATA_UPDATE; 1192135446Strhodes goto doneparsing; 1193135446Strhodes } else { 1194135446Strhodes fprintf(stderr, "could not read class or type\n"); 1195135446Strhodes goto failure; 1196135446Strhodes } 1197135446Strhodes } 1198135446Strhodes region.base = word; 1199135446Strhodes region.length = strlen(word); 1200135446Strhodes result = dns_rdataclass_fromtext(&rdataclass, ®ion); 1201135446Strhodes if (result == ISC_R_SUCCESS) { 1202135446Strhodes if (!setzoneclass(rdataclass)) { 1203135446Strhodes fprintf(stderr, "class mismatch: %s\n", word); 1204135446Strhodes goto failure; 1205135446Strhodes } 1206135446Strhodes /* 1207135446Strhodes * Now read the type. 1208135446Strhodes */ 1209135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1210135446Strhodes if (*word == 0) { 1211135446Strhodes if (isdelete) { 1212135446Strhodes rdataclass = dns_rdataclass_any; 1213135446Strhodes rdatatype = dns_rdatatype_any; 1214135446Strhodes rdata->flags = DNS_RDATA_UPDATE; 1215135446Strhodes goto doneparsing; 1216135446Strhodes } else { 1217135446Strhodes fprintf(stderr, "could not read type\n"); 1218135446Strhodes goto failure; 1219135446Strhodes } 1220135446Strhodes } 1221135446Strhodes region.base = word; 1222135446Strhodes region.length = strlen(word); 1223135446Strhodes result = dns_rdatatype_fromtext(&rdatatype, ®ion); 1224135446Strhodes if (result != ISC_R_SUCCESS) { 1225135446Strhodes fprintf(stderr, "'%s' is not a valid type: %s\n", 1226135446Strhodes word, isc_result_totext(result)); 1227135446Strhodes goto failure; 1228135446Strhodes } 1229135446Strhodes } else { 1230135446Strhodes rdataclass = getzoneclass(); 1231135446Strhodes result = dns_rdatatype_fromtext(&rdatatype, ®ion); 1232135446Strhodes if (result != ISC_R_SUCCESS) { 1233135446Strhodes fprintf(stderr, "'%s' is not a valid class or type: " 1234135446Strhodes "%s\n", word, isc_result_totext(result)); 1235135446Strhodes goto failure; 1236135446Strhodes } 1237135446Strhodes } 1238135446Strhodes 1239135446Strhodes retval = parse_rdata(&cmdline, rdataclass, rdatatype, updatemsg, 1240135446Strhodes rdata); 1241135446Strhodes if (retval != STATUS_MORE) 1242135446Strhodes goto failure; 1243135446Strhodes 1244135446Strhodes if (isdelete) { 1245135446Strhodes if ((rdata->flags & DNS_RDATA_UPDATE) != 0) 1246135446Strhodes rdataclass = dns_rdataclass_any; 1247135446Strhodes else 1248135446Strhodes rdataclass = dns_rdataclass_none; 1249135446Strhodes } else { 1250135446Strhodes if ((rdata->flags & DNS_RDATA_UPDATE) != 0) { 1251135446Strhodes fprintf(stderr, "could not read rdata\n"); 1252135446Strhodes goto failure; 1253135446Strhodes } 1254135446Strhodes } 1255135446Strhodes 1256135446Strhodes doneparsing: 1257135446Strhodes 1258135446Strhodes result = dns_message_gettemprdatalist(updatemsg, &rdatalist); 1259135446Strhodes check_result(result, "dns_message_gettemprdatalist"); 1260135446Strhodes result = dns_message_gettemprdataset(updatemsg, &rdataset); 1261135446Strhodes check_result(result, "dns_message_gettemprdataset"); 1262135446Strhodes dns_rdatalist_init(rdatalist); 1263135446Strhodes rdatalist->type = rdatatype; 1264135446Strhodes rdatalist->rdclass = rdataclass; 1265135446Strhodes rdatalist->covers = rdatatype; 1266135446Strhodes rdatalist->ttl = (dns_ttl_t)ttl; 1267135446Strhodes ISC_LIST_INIT(rdatalist->rdata); 1268135446Strhodes ISC_LIST_APPEND(rdatalist->rdata, rdata, link); 1269135446Strhodes dns_rdataset_init(rdataset); 1270135446Strhodes dns_rdatalist_tordataset(rdatalist, rdataset); 1271135446Strhodes ISC_LIST_INIT(name->list); 1272135446Strhodes ISC_LIST_APPEND(name->list, rdataset, link); 1273135446Strhodes dns_message_addname(updatemsg, name, DNS_SECTION_UPDATE); 1274135446Strhodes return (STATUS_MORE); 1275135446Strhodes 1276135446Strhodes failure: 1277135446Strhodes if (name != NULL) 1278135446Strhodes dns_message_puttempname(updatemsg, &name); 1279135446Strhodes if (rdata != NULL) 1280135446Strhodes dns_message_puttemprdata(updatemsg, &rdata); 1281135446Strhodes return (STATUS_SYNTAX); 1282135446Strhodes} 1283135446Strhodes 1284135446Strhodesstatic isc_uint16_t 1285135446Strhodesevaluate_update(char *cmdline) { 1286135446Strhodes char *word; 1287135446Strhodes isc_boolean_t isdelete; 1288135446Strhodes 1289135446Strhodes ddebug("evaluate_update()"); 1290135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1291135446Strhodes if (*word == 0) { 1292135446Strhodes fprintf(stderr, "could not read operation code\n"); 1293135446Strhodes return (STATUS_SYNTAX); 1294135446Strhodes } 1295135446Strhodes if (strcasecmp(word, "delete") == 0) 1296135446Strhodes isdelete = ISC_TRUE; 1297135446Strhodes else if (strcasecmp(word, "add") == 0) 1298135446Strhodes isdelete = ISC_FALSE; 1299135446Strhodes else { 1300135446Strhodes fprintf(stderr, "incorrect operation code: %s\n", word); 1301135446Strhodes return (STATUS_SYNTAX); 1302135446Strhodes } 1303135446Strhodes return (update_addordelete(cmdline, isdelete)); 1304135446Strhodes} 1305135446Strhodes 1306135446Strhodesstatic void 1307135446Strhodesshow_message(dns_message_t *msg) { 1308135446Strhodes isc_result_t result; 1309135446Strhodes isc_buffer_t *buf = NULL; 1310135446Strhodes int bufsz; 1311135446Strhodes 1312135446Strhodes ddebug("show_message()"); 1313135446Strhodes bufsz = INITTEXT; 1314135446Strhodes do { 1315135446Strhodes if (bufsz > MAXTEXT) { 1316135446Strhodes fprintf(stderr, "could not allocate large enough " 1317135446Strhodes "buffer to display message\n"); 1318135446Strhodes exit(1); 1319135446Strhodes } 1320135446Strhodes if (buf != NULL) 1321135446Strhodes isc_buffer_free(&buf); 1322135446Strhodes result = isc_buffer_allocate(mctx, &buf, bufsz); 1323135446Strhodes check_result(result, "isc_buffer_allocate"); 1324135446Strhodes result = dns_message_totext(msg, style, 0, buf); 1325135446Strhodes bufsz *= 2; 1326135446Strhodes } while (result == ISC_R_NOSPACE); 1327135446Strhodes if (result != ISC_R_SUCCESS) { 1328135446Strhodes fprintf(stderr, "could not convert message to text format.\n"); 1329135446Strhodes isc_buffer_free(&buf); 1330135446Strhodes return; 1331135446Strhodes } 1332135446Strhodes printf("Outgoing update query:\n%.*s", 1333135446Strhodes (int)isc_buffer_usedlength(buf), 1334135446Strhodes (char*)isc_buffer_base(buf)); 1335135446Strhodes isc_buffer_free(&buf); 1336135446Strhodes} 1337135446Strhodes 1338135446Strhodes 1339135446Strhodesstatic isc_uint16_t 1340135446Strhodesget_next_command(void) { 1341135446Strhodes char cmdlinebuf[MAXCMD]; 1342135446Strhodes char *cmdline; 1343135446Strhodes char *word; 1344135446Strhodes 1345135446Strhodes ddebug("get_next_command()"); 1346135446Strhodes if (interactive) 1347135446Strhodes fprintf(stdout, "> "); 1348135446Strhodes isc_app_block(); 1349135446Strhodes cmdline = fgets(cmdlinebuf, MAXCMD, input); 1350135446Strhodes isc_app_unblock(); 1351135446Strhodes if (cmdline == NULL) 1352135446Strhodes return (STATUS_QUIT); 1353135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1354135446Strhodes 1355135446Strhodes if (feof(input)) 1356135446Strhodes return (STATUS_QUIT); 1357135446Strhodes if (*word == 0) 1358135446Strhodes return (STATUS_SEND); 1359135446Strhodes if (word[0] == ';') 1360135446Strhodes return (STATUS_MORE); 1361135446Strhodes if (strcasecmp(word, "quit") == 0) 1362135446Strhodes return (STATUS_QUIT); 1363135446Strhodes if (strcasecmp(word, "prereq") == 0) 1364135446Strhodes return (evaluate_prereq(cmdline)); 1365135446Strhodes if (strcasecmp(word, "update") == 0) 1366135446Strhodes return (evaluate_update(cmdline)); 1367135446Strhodes if (strcasecmp(word, "server") == 0) 1368135446Strhodes return (evaluate_server(cmdline)); 1369135446Strhodes if (strcasecmp(word, "local") == 0) 1370135446Strhodes return (evaluate_local(cmdline)); 1371135446Strhodes if (strcasecmp(word, "zone") == 0) 1372135446Strhodes return (evaluate_zone(cmdline)); 1373135446Strhodes if (strcasecmp(word, "class") == 0) 1374135446Strhodes return (evaluate_class(cmdline)); 1375135446Strhodes if (strcasecmp(word, "send") == 0) 1376135446Strhodes return (STATUS_SEND); 1377135446Strhodes if (strcasecmp(word, "show") == 0) { 1378135446Strhodes show_message(updatemsg); 1379135446Strhodes return (STATUS_MORE); 1380135446Strhodes } 1381135446Strhodes if (strcasecmp(word, "answer") == 0) { 1382135446Strhodes if (answer != NULL) 1383135446Strhodes show_message(answer); 1384135446Strhodes return (STATUS_MORE); 1385135446Strhodes } 1386135446Strhodes if (strcasecmp(word, "key") == 0) 1387135446Strhodes return (evaluate_key(cmdline)); 1388135446Strhodes fprintf(stderr, "incorrect section name: %s\n", word); 1389135446Strhodes return (STATUS_SYNTAX); 1390135446Strhodes} 1391135446Strhodes 1392135446Strhodesstatic isc_boolean_t 1393135446Strhodesuser_interaction(void) { 1394135446Strhodes isc_uint16_t result = STATUS_MORE; 1395135446Strhodes 1396135446Strhodes ddebug("user_interaction()"); 1397135446Strhodes while ((result == STATUS_MORE) || (result == STATUS_SYNTAX)) 1398135446Strhodes result = get_next_command(); 1399135446Strhodes if (result == STATUS_SEND) 1400135446Strhodes return (ISC_TRUE); 1401135446Strhodes return (ISC_FALSE); 1402135446Strhodes 1403135446Strhodes} 1404135446Strhodes 1405135446Strhodesstatic void 1406135446Strhodesdone_update(void) { 1407135446Strhodes isc_event_t *event = global_event; 1408135446Strhodes ddebug("done_update()"); 1409135446Strhodes isc_task_send(global_task, &event); 1410135446Strhodes} 1411135446Strhodes 1412135446Strhodesstatic void 1413135446Strhodescheck_tsig_error(dns_rdataset_t *rdataset, isc_buffer_t *b) { 1414135446Strhodes isc_result_t result; 1415135446Strhodes dns_rdata_t rdata = DNS_RDATA_INIT; 1416135446Strhodes dns_rdata_any_tsig_t tsig; 1417135446Strhodes 1418135446Strhodes result = dns_rdataset_first(rdataset); 1419135446Strhodes check_result(result, "dns_rdataset_first"); 1420135446Strhodes dns_rdataset_current(rdataset, &rdata); 1421135446Strhodes result = dns_rdata_tostruct(&rdata, &tsig, NULL); 1422135446Strhodes check_result(result, "dns_rdata_tostruct"); 1423135446Strhodes if (tsig.error != 0) { 1424135446Strhodes if (isc_buffer_remaininglength(b) < 1) 1425135446Strhodes check_result(ISC_R_NOSPACE, "isc_buffer_remaininglength"); 1426135446Strhodes isc__buffer_putstr(b, "(" /*)*/); 1427135446Strhodes result = dns_tsigrcode_totext(tsig.error, b); 1428135446Strhodes check_result(result, "dns_tsigrcode_totext"); 1429135446Strhodes if (isc_buffer_remaininglength(b) < 1) 1430135446Strhodes check_result(ISC_R_NOSPACE, "isc_buffer_remaininglength"); 1431135446Strhodes isc__buffer_putstr(b, /*(*/ ")"); 1432135446Strhodes } 1433135446Strhodes} 1434135446Strhodes 1435135446Strhodesstatic void 1436135446Strhodesupdate_completed(isc_task_t *task, isc_event_t *event) { 1437135446Strhodes dns_requestevent_t *reqev = NULL; 1438135446Strhodes isc_result_t result; 1439135446Strhodes dns_request_t *request; 1440135446Strhodes 1441135446Strhodes UNUSED(task); 1442135446Strhodes 1443135446Strhodes ddebug("update_completed()"); 1444135446Strhodes 1445135446Strhodes requests--; 1446135446Strhodes 1447135446Strhodes REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE); 1448135446Strhodes reqev = (dns_requestevent_t *)event; 1449135446Strhodes request = reqev->request; 1450135446Strhodes 1451135446Strhodes if (shuttingdown) { 1452135446Strhodes dns_request_destroy(&request); 1453135446Strhodes isc_event_free(&event); 1454135446Strhodes maybeshutdown(); 1455135446Strhodes return; 1456135446Strhodes } 1457135446Strhodes 1458135446Strhodes if (reqev->result != ISC_R_SUCCESS) { 1459135446Strhodes fprintf(stderr, "; Communication with server failed: %s\n", 1460135446Strhodes isc_result_totext(reqev->result)); 1461135446Strhodes seenerror = ISC_TRUE; 1462135446Strhodes goto done; 1463135446Strhodes } 1464135446Strhodes 1465135446Strhodes result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &answer); 1466135446Strhodes check_result(result, "dns_message_create"); 1467135446Strhodes result = dns_request_getresponse(request, answer, 1468135446Strhodes DNS_MESSAGEPARSE_PRESERVEORDER); 1469135446Strhodes switch (result) { 1470135446Strhodes case ISC_R_SUCCESS: 1471135446Strhodes break; 1472135446Strhodes case DNS_R_CLOCKSKEW: 1473135446Strhodes case DNS_R_EXPECTEDTSIG: 1474135446Strhodes case DNS_R_TSIGERRORSET: 1475135446Strhodes case DNS_R_TSIGVERIFYFAILURE: 1476135446Strhodes case DNS_R_UNEXPECTEDTSIG: 1477135446Strhodes fprintf(stderr, "; TSIG error with server: %s\n", 1478135446Strhodes isc_result_totext(result)); 1479135446Strhodes seenerror = ISC_TRUE; 1480135446Strhodes break; 1481135446Strhodes default: 1482135446Strhodes check_result(result, "dns_request_getresponse"); 1483135446Strhodes } 1484135446Strhodes 1485135446Strhodes if (answer->rcode != dns_rcode_noerror) { 1486135446Strhodes seenerror = ISC_TRUE; 1487135446Strhodes if (!debugging) { 1488135446Strhodes char buf[64]; 1489135446Strhodes isc_buffer_t b; 1490135446Strhodes dns_rdataset_t *rds; 1491135446Strhodes 1492135446Strhodes isc_buffer_init(&b, buf, sizeof(buf) - 1); 1493135446Strhodes result = dns_rcode_totext(answer->rcode, &b); 1494135446Strhodes check_result(result, "dns_rcode_totext"); 1495135446Strhodes rds = dns_message_gettsig(answer, NULL); 1496135446Strhodes if (rds != NULL) 1497135446Strhodes check_tsig_error(rds, &b); 1498135446Strhodes fprintf(stderr, "update failed: %.*s\n", 1499135446Strhodes (int)isc_buffer_usedlength(&b), buf); 1500135446Strhodes } 1501135446Strhodes } 1502135446Strhodes if (debugging) { 1503135446Strhodes isc_buffer_t *buf = NULL; 1504135446Strhodes int bufsz; 1505135446Strhodes 1506135446Strhodes bufsz = INITTEXT; 1507135446Strhodes do { 1508135446Strhodes if (bufsz > MAXTEXT) { 1509135446Strhodes fprintf(stderr, "could not allocate large " 1510135446Strhodes "enough buffer to display message\n"); 1511135446Strhodes exit(1); 1512135446Strhodes } 1513135446Strhodes if (buf != NULL) 1514135446Strhodes isc_buffer_free(&buf); 1515135446Strhodes result = isc_buffer_allocate(mctx, &buf, bufsz); 1516135446Strhodes check_result(result, "isc_buffer_allocate"); 1517135446Strhodes result = dns_message_totext(answer, style, 0, buf); 1518135446Strhodes bufsz *= 2; 1519135446Strhodes } while (result == ISC_R_NOSPACE); 1520135446Strhodes check_result(result, "dns_message_totext"); 1521135446Strhodes fprintf(stderr, "\nReply from update query:\n%.*s\n", 1522135446Strhodes (int)isc_buffer_usedlength(buf), 1523135446Strhodes (char*)isc_buffer_base(buf)); 1524135446Strhodes isc_buffer_free(&buf); 1525135446Strhodes } 1526135446Strhodes done: 1527135446Strhodes dns_request_destroy(&request); 1528135446Strhodes isc_event_free(&event); 1529135446Strhodes done_update(); 1530135446Strhodes} 1531135446Strhodes 1532135446Strhodesstatic void 1533135446Strhodessend_update(dns_name_t *zonename, isc_sockaddr_t *master, 1534135446Strhodes isc_sockaddr_t *srcaddr) 1535135446Strhodes{ 1536135446Strhodes isc_result_t result; 1537135446Strhodes dns_request_t *request = NULL; 1538135446Strhodes dns_name_t *name = NULL; 1539135446Strhodes dns_rdataset_t *rdataset = NULL; 1540135446Strhodes unsigned int options = 0; 1541135446Strhodes 1542135446Strhodes ddebug("send_update()"); 1543135446Strhodes 1544135446Strhodes result = dns_message_gettempname(updatemsg, &name); 1545135446Strhodes check_result(result, "dns_message_gettempname"); 1546135446Strhodes dns_name_init(name, NULL); 1547135446Strhodes dns_name_clone(zonename, name); 1548135446Strhodes result = dns_message_gettemprdataset(updatemsg, &rdataset); 1549135446Strhodes check_result(result, "dns_message_gettemprdataset"); 1550135446Strhodes dns_rdataset_makequestion(rdataset, getzoneclass(), dns_rdatatype_soa); 1551135446Strhodes ISC_LIST_INIT(name->list); 1552135446Strhodes ISC_LIST_APPEND(name->list, rdataset, link); 1553135446Strhodes dns_message_addname(updatemsg, name, DNS_SECTION_ZONE); 1554135446Strhodes 1555135446Strhodes if (usevc) 1556135446Strhodes options |= DNS_REQUESTOPT_TCP; 1557135446Strhodes if (tsigkey == NULL && sig0key != NULL) { 1558135446Strhodes result = dns_message_setsig0key(updatemsg, sig0key); 1559135446Strhodes check_result(result, "dns_message_setsig0key"); 1560135446Strhodes } 1561135446Strhodes if (debugging) { 1562135446Strhodes char addrbuf[ISC_SOCKADDR_FORMATSIZE]; 1563135446Strhodes 1564135446Strhodes isc_sockaddr_format(master, addrbuf, sizeof(addrbuf)); 1565135446Strhodes fprintf(stderr, "Sending update to %s\n", addrbuf); 1566135446Strhodes } 1567135446Strhodes result = dns_request_createvia3(requestmgr, updatemsg, srcaddr, 1568135446Strhodes master, options, tsigkey, timeout, 1569135446Strhodes udp_timeout, udp_retries, global_task, 1570135446Strhodes update_completed, NULL, &request); 1571135446Strhodes check_result(result, "dns_request_createvia3"); 1572135446Strhodes 1573135446Strhodes if (debugging) 1574135446Strhodes show_message(updatemsg); 1575135446Strhodes 1576135446Strhodes requests++; 1577135446Strhodes} 1578135446Strhodes 1579135446Strhodesstatic void 1580135446Strhodesrecvsoa(isc_task_t *task, isc_event_t *event) { 1581135446Strhodes dns_requestevent_t *reqev = NULL; 1582135446Strhodes dns_request_t *request = NULL; 1583135446Strhodes isc_result_t result, eresult; 1584135446Strhodes dns_message_t *rcvmsg = NULL; 1585135446Strhodes dns_section_t section; 1586135446Strhodes dns_name_t *name = NULL; 1587135446Strhodes dns_rdataset_t *soaset = NULL; 1588135446Strhodes dns_rdata_soa_t soa; 1589135446Strhodes dns_rdata_t soarr = DNS_RDATA_INIT; 1590135446Strhodes int pass = 0; 1591135446Strhodes dns_name_t master; 1592135446Strhodes isc_sockaddr_t *serveraddr, tempaddr; 1593135446Strhodes dns_name_t *zonename; 1594135446Strhodes nsu_requestinfo_t *reqinfo; 1595135446Strhodes dns_message_t *soaquery = NULL; 1596135446Strhodes isc_sockaddr_t *addr; 1597135446Strhodes isc_boolean_t seencname = ISC_FALSE; 1598135446Strhodes 1599135446Strhodes UNUSED(task); 1600135446Strhodes 1601135446Strhodes ddebug("recvsoa()"); 1602135446Strhodes 1603135446Strhodes requests--; 1604135446Strhodes 1605135446Strhodes REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE); 1606135446Strhodes reqev = (dns_requestevent_t *)event; 1607135446Strhodes request = reqev->request; 1608135446Strhodes eresult = reqev->result; 1609135446Strhodes reqinfo = reqev->ev_arg; 1610135446Strhodes soaquery = reqinfo->msg; 1611135446Strhodes addr = reqinfo->addr; 1612135446Strhodes 1613135446Strhodes if (shuttingdown) { 1614135446Strhodes dns_request_destroy(&request); 1615135446Strhodes dns_message_destroy(&soaquery); 1616135446Strhodes isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t)); 1617135446Strhodes isc_event_free(&event); 1618135446Strhodes maybeshutdown(); 1619135446Strhodes return; 1620135446Strhodes } 1621135446Strhodes 1622135446Strhodes if (eresult != ISC_R_SUCCESS) { 1623135446Strhodes char addrbuf[ISC_SOCKADDR_FORMATSIZE]; 1624135446Strhodes 1625135446Strhodes isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf)); 1626135446Strhodes fprintf(stderr, "; Communication with %s failed: %s\n", 1627135446Strhodes addrbuf, isc_result_totext(eresult)); 1628135446Strhodes if (userserver != NULL) 1629135446Strhodes fatal("could not talk to specified name server"); 1630135446Strhodes else if (++ns_inuse >= lwconf->nsnext) 1631135446Strhodes fatal("could not talk to any default name server"); 1632135446Strhodes ddebug("Destroying request [%p]", request); 1633135446Strhodes dns_request_destroy(&request); 1634135446Strhodes dns_message_renderreset(soaquery); 1635135446Strhodes sendrequest(localaddr, &servers[ns_inuse], soaquery, &request); 1636135446Strhodes isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t)); 1637135446Strhodes isc_event_free(&event); 1638135446Strhodes setzoneclass(dns_rdataclass_none); 1639135446Strhodes return; 1640135446Strhodes } 1641135446Strhodes isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t)); 1642135446Strhodes 1643135446Strhodes isc_event_free(&event); 1644135446Strhodes reqev = NULL; 1645135446Strhodes 1646135446Strhodes ddebug("About to create rcvmsg"); 1647135446Strhodes result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &rcvmsg); 1648135446Strhodes check_result(result, "dns_message_create"); 1649135446Strhodes result = dns_request_getresponse(request, rcvmsg, 1650135446Strhodes DNS_MESSAGEPARSE_PRESERVEORDER); 1651135446Strhodes if (result == DNS_R_TSIGERRORSET && userserver != NULL) { 1652135446Strhodes dns_message_destroy(&rcvmsg); 1653135446Strhodes ddebug("Destroying request [%p]", request); 1654135446Strhodes dns_request_destroy(&request); 1655135446Strhodes reqinfo = isc_mem_get(mctx, sizeof(nsu_requestinfo_t)); 1656135446Strhodes if (reqinfo == NULL) 1657135446Strhodes fatal("out of memory"); 1658135446Strhodes reqinfo->msg = soaquery; 1659135446Strhodes reqinfo->addr = addr; 1660135446Strhodes dns_message_renderreset(soaquery); 1661135446Strhodes ddebug("retrying soa request without TSIG"); 1662135446Strhodes result = dns_request_createvia3(requestmgr, soaquery, 1663135446Strhodes localaddr, addr, 0, NULL, 1664135446Strhodes FIND_TIMEOUT * 20, 1665135446Strhodes FIND_TIMEOUT * 20, 3, 1666135446Strhodes global_task, recvsoa, reqinfo, 1667135446Strhodes &request); 1668135446Strhodes check_result(result, "dns_request_createvia"); 1669135446Strhodes requests++; 1670135446Strhodes return; 1671135446Strhodes } 1672135446Strhodes check_result(result, "dns_request_getresponse"); 1673135446Strhodes section = DNS_SECTION_ANSWER; 1674135446Strhodes if (debugging) { 1675135446Strhodes isc_buffer_t *buf = NULL; 1676135446Strhodes int bufsz; 1677135446Strhodes bufsz = INITTEXT; 1678135446Strhodes do { 1679135446Strhodes if (buf != NULL) 1680135446Strhodes isc_buffer_free(&buf); 1681135446Strhodes if (bufsz > MAXTEXT) { 1682135446Strhodes fprintf(stderr, "could not allocate enough " 1683135446Strhodes "space for debugging message\n"); 1684135446Strhodes exit(1); 1685135446Strhodes } 1686135446Strhodes result = isc_buffer_allocate(mctx, &buf, bufsz); 1687135446Strhodes check_result(result, "isc_buffer_allocate"); 1688135446Strhodes result = dns_message_totext(rcvmsg, style, 0, buf); 1689135446Strhodes } while (result == ISC_R_NOSPACE); 1690135446Strhodes check_result(result, "dns_message_totext"); 1691135446Strhodes fprintf(stderr, "Reply from SOA query:\n%.*s\n", 1692135446Strhodes (int)isc_buffer_usedlength(buf), 1693135446Strhodes (char*)isc_buffer_base(buf)); 1694135446Strhodes isc_buffer_free(&buf); 1695135446Strhodes } 1696135446Strhodes 1697135446Strhodes if (rcvmsg->rcode != dns_rcode_noerror && 1698135446Strhodes rcvmsg->rcode != dns_rcode_nxdomain) 1699135446Strhodes fatal("response to SOA query was unsuccessful"); 1700135446Strhodes 1701135446Strhodes lookforsoa: 1702135446Strhodes if (pass == 0) 1703135446Strhodes section = DNS_SECTION_ANSWER; 1704135446Strhodes else if (pass == 1) 1705135446Strhodes section = DNS_SECTION_AUTHORITY; 1706135446Strhodes else 1707135446Strhodes fatal("response to SOA query didn't contain an SOA"); 1708135446Strhodes 1709135446Strhodes 1710135446Strhodes result = dns_message_firstname(rcvmsg, section); 1711135446Strhodes if (result != ISC_R_SUCCESS) { 1712135446Strhodes pass++; 1713135446Strhodes goto lookforsoa; 1714135446Strhodes } 1715135446Strhodes while (result == ISC_R_SUCCESS) { 1716135446Strhodes name = NULL; 1717135446Strhodes dns_message_currentname(rcvmsg, section, &name); 1718135446Strhodes soaset = NULL; 1719135446Strhodes result = dns_message_findtype(name, dns_rdatatype_soa, 0, 1720135446Strhodes &soaset); 1721135446Strhodes if (result == ISC_R_SUCCESS) 1722135446Strhodes break; 1723135446Strhodes if (section == DNS_SECTION_ANSWER) { 1724135446Strhodes dns_rdataset_t *tset = NULL; 1725135446Strhodes if (dns_message_findtype(name, dns_rdatatype_cname, 0, 1726135446Strhodes &tset) == ISC_R_SUCCESS 1727135446Strhodes || 1728135446Strhodes dns_message_findtype(name, dns_rdatatype_dname, 0, 1729135446Strhodes &tset) == ISC_R_SUCCESS 1730135446Strhodes ) 1731135446Strhodes { 1732135446Strhodes seencname = ISC_TRUE; 1733135446Strhodes break; 1734135446Strhodes } 1735135446Strhodes } 1736135446Strhodes 1737135446Strhodes result = dns_message_nextname(rcvmsg, section); 1738135446Strhodes } 1739135446Strhodes 1740135446Strhodes if (soaset == NULL && !seencname) { 1741135446Strhodes pass++; 1742135446Strhodes goto lookforsoa; 1743135446Strhodes } 1744135446Strhodes 1745135446Strhodes if (seencname) { 1746135446Strhodes dns_name_t tname; 1747135446Strhodes unsigned int nlabels; 1748135446Strhodes 1749135446Strhodes result = dns_message_firstname(soaquery, DNS_SECTION_QUESTION); 1750135446Strhodes INSIST(result == ISC_R_SUCCESS); 1751135446Strhodes name = NULL; 1752135446Strhodes dns_message_currentname(soaquery, DNS_SECTION_QUESTION, &name); 1753135446Strhodes nlabels = dns_name_countlabels(name); 1754135446Strhodes if (nlabels == 1) 1755135446Strhodes fatal("could not find enclosing zone"); 1756135446Strhodes dns_name_init(&tname, NULL); 1757135446Strhodes dns_name_getlabelsequence(name, 1, nlabels - 1, &tname); 1758135446Strhodes dns_name_clone(&tname, name); 1759135446Strhodes dns_request_destroy(&request); 1760135446Strhodes dns_message_renderreset(soaquery); 1761135446Strhodes if (userserver != NULL) 1762135446Strhodes sendrequest(localaddr, userserver, soaquery, &request); 1763135446Strhodes else 1764135446Strhodes sendrequest(localaddr, &servers[ns_inuse], soaquery, 1765135446Strhodes &request); 1766135446Strhodes goto out; 1767135446Strhodes } 1768135446Strhodes 1769135446Strhodes if (debugging) { 1770135446Strhodes char namestr[DNS_NAME_FORMATSIZE]; 1771135446Strhodes dns_name_format(name, namestr, sizeof(namestr)); 1772135446Strhodes fprintf(stderr, "Found zone name: %s\n", namestr); 1773135446Strhodes } 1774135446Strhodes 1775135446Strhodes result = dns_rdataset_first(soaset); 1776135446Strhodes check_result(result, "dns_rdataset_first"); 1777135446Strhodes 1778135446Strhodes dns_rdata_init(&soarr); 1779135446Strhodes dns_rdataset_current(soaset, &soarr); 1780135446Strhodes result = dns_rdata_tostruct(&soarr, &soa, NULL); 1781135446Strhodes check_result(result, "dns_rdata_tostruct"); 1782135446Strhodes 1783135446Strhodes dns_name_init(&master, NULL); 1784135446Strhodes dns_name_clone(&soa.origin, &master); 1785135446Strhodes 1786135446Strhodes if (userzone != NULL) 1787135446Strhodes zonename = userzone; 1788135446Strhodes else 1789135446Strhodes zonename = name; 1790135446Strhodes 1791135446Strhodes if (debugging) { 1792135446Strhodes char namestr[DNS_NAME_FORMATSIZE]; 1793135446Strhodes dns_name_format(&master, namestr, sizeof(namestr)); 1794135446Strhodes fprintf(stderr, "The master is: %s\n", namestr); 1795135446Strhodes } 1796135446Strhodes 1797135446Strhodes if (userserver != NULL) 1798135446Strhodes serveraddr = userserver; 1799135446Strhodes else { 1800135446Strhodes char serverstr[DNS_NAME_MAXTEXT+1]; 1801135446Strhodes isc_buffer_t buf; 1802135446Strhodes 1803135446Strhodes isc_buffer_init(&buf, serverstr, sizeof(serverstr)); 1804135446Strhodes result = dns_name_totext(&master, ISC_TRUE, &buf); 1805135446Strhodes check_result(result, "dns_name_totext"); 1806135446Strhodes serverstr[isc_buffer_usedlength(&buf)] = 0; 1807135446Strhodes get_address(serverstr, DNSDEFAULTPORT, &tempaddr); 1808135446Strhodes serveraddr = &tempaddr; 1809135446Strhodes } 1810135446Strhodes 1811135446Strhodes send_update(zonename, serveraddr, localaddr); 1812135446Strhodes 1813135446Strhodes dns_message_destroy(&soaquery); 1814135446Strhodes dns_request_destroy(&request); 1815135446Strhodes 1816135446Strhodes out: 1817135446Strhodes setzoneclass(dns_rdataclass_none); 1818135446Strhodes dns_rdata_freestruct(&soa); 1819135446Strhodes dns_message_destroy(&rcvmsg); 1820135446Strhodes ddebug("Out of recvsoa"); 1821135446Strhodes} 1822135446Strhodes 1823135446Strhodesstatic void 1824135446Strhodessendrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, 1825135446Strhodes dns_message_t *msg, dns_request_t **request) 1826135446Strhodes{ 1827135446Strhodes isc_result_t result; 1828135446Strhodes nsu_requestinfo_t *reqinfo; 1829135446Strhodes 1830135446Strhodes reqinfo = isc_mem_get(mctx, sizeof(nsu_requestinfo_t)); 1831135446Strhodes if (reqinfo == NULL) 1832135446Strhodes fatal("out of memory"); 1833135446Strhodes reqinfo->msg = msg; 1834135446Strhodes reqinfo->addr = destaddr; 1835135446Strhodes result = dns_request_createvia3(requestmgr, msg, srcaddr, destaddr, 0, 1836135446Strhodes (userserver != NULL) ? tsigkey : NULL, 1837135446Strhodes FIND_TIMEOUT * 20, FIND_TIMEOUT, 3, 1838135446Strhodes global_task, recvsoa, reqinfo, request); 1839135446Strhodes check_result(result, "dns_request_createvia"); 1840135446Strhodes requests++; 1841135446Strhodes} 1842135446Strhodes 1843135446Strhodesstatic void 1844135446Strhodesstart_update(void) { 1845135446Strhodes isc_result_t result; 1846135446Strhodes dns_rdataset_t *rdataset = NULL; 1847135446Strhodes dns_name_t *name = NULL; 1848135446Strhodes dns_request_t *request = NULL; 1849135446Strhodes dns_message_t *soaquery = NULL; 1850135446Strhodes dns_name_t *firstname; 1851135446Strhodes dns_section_t section = DNS_SECTION_UPDATE; 1852135446Strhodes 1853135446Strhodes ddebug("start_update()"); 1854135446Strhodes 1855135446Strhodes if (answer != NULL) 1856135446Strhodes dns_message_destroy(&answer); 1857135446Strhodes result = dns_message_firstname(updatemsg, section); 1858135446Strhodes if (result == ISC_R_NOMORE) { 1859135446Strhodes section = DNS_SECTION_PREREQUISITE; 1860135446Strhodes result = dns_message_firstname(updatemsg, section); 1861135446Strhodes } 1862135446Strhodes if (result != ISC_R_SUCCESS) { 1863135446Strhodes done_update(); 1864135446Strhodes return; 1865135446Strhodes } 1866135446Strhodes 1867135446Strhodes if (userzone != NULL && userserver != NULL) { 1868135446Strhodes send_update(userzone, userserver, localaddr); 1869135446Strhodes setzoneclass(dns_rdataclass_none); 1870135446Strhodes return; 1871135446Strhodes } 1872135446Strhodes 1873135446Strhodes result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, 1874135446Strhodes &soaquery); 1875135446Strhodes check_result(result, "dns_message_create"); 1876135446Strhodes 1877135446Strhodes soaquery->flags |= DNS_MESSAGEFLAG_RD; 1878135446Strhodes 1879135446Strhodes result = dns_message_gettempname(soaquery, &name); 1880135446Strhodes check_result(result, "dns_message_gettempname"); 1881135446Strhodes 1882135446Strhodes result = dns_message_gettemprdataset(soaquery, &rdataset); 1883135446Strhodes check_result(result, "dns_message_gettemprdataset"); 1884135446Strhodes 1885135446Strhodes dns_rdataset_makequestion(rdataset, getzoneclass(), dns_rdatatype_soa); 1886135446Strhodes 1887135446Strhodes firstname = NULL; 1888135446Strhodes dns_message_currentname(updatemsg, section, &firstname); 1889135446Strhodes dns_name_init(name, NULL); 1890135446Strhodes dns_name_clone(firstname, name); 1891135446Strhodes 1892135446Strhodes ISC_LIST_INIT(name->list); 1893135446Strhodes ISC_LIST_APPEND(name->list, rdataset, link); 1894135446Strhodes dns_message_addname(soaquery, name, DNS_SECTION_QUESTION); 1895135446Strhodes 1896135446Strhodes if (userserver != NULL) 1897135446Strhodes sendrequest(localaddr, userserver, soaquery, &request); 1898135446Strhodes else { 1899135446Strhodes ns_inuse = 0; 1900135446Strhodes sendrequest(localaddr, &servers[ns_inuse], soaquery, &request); 1901135446Strhodes } 1902135446Strhodes} 1903135446Strhodes 1904135446Strhodesstatic void 1905135446Strhodescleanup(void) { 1906135446Strhodes ddebug("cleanup()"); 1907135446Strhodes 1908135446Strhodes if (answer != NULL) 1909135446Strhodes dns_message_destroy(&answer); 1910135446Strhodes ddebug("Shutting down task manager"); 1911135446Strhodes isc_taskmgr_destroy(&taskmgr); 1912135446Strhodes 1913135446Strhodes ddebug("Destroying event"); 1914135446Strhodes isc_event_free(&global_event); 1915135446Strhodes 1916135446Strhodes ddebug("Shutting down socket manager"); 1917135446Strhodes isc_socketmgr_destroy(&socketmgr); 1918135446Strhodes 1919135446Strhodes ddebug("Shutting down timer manager"); 1920135446Strhodes isc_timermgr_destroy(&timermgr); 1921135446Strhodes 1922135446Strhodes ddebug("Destroying hash context"); 1923135446Strhodes isc_hash_destroy(); 1924135446Strhodes 1925135446Strhodes ddebug("Destroying memory context"); 1926135446Strhodes if (memdebugging) 1927135446Strhodes isc_mem_stats(mctx, stderr); 1928135446Strhodes isc_mem_destroy(&mctx); 1929135446Strhodes} 1930135446Strhodes 1931135446Strhodesstatic void 1932135446Strhodesgetinput(isc_task_t *task, isc_event_t *event) { 1933135446Strhodes isc_boolean_t more; 1934135446Strhodes 1935135446Strhodes UNUSED(task); 1936135446Strhodes 1937135446Strhodes if (shuttingdown) { 1938135446Strhodes maybeshutdown(); 1939135446Strhodes return; 1940135446Strhodes } 1941135446Strhodes 1942135446Strhodes if (global_event == NULL) 1943135446Strhodes global_event = event; 1944135446Strhodes 1945135446Strhodes reset_system(); 1946135446Strhodes more = user_interaction(); 1947135446Strhodes if (!more) { 1948135446Strhodes isc_app_shutdown(); 1949135446Strhodes return; 1950135446Strhodes } 1951135446Strhodes start_update(); 1952135446Strhodes return; 1953135446Strhodes} 1954135446Strhodes 1955135446Strhodesint 1956135446Strhodesmain(int argc, char **argv) { 1957135446Strhodes isc_result_t result; 1958135446Strhodes style = &dns_master_style_debug; 1959135446Strhodes 1960135446Strhodes input = stdin; 1961135446Strhodes 1962135446Strhodes interactive = ISC_TF(isatty(0)); 1963135446Strhodes 1964135446Strhodes isc_app_start(); 1965135446Strhodes 1966135446Strhodes parse_args(argc, argv); 1967135446Strhodes 1968135446Strhodes setup_system(); 1969135446Strhodes 1970135446Strhodes result = isc_app_onrun(mctx, global_task, getinput, NULL); 1971135446Strhodes check_result(result, "isc_app_onrun"); 1972135446Strhodes 1973135446Strhodes (void)isc_app_run(); 1974135446Strhodes 1975135446Strhodes cleanup(); 1976135446Strhodes 1977135446Strhodes isc_app_finish(); 1978135446Strhodes 1979135446Strhodes if (seenerror) 1980135446Strhodes return (2); 1981135446Strhodes else 1982135446Strhodes return (0); 1983135446Strhodes} 1984