nsupdate.c revision 222395
1135446Strhodes/* 2218384Sdougb * Copyright (C) 2004-2010 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 2000-2003 Internet Software Consortium. 4135446Strhodes * 5174187Sdougb * Permission to use, copy, modify, and/or 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 18218384Sdougb/* $Id: nsupdate.c,v 1.163.48.15 2010-12-09 04:30:57 tbox Exp $ */ 19135446Strhodes 20170222Sdougb/*! \file */ 21170222Sdougb 22135446Strhodes#include <config.h> 23135446Strhodes 24135446Strhodes#include <ctype.h> 25135446Strhodes#include <errno.h> 26135446Strhodes#include <limits.h> 27135446Strhodes#include <stdlib.h> 28135446Strhodes#include <unistd.h> 29135446Strhodes 30135446Strhodes#include <isc/app.h> 31135446Strhodes#include <isc/base64.h> 32135446Strhodes#include <isc/buffer.h> 33135446Strhodes#include <isc/commandline.h> 34135446Strhodes#include <isc/entropy.h> 35135446Strhodes#include <isc/event.h> 36135446Strhodes#include <isc/hash.h> 37135446Strhodes#include <isc/lex.h> 38193149Sdougb#include <isc/log.h> 39135446Strhodes#include <isc/mem.h> 40135446Strhodes#include <isc/parseint.h> 41218384Sdougb#include <isc/print.h> 42193149Sdougb#include <isc/random.h> 43135446Strhodes#include <isc/region.h> 44135446Strhodes#include <isc/sockaddr.h> 45135446Strhodes#include <isc/socket.h> 46135446Strhodes#include <isc/stdio.h> 47135446Strhodes#include <isc/string.h> 48135446Strhodes#include <isc/task.h> 49135446Strhodes#include <isc/timer.h> 50135446Strhodes#include <isc/types.h> 51135446Strhodes#include <isc/util.h> 52135446Strhodes 53135446Strhodes#include <dns/callbacks.h> 54135446Strhodes#include <dns/dispatch.h> 55135446Strhodes#include <dns/dnssec.h> 56135446Strhodes#include <dns/events.h> 57135446Strhodes#include <dns/fixedname.h> 58193149Sdougb#include <dns/log.h> 59135446Strhodes#include <dns/masterdump.h> 60135446Strhodes#include <dns/message.h> 61135446Strhodes#include <dns/name.h> 62135446Strhodes#include <dns/rcode.h> 63135446Strhodes#include <dns/rdata.h> 64135446Strhodes#include <dns/rdataclass.h> 65135446Strhodes#include <dns/rdatalist.h> 66135446Strhodes#include <dns/rdataset.h> 67135446Strhodes#include <dns/rdatastruct.h> 68135446Strhodes#include <dns/rdatatype.h> 69135446Strhodes#include <dns/request.h> 70135446Strhodes#include <dns/result.h> 71193149Sdougb#include <dns/tkey.h> 72135446Strhodes#include <dns/tsig.h> 73135446Strhodes 74135446Strhodes#include <dst/dst.h> 75135446Strhodes 76135446Strhodes#include <lwres/lwres.h> 77135446Strhodes#include <lwres/net.h> 78135446Strhodes 79193149Sdougb#ifdef GSSAPI 80193149Sdougb#include <dst/gssapi.h> 81193149Sdougb#endif 82135446Strhodes#include <bind9/getaddresses.h> 83135446Strhodes 84193149Sdougb 85135446Strhodes#ifdef HAVE_ADDRINFO 86135446Strhodes#ifdef HAVE_GETADDRINFO 87135446Strhodes#ifdef HAVE_GAISTRERROR 88135446Strhodes#define USE_GETADDRINFO 89135446Strhodes#endif 90135446Strhodes#endif 91135446Strhodes#endif 92135446Strhodes 93135446Strhodes#ifndef USE_GETADDRINFO 94135446Strhodes#ifndef ISC_PLATFORM_NONSTDHERRNO 95135446Strhodesextern int h_errno; 96135446Strhodes#endif 97135446Strhodes#endif 98135446Strhodes 99135446Strhodes#define MAXCMD (4 * 1024) 100135446Strhodes#define MAXWIRE (64 * 1024) 101135446Strhodes#define PACKETSIZE ((64 * 1024) - 1) 102135446Strhodes#define INITTEXT (2 * 1024) 103135446Strhodes#define MAXTEXT (128 * 1024) 104135446Strhodes#define FIND_TIMEOUT 5 105135446Strhodes#define TTL_MAX 2147483647U /* Maximum signed 32 bit integer. */ 106135446Strhodes 107135446Strhodes#define DNSDEFAULTPORT 53 108135446Strhodes 109135446Strhodes#ifndef RESOLV_CONF 110135446Strhodes#define RESOLV_CONF "/etc/resolv.conf" 111135446Strhodes#endif 112135446Strhodes 113135446Strhodesstatic isc_boolean_t debugging = ISC_FALSE, ddebugging = ISC_FALSE; 114135446Strhodesstatic isc_boolean_t memdebugging = ISC_FALSE; 115135446Strhodesstatic isc_boolean_t have_ipv4 = ISC_FALSE; 116135446Strhodesstatic isc_boolean_t have_ipv6 = ISC_FALSE; 117135446Strhodesstatic isc_boolean_t is_dst_up = ISC_FALSE; 118135446Strhodesstatic isc_boolean_t usevc = ISC_FALSE; 119193149Sdougbstatic isc_boolean_t usegsstsig = ISC_FALSE; 120193149Sdougbstatic isc_boolean_t use_win2k_gsstsig = ISC_FALSE; 121193149Sdougbstatic isc_boolean_t tried_other_gsstsig = ISC_FALSE; 122135446Strhodesstatic isc_taskmgr_t *taskmgr = NULL; 123135446Strhodesstatic isc_task_t *global_task = NULL; 124135446Strhodesstatic isc_event_t *global_event = NULL; 125193149Sdougbstatic isc_log_t *lctx = NULL; 126135446Strhodesstatic isc_mem_t *mctx = NULL; 127135446Strhodesstatic dns_dispatchmgr_t *dispatchmgr = NULL; 128135446Strhodesstatic dns_requestmgr_t *requestmgr = NULL; 129135446Strhodesstatic isc_socketmgr_t *socketmgr = NULL; 130135446Strhodesstatic isc_timermgr_t *timermgr = NULL; 131135446Strhodesstatic dns_dispatch_t *dispatchv4 = NULL; 132135446Strhodesstatic dns_dispatch_t *dispatchv6 = NULL; 133135446Strhodesstatic dns_message_t *updatemsg = NULL; 134135446Strhodesstatic dns_fixedname_t fuserzone; 135135446Strhodesstatic dns_name_t *userzone = NULL; 136193149Sdougbstatic dns_name_t *zonename = NULL; 137193149Sdougbstatic dns_name_t tmpzonename; 138193149Sdougbstatic dns_name_t restart_master; 139193149Sdougbstatic dns_tsig_keyring_t *gssring = NULL; 140135446Strhodesstatic dns_tsigkey_t *tsigkey = NULL; 141135446Strhodesstatic dst_key_t *sig0key; 142135446Strhodesstatic lwres_context_t *lwctx = NULL; 143135446Strhodesstatic lwres_conf_t *lwconf; 144135446Strhodesstatic isc_sockaddr_t *servers; 145135446Strhodesstatic int ns_inuse = 0; 146135446Strhodesstatic int ns_total = 0; 147135446Strhodesstatic isc_sockaddr_t *userserver = NULL; 148135446Strhodesstatic isc_sockaddr_t *localaddr = NULL; 149193149Sdougbstatic isc_sockaddr_t *serveraddr = NULL; 150193149Sdougbstatic isc_sockaddr_t tempaddr; 151135446Strhodesstatic char *keystr = NULL, *keyfile = NULL; 152193149Sdougbstatic isc_entropy_t *entropy = NULL; 153135446Strhodesstatic isc_boolean_t shuttingdown = ISC_FALSE; 154135446Strhodesstatic FILE *input; 155135446Strhodesstatic isc_boolean_t interactive = ISC_TRUE; 156135446Strhodesstatic isc_boolean_t seenerror = ISC_FALSE; 157135446Strhodesstatic const dns_master_style_t *style; 158135446Strhodesstatic int requests = 0; 159193149Sdougbstatic unsigned int logdebuglevel = 0; 160135446Strhodesstatic unsigned int timeout = 300; 161135446Strhodesstatic unsigned int udp_timeout = 3; 162135446Strhodesstatic unsigned int udp_retries = 3; 163135446Strhodesstatic dns_rdataclass_t defaultclass = dns_rdataclass_in; 164135446Strhodesstatic dns_rdataclass_t zoneclass = dns_rdataclass_none; 165135446Strhodesstatic dns_message_t *answer = NULL; 166193149Sdougbstatic isc_uint32_t default_ttl = 0; 167193149Sdougbstatic isc_boolean_t default_ttl_set = ISC_FALSE; 168135446Strhodes 169135446Strhodestypedef struct nsu_requestinfo { 170135446Strhodes dns_message_t *msg; 171135446Strhodes isc_sockaddr_t *addr; 172135446Strhodes} nsu_requestinfo_t; 173135446Strhodes 174135446Strhodesstatic void 175135446Strhodessendrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, 176135446Strhodes dns_message_t *msg, dns_request_t **request); 177135446Strhodesstatic void 178135446Strhodesfatal(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); 179135446Strhodes 180135446Strhodesstatic void 181135446Strhodesdebug(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); 182135446Strhodes 183135446Strhodesstatic void 184135446Strhodesddebug(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); 185135446Strhodes 186193149Sdougb#ifdef GSSAPI 187193149Sdougbstatic dns_fixedname_t fkname; 188193149Sdougbstatic isc_sockaddr_t *kserver = NULL; 189218384Sdougbstatic char *realm = NULL; 190193149Sdougbstatic char servicename[DNS_NAME_FORMATSIZE]; 191193149Sdougbstatic dns_name_t *keyname; 192193149Sdougbtypedef struct nsu_gssinfo { 193193149Sdougb dns_message_t *msg; 194193149Sdougb isc_sockaddr_t *addr; 195193149Sdougb gss_ctx_id_t context; 196193149Sdougb} nsu_gssinfo_t; 197193149Sdougb 198170222Sdougbstatic void 199193149Sdougbstart_gssrequest(dns_name_t *master); 200193149Sdougbstatic void 201193149Sdougbsend_gssrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, 202193149Sdougb dns_message_t *msg, dns_request_t **request, 203193149Sdougb gss_ctx_id_t context); 204193149Sdougbstatic void 205193149Sdougbrecvgss(isc_task_t *task, isc_event_t *event); 206193149Sdougb#endif /* GSSAPI */ 207193149Sdougb 208193149Sdougbstatic void 209170222Sdougberror(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); 210170222Sdougb 211135446Strhodes#define STATUS_MORE (isc_uint16_t)0 212135446Strhodes#define STATUS_SEND (isc_uint16_t)1 213135446Strhodes#define STATUS_QUIT (isc_uint16_t)2 214135446Strhodes#define STATUS_SYNTAX (isc_uint16_t)3 215135446Strhodes 216193149Sdougbtypedef struct entropysource entropysource_t; 217193149Sdougb 218193149Sdougbstruct entropysource { 219193149Sdougb isc_entropysource_t *source; 220193149Sdougb isc_mem_t *mctx; 221193149Sdougb ISC_LINK(entropysource_t) link; 222193149Sdougb}; 223193149Sdougb 224193149Sdougbstatic ISC_LIST(entropysource_t) sources; 225193149Sdougb 226193149Sdougbstatic void 227193149Sdougbsetup_entropy(isc_mem_t *mctx, const char *randomfile, isc_entropy_t **ectx) 228193149Sdougb{ 229193149Sdougb isc_result_t result; 230193149Sdougb isc_entropysource_t *source = NULL; 231193149Sdougb entropysource_t *elt; 232193149Sdougb int usekeyboard = ISC_ENTROPY_KEYBOARDMAYBE; 233193149Sdougb 234193149Sdougb REQUIRE(ectx != NULL); 235193149Sdougb 236193149Sdougb if (*ectx == NULL) { 237193149Sdougb result = isc_entropy_create(mctx, ectx); 238193149Sdougb if (result != ISC_R_SUCCESS) 239193149Sdougb fatal("could not create entropy object"); 240193149Sdougb ISC_LIST_INIT(sources); 241193149Sdougb } 242193149Sdougb 243193149Sdougb if (randomfile != NULL && strcmp(randomfile, "keyboard") == 0) { 244193149Sdougb usekeyboard = ISC_ENTROPY_KEYBOARDYES; 245193149Sdougb randomfile = NULL; 246193149Sdougb } 247193149Sdougb 248193149Sdougb result = isc_entropy_usebestsource(*ectx, &source, randomfile, 249193149Sdougb usekeyboard); 250193149Sdougb 251193149Sdougb if (result != ISC_R_SUCCESS) 252193149Sdougb fatal("could not initialize entropy source: %s", 253193149Sdougb isc_result_totext(result)); 254193149Sdougb 255193149Sdougb if (source != NULL) { 256193149Sdougb elt = isc_mem_get(mctx, sizeof(*elt)); 257193149Sdougb if (elt == NULL) 258193149Sdougb fatal("out of memory"); 259193149Sdougb elt->source = source; 260193149Sdougb elt->mctx = mctx; 261193149Sdougb ISC_LINK_INIT(elt, link); 262193149Sdougb ISC_LIST_APPEND(sources, elt, link); 263193149Sdougb } 264193149Sdougb} 265193149Sdougb 266193149Sdougbstatic void 267193149Sdougbcleanup_entropy(isc_entropy_t **ectx) { 268193149Sdougb entropysource_t *source; 269193149Sdougb while (!ISC_LIST_EMPTY(sources)) { 270193149Sdougb source = ISC_LIST_HEAD(sources); 271193149Sdougb ISC_LIST_UNLINK(sources, source, link); 272193149Sdougb isc_entropy_destroysource(&source->source); 273193149Sdougb isc_mem_put(source->mctx, source, sizeof(*source)); 274193149Sdougb } 275193149Sdougb isc_entropy_detach(ectx); 276193149Sdougb} 277193149Sdougb 278193149Sdougb 279135446Strhodesstatic dns_rdataclass_t 280135446Strhodesgetzoneclass(void) { 281135446Strhodes if (zoneclass == dns_rdataclass_none) 282135446Strhodes zoneclass = defaultclass; 283135446Strhodes return (zoneclass); 284135446Strhodes} 285135446Strhodes 286135446Strhodesstatic isc_boolean_t 287135446Strhodessetzoneclass(dns_rdataclass_t rdclass) { 288135446Strhodes if (zoneclass == dns_rdataclass_none || 289135446Strhodes rdclass == dns_rdataclass_none) 290135446Strhodes zoneclass = rdclass; 291135446Strhodes if (zoneclass != rdclass) 292135446Strhodes return (ISC_FALSE); 293135446Strhodes return (ISC_TRUE); 294135446Strhodes} 295135446Strhodes 296135446Strhodesstatic void 297135446Strhodesfatal(const char *format, ...) { 298135446Strhodes va_list args; 299135446Strhodes 300135446Strhodes va_start(args, format); 301135446Strhodes vfprintf(stderr, format, args); 302135446Strhodes va_end(args); 303135446Strhodes fprintf(stderr, "\n"); 304135446Strhodes exit(1); 305135446Strhodes} 306135446Strhodes 307135446Strhodesstatic void 308170222Sdougberror(const char *format, ...) { 309170222Sdougb va_list args; 310170222Sdougb 311170222Sdougb va_start(args, format); 312170222Sdougb vfprintf(stderr, format, args); 313170222Sdougb va_end(args); 314170222Sdougb fprintf(stderr, "\n"); 315170222Sdougb} 316170222Sdougb 317170222Sdougbstatic void 318135446Strhodesdebug(const char *format, ...) { 319135446Strhodes va_list args; 320135446Strhodes 321135446Strhodes if (debugging) { 322135446Strhodes va_start(args, format); 323135446Strhodes vfprintf(stderr, format, args); 324135446Strhodes va_end(args); 325135446Strhodes fprintf(stderr, "\n"); 326135446Strhodes } 327135446Strhodes} 328135446Strhodes 329135446Strhodesstatic void 330135446Strhodesddebug(const char *format, ...) { 331135446Strhodes va_list args; 332135446Strhodes 333135446Strhodes if (ddebugging) { 334135446Strhodes va_start(args, format); 335135446Strhodes vfprintf(stderr, format, args); 336135446Strhodes va_end(args); 337135446Strhodes fprintf(stderr, "\n"); 338135446Strhodes } 339135446Strhodes} 340135446Strhodes 341135446Strhodesstatic inline void 342135446Strhodescheck_result(isc_result_t result, const char *msg) { 343135446Strhodes if (result != ISC_R_SUCCESS) 344135446Strhodes fatal("%s: %s", msg, isc_result_totext(result)); 345135446Strhodes} 346135446Strhodes 347135446Strhodesstatic void * 348135446Strhodesmem_alloc(void *arg, size_t size) { 349135446Strhodes return (isc_mem_get(arg, size)); 350135446Strhodes} 351135446Strhodes 352135446Strhodesstatic void 353135446Strhodesmem_free(void *arg, void *mem, size_t size) { 354135446Strhodes isc_mem_put(arg, mem, size); 355135446Strhodes} 356135446Strhodes 357135446Strhodesstatic char * 358135446Strhodesnsu_strsep(char **stringp, const char *delim) { 359135446Strhodes char *string = *stringp; 360135446Strhodes char *s; 361135446Strhodes const char *d; 362135446Strhodes char sc, dc; 363135446Strhodes 364135446Strhodes if (string == NULL) 365135446Strhodes return (NULL); 366135446Strhodes 367135446Strhodes for (; *string != '\0'; string++) { 368135446Strhodes sc = *string; 369135446Strhodes for (d = delim; (dc = *d) != '\0'; d++) { 370135446Strhodes if (sc == dc) 371135446Strhodes break; 372135446Strhodes } 373135446Strhodes if (dc == 0) 374135446Strhodes break; 375135446Strhodes } 376135446Strhodes 377135446Strhodes for (s = string; *s != '\0'; s++) { 378135446Strhodes sc = *s; 379135446Strhodes for (d = delim; (dc = *d) != '\0'; d++) { 380135446Strhodes if (sc == dc) { 381135446Strhodes *s++ = '\0'; 382135446Strhodes *stringp = s; 383135446Strhodes return (string); 384135446Strhodes } 385135446Strhodes } 386135446Strhodes } 387135446Strhodes *stringp = NULL; 388135446Strhodes return (string); 389135446Strhodes} 390135446Strhodes 391135446Strhodesstatic void 392135446Strhodesreset_system(void) { 393135446Strhodes isc_result_t result; 394135446Strhodes 395135446Strhodes ddebug("reset_system()"); 396135446Strhodes /* If the update message is still around, destroy it */ 397135446Strhodes if (updatemsg != NULL) 398135446Strhodes dns_message_reset(updatemsg, DNS_MESSAGE_INTENTRENDER); 399135446Strhodes else { 400135446Strhodes result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, 401135446Strhodes &updatemsg); 402135446Strhodes check_result(result, "dns_message_create"); 403135446Strhodes } 404135446Strhodes updatemsg->opcode = dns_opcode_update; 405193149Sdougb if (usegsstsig) { 406193149Sdougb if (tsigkey != NULL) 407193149Sdougb dns_tsigkey_detach(&tsigkey); 408193149Sdougb if (gssring != NULL) 409193149Sdougb dns_tsigkeyring_destroy(&gssring); 410193149Sdougb tried_other_gsstsig = ISC_FALSE; 411193149Sdougb } 412135446Strhodes} 413135446Strhodes 414170222Sdougbstatic isc_uint16_t 415170222Sdougbparse_hmac(dns_name_t **hmac, const char *hmacstr, size_t len) { 416170222Sdougb isc_uint16_t digestbits = 0; 417170222Sdougb isc_result_t result; 418170222Sdougb char buf[20]; 419170222Sdougb 420170222Sdougb REQUIRE(hmac != NULL && *hmac == NULL); 421170222Sdougb REQUIRE(hmacstr != NULL); 422170222Sdougb 423170222Sdougb if (len >= sizeof(buf)) 424170222Sdougb fatal("unknown key type '%.*s'", (int)(len), hmacstr); 425170222Sdougb 426170222Sdougb strncpy(buf, hmacstr, len); 427170222Sdougb buf[len] = 0; 428186462Sdougb 429170222Sdougb if (strcasecmp(buf, "hmac-md5") == 0) { 430170222Sdougb *hmac = DNS_TSIG_HMACMD5_NAME; 431170222Sdougb } else if (strncasecmp(buf, "hmac-md5-", 9) == 0) { 432170222Sdougb *hmac = DNS_TSIG_HMACMD5_NAME; 433170222Sdougb result = isc_parse_uint16(&digestbits, &buf[9], 10); 434170222Sdougb if (result != ISC_R_SUCCESS || digestbits > 128) 435170222Sdougb fatal("digest-bits out of range [0..128]"); 436170222Sdougb digestbits = (digestbits +7) & ~0x7U; 437170222Sdougb } else if (strcasecmp(buf, "hmac-sha1") == 0) { 438170222Sdougb *hmac = DNS_TSIG_HMACSHA1_NAME; 439170222Sdougb } else if (strncasecmp(buf, "hmac-sha1-", 10) == 0) { 440170222Sdougb *hmac = DNS_TSIG_HMACSHA1_NAME; 441170222Sdougb result = isc_parse_uint16(&digestbits, &buf[10], 10); 442170222Sdougb if (result != ISC_R_SUCCESS || digestbits > 160) 443170222Sdougb fatal("digest-bits out of range [0..160]"); 444170222Sdougb digestbits = (digestbits +7) & ~0x7U; 445170222Sdougb } else if (strcasecmp(buf, "hmac-sha224") == 0) { 446170222Sdougb *hmac = DNS_TSIG_HMACSHA224_NAME; 447170222Sdougb } else if (strncasecmp(buf, "hmac-sha224-", 12) == 0) { 448170222Sdougb *hmac = DNS_TSIG_HMACSHA224_NAME; 449170222Sdougb result = isc_parse_uint16(&digestbits, &buf[12], 10); 450170222Sdougb if (result != ISC_R_SUCCESS || digestbits > 224) 451170222Sdougb fatal("digest-bits out of range [0..224]"); 452170222Sdougb digestbits = (digestbits +7) & ~0x7U; 453170222Sdougb } else if (strcasecmp(buf, "hmac-sha256") == 0) { 454170222Sdougb *hmac = DNS_TSIG_HMACSHA256_NAME; 455170222Sdougb } else if (strncasecmp(buf, "hmac-sha256-", 12) == 0) { 456170222Sdougb *hmac = DNS_TSIG_HMACSHA256_NAME; 457170222Sdougb result = isc_parse_uint16(&digestbits, &buf[12], 10); 458170222Sdougb if (result != ISC_R_SUCCESS || digestbits > 256) 459170222Sdougb fatal("digest-bits out of range [0..256]"); 460170222Sdougb digestbits = (digestbits +7) & ~0x7U; 461170222Sdougb } else if (strcasecmp(buf, "hmac-sha384") == 0) { 462170222Sdougb *hmac = DNS_TSIG_HMACSHA384_NAME; 463170222Sdougb } else if (strncasecmp(buf, "hmac-sha384-", 12) == 0) { 464170222Sdougb *hmac = DNS_TSIG_HMACSHA384_NAME; 465170222Sdougb result = isc_parse_uint16(&digestbits, &buf[12], 10); 466170222Sdougb if (result != ISC_R_SUCCESS || digestbits > 384) 467170222Sdougb fatal("digest-bits out of range [0..384]"); 468170222Sdougb digestbits = (digestbits +7) & ~0x7U; 469170222Sdougb } else if (strcasecmp(buf, "hmac-sha512") == 0) { 470170222Sdougb *hmac = DNS_TSIG_HMACSHA512_NAME; 471170222Sdougb } else if (strncasecmp(buf, "hmac-sha512-", 12) == 0) { 472170222Sdougb *hmac = DNS_TSIG_HMACSHA512_NAME; 473170222Sdougb result = isc_parse_uint16(&digestbits, &buf[12], 10); 474170222Sdougb if (result != ISC_R_SUCCESS || digestbits > 512) 475170222Sdougb fatal("digest-bits out of range [0..512]"); 476170222Sdougb digestbits = (digestbits +7) & ~0x7U; 477170222Sdougb } else 478170222Sdougb fatal("unknown key type '%s'", buf); 479170222Sdougb return (digestbits); 480170222Sdougb} 481170222Sdougb 482135446Strhodesstatic void 483135446Strhodessetup_keystr(void) { 484135446Strhodes unsigned char *secret = NULL; 485135446Strhodes int secretlen; 486135446Strhodes isc_buffer_t secretbuf; 487135446Strhodes isc_result_t result; 488135446Strhodes isc_buffer_t keynamesrc; 489135446Strhodes char *secretstr; 490170222Sdougb char *s, *n; 491135446Strhodes dns_fixedname_t fkeyname; 492135446Strhodes dns_name_t *keyname; 493170222Sdougb char *name; 494170222Sdougb dns_name_t *hmacname = NULL; 495170222Sdougb isc_uint16_t digestbits = 0; 496135446Strhodes 497135446Strhodes dns_fixedname_init(&fkeyname); 498135446Strhodes keyname = dns_fixedname_name(&fkeyname); 499135446Strhodes 500135446Strhodes debug("Creating key..."); 501135446Strhodes 502135446Strhodes s = strchr(keystr, ':'); 503170222Sdougb if (s == NULL || s == keystr || s[1] == 0) 504170222Sdougb fatal("key option must specify [hmac:]keyname:secret"); 505135446Strhodes secretstr = s + 1; 506170222Sdougb n = strchr(secretstr, ':'); 507170222Sdougb if (n != NULL) { 508170222Sdougb if (n == secretstr || n[1] == 0) 509170222Sdougb fatal("key option must specify [hmac:]keyname:secret"); 510170222Sdougb name = secretstr; 511170222Sdougb secretstr = n + 1; 512170222Sdougb digestbits = parse_hmac(&hmacname, keystr, s - keystr); 513170222Sdougb } else { 514170222Sdougb hmacname = DNS_TSIG_HMACMD5_NAME; 515170222Sdougb name = keystr; 516170222Sdougb n = s; 517170222Sdougb } 518135446Strhodes 519170222Sdougb isc_buffer_init(&keynamesrc, name, n - name); 520170222Sdougb isc_buffer_add(&keynamesrc, n - name); 521135446Strhodes 522135446Strhodes debug("namefromtext"); 523135446Strhodes result = dns_name_fromtext(keyname, &keynamesrc, dns_rootname, 524135446Strhodes ISC_FALSE, NULL); 525135446Strhodes check_result(result, "dns_name_fromtext"); 526135446Strhodes 527135446Strhodes secretlen = strlen(secretstr) * 3 / 4; 528135446Strhodes secret = isc_mem_allocate(mctx, secretlen); 529135446Strhodes if (secret == NULL) 530135446Strhodes fatal("out of memory"); 531135446Strhodes 532135446Strhodes isc_buffer_init(&secretbuf, secret, secretlen); 533135446Strhodes result = isc_base64_decodestring(secretstr, &secretbuf); 534135446Strhodes if (result != ISC_R_SUCCESS) { 535135446Strhodes fprintf(stderr, "could not create key from %s: %s\n", 536135446Strhodes keystr, isc_result_totext(result)); 537135446Strhodes goto failure; 538135446Strhodes } 539135446Strhodes 540135446Strhodes secretlen = isc_buffer_usedlength(&secretbuf); 541135446Strhodes 542135446Strhodes debug("keycreate"); 543170222Sdougb result = dns_tsigkey_create(keyname, hmacname, secret, secretlen, 544218384Sdougb ISC_FALSE, NULL, 0, 0, mctx, NULL, 545218384Sdougb &tsigkey); 546135446Strhodes if (result != ISC_R_SUCCESS) 547135446Strhodes fprintf(stderr, "could not create key from %s: %s\n", 548135446Strhodes keystr, dns_result_totext(result)); 549170222Sdougb else 550170222Sdougb dst_key_setbits(tsigkey->key, digestbits); 551135446Strhodes failure: 552135446Strhodes if (secret != NULL) 553135446Strhodes isc_mem_free(mctx, secret); 554135446Strhodes} 555135446Strhodes 556218384Sdougbstatic int 557218384Sdougbbasenamelen(const char *file) { 558218384Sdougb int len = strlen(file); 559218384Sdougb 560218384Sdougb if (len > 1 && file[len - 1] == '.') 561218384Sdougb len -= 1; 562218384Sdougb else if (len > 8 && strcmp(file + len - 8, ".private") == 0) 563218384Sdougb len -= 8; 564218384Sdougb else if (len > 4 && strcmp(file + len - 4, ".key") == 0) 565218384Sdougb len -= 4; 566218384Sdougb return (len); 567218384Sdougb} 568218384Sdougb 569135446Strhodesstatic void 570135446Strhodessetup_keyfile(void) { 571135446Strhodes dst_key_t *dstkey = NULL; 572135446Strhodes isc_result_t result; 573170222Sdougb dns_name_t *hmacname = NULL; 574135446Strhodes 575135446Strhodes debug("Creating key..."); 576135446Strhodes 577218384Sdougb if (sig0key != NULL) 578218384Sdougb dst_key_free(&sig0key); 579218384Sdougb 580135446Strhodes result = dst_key_fromnamedfile(keyfile, 581135446Strhodes DST_TYPE_PRIVATE | DST_TYPE_KEY, mctx, 582135446Strhodes &dstkey); 583135446Strhodes if (result != ISC_R_SUCCESS) { 584218384Sdougb fprintf(stderr, "could not read key from %.*s.{private,key}: " 585218384Sdougb "%s\n", basenamelen(keyfile), keyfile, 586218384Sdougb isc_result_totext(result)); 587135446Strhodes return; 588135446Strhodes } 589170222Sdougb switch (dst_key_alg(dstkey)) { 590170222Sdougb case DST_ALG_HMACMD5: 591170222Sdougb hmacname = DNS_TSIG_HMACMD5_NAME; 592170222Sdougb break; 593170222Sdougb case DST_ALG_HMACSHA1: 594170222Sdougb hmacname = DNS_TSIG_HMACSHA1_NAME; 595170222Sdougb break; 596170222Sdougb case DST_ALG_HMACSHA224: 597170222Sdougb hmacname = DNS_TSIG_HMACSHA224_NAME; 598170222Sdougb break; 599170222Sdougb case DST_ALG_HMACSHA256: 600170222Sdougb hmacname = DNS_TSIG_HMACSHA256_NAME; 601170222Sdougb break; 602170222Sdougb case DST_ALG_HMACSHA384: 603170222Sdougb hmacname = DNS_TSIG_HMACSHA384_NAME; 604170222Sdougb break; 605170222Sdougb case DST_ALG_HMACSHA512: 606170222Sdougb hmacname = DNS_TSIG_HMACSHA512_NAME; 607170222Sdougb break; 608170222Sdougb } 609170222Sdougb if (hmacname != NULL) { 610135446Strhodes result = dns_tsigkey_createfromkey(dst_key_name(dstkey), 611170222Sdougb hmacname, dstkey, ISC_FALSE, 612170222Sdougb NULL, 0, 0, mctx, NULL, 613170222Sdougb &tsigkey); 614218384Sdougb dst_key_free(&dstkey); 615135446Strhodes if (result != ISC_R_SUCCESS) { 616135446Strhodes fprintf(stderr, "could not create key from %s: %s\n", 617135446Strhodes keyfile, isc_result_totext(result)); 618135446Strhodes return; 619135446Strhodes } 620222395Sdougb } else { 621218384Sdougb dst_key_attach(dstkey, &sig0key); 622222395Sdougb dst_key_free(&dstkey); 623222395Sdougb } 624135446Strhodes} 625135446Strhodes 626135446Strhodesstatic void 627135446Strhodesdoshutdown(void) { 628135446Strhodes isc_task_detach(&global_task); 629135446Strhodes 630135446Strhodes if (userserver != NULL) 631135446Strhodes isc_mem_put(mctx, userserver, sizeof(isc_sockaddr_t)); 632135446Strhodes 633135446Strhodes if (localaddr != NULL) 634135446Strhodes isc_mem_put(mctx, localaddr, sizeof(isc_sockaddr_t)); 635135446Strhodes 636135446Strhodes if (tsigkey != NULL) { 637135446Strhodes ddebug("Freeing TSIG key"); 638135446Strhodes dns_tsigkey_detach(&tsigkey); 639135446Strhodes } 640135446Strhodes 641135446Strhodes if (sig0key != NULL) { 642135446Strhodes ddebug("Freeing SIG(0) key"); 643135446Strhodes dst_key_free(&sig0key); 644135446Strhodes } 645135446Strhodes 646135446Strhodes if (updatemsg != NULL) 647135446Strhodes dns_message_destroy(&updatemsg); 648135446Strhodes 649135446Strhodes if (is_dst_up) { 650135446Strhodes ddebug("Destroy DST lib"); 651135446Strhodes dst_lib_destroy(); 652135446Strhodes is_dst_up = ISC_FALSE; 653135446Strhodes } 654135446Strhodes 655193149Sdougb cleanup_entropy(&entropy); 656135446Strhodes 657135446Strhodes lwres_conf_clear(lwctx); 658135446Strhodes lwres_context_destroy(&lwctx); 659135446Strhodes 660135446Strhodes isc_mem_put(mctx, servers, ns_total * sizeof(isc_sockaddr_t)); 661135446Strhodes 662135446Strhodes ddebug("Destroying request manager"); 663135446Strhodes dns_requestmgr_detach(&requestmgr); 664135446Strhodes 665135446Strhodes ddebug("Freeing the dispatchers"); 666135446Strhodes if (have_ipv4) 667135446Strhodes dns_dispatch_detach(&dispatchv4); 668135446Strhodes if (have_ipv6) 669135446Strhodes dns_dispatch_detach(&dispatchv6); 670135446Strhodes 671135446Strhodes ddebug("Shutting down dispatch manager"); 672135446Strhodes dns_dispatchmgr_destroy(&dispatchmgr); 673135446Strhodes 674135446Strhodes} 675135446Strhodes 676135446Strhodesstatic void 677135446Strhodesmaybeshutdown(void) { 678135446Strhodes ddebug("Shutting down request manager"); 679135446Strhodes dns_requestmgr_shutdown(requestmgr); 680135446Strhodes 681135446Strhodes if (requests != 0) 682135446Strhodes return; 683135446Strhodes 684135446Strhodes doshutdown(); 685135446Strhodes} 686135446Strhodes 687135446Strhodesstatic void 688135446Strhodesshutdown_program(isc_task_t *task, isc_event_t *event) { 689135446Strhodes REQUIRE(task == global_task); 690135446Strhodes UNUSED(task); 691135446Strhodes 692135446Strhodes ddebug("shutdown_program()"); 693135446Strhodes isc_event_free(&event); 694135446Strhodes 695135446Strhodes shuttingdown = ISC_TRUE; 696135446Strhodes maybeshutdown(); 697135446Strhodes} 698135446Strhodes 699135446Strhodesstatic void 700135446Strhodessetup_system(void) { 701135446Strhodes isc_result_t result; 702135446Strhodes isc_sockaddr_t bind_any, bind_any6; 703135446Strhodes lwres_result_t lwresult; 704135446Strhodes unsigned int attrs, attrmask; 705135446Strhodes int i; 706193149Sdougb isc_logconfig_t *logconfig = NULL; 707135446Strhodes 708135446Strhodes ddebug("setup_system()"); 709135446Strhodes 710135446Strhodes dns_result_register(); 711135446Strhodes 712135446Strhodes result = isc_net_probeipv4(); 713135446Strhodes if (result == ISC_R_SUCCESS) 714135446Strhodes have_ipv4 = ISC_TRUE; 715135446Strhodes 716135446Strhodes result = isc_net_probeipv6(); 717135446Strhodes if (result == ISC_R_SUCCESS) 718135446Strhodes have_ipv6 = ISC_TRUE; 719135446Strhodes 720135446Strhodes if (!have_ipv4 && !have_ipv6) 721135446Strhodes fatal("could not find either IPv4 or IPv6"); 722135446Strhodes 723193149Sdougb result = isc_log_create(mctx, &lctx, &logconfig); 724193149Sdougb check_result(result, "isc_log_create"); 725135446Strhodes 726193149Sdougb isc_log_setcontext(lctx); 727193149Sdougb dns_log_init(lctx); 728193149Sdougb dns_log_setcontext(lctx); 729193149Sdougb 730193149Sdougb result = isc_log_usechannel(logconfig, "default_debug", NULL, NULL); 731193149Sdougb check_result(result, "isc_log_usechannel"); 732193149Sdougb 733193149Sdougb isc_log_setdebuglevel(lctx, logdebuglevel); 734193149Sdougb 735135446Strhodes lwresult = lwres_context_create(&lwctx, mctx, mem_alloc, mem_free, 1); 736135446Strhodes if (lwresult != LWRES_R_SUCCESS) 737135446Strhodes fatal("lwres_context_create failed"); 738135446Strhodes 739135446Strhodes (void)lwres_conf_parse(lwctx, RESOLV_CONF); 740135446Strhodes lwconf = lwres_conf_get(lwctx); 741135446Strhodes 742135446Strhodes ns_total = lwconf->nsnext; 743135446Strhodes if (ns_total <= 0) { 744135446Strhodes /* No name servers in resolv.conf; default to loopback. */ 745135446Strhodes struct in_addr localhost; 746135446Strhodes ns_total = 1; 747135446Strhodes servers = isc_mem_get(mctx, ns_total * sizeof(isc_sockaddr_t)); 748135446Strhodes if (servers == NULL) 749135446Strhodes fatal("out of memory"); 750135446Strhodes localhost.s_addr = htonl(INADDR_LOOPBACK); 751135446Strhodes isc_sockaddr_fromin(&servers[0], &localhost, DNSDEFAULTPORT); 752135446Strhodes } else { 753135446Strhodes servers = isc_mem_get(mctx, ns_total * sizeof(isc_sockaddr_t)); 754135446Strhodes if (servers == NULL) 755135446Strhodes fatal("out of memory"); 756135446Strhodes for (i = 0; i < ns_total; i++) { 757135446Strhodes if (lwconf->nameservers[i].family == LWRES_ADDRTYPE_V4) { 758135446Strhodes struct in_addr in4; 759135446Strhodes memcpy(&in4, lwconf->nameservers[i].address, 4); 760135446Strhodes isc_sockaddr_fromin(&servers[i], &in4, DNSDEFAULTPORT); 761135446Strhodes } else { 762135446Strhodes struct in6_addr in6; 763135446Strhodes memcpy(&in6, lwconf->nameservers[i].address, 16); 764135446Strhodes isc_sockaddr_fromin6(&servers[i], &in6, 765135446Strhodes DNSDEFAULTPORT); 766135446Strhodes } 767135446Strhodes } 768135446Strhodes } 769135446Strhodes 770193149Sdougb setup_entropy(mctx, NULL, &entropy); 771135446Strhodes 772193149Sdougb result = isc_hash_create(mctx, entropy, DNS_NAME_MAXWIRE); 773135446Strhodes check_result(result, "isc_hash_create"); 774135446Strhodes isc_hash_init(); 775135446Strhodes 776193149Sdougb result = dns_dispatchmgr_create(mctx, entropy, &dispatchmgr); 777135446Strhodes check_result(result, "dns_dispatchmgr_create"); 778135446Strhodes 779135446Strhodes result = isc_socketmgr_create(mctx, &socketmgr); 780135446Strhodes check_result(result, "dns_socketmgr_create"); 781135446Strhodes 782135446Strhodes result = isc_timermgr_create(mctx, &timermgr); 783135446Strhodes check_result(result, "dns_timermgr_create"); 784135446Strhodes 785135446Strhodes result = isc_taskmgr_create(mctx, 1, 0, &taskmgr); 786135446Strhodes check_result(result, "isc_taskmgr_create"); 787135446Strhodes 788135446Strhodes result = isc_task_create(taskmgr, 0, &global_task); 789135446Strhodes check_result(result, "isc_task_create"); 790135446Strhodes 791135446Strhodes result = isc_task_onshutdown(global_task, shutdown_program, NULL); 792135446Strhodes check_result(result, "isc_task_onshutdown"); 793135446Strhodes 794193149Sdougb result = dst_lib_init(mctx, entropy, 0); 795135446Strhodes check_result(result, "dst_lib_init"); 796135446Strhodes is_dst_up = ISC_TRUE; 797135446Strhodes 798135446Strhodes attrmask = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP; 799135446Strhodes attrmask |= DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6; 800135446Strhodes 801135446Strhodes if (have_ipv6) { 802135446Strhodes attrs = DNS_DISPATCHATTR_UDP; 803135446Strhodes attrs |= DNS_DISPATCHATTR_MAKEQUERY; 804135446Strhodes attrs |= DNS_DISPATCHATTR_IPV6; 805135446Strhodes isc_sockaddr_any6(&bind_any6); 806135446Strhodes result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, 807135446Strhodes &bind_any6, PACKETSIZE, 808135446Strhodes 4, 2, 3, 5, 809135446Strhodes attrs, attrmask, &dispatchv6); 810135446Strhodes check_result(result, "dns_dispatch_getudp (v6)"); 811135446Strhodes } 812135446Strhodes 813135446Strhodes if (have_ipv4) { 814135446Strhodes attrs = DNS_DISPATCHATTR_UDP; 815135446Strhodes attrs |= DNS_DISPATCHATTR_MAKEQUERY; 816135446Strhodes attrs |= DNS_DISPATCHATTR_IPV4; 817135446Strhodes isc_sockaddr_any(&bind_any); 818135446Strhodes result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, 819135446Strhodes &bind_any, PACKETSIZE, 820135446Strhodes 4, 2, 3, 5, 821135446Strhodes attrs, attrmask, &dispatchv4); 822135446Strhodes check_result(result, "dns_dispatch_getudp (v4)"); 823135446Strhodes } 824135446Strhodes 825135446Strhodes result = dns_requestmgr_create(mctx, timermgr, 826135446Strhodes socketmgr, taskmgr, dispatchmgr, 827135446Strhodes dispatchv4, dispatchv6, &requestmgr); 828135446Strhodes check_result(result, "dns_requestmgr_create"); 829135446Strhodes 830135446Strhodes if (keystr != NULL) 831135446Strhodes setup_keystr(); 832135446Strhodes else if (keyfile != NULL) 833135446Strhodes setup_keyfile(); 834135446Strhodes} 835135446Strhodes 836135446Strhodesstatic void 837135446Strhodesget_address(char *host, in_port_t port, isc_sockaddr_t *sockaddr) { 838135446Strhodes int count; 839135446Strhodes isc_result_t result; 840135446Strhodes 841135446Strhodes isc_app_block(); 842135446Strhodes result = bind9_getaddresses(host, port, sockaddr, 1, &count); 843135446Strhodes isc_app_unblock(); 844135446Strhodes if (result != ISC_R_SUCCESS) 845135446Strhodes fatal("couldn't get address for '%s': %s", 846135446Strhodes host, isc_result_totext(result)); 847135446Strhodes INSIST(count == 1); 848135446Strhodes} 849135446Strhodes 850193149Sdougb#define PARSE_ARGS_FMT "dDMl:y:govk:rR::t:u:" 851193149Sdougb 852135446Strhodesstatic void 853193149Sdougbpre_parse_args(int argc, char **argv) { 854135446Strhodes int ch; 855193149Sdougb 856193149Sdougb while ((ch = isc_commandline_parse(argc, argv, PARSE_ARGS_FMT)) != -1) { 857193149Sdougb switch (ch) { 858193149Sdougb case 'M': /* was -dm */ 859193149Sdougb debugging = ISC_TRUE; 860193149Sdougb ddebugging = ISC_TRUE; 861193149Sdougb memdebugging = ISC_TRUE; 862193149Sdougb isc_mem_debugging = ISC_MEM_DEBUGTRACE | 863193149Sdougb ISC_MEM_DEBUGRECORD; 864193149Sdougb break; 865193149Sdougb 866193149Sdougb case '?': 867193149Sdougb if (isc_commandline_option != '?') 868193149Sdougb fprintf(stderr, "%s: invalid argument -%c\n", 869193149Sdougb argv[0], isc_commandline_option); 870193149Sdougb fprintf(stderr, "usage: nsupdate [-d] " 871193149Sdougb "[-g | -o | -y keyname:secret | -k keyfile] " 872193149Sdougb "[-v] [filename]\n"); 873193149Sdougb exit(1); 874193149Sdougb 875193149Sdougb default: 876193149Sdougb break; 877193149Sdougb } 878193149Sdougb } 879193149Sdougb isc_commandline_reset = ISC_TRUE; 880193149Sdougb isc_commandline_index = 1; 881193149Sdougb} 882193149Sdougb 883193149Sdougbstatic void 884193149Sdougbparse_args(int argc, char **argv, isc_mem_t *mctx, isc_entropy_t **ectx) { 885193149Sdougb int ch; 886193149Sdougb isc_uint32_t i; 887135446Strhodes isc_result_t result; 888135446Strhodes 889135446Strhodes debug("parse_args"); 890193149Sdougb while ((ch = isc_commandline_parse(argc, argv, PARSE_ARGS_FMT)) != -1) { 891135446Strhodes switch (ch) { 892135446Strhodes case 'd': 893135446Strhodes debugging = ISC_TRUE; 894135446Strhodes break; 895135446Strhodes case 'D': /* was -dd */ 896135446Strhodes debugging = ISC_TRUE; 897135446Strhodes ddebugging = ISC_TRUE; 898135446Strhodes break; 899193149Sdougb case 'M': 900135446Strhodes break; 901193149Sdougb case 'l': 902193149Sdougb result = isc_parse_uint32(&i, isc_commandline_argument, 903193149Sdougb 10); 904193149Sdougb if (result != ISC_R_SUCCESS) { 905193149Sdougb fprintf(stderr, "bad library debug value " 906193149Sdougb "'%s'\n", isc_commandline_argument); 907193149Sdougb exit(1); 908193149Sdougb } 909193149Sdougb logdebuglevel = i; 910193149Sdougb break; 911135446Strhodes case 'y': 912135446Strhodes keystr = isc_commandline_argument; 913135446Strhodes break; 914135446Strhodes case 'v': 915135446Strhodes usevc = ISC_TRUE; 916135446Strhodes break; 917135446Strhodes case 'k': 918135446Strhodes keyfile = isc_commandline_argument; 919135446Strhodes break; 920193149Sdougb case 'g': 921193149Sdougb usegsstsig = ISC_TRUE; 922193149Sdougb use_win2k_gsstsig = ISC_FALSE; 923193149Sdougb break; 924193149Sdougb case 'o': 925193149Sdougb usegsstsig = ISC_TRUE; 926193149Sdougb use_win2k_gsstsig = ISC_TRUE; 927193149Sdougb break; 928135446Strhodes case 't': 929135446Strhodes result = isc_parse_uint32(&timeout, 930135446Strhodes isc_commandline_argument, 10); 931135446Strhodes if (result != ISC_R_SUCCESS) { 932135446Strhodes fprintf(stderr, "bad timeout '%s'\n", isc_commandline_argument); 933135446Strhodes exit(1); 934135446Strhodes } 935135446Strhodes if (timeout == 0) 936143731Sdougb timeout = UINT_MAX; 937135446Strhodes break; 938135446Strhodes case 'u': 939135446Strhodes result = isc_parse_uint32(&udp_timeout, 940135446Strhodes isc_commandline_argument, 10); 941135446Strhodes if (result != ISC_R_SUCCESS) { 942135446Strhodes fprintf(stderr, "bad udp timeout '%s'\n", isc_commandline_argument); 943135446Strhodes exit(1); 944135446Strhodes } 945135446Strhodes if (udp_timeout == 0) 946143731Sdougb udp_timeout = UINT_MAX; 947135446Strhodes break; 948135446Strhodes case 'r': 949135446Strhodes result = isc_parse_uint32(&udp_retries, 950135446Strhodes isc_commandline_argument, 10); 951135446Strhodes if (result != ISC_R_SUCCESS) { 952135446Strhodes fprintf(stderr, "bad udp retries '%s'\n", isc_commandline_argument); 953135446Strhodes exit(1); 954135446Strhodes } 955135446Strhodes break; 956193149Sdougb 957193149Sdougb case 'R': 958193149Sdougb setup_entropy(mctx, isc_commandline_argument, ectx); 959193149Sdougb break; 960193149Sdougb 961135446Strhodes default: 962193149Sdougb fprintf(stderr, "%s: unhandled option: %c\n", 963193149Sdougb argv[0], isc_commandline_option); 964135446Strhodes exit(1); 965135446Strhodes } 966135446Strhodes } 967135446Strhodes if (keyfile != NULL && keystr != NULL) { 968135446Strhodes fprintf(stderr, "%s: cannot specify both -k and -y\n", 969135446Strhodes argv[0]); 970135446Strhodes exit(1); 971135446Strhodes } 972135446Strhodes 973193149Sdougb#ifdef GSSAPI 974193149Sdougb if (usegsstsig && (keyfile != NULL || keystr != NULL)) { 975193149Sdougb fprintf(stderr, "%s: cannot specify -g with -k or -y\n", 976193149Sdougb argv[0]); 977193149Sdougb exit(1); 978193149Sdougb } 979193149Sdougb#else 980193149Sdougb if (usegsstsig) { 981193149Sdougb fprintf(stderr, "%s: cannot specify -g or -o, " \ 982193149Sdougb "program not linked with GSS API Library\n", 983193149Sdougb argv[0]); 984193149Sdougb exit(1); 985193149Sdougb } 986193149Sdougb#endif 987193149Sdougb 988135446Strhodes if (argv[isc_commandline_index] != NULL) { 989135446Strhodes if (strcmp(argv[isc_commandline_index], "-") == 0) { 990135446Strhodes input = stdin; 991135446Strhodes } else { 992135446Strhodes result = isc_stdio_open(argv[isc_commandline_index], 993135446Strhodes "r", &input); 994135446Strhodes if (result != ISC_R_SUCCESS) { 995135446Strhodes fprintf(stderr, "could not open '%s': %s\n", 996135446Strhodes argv[isc_commandline_index], 997135446Strhodes isc_result_totext(result)); 998135446Strhodes exit(1); 999135446Strhodes } 1000135446Strhodes } 1001135446Strhodes interactive = ISC_FALSE; 1002135446Strhodes } 1003135446Strhodes} 1004135446Strhodes 1005135446Strhodesstatic isc_uint16_t 1006135446Strhodesparse_name(char **cmdlinep, dns_message_t *msg, dns_name_t **namep) { 1007135446Strhodes isc_result_t result; 1008135446Strhodes char *word; 1009135446Strhodes isc_buffer_t *namebuf = NULL; 1010135446Strhodes isc_buffer_t source; 1011135446Strhodes 1012135446Strhodes word = nsu_strsep(cmdlinep, " \t\r\n"); 1013135446Strhodes if (*word == 0) { 1014135446Strhodes fprintf(stderr, "could not read owner name\n"); 1015135446Strhodes return (STATUS_SYNTAX); 1016135446Strhodes } 1017135446Strhodes 1018135446Strhodes result = dns_message_gettempname(msg, namep); 1019135446Strhodes check_result(result, "dns_message_gettempname"); 1020135446Strhodes result = isc_buffer_allocate(mctx, &namebuf, DNS_NAME_MAXWIRE); 1021135446Strhodes check_result(result, "isc_buffer_allocate"); 1022135446Strhodes dns_name_init(*namep, NULL); 1023135446Strhodes dns_name_setbuffer(*namep, namebuf); 1024135446Strhodes dns_message_takebuffer(msg, &namebuf); 1025135446Strhodes isc_buffer_init(&source, word, strlen(word)); 1026135446Strhodes isc_buffer_add(&source, strlen(word)); 1027135446Strhodes result = dns_name_fromtext(*namep, &source, dns_rootname, 1028135446Strhodes ISC_FALSE, NULL); 1029135446Strhodes check_result(result, "dns_name_fromtext"); 1030135446Strhodes isc_buffer_invalidate(&source); 1031135446Strhodes return (STATUS_MORE); 1032135446Strhodes} 1033135446Strhodes 1034135446Strhodesstatic isc_uint16_t 1035135446Strhodesparse_rdata(char **cmdlinep, dns_rdataclass_t rdataclass, 1036135446Strhodes dns_rdatatype_t rdatatype, dns_message_t *msg, 1037135446Strhodes dns_rdata_t *rdata) 1038135446Strhodes{ 1039135446Strhodes char *cmdline = *cmdlinep; 1040135446Strhodes isc_buffer_t source, *buf = NULL, *newbuf = NULL; 1041135446Strhodes isc_region_t r; 1042135446Strhodes isc_lex_t *lex = NULL; 1043135446Strhodes dns_rdatacallbacks_t callbacks; 1044135446Strhodes isc_result_t result; 1045135446Strhodes 1046135446Strhodes while (*cmdline != 0 && isspace((unsigned char)*cmdline)) 1047135446Strhodes cmdline++; 1048135446Strhodes 1049135446Strhodes if (*cmdline != 0) { 1050135446Strhodes dns_rdatacallbacks_init(&callbacks); 1051135446Strhodes result = isc_lex_create(mctx, strlen(cmdline), &lex); 1052135446Strhodes check_result(result, "isc_lex_create"); 1053135446Strhodes isc_buffer_init(&source, cmdline, strlen(cmdline)); 1054135446Strhodes isc_buffer_add(&source, strlen(cmdline)); 1055135446Strhodes result = isc_lex_openbuffer(lex, &source); 1056135446Strhodes check_result(result, "isc_lex_openbuffer"); 1057135446Strhodes result = isc_buffer_allocate(mctx, &buf, MAXWIRE); 1058135446Strhodes check_result(result, "isc_buffer_allocate"); 1059193149Sdougb result = dns_rdata_fromtext(NULL, rdataclass, rdatatype, lex, 1060135446Strhodes dns_rootname, 0, mctx, buf, 1061135446Strhodes &callbacks); 1062135446Strhodes isc_lex_destroy(&lex); 1063135446Strhodes if (result == ISC_R_SUCCESS) { 1064135446Strhodes isc_buffer_usedregion(buf, &r); 1065135446Strhodes result = isc_buffer_allocate(mctx, &newbuf, r.length); 1066135446Strhodes check_result(result, "isc_buffer_allocate"); 1067135446Strhodes isc_buffer_putmem(newbuf, r.base, r.length); 1068135446Strhodes isc_buffer_usedregion(newbuf, &r); 1069135446Strhodes dns_rdata_fromregion(rdata, rdataclass, rdatatype, &r); 1070135446Strhodes isc_buffer_free(&buf); 1071135446Strhodes dns_message_takebuffer(msg, &newbuf); 1072135446Strhodes } else { 1073135446Strhodes fprintf(stderr, "invalid rdata format: %s\n", 1074135446Strhodes isc_result_totext(result)); 1075135446Strhodes isc_buffer_free(&buf); 1076135446Strhodes return (STATUS_SYNTAX); 1077135446Strhodes } 1078135446Strhodes } else { 1079135446Strhodes rdata->flags = DNS_RDATA_UPDATE; 1080135446Strhodes } 1081135446Strhodes *cmdlinep = cmdline; 1082135446Strhodes return (STATUS_MORE); 1083135446Strhodes} 1084135446Strhodes 1085135446Strhodesstatic isc_uint16_t 1086135446Strhodesmake_prereq(char *cmdline, isc_boolean_t ispositive, isc_boolean_t isrrset) { 1087135446Strhodes isc_result_t result; 1088135446Strhodes char *word; 1089135446Strhodes dns_name_t *name = NULL; 1090135446Strhodes isc_textregion_t region; 1091135446Strhodes dns_rdataset_t *rdataset = NULL; 1092135446Strhodes dns_rdatalist_t *rdatalist = NULL; 1093135446Strhodes dns_rdataclass_t rdataclass; 1094135446Strhodes dns_rdatatype_t rdatatype; 1095135446Strhodes dns_rdata_t *rdata = NULL; 1096135446Strhodes isc_uint16_t retval; 1097135446Strhodes 1098135446Strhodes ddebug("make_prereq()"); 1099135446Strhodes 1100135446Strhodes /* 1101135446Strhodes * Read the owner name 1102135446Strhodes */ 1103135446Strhodes retval = parse_name(&cmdline, updatemsg, &name); 1104135446Strhodes if (retval != STATUS_MORE) 1105135446Strhodes return (retval); 1106135446Strhodes 1107135446Strhodes /* 1108135446Strhodes * If this is an rrset prereq, read the class or type. 1109135446Strhodes */ 1110135446Strhodes if (isrrset) { 1111135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1112135446Strhodes if (*word == 0) { 1113135446Strhodes fprintf(stderr, "could not read class or type\n"); 1114135446Strhodes goto failure; 1115135446Strhodes } 1116135446Strhodes region.base = word; 1117135446Strhodes region.length = strlen(word); 1118135446Strhodes result = dns_rdataclass_fromtext(&rdataclass, ®ion); 1119135446Strhodes if (result == ISC_R_SUCCESS) { 1120135446Strhodes if (!setzoneclass(rdataclass)) { 1121135446Strhodes fprintf(stderr, "class mismatch: %s\n", word); 1122135446Strhodes goto failure; 1123135446Strhodes } 1124135446Strhodes /* 1125135446Strhodes * Now read the type. 1126135446Strhodes */ 1127135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1128135446Strhodes if (*word == 0) { 1129135446Strhodes fprintf(stderr, "could not read type\n"); 1130135446Strhodes goto failure; 1131135446Strhodes } 1132135446Strhodes region.base = word; 1133135446Strhodes region.length = strlen(word); 1134135446Strhodes result = dns_rdatatype_fromtext(&rdatatype, ®ion); 1135135446Strhodes if (result != ISC_R_SUCCESS) { 1136135446Strhodes fprintf(stderr, "invalid type: %s\n", word); 1137135446Strhodes goto failure; 1138135446Strhodes } 1139135446Strhodes } else { 1140135446Strhodes rdataclass = getzoneclass(); 1141135446Strhodes result = dns_rdatatype_fromtext(&rdatatype, ®ion); 1142135446Strhodes if (result != ISC_R_SUCCESS) { 1143135446Strhodes fprintf(stderr, "invalid type: %s\n", word); 1144135446Strhodes goto failure; 1145135446Strhodes } 1146135446Strhodes } 1147135446Strhodes } else 1148135446Strhodes rdatatype = dns_rdatatype_any; 1149135446Strhodes 1150135446Strhodes result = dns_message_gettemprdata(updatemsg, &rdata); 1151135446Strhodes check_result(result, "dns_message_gettemprdata"); 1152135446Strhodes 1153193149Sdougb dns_rdata_init(rdata); 1154135446Strhodes 1155135446Strhodes if (isrrset && ispositive) { 1156135446Strhodes retval = parse_rdata(&cmdline, rdataclass, rdatatype, 1157135446Strhodes updatemsg, rdata); 1158135446Strhodes if (retval != STATUS_MORE) 1159135446Strhodes goto failure; 1160135446Strhodes } else 1161135446Strhodes rdata->flags = DNS_RDATA_UPDATE; 1162135446Strhodes 1163135446Strhodes result = dns_message_gettemprdatalist(updatemsg, &rdatalist); 1164135446Strhodes check_result(result, "dns_message_gettemprdatalist"); 1165135446Strhodes result = dns_message_gettemprdataset(updatemsg, &rdataset); 1166135446Strhodes check_result(result, "dns_message_gettemprdataset"); 1167135446Strhodes dns_rdatalist_init(rdatalist); 1168135446Strhodes rdatalist->type = rdatatype; 1169135446Strhodes if (ispositive) { 1170135446Strhodes if (isrrset && rdata->data != NULL) 1171135446Strhodes rdatalist->rdclass = rdataclass; 1172135446Strhodes else 1173135446Strhodes rdatalist->rdclass = dns_rdataclass_any; 1174135446Strhodes } else 1175135446Strhodes rdatalist->rdclass = dns_rdataclass_none; 1176135446Strhodes rdatalist->covers = 0; 1177135446Strhodes rdatalist->ttl = 0; 1178135446Strhodes rdata->rdclass = rdatalist->rdclass; 1179135446Strhodes rdata->type = rdatatype; 1180135446Strhodes ISC_LIST_INIT(rdatalist->rdata); 1181135446Strhodes ISC_LIST_APPEND(rdatalist->rdata, rdata, link); 1182135446Strhodes dns_rdataset_init(rdataset); 1183135446Strhodes dns_rdatalist_tordataset(rdatalist, rdataset); 1184135446Strhodes ISC_LIST_INIT(name->list); 1185135446Strhodes ISC_LIST_APPEND(name->list, rdataset, link); 1186135446Strhodes dns_message_addname(updatemsg, name, DNS_SECTION_PREREQUISITE); 1187135446Strhodes return (STATUS_MORE); 1188135446Strhodes 1189135446Strhodes failure: 1190135446Strhodes if (name != NULL) 1191135446Strhodes dns_message_puttempname(updatemsg, &name); 1192135446Strhodes return (STATUS_SYNTAX); 1193135446Strhodes} 1194135446Strhodes 1195135446Strhodesstatic isc_uint16_t 1196135446Strhodesevaluate_prereq(char *cmdline) { 1197135446Strhodes char *word; 1198135446Strhodes isc_boolean_t ispositive, isrrset; 1199135446Strhodes 1200135446Strhodes ddebug("evaluate_prereq()"); 1201135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1202135446Strhodes if (*word == 0) { 1203135446Strhodes fprintf(stderr, "could not read operation code\n"); 1204135446Strhodes return (STATUS_SYNTAX); 1205135446Strhodes } 1206135446Strhodes if (strcasecmp(word, "nxdomain") == 0) { 1207135446Strhodes ispositive = ISC_FALSE; 1208135446Strhodes isrrset = ISC_FALSE; 1209135446Strhodes } else if (strcasecmp(word, "yxdomain") == 0) { 1210135446Strhodes ispositive = ISC_TRUE; 1211135446Strhodes isrrset = ISC_FALSE; 1212135446Strhodes } else if (strcasecmp(word, "nxrrset") == 0) { 1213135446Strhodes ispositive = ISC_FALSE; 1214135446Strhodes isrrset = ISC_TRUE; 1215135446Strhodes } else if (strcasecmp(word, "yxrrset") == 0) { 1216135446Strhodes ispositive = ISC_TRUE; 1217135446Strhodes isrrset = ISC_TRUE; 1218135446Strhodes } else { 1219135446Strhodes fprintf(stderr, "incorrect operation code: %s\n", word); 1220135446Strhodes return (STATUS_SYNTAX); 1221135446Strhodes } 1222135446Strhodes return (make_prereq(cmdline, ispositive, isrrset)); 1223135446Strhodes} 1224135446Strhodes 1225135446Strhodesstatic isc_uint16_t 1226135446Strhodesevaluate_server(char *cmdline) { 1227135446Strhodes char *word, *server; 1228135446Strhodes long port; 1229135446Strhodes 1230135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1231135446Strhodes if (*word == 0) { 1232135446Strhodes fprintf(stderr, "could not read server name\n"); 1233135446Strhodes return (STATUS_SYNTAX); 1234135446Strhodes } 1235135446Strhodes server = word; 1236135446Strhodes 1237135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1238135446Strhodes if (*word == 0) 1239135446Strhodes port = DNSDEFAULTPORT; 1240135446Strhodes else { 1241135446Strhodes char *endp; 1242135446Strhodes port = strtol(word, &endp, 10); 1243135446Strhodes if (*endp != 0) { 1244135446Strhodes fprintf(stderr, "port '%s' is not numeric\n", word); 1245135446Strhodes return (STATUS_SYNTAX); 1246135446Strhodes } else if (port < 1 || port > 65535) { 1247135446Strhodes fprintf(stderr, "port '%s' is out of range " 1248135446Strhodes "(1 to 65535)\n", word); 1249135446Strhodes return (STATUS_SYNTAX); 1250135446Strhodes } 1251135446Strhodes } 1252135446Strhodes 1253135446Strhodes if (userserver == NULL) { 1254135446Strhodes userserver = isc_mem_get(mctx, sizeof(isc_sockaddr_t)); 1255135446Strhodes if (userserver == NULL) 1256135446Strhodes fatal("out of memory"); 1257135446Strhodes } 1258135446Strhodes 1259135446Strhodes get_address(server, (in_port_t)port, userserver); 1260135446Strhodes 1261135446Strhodes return (STATUS_MORE); 1262135446Strhodes} 1263135446Strhodes 1264135446Strhodesstatic isc_uint16_t 1265135446Strhodesevaluate_local(char *cmdline) { 1266135446Strhodes char *word, *local; 1267135446Strhodes long port; 1268135446Strhodes struct in_addr in4; 1269135446Strhodes struct in6_addr in6; 1270135446Strhodes 1271135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1272135446Strhodes if (*word == 0) { 1273135446Strhodes fprintf(stderr, "could not read server name\n"); 1274135446Strhodes return (STATUS_SYNTAX); 1275135446Strhodes } 1276135446Strhodes local = word; 1277135446Strhodes 1278135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1279135446Strhodes if (*word == 0) 1280135446Strhodes port = 0; 1281135446Strhodes else { 1282135446Strhodes char *endp; 1283135446Strhodes port = strtol(word, &endp, 10); 1284135446Strhodes if (*endp != 0) { 1285135446Strhodes fprintf(stderr, "port '%s' is not numeric\n", word); 1286135446Strhodes return (STATUS_SYNTAX); 1287135446Strhodes } else if (port < 1 || port > 65535) { 1288135446Strhodes fprintf(stderr, "port '%s' is out of range " 1289135446Strhodes "(1 to 65535)\n", word); 1290135446Strhodes return (STATUS_SYNTAX); 1291135446Strhodes } 1292135446Strhodes } 1293135446Strhodes 1294135446Strhodes if (localaddr == NULL) { 1295135446Strhodes localaddr = isc_mem_get(mctx, sizeof(isc_sockaddr_t)); 1296135446Strhodes if (localaddr == NULL) 1297135446Strhodes fatal("out of memory"); 1298135446Strhodes } 1299135446Strhodes 1300135446Strhodes if (have_ipv6 && inet_pton(AF_INET6, local, &in6) == 1) 1301135446Strhodes isc_sockaddr_fromin6(localaddr, &in6, (in_port_t)port); 1302135446Strhodes else if (have_ipv4 && inet_pton(AF_INET, local, &in4) == 1) 1303135446Strhodes isc_sockaddr_fromin(localaddr, &in4, (in_port_t)port); 1304135446Strhodes else { 1305135446Strhodes fprintf(stderr, "invalid address %s", local); 1306135446Strhodes return (STATUS_SYNTAX); 1307135446Strhodes } 1308135446Strhodes 1309135446Strhodes return (STATUS_MORE); 1310135446Strhodes} 1311135446Strhodes 1312135446Strhodesstatic isc_uint16_t 1313135446Strhodesevaluate_key(char *cmdline) { 1314135446Strhodes char *namestr; 1315135446Strhodes char *secretstr; 1316135446Strhodes isc_buffer_t b; 1317135446Strhodes isc_result_t result; 1318135446Strhodes dns_fixedname_t fkeyname; 1319135446Strhodes dns_name_t *keyname; 1320135446Strhodes int secretlen; 1321135446Strhodes unsigned char *secret = NULL; 1322135446Strhodes isc_buffer_t secretbuf; 1323170222Sdougb dns_name_t *hmacname = NULL; 1324170222Sdougb isc_uint16_t digestbits = 0; 1325170222Sdougb char *n; 1326135446Strhodes 1327135446Strhodes namestr = nsu_strsep(&cmdline, " \t\r\n"); 1328135446Strhodes if (*namestr == 0) { 1329135446Strhodes fprintf(stderr, "could not read key name\n"); 1330135446Strhodes return (STATUS_SYNTAX); 1331135446Strhodes } 1332135446Strhodes 1333135446Strhodes dns_fixedname_init(&fkeyname); 1334135446Strhodes keyname = dns_fixedname_name(&fkeyname); 1335135446Strhodes 1336170222Sdougb n = strchr(namestr, ':'); 1337170222Sdougb if (n != NULL) { 1338170222Sdougb digestbits = parse_hmac(&hmacname, namestr, n - namestr); 1339170222Sdougb namestr = n + 1; 1340170222Sdougb } else 1341170222Sdougb hmacname = DNS_TSIG_HMACMD5_NAME; 1342170222Sdougb 1343135446Strhodes isc_buffer_init(&b, namestr, strlen(namestr)); 1344135446Strhodes isc_buffer_add(&b, strlen(namestr)); 1345135446Strhodes result = dns_name_fromtext(keyname, &b, dns_rootname, ISC_FALSE, NULL); 1346135446Strhodes if (result != ISC_R_SUCCESS) { 1347135446Strhodes fprintf(stderr, "could not parse key name\n"); 1348135446Strhodes return (STATUS_SYNTAX); 1349135446Strhodes } 1350135446Strhodes 1351135446Strhodes secretstr = nsu_strsep(&cmdline, "\r\n"); 1352135446Strhodes if (*secretstr == 0) { 1353135446Strhodes fprintf(stderr, "could not read key secret\n"); 1354135446Strhodes return (STATUS_SYNTAX); 1355135446Strhodes } 1356135446Strhodes secretlen = strlen(secretstr) * 3 / 4; 1357135446Strhodes secret = isc_mem_allocate(mctx, secretlen); 1358135446Strhodes if (secret == NULL) 1359135446Strhodes fatal("out of memory"); 1360186462Sdougb 1361135446Strhodes isc_buffer_init(&secretbuf, secret, secretlen); 1362135446Strhodes result = isc_base64_decodestring(secretstr, &secretbuf); 1363135446Strhodes if (result != ISC_R_SUCCESS) { 1364135446Strhodes fprintf(stderr, "could not create key from %s: %s\n", 1365135446Strhodes secretstr, isc_result_totext(result)); 1366135446Strhodes isc_mem_free(mctx, secret); 1367135446Strhodes return (STATUS_SYNTAX); 1368135446Strhodes } 1369135446Strhodes secretlen = isc_buffer_usedlength(&secretbuf); 1370135446Strhodes 1371135446Strhodes if (tsigkey != NULL) 1372135446Strhodes dns_tsigkey_detach(&tsigkey); 1373170222Sdougb result = dns_tsigkey_create(keyname, hmacname, secret, secretlen, 1374218384Sdougb ISC_FALSE, NULL, 0, 0, mctx, NULL, 1375170222Sdougb &tsigkey); 1376135446Strhodes isc_mem_free(mctx, secret); 1377135446Strhodes if (result != ISC_R_SUCCESS) { 1378135446Strhodes fprintf(stderr, "could not create key from %s %s: %s\n", 1379135446Strhodes namestr, secretstr, dns_result_totext(result)); 1380135446Strhodes return (STATUS_SYNTAX); 1381135446Strhodes } 1382170222Sdougb dst_key_setbits(tsigkey->key, digestbits); 1383135446Strhodes return (STATUS_MORE); 1384135446Strhodes} 1385135446Strhodes 1386135446Strhodesstatic isc_uint16_t 1387135446Strhodesevaluate_zone(char *cmdline) { 1388135446Strhodes char *word; 1389135446Strhodes isc_buffer_t b; 1390135446Strhodes isc_result_t result; 1391135446Strhodes 1392135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1393135446Strhodes if (*word == 0) { 1394135446Strhodes fprintf(stderr, "could not read zone name\n"); 1395135446Strhodes return (STATUS_SYNTAX); 1396135446Strhodes } 1397135446Strhodes 1398135446Strhodes dns_fixedname_init(&fuserzone); 1399135446Strhodes userzone = dns_fixedname_name(&fuserzone); 1400135446Strhodes isc_buffer_init(&b, word, strlen(word)); 1401135446Strhodes isc_buffer_add(&b, strlen(word)); 1402135446Strhodes result = dns_name_fromtext(userzone, &b, dns_rootname, ISC_FALSE, 1403135446Strhodes NULL); 1404135446Strhodes if (result != ISC_R_SUCCESS) { 1405135446Strhodes userzone = NULL; /* Lest it point to an invalid name */ 1406135446Strhodes fprintf(stderr, "could not parse zone name\n"); 1407135446Strhodes return (STATUS_SYNTAX); 1408135446Strhodes } 1409135446Strhodes 1410135446Strhodes return (STATUS_MORE); 1411135446Strhodes} 1412135446Strhodes 1413135446Strhodesstatic isc_uint16_t 1414218384Sdougbevaluate_realm(char *cmdline) { 1415218384Sdougb#ifdef GSSAPI 1416218384Sdougb char *word; 1417218384Sdougb char buf[1024]; 1418218384Sdougb 1419218384Sdougb word = nsu_strsep(&cmdline, " \t\r\n"); 1420218384Sdougb if (*word == 0) { 1421218384Sdougb if (realm != NULL) 1422218384Sdougb isc_mem_free(mctx, realm); 1423218384Sdougb realm = NULL; 1424218384Sdougb return (STATUS_MORE); 1425218384Sdougb } 1426218384Sdougb 1427218384Sdougb snprintf(buf, sizeof(buf), "@%s", word); 1428218384Sdougb realm = isc_mem_strdup(mctx, buf); 1429218384Sdougb if (realm == NULL) 1430218384Sdougb fatal("out of memory"); 1431218384Sdougb return (STATUS_MORE); 1432218384Sdougb#else 1433218384Sdougb UNUSED(cmdline); 1434218384Sdougb return (STATUS_SYNTAX); 1435218384Sdougb#endif 1436218384Sdougb} 1437218384Sdougb 1438218384Sdougbstatic isc_uint16_t 1439193149Sdougbevaluate_ttl(char *cmdline) { 1440193149Sdougb char *word; 1441193149Sdougb isc_result_t result; 1442193149Sdougb isc_uint32_t ttl; 1443193149Sdougb 1444193149Sdougb word = nsu_strsep(&cmdline, " \t\r\n"); 1445193149Sdougb if (*word == 0) { 1446193149Sdougb fprintf(stderr, "could not ttl\n"); 1447193149Sdougb return (STATUS_SYNTAX); 1448193149Sdougb } 1449193149Sdougb 1450193149Sdougb if (!strcasecmp(word, "none")) { 1451193149Sdougb default_ttl = 0; 1452193149Sdougb default_ttl_set = ISC_FALSE; 1453193149Sdougb return (STATUS_MORE); 1454193149Sdougb } 1455193149Sdougb 1456193149Sdougb result = isc_parse_uint32(&ttl, word, 10); 1457193149Sdougb if (result != ISC_R_SUCCESS) 1458193149Sdougb return (STATUS_SYNTAX); 1459193149Sdougb 1460193149Sdougb if (ttl > TTL_MAX) { 1461193149Sdougb fprintf(stderr, "ttl '%s' is out of range (0 to %u)\n", 1462193149Sdougb word, TTL_MAX); 1463193149Sdougb return (STATUS_SYNTAX); 1464193149Sdougb } 1465193149Sdougb default_ttl = ttl; 1466193149Sdougb default_ttl_set = ISC_TRUE; 1467193149Sdougb 1468193149Sdougb return (STATUS_MORE); 1469193149Sdougb} 1470193149Sdougb 1471193149Sdougbstatic isc_uint16_t 1472135446Strhodesevaluate_class(char *cmdline) { 1473135446Strhodes char *word; 1474135446Strhodes isc_textregion_t r; 1475135446Strhodes isc_result_t result; 1476135446Strhodes dns_rdataclass_t rdclass; 1477135446Strhodes 1478135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1479135446Strhodes if (*word == 0) { 1480135446Strhodes fprintf(stderr, "could not read class name\n"); 1481135446Strhodes return (STATUS_SYNTAX); 1482135446Strhodes } 1483135446Strhodes 1484135446Strhodes r.base = word; 1485186462Sdougb r.length = strlen(word); 1486186462Sdougb result = dns_rdataclass_fromtext(&rdclass, &r); 1487135446Strhodes if (result != ISC_R_SUCCESS) { 1488135446Strhodes fprintf(stderr, "could not parse class name: %s\n", word); 1489135446Strhodes return (STATUS_SYNTAX); 1490135446Strhodes } 1491135446Strhodes switch (rdclass) { 1492135446Strhodes case dns_rdataclass_none: 1493135446Strhodes case dns_rdataclass_any: 1494135446Strhodes case dns_rdataclass_reserved0: 1495135446Strhodes fprintf(stderr, "bad default class: %s\n", word); 1496135446Strhodes return (STATUS_SYNTAX); 1497135446Strhodes default: 1498135446Strhodes defaultclass = rdclass; 1499135446Strhodes } 1500135446Strhodes 1501135446Strhodes return (STATUS_MORE); 1502135446Strhodes} 1503135446Strhodes 1504135446Strhodesstatic isc_uint16_t 1505135446Strhodesupdate_addordelete(char *cmdline, isc_boolean_t isdelete) { 1506135446Strhodes isc_result_t result; 1507135446Strhodes dns_name_t *name = NULL; 1508135446Strhodes isc_uint32_t ttl; 1509135446Strhodes char *word; 1510135446Strhodes dns_rdataclass_t rdataclass; 1511135446Strhodes dns_rdatatype_t rdatatype; 1512135446Strhodes dns_rdata_t *rdata = NULL; 1513135446Strhodes dns_rdatalist_t *rdatalist = NULL; 1514135446Strhodes dns_rdataset_t *rdataset = NULL; 1515135446Strhodes isc_textregion_t region; 1516135446Strhodes isc_uint16_t retval; 1517135446Strhodes 1518135446Strhodes ddebug("update_addordelete()"); 1519135446Strhodes 1520135446Strhodes /* 1521135446Strhodes * Read the owner name. 1522135446Strhodes */ 1523135446Strhodes retval = parse_name(&cmdline, updatemsg, &name); 1524135446Strhodes if (retval != STATUS_MORE) 1525135446Strhodes return (retval); 1526135446Strhodes 1527135446Strhodes result = dns_message_gettemprdata(updatemsg, &rdata); 1528135446Strhodes check_result(result, "dns_message_gettemprdata"); 1529135446Strhodes 1530193149Sdougb dns_rdata_init(rdata); 1531135446Strhodes 1532135446Strhodes /* 1533135446Strhodes * If this is an add, read the TTL and verify that it's in range. 1534135446Strhodes * If it's a delete, ignore a TTL if present (for compatibility). 1535135446Strhodes */ 1536135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1537135446Strhodes if (*word == 0) { 1538135446Strhodes if (!isdelete) { 1539135446Strhodes fprintf(stderr, "could not read owner ttl\n"); 1540135446Strhodes goto failure; 1541135446Strhodes } 1542135446Strhodes else { 1543135446Strhodes ttl = 0; 1544135446Strhodes rdataclass = dns_rdataclass_any; 1545135446Strhodes rdatatype = dns_rdatatype_any; 1546135446Strhodes rdata->flags = DNS_RDATA_UPDATE; 1547135446Strhodes goto doneparsing; 1548135446Strhodes } 1549135446Strhodes } 1550135446Strhodes result = isc_parse_uint32(&ttl, word, 10); 1551135446Strhodes if (result != ISC_R_SUCCESS) { 1552135446Strhodes if (isdelete) { 1553135446Strhodes ttl = 0; 1554135446Strhodes goto parseclass; 1555193149Sdougb } else if (default_ttl_set) { 1556193149Sdougb ttl = default_ttl; 1557193149Sdougb goto parseclass; 1558135446Strhodes } else { 1559135446Strhodes fprintf(stderr, "ttl '%s': %s\n", word, 1560135446Strhodes isc_result_totext(result)); 1561135446Strhodes goto failure; 1562135446Strhodes } 1563135446Strhodes } 1564135446Strhodes 1565135446Strhodes if (isdelete) 1566135446Strhodes ttl = 0; 1567135446Strhodes else if (ttl > TTL_MAX) { 1568135446Strhodes fprintf(stderr, "ttl '%s' is out of range (0 to %u)\n", 1569135446Strhodes word, TTL_MAX); 1570135446Strhodes goto failure; 1571135446Strhodes } 1572135446Strhodes 1573135446Strhodes /* 1574135446Strhodes * Read the class or type. 1575135446Strhodes */ 1576135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1577135446Strhodes parseclass: 1578135446Strhodes if (*word == 0) { 1579135446Strhodes if (isdelete) { 1580135446Strhodes rdataclass = dns_rdataclass_any; 1581135446Strhodes rdatatype = dns_rdatatype_any; 1582135446Strhodes rdata->flags = DNS_RDATA_UPDATE; 1583135446Strhodes goto doneparsing; 1584135446Strhodes } else { 1585135446Strhodes fprintf(stderr, "could not read class or type\n"); 1586135446Strhodes goto failure; 1587135446Strhodes } 1588135446Strhodes } 1589135446Strhodes region.base = word; 1590135446Strhodes region.length = strlen(word); 1591193149Sdougb rdataclass = dns_rdataclass_any; 1592135446Strhodes result = dns_rdataclass_fromtext(&rdataclass, ®ion); 1593193149Sdougb if (result == ISC_R_SUCCESS && rdataclass != dns_rdataclass_any) { 1594135446Strhodes if (!setzoneclass(rdataclass)) { 1595135446Strhodes fprintf(stderr, "class mismatch: %s\n", word); 1596135446Strhodes goto failure; 1597135446Strhodes } 1598135446Strhodes /* 1599135446Strhodes * Now read the type. 1600135446Strhodes */ 1601135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1602135446Strhodes if (*word == 0) { 1603135446Strhodes if (isdelete) { 1604135446Strhodes rdataclass = dns_rdataclass_any; 1605135446Strhodes rdatatype = dns_rdatatype_any; 1606135446Strhodes rdata->flags = DNS_RDATA_UPDATE; 1607135446Strhodes goto doneparsing; 1608135446Strhodes } else { 1609135446Strhodes fprintf(stderr, "could not read type\n"); 1610135446Strhodes goto failure; 1611135446Strhodes } 1612135446Strhodes } 1613135446Strhodes region.base = word; 1614135446Strhodes region.length = strlen(word); 1615135446Strhodes result = dns_rdatatype_fromtext(&rdatatype, ®ion); 1616135446Strhodes if (result != ISC_R_SUCCESS) { 1617135446Strhodes fprintf(stderr, "'%s' is not a valid type: %s\n", 1618135446Strhodes word, isc_result_totext(result)); 1619135446Strhodes goto failure; 1620135446Strhodes } 1621135446Strhodes } else { 1622135446Strhodes rdataclass = getzoneclass(); 1623135446Strhodes result = dns_rdatatype_fromtext(&rdatatype, ®ion); 1624135446Strhodes if (result != ISC_R_SUCCESS) { 1625135446Strhodes fprintf(stderr, "'%s' is not a valid class or type: " 1626135446Strhodes "%s\n", word, isc_result_totext(result)); 1627135446Strhodes goto failure; 1628135446Strhodes } 1629135446Strhodes } 1630135446Strhodes 1631135446Strhodes retval = parse_rdata(&cmdline, rdataclass, rdatatype, updatemsg, 1632135446Strhodes rdata); 1633135446Strhodes if (retval != STATUS_MORE) 1634135446Strhodes goto failure; 1635135446Strhodes 1636135446Strhodes if (isdelete) { 1637135446Strhodes if ((rdata->flags & DNS_RDATA_UPDATE) != 0) 1638135446Strhodes rdataclass = dns_rdataclass_any; 1639135446Strhodes else 1640135446Strhodes rdataclass = dns_rdataclass_none; 1641135446Strhodes } else { 1642135446Strhodes if ((rdata->flags & DNS_RDATA_UPDATE) != 0) { 1643135446Strhodes fprintf(stderr, "could not read rdata\n"); 1644135446Strhodes goto failure; 1645135446Strhodes } 1646135446Strhodes } 1647135446Strhodes 1648135446Strhodes doneparsing: 1649135446Strhodes 1650135446Strhodes result = dns_message_gettemprdatalist(updatemsg, &rdatalist); 1651135446Strhodes check_result(result, "dns_message_gettemprdatalist"); 1652135446Strhodes result = dns_message_gettemprdataset(updatemsg, &rdataset); 1653135446Strhodes check_result(result, "dns_message_gettemprdataset"); 1654135446Strhodes dns_rdatalist_init(rdatalist); 1655135446Strhodes rdatalist->type = rdatatype; 1656135446Strhodes rdatalist->rdclass = rdataclass; 1657135446Strhodes rdatalist->covers = rdatatype; 1658135446Strhodes rdatalist->ttl = (dns_ttl_t)ttl; 1659135446Strhodes ISC_LIST_INIT(rdatalist->rdata); 1660135446Strhodes ISC_LIST_APPEND(rdatalist->rdata, rdata, link); 1661135446Strhodes dns_rdataset_init(rdataset); 1662135446Strhodes dns_rdatalist_tordataset(rdatalist, rdataset); 1663135446Strhodes ISC_LIST_INIT(name->list); 1664135446Strhodes ISC_LIST_APPEND(name->list, rdataset, link); 1665135446Strhodes dns_message_addname(updatemsg, name, DNS_SECTION_UPDATE); 1666135446Strhodes return (STATUS_MORE); 1667135446Strhodes 1668135446Strhodes failure: 1669135446Strhodes if (name != NULL) 1670135446Strhodes dns_message_puttempname(updatemsg, &name); 1671186462Sdougb dns_message_puttemprdata(updatemsg, &rdata); 1672135446Strhodes return (STATUS_SYNTAX); 1673135446Strhodes} 1674135446Strhodes 1675135446Strhodesstatic isc_uint16_t 1676135446Strhodesevaluate_update(char *cmdline) { 1677135446Strhodes char *word; 1678135446Strhodes isc_boolean_t isdelete; 1679135446Strhodes 1680135446Strhodes ddebug("evaluate_update()"); 1681135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1682135446Strhodes if (*word == 0) { 1683135446Strhodes fprintf(stderr, "could not read operation code\n"); 1684135446Strhodes return (STATUS_SYNTAX); 1685135446Strhodes } 1686135446Strhodes if (strcasecmp(word, "delete") == 0) 1687135446Strhodes isdelete = ISC_TRUE; 1688135446Strhodes else if (strcasecmp(word, "add") == 0) 1689135446Strhodes isdelete = ISC_FALSE; 1690135446Strhodes else { 1691135446Strhodes fprintf(stderr, "incorrect operation code: %s\n", word); 1692135446Strhodes return (STATUS_SYNTAX); 1693135446Strhodes } 1694135446Strhodes return (update_addordelete(cmdline, isdelete)); 1695135446Strhodes} 1696135446Strhodes 1697135446Strhodesstatic void 1698170222Sdougbsetzone(dns_name_t *zonename) { 1699170222Sdougb isc_result_t result; 1700170222Sdougb dns_name_t *name = NULL; 1701170222Sdougb dns_rdataset_t *rdataset = NULL; 1702170222Sdougb 1703170222Sdougb result = dns_message_firstname(updatemsg, DNS_SECTION_ZONE); 1704170222Sdougb if (result == ISC_R_SUCCESS) { 1705170222Sdougb dns_message_currentname(updatemsg, DNS_SECTION_ZONE, &name); 1706170222Sdougb dns_message_removename(updatemsg, name, DNS_SECTION_ZONE); 1707170222Sdougb for (rdataset = ISC_LIST_HEAD(name->list); 1708170222Sdougb rdataset != NULL; 1709170222Sdougb rdataset = ISC_LIST_HEAD(name->list)) { 1710170222Sdougb ISC_LIST_UNLINK(name->list, rdataset, link); 1711170222Sdougb dns_rdataset_disassociate(rdataset); 1712170222Sdougb dns_message_puttemprdataset(updatemsg, &rdataset); 1713170222Sdougb } 1714170222Sdougb dns_message_puttempname(updatemsg, &name); 1715170222Sdougb } 1716170222Sdougb 1717170222Sdougb if (zonename != NULL) { 1718170222Sdougb result = dns_message_gettempname(updatemsg, &name); 1719170222Sdougb check_result(result, "dns_message_gettempname"); 1720170222Sdougb dns_name_init(name, NULL); 1721170222Sdougb dns_name_clone(zonename, name); 1722170222Sdougb result = dns_message_gettemprdataset(updatemsg, &rdataset); 1723170222Sdougb check_result(result, "dns_message_gettemprdataset"); 1724170222Sdougb dns_rdataset_makequestion(rdataset, getzoneclass(), 1725170222Sdougb dns_rdatatype_soa); 1726170222Sdougb ISC_LIST_INIT(name->list); 1727170222Sdougb ISC_LIST_APPEND(name->list, rdataset, link); 1728170222Sdougb dns_message_addname(updatemsg, name, DNS_SECTION_ZONE); 1729170222Sdougb } 1730170222Sdougb} 1731170222Sdougb 1732170222Sdougbstatic void 1733193149Sdougbshow_message(FILE *stream, dns_message_t *msg, const char *description) { 1734135446Strhodes isc_result_t result; 1735135446Strhodes isc_buffer_t *buf = NULL; 1736135446Strhodes int bufsz; 1737135446Strhodes 1738135446Strhodes ddebug("show_message()"); 1739170222Sdougb 1740170222Sdougb setzone(userzone); 1741170222Sdougb 1742135446Strhodes bufsz = INITTEXT; 1743186462Sdougb do { 1744135446Strhodes if (bufsz > MAXTEXT) { 1745135446Strhodes fprintf(stderr, "could not allocate large enough " 1746135446Strhodes "buffer to display message\n"); 1747135446Strhodes exit(1); 1748135446Strhodes } 1749135446Strhodes if (buf != NULL) 1750135446Strhodes isc_buffer_free(&buf); 1751135446Strhodes result = isc_buffer_allocate(mctx, &buf, bufsz); 1752135446Strhodes check_result(result, "isc_buffer_allocate"); 1753135446Strhodes result = dns_message_totext(msg, style, 0, buf); 1754135446Strhodes bufsz *= 2; 1755135446Strhodes } while (result == ISC_R_NOSPACE); 1756135446Strhodes if (result != ISC_R_SUCCESS) { 1757135446Strhodes fprintf(stderr, "could not convert message to text format.\n"); 1758135446Strhodes isc_buffer_free(&buf); 1759135446Strhodes return; 1760135446Strhodes } 1761193149Sdougb fprintf(stream, "%s\n%.*s", description, 1762193149Sdougb (int)isc_buffer_usedlength(buf), (char*)isc_buffer_base(buf)); 1763135446Strhodes isc_buffer_free(&buf); 1764135446Strhodes} 1765135446Strhodes 1766135446Strhodes 1767135446Strhodesstatic isc_uint16_t 1768135446Strhodesget_next_command(void) { 1769135446Strhodes char cmdlinebuf[MAXCMD]; 1770135446Strhodes char *cmdline; 1771135446Strhodes char *word; 1772135446Strhodes 1773135446Strhodes ddebug("get_next_command()"); 1774165071Sdougb if (interactive) { 1775135446Strhodes fprintf(stdout, "> "); 1776165071Sdougb fflush(stdout); 1777165071Sdougb } 1778135446Strhodes isc_app_block(); 1779135446Strhodes cmdline = fgets(cmdlinebuf, MAXCMD, input); 1780135446Strhodes isc_app_unblock(); 1781135446Strhodes if (cmdline == NULL) 1782135446Strhodes return (STATUS_QUIT); 1783135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1784135446Strhodes 1785135446Strhodes if (feof(input)) 1786135446Strhodes return (STATUS_QUIT); 1787135446Strhodes if (*word == 0) 1788135446Strhodes return (STATUS_SEND); 1789135446Strhodes if (word[0] == ';') 1790135446Strhodes return (STATUS_MORE); 1791135446Strhodes if (strcasecmp(word, "quit") == 0) 1792135446Strhodes return (STATUS_QUIT); 1793135446Strhodes if (strcasecmp(word, "prereq") == 0) 1794135446Strhodes return (evaluate_prereq(cmdline)); 1795135446Strhodes if (strcasecmp(word, "update") == 0) 1796135446Strhodes return (evaluate_update(cmdline)); 1797135446Strhodes if (strcasecmp(word, "server") == 0) 1798135446Strhodes return (evaluate_server(cmdline)); 1799135446Strhodes if (strcasecmp(word, "local") == 0) 1800135446Strhodes return (evaluate_local(cmdline)); 1801135446Strhodes if (strcasecmp(word, "zone") == 0) 1802135446Strhodes return (evaluate_zone(cmdline)); 1803135446Strhodes if (strcasecmp(word, "class") == 0) 1804135446Strhodes return (evaluate_class(cmdline)); 1805135446Strhodes if (strcasecmp(word, "send") == 0) 1806135446Strhodes return (STATUS_SEND); 1807193149Sdougb if (strcasecmp(word, "debug") == 0) { 1808193149Sdougb if (debugging) 1809193149Sdougb ddebugging = ISC_TRUE; 1810193149Sdougb else 1811193149Sdougb debugging = ISC_TRUE; 1812193149Sdougb return (STATUS_MORE); 1813193149Sdougb } 1814193149Sdougb if (strcasecmp(word, "ttl") == 0) 1815193149Sdougb return (evaluate_ttl(cmdline)); 1816135446Strhodes if (strcasecmp(word, "show") == 0) { 1817193149Sdougb show_message(stdout, updatemsg, "Outgoing update query:"); 1818135446Strhodes return (STATUS_MORE); 1819135446Strhodes } 1820135446Strhodes if (strcasecmp(word, "answer") == 0) { 1821135446Strhodes if (answer != NULL) 1822193149Sdougb show_message(stdout, answer, "Answer:"); 1823135446Strhodes return (STATUS_MORE); 1824135446Strhodes } 1825193149Sdougb if (strcasecmp(word, "key") == 0) { 1826193149Sdougb usegsstsig = ISC_FALSE; 1827135446Strhodes return (evaluate_key(cmdline)); 1828193149Sdougb } 1829218384Sdougb if (strcasecmp(word, "realm") == 0) 1830218384Sdougb return (evaluate_realm(cmdline)); 1831193149Sdougb if (strcasecmp(word, "gsstsig") == 0) { 1832193149Sdougb#ifdef GSSAPI 1833193149Sdougb usegsstsig = ISC_TRUE; 1834193149Sdougb use_win2k_gsstsig = ISC_FALSE; 1835193149Sdougb#else 1836193149Sdougb fprintf(stderr, "gsstsig not supported\n"); 1837193149Sdougb#endif 1838193149Sdougb return (STATUS_MORE); 1839193149Sdougb } 1840193149Sdougb if (strcasecmp(word, "oldgsstsig") == 0) { 1841193149Sdougb#ifdef GSSAPI 1842193149Sdougb usegsstsig = ISC_TRUE; 1843193149Sdougb use_win2k_gsstsig = ISC_TRUE; 1844193149Sdougb#else 1845193149Sdougb fprintf(stderr, "gsstsig not supported\n"); 1846193149Sdougb#endif 1847193149Sdougb return (STATUS_MORE); 1848193149Sdougb } 1849193149Sdougb if (strcasecmp(word, "help") == 0) { 1850193149Sdougb fprintf(stdout, 1851193149Sdougb"local address [port] (set local resolver)\n" 1852193149Sdougb"server address [port] (set master server for zone)\n" 1853193149Sdougb"send (send the update request)\n" 1854193149Sdougb"show (show the update request)\n" 1855193149Sdougb"answer (show the answer to the last request)\n" 1856193149Sdougb"quit (quit, any pending update is not sent\n" 1857193149Sdougb"help (display this message_\n" 1858193149Sdougb"key [hmac:]keyname secret (use TSIG to sign the request)\n" 1859193149Sdougb"gsstsig (use GSS_TSIG to sign the request)\n" 1860193149Sdougb"oldgsstsig (use Microsoft's GSS_TSIG to sign the request)\n" 1861193149Sdougb"zone name (set the zone to be updated)\n" 1862193149Sdougb"class CLASS (set the zone's DNS class, e.g. IN (default), CH)\n" 1863193149Sdougb"prereq nxdomain name (does this name not exist)\n" 1864193149Sdougb"prereq yxdomain name (does this name exist)\n" 1865193149Sdougb"prereq nxrrset .... (does this RRset exist)\n" 1866193149Sdougb"prereq yxrrset .... (does this RRset not exist)\n" 1867193149Sdougb"update add .... (add the given record to the zone)\n" 1868193149Sdougb"update delete .... (remove the given record(s) from the zone)\n"); 1869193149Sdougb return (STATUS_MORE); 1870193149Sdougb } 1871135446Strhodes fprintf(stderr, "incorrect section name: %s\n", word); 1872135446Strhodes return (STATUS_SYNTAX); 1873135446Strhodes} 1874135446Strhodes 1875135446Strhodesstatic isc_boolean_t 1876135446Strhodesuser_interaction(void) { 1877135446Strhodes isc_uint16_t result = STATUS_MORE; 1878135446Strhodes 1879135446Strhodes ddebug("user_interaction()"); 1880174187Sdougb while ((result == STATUS_MORE) || (result == STATUS_SYNTAX)) { 1881135446Strhodes result = get_next_command(); 1882174187Sdougb if (!interactive && result == STATUS_SYNTAX) 1883174187Sdougb fatal("syntax error"); 1884174187Sdougb } 1885135446Strhodes if (result == STATUS_SEND) 1886135446Strhodes return (ISC_TRUE); 1887135446Strhodes return (ISC_FALSE); 1888135446Strhodes 1889135446Strhodes} 1890135446Strhodes 1891135446Strhodesstatic void 1892135446Strhodesdone_update(void) { 1893135446Strhodes isc_event_t *event = global_event; 1894135446Strhodes ddebug("done_update()"); 1895135446Strhodes isc_task_send(global_task, &event); 1896135446Strhodes} 1897135446Strhodes 1898135446Strhodesstatic void 1899135446Strhodescheck_tsig_error(dns_rdataset_t *rdataset, isc_buffer_t *b) { 1900135446Strhodes isc_result_t result; 1901135446Strhodes dns_rdata_t rdata = DNS_RDATA_INIT; 1902135446Strhodes dns_rdata_any_tsig_t tsig; 1903135446Strhodes 1904135446Strhodes result = dns_rdataset_first(rdataset); 1905135446Strhodes check_result(result, "dns_rdataset_first"); 1906135446Strhodes dns_rdataset_current(rdataset, &rdata); 1907135446Strhodes result = dns_rdata_tostruct(&rdata, &tsig, NULL); 1908135446Strhodes check_result(result, "dns_rdata_tostruct"); 1909135446Strhodes if (tsig.error != 0) { 1910135446Strhodes if (isc_buffer_remaininglength(b) < 1) 1911135446Strhodes check_result(ISC_R_NOSPACE, "isc_buffer_remaininglength"); 1912135446Strhodes isc__buffer_putstr(b, "(" /*)*/); 1913135446Strhodes result = dns_tsigrcode_totext(tsig.error, b); 1914135446Strhodes check_result(result, "dns_tsigrcode_totext"); 1915135446Strhodes if (isc_buffer_remaininglength(b) < 1) 1916135446Strhodes check_result(ISC_R_NOSPACE, "isc_buffer_remaininglength"); 1917135446Strhodes isc__buffer_putstr(b, /*(*/ ")"); 1918135446Strhodes } 1919135446Strhodes} 1920135446Strhodes 1921135446Strhodesstatic void 1922135446Strhodesupdate_completed(isc_task_t *task, isc_event_t *event) { 1923135446Strhodes dns_requestevent_t *reqev = NULL; 1924135446Strhodes isc_result_t result; 1925135446Strhodes dns_request_t *request; 1926135446Strhodes 1927135446Strhodes UNUSED(task); 1928135446Strhodes 1929135446Strhodes ddebug("update_completed()"); 1930135446Strhodes 1931135446Strhodes requests--; 1932135446Strhodes 1933135446Strhodes REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE); 1934135446Strhodes reqev = (dns_requestevent_t *)event; 1935135446Strhodes request = reqev->request; 1936135446Strhodes 1937135446Strhodes if (shuttingdown) { 1938135446Strhodes dns_request_destroy(&request); 1939135446Strhodes isc_event_free(&event); 1940135446Strhodes maybeshutdown(); 1941135446Strhodes return; 1942135446Strhodes } 1943135446Strhodes 1944135446Strhodes if (reqev->result != ISC_R_SUCCESS) { 1945135446Strhodes fprintf(stderr, "; Communication with server failed: %s\n", 1946135446Strhodes isc_result_totext(reqev->result)); 1947135446Strhodes seenerror = ISC_TRUE; 1948135446Strhodes goto done; 1949135446Strhodes } 1950135446Strhodes 1951135446Strhodes result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &answer); 1952135446Strhodes check_result(result, "dns_message_create"); 1953135446Strhodes result = dns_request_getresponse(request, answer, 1954135446Strhodes DNS_MESSAGEPARSE_PRESERVEORDER); 1955135446Strhodes switch (result) { 1956135446Strhodes case ISC_R_SUCCESS: 1957193149Sdougb if (answer->verify_attempted) 1958193149Sdougb ddebug("tsig verification successful"); 1959135446Strhodes break; 1960135446Strhodes case DNS_R_CLOCKSKEW: 1961135446Strhodes case DNS_R_EXPECTEDTSIG: 1962135446Strhodes case DNS_R_TSIGERRORSET: 1963135446Strhodes case DNS_R_TSIGVERIFYFAILURE: 1964135446Strhodes case DNS_R_UNEXPECTEDTSIG: 1965193149Sdougb case ISC_R_FAILURE: 1966193149Sdougb#if 0 1967193149Sdougb if (usegsstsig && answer->rcode == dns_rcode_noerror) { 1968193149Sdougb /* 1969193149Sdougb * For MS DNS that violates RFC 2845, section 4.2 1970193149Sdougb */ 1971193149Sdougb break; 1972193149Sdougb } 1973193149Sdougb#endif 1974135446Strhodes fprintf(stderr, "; TSIG error with server: %s\n", 1975135446Strhodes isc_result_totext(result)); 1976135446Strhodes seenerror = ISC_TRUE; 1977135446Strhodes break; 1978135446Strhodes default: 1979135446Strhodes check_result(result, "dns_request_getresponse"); 1980135446Strhodes } 1981135446Strhodes 1982135446Strhodes if (answer->rcode != dns_rcode_noerror) { 1983135446Strhodes seenerror = ISC_TRUE; 1984135446Strhodes if (!debugging) { 1985135446Strhodes char buf[64]; 1986135446Strhodes isc_buffer_t b; 1987135446Strhodes dns_rdataset_t *rds; 1988186462Sdougb 1989135446Strhodes isc_buffer_init(&b, buf, sizeof(buf) - 1); 1990135446Strhodes result = dns_rcode_totext(answer->rcode, &b); 1991135446Strhodes check_result(result, "dns_rcode_totext"); 1992135446Strhodes rds = dns_message_gettsig(answer, NULL); 1993135446Strhodes if (rds != NULL) 1994135446Strhodes check_tsig_error(rds, &b); 1995135446Strhodes fprintf(stderr, "update failed: %.*s\n", 1996135446Strhodes (int)isc_buffer_usedlength(&b), buf); 1997135446Strhodes } 1998135446Strhodes } 1999193149Sdougb if (debugging) 2000193149Sdougb show_message(stderr, answer, "\nReply from update query:"); 2001135446Strhodes 2002135446Strhodes done: 2003135446Strhodes dns_request_destroy(&request); 2004193149Sdougb if (usegsstsig) { 2005193149Sdougb dns_name_free(&tmpzonename, mctx); 2006193149Sdougb dns_name_free(&restart_master, mctx); 2007193149Sdougb } 2008135446Strhodes isc_event_free(&event); 2009135446Strhodes done_update(); 2010135446Strhodes} 2011135446Strhodes 2012135446Strhodesstatic void 2013135446Strhodessend_update(dns_name_t *zonename, isc_sockaddr_t *master, 2014135446Strhodes isc_sockaddr_t *srcaddr) 2015135446Strhodes{ 2016135446Strhodes isc_result_t result; 2017135446Strhodes dns_request_t *request = NULL; 2018135446Strhodes unsigned int options = 0; 2019135446Strhodes 2020135446Strhodes ddebug("send_update()"); 2021135446Strhodes 2022170222Sdougb setzone(zonename); 2023135446Strhodes 2024135446Strhodes if (usevc) 2025135446Strhodes options |= DNS_REQUESTOPT_TCP; 2026135446Strhodes if (tsigkey == NULL && sig0key != NULL) { 2027135446Strhodes result = dns_message_setsig0key(updatemsg, sig0key); 2028135446Strhodes check_result(result, "dns_message_setsig0key"); 2029135446Strhodes } 2030135446Strhodes if (debugging) { 2031135446Strhodes char addrbuf[ISC_SOCKADDR_FORMATSIZE]; 2032135446Strhodes 2033135446Strhodes isc_sockaddr_format(master, addrbuf, sizeof(addrbuf)); 2034135446Strhodes fprintf(stderr, "Sending update to %s\n", addrbuf); 2035135446Strhodes } 2036193149Sdougb 2037218384Sdougb /* Windows doesn't like the tsig name to be compressed. */ 2038218384Sdougb if (updatemsg->tsigname) 2039218384Sdougb updatemsg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS; 2040218384Sdougb 2041135446Strhodes result = dns_request_createvia3(requestmgr, updatemsg, srcaddr, 2042135446Strhodes master, options, tsigkey, timeout, 2043135446Strhodes udp_timeout, udp_retries, global_task, 2044135446Strhodes update_completed, NULL, &request); 2045135446Strhodes check_result(result, "dns_request_createvia3"); 2046135446Strhodes 2047135446Strhodes if (debugging) 2048193149Sdougb show_message(stdout, updatemsg, "Outgoing update query:"); 2049135446Strhodes 2050135446Strhodes requests++; 2051135446Strhodes} 2052135446Strhodes 2053135446Strhodesstatic void 2054135446Strhodesrecvsoa(isc_task_t *task, isc_event_t *event) { 2055135446Strhodes dns_requestevent_t *reqev = NULL; 2056135446Strhodes dns_request_t *request = NULL; 2057135446Strhodes isc_result_t result, eresult; 2058135446Strhodes dns_message_t *rcvmsg = NULL; 2059135446Strhodes dns_section_t section; 2060135446Strhodes dns_name_t *name = NULL; 2061135446Strhodes dns_rdataset_t *soaset = NULL; 2062135446Strhodes dns_rdata_soa_t soa; 2063135446Strhodes dns_rdata_t soarr = DNS_RDATA_INIT; 2064135446Strhodes int pass = 0; 2065135446Strhodes dns_name_t master; 2066135446Strhodes nsu_requestinfo_t *reqinfo; 2067135446Strhodes dns_message_t *soaquery = NULL; 2068135446Strhodes isc_sockaddr_t *addr; 2069135446Strhodes isc_boolean_t seencname = ISC_FALSE; 2070143731Sdougb dns_name_t tname; 2071143731Sdougb unsigned int nlabels; 2072135446Strhodes 2073135446Strhodes UNUSED(task); 2074135446Strhodes 2075135446Strhodes ddebug("recvsoa()"); 2076135446Strhodes 2077135446Strhodes requests--; 2078186462Sdougb 2079135446Strhodes REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE); 2080135446Strhodes reqev = (dns_requestevent_t *)event; 2081135446Strhodes request = reqev->request; 2082135446Strhodes eresult = reqev->result; 2083135446Strhodes reqinfo = reqev->ev_arg; 2084135446Strhodes soaquery = reqinfo->msg; 2085135446Strhodes addr = reqinfo->addr; 2086135446Strhodes 2087135446Strhodes if (shuttingdown) { 2088135446Strhodes dns_request_destroy(&request); 2089135446Strhodes dns_message_destroy(&soaquery); 2090135446Strhodes isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t)); 2091135446Strhodes isc_event_free(&event); 2092135446Strhodes maybeshutdown(); 2093135446Strhodes return; 2094135446Strhodes } 2095135446Strhodes 2096135446Strhodes if (eresult != ISC_R_SUCCESS) { 2097135446Strhodes char addrbuf[ISC_SOCKADDR_FORMATSIZE]; 2098135446Strhodes 2099135446Strhodes isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf)); 2100135446Strhodes fprintf(stderr, "; Communication with %s failed: %s\n", 2101193149Sdougb addrbuf, isc_result_totext(eresult)); 2102135446Strhodes if (userserver != NULL) 2103135446Strhodes fatal("could not talk to specified name server"); 2104135446Strhodes else if (++ns_inuse >= lwconf->nsnext) 2105135446Strhodes fatal("could not talk to any default name server"); 2106135446Strhodes ddebug("Destroying request [%p]", request); 2107135446Strhodes dns_request_destroy(&request); 2108135446Strhodes dns_message_renderreset(soaquery); 2109153816Sdougb dns_message_settsigkey(soaquery, NULL); 2110135446Strhodes sendrequest(localaddr, &servers[ns_inuse], soaquery, &request); 2111135446Strhodes isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t)); 2112135446Strhodes isc_event_free(&event); 2113135446Strhodes setzoneclass(dns_rdataclass_none); 2114135446Strhodes return; 2115135446Strhodes } 2116170222Sdougb 2117135446Strhodes isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t)); 2118170222Sdougb reqinfo = NULL; 2119135446Strhodes isc_event_free(&event); 2120135446Strhodes reqev = NULL; 2121135446Strhodes 2122135446Strhodes ddebug("About to create rcvmsg"); 2123135446Strhodes result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &rcvmsg); 2124135446Strhodes check_result(result, "dns_message_create"); 2125135446Strhodes result = dns_request_getresponse(request, rcvmsg, 2126135446Strhodes DNS_MESSAGEPARSE_PRESERVEORDER); 2127135446Strhodes if (result == DNS_R_TSIGERRORSET && userserver != NULL) { 2128135446Strhodes dns_message_destroy(&rcvmsg); 2129135446Strhodes ddebug("Destroying request [%p]", request); 2130135446Strhodes dns_request_destroy(&request); 2131135446Strhodes reqinfo = isc_mem_get(mctx, sizeof(nsu_requestinfo_t)); 2132135446Strhodes if (reqinfo == NULL) 2133135446Strhodes fatal("out of memory"); 2134135446Strhodes reqinfo->msg = soaquery; 2135135446Strhodes reqinfo->addr = addr; 2136135446Strhodes dns_message_renderreset(soaquery); 2137135446Strhodes ddebug("retrying soa request without TSIG"); 2138135446Strhodes result = dns_request_createvia3(requestmgr, soaquery, 2139135446Strhodes localaddr, addr, 0, NULL, 2140135446Strhodes FIND_TIMEOUT * 20, 2141165071Sdougb FIND_TIMEOUT, 3, 2142135446Strhodes global_task, recvsoa, reqinfo, 2143135446Strhodes &request); 2144135446Strhodes check_result(result, "dns_request_createvia"); 2145135446Strhodes requests++; 2146135446Strhodes return; 2147135446Strhodes } 2148135446Strhodes check_result(result, "dns_request_getresponse"); 2149135446Strhodes section = DNS_SECTION_ANSWER; 2150193149Sdougb if (debugging) 2151193149Sdougb show_message(stderr, rcvmsg, "Reply from SOA query:"); 2152135446Strhodes 2153135446Strhodes if (rcvmsg->rcode != dns_rcode_noerror && 2154135446Strhodes rcvmsg->rcode != dns_rcode_nxdomain) 2155135446Strhodes fatal("response to SOA query was unsuccessful"); 2156135446Strhodes 2157170222Sdougb if (userzone != NULL && rcvmsg->rcode == dns_rcode_nxdomain) { 2158170222Sdougb char namebuf[DNS_NAME_FORMATSIZE]; 2159170222Sdougb dns_name_format(userzone, namebuf, sizeof(namebuf)); 2160170222Sdougb error("specified zone '%s' does not exist (NXDOMAIN)", 2161170222Sdougb namebuf); 2162170222Sdougb dns_message_destroy(&rcvmsg); 2163170222Sdougb dns_request_destroy(&request); 2164170222Sdougb dns_message_destroy(&soaquery); 2165170222Sdougb ddebug("Out of recvsoa"); 2166170222Sdougb done_update(); 2167170222Sdougb return; 2168170222Sdougb } 2169170222Sdougb 2170135446Strhodes lookforsoa: 2171135446Strhodes if (pass == 0) 2172135446Strhodes section = DNS_SECTION_ANSWER; 2173135446Strhodes else if (pass == 1) 2174135446Strhodes section = DNS_SECTION_AUTHORITY; 2175186462Sdougb else 2176143731Sdougb goto droplabel; 2177135446Strhodes 2178135446Strhodes result = dns_message_firstname(rcvmsg, section); 2179135446Strhodes if (result != ISC_R_SUCCESS) { 2180135446Strhodes pass++; 2181135446Strhodes goto lookforsoa; 2182135446Strhodes } 2183135446Strhodes while (result == ISC_R_SUCCESS) { 2184135446Strhodes name = NULL; 2185135446Strhodes dns_message_currentname(rcvmsg, section, &name); 2186135446Strhodes soaset = NULL; 2187135446Strhodes result = dns_message_findtype(name, dns_rdatatype_soa, 0, 2188135446Strhodes &soaset); 2189135446Strhodes if (result == ISC_R_SUCCESS) 2190135446Strhodes break; 2191135446Strhodes if (section == DNS_SECTION_ANSWER) { 2192135446Strhodes dns_rdataset_t *tset = NULL; 2193135446Strhodes if (dns_message_findtype(name, dns_rdatatype_cname, 0, 2194193149Sdougb &tset) == ISC_R_SUCCESS || 2195135446Strhodes dns_message_findtype(name, dns_rdatatype_dname, 0, 2196193149Sdougb &tset) == ISC_R_SUCCESS ) { 2197135446Strhodes seencname = ISC_TRUE; 2198135446Strhodes break; 2199135446Strhodes } 2200135446Strhodes } 2201186462Sdougb 2202135446Strhodes result = dns_message_nextname(rcvmsg, section); 2203135446Strhodes } 2204135446Strhodes 2205135446Strhodes if (soaset == NULL && !seencname) { 2206135446Strhodes pass++; 2207135446Strhodes goto lookforsoa; 2208135446Strhodes } 2209135446Strhodes 2210143731Sdougb if (seencname) 2211143731Sdougb goto droplabel; 2212135446Strhodes 2213135446Strhodes if (debugging) { 2214135446Strhodes char namestr[DNS_NAME_FORMATSIZE]; 2215135446Strhodes dns_name_format(name, namestr, sizeof(namestr)); 2216135446Strhodes fprintf(stderr, "Found zone name: %s\n", namestr); 2217135446Strhodes } 2218135446Strhodes 2219135446Strhodes result = dns_rdataset_first(soaset); 2220135446Strhodes check_result(result, "dns_rdataset_first"); 2221135446Strhodes 2222135446Strhodes dns_rdata_init(&soarr); 2223135446Strhodes dns_rdataset_current(soaset, &soarr); 2224135446Strhodes result = dns_rdata_tostruct(&soarr, &soa, NULL); 2225135446Strhodes check_result(result, "dns_rdata_tostruct"); 2226135446Strhodes 2227135446Strhodes dns_name_init(&master, NULL); 2228135446Strhodes dns_name_clone(&soa.origin, &master); 2229135446Strhodes 2230135446Strhodes if (userzone != NULL) 2231135446Strhodes zonename = userzone; 2232135446Strhodes else 2233135446Strhodes zonename = name; 2234135446Strhodes 2235135446Strhodes if (debugging) { 2236135446Strhodes char namestr[DNS_NAME_FORMATSIZE]; 2237135446Strhodes dns_name_format(&master, namestr, sizeof(namestr)); 2238135446Strhodes fprintf(stderr, "The master is: %s\n", namestr); 2239135446Strhodes } 2240135446Strhodes 2241135446Strhodes if (userserver != NULL) 2242135446Strhodes serveraddr = userserver; 2243135446Strhodes else { 2244135446Strhodes char serverstr[DNS_NAME_MAXTEXT+1]; 2245135446Strhodes isc_buffer_t buf; 2246135446Strhodes 2247135446Strhodes isc_buffer_init(&buf, serverstr, sizeof(serverstr)); 2248135446Strhodes result = dns_name_totext(&master, ISC_TRUE, &buf); 2249135446Strhodes check_result(result, "dns_name_totext"); 2250135446Strhodes serverstr[isc_buffer_usedlength(&buf)] = 0; 2251135446Strhodes get_address(serverstr, DNSDEFAULTPORT, &tempaddr); 2252135446Strhodes serveraddr = &tempaddr; 2253135446Strhodes } 2254143731Sdougb dns_rdata_freestruct(&soa); 2255135446Strhodes 2256193149Sdougb#ifdef GSSAPI 2257193149Sdougb if (usegsstsig) { 2258193149Sdougb dns_name_init(&tmpzonename, NULL); 2259193149Sdougb dns_name_dup(zonename, mctx, &tmpzonename); 2260193149Sdougb dns_name_init(&restart_master, NULL); 2261193149Sdougb dns_name_dup(&master, mctx, &restart_master); 2262193149Sdougb start_gssrequest(&master); 2263193149Sdougb } else { 2264193149Sdougb send_update(zonename, serveraddr, localaddr); 2265193149Sdougb setzoneclass(dns_rdataclass_none); 2266193149Sdougb } 2267193149Sdougb#else 2268135446Strhodes send_update(zonename, serveraddr, localaddr); 2269143731Sdougb setzoneclass(dns_rdataclass_none); 2270193149Sdougb#endif 2271135446Strhodes 2272135446Strhodes dns_message_destroy(&soaquery); 2273135446Strhodes dns_request_destroy(&request); 2274135446Strhodes 2275135446Strhodes out: 2276135446Strhodes dns_message_destroy(&rcvmsg); 2277135446Strhodes ddebug("Out of recvsoa"); 2278143731Sdougb return; 2279186462Sdougb 2280143731Sdougb droplabel: 2281143731Sdougb result = dns_message_firstname(soaquery, DNS_SECTION_QUESTION); 2282143731Sdougb INSIST(result == ISC_R_SUCCESS); 2283143731Sdougb name = NULL; 2284143731Sdougb dns_message_currentname(soaquery, DNS_SECTION_QUESTION, &name); 2285143731Sdougb nlabels = dns_name_countlabels(name); 2286143731Sdougb if (nlabels == 1) 2287143731Sdougb fatal("could not find enclosing zone"); 2288143731Sdougb dns_name_init(&tname, NULL); 2289143731Sdougb dns_name_getlabelsequence(name, 1, nlabels - 1, &tname); 2290143731Sdougb dns_name_clone(&tname, name); 2291143731Sdougb dns_request_destroy(&request); 2292143731Sdougb dns_message_renderreset(soaquery); 2293153816Sdougb dns_message_settsigkey(soaquery, NULL); 2294143731Sdougb if (userserver != NULL) 2295143731Sdougb sendrequest(localaddr, userserver, soaquery, &request); 2296143731Sdougb else 2297193149Sdougb sendrequest(localaddr, &servers[ns_inuse], soaquery, &request); 2298143731Sdougb goto out; 2299135446Strhodes} 2300135446Strhodes 2301135446Strhodesstatic void 2302135446Strhodessendrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, 2303135446Strhodes dns_message_t *msg, dns_request_t **request) 2304135446Strhodes{ 2305135446Strhodes isc_result_t result; 2306135446Strhodes nsu_requestinfo_t *reqinfo; 2307135446Strhodes 2308135446Strhodes reqinfo = isc_mem_get(mctx, sizeof(nsu_requestinfo_t)); 2309135446Strhodes if (reqinfo == NULL) 2310135446Strhodes fatal("out of memory"); 2311135446Strhodes reqinfo->msg = msg; 2312135446Strhodes reqinfo->addr = destaddr; 2313135446Strhodes result = dns_request_createvia3(requestmgr, msg, srcaddr, destaddr, 0, 2314135446Strhodes (userserver != NULL) ? tsigkey : NULL, 2315135446Strhodes FIND_TIMEOUT * 20, FIND_TIMEOUT, 3, 2316135446Strhodes global_task, recvsoa, reqinfo, request); 2317135446Strhodes check_result(result, "dns_request_createvia"); 2318135446Strhodes requests++; 2319135446Strhodes} 2320135446Strhodes 2321193149Sdougb#ifdef GSSAPI 2322135446Strhodesstatic void 2323193149Sdougbstart_gssrequest(dns_name_t *master) 2324193149Sdougb{ 2325193149Sdougb gss_ctx_id_t context; 2326193149Sdougb isc_buffer_t buf; 2327193149Sdougb isc_result_t result; 2328193149Sdougb isc_uint32_t val = 0; 2329193149Sdougb dns_message_t *rmsg; 2330193149Sdougb dns_request_t *request = NULL; 2331193149Sdougb dns_name_t *servname; 2332193149Sdougb dns_fixedname_t fname; 2333193149Sdougb char namestr[DNS_NAME_FORMATSIZE]; 2334193149Sdougb char keystr[DNS_NAME_FORMATSIZE]; 2335193149Sdougb 2336193149Sdougb debug("start_gssrequest"); 2337193149Sdougb usevc = ISC_TRUE; 2338193149Sdougb 2339193149Sdougb if (gssring != NULL) 2340193149Sdougb dns_tsigkeyring_destroy(&gssring); 2341193149Sdougb gssring = NULL; 2342193149Sdougb result = dns_tsigkeyring_create(mctx, &gssring); 2343193149Sdougb 2344193149Sdougb if (result != ISC_R_SUCCESS) 2345193149Sdougb fatal("dns_tsigkeyring_create failed: %s", 2346193149Sdougb isc_result_totext(result)); 2347193149Sdougb 2348193149Sdougb dns_name_format(master, namestr, sizeof(namestr)); 2349193149Sdougb if (kserver == NULL) { 2350193149Sdougb kserver = isc_mem_get(mctx, sizeof(isc_sockaddr_t)); 2351193149Sdougb if (kserver == NULL) 2352193149Sdougb fatal("out of memory"); 2353193149Sdougb } 2354193149Sdougb if (userserver == NULL) 2355193149Sdougb get_address(namestr, DNSDEFAULTPORT, kserver); 2356193149Sdougb else 2357193149Sdougb (void)memcpy(kserver, userserver, sizeof(isc_sockaddr_t)); 2358193149Sdougb 2359193149Sdougb dns_fixedname_init(&fname); 2360193149Sdougb servname = dns_fixedname_name(&fname); 2361193149Sdougb 2362193149Sdougb result = isc_string_printf(servicename, sizeof(servicename), 2363218384Sdougb "DNS/%s%s", namestr, realm ? realm : ""); 2364193149Sdougb if (result != ISC_R_SUCCESS) 2365193149Sdougb fatal("isc_string_printf(servicename) failed: %s", 2366193149Sdougb isc_result_totext(result)); 2367193149Sdougb isc_buffer_init(&buf, servicename, strlen(servicename)); 2368193149Sdougb isc_buffer_add(&buf, strlen(servicename)); 2369193149Sdougb result = dns_name_fromtext(servname, &buf, dns_rootname, 2370193149Sdougb ISC_FALSE, NULL); 2371193149Sdougb if (result != ISC_R_SUCCESS) 2372193149Sdougb fatal("dns_name_fromtext(servname) failed: %s", 2373193149Sdougb isc_result_totext(result)); 2374193149Sdougb 2375193149Sdougb dns_fixedname_init(&fkname); 2376193149Sdougb keyname = dns_fixedname_name(&fkname); 2377193149Sdougb 2378193149Sdougb isc_random_get(&val); 2379193149Sdougb result = isc_string_printf(keystr, sizeof(keystr), "%u.sig-%s", 2380193149Sdougb val, namestr); 2381193149Sdougb if (result != ISC_R_SUCCESS) 2382193149Sdougb fatal("isc_string_printf(keystr) failed: %s", 2383193149Sdougb isc_result_totext(result)); 2384193149Sdougb isc_buffer_init(&buf, keystr, strlen(keystr)); 2385193149Sdougb isc_buffer_add(&buf, strlen(keystr)); 2386193149Sdougb 2387193149Sdougb result = dns_name_fromtext(keyname, &buf, dns_rootname, 2388193149Sdougb ISC_FALSE, NULL); 2389193149Sdougb if (result != ISC_R_SUCCESS) 2390193149Sdougb fatal("dns_name_fromtext(keyname) failed: %s", 2391193149Sdougb isc_result_totext(result)); 2392193149Sdougb 2393193149Sdougb /* Windows doesn't recognize name compression in the key name. */ 2394193149Sdougb keyname->attributes |= DNS_NAMEATTR_NOCOMPRESS; 2395193149Sdougb 2396193149Sdougb rmsg = NULL; 2397193149Sdougb result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &rmsg); 2398193149Sdougb if (result != ISC_R_SUCCESS) 2399193149Sdougb fatal("dns_message_create failed: %s", 2400193149Sdougb isc_result_totext(result)); 2401193149Sdougb 2402193149Sdougb /* Build first request. */ 2403193149Sdougb context = GSS_C_NO_CONTEXT; 2404193149Sdougb result = dns_tkey_buildgssquery(rmsg, keyname, servname, NULL, 0, 2405193149Sdougb &context, use_win2k_gsstsig); 2406193149Sdougb if (result == ISC_R_FAILURE) 2407193149Sdougb fatal("Check your Kerberos ticket, it may have expired."); 2408193149Sdougb if (result != ISC_R_SUCCESS) 2409193149Sdougb fatal("dns_tkey_buildgssquery failed: %s", 2410193149Sdougb isc_result_totext(result)); 2411193149Sdougb 2412193149Sdougb send_gssrequest(localaddr, kserver, rmsg, &request, context); 2413193149Sdougb} 2414193149Sdougb 2415193149Sdougbstatic void 2416193149Sdougbsend_gssrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, 2417193149Sdougb dns_message_t *msg, dns_request_t **request, 2418193149Sdougb gss_ctx_id_t context) 2419193149Sdougb{ 2420193149Sdougb isc_result_t result; 2421193149Sdougb nsu_gssinfo_t *reqinfo; 2422193149Sdougb unsigned int options = 0; 2423193149Sdougb 2424193149Sdougb debug("send_gssrequest"); 2425193149Sdougb reqinfo = isc_mem_get(mctx, sizeof(nsu_gssinfo_t)); 2426193149Sdougb if (reqinfo == NULL) 2427193149Sdougb fatal("out of memory"); 2428193149Sdougb reqinfo->msg = msg; 2429193149Sdougb reqinfo->addr = destaddr; 2430193149Sdougb reqinfo->context = context; 2431193149Sdougb 2432193149Sdougb options |= DNS_REQUESTOPT_TCP; 2433193149Sdougb result = dns_request_createvia3(requestmgr, msg, srcaddr, destaddr, 2434193149Sdougb options, tsigkey, FIND_TIMEOUT * 20, 2435193149Sdougb FIND_TIMEOUT, 3, global_task, recvgss, 2436193149Sdougb reqinfo, request); 2437193149Sdougb check_result(result, "dns_request_createvia3"); 2438193149Sdougb if (debugging) 2439193149Sdougb show_message(stdout, msg, "Outgoing update query:"); 2440193149Sdougb requests++; 2441193149Sdougb} 2442193149Sdougb 2443193149Sdougbstatic void 2444193149Sdougbrecvgss(isc_task_t *task, isc_event_t *event) { 2445193149Sdougb dns_requestevent_t *reqev = NULL; 2446193149Sdougb dns_request_t *request = NULL; 2447193149Sdougb isc_result_t result, eresult; 2448193149Sdougb dns_message_t *rcvmsg = NULL; 2449193149Sdougb nsu_gssinfo_t *reqinfo; 2450193149Sdougb dns_message_t *tsigquery = NULL; 2451193149Sdougb isc_sockaddr_t *addr; 2452193149Sdougb gss_ctx_id_t context; 2453193149Sdougb isc_buffer_t buf; 2454193149Sdougb dns_name_t *servname; 2455193149Sdougb dns_fixedname_t fname; 2456193149Sdougb 2457193149Sdougb UNUSED(task); 2458193149Sdougb 2459193149Sdougb ddebug("recvgss()"); 2460193149Sdougb 2461193149Sdougb requests--; 2462193149Sdougb 2463193149Sdougb REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE); 2464193149Sdougb reqev = (dns_requestevent_t *)event; 2465193149Sdougb request = reqev->request; 2466193149Sdougb eresult = reqev->result; 2467193149Sdougb reqinfo = reqev->ev_arg; 2468193149Sdougb tsigquery = reqinfo->msg; 2469193149Sdougb context = reqinfo->context; 2470193149Sdougb addr = reqinfo->addr; 2471193149Sdougb 2472193149Sdougb if (shuttingdown) { 2473193149Sdougb dns_request_destroy(&request); 2474193149Sdougb dns_message_destroy(&tsigquery); 2475193149Sdougb isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_t)); 2476193149Sdougb isc_event_free(&event); 2477193149Sdougb maybeshutdown(); 2478193149Sdougb return; 2479193149Sdougb } 2480193149Sdougb 2481193149Sdougb if (eresult != ISC_R_SUCCESS) { 2482193149Sdougb char addrbuf[ISC_SOCKADDR_FORMATSIZE]; 2483193149Sdougb 2484193149Sdougb isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf)); 2485193149Sdougb fprintf(stderr, "; Communication with %s failed: %s\n", 2486193149Sdougb addrbuf, isc_result_totext(eresult)); 2487193149Sdougb if (userserver != NULL) 2488193149Sdougb fatal("could not talk to specified name server"); 2489193149Sdougb else if (++ns_inuse >= lwconf->nsnext) 2490193149Sdougb fatal("could not talk to any default name server"); 2491193149Sdougb ddebug("Destroying request [%p]", request); 2492193149Sdougb dns_request_destroy(&request); 2493193149Sdougb dns_message_renderreset(tsigquery); 2494193149Sdougb sendrequest(localaddr, &servers[ns_inuse], tsigquery, 2495193149Sdougb &request); 2496193149Sdougb isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_t)); 2497193149Sdougb isc_event_free(&event); 2498193149Sdougb return; 2499193149Sdougb } 2500193149Sdougb isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_t)); 2501193149Sdougb 2502193149Sdougb isc_event_free(&event); 2503193149Sdougb reqev = NULL; 2504193149Sdougb 2505193149Sdougb ddebug("recvgss creating rcvmsg"); 2506193149Sdougb result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &rcvmsg); 2507193149Sdougb check_result(result, "dns_message_create"); 2508193149Sdougb 2509193149Sdougb result = dns_request_getresponse(request, rcvmsg, 2510193149Sdougb DNS_MESSAGEPARSE_PRESERVEORDER); 2511193149Sdougb check_result(result, "dns_request_getresponse"); 2512193149Sdougb 2513193149Sdougb if (debugging) 2514193149Sdougb show_message(stderr, rcvmsg, 2515193149Sdougb "recvmsg reply from GSS-TSIG query"); 2516193149Sdougb 2517193149Sdougb if (rcvmsg->rcode == dns_rcode_formerr && !tried_other_gsstsig) { 2518193149Sdougb ddebug("recvgss trying %s GSS-TSIG", 2519193149Sdougb use_win2k_gsstsig ? "Standard" : "Win2k"); 2520193149Sdougb if (use_win2k_gsstsig) 2521193149Sdougb use_win2k_gsstsig = ISC_FALSE; 2522193149Sdougb else 2523193149Sdougb use_win2k_gsstsig = ISC_TRUE; 2524193149Sdougb tried_other_gsstsig = ISC_TRUE; 2525193149Sdougb start_gssrequest(&restart_master); 2526193149Sdougb goto done; 2527193149Sdougb } 2528193149Sdougb 2529193149Sdougb if (rcvmsg->rcode != dns_rcode_noerror && 2530193149Sdougb rcvmsg->rcode != dns_rcode_nxdomain) 2531193149Sdougb fatal("response to GSS-TSIG query was unsuccessful"); 2532193149Sdougb 2533193149Sdougb 2534193149Sdougb dns_fixedname_init(&fname); 2535193149Sdougb servname = dns_fixedname_name(&fname); 2536193149Sdougb isc_buffer_init(&buf, servicename, strlen(servicename)); 2537193149Sdougb isc_buffer_add(&buf, strlen(servicename)); 2538193149Sdougb result = dns_name_fromtext(servname, &buf, dns_rootname, 2539193149Sdougb ISC_FALSE, NULL); 2540193149Sdougb check_result(result, "dns_name_fromtext"); 2541193149Sdougb 2542193149Sdougb tsigkey = NULL; 2543193149Sdougb result = dns_tkey_gssnegotiate(tsigquery, rcvmsg, servname, 2544193149Sdougb &context, &tsigkey, gssring, 2545193149Sdougb use_win2k_gsstsig); 2546193149Sdougb switch (result) { 2547193149Sdougb 2548193149Sdougb case DNS_R_CONTINUE: 2549193149Sdougb send_gssrequest(localaddr, kserver, tsigquery, &request, 2550193149Sdougb context); 2551193149Sdougb break; 2552193149Sdougb 2553193149Sdougb case ISC_R_SUCCESS: 2554193149Sdougb /* 2555193149Sdougb * XXXSRA Waaay too much fun here. There's no good 2556193149Sdougb * reason why we need a TSIG here (the people who put 2557193149Sdougb * it into the spec admitted at the time that it was 2558193149Sdougb * not a security issue), and Windows clients don't 2559193149Sdougb * seem to work if named complies with the spec and 2560193149Sdougb * includes the gratuitous TSIG. So we're in the 2561193149Sdougb * bizarre situation of having to choose between 2562193149Sdougb * complying with a useless requirement in the spec 2563193149Sdougb * and interoperating. This is nuts. If we can 2564193149Sdougb * confirm this behavior, we should ask the WG to 2565193149Sdougb * consider removing the requirement for the 2566193149Sdougb * gratuitous TSIG here. For the moment, we ignore 2567193149Sdougb * the TSIG -- this too is a spec violation, but it's 2568193149Sdougb * the least insane thing to do. 2569193149Sdougb */ 2570193149Sdougb#if 0 2571193149Sdougb /* 2572193149Sdougb * Verify the signature. 2573193149Sdougb */ 2574193149Sdougb rcvmsg->state = DNS_SECTION_ANY; 2575193149Sdougb dns_message_setquerytsig(rcvmsg, NULL); 2576193149Sdougb result = dns_message_settsigkey(rcvmsg, tsigkey); 2577193149Sdougb check_result(result, "dns_message_settsigkey"); 2578193149Sdougb result = dns_message_checksig(rcvmsg, NULL); 2579193149Sdougb ddebug("tsig verification: %s", dns_result_totext(result)); 2580193149Sdougb check_result(result, "dns_message_checksig"); 2581193149Sdougb#endif /* 0 */ 2582193149Sdougb 2583193149Sdougb send_update(&tmpzonename, serveraddr, localaddr); 2584193149Sdougb setzoneclass(dns_rdataclass_none); 2585193149Sdougb break; 2586193149Sdougb 2587193149Sdougb default: 2588193149Sdougb fatal("dns_tkey_negotiategss: %s", isc_result_totext(result)); 2589193149Sdougb } 2590193149Sdougb 2591193149Sdougb done: 2592193149Sdougb dns_request_destroy(&request); 2593193149Sdougb dns_message_destroy(&tsigquery); 2594193149Sdougb 2595193149Sdougb dns_message_destroy(&rcvmsg); 2596193149Sdougb ddebug("Out of recvgss"); 2597193149Sdougb} 2598193149Sdougb#endif 2599193149Sdougb 2600193149Sdougbstatic void 2601135446Strhodesstart_update(void) { 2602135446Strhodes isc_result_t result; 2603135446Strhodes dns_rdataset_t *rdataset = NULL; 2604135446Strhodes dns_name_t *name = NULL; 2605135446Strhodes dns_request_t *request = NULL; 2606135446Strhodes dns_message_t *soaquery = NULL; 2607135446Strhodes dns_name_t *firstname; 2608135446Strhodes dns_section_t section = DNS_SECTION_UPDATE; 2609135446Strhodes 2610135446Strhodes ddebug("start_update()"); 2611135446Strhodes 2612135446Strhodes if (answer != NULL) 2613135446Strhodes dns_message_destroy(&answer); 2614135446Strhodes 2615193149Sdougb if (userzone != NULL && userserver != NULL && ! usegsstsig) { 2616135446Strhodes send_update(userzone, userserver, localaddr); 2617135446Strhodes setzoneclass(dns_rdataclass_none); 2618135446Strhodes return; 2619135446Strhodes } 2620135446Strhodes 2621135446Strhodes result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, 2622135446Strhodes &soaquery); 2623135446Strhodes check_result(result, "dns_message_create"); 2624135446Strhodes 2625170222Sdougb if (userserver == NULL) 2626170222Sdougb soaquery->flags |= DNS_MESSAGEFLAG_RD; 2627135446Strhodes 2628135446Strhodes result = dns_message_gettempname(soaquery, &name); 2629135446Strhodes check_result(result, "dns_message_gettempname"); 2630135446Strhodes 2631135446Strhodes result = dns_message_gettemprdataset(soaquery, &rdataset); 2632135446Strhodes check_result(result, "dns_message_gettemprdataset"); 2633135446Strhodes 2634135446Strhodes dns_rdataset_makequestion(rdataset, getzoneclass(), dns_rdatatype_soa); 2635135446Strhodes 2636170222Sdougb if (userzone != NULL) { 2637170222Sdougb dns_name_init(name, NULL); 2638170222Sdougb dns_name_clone(userzone, name); 2639170222Sdougb } else { 2640218384Sdougb dns_rdataset_t *tmprdataset; 2641170222Sdougb result = dns_message_firstname(updatemsg, section); 2642170222Sdougb if (result == ISC_R_NOMORE) { 2643170222Sdougb section = DNS_SECTION_PREREQUISITE; 2644170222Sdougb result = dns_message_firstname(updatemsg, section); 2645170222Sdougb } 2646170222Sdougb if (result != ISC_R_SUCCESS) { 2647174187Sdougb dns_message_puttempname(soaquery, &name); 2648174187Sdougb dns_rdataset_disassociate(rdataset); 2649174187Sdougb dns_message_puttemprdataset(soaquery, &rdataset); 2650174187Sdougb dns_message_destroy(&soaquery); 2651170222Sdougb done_update(); 2652170222Sdougb return; 2653170222Sdougb } 2654170222Sdougb firstname = NULL; 2655170222Sdougb dns_message_currentname(updatemsg, section, &firstname); 2656170222Sdougb dns_name_init(name, NULL); 2657170222Sdougb dns_name_clone(firstname, name); 2658218384Sdougb /* 2659218384Sdougb * Looks to see if the first name references a DS record 2660218384Sdougb * and if that name is not the root remove a label as DS 2661218384Sdougb * records live in the parent zone so we need to start our 2662218384Sdougb * search one label up. 2663218384Sdougb */ 2664218384Sdougb tmprdataset = ISC_LIST_HEAD(firstname->list); 2665218384Sdougb if (section == DNS_SECTION_UPDATE && 2666218384Sdougb !dns_name_equal(firstname, dns_rootname) && 2667218384Sdougb tmprdataset->type == dns_rdatatype_ds) { 2668218384Sdougb unsigned int labels = dns_name_countlabels(name); 2669218384Sdougb dns_name_getlabelsequence(name, 1, labels - 1, name); 2670218384Sdougb } 2671170222Sdougb } 2672135446Strhodes 2673135446Strhodes ISC_LIST_INIT(name->list); 2674135446Strhodes ISC_LIST_APPEND(name->list, rdataset, link); 2675135446Strhodes dns_message_addname(soaquery, name, DNS_SECTION_QUESTION); 2676135446Strhodes 2677135446Strhodes if (userserver != NULL) 2678135446Strhodes sendrequest(localaddr, userserver, soaquery, &request); 2679135446Strhodes else { 2680135446Strhodes ns_inuse = 0; 2681135446Strhodes sendrequest(localaddr, &servers[ns_inuse], soaquery, &request); 2682135446Strhodes } 2683135446Strhodes} 2684135446Strhodes 2685135446Strhodesstatic void 2686135446Strhodescleanup(void) { 2687135446Strhodes ddebug("cleanup()"); 2688135446Strhodes 2689135446Strhodes if (answer != NULL) 2690135446Strhodes dns_message_destroy(&answer); 2691193149Sdougb 2692193149Sdougb#ifdef GSSAPI 2693193149Sdougb if (tsigkey != NULL) { 2694193149Sdougb ddebug("detach tsigkey x%p", tsigkey); 2695193149Sdougb dns_tsigkey_detach(&tsigkey); 2696193149Sdougb } 2697193149Sdougb if (gssring != NULL) { 2698193149Sdougb ddebug("Destroying GSS-TSIG keyring"); 2699193149Sdougb dns_tsigkeyring_destroy(&gssring); 2700193149Sdougb } 2701193149Sdougb if (kserver != NULL) { 2702193149Sdougb isc_mem_put(mctx, kserver, sizeof(isc_sockaddr_t)); 2703193149Sdougb kserver = NULL; 2704193149Sdougb } 2705218384Sdougb if (realm != NULL) { 2706218384Sdougb isc_mem_free(mctx, realm); 2707218384Sdougb realm = NULL; 2708218384Sdougb } 2709193149Sdougb#endif 2710193149Sdougb 2711135446Strhodes ddebug("Shutting down task manager"); 2712135446Strhodes isc_taskmgr_destroy(&taskmgr); 2713135446Strhodes 2714135446Strhodes ddebug("Destroying event"); 2715135446Strhodes isc_event_free(&global_event); 2716135446Strhodes 2717135446Strhodes ddebug("Shutting down socket manager"); 2718135446Strhodes isc_socketmgr_destroy(&socketmgr); 2719135446Strhodes 2720135446Strhodes ddebug("Shutting down timer manager"); 2721135446Strhodes isc_timermgr_destroy(&timermgr); 2722135446Strhodes 2723135446Strhodes ddebug("Destroying hash context"); 2724135446Strhodes isc_hash_destroy(); 2725135446Strhodes 2726170222Sdougb ddebug("Destroying name state"); 2727170222Sdougb dns_name_destroy(); 2728170222Sdougb 2729193149Sdougb ddebug("Removing log context"); 2730193149Sdougb isc_log_destroy(&lctx); 2731193149Sdougb 2732135446Strhodes ddebug("Destroying memory context"); 2733135446Strhodes if (memdebugging) 2734135446Strhodes isc_mem_stats(mctx, stderr); 2735135446Strhodes isc_mem_destroy(&mctx); 2736135446Strhodes} 2737135446Strhodes 2738135446Strhodesstatic void 2739135446Strhodesgetinput(isc_task_t *task, isc_event_t *event) { 2740135446Strhodes isc_boolean_t more; 2741135446Strhodes 2742135446Strhodes UNUSED(task); 2743135446Strhodes 2744135446Strhodes if (shuttingdown) { 2745135446Strhodes maybeshutdown(); 2746135446Strhodes return; 2747135446Strhodes } 2748135446Strhodes 2749135446Strhodes if (global_event == NULL) 2750135446Strhodes global_event = event; 2751135446Strhodes 2752135446Strhodes reset_system(); 2753135446Strhodes more = user_interaction(); 2754135446Strhodes if (!more) { 2755135446Strhodes isc_app_shutdown(); 2756135446Strhodes return; 2757135446Strhodes } 2758135446Strhodes start_update(); 2759135446Strhodes return; 2760135446Strhodes} 2761135446Strhodes 2762135446Strhodesint 2763135446Strhodesmain(int argc, char **argv) { 2764135446Strhodes isc_result_t result; 2765135446Strhodes style = &dns_master_style_debug; 2766135446Strhodes 2767135446Strhodes input = stdin; 2768135446Strhodes 2769135446Strhodes interactive = ISC_TF(isatty(0)); 2770135446Strhodes 2771135446Strhodes isc_app_start(); 2772135446Strhodes 2773193149Sdougb pre_parse_args(argc, argv); 2774135446Strhodes 2775193149Sdougb result = isc_mem_create(0, 0, &mctx); 2776193149Sdougb check_result(result, "isc_mem_create"); 2777193149Sdougb 2778193149Sdougb parse_args(argc, argv, mctx, &entropy); 2779193149Sdougb 2780135446Strhodes setup_system(); 2781135446Strhodes 2782135446Strhodes result = isc_app_onrun(mctx, global_task, getinput, NULL); 2783135446Strhodes check_result(result, "isc_app_onrun"); 2784135446Strhodes 2785135446Strhodes (void)isc_app_run(); 2786135446Strhodes 2787135446Strhodes cleanup(); 2788135446Strhodes 2789135446Strhodes isc_app_finish(); 2790135446Strhodes 2791135446Strhodes if (seenerror) 2792135446Strhodes return (2); 2793135446Strhodes else 2794135446Strhodes return (0); 2795135446Strhodes} 2796