nsupdate.c revision 225361
1135446Strhodes/* 2224092Sdougb * Copyright (C) 2004-2011 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 18225361Sdougb/* $Id: nsupdate.c,v 1.193.12.3 2011-05-23 22:12:14 each 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> 36224092Sdougb#include <isc/file.h> 37135446Strhodes#include <isc/hash.h> 38135446Strhodes#include <isc/lex.h> 39193149Sdougb#include <isc/log.h> 40135446Strhodes#include <isc/mem.h> 41135446Strhodes#include <isc/parseint.h> 42218384Sdougb#include <isc/print.h> 43193149Sdougb#include <isc/random.h> 44135446Strhodes#include <isc/region.h> 45135446Strhodes#include <isc/sockaddr.h> 46135446Strhodes#include <isc/socket.h> 47135446Strhodes#include <isc/stdio.h> 48135446Strhodes#include <isc/string.h> 49135446Strhodes#include <isc/task.h> 50135446Strhodes#include <isc/timer.h> 51135446Strhodes#include <isc/types.h> 52135446Strhodes#include <isc/util.h> 53135446Strhodes 54224092Sdougb#include <isccfg/namedconf.h> 55224092Sdougb 56135446Strhodes#include <dns/callbacks.h> 57135446Strhodes#include <dns/dispatch.h> 58135446Strhodes#include <dns/dnssec.h> 59135446Strhodes#include <dns/events.h> 60135446Strhodes#include <dns/fixedname.h> 61193149Sdougb#include <dns/log.h> 62135446Strhodes#include <dns/masterdump.h> 63135446Strhodes#include <dns/message.h> 64135446Strhodes#include <dns/name.h> 65135446Strhodes#include <dns/rcode.h> 66135446Strhodes#include <dns/rdata.h> 67135446Strhodes#include <dns/rdataclass.h> 68135446Strhodes#include <dns/rdatalist.h> 69135446Strhodes#include <dns/rdataset.h> 70135446Strhodes#include <dns/rdatastruct.h> 71135446Strhodes#include <dns/rdatatype.h> 72135446Strhodes#include <dns/request.h> 73135446Strhodes#include <dns/result.h> 74193149Sdougb#include <dns/tkey.h> 75135446Strhodes#include <dns/tsig.h> 76135446Strhodes 77135446Strhodes#include <dst/dst.h> 78135446Strhodes 79135446Strhodes#include <lwres/lwres.h> 80135446Strhodes#include <lwres/net.h> 81135446Strhodes 82193149Sdougb#ifdef GSSAPI 83193149Sdougb#include <dst/gssapi.h> 84224092Sdougb#include ISC_PLATFORM_KRB5HEADER 85193149Sdougb#endif 86135446Strhodes#include <bind9/getaddresses.h> 87135446Strhodes 88193149Sdougb 89135446Strhodes#ifdef HAVE_ADDRINFO 90135446Strhodes#ifdef HAVE_GETADDRINFO 91135446Strhodes#ifdef HAVE_GAISTRERROR 92135446Strhodes#define USE_GETADDRINFO 93135446Strhodes#endif 94135446Strhodes#endif 95135446Strhodes#endif 96135446Strhodes 97135446Strhodes#ifndef USE_GETADDRINFO 98135446Strhodes#ifndef ISC_PLATFORM_NONSTDHERRNO 99135446Strhodesextern int h_errno; 100135446Strhodes#endif 101135446Strhodes#endif 102135446Strhodes 103135446Strhodes#define MAXCMD (4 * 1024) 104135446Strhodes#define MAXWIRE (64 * 1024) 105135446Strhodes#define PACKETSIZE ((64 * 1024) - 1) 106135446Strhodes#define INITTEXT (2 * 1024) 107135446Strhodes#define MAXTEXT (128 * 1024) 108135446Strhodes#define FIND_TIMEOUT 5 109135446Strhodes#define TTL_MAX 2147483647U /* Maximum signed 32 bit integer. */ 110135446Strhodes 111135446Strhodes#define DNSDEFAULTPORT 53 112135446Strhodes 113224092Sdougbstatic isc_uint16_t dnsport = DNSDEFAULTPORT; 114224092Sdougb 115135446Strhodes#ifndef RESOLV_CONF 116135446Strhodes#define RESOLV_CONF "/etc/resolv.conf" 117135446Strhodes#endif 118135446Strhodes 119135446Strhodesstatic isc_boolean_t debugging = ISC_FALSE, ddebugging = ISC_FALSE; 120135446Strhodesstatic isc_boolean_t memdebugging = ISC_FALSE; 121135446Strhodesstatic isc_boolean_t have_ipv4 = ISC_FALSE; 122135446Strhodesstatic isc_boolean_t have_ipv6 = ISC_FALSE; 123135446Strhodesstatic isc_boolean_t is_dst_up = ISC_FALSE; 124135446Strhodesstatic isc_boolean_t usevc = ISC_FALSE; 125193149Sdougbstatic isc_boolean_t usegsstsig = ISC_FALSE; 126193149Sdougbstatic isc_boolean_t use_win2k_gsstsig = ISC_FALSE; 127193149Sdougbstatic isc_boolean_t tried_other_gsstsig = ISC_FALSE; 128224092Sdougbstatic isc_boolean_t local_only = ISC_FALSE; 129135446Strhodesstatic isc_taskmgr_t *taskmgr = NULL; 130135446Strhodesstatic isc_task_t *global_task = NULL; 131135446Strhodesstatic isc_event_t *global_event = NULL; 132193149Sdougbstatic isc_log_t *lctx = NULL; 133135446Strhodesstatic isc_mem_t *mctx = NULL; 134135446Strhodesstatic dns_dispatchmgr_t *dispatchmgr = NULL; 135135446Strhodesstatic dns_requestmgr_t *requestmgr = NULL; 136135446Strhodesstatic isc_socketmgr_t *socketmgr = NULL; 137135446Strhodesstatic isc_timermgr_t *timermgr = NULL; 138135446Strhodesstatic dns_dispatch_t *dispatchv4 = NULL; 139135446Strhodesstatic dns_dispatch_t *dispatchv6 = NULL; 140135446Strhodesstatic dns_message_t *updatemsg = NULL; 141135446Strhodesstatic dns_fixedname_t fuserzone; 142135446Strhodesstatic dns_name_t *userzone = NULL; 143193149Sdougbstatic dns_name_t *zonename = NULL; 144193149Sdougbstatic dns_name_t tmpzonename; 145193149Sdougbstatic dns_name_t restart_master; 146193149Sdougbstatic dns_tsig_keyring_t *gssring = NULL; 147135446Strhodesstatic dns_tsigkey_t *tsigkey = NULL; 148225361Sdougbstatic dst_key_t *sig0key = NULL; 149135446Strhodesstatic lwres_context_t *lwctx = NULL; 150135446Strhodesstatic lwres_conf_t *lwconf; 151135446Strhodesstatic isc_sockaddr_t *servers; 152135446Strhodesstatic int ns_inuse = 0; 153135446Strhodesstatic int ns_total = 0; 154135446Strhodesstatic isc_sockaddr_t *userserver = NULL; 155135446Strhodesstatic isc_sockaddr_t *localaddr = NULL; 156193149Sdougbstatic isc_sockaddr_t *serveraddr = NULL; 157193149Sdougbstatic isc_sockaddr_t tempaddr; 158224092Sdougbstatic const char *keyfile = NULL; 159224092Sdougbstatic char *keystr = NULL; 160193149Sdougbstatic isc_entropy_t *entropy = NULL; 161135446Strhodesstatic isc_boolean_t shuttingdown = ISC_FALSE; 162135446Strhodesstatic FILE *input; 163135446Strhodesstatic isc_boolean_t interactive = ISC_TRUE; 164135446Strhodesstatic isc_boolean_t seenerror = ISC_FALSE; 165135446Strhodesstatic const dns_master_style_t *style; 166135446Strhodesstatic int requests = 0; 167193149Sdougbstatic unsigned int logdebuglevel = 0; 168135446Strhodesstatic unsigned int timeout = 300; 169135446Strhodesstatic unsigned int udp_timeout = 3; 170135446Strhodesstatic unsigned int udp_retries = 3; 171135446Strhodesstatic dns_rdataclass_t defaultclass = dns_rdataclass_in; 172135446Strhodesstatic dns_rdataclass_t zoneclass = dns_rdataclass_none; 173135446Strhodesstatic dns_message_t *answer = NULL; 174193149Sdougbstatic isc_uint32_t default_ttl = 0; 175193149Sdougbstatic isc_boolean_t default_ttl_set = ISC_FALSE; 176135446Strhodes 177135446Strhodestypedef struct nsu_requestinfo { 178135446Strhodes dns_message_t *msg; 179135446Strhodes isc_sockaddr_t *addr; 180135446Strhodes} nsu_requestinfo_t; 181135446Strhodes 182135446Strhodesstatic void 183135446Strhodessendrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, 184135446Strhodes dns_message_t *msg, dns_request_t **request); 185135446Strhodes 186224092SdougbISC_PLATFORM_NORETURN_PRE static void 187224092Sdougbfatal(const char *format, ...) 188224092SdougbISC_FORMAT_PRINTF(1, 2) ISC_PLATFORM_NORETURN_POST; 189224092Sdougb 190135446Strhodesstatic void 191135446Strhodesdebug(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); 192135446Strhodes 193135446Strhodesstatic void 194135446Strhodesddebug(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); 195135446Strhodes 196193149Sdougb#ifdef GSSAPI 197193149Sdougbstatic dns_fixedname_t fkname; 198193149Sdougbstatic isc_sockaddr_t *kserver = NULL; 199218384Sdougbstatic char *realm = NULL; 200193149Sdougbstatic char servicename[DNS_NAME_FORMATSIZE]; 201193149Sdougbstatic dns_name_t *keyname; 202193149Sdougbtypedef struct nsu_gssinfo { 203193149Sdougb dns_message_t *msg; 204193149Sdougb isc_sockaddr_t *addr; 205193149Sdougb gss_ctx_id_t context; 206193149Sdougb} nsu_gssinfo_t; 207193149Sdougb 208170222Sdougbstatic void 209193149Sdougbstart_gssrequest(dns_name_t *master); 210193149Sdougbstatic void 211193149Sdougbsend_gssrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, 212193149Sdougb dns_message_t *msg, dns_request_t **request, 213193149Sdougb gss_ctx_id_t context); 214193149Sdougbstatic void 215193149Sdougbrecvgss(isc_task_t *task, isc_event_t *event); 216193149Sdougb#endif /* GSSAPI */ 217193149Sdougb 218193149Sdougbstatic void 219170222Sdougberror(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); 220170222Sdougb 221135446Strhodes#define STATUS_MORE (isc_uint16_t)0 222135446Strhodes#define STATUS_SEND (isc_uint16_t)1 223135446Strhodes#define STATUS_QUIT (isc_uint16_t)2 224135446Strhodes#define STATUS_SYNTAX (isc_uint16_t)3 225135446Strhodes 226193149Sdougbtypedef struct entropysource entropysource_t; 227193149Sdougb 228193149Sdougbstruct entropysource { 229193149Sdougb isc_entropysource_t *source; 230193149Sdougb isc_mem_t *mctx; 231193149Sdougb ISC_LINK(entropysource_t) link; 232193149Sdougb}; 233193149Sdougb 234193149Sdougbstatic ISC_LIST(entropysource_t) sources; 235193149Sdougb 236193149Sdougbstatic void 237193149Sdougbsetup_entropy(isc_mem_t *mctx, const char *randomfile, isc_entropy_t **ectx) 238193149Sdougb{ 239193149Sdougb isc_result_t result; 240193149Sdougb isc_entropysource_t *source = NULL; 241193149Sdougb entropysource_t *elt; 242193149Sdougb int usekeyboard = ISC_ENTROPY_KEYBOARDMAYBE; 243193149Sdougb 244193149Sdougb REQUIRE(ectx != NULL); 245193149Sdougb 246193149Sdougb if (*ectx == NULL) { 247193149Sdougb result = isc_entropy_create(mctx, ectx); 248193149Sdougb if (result != ISC_R_SUCCESS) 249193149Sdougb fatal("could not create entropy object"); 250193149Sdougb ISC_LIST_INIT(sources); 251193149Sdougb } 252193149Sdougb 253193149Sdougb if (randomfile != NULL && strcmp(randomfile, "keyboard") == 0) { 254193149Sdougb usekeyboard = ISC_ENTROPY_KEYBOARDYES; 255193149Sdougb randomfile = NULL; 256193149Sdougb } 257193149Sdougb 258193149Sdougb result = isc_entropy_usebestsource(*ectx, &source, randomfile, 259193149Sdougb usekeyboard); 260193149Sdougb 261193149Sdougb if (result != ISC_R_SUCCESS) 262193149Sdougb fatal("could not initialize entropy source: %s", 263193149Sdougb isc_result_totext(result)); 264193149Sdougb 265193149Sdougb if (source != NULL) { 266193149Sdougb elt = isc_mem_get(mctx, sizeof(*elt)); 267193149Sdougb if (elt == NULL) 268193149Sdougb fatal("out of memory"); 269193149Sdougb elt->source = source; 270193149Sdougb elt->mctx = mctx; 271193149Sdougb ISC_LINK_INIT(elt, link); 272193149Sdougb ISC_LIST_APPEND(sources, elt, link); 273193149Sdougb } 274193149Sdougb} 275193149Sdougb 276193149Sdougbstatic void 277193149Sdougbcleanup_entropy(isc_entropy_t **ectx) { 278193149Sdougb entropysource_t *source; 279193149Sdougb while (!ISC_LIST_EMPTY(sources)) { 280193149Sdougb source = ISC_LIST_HEAD(sources); 281193149Sdougb ISC_LIST_UNLINK(sources, source, link); 282193149Sdougb isc_entropy_destroysource(&source->source); 283193149Sdougb isc_mem_put(source->mctx, source, sizeof(*source)); 284193149Sdougb } 285193149Sdougb isc_entropy_detach(ectx); 286193149Sdougb} 287193149Sdougb 288193149Sdougb 289135446Strhodesstatic dns_rdataclass_t 290135446Strhodesgetzoneclass(void) { 291135446Strhodes if (zoneclass == dns_rdataclass_none) 292135446Strhodes zoneclass = defaultclass; 293135446Strhodes return (zoneclass); 294135446Strhodes} 295135446Strhodes 296135446Strhodesstatic isc_boolean_t 297135446Strhodessetzoneclass(dns_rdataclass_t rdclass) { 298135446Strhodes if (zoneclass == dns_rdataclass_none || 299135446Strhodes rdclass == dns_rdataclass_none) 300135446Strhodes zoneclass = rdclass; 301135446Strhodes if (zoneclass != rdclass) 302135446Strhodes return (ISC_FALSE); 303135446Strhodes return (ISC_TRUE); 304135446Strhodes} 305135446Strhodes 306135446Strhodesstatic void 307135446Strhodesfatal(const char *format, ...) { 308135446Strhodes va_list args; 309135446Strhodes 310135446Strhodes va_start(args, format); 311135446Strhodes vfprintf(stderr, format, args); 312135446Strhodes va_end(args); 313135446Strhodes fprintf(stderr, "\n"); 314135446Strhodes exit(1); 315135446Strhodes} 316135446Strhodes 317135446Strhodesstatic void 318170222Sdougberror(const char *format, ...) { 319170222Sdougb va_list args; 320170222Sdougb 321170222Sdougb va_start(args, format); 322170222Sdougb vfprintf(stderr, format, args); 323170222Sdougb va_end(args); 324170222Sdougb fprintf(stderr, "\n"); 325170222Sdougb} 326170222Sdougb 327170222Sdougbstatic void 328135446Strhodesdebug(const char *format, ...) { 329135446Strhodes va_list args; 330135446Strhodes 331135446Strhodes if (debugging) { 332135446Strhodes va_start(args, format); 333135446Strhodes vfprintf(stderr, format, args); 334135446Strhodes va_end(args); 335135446Strhodes fprintf(stderr, "\n"); 336135446Strhodes } 337135446Strhodes} 338135446Strhodes 339135446Strhodesstatic void 340135446Strhodesddebug(const char *format, ...) { 341135446Strhodes va_list args; 342135446Strhodes 343135446Strhodes if (ddebugging) { 344135446Strhodes va_start(args, format); 345135446Strhodes vfprintf(stderr, format, args); 346135446Strhodes va_end(args); 347135446Strhodes fprintf(stderr, "\n"); 348135446Strhodes } 349135446Strhodes} 350135446Strhodes 351135446Strhodesstatic inline void 352135446Strhodescheck_result(isc_result_t result, const char *msg) { 353135446Strhodes if (result != ISC_R_SUCCESS) 354135446Strhodes fatal("%s: %s", msg, isc_result_totext(result)); 355135446Strhodes} 356135446Strhodes 357135446Strhodesstatic void * 358135446Strhodesmem_alloc(void *arg, size_t size) { 359135446Strhodes return (isc_mem_get(arg, size)); 360135446Strhodes} 361135446Strhodes 362135446Strhodesstatic void 363135446Strhodesmem_free(void *arg, void *mem, size_t size) { 364135446Strhodes isc_mem_put(arg, mem, size); 365135446Strhodes} 366135446Strhodes 367135446Strhodesstatic char * 368135446Strhodesnsu_strsep(char **stringp, const char *delim) { 369135446Strhodes char *string = *stringp; 370135446Strhodes char *s; 371135446Strhodes const char *d; 372135446Strhodes char sc, dc; 373135446Strhodes 374135446Strhodes if (string == NULL) 375135446Strhodes return (NULL); 376135446Strhodes 377135446Strhodes for (; *string != '\0'; string++) { 378135446Strhodes sc = *string; 379135446Strhodes for (d = delim; (dc = *d) != '\0'; d++) { 380135446Strhodes if (sc == dc) 381135446Strhodes break; 382135446Strhodes } 383135446Strhodes if (dc == 0) 384135446Strhodes break; 385135446Strhodes } 386135446Strhodes 387135446Strhodes for (s = string; *s != '\0'; s++) { 388135446Strhodes sc = *s; 389135446Strhodes for (d = delim; (dc = *d) != '\0'; d++) { 390135446Strhodes if (sc == dc) { 391135446Strhodes *s++ = '\0'; 392135446Strhodes *stringp = s; 393135446Strhodes return (string); 394135446Strhodes } 395135446Strhodes } 396135446Strhodes } 397135446Strhodes *stringp = NULL; 398135446Strhodes return (string); 399135446Strhodes} 400135446Strhodes 401135446Strhodesstatic void 402135446Strhodesreset_system(void) { 403135446Strhodes isc_result_t result; 404135446Strhodes 405135446Strhodes ddebug("reset_system()"); 406135446Strhodes /* If the update message is still around, destroy it */ 407135446Strhodes if (updatemsg != NULL) 408135446Strhodes dns_message_reset(updatemsg, DNS_MESSAGE_INTENTRENDER); 409135446Strhodes else { 410135446Strhodes result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, 411135446Strhodes &updatemsg); 412135446Strhodes check_result(result, "dns_message_create"); 413135446Strhodes } 414135446Strhodes updatemsg->opcode = dns_opcode_update; 415193149Sdougb if (usegsstsig) { 416193149Sdougb if (tsigkey != NULL) 417193149Sdougb dns_tsigkey_detach(&tsigkey); 418193149Sdougb if (gssring != NULL) 419224092Sdougb dns_tsigkeyring_detach(&gssring); 420193149Sdougb tried_other_gsstsig = ISC_FALSE; 421193149Sdougb } 422135446Strhodes} 423135446Strhodes 424170222Sdougbstatic isc_uint16_t 425170222Sdougbparse_hmac(dns_name_t **hmac, const char *hmacstr, size_t len) { 426170222Sdougb isc_uint16_t digestbits = 0; 427170222Sdougb isc_result_t result; 428170222Sdougb char buf[20]; 429170222Sdougb 430170222Sdougb REQUIRE(hmac != NULL && *hmac == NULL); 431170222Sdougb REQUIRE(hmacstr != NULL); 432170222Sdougb 433170222Sdougb if (len >= sizeof(buf)) 434170222Sdougb fatal("unknown key type '%.*s'", (int)(len), hmacstr); 435170222Sdougb 436170222Sdougb strncpy(buf, hmacstr, len); 437170222Sdougb buf[len] = 0; 438186462Sdougb 439170222Sdougb if (strcasecmp(buf, "hmac-md5") == 0) { 440170222Sdougb *hmac = DNS_TSIG_HMACMD5_NAME; 441170222Sdougb } else if (strncasecmp(buf, "hmac-md5-", 9) == 0) { 442170222Sdougb *hmac = DNS_TSIG_HMACMD5_NAME; 443170222Sdougb result = isc_parse_uint16(&digestbits, &buf[9], 10); 444170222Sdougb if (result != ISC_R_SUCCESS || digestbits > 128) 445170222Sdougb fatal("digest-bits out of range [0..128]"); 446170222Sdougb digestbits = (digestbits +7) & ~0x7U; 447170222Sdougb } else if (strcasecmp(buf, "hmac-sha1") == 0) { 448170222Sdougb *hmac = DNS_TSIG_HMACSHA1_NAME; 449170222Sdougb } else if (strncasecmp(buf, "hmac-sha1-", 10) == 0) { 450170222Sdougb *hmac = DNS_TSIG_HMACSHA1_NAME; 451170222Sdougb result = isc_parse_uint16(&digestbits, &buf[10], 10); 452170222Sdougb if (result != ISC_R_SUCCESS || digestbits > 160) 453170222Sdougb fatal("digest-bits out of range [0..160]"); 454170222Sdougb digestbits = (digestbits +7) & ~0x7U; 455170222Sdougb } else if (strcasecmp(buf, "hmac-sha224") == 0) { 456170222Sdougb *hmac = DNS_TSIG_HMACSHA224_NAME; 457170222Sdougb } else if (strncasecmp(buf, "hmac-sha224-", 12) == 0) { 458170222Sdougb *hmac = DNS_TSIG_HMACSHA224_NAME; 459170222Sdougb result = isc_parse_uint16(&digestbits, &buf[12], 10); 460170222Sdougb if (result != ISC_R_SUCCESS || digestbits > 224) 461170222Sdougb fatal("digest-bits out of range [0..224]"); 462170222Sdougb digestbits = (digestbits +7) & ~0x7U; 463170222Sdougb } else if (strcasecmp(buf, "hmac-sha256") == 0) { 464170222Sdougb *hmac = DNS_TSIG_HMACSHA256_NAME; 465170222Sdougb } else if (strncasecmp(buf, "hmac-sha256-", 12) == 0) { 466170222Sdougb *hmac = DNS_TSIG_HMACSHA256_NAME; 467170222Sdougb result = isc_parse_uint16(&digestbits, &buf[12], 10); 468170222Sdougb if (result != ISC_R_SUCCESS || digestbits > 256) 469170222Sdougb fatal("digest-bits out of range [0..256]"); 470170222Sdougb digestbits = (digestbits +7) & ~0x7U; 471170222Sdougb } else if (strcasecmp(buf, "hmac-sha384") == 0) { 472170222Sdougb *hmac = DNS_TSIG_HMACSHA384_NAME; 473170222Sdougb } else if (strncasecmp(buf, "hmac-sha384-", 12) == 0) { 474170222Sdougb *hmac = DNS_TSIG_HMACSHA384_NAME; 475170222Sdougb result = isc_parse_uint16(&digestbits, &buf[12], 10); 476170222Sdougb if (result != ISC_R_SUCCESS || digestbits > 384) 477170222Sdougb fatal("digest-bits out of range [0..384]"); 478170222Sdougb digestbits = (digestbits +7) & ~0x7U; 479170222Sdougb } else if (strcasecmp(buf, "hmac-sha512") == 0) { 480170222Sdougb *hmac = DNS_TSIG_HMACSHA512_NAME; 481170222Sdougb } else if (strncasecmp(buf, "hmac-sha512-", 12) == 0) { 482170222Sdougb *hmac = DNS_TSIG_HMACSHA512_NAME; 483170222Sdougb result = isc_parse_uint16(&digestbits, &buf[12], 10); 484170222Sdougb if (result != ISC_R_SUCCESS || digestbits > 512) 485170222Sdougb fatal("digest-bits out of range [0..512]"); 486170222Sdougb digestbits = (digestbits +7) & ~0x7U; 487170222Sdougb } else 488170222Sdougb fatal("unknown key type '%s'", buf); 489170222Sdougb return (digestbits); 490170222Sdougb} 491170222Sdougb 492224092Sdougbstatic int 493224092Sdougbbasenamelen(const char *file) { 494224092Sdougb int len = strlen(file); 495224092Sdougb 496224092Sdougb if (len > 1 && file[len - 1] == '.') 497224092Sdougb len -= 1; 498224092Sdougb else if (len > 8 && strcmp(file + len - 8, ".private") == 0) 499224092Sdougb len -= 8; 500224092Sdougb else if (len > 4 && strcmp(file + len - 4, ".key") == 0) 501224092Sdougb len -= 4; 502224092Sdougb return (len); 503224092Sdougb} 504224092Sdougb 505135446Strhodesstatic void 506135446Strhodessetup_keystr(void) { 507135446Strhodes unsigned char *secret = NULL; 508135446Strhodes int secretlen; 509135446Strhodes isc_buffer_t secretbuf; 510135446Strhodes isc_result_t result; 511135446Strhodes isc_buffer_t keynamesrc; 512135446Strhodes char *secretstr; 513170222Sdougb char *s, *n; 514135446Strhodes dns_fixedname_t fkeyname; 515135446Strhodes dns_name_t *keyname; 516170222Sdougb char *name; 517170222Sdougb dns_name_t *hmacname = NULL; 518170222Sdougb isc_uint16_t digestbits = 0; 519135446Strhodes 520135446Strhodes dns_fixedname_init(&fkeyname); 521135446Strhodes keyname = dns_fixedname_name(&fkeyname); 522135446Strhodes 523135446Strhodes debug("Creating key..."); 524135446Strhodes 525135446Strhodes s = strchr(keystr, ':'); 526170222Sdougb if (s == NULL || s == keystr || s[1] == 0) 527170222Sdougb fatal("key option must specify [hmac:]keyname:secret"); 528135446Strhodes secretstr = s + 1; 529170222Sdougb n = strchr(secretstr, ':'); 530170222Sdougb if (n != NULL) { 531170222Sdougb if (n == secretstr || n[1] == 0) 532170222Sdougb fatal("key option must specify [hmac:]keyname:secret"); 533170222Sdougb name = secretstr; 534170222Sdougb secretstr = n + 1; 535170222Sdougb digestbits = parse_hmac(&hmacname, keystr, s - keystr); 536170222Sdougb } else { 537170222Sdougb hmacname = DNS_TSIG_HMACMD5_NAME; 538170222Sdougb name = keystr; 539170222Sdougb n = s; 540170222Sdougb } 541135446Strhodes 542170222Sdougb isc_buffer_init(&keynamesrc, name, n - name); 543170222Sdougb isc_buffer_add(&keynamesrc, n - name); 544135446Strhodes 545135446Strhodes debug("namefromtext"); 546224092Sdougb result = dns_name_fromtext(keyname, &keynamesrc, dns_rootname, 0, NULL); 547135446Strhodes check_result(result, "dns_name_fromtext"); 548135446Strhodes 549135446Strhodes secretlen = strlen(secretstr) * 3 / 4; 550135446Strhodes secret = isc_mem_allocate(mctx, secretlen); 551135446Strhodes if (secret == NULL) 552135446Strhodes fatal("out of memory"); 553135446Strhodes 554135446Strhodes isc_buffer_init(&secretbuf, secret, secretlen); 555135446Strhodes result = isc_base64_decodestring(secretstr, &secretbuf); 556135446Strhodes if (result != ISC_R_SUCCESS) { 557135446Strhodes fprintf(stderr, "could not create key from %s: %s\n", 558135446Strhodes keystr, isc_result_totext(result)); 559135446Strhodes goto failure; 560135446Strhodes } 561135446Strhodes 562135446Strhodes secretlen = isc_buffer_usedlength(&secretbuf); 563135446Strhodes 564135446Strhodes debug("keycreate"); 565170222Sdougb result = dns_tsigkey_create(keyname, hmacname, secret, secretlen, 566218384Sdougb ISC_FALSE, NULL, 0, 0, mctx, NULL, 567218384Sdougb &tsigkey); 568135446Strhodes if (result != ISC_R_SUCCESS) 569135446Strhodes fprintf(stderr, "could not create key from %s: %s\n", 570135446Strhodes keystr, dns_result_totext(result)); 571170222Sdougb else 572170222Sdougb dst_key_setbits(tsigkey->key, digestbits); 573135446Strhodes failure: 574135446Strhodes if (secret != NULL) 575135446Strhodes isc_mem_free(mctx, secret); 576135446Strhodes} 577135446Strhodes 578224092Sdougb/* 579224092Sdougb * Get a key from a named.conf format keyfile 580224092Sdougb */ 581224092Sdougbstatic isc_result_t 582224092Sdougbread_sessionkey(isc_mem_t *mctx, isc_log_t *lctx) { 583224092Sdougb cfg_parser_t *pctx = NULL; 584224092Sdougb cfg_obj_t *sessionkey = NULL; 585224092Sdougb const cfg_obj_t *key = NULL; 586224092Sdougb const cfg_obj_t *secretobj = NULL; 587224092Sdougb const cfg_obj_t *algorithmobj = NULL; 588224092Sdougb const char *keyname; 589224092Sdougb const char *secretstr; 590224092Sdougb const char *algorithm; 591224092Sdougb isc_result_t result; 592224092Sdougb int len; 593218384Sdougb 594224092Sdougb if (! isc_file_exists(keyfile)) 595224092Sdougb return (ISC_R_FILENOTFOUND); 596224092Sdougb 597224092Sdougb result = cfg_parser_create(mctx, lctx, &pctx); 598224092Sdougb if (result != ISC_R_SUCCESS) 599224092Sdougb goto cleanup; 600224092Sdougb 601224092Sdougb result = cfg_parse_file(pctx, keyfile, &cfg_type_sessionkey, 602224092Sdougb &sessionkey); 603224092Sdougb if (result != ISC_R_SUCCESS) 604224092Sdougb goto cleanup; 605224092Sdougb 606224092Sdougb result = cfg_map_get(sessionkey, "key", &key); 607224092Sdougb if (result != ISC_R_SUCCESS) 608224092Sdougb goto cleanup; 609224092Sdougb 610224092Sdougb (void) cfg_map_get(key, "secret", &secretobj); 611224092Sdougb (void) cfg_map_get(key, "algorithm", &algorithmobj); 612224092Sdougb if (secretobj == NULL || algorithmobj == NULL) 613224092Sdougb fatal("key must have algorithm and secret"); 614224092Sdougb 615224092Sdougb keyname = cfg_obj_asstring(cfg_map_getname(key)); 616224092Sdougb secretstr = cfg_obj_asstring(secretobj); 617224092Sdougb algorithm = cfg_obj_asstring(algorithmobj); 618224092Sdougb 619224092Sdougb len = strlen(algorithm) + strlen(keyname) + strlen(secretstr) + 3; 620224092Sdougb keystr = isc_mem_allocate(mctx, len); 621224092Sdougb snprintf(keystr, len, "%s:%s:%s", algorithm, keyname, secretstr); 622224092Sdougb setup_keystr(); 623224092Sdougb 624224092Sdougb cleanup: 625224092Sdougb if (pctx != NULL) { 626224092Sdougb if (sessionkey != NULL) 627224092Sdougb cfg_obj_destroy(pctx, &sessionkey); 628224092Sdougb cfg_parser_destroy(&pctx); 629224092Sdougb } 630224092Sdougb 631224092Sdougb if (keystr != NULL) 632224092Sdougb isc_mem_free(mctx, keystr); 633224092Sdougb 634224092Sdougb return (result); 635218384Sdougb} 636218384Sdougb 637135446Strhodesstatic void 638224092Sdougbsetup_keyfile(isc_mem_t *mctx, isc_log_t *lctx) { 639135446Strhodes dst_key_t *dstkey = NULL; 640135446Strhodes isc_result_t result; 641170222Sdougb dns_name_t *hmacname = NULL; 642135446Strhodes 643135446Strhodes debug("Creating key..."); 644135446Strhodes 645218384Sdougb if (sig0key != NULL) 646218384Sdougb dst_key_free(&sig0key); 647218384Sdougb 648224092Sdougb /* Try reading the key from a K* pair */ 649224092Sdougb result = dst_key_fromnamedfile(keyfile, NULL, 650135446Strhodes DST_TYPE_PRIVATE | DST_TYPE_KEY, mctx, 651135446Strhodes &dstkey); 652224092Sdougb 653224092Sdougb /* If that didn't work, try reading it as a session.key keyfile */ 654135446Strhodes if (result != ISC_R_SUCCESS) { 655224092Sdougb result = read_sessionkey(mctx, lctx); 656224092Sdougb if (result == ISC_R_SUCCESS) 657224092Sdougb return; 658224092Sdougb } 659224092Sdougb 660224092Sdougb if (result != ISC_R_SUCCESS) { 661218384Sdougb fprintf(stderr, "could not read key from %.*s.{private,key}: " 662218384Sdougb "%s\n", basenamelen(keyfile), keyfile, 663218384Sdougb isc_result_totext(result)); 664135446Strhodes return; 665135446Strhodes } 666224092Sdougb 667170222Sdougb switch (dst_key_alg(dstkey)) { 668170222Sdougb case DST_ALG_HMACMD5: 669170222Sdougb hmacname = DNS_TSIG_HMACMD5_NAME; 670170222Sdougb break; 671170222Sdougb case DST_ALG_HMACSHA1: 672170222Sdougb hmacname = DNS_TSIG_HMACSHA1_NAME; 673170222Sdougb break; 674170222Sdougb case DST_ALG_HMACSHA224: 675170222Sdougb hmacname = DNS_TSIG_HMACSHA224_NAME; 676170222Sdougb break; 677170222Sdougb case DST_ALG_HMACSHA256: 678170222Sdougb hmacname = DNS_TSIG_HMACSHA256_NAME; 679170222Sdougb break; 680170222Sdougb case DST_ALG_HMACSHA384: 681170222Sdougb hmacname = DNS_TSIG_HMACSHA384_NAME; 682170222Sdougb break; 683170222Sdougb case DST_ALG_HMACSHA512: 684170222Sdougb hmacname = DNS_TSIG_HMACSHA512_NAME; 685170222Sdougb break; 686170222Sdougb } 687170222Sdougb if (hmacname != NULL) { 688135446Strhodes result = dns_tsigkey_createfromkey(dst_key_name(dstkey), 689170222Sdougb hmacname, dstkey, ISC_FALSE, 690170222Sdougb NULL, 0, 0, mctx, NULL, 691170222Sdougb &tsigkey); 692218384Sdougb dst_key_free(&dstkey); 693135446Strhodes if (result != ISC_R_SUCCESS) { 694135446Strhodes fprintf(stderr, "could not create key from %s: %s\n", 695135446Strhodes keyfile, isc_result_totext(result)); 696135446Strhodes return; 697135446Strhodes } 698222395Sdougb } else { 699218384Sdougb dst_key_attach(dstkey, &sig0key); 700222395Sdougb dst_key_free(&dstkey); 701222395Sdougb } 702135446Strhodes} 703135446Strhodes 704135446Strhodesstatic void 705135446Strhodesdoshutdown(void) { 706135446Strhodes isc_task_detach(&global_task); 707135446Strhodes 708135446Strhodes if (userserver != NULL) 709135446Strhodes isc_mem_put(mctx, userserver, sizeof(isc_sockaddr_t)); 710135446Strhodes 711135446Strhodes if (localaddr != NULL) 712135446Strhodes isc_mem_put(mctx, localaddr, sizeof(isc_sockaddr_t)); 713135446Strhodes 714135446Strhodes if (tsigkey != NULL) { 715135446Strhodes ddebug("Freeing TSIG key"); 716135446Strhodes dns_tsigkey_detach(&tsigkey); 717135446Strhodes } 718135446Strhodes 719135446Strhodes if (sig0key != NULL) { 720135446Strhodes ddebug("Freeing SIG(0) key"); 721135446Strhodes dst_key_free(&sig0key); 722135446Strhodes } 723135446Strhodes 724135446Strhodes if (updatemsg != NULL) 725135446Strhodes dns_message_destroy(&updatemsg); 726135446Strhodes 727135446Strhodes if (is_dst_up) { 728135446Strhodes ddebug("Destroy DST lib"); 729135446Strhodes dst_lib_destroy(); 730135446Strhodes is_dst_up = ISC_FALSE; 731135446Strhodes } 732135446Strhodes 733193149Sdougb cleanup_entropy(&entropy); 734135446Strhodes 735135446Strhodes lwres_conf_clear(lwctx); 736135446Strhodes lwres_context_destroy(&lwctx); 737135446Strhodes 738135446Strhodes isc_mem_put(mctx, servers, ns_total * sizeof(isc_sockaddr_t)); 739135446Strhodes 740135446Strhodes ddebug("Destroying request manager"); 741135446Strhodes dns_requestmgr_detach(&requestmgr); 742135446Strhodes 743135446Strhodes ddebug("Freeing the dispatchers"); 744135446Strhodes if (have_ipv4) 745135446Strhodes dns_dispatch_detach(&dispatchv4); 746135446Strhodes if (have_ipv6) 747135446Strhodes dns_dispatch_detach(&dispatchv6); 748135446Strhodes 749135446Strhodes ddebug("Shutting down dispatch manager"); 750135446Strhodes dns_dispatchmgr_destroy(&dispatchmgr); 751135446Strhodes 752135446Strhodes} 753135446Strhodes 754135446Strhodesstatic void 755135446Strhodesmaybeshutdown(void) { 756135446Strhodes ddebug("Shutting down request manager"); 757135446Strhodes dns_requestmgr_shutdown(requestmgr); 758135446Strhodes 759135446Strhodes if (requests != 0) 760135446Strhodes return; 761135446Strhodes 762135446Strhodes doshutdown(); 763135446Strhodes} 764135446Strhodes 765135446Strhodesstatic void 766135446Strhodesshutdown_program(isc_task_t *task, isc_event_t *event) { 767135446Strhodes REQUIRE(task == global_task); 768135446Strhodes UNUSED(task); 769135446Strhodes 770135446Strhodes ddebug("shutdown_program()"); 771135446Strhodes isc_event_free(&event); 772135446Strhodes 773135446Strhodes shuttingdown = ISC_TRUE; 774135446Strhodes maybeshutdown(); 775135446Strhodes} 776135446Strhodes 777135446Strhodesstatic void 778135446Strhodessetup_system(void) { 779135446Strhodes isc_result_t result; 780135446Strhodes isc_sockaddr_t bind_any, bind_any6; 781135446Strhodes lwres_result_t lwresult; 782135446Strhodes unsigned int attrs, attrmask; 783135446Strhodes int i; 784193149Sdougb isc_logconfig_t *logconfig = NULL; 785135446Strhodes 786135446Strhodes ddebug("setup_system()"); 787135446Strhodes 788135446Strhodes dns_result_register(); 789135446Strhodes 790135446Strhodes result = isc_net_probeipv4(); 791135446Strhodes if (result == ISC_R_SUCCESS) 792135446Strhodes have_ipv4 = ISC_TRUE; 793135446Strhodes 794135446Strhodes result = isc_net_probeipv6(); 795135446Strhodes if (result == ISC_R_SUCCESS) 796135446Strhodes have_ipv6 = ISC_TRUE; 797135446Strhodes 798135446Strhodes if (!have_ipv4 && !have_ipv6) 799135446Strhodes fatal("could not find either IPv4 or IPv6"); 800135446Strhodes 801193149Sdougb result = isc_log_create(mctx, &lctx, &logconfig); 802193149Sdougb check_result(result, "isc_log_create"); 803135446Strhodes 804193149Sdougb isc_log_setcontext(lctx); 805193149Sdougb dns_log_init(lctx); 806193149Sdougb dns_log_setcontext(lctx); 807193149Sdougb 808193149Sdougb result = isc_log_usechannel(logconfig, "default_debug", NULL, NULL); 809193149Sdougb check_result(result, "isc_log_usechannel"); 810193149Sdougb 811193149Sdougb isc_log_setdebuglevel(lctx, logdebuglevel); 812193149Sdougb 813135446Strhodes lwresult = lwres_context_create(&lwctx, mctx, mem_alloc, mem_free, 1); 814135446Strhodes if (lwresult != LWRES_R_SUCCESS) 815135446Strhodes fatal("lwres_context_create failed"); 816135446Strhodes 817135446Strhodes (void)lwres_conf_parse(lwctx, RESOLV_CONF); 818135446Strhodes lwconf = lwres_conf_get(lwctx); 819135446Strhodes 820135446Strhodes ns_total = lwconf->nsnext; 821135446Strhodes if (ns_total <= 0) { 822135446Strhodes /* No name servers in resolv.conf; default to loopback. */ 823135446Strhodes struct in_addr localhost; 824135446Strhodes ns_total = 1; 825135446Strhodes servers = isc_mem_get(mctx, ns_total * sizeof(isc_sockaddr_t)); 826135446Strhodes if (servers == NULL) 827135446Strhodes fatal("out of memory"); 828135446Strhodes localhost.s_addr = htonl(INADDR_LOOPBACK); 829224092Sdougb isc_sockaddr_fromin(&servers[0], &localhost, dnsport); 830135446Strhodes } else { 831135446Strhodes servers = isc_mem_get(mctx, ns_total * sizeof(isc_sockaddr_t)); 832135446Strhodes if (servers == NULL) 833135446Strhodes fatal("out of memory"); 834135446Strhodes for (i = 0; i < ns_total; i++) { 835135446Strhodes if (lwconf->nameservers[i].family == LWRES_ADDRTYPE_V4) { 836135446Strhodes struct in_addr in4; 837135446Strhodes memcpy(&in4, lwconf->nameservers[i].address, 4); 838224092Sdougb isc_sockaddr_fromin(&servers[i], &in4, dnsport); 839135446Strhodes } else { 840135446Strhodes struct in6_addr in6; 841135446Strhodes memcpy(&in6, lwconf->nameservers[i].address, 16); 842135446Strhodes isc_sockaddr_fromin6(&servers[i], &in6, 843224092Sdougb dnsport); 844135446Strhodes } 845135446Strhodes } 846135446Strhodes } 847135446Strhodes 848193149Sdougb setup_entropy(mctx, NULL, &entropy); 849135446Strhodes 850193149Sdougb result = isc_hash_create(mctx, entropy, DNS_NAME_MAXWIRE); 851135446Strhodes check_result(result, "isc_hash_create"); 852135446Strhodes isc_hash_init(); 853135446Strhodes 854193149Sdougb result = dns_dispatchmgr_create(mctx, entropy, &dispatchmgr); 855135446Strhodes check_result(result, "dns_dispatchmgr_create"); 856135446Strhodes 857135446Strhodes result = isc_socketmgr_create(mctx, &socketmgr); 858135446Strhodes check_result(result, "dns_socketmgr_create"); 859135446Strhodes 860135446Strhodes result = isc_timermgr_create(mctx, &timermgr); 861135446Strhodes check_result(result, "dns_timermgr_create"); 862135446Strhodes 863135446Strhodes result = isc_taskmgr_create(mctx, 1, 0, &taskmgr); 864135446Strhodes check_result(result, "isc_taskmgr_create"); 865135446Strhodes 866135446Strhodes result = isc_task_create(taskmgr, 0, &global_task); 867135446Strhodes check_result(result, "isc_task_create"); 868135446Strhodes 869135446Strhodes result = isc_task_onshutdown(global_task, shutdown_program, NULL); 870135446Strhodes check_result(result, "isc_task_onshutdown"); 871135446Strhodes 872193149Sdougb result = dst_lib_init(mctx, entropy, 0); 873135446Strhodes check_result(result, "dst_lib_init"); 874135446Strhodes is_dst_up = ISC_TRUE; 875135446Strhodes 876135446Strhodes attrmask = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP; 877135446Strhodes attrmask |= DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6; 878135446Strhodes 879135446Strhodes if (have_ipv6) { 880135446Strhodes attrs = DNS_DISPATCHATTR_UDP; 881135446Strhodes attrs |= DNS_DISPATCHATTR_MAKEQUERY; 882135446Strhodes attrs |= DNS_DISPATCHATTR_IPV6; 883135446Strhodes isc_sockaddr_any6(&bind_any6); 884135446Strhodes result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, 885135446Strhodes &bind_any6, PACKETSIZE, 886135446Strhodes 4, 2, 3, 5, 887135446Strhodes attrs, attrmask, &dispatchv6); 888135446Strhodes check_result(result, "dns_dispatch_getudp (v6)"); 889135446Strhodes } 890135446Strhodes 891135446Strhodes if (have_ipv4) { 892135446Strhodes attrs = DNS_DISPATCHATTR_UDP; 893135446Strhodes attrs |= DNS_DISPATCHATTR_MAKEQUERY; 894135446Strhodes attrs |= DNS_DISPATCHATTR_IPV4; 895135446Strhodes isc_sockaddr_any(&bind_any); 896135446Strhodes result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, 897135446Strhodes &bind_any, PACKETSIZE, 898135446Strhodes 4, 2, 3, 5, 899135446Strhodes attrs, attrmask, &dispatchv4); 900135446Strhodes check_result(result, "dns_dispatch_getudp (v4)"); 901135446Strhodes } 902135446Strhodes 903135446Strhodes result = dns_requestmgr_create(mctx, timermgr, 904135446Strhodes socketmgr, taskmgr, dispatchmgr, 905135446Strhodes dispatchv4, dispatchv6, &requestmgr); 906135446Strhodes check_result(result, "dns_requestmgr_create"); 907135446Strhodes 908135446Strhodes if (keystr != NULL) 909135446Strhodes setup_keystr(); 910224092Sdougb else if (local_only) { 911224092Sdougb result = read_sessionkey(mctx, lctx); 912224092Sdougb if (result != ISC_R_SUCCESS) 913224092Sdougb fatal("can't read key from %s: %s\n", 914224092Sdougb keyfile, isc_result_totext(result)); 915224092Sdougb } else if (keyfile != NULL) 916224092Sdougb setup_keyfile(mctx, lctx); 917135446Strhodes} 918135446Strhodes 919135446Strhodesstatic void 920135446Strhodesget_address(char *host, in_port_t port, isc_sockaddr_t *sockaddr) { 921135446Strhodes int count; 922135446Strhodes isc_result_t result; 923135446Strhodes 924135446Strhodes isc_app_block(); 925135446Strhodes result = bind9_getaddresses(host, port, sockaddr, 1, &count); 926135446Strhodes isc_app_unblock(); 927135446Strhodes if (result != ISC_R_SUCCESS) 928135446Strhodes fatal("couldn't get address for '%s': %s", 929135446Strhodes host, isc_result_totext(result)); 930135446Strhodes INSIST(count == 1); 931135446Strhodes} 932135446Strhodes 933224092Sdougb#define PARSE_ARGS_FMT "dDML:y:ghlovk:p:rR::t:u:" 934193149Sdougb 935135446Strhodesstatic void 936193149Sdougbpre_parse_args(int argc, char **argv) { 937135446Strhodes int ch; 938193149Sdougb 939193149Sdougb while ((ch = isc_commandline_parse(argc, argv, PARSE_ARGS_FMT)) != -1) { 940193149Sdougb switch (ch) { 941193149Sdougb case 'M': /* was -dm */ 942193149Sdougb debugging = ISC_TRUE; 943193149Sdougb ddebugging = ISC_TRUE; 944193149Sdougb memdebugging = ISC_TRUE; 945193149Sdougb isc_mem_debugging = ISC_MEM_DEBUGTRACE | 946193149Sdougb ISC_MEM_DEBUGRECORD; 947193149Sdougb break; 948193149Sdougb 949193149Sdougb case '?': 950224092Sdougb case 'h': 951193149Sdougb if (isc_commandline_option != '?') 952193149Sdougb fprintf(stderr, "%s: invalid argument -%c\n", 953193149Sdougb argv[0], isc_commandline_option); 954224092Sdougb fprintf(stderr, "usage: nsupdate [-dD] [-L level] [-l]" 955193149Sdougb "[-g | -o | -y keyname:secret | -k keyfile] " 956193149Sdougb "[-v] [filename]\n"); 957193149Sdougb exit(1); 958193149Sdougb 959193149Sdougb default: 960193149Sdougb break; 961193149Sdougb } 962193149Sdougb } 963193149Sdougb isc_commandline_reset = ISC_TRUE; 964193149Sdougb isc_commandline_index = 1; 965193149Sdougb} 966193149Sdougb 967193149Sdougbstatic void 968193149Sdougbparse_args(int argc, char **argv, isc_mem_t *mctx, isc_entropy_t **ectx) { 969193149Sdougb int ch; 970193149Sdougb isc_uint32_t i; 971135446Strhodes isc_result_t result; 972135446Strhodes 973135446Strhodes debug("parse_args"); 974193149Sdougb while ((ch = isc_commandline_parse(argc, argv, PARSE_ARGS_FMT)) != -1) { 975135446Strhodes switch (ch) { 976135446Strhodes case 'd': 977135446Strhodes debugging = ISC_TRUE; 978135446Strhodes break; 979135446Strhodes case 'D': /* was -dd */ 980135446Strhodes debugging = ISC_TRUE; 981135446Strhodes ddebugging = ISC_TRUE; 982135446Strhodes break; 983193149Sdougb case 'M': 984135446Strhodes break; 985193149Sdougb case 'l': 986224092Sdougb local_only = ISC_TRUE; 987224092Sdougb break; 988224092Sdougb case 'L': 989193149Sdougb result = isc_parse_uint32(&i, isc_commandline_argument, 990193149Sdougb 10); 991193149Sdougb if (result != ISC_R_SUCCESS) { 992193149Sdougb fprintf(stderr, "bad library debug value " 993193149Sdougb "'%s'\n", isc_commandline_argument); 994193149Sdougb exit(1); 995193149Sdougb } 996193149Sdougb logdebuglevel = i; 997193149Sdougb break; 998135446Strhodes case 'y': 999135446Strhodes keystr = isc_commandline_argument; 1000135446Strhodes break; 1001135446Strhodes case 'v': 1002135446Strhodes usevc = ISC_TRUE; 1003135446Strhodes break; 1004135446Strhodes case 'k': 1005135446Strhodes keyfile = isc_commandline_argument; 1006135446Strhodes break; 1007193149Sdougb case 'g': 1008193149Sdougb usegsstsig = ISC_TRUE; 1009193149Sdougb use_win2k_gsstsig = ISC_FALSE; 1010193149Sdougb break; 1011193149Sdougb case 'o': 1012193149Sdougb usegsstsig = ISC_TRUE; 1013193149Sdougb use_win2k_gsstsig = ISC_TRUE; 1014193149Sdougb break; 1015224092Sdougb case 'p': 1016224092Sdougb result = isc_parse_uint16(&dnsport, 1017224092Sdougb isc_commandline_argument, 10); 1018224092Sdougb if (result != ISC_R_SUCCESS) { 1019224092Sdougb fprintf(stderr, "bad port number " 1020224092Sdougb "'%s'\n", isc_commandline_argument); 1021224092Sdougb exit(1); 1022224092Sdougb } 1023224092Sdougb break; 1024135446Strhodes case 't': 1025135446Strhodes result = isc_parse_uint32(&timeout, 1026135446Strhodes isc_commandline_argument, 10); 1027135446Strhodes if (result != ISC_R_SUCCESS) { 1028135446Strhodes fprintf(stderr, "bad timeout '%s'\n", isc_commandline_argument); 1029135446Strhodes exit(1); 1030135446Strhodes } 1031135446Strhodes if (timeout == 0) 1032143731Sdougb timeout = UINT_MAX; 1033135446Strhodes break; 1034135446Strhodes case 'u': 1035135446Strhodes result = isc_parse_uint32(&udp_timeout, 1036135446Strhodes isc_commandline_argument, 10); 1037135446Strhodes if (result != ISC_R_SUCCESS) { 1038135446Strhodes fprintf(stderr, "bad udp timeout '%s'\n", isc_commandline_argument); 1039135446Strhodes exit(1); 1040135446Strhodes } 1041135446Strhodes if (udp_timeout == 0) 1042143731Sdougb udp_timeout = UINT_MAX; 1043135446Strhodes break; 1044135446Strhodes case 'r': 1045135446Strhodes result = isc_parse_uint32(&udp_retries, 1046135446Strhodes isc_commandline_argument, 10); 1047135446Strhodes if (result != ISC_R_SUCCESS) { 1048135446Strhodes fprintf(stderr, "bad udp retries '%s'\n", isc_commandline_argument); 1049135446Strhodes exit(1); 1050135446Strhodes } 1051135446Strhodes break; 1052193149Sdougb 1053193149Sdougb case 'R': 1054193149Sdougb setup_entropy(mctx, isc_commandline_argument, ectx); 1055193149Sdougb break; 1056193149Sdougb 1057135446Strhodes default: 1058193149Sdougb fprintf(stderr, "%s: unhandled option: %c\n", 1059193149Sdougb argv[0], isc_commandline_option); 1060135446Strhodes exit(1); 1061135446Strhodes } 1062135446Strhodes } 1063135446Strhodes if (keyfile != NULL && keystr != NULL) { 1064135446Strhodes fprintf(stderr, "%s: cannot specify both -k and -y\n", 1065135446Strhodes argv[0]); 1066135446Strhodes exit(1); 1067135446Strhodes } 1068135446Strhodes 1069224092Sdougb if (local_only) { 1070224092Sdougb struct in_addr localhost; 1071224092Sdougb 1072224092Sdougb if (keyfile == NULL) 1073224092Sdougb keyfile = SESSION_KEYFILE; 1074224092Sdougb 1075224092Sdougb if (userserver == NULL) { 1076224092Sdougb userserver = isc_mem_get(mctx, sizeof(isc_sockaddr_t)); 1077224092Sdougb if (userserver == NULL) 1078224092Sdougb fatal("out of memory"); 1079224092Sdougb } 1080224092Sdougb 1081224092Sdougb localhost.s_addr = htonl(INADDR_LOOPBACK); 1082224092Sdougb isc_sockaddr_fromin(userserver, &localhost, dnsport); 1083224092Sdougb } 1084224092Sdougb 1085193149Sdougb#ifdef GSSAPI 1086193149Sdougb if (usegsstsig && (keyfile != NULL || keystr != NULL)) { 1087193149Sdougb fprintf(stderr, "%s: cannot specify -g with -k or -y\n", 1088193149Sdougb argv[0]); 1089193149Sdougb exit(1); 1090193149Sdougb } 1091193149Sdougb#else 1092193149Sdougb if (usegsstsig) { 1093224092Sdougb fprintf(stderr, "%s: cannot specify -g or -o, " \ 1094193149Sdougb "program not linked with GSS API Library\n", 1095193149Sdougb argv[0]); 1096193149Sdougb exit(1); 1097193149Sdougb } 1098193149Sdougb#endif 1099193149Sdougb 1100135446Strhodes if (argv[isc_commandline_index] != NULL) { 1101135446Strhodes if (strcmp(argv[isc_commandline_index], "-") == 0) { 1102135446Strhodes input = stdin; 1103135446Strhodes } else { 1104135446Strhodes result = isc_stdio_open(argv[isc_commandline_index], 1105135446Strhodes "r", &input); 1106135446Strhodes if (result != ISC_R_SUCCESS) { 1107135446Strhodes fprintf(stderr, "could not open '%s': %s\n", 1108135446Strhodes argv[isc_commandline_index], 1109135446Strhodes isc_result_totext(result)); 1110135446Strhodes exit(1); 1111135446Strhodes } 1112135446Strhodes } 1113135446Strhodes interactive = ISC_FALSE; 1114135446Strhodes } 1115135446Strhodes} 1116135446Strhodes 1117135446Strhodesstatic isc_uint16_t 1118135446Strhodesparse_name(char **cmdlinep, dns_message_t *msg, dns_name_t **namep) { 1119135446Strhodes isc_result_t result; 1120135446Strhodes char *word; 1121135446Strhodes isc_buffer_t *namebuf = NULL; 1122135446Strhodes isc_buffer_t source; 1123135446Strhodes 1124135446Strhodes word = nsu_strsep(cmdlinep, " \t\r\n"); 1125135446Strhodes if (*word == 0) { 1126135446Strhodes fprintf(stderr, "could not read owner name\n"); 1127135446Strhodes return (STATUS_SYNTAX); 1128135446Strhodes } 1129135446Strhodes 1130135446Strhodes result = dns_message_gettempname(msg, namep); 1131135446Strhodes check_result(result, "dns_message_gettempname"); 1132135446Strhodes result = isc_buffer_allocate(mctx, &namebuf, DNS_NAME_MAXWIRE); 1133135446Strhodes check_result(result, "isc_buffer_allocate"); 1134135446Strhodes dns_name_init(*namep, NULL); 1135135446Strhodes dns_name_setbuffer(*namep, namebuf); 1136135446Strhodes dns_message_takebuffer(msg, &namebuf); 1137135446Strhodes isc_buffer_init(&source, word, strlen(word)); 1138135446Strhodes isc_buffer_add(&source, strlen(word)); 1139224092Sdougb result = dns_name_fromtext(*namep, &source, dns_rootname, 0, NULL); 1140135446Strhodes check_result(result, "dns_name_fromtext"); 1141135446Strhodes isc_buffer_invalidate(&source); 1142135446Strhodes return (STATUS_MORE); 1143135446Strhodes} 1144135446Strhodes 1145135446Strhodesstatic isc_uint16_t 1146135446Strhodesparse_rdata(char **cmdlinep, dns_rdataclass_t rdataclass, 1147135446Strhodes dns_rdatatype_t rdatatype, dns_message_t *msg, 1148135446Strhodes dns_rdata_t *rdata) 1149135446Strhodes{ 1150135446Strhodes char *cmdline = *cmdlinep; 1151135446Strhodes isc_buffer_t source, *buf = NULL, *newbuf = NULL; 1152135446Strhodes isc_region_t r; 1153135446Strhodes isc_lex_t *lex = NULL; 1154135446Strhodes dns_rdatacallbacks_t callbacks; 1155135446Strhodes isc_result_t result; 1156135446Strhodes 1157135446Strhodes while (*cmdline != 0 && isspace((unsigned char)*cmdline)) 1158135446Strhodes cmdline++; 1159135446Strhodes 1160135446Strhodes if (*cmdline != 0) { 1161135446Strhodes dns_rdatacallbacks_init(&callbacks); 1162135446Strhodes result = isc_lex_create(mctx, strlen(cmdline), &lex); 1163135446Strhodes check_result(result, "isc_lex_create"); 1164135446Strhodes isc_buffer_init(&source, cmdline, strlen(cmdline)); 1165135446Strhodes isc_buffer_add(&source, strlen(cmdline)); 1166135446Strhodes result = isc_lex_openbuffer(lex, &source); 1167135446Strhodes check_result(result, "isc_lex_openbuffer"); 1168135446Strhodes result = isc_buffer_allocate(mctx, &buf, MAXWIRE); 1169135446Strhodes check_result(result, "isc_buffer_allocate"); 1170193149Sdougb result = dns_rdata_fromtext(NULL, rdataclass, rdatatype, lex, 1171135446Strhodes dns_rootname, 0, mctx, buf, 1172135446Strhodes &callbacks); 1173135446Strhodes isc_lex_destroy(&lex); 1174135446Strhodes if (result == ISC_R_SUCCESS) { 1175135446Strhodes isc_buffer_usedregion(buf, &r); 1176135446Strhodes result = isc_buffer_allocate(mctx, &newbuf, r.length); 1177135446Strhodes check_result(result, "isc_buffer_allocate"); 1178135446Strhodes isc_buffer_putmem(newbuf, r.base, r.length); 1179135446Strhodes isc_buffer_usedregion(newbuf, &r); 1180135446Strhodes dns_rdata_fromregion(rdata, rdataclass, rdatatype, &r); 1181135446Strhodes isc_buffer_free(&buf); 1182135446Strhodes dns_message_takebuffer(msg, &newbuf); 1183135446Strhodes } else { 1184135446Strhodes fprintf(stderr, "invalid rdata format: %s\n", 1185135446Strhodes isc_result_totext(result)); 1186135446Strhodes isc_buffer_free(&buf); 1187135446Strhodes return (STATUS_SYNTAX); 1188135446Strhodes } 1189135446Strhodes } else { 1190135446Strhodes rdata->flags = DNS_RDATA_UPDATE; 1191135446Strhodes } 1192135446Strhodes *cmdlinep = cmdline; 1193135446Strhodes return (STATUS_MORE); 1194135446Strhodes} 1195135446Strhodes 1196135446Strhodesstatic isc_uint16_t 1197135446Strhodesmake_prereq(char *cmdline, isc_boolean_t ispositive, isc_boolean_t isrrset) { 1198135446Strhodes isc_result_t result; 1199135446Strhodes char *word; 1200135446Strhodes dns_name_t *name = NULL; 1201135446Strhodes isc_textregion_t region; 1202135446Strhodes dns_rdataset_t *rdataset = NULL; 1203135446Strhodes dns_rdatalist_t *rdatalist = NULL; 1204135446Strhodes dns_rdataclass_t rdataclass; 1205135446Strhodes dns_rdatatype_t rdatatype; 1206135446Strhodes dns_rdata_t *rdata = NULL; 1207135446Strhodes isc_uint16_t retval; 1208135446Strhodes 1209135446Strhodes ddebug("make_prereq()"); 1210135446Strhodes 1211135446Strhodes /* 1212135446Strhodes * Read the owner name 1213135446Strhodes */ 1214135446Strhodes retval = parse_name(&cmdline, updatemsg, &name); 1215135446Strhodes if (retval != STATUS_MORE) 1216135446Strhodes return (retval); 1217135446Strhodes 1218135446Strhodes /* 1219135446Strhodes * If this is an rrset prereq, read the class or type. 1220135446Strhodes */ 1221135446Strhodes if (isrrset) { 1222135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1223135446Strhodes if (*word == 0) { 1224135446Strhodes fprintf(stderr, "could not read class or type\n"); 1225135446Strhodes goto failure; 1226135446Strhodes } 1227135446Strhodes region.base = word; 1228135446Strhodes region.length = strlen(word); 1229135446Strhodes result = dns_rdataclass_fromtext(&rdataclass, ®ion); 1230135446Strhodes if (result == ISC_R_SUCCESS) { 1231135446Strhodes if (!setzoneclass(rdataclass)) { 1232135446Strhodes fprintf(stderr, "class mismatch: %s\n", word); 1233135446Strhodes goto failure; 1234135446Strhodes } 1235135446Strhodes /* 1236135446Strhodes * Now read the type. 1237135446Strhodes */ 1238135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1239135446Strhodes if (*word == 0) { 1240135446Strhodes fprintf(stderr, "could not read type\n"); 1241135446Strhodes goto failure; 1242135446Strhodes } 1243135446Strhodes region.base = word; 1244135446Strhodes region.length = strlen(word); 1245135446Strhodes result = dns_rdatatype_fromtext(&rdatatype, ®ion); 1246135446Strhodes if (result != ISC_R_SUCCESS) { 1247135446Strhodes fprintf(stderr, "invalid type: %s\n", word); 1248135446Strhodes goto failure; 1249135446Strhodes } 1250135446Strhodes } else { 1251135446Strhodes rdataclass = getzoneclass(); 1252135446Strhodes result = dns_rdatatype_fromtext(&rdatatype, ®ion); 1253135446Strhodes if (result != ISC_R_SUCCESS) { 1254135446Strhodes fprintf(stderr, "invalid type: %s\n", word); 1255135446Strhodes goto failure; 1256135446Strhodes } 1257135446Strhodes } 1258135446Strhodes } else 1259135446Strhodes rdatatype = dns_rdatatype_any; 1260135446Strhodes 1261135446Strhodes result = dns_message_gettemprdata(updatemsg, &rdata); 1262135446Strhodes check_result(result, "dns_message_gettemprdata"); 1263135446Strhodes 1264193149Sdougb dns_rdata_init(rdata); 1265135446Strhodes 1266135446Strhodes if (isrrset && ispositive) { 1267135446Strhodes retval = parse_rdata(&cmdline, rdataclass, rdatatype, 1268135446Strhodes updatemsg, rdata); 1269135446Strhodes if (retval != STATUS_MORE) 1270135446Strhodes goto failure; 1271135446Strhodes } else 1272135446Strhodes rdata->flags = DNS_RDATA_UPDATE; 1273135446Strhodes 1274135446Strhodes result = dns_message_gettemprdatalist(updatemsg, &rdatalist); 1275135446Strhodes check_result(result, "dns_message_gettemprdatalist"); 1276135446Strhodes result = dns_message_gettemprdataset(updatemsg, &rdataset); 1277135446Strhodes check_result(result, "dns_message_gettemprdataset"); 1278135446Strhodes dns_rdatalist_init(rdatalist); 1279135446Strhodes rdatalist->type = rdatatype; 1280135446Strhodes if (ispositive) { 1281135446Strhodes if (isrrset && rdata->data != NULL) 1282135446Strhodes rdatalist->rdclass = rdataclass; 1283135446Strhodes else 1284135446Strhodes rdatalist->rdclass = dns_rdataclass_any; 1285135446Strhodes } else 1286135446Strhodes rdatalist->rdclass = dns_rdataclass_none; 1287135446Strhodes rdatalist->covers = 0; 1288135446Strhodes rdatalist->ttl = 0; 1289135446Strhodes rdata->rdclass = rdatalist->rdclass; 1290135446Strhodes rdata->type = rdatatype; 1291135446Strhodes ISC_LIST_INIT(rdatalist->rdata); 1292135446Strhodes ISC_LIST_APPEND(rdatalist->rdata, rdata, link); 1293135446Strhodes dns_rdataset_init(rdataset); 1294135446Strhodes dns_rdatalist_tordataset(rdatalist, rdataset); 1295135446Strhodes ISC_LIST_INIT(name->list); 1296135446Strhodes ISC_LIST_APPEND(name->list, rdataset, link); 1297135446Strhodes dns_message_addname(updatemsg, name, DNS_SECTION_PREREQUISITE); 1298135446Strhodes return (STATUS_MORE); 1299135446Strhodes 1300135446Strhodes failure: 1301135446Strhodes if (name != NULL) 1302135446Strhodes dns_message_puttempname(updatemsg, &name); 1303135446Strhodes return (STATUS_SYNTAX); 1304135446Strhodes} 1305135446Strhodes 1306135446Strhodesstatic isc_uint16_t 1307135446Strhodesevaluate_prereq(char *cmdline) { 1308135446Strhodes char *word; 1309135446Strhodes isc_boolean_t ispositive, isrrset; 1310135446Strhodes 1311135446Strhodes ddebug("evaluate_prereq()"); 1312135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1313135446Strhodes if (*word == 0) { 1314135446Strhodes fprintf(stderr, "could not read operation code\n"); 1315135446Strhodes return (STATUS_SYNTAX); 1316135446Strhodes } 1317135446Strhodes if (strcasecmp(word, "nxdomain") == 0) { 1318135446Strhodes ispositive = ISC_FALSE; 1319135446Strhodes isrrset = ISC_FALSE; 1320135446Strhodes } else if (strcasecmp(word, "yxdomain") == 0) { 1321135446Strhodes ispositive = ISC_TRUE; 1322135446Strhodes isrrset = ISC_FALSE; 1323135446Strhodes } else if (strcasecmp(word, "nxrrset") == 0) { 1324135446Strhodes ispositive = ISC_FALSE; 1325135446Strhodes isrrset = ISC_TRUE; 1326135446Strhodes } else if (strcasecmp(word, "yxrrset") == 0) { 1327135446Strhodes ispositive = ISC_TRUE; 1328135446Strhodes isrrset = ISC_TRUE; 1329135446Strhodes } else { 1330135446Strhodes fprintf(stderr, "incorrect operation code: %s\n", word); 1331135446Strhodes return (STATUS_SYNTAX); 1332135446Strhodes } 1333135446Strhodes return (make_prereq(cmdline, ispositive, isrrset)); 1334135446Strhodes} 1335135446Strhodes 1336135446Strhodesstatic isc_uint16_t 1337135446Strhodesevaluate_server(char *cmdline) { 1338135446Strhodes char *word, *server; 1339135446Strhodes long port; 1340135446Strhodes 1341224092Sdougb if (local_only) { 1342224092Sdougb fprintf(stderr, "cannot reset server in localhost-only mode\n"); 1343224092Sdougb return (STATUS_SYNTAX); 1344224092Sdougb } 1345224092Sdougb 1346135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1347135446Strhodes if (*word == 0) { 1348135446Strhodes fprintf(stderr, "could not read server name\n"); 1349135446Strhodes return (STATUS_SYNTAX); 1350135446Strhodes } 1351135446Strhodes server = word; 1352135446Strhodes 1353135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1354135446Strhodes if (*word == 0) 1355224092Sdougb port = dnsport; 1356135446Strhodes else { 1357135446Strhodes char *endp; 1358135446Strhodes port = strtol(word, &endp, 10); 1359135446Strhodes if (*endp != 0) { 1360135446Strhodes fprintf(stderr, "port '%s' is not numeric\n", word); 1361135446Strhodes return (STATUS_SYNTAX); 1362135446Strhodes } else if (port < 1 || port > 65535) { 1363135446Strhodes fprintf(stderr, "port '%s' is out of range " 1364135446Strhodes "(1 to 65535)\n", word); 1365135446Strhodes return (STATUS_SYNTAX); 1366135446Strhodes } 1367135446Strhodes } 1368135446Strhodes 1369135446Strhodes if (userserver == NULL) { 1370135446Strhodes userserver = isc_mem_get(mctx, sizeof(isc_sockaddr_t)); 1371135446Strhodes if (userserver == NULL) 1372135446Strhodes fatal("out of memory"); 1373135446Strhodes } 1374135446Strhodes 1375135446Strhodes get_address(server, (in_port_t)port, userserver); 1376135446Strhodes 1377135446Strhodes return (STATUS_MORE); 1378135446Strhodes} 1379135446Strhodes 1380135446Strhodesstatic isc_uint16_t 1381135446Strhodesevaluate_local(char *cmdline) { 1382135446Strhodes char *word, *local; 1383135446Strhodes long port; 1384135446Strhodes struct in_addr in4; 1385135446Strhodes struct in6_addr in6; 1386135446Strhodes 1387135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1388135446Strhodes if (*word == 0) { 1389135446Strhodes fprintf(stderr, "could not read server name\n"); 1390135446Strhodes return (STATUS_SYNTAX); 1391135446Strhodes } 1392135446Strhodes local = word; 1393135446Strhodes 1394135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1395135446Strhodes if (*word == 0) 1396135446Strhodes port = 0; 1397135446Strhodes else { 1398135446Strhodes char *endp; 1399135446Strhodes port = strtol(word, &endp, 10); 1400135446Strhodes if (*endp != 0) { 1401135446Strhodes fprintf(stderr, "port '%s' is not numeric\n", word); 1402135446Strhodes return (STATUS_SYNTAX); 1403135446Strhodes } else if (port < 1 || port > 65535) { 1404135446Strhodes fprintf(stderr, "port '%s' is out of range " 1405135446Strhodes "(1 to 65535)\n", word); 1406135446Strhodes return (STATUS_SYNTAX); 1407135446Strhodes } 1408135446Strhodes } 1409135446Strhodes 1410135446Strhodes if (localaddr == NULL) { 1411135446Strhodes localaddr = isc_mem_get(mctx, sizeof(isc_sockaddr_t)); 1412135446Strhodes if (localaddr == NULL) 1413135446Strhodes fatal("out of memory"); 1414135446Strhodes } 1415135446Strhodes 1416135446Strhodes if (have_ipv6 && inet_pton(AF_INET6, local, &in6) == 1) 1417135446Strhodes isc_sockaddr_fromin6(localaddr, &in6, (in_port_t)port); 1418135446Strhodes else if (have_ipv4 && inet_pton(AF_INET, local, &in4) == 1) 1419135446Strhodes isc_sockaddr_fromin(localaddr, &in4, (in_port_t)port); 1420135446Strhodes else { 1421135446Strhodes fprintf(stderr, "invalid address %s", local); 1422135446Strhodes return (STATUS_SYNTAX); 1423135446Strhodes } 1424135446Strhodes 1425135446Strhodes return (STATUS_MORE); 1426135446Strhodes} 1427135446Strhodes 1428135446Strhodesstatic isc_uint16_t 1429135446Strhodesevaluate_key(char *cmdline) { 1430135446Strhodes char *namestr; 1431135446Strhodes char *secretstr; 1432135446Strhodes isc_buffer_t b; 1433135446Strhodes isc_result_t result; 1434135446Strhodes dns_fixedname_t fkeyname; 1435135446Strhodes dns_name_t *keyname; 1436135446Strhodes int secretlen; 1437135446Strhodes unsigned char *secret = NULL; 1438135446Strhodes isc_buffer_t secretbuf; 1439170222Sdougb dns_name_t *hmacname = NULL; 1440170222Sdougb isc_uint16_t digestbits = 0; 1441170222Sdougb char *n; 1442135446Strhodes 1443135446Strhodes namestr = nsu_strsep(&cmdline, " \t\r\n"); 1444135446Strhodes if (*namestr == 0) { 1445135446Strhodes fprintf(stderr, "could not read key name\n"); 1446135446Strhodes return (STATUS_SYNTAX); 1447135446Strhodes } 1448135446Strhodes 1449135446Strhodes dns_fixedname_init(&fkeyname); 1450135446Strhodes keyname = dns_fixedname_name(&fkeyname); 1451135446Strhodes 1452170222Sdougb n = strchr(namestr, ':'); 1453170222Sdougb if (n != NULL) { 1454170222Sdougb digestbits = parse_hmac(&hmacname, namestr, n - namestr); 1455170222Sdougb namestr = n + 1; 1456170222Sdougb } else 1457170222Sdougb hmacname = DNS_TSIG_HMACMD5_NAME; 1458170222Sdougb 1459135446Strhodes isc_buffer_init(&b, namestr, strlen(namestr)); 1460135446Strhodes isc_buffer_add(&b, strlen(namestr)); 1461224092Sdougb result = dns_name_fromtext(keyname, &b, dns_rootname, 0, NULL); 1462135446Strhodes if (result != ISC_R_SUCCESS) { 1463135446Strhodes fprintf(stderr, "could not parse key name\n"); 1464135446Strhodes return (STATUS_SYNTAX); 1465135446Strhodes } 1466135446Strhodes 1467135446Strhodes secretstr = nsu_strsep(&cmdline, "\r\n"); 1468135446Strhodes if (*secretstr == 0) { 1469135446Strhodes fprintf(stderr, "could not read key secret\n"); 1470135446Strhodes return (STATUS_SYNTAX); 1471135446Strhodes } 1472135446Strhodes secretlen = strlen(secretstr) * 3 / 4; 1473135446Strhodes secret = isc_mem_allocate(mctx, secretlen); 1474135446Strhodes if (secret == NULL) 1475135446Strhodes fatal("out of memory"); 1476186462Sdougb 1477135446Strhodes isc_buffer_init(&secretbuf, secret, secretlen); 1478135446Strhodes result = isc_base64_decodestring(secretstr, &secretbuf); 1479135446Strhodes if (result != ISC_R_SUCCESS) { 1480135446Strhodes fprintf(stderr, "could not create key from %s: %s\n", 1481135446Strhodes secretstr, isc_result_totext(result)); 1482135446Strhodes isc_mem_free(mctx, secret); 1483135446Strhodes return (STATUS_SYNTAX); 1484135446Strhodes } 1485135446Strhodes secretlen = isc_buffer_usedlength(&secretbuf); 1486135446Strhodes 1487135446Strhodes if (tsigkey != NULL) 1488135446Strhodes dns_tsigkey_detach(&tsigkey); 1489170222Sdougb result = dns_tsigkey_create(keyname, hmacname, secret, secretlen, 1490218384Sdougb ISC_FALSE, NULL, 0, 0, mctx, NULL, 1491170222Sdougb &tsigkey); 1492135446Strhodes isc_mem_free(mctx, secret); 1493135446Strhodes if (result != ISC_R_SUCCESS) { 1494135446Strhodes fprintf(stderr, "could not create key from %s %s: %s\n", 1495135446Strhodes namestr, secretstr, dns_result_totext(result)); 1496135446Strhodes return (STATUS_SYNTAX); 1497135446Strhodes } 1498170222Sdougb dst_key_setbits(tsigkey->key, digestbits); 1499135446Strhodes return (STATUS_MORE); 1500135446Strhodes} 1501135446Strhodes 1502135446Strhodesstatic isc_uint16_t 1503135446Strhodesevaluate_zone(char *cmdline) { 1504135446Strhodes char *word; 1505135446Strhodes isc_buffer_t b; 1506135446Strhodes isc_result_t result; 1507135446Strhodes 1508135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1509135446Strhodes if (*word == 0) { 1510135446Strhodes fprintf(stderr, "could not read zone name\n"); 1511135446Strhodes return (STATUS_SYNTAX); 1512135446Strhodes } 1513135446Strhodes 1514135446Strhodes dns_fixedname_init(&fuserzone); 1515135446Strhodes userzone = dns_fixedname_name(&fuserzone); 1516135446Strhodes isc_buffer_init(&b, word, strlen(word)); 1517135446Strhodes isc_buffer_add(&b, strlen(word)); 1518224092Sdougb result = dns_name_fromtext(userzone, &b, dns_rootname, 0, NULL); 1519135446Strhodes if (result != ISC_R_SUCCESS) { 1520135446Strhodes userzone = NULL; /* Lest it point to an invalid name */ 1521135446Strhodes fprintf(stderr, "could not parse zone name\n"); 1522135446Strhodes return (STATUS_SYNTAX); 1523135446Strhodes } 1524135446Strhodes 1525135446Strhodes return (STATUS_MORE); 1526135446Strhodes} 1527135446Strhodes 1528135446Strhodesstatic isc_uint16_t 1529218384Sdougbevaluate_realm(char *cmdline) { 1530218384Sdougb#ifdef GSSAPI 1531218384Sdougb char *word; 1532218384Sdougb char buf[1024]; 1533218384Sdougb 1534218384Sdougb word = nsu_strsep(&cmdline, " \t\r\n"); 1535218384Sdougb if (*word == 0) { 1536218384Sdougb if (realm != NULL) 1537218384Sdougb isc_mem_free(mctx, realm); 1538218384Sdougb realm = NULL; 1539218384Sdougb return (STATUS_MORE); 1540218384Sdougb } 1541218384Sdougb 1542218384Sdougb snprintf(buf, sizeof(buf), "@%s", word); 1543218384Sdougb realm = isc_mem_strdup(mctx, buf); 1544218384Sdougb if (realm == NULL) 1545218384Sdougb fatal("out of memory"); 1546218384Sdougb return (STATUS_MORE); 1547218384Sdougb#else 1548218384Sdougb UNUSED(cmdline); 1549218384Sdougb return (STATUS_SYNTAX); 1550218384Sdougb#endif 1551218384Sdougb} 1552218384Sdougb 1553218384Sdougbstatic isc_uint16_t 1554193149Sdougbevaluate_ttl(char *cmdline) { 1555193149Sdougb char *word; 1556193149Sdougb isc_result_t result; 1557193149Sdougb isc_uint32_t ttl; 1558193149Sdougb 1559193149Sdougb word = nsu_strsep(&cmdline, " \t\r\n"); 1560193149Sdougb if (*word == 0) { 1561193149Sdougb fprintf(stderr, "could not ttl\n"); 1562193149Sdougb return (STATUS_SYNTAX); 1563193149Sdougb } 1564193149Sdougb 1565193149Sdougb if (!strcasecmp(word, "none")) { 1566193149Sdougb default_ttl = 0; 1567193149Sdougb default_ttl_set = ISC_FALSE; 1568193149Sdougb return (STATUS_MORE); 1569193149Sdougb } 1570193149Sdougb 1571193149Sdougb result = isc_parse_uint32(&ttl, word, 10); 1572193149Sdougb if (result != ISC_R_SUCCESS) 1573193149Sdougb return (STATUS_SYNTAX); 1574193149Sdougb 1575193149Sdougb if (ttl > TTL_MAX) { 1576193149Sdougb fprintf(stderr, "ttl '%s' is out of range (0 to %u)\n", 1577193149Sdougb word, TTL_MAX); 1578193149Sdougb return (STATUS_SYNTAX); 1579193149Sdougb } 1580193149Sdougb default_ttl = ttl; 1581193149Sdougb default_ttl_set = ISC_TRUE; 1582193149Sdougb 1583193149Sdougb return (STATUS_MORE); 1584193149Sdougb} 1585193149Sdougb 1586193149Sdougbstatic isc_uint16_t 1587135446Strhodesevaluate_class(char *cmdline) { 1588135446Strhodes char *word; 1589135446Strhodes isc_textregion_t r; 1590135446Strhodes isc_result_t result; 1591135446Strhodes dns_rdataclass_t rdclass; 1592135446Strhodes 1593135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1594135446Strhodes if (*word == 0) { 1595135446Strhodes fprintf(stderr, "could not read class name\n"); 1596135446Strhodes return (STATUS_SYNTAX); 1597135446Strhodes } 1598135446Strhodes 1599135446Strhodes r.base = word; 1600186462Sdougb r.length = strlen(word); 1601186462Sdougb result = dns_rdataclass_fromtext(&rdclass, &r); 1602135446Strhodes if (result != ISC_R_SUCCESS) { 1603135446Strhodes fprintf(stderr, "could not parse class name: %s\n", word); 1604135446Strhodes return (STATUS_SYNTAX); 1605135446Strhodes } 1606135446Strhodes switch (rdclass) { 1607135446Strhodes case dns_rdataclass_none: 1608135446Strhodes case dns_rdataclass_any: 1609135446Strhodes case dns_rdataclass_reserved0: 1610135446Strhodes fprintf(stderr, "bad default class: %s\n", word); 1611135446Strhodes return (STATUS_SYNTAX); 1612135446Strhodes default: 1613135446Strhodes defaultclass = rdclass; 1614135446Strhodes } 1615135446Strhodes 1616135446Strhodes return (STATUS_MORE); 1617135446Strhodes} 1618135446Strhodes 1619135446Strhodesstatic isc_uint16_t 1620135446Strhodesupdate_addordelete(char *cmdline, isc_boolean_t isdelete) { 1621135446Strhodes isc_result_t result; 1622135446Strhodes dns_name_t *name = NULL; 1623135446Strhodes isc_uint32_t ttl; 1624135446Strhodes char *word; 1625135446Strhodes dns_rdataclass_t rdataclass; 1626135446Strhodes dns_rdatatype_t rdatatype; 1627135446Strhodes dns_rdata_t *rdata = NULL; 1628135446Strhodes dns_rdatalist_t *rdatalist = NULL; 1629135446Strhodes dns_rdataset_t *rdataset = NULL; 1630135446Strhodes isc_textregion_t region; 1631135446Strhodes isc_uint16_t retval; 1632135446Strhodes 1633135446Strhodes ddebug("update_addordelete()"); 1634135446Strhodes 1635135446Strhodes /* 1636135446Strhodes * Read the owner name. 1637135446Strhodes */ 1638135446Strhodes retval = parse_name(&cmdline, updatemsg, &name); 1639135446Strhodes if (retval != STATUS_MORE) 1640135446Strhodes return (retval); 1641135446Strhodes 1642135446Strhodes result = dns_message_gettemprdata(updatemsg, &rdata); 1643135446Strhodes check_result(result, "dns_message_gettemprdata"); 1644135446Strhodes 1645193149Sdougb dns_rdata_init(rdata); 1646135446Strhodes 1647135446Strhodes /* 1648135446Strhodes * If this is an add, read the TTL and verify that it's in range. 1649135446Strhodes * If it's a delete, ignore a TTL if present (for compatibility). 1650135446Strhodes */ 1651135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1652135446Strhodes if (*word == 0) { 1653135446Strhodes if (!isdelete) { 1654135446Strhodes fprintf(stderr, "could not read owner ttl\n"); 1655135446Strhodes goto failure; 1656135446Strhodes } 1657135446Strhodes else { 1658135446Strhodes ttl = 0; 1659135446Strhodes rdataclass = dns_rdataclass_any; 1660135446Strhodes rdatatype = dns_rdatatype_any; 1661135446Strhodes rdata->flags = DNS_RDATA_UPDATE; 1662135446Strhodes goto doneparsing; 1663135446Strhodes } 1664135446Strhodes } 1665135446Strhodes result = isc_parse_uint32(&ttl, word, 10); 1666135446Strhodes if (result != ISC_R_SUCCESS) { 1667135446Strhodes if (isdelete) { 1668135446Strhodes ttl = 0; 1669135446Strhodes goto parseclass; 1670193149Sdougb } else if (default_ttl_set) { 1671193149Sdougb ttl = default_ttl; 1672193149Sdougb goto parseclass; 1673135446Strhodes } else { 1674135446Strhodes fprintf(stderr, "ttl '%s': %s\n", word, 1675135446Strhodes isc_result_totext(result)); 1676135446Strhodes goto failure; 1677135446Strhodes } 1678135446Strhodes } 1679135446Strhodes 1680135446Strhodes if (isdelete) 1681135446Strhodes ttl = 0; 1682135446Strhodes else if (ttl > TTL_MAX) { 1683135446Strhodes fprintf(stderr, "ttl '%s' is out of range (0 to %u)\n", 1684135446Strhodes word, TTL_MAX); 1685135446Strhodes goto failure; 1686135446Strhodes } 1687135446Strhodes 1688135446Strhodes /* 1689135446Strhodes * Read the class or type. 1690135446Strhodes */ 1691135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1692135446Strhodes parseclass: 1693135446Strhodes if (*word == 0) { 1694135446Strhodes if (isdelete) { 1695135446Strhodes rdataclass = dns_rdataclass_any; 1696135446Strhodes rdatatype = dns_rdatatype_any; 1697135446Strhodes rdata->flags = DNS_RDATA_UPDATE; 1698135446Strhodes goto doneparsing; 1699135446Strhodes } else { 1700135446Strhodes fprintf(stderr, "could not read class or type\n"); 1701135446Strhodes goto failure; 1702135446Strhodes } 1703135446Strhodes } 1704135446Strhodes region.base = word; 1705135446Strhodes region.length = strlen(word); 1706193149Sdougb rdataclass = dns_rdataclass_any; 1707135446Strhodes result = dns_rdataclass_fromtext(&rdataclass, ®ion); 1708193149Sdougb if (result == ISC_R_SUCCESS && rdataclass != dns_rdataclass_any) { 1709135446Strhodes if (!setzoneclass(rdataclass)) { 1710135446Strhodes fprintf(stderr, "class mismatch: %s\n", word); 1711135446Strhodes goto failure; 1712135446Strhodes } 1713135446Strhodes /* 1714135446Strhodes * Now read the type. 1715135446Strhodes */ 1716135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1717135446Strhodes if (*word == 0) { 1718135446Strhodes if (isdelete) { 1719135446Strhodes rdataclass = dns_rdataclass_any; 1720135446Strhodes rdatatype = dns_rdatatype_any; 1721135446Strhodes rdata->flags = DNS_RDATA_UPDATE; 1722135446Strhodes goto doneparsing; 1723135446Strhodes } else { 1724135446Strhodes fprintf(stderr, "could not read type\n"); 1725135446Strhodes goto failure; 1726135446Strhodes } 1727135446Strhodes } 1728135446Strhodes region.base = word; 1729135446Strhodes region.length = strlen(word); 1730135446Strhodes result = dns_rdatatype_fromtext(&rdatatype, ®ion); 1731135446Strhodes if (result != ISC_R_SUCCESS) { 1732135446Strhodes fprintf(stderr, "'%s' is not a valid type: %s\n", 1733135446Strhodes word, isc_result_totext(result)); 1734135446Strhodes goto failure; 1735135446Strhodes } 1736135446Strhodes } else { 1737135446Strhodes rdataclass = getzoneclass(); 1738135446Strhodes result = dns_rdatatype_fromtext(&rdatatype, ®ion); 1739135446Strhodes if (result != ISC_R_SUCCESS) { 1740135446Strhodes fprintf(stderr, "'%s' is not a valid class or type: " 1741135446Strhodes "%s\n", word, isc_result_totext(result)); 1742135446Strhodes goto failure; 1743135446Strhodes } 1744135446Strhodes } 1745135446Strhodes 1746135446Strhodes retval = parse_rdata(&cmdline, rdataclass, rdatatype, updatemsg, 1747135446Strhodes rdata); 1748135446Strhodes if (retval != STATUS_MORE) 1749135446Strhodes goto failure; 1750135446Strhodes 1751135446Strhodes if (isdelete) { 1752135446Strhodes if ((rdata->flags & DNS_RDATA_UPDATE) != 0) 1753135446Strhodes rdataclass = dns_rdataclass_any; 1754135446Strhodes else 1755135446Strhodes rdataclass = dns_rdataclass_none; 1756135446Strhodes } else { 1757135446Strhodes if ((rdata->flags & DNS_RDATA_UPDATE) != 0) { 1758135446Strhodes fprintf(stderr, "could not read rdata\n"); 1759135446Strhodes goto failure; 1760135446Strhodes } 1761135446Strhodes } 1762135446Strhodes 1763135446Strhodes doneparsing: 1764135446Strhodes 1765135446Strhodes result = dns_message_gettemprdatalist(updatemsg, &rdatalist); 1766135446Strhodes check_result(result, "dns_message_gettemprdatalist"); 1767135446Strhodes result = dns_message_gettemprdataset(updatemsg, &rdataset); 1768135446Strhodes check_result(result, "dns_message_gettemprdataset"); 1769135446Strhodes dns_rdatalist_init(rdatalist); 1770135446Strhodes rdatalist->type = rdatatype; 1771135446Strhodes rdatalist->rdclass = rdataclass; 1772135446Strhodes rdatalist->covers = rdatatype; 1773135446Strhodes rdatalist->ttl = (dns_ttl_t)ttl; 1774135446Strhodes ISC_LIST_INIT(rdatalist->rdata); 1775135446Strhodes ISC_LIST_APPEND(rdatalist->rdata, rdata, link); 1776135446Strhodes dns_rdataset_init(rdataset); 1777135446Strhodes dns_rdatalist_tordataset(rdatalist, rdataset); 1778135446Strhodes ISC_LIST_INIT(name->list); 1779135446Strhodes ISC_LIST_APPEND(name->list, rdataset, link); 1780135446Strhodes dns_message_addname(updatemsg, name, DNS_SECTION_UPDATE); 1781135446Strhodes return (STATUS_MORE); 1782135446Strhodes 1783135446Strhodes failure: 1784135446Strhodes if (name != NULL) 1785135446Strhodes dns_message_puttempname(updatemsg, &name); 1786186462Sdougb dns_message_puttemprdata(updatemsg, &rdata); 1787135446Strhodes return (STATUS_SYNTAX); 1788135446Strhodes} 1789135446Strhodes 1790135446Strhodesstatic isc_uint16_t 1791135446Strhodesevaluate_update(char *cmdline) { 1792135446Strhodes char *word; 1793135446Strhodes isc_boolean_t isdelete; 1794135446Strhodes 1795135446Strhodes ddebug("evaluate_update()"); 1796135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1797135446Strhodes if (*word == 0) { 1798135446Strhodes fprintf(stderr, "could not read operation code\n"); 1799135446Strhodes return (STATUS_SYNTAX); 1800135446Strhodes } 1801135446Strhodes if (strcasecmp(word, "delete") == 0) 1802135446Strhodes isdelete = ISC_TRUE; 1803135446Strhodes else if (strcasecmp(word, "add") == 0) 1804135446Strhodes isdelete = ISC_FALSE; 1805135446Strhodes else { 1806135446Strhodes fprintf(stderr, "incorrect operation code: %s\n", word); 1807135446Strhodes return (STATUS_SYNTAX); 1808135446Strhodes } 1809135446Strhodes return (update_addordelete(cmdline, isdelete)); 1810135446Strhodes} 1811135446Strhodes 1812135446Strhodesstatic void 1813170222Sdougbsetzone(dns_name_t *zonename) { 1814170222Sdougb isc_result_t result; 1815170222Sdougb dns_name_t *name = NULL; 1816170222Sdougb dns_rdataset_t *rdataset = NULL; 1817170222Sdougb 1818170222Sdougb result = dns_message_firstname(updatemsg, DNS_SECTION_ZONE); 1819170222Sdougb if (result == ISC_R_SUCCESS) { 1820170222Sdougb dns_message_currentname(updatemsg, DNS_SECTION_ZONE, &name); 1821170222Sdougb dns_message_removename(updatemsg, name, DNS_SECTION_ZONE); 1822170222Sdougb for (rdataset = ISC_LIST_HEAD(name->list); 1823170222Sdougb rdataset != NULL; 1824170222Sdougb rdataset = ISC_LIST_HEAD(name->list)) { 1825170222Sdougb ISC_LIST_UNLINK(name->list, rdataset, link); 1826170222Sdougb dns_rdataset_disassociate(rdataset); 1827170222Sdougb dns_message_puttemprdataset(updatemsg, &rdataset); 1828170222Sdougb } 1829170222Sdougb dns_message_puttempname(updatemsg, &name); 1830170222Sdougb } 1831170222Sdougb 1832170222Sdougb if (zonename != NULL) { 1833170222Sdougb result = dns_message_gettempname(updatemsg, &name); 1834170222Sdougb check_result(result, "dns_message_gettempname"); 1835170222Sdougb dns_name_init(name, NULL); 1836170222Sdougb dns_name_clone(zonename, name); 1837170222Sdougb result = dns_message_gettemprdataset(updatemsg, &rdataset); 1838170222Sdougb check_result(result, "dns_message_gettemprdataset"); 1839170222Sdougb dns_rdataset_makequestion(rdataset, getzoneclass(), 1840170222Sdougb dns_rdatatype_soa); 1841170222Sdougb ISC_LIST_INIT(name->list); 1842170222Sdougb ISC_LIST_APPEND(name->list, rdataset, link); 1843170222Sdougb dns_message_addname(updatemsg, name, DNS_SECTION_ZONE); 1844170222Sdougb } 1845170222Sdougb} 1846170222Sdougb 1847170222Sdougbstatic void 1848193149Sdougbshow_message(FILE *stream, dns_message_t *msg, const char *description) { 1849135446Strhodes isc_result_t result; 1850135446Strhodes isc_buffer_t *buf = NULL; 1851135446Strhodes int bufsz; 1852135446Strhodes 1853135446Strhodes ddebug("show_message()"); 1854170222Sdougb 1855170222Sdougb setzone(userzone); 1856170222Sdougb 1857135446Strhodes bufsz = INITTEXT; 1858186462Sdougb do { 1859135446Strhodes if (bufsz > MAXTEXT) { 1860135446Strhodes fprintf(stderr, "could not allocate large enough " 1861135446Strhodes "buffer to display message\n"); 1862135446Strhodes exit(1); 1863135446Strhodes } 1864135446Strhodes if (buf != NULL) 1865135446Strhodes isc_buffer_free(&buf); 1866135446Strhodes result = isc_buffer_allocate(mctx, &buf, bufsz); 1867135446Strhodes check_result(result, "isc_buffer_allocate"); 1868135446Strhodes result = dns_message_totext(msg, style, 0, buf); 1869135446Strhodes bufsz *= 2; 1870135446Strhodes } while (result == ISC_R_NOSPACE); 1871135446Strhodes if (result != ISC_R_SUCCESS) { 1872135446Strhodes fprintf(stderr, "could not convert message to text format.\n"); 1873135446Strhodes isc_buffer_free(&buf); 1874135446Strhodes return; 1875135446Strhodes } 1876193149Sdougb fprintf(stream, "%s\n%.*s", description, 1877193149Sdougb (int)isc_buffer_usedlength(buf), (char*)isc_buffer_base(buf)); 1878135446Strhodes isc_buffer_free(&buf); 1879135446Strhodes} 1880135446Strhodes 1881135446Strhodes 1882135446Strhodesstatic isc_uint16_t 1883135446Strhodesget_next_command(void) { 1884135446Strhodes char cmdlinebuf[MAXCMD]; 1885135446Strhodes char *cmdline; 1886135446Strhodes char *word; 1887135446Strhodes 1888135446Strhodes ddebug("get_next_command()"); 1889165071Sdougb if (interactive) { 1890135446Strhodes fprintf(stdout, "> "); 1891165071Sdougb fflush(stdout); 1892165071Sdougb } 1893135446Strhodes isc_app_block(); 1894135446Strhodes cmdline = fgets(cmdlinebuf, MAXCMD, input); 1895135446Strhodes isc_app_unblock(); 1896135446Strhodes if (cmdline == NULL) 1897135446Strhodes return (STATUS_QUIT); 1898135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1899135446Strhodes 1900135446Strhodes if (feof(input)) 1901135446Strhodes return (STATUS_QUIT); 1902135446Strhodes if (*word == 0) 1903135446Strhodes return (STATUS_SEND); 1904135446Strhodes if (word[0] == ';') 1905135446Strhodes return (STATUS_MORE); 1906135446Strhodes if (strcasecmp(word, "quit") == 0) 1907135446Strhodes return (STATUS_QUIT); 1908135446Strhodes if (strcasecmp(word, "prereq") == 0) 1909135446Strhodes return (evaluate_prereq(cmdline)); 1910135446Strhodes if (strcasecmp(word, "update") == 0) 1911135446Strhodes return (evaluate_update(cmdline)); 1912135446Strhodes if (strcasecmp(word, "server") == 0) 1913135446Strhodes return (evaluate_server(cmdline)); 1914135446Strhodes if (strcasecmp(word, "local") == 0) 1915135446Strhodes return (evaluate_local(cmdline)); 1916135446Strhodes if (strcasecmp(word, "zone") == 0) 1917135446Strhodes return (evaluate_zone(cmdline)); 1918135446Strhodes if (strcasecmp(word, "class") == 0) 1919135446Strhodes return (evaluate_class(cmdline)); 1920135446Strhodes if (strcasecmp(word, "send") == 0) 1921135446Strhodes return (STATUS_SEND); 1922193149Sdougb if (strcasecmp(word, "debug") == 0) { 1923193149Sdougb if (debugging) 1924193149Sdougb ddebugging = ISC_TRUE; 1925193149Sdougb else 1926193149Sdougb debugging = ISC_TRUE; 1927193149Sdougb return (STATUS_MORE); 1928193149Sdougb } 1929193149Sdougb if (strcasecmp(word, "ttl") == 0) 1930193149Sdougb return (evaluate_ttl(cmdline)); 1931135446Strhodes if (strcasecmp(word, "show") == 0) { 1932193149Sdougb show_message(stdout, updatemsg, "Outgoing update query:"); 1933135446Strhodes return (STATUS_MORE); 1934135446Strhodes } 1935135446Strhodes if (strcasecmp(word, "answer") == 0) { 1936135446Strhodes if (answer != NULL) 1937193149Sdougb show_message(stdout, answer, "Answer:"); 1938135446Strhodes return (STATUS_MORE); 1939135446Strhodes } 1940193149Sdougb if (strcasecmp(word, "key") == 0) { 1941193149Sdougb usegsstsig = ISC_FALSE; 1942135446Strhodes return (evaluate_key(cmdline)); 1943193149Sdougb } 1944218384Sdougb if (strcasecmp(word, "realm") == 0) 1945218384Sdougb return (evaluate_realm(cmdline)); 1946193149Sdougb if (strcasecmp(word, "gsstsig") == 0) { 1947193149Sdougb#ifdef GSSAPI 1948193149Sdougb usegsstsig = ISC_TRUE; 1949193149Sdougb use_win2k_gsstsig = ISC_FALSE; 1950193149Sdougb#else 1951193149Sdougb fprintf(stderr, "gsstsig not supported\n"); 1952193149Sdougb#endif 1953193149Sdougb return (STATUS_MORE); 1954193149Sdougb } 1955193149Sdougb if (strcasecmp(word, "oldgsstsig") == 0) { 1956193149Sdougb#ifdef GSSAPI 1957193149Sdougb usegsstsig = ISC_TRUE; 1958193149Sdougb use_win2k_gsstsig = ISC_TRUE; 1959193149Sdougb#else 1960193149Sdougb fprintf(stderr, "gsstsig not supported\n"); 1961193149Sdougb#endif 1962193149Sdougb return (STATUS_MORE); 1963193149Sdougb } 1964193149Sdougb if (strcasecmp(word, "help") == 0) { 1965193149Sdougb fprintf(stdout, 1966193149Sdougb"local address [port] (set local resolver)\n" 1967193149Sdougb"server address [port] (set master server for zone)\n" 1968193149Sdougb"send (send the update request)\n" 1969193149Sdougb"show (show the update request)\n" 1970224092Sdougb"answer (show the answer to the last request)\n" 1971193149Sdougb"quit (quit, any pending update is not sent\n" 1972224092Sdougb"help (display this message_\n" 1973193149Sdougb"key [hmac:]keyname secret (use TSIG to sign the request)\n" 1974193149Sdougb"gsstsig (use GSS_TSIG to sign the request)\n" 1975193149Sdougb"oldgsstsig (use Microsoft's GSS_TSIG to sign the request)\n" 1976193149Sdougb"zone name (set the zone to be updated)\n" 1977193149Sdougb"class CLASS (set the zone's DNS class, e.g. IN (default), CH)\n" 1978193149Sdougb"prereq nxdomain name (does this name not exist)\n" 1979193149Sdougb"prereq yxdomain name (does this name exist)\n" 1980193149Sdougb"prereq nxrrset .... (does this RRset exist)\n" 1981193149Sdougb"prereq yxrrset .... (does this RRset not exist)\n" 1982193149Sdougb"update add .... (add the given record to the zone)\n" 1983193149Sdougb"update delete .... (remove the given record(s) from the zone)\n"); 1984193149Sdougb return (STATUS_MORE); 1985193149Sdougb } 1986135446Strhodes fprintf(stderr, "incorrect section name: %s\n", word); 1987135446Strhodes return (STATUS_SYNTAX); 1988135446Strhodes} 1989135446Strhodes 1990135446Strhodesstatic isc_boolean_t 1991135446Strhodesuser_interaction(void) { 1992135446Strhodes isc_uint16_t result = STATUS_MORE; 1993135446Strhodes 1994135446Strhodes ddebug("user_interaction()"); 1995174187Sdougb while ((result == STATUS_MORE) || (result == STATUS_SYNTAX)) { 1996135446Strhodes result = get_next_command(); 1997174187Sdougb if (!interactive && result == STATUS_SYNTAX) 1998174187Sdougb fatal("syntax error"); 1999174187Sdougb } 2000135446Strhodes if (result == STATUS_SEND) 2001135446Strhodes return (ISC_TRUE); 2002135446Strhodes return (ISC_FALSE); 2003135446Strhodes 2004135446Strhodes} 2005135446Strhodes 2006135446Strhodesstatic void 2007135446Strhodesdone_update(void) { 2008135446Strhodes isc_event_t *event = global_event; 2009135446Strhodes ddebug("done_update()"); 2010135446Strhodes isc_task_send(global_task, &event); 2011135446Strhodes} 2012135446Strhodes 2013135446Strhodesstatic void 2014135446Strhodescheck_tsig_error(dns_rdataset_t *rdataset, isc_buffer_t *b) { 2015135446Strhodes isc_result_t result; 2016135446Strhodes dns_rdata_t rdata = DNS_RDATA_INIT; 2017135446Strhodes dns_rdata_any_tsig_t tsig; 2018135446Strhodes 2019135446Strhodes result = dns_rdataset_first(rdataset); 2020135446Strhodes check_result(result, "dns_rdataset_first"); 2021135446Strhodes dns_rdataset_current(rdataset, &rdata); 2022135446Strhodes result = dns_rdata_tostruct(&rdata, &tsig, NULL); 2023135446Strhodes check_result(result, "dns_rdata_tostruct"); 2024135446Strhodes if (tsig.error != 0) { 2025135446Strhodes if (isc_buffer_remaininglength(b) < 1) 2026135446Strhodes check_result(ISC_R_NOSPACE, "isc_buffer_remaininglength"); 2027135446Strhodes isc__buffer_putstr(b, "(" /*)*/); 2028135446Strhodes result = dns_tsigrcode_totext(tsig.error, b); 2029135446Strhodes check_result(result, "dns_tsigrcode_totext"); 2030135446Strhodes if (isc_buffer_remaininglength(b) < 1) 2031135446Strhodes check_result(ISC_R_NOSPACE, "isc_buffer_remaininglength"); 2032135446Strhodes isc__buffer_putstr(b, /*(*/ ")"); 2033135446Strhodes } 2034135446Strhodes} 2035135446Strhodes 2036135446Strhodesstatic void 2037135446Strhodesupdate_completed(isc_task_t *task, isc_event_t *event) { 2038135446Strhodes dns_requestevent_t *reqev = NULL; 2039135446Strhodes isc_result_t result; 2040135446Strhodes dns_request_t *request; 2041135446Strhodes 2042135446Strhodes UNUSED(task); 2043135446Strhodes 2044135446Strhodes ddebug("update_completed()"); 2045135446Strhodes 2046135446Strhodes requests--; 2047135446Strhodes 2048135446Strhodes REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE); 2049135446Strhodes reqev = (dns_requestevent_t *)event; 2050135446Strhodes request = reqev->request; 2051135446Strhodes 2052135446Strhodes if (shuttingdown) { 2053135446Strhodes dns_request_destroy(&request); 2054135446Strhodes isc_event_free(&event); 2055135446Strhodes maybeshutdown(); 2056135446Strhodes return; 2057135446Strhodes } 2058135446Strhodes 2059135446Strhodes if (reqev->result != ISC_R_SUCCESS) { 2060135446Strhodes fprintf(stderr, "; Communication with server failed: %s\n", 2061135446Strhodes isc_result_totext(reqev->result)); 2062135446Strhodes seenerror = ISC_TRUE; 2063135446Strhodes goto done; 2064135446Strhodes } 2065135446Strhodes 2066135446Strhodes result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &answer); 2067135446Strhodes check_result(result, "dns_message_create"); 2068135446Strhodes result = dns_request_getresponse(request, answer, 2069135446Strhodes DNS_MESSAGEPARSE_PRESERVEORDER); 2070135446Strhodes switch (result) { 2071135446Strhodes case ISC_R_SUCCESS: 2072193149Sdougb if (answer->verify_attempted) 2073193149Sdougb ddebug("tsig verification successful"); 2074135446Strhodes break; 2075135446Strhodes case DNS_R_CLOCKSKEW: 2076135446Strhodes case DNS_R_EXPECTEDTSIG: 2077135446Strhodes case DNS_R_TSIGERRORSET: 2078135446Strhodes case DNS_R_TSIGVERIFYFAILURE: 2079135446Strhodes case DNS_R_UNEXPECTEDTSIG: 2080193149Sdougb case ISC_R_FAILURE: 2081193149Sdougb#if 0 2082193149Sdougb if (usegsstsig && answer->rcode == dns_rcode_noerror) { 2083193149Sdougb /* 2084193149Sdougb * For MS DNS that violates RFC 2845, section 4.2 2085193149Sdougb */ 2086193149Sdougb break; 2087193149Sdougb } 2088193149Sdougb#endif 2089135446Strhodes fprintf(stderr, "; TSIG error with server: %s\n", 2090135446Strhodes isc_result_totext(result)); 2091135446Strhodes seenerror = ISC_TRUE; 2092135446Strhodes break; 2093135446Strhodes default: 2094135446Strhodes check_result(result, "dns_request_getresponse"); 2095135446Strhodes } 2096135446Strhodes 2097135446Strhodes if (answer->rcode != dns_rcode_noerror) { 2098135446Strhodes seenerror = ISC_TRUE; 2099135446Strhodes if (!debugging) { 2100135446Strhodes char buf[64]; 2101135446Strhodes isc_buffer_t b; 2102135446Strhodes dns_rdataset_t *rds; 2103186462Sdougb 2104135446Strhodes isc_buffer_init(&b, buf, sizeof(buf) - 1); 2105135446Strhodes result = dns_rcode_totext(answer->rcode, &b); 2106135446Strhodes check_result(result, "dns_rcode_totext"); 2107135446Strhodes rds = dns_message_gettsig(answer, NULL); 2108135446Strhodes if (rds != NULL) 2109135446Strhodes check_tsig_error(rds, &b); 2110135446Strhodes fprintf(stderr, "update failed: %.*s\n", 2111135446Strhodes (int)isc_buffer_usedlength(&b), buf); 2112135446Strhodes } 2113135446Strhodes } 2114193149Sdougb if (debugging) 2115193149Sdougb show_message(stderr, answer, "\nReply from update query:"); 2116135446Strhodes 2117135446Strhodes done: 2118135446Strhodes dns_request_destroy(&request); 2119193149Sdougb if (usegsstsig) { 2120193149Sdougb dns_name_free(&tmpzonename, mctx); 2121193149Sdougb dns_name_free(&restart_master, mctx); 2122193149Sdougb } 2123135446Strhodes isc_event_free(&event); 2124135446Strhodes done_update(); 2125135446Strhodes} 2126135446Strhodes 2127135446Strhodesstatic void 2128135446Strhodessend_update(dns_name_t *zonename, isc_sockaddr_t *master, 2129135446Strhodes isc_sockaddr_t *srcaddr) 2130135446Strhodes{ 2131135446Strhodes isc_result_t result; 2132135446Strhodes dns_request_t *request = NULL; 2133224092Sdougb unsigned int options = DNS_REQUESTOPT_CASE; 2134135446Strhodes 2135135446Strhodes ddebug("send_update()"); 2136135446Strhodes 2137170222Sdougb setzone(zonename); 2138135446Strhodes 2139135446Strhodes if (usevc) 2140135446Strhodes options |= DNS_REQUESTOPT_TCP; 2141135446Strhodes if (tsigkey == NULL && sig0key != NULL) { 2142135446Strhodes result = dns_message_setsig0key(updatemsg, sig0key); 2143135446Strhodes check_result(result, "dns_message_setsig0key"); 2144135446Strhodes } 2145135446Strhodes if (debugging) { 2146135446Strhodes char addrbuf[ISC_SOCKADDR_FORMATSIZE]; 2147135446Strhodes 2148135446Strhodes isc_sockaddr_format(master, addrbuf, sizeof(addrbuf)); 2149135446Strhodes fprintf(stderr, "Sending update to %s\n", addrbuf); 2150135446Strhodes } 2151193149Sdougb 2152218384Sdougb /* Windows doesn't like the tsig name to be compressed. */ 2153218384Sdougb if (updatemsg->tsigname) 2154218384Sdougb updatemsg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS; 2155218384Sdougb 2156135446Strhodes result = dns_request_createvia3(requestmgr, updatemsg, srcaddr, 2157135446Strhodes master, options, tsigkey, timeout, 2158135446Strhodes udp_timeout, udp_retries, global_task, 2159135446Strhodes update_completed, NULL, &request); 2160135446Strhodes check_result(result, "dns_request_createvia3"); 2161135446Strhodes 2162135446Strhodes if (debugging) 2163193149Sdougb show_message(stdout, updatemsg, "Outgoing update query:"); 2164135446Strhodes 2165135446Strhodes requests++; 2166135446Strhodes} 2167135446Strhodes 2168135446Strhodesstatic void 2169135446Strhodesrecvsoa(isc_task_t *task, isc_event_t *event) { 2170135446Strhodes dns_requestevent_t *reqev = NULL; 2171135446Strhodes dns_request_t *request = NULL; 2172135446Strhodes isc_result_t result, eresult; 2173135446Strhodes dns_message_t *rcvmsg = NULL; 2174135446Strhodes dns_section_t section; 2175135446Strhodes dns_name_t *name = NULL; 2176135446Strhodes dns_rdataset_t *soaset = NULL; 2177135446Strhodes dns_rdata_soa_t soa; 2178135446Strhodes dns_rdata_t soarr = DNS_RDATA_INIT; 2179135446Strhodes int pass = 0; 2180135446Strhodes dns_name_t master; 2181135446Strhodes nsu_requestinfo_t *reqinfo; 2182135446Strhodes dns_message_t *soaquery = NULL; 2183135446Strhodes isc_sockaddr_t *addr; 2184135446Strhodes isc_boolean_t seencname = ISC_FALSE; 2185143731Sdougb dns_name_t tname; 2186143731Sdougb unsigned int nlabels; 2187135446Strhodes 2188135446Strhodes UNUSED(task); 2189135446Strhodes 2190135446Strhodes ddebug("recvsoa()"); 2191135446Strhodes 2192135446Strhodes requests--; 2193186462Sdougb 2194135446Strhodes REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE); 2195135446Strhodes reqev = (dns_requestevent_t *)event; 2196135446Strhodes request = reqev->request; 2197135446Strhodes eresult = reqev->result; 2198135446Strhodes reqinfo = reqev->ev_arg; 2199135446Strhodes soaquery = reqinfo->msg; 2200135446Strhodes addr = reqinfo->addr; 2201135446Strhodes 2202135446Strhodes if (shuttingdown) { 2203135446Strhodes dns_request_destroy(&request); 2204135446Strhodes dns_message_destroy(&soaquery); 2205135446Strhodes isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t)); 2206135446Strhodes isc_event_free(&event); 2207135446Strhodes maybeshutdown(); 2208135446Strhodes return; 2209135446Strhodes } 2210135446Strhodes 2211135446Strhodes if (eresult != ISC_R_SUCCESS) { 2212135446Strhodes char addrbuf[ISC_SOCKADDR_FORMATSIZE]; 2213135446Strhodes 2214135446Strhodes isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf)); 2215135446Strhodes fprintf(stderr, "; Communication with %s failed: %s\n", 2216193149Sdougb addrbuf, isc_result_totext(eresult)); 2217135446Strhodes if (userserver != NULL) 2218135446Strhodes fatal("could not talk to specified name server"); 2219135446Strhodes else if (++ns_inuse >= lwconf->nsnext) 2220135446Strhodes fatal("could not talk to any default name server"); 2221135446Strhodes ddebug("Destroying request [%p]", request); 2222135446Strhodes dns_request_destroy(&request); 2223135446Strhodes dns_message_renderreset(soaquery); 2224153816Sdougb dns_message_settsigkey(soaquery, NULL); 2225135446Strhodes sendrequest(localaddr, &servers[ns_inuse], soaquery, &request); 2226135446Strhodes isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t)); 2227135446Strhodes isc_event_free(&event); 2228135446Strhodes setzoneclass(dns_rdataclass_none); 2229135446Strhodes return; 2230135446Strhodes } 2231170222Sdougb 2232135446Strhodes isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t)); 2233170222Sdougb reqinfo = NULL; 2234135446Strhodes isc_event_free(&event); 2235135446Strhodes reqev = NULL; 2236135446Strhodes 2237135446Strhodes ddebug("About to create rcvmsg"); 2238135446Strhodes result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &rcvmsg); 2239135446Strhodes check_result(result, "dns_message_create"); 2240135446Strhodes result = dns_request_getresponse(request, rcvmsg, 2241135446Strhodes DNS_MESSAGEPARSE_PRESERVEORDER); 2242135446Strhodes if (result == DNS_R_TSIGERRORSET && userserver != NULL) { 2243135446Strhodes dns_message_destroy(&rcvmsg); 2244135446Strhodes ddebug("Destroying request [%p]", request); 2245135446Strhodes dns_request_destroy(&request); 2246135446Strhodes reqinfo = isc_mem_get(mctx, sizeof(nsu_requestinfo_t)); 2247135446Strhodes if (reqinfo == NULL) 2248135446Strhodes fatal("out of memory"); 2249135446Strhodes reqinfo->msg = soaquery; 2250135446Strhodes reqinfo->addr = addr; 2251135446Strhodes dns_message_renderreset(soaquery); 2252135446Strhodes ddebug("retrying soa request without TSIG"); 2253135446Strhodes result = dns_request_createvia3(requestmgr, soaquery, 2254135446Strhodes localaddr, addr, 0, NULL, 2255135446Strhodes FIND_TIMEOUT * 20, 2256165071Sdougb FIND_TIMEOUT, 3, 2257135446Strhodes global_task, recvsoa, reqinfo, 2258135446Strhodes &request); 2259135446Strhodes check_result(result, "dns_request_createvia"); 2260135446Strhodes requests++; 2261135446Strhodes return; 2262135446Strhodes } 2263135446Strhodes check_result(result, "dns_request_getresponse"); 2264135446Strhodes section = DNS_SECTION_ANSWER; 2265225361Sdougb POST(section); 2266193149Sdougb if (debugging) 2267193149Sdougb show_message(stderr, rcvmsg, "Reply from SOA query:"); 2268135446Strhodes 2269135446Strhodes if (rcvmsg->rcode != dns_rcode_noerror && 2270135446Strhodes rcvmsg->rcode != dns_rcode_nxdomain) 2271135446Strhodes fatal("response to SOA query was unsuccessful"); 2272135446Strhodes 2273170222Sdougb if (userzone != NULL && rcvmsg->rcode == dns_rcode_nxdomain) { 2274170222Sdougb char namebuf[DNS_NAME_FORMATSIZE]; 2275170222Sdougb dns_name_format(userzone, namebuf, sizeof(namebuf)); 2276170222Sdougb error("specified zone '%s' does not exist (NXDOMAIN)", 2277170222Sdougb namebuf); 2278170222Sdougb dns_message_destroy(&rcvmsg); 2279170222Sdougb dns_request_destroy(&request); 2280170222Sdougb dns_message_destroy(&soaquery); 2281170222Sdougb ddebug("Out of recvsoa"); 2282170222Sdougb done_update(); 2283170222Sdougb return; 2284170222Sdougb } 2285170222Sdougb 2286135446Strhodes lookforsoa: 2287135446Strhodes if (pass == 0) 2288135446Strhodes section = DNS_SECTION_ANSWER; 2289135446Strhodes else if (pass == 1) 2290135446Strhodes section = DNS_SECTION_AUTHORITY; 2291186462Sdougb else 2292143731Sdougb goto droplabel; 2293135446Strhodes 2294135446Strhodes result = dns_message_firstname(rcvmsg, section); 2295135446Strhodes if (result != ISC_R_SUCCESS) { 2296135446Strhodes pass++; 2297135446Strhodes goto lookforsoa; 2298135446Strhodes } 2299135446Strhodes while (result == ISC_R_SUCCESS) { 2300135446Strhodes name = NULL; 2301135446Strhodes dns_message_currentname(rcvmsg, section, &name); 2302135446Strhodes soaset = NULL; 2303135446Strhodes result = dns_message_findtype(name, dns_rdatatype_soa, 0, 2304135446Strhodes &soaset); 2305135446Strhodes if (result == ISC_R_SUCCESS) 2306135446Strhodes break; 2307135446Strhodes if (section == DNS_SECTION_ANSWER) { 2308135446Strhodes dns_rdataset_t *tset = NULL; 2309135446Strhodes if (dns_message_findtype(name, dns_rdatatype_cname, 0, 2310193149Sdougb &tset) == ISC_R_SUCCESS || 2311135446Strhodes dns_message_findtype(name, dns_rdatatype_dname, 0, 2312193149Sdougb &tset) == ISC_R_SUCCESS ) { 2313135446Strhodes seencname = ISC_TRUE; 2314135446Strhodes break; 2315135446Strhodes } 2316135446Strhodes } 2317186462Sdougb 2318135446Strhodes result = dns_message_nextname(rcvmsg, section); 2319135446Strhodes } 2320135446Strhodes 2321135446Strhodes if (soaset == NULL && !seencname) { 2322135446Strhodes pass++; 2323135446Strhodes goto lookforsoa; 2324135446Strhodes } 2325135446Strhodes 2326143731Sdougb if (seencname) 2327143731Sdougb goto droplabel; 2328135446Strhodes 2329135446Strhodes if (debugging) { 2330135446Strhodes char namestr[DNS_NAME_FORMATSIZE]; 2331135446Strhodes dns_name_format(name, namestr, sizeof(namestr)); 2332135446Strhodes fprintf(stderr, "Found zone name: %s\n", namestr); 2333135446Strhodes } 2334135446Strhodes 2335135446Strhodes result = dns_rdataset_first(soaset); 2336135446Strhodes check_result(result, "dns_rdataset_first"); 2337135446Strhodes 2338135446Strhodes dns_rdata_init(&soarr); 2339135446Strhodes dns_rdataset_current(soaset, &soarr); 2340135446Strhodes result = dns_rdata_tostruct(&soarr, &soa, NULL); 2341135446Strhodes check_result(result, "dns_rdata_tostruct"); 2342135446Strhodes 2343135446Strhodes dns_name_init(&master, NULL); 2344135446Strhodes dns_name_clone(&soa.origin, &master); 2345135446Strhodes 2346135446Strhodes if (userzone != NULL) 2347135446Strhodes zonename = userzone; 2348135446Strhodes else 2349135446Strhodes zonename = name; 2350135446Strhodes 2351135446Strhodes if (debugging) { 2352135446Strhodes char namestr[DNS_NAME_FORMATSIZE]; 2353135446Strhodes dns_name_format(&master, namestr, sizeof(namestr)); 2354135446Strhodes fprintf(stderr, "The master is: %s\n", namestr); 2355135446Strhodes } 2356135446Strhodes 2357135446Strhodes if (userserver != NULL) 2358135446Strhodes serveraddr = userserver; 2359135446Strhodes else { 2360135446Strhodes char serverstr[DNS_NAME_MAXTEXT+1]; 2361135446Strhodes isc_buffer_t buf; 2362135446Strhodes 2363135446Strhodes isc_buffer_init(&buf, serverstr, sizeof(serverstr)); 2364135446Strhodes result = dns_name_totext(&master, ISC_TRUE, &buf); 2365135446Strhodes check_result(result, "dns_name_totext"); 2366135446Strhodes serverstr[isc_buffer_usedlength(&buf)] = 0; 2367224092Sdougb get_address(serverstr, dnsport, &tempaddr); 2368135446Strhodes serveraddr = &tempaddr; 2369135446Strhodes } 2370143731Sdougb dns_rdata_freestruct(&soa); 2371135446Strhodes 2372193149Sdougb#ifdef GSSAPI 2373193149Sdougb if (usegsstsig) { 2374193149Sdougb dns_name_init(&tmpzonename, NULL); 2375193149Sdougb dns_name_dup(zonename, mctx, &tmpzonename); 2376193149Sdougb dns_name_init(&restart_master, NULL); 2377193149Sdougb dns_name_dup(&master, mctx, &restart_master); 2378193149Sdougb start_gssrequest(&master); 2379193149Sdougb } else { 2380193149Sdougb send_update(zonename, serveraddr, localaddr); 2381193149Sdougb setzoneclass(dns_rdataclass_none); 2382193149Sdougb } 2383193149Sdougb#else 2384135446Strhodes send_update(zonename, serveraddr, localaddr); 2385143731Sdougb setzoneclass(dns_rdataclass_none); 2386193149Sdougb#endif 2387135446Strhodes 2388135446Strhodes dns_message_destroy(&soaquery); 2389135446Strhodes dns_request_destroy(&request); 2390135446Strhodes 2391135446Strhodes out: 2392135446Strhodes dns_message_destroy(&rcvmsg); 2393135446Strhodes ddebug("Out of recvsoa"); 2394143731Sdougb return; 2395186462Sdougb 2396143731Sdougb droplabel: 2397143731Sdougb result = dns_message_firstname(soaquery, DNS_SECTION_QUESTION); 2398143731Sdougb INSIST(result == ISC_R_SUCCESS); 2399143731Sdougb name = NULL; 2400143731Sdougb dns_message_currentname(soaquery, DNS_SECTION_QUESTION, &name); 2401143731Sdougb nlabels = dns_name_countlabels(name); 2402143731Sdougb if (nlabels == 1) 2403143731Sdougb fatal("could not find enclosing zone"); 2404143731Sdougb dns_name_init(&tname, NULL); 2405143731Sdougb dns_name_getlabelsequence(name, 1, nlabels - 1, &tname); 2406143731Sdougb dns_name_clone(&tname, name); 2407143731Sdougb dns_request_destroy(&request); 2408143731Sdougb dns_message_renderreset(soaquery); 2409153816Sdougb dns_message_settsigkey(soaquery, NULL); 2410143731Sdougb if (userserver != NULL) 2411143731Sdougb sendrequest(localaddr, userserver, soaquery, &request); 2412143731Sdougb else 2413193149Sdougb sendrequest(localaddr, &servers[ns_inuse], soaquery, &request); 2414143731Sdougb goto out; 2415135446Strhodes} 2416135446Strhodes 2417135446Strhodesstatic void 2418135446Strhodessendrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, 2419135446Strhodes dns_message_t *msg, dns_request_t **request) 2420135446Strhodes{ 2421135446Strhodes isc_result_t result; 2422135446Strhodes nsu_requestinfo_t *reqinfo; 2423135446Strhodes 2424135446Strhodes reqinfo = isc_mem_get(mctx, sizeof(nsu_requestinfo_t)); 2425135446Strhodes if (reqinfo == NULL) 2426135446Strhodes fatal("out of memory"); 2427135446Strhodes reqinfo->msg = msg; 2428135446Strhodes reqinfo->addr = destaddr; 2429135446Strhodes result = dns_request_createvia3(requestmgr, msg, srcaddr, destaddr, 0, 2430135446Strhodes (userserver != NULL) ? tsigkey : NULL, 2431135446Strhodes FIND_TIMEOUT * 20, FIND_TIMEOUT, 3, 2432135446Strhodes global_task, recvsoa, reqinfo, request); 2433135446Strhodes check_result(result, "dns_request_createvia"); 2434135446Strhodes requests++; 2435135446Strhodes} 2436135446Strhodes 2437193149Sdougb#ifdef GSSAPI 2438224092Sdougb 2439224092Sdougb/* 2440224092Sdougb * Get the realm from the users kerberos ticket if possible 2441224092Sdougb */ 2442135446Strhodesstatic void 2443224092Sdougbget_ticket_realm(isc_mem_t *mctx) 2444193149Sdougb{ 2445224092Sdougb krb5_context ctx; 2446224092Sdougb krb5_error_code rc; 2447224092Sdougb krb5_ccache ccache; 2448224092Sdougb krb5_principal princ; 2449224092Sdougb char *name, *ticket_realm; 2450224092Sdougb 2451224092Sdougb rc = krb5_init_context(&ctx); 2452224092Sdougb if (rc != 0) 2453224092Sdougb return; 2454224092Sdougb 2455224092Sdougb rc = krb5_cc_default(ctx, &ccache); 2456224092Sdougb if (rc != 0) { 2457224092Sdougb krb5_free_context(ctx); 2458224092Sdougb return; 2459224092Sdougb } 2460224092Sdougb 2461224092Sdougb rc = krb5_cc_get_principal(ctx, ccache, &princ); 2462224092Sdougb if (rc != 0) { 2463224092Sdougb krb5_cc_close(ctx, ccache); 2464224092Sdougb krb5_free_context(ctx); 2465224092Sdougb return; 2466224092Sdougb } 2467224092Sdougb 2468224092Sdougb rc = krb5_unparse_name(ctx, princ, &name); 2469224092Sdougb if (rc != 0) { 2470224092Sdougb krb5_free_principal(ctx, princ); 2471224092Sdougb krb5_cc_close(ctx, ccache); 2472224092Sdougb krb5_free_context(ctx); 2473224092Sdougb return; 2474224092Sdougb } 2475224092Sdougb 2476224092Sdougb ticket_realm = strrchr(name, '@'); 2477224092Sdougb if (ticket_realm != NULL) { 2478224092Sdougb realm = isc_mem_strdup(mctx, ticket_realm); 2479224092Sdougb } 2480224092Sdougb 2481224092Sdougb free(name); 2482224092Sdougb krb5_free_principal(ctx, princ); 2483224092Sdougb krb5_cc_close(ctx, ccache); 2484224092Sdougb krb5_free_context(ctx); 2485224092Sdougb if (realm != NULL && debugging) 2486224092Sdougb fprintf(stderr, "Found realm from ticket: %s\n", realm+1); 2487224092Sdougb} 2488224092Sdougb 2489224092Sdougb 2490224092Sdougbstatic void 2491224092Sdougbstart_gssrequest(dns_name_t *master) { 2492193149Sdougb gss_ctx_id_t context; 2493193149Sdougb isc_buffer_t buf; 2494193149Sdougb isc_result_t result; 2495193149Sdougb isc_uint32_t val = 0; 2496193149Sdougb dns_message_t *rmsg; 2497193149Sdougb dns_request_t *request = NULL; 2498193149Sdougb dns_name_t *servname; 2499193149Sdougb dns_fixedname_t fname; 2500193149Sdougb char namestr[DNS_NAME_FORMATSIZE]; 2501193149Sdougb char keystr[DNS_NAME_FORMATSIZE]; 2502224092Sdougb char *err_message = NULL; 2503193149Sdougb 2504193149Sdougb debug("start_gssrequest"); 2505193149Sdougb usevc = ISC_TRUE; 2506193149Sdougb 2507193149Sdougb if (gssring != NULL) 2508224092Sdougb dns_tsigkeyring_detach(&gssring); 2509193149Sdougb gssring = NULL; 2510193149Sdougb result = dns_tsigkeyring_create(mctx, &gssring); 2511193149Sdougb 2512193149Sdougb if (result != ISC_R_SUCCESS) 2513193149Sdougb fatal("dns_tsigkeyring_create failed: %s", 2514193149Sdougb isc_result_totext(result)); 2515193149Sdougb 2516193149Sdougb dns_name_format(master, namestr, sizeof(namestr)); 2517193149Sdougb if (kserver == NULL) { 2518193149Sdougb kserver = isc_mem_get(mctx, sizeof(isc_sockaddr_t)); 2519193149Sdougb if (kserver == NULL) 2520193149Sdougb fatal("out of memory"); 2521193149Sdougb } 2522193149Sdougb if (userserver == NULL) 2523224092Sdougb get_address(namestr, dnsport, kserver); 2524193149Sdougb else 2525193149Sdougb (void)memcpy(kserver, userserver, sizeof(isc_sockaddr_t)); 2526193149Sdougb 2527193149Sdougb dns_fixedname_init(&fname); 2528193149Sdougb servname = dns_fixedname_name(&fname); 2529193149Sdougb 2530224092Sdougb if (realm == NULL) 2531224092Sdougb get_ticket_realm(mctx); 2532224092Sdougb 2533193149Sdougb result = isc_string_printf(servicename, sizeof(servicename), 2534218384Sdougb "DNS/%s%s", namestr, realm ? realm : ""); 2535193149Sdougb if (result != ISC_R_SUCCESS) 2536193149Sdougb fatal("isc_string_printf(servicename) failed: %s", 2537193149Sdougb isc_result_totext(result)); 2538193149Sdougb isc_buffer_init(&buf, servicename, strlen(servicename)); 2539193149Sdougb isc_buffer_add(&buf, strlen(servicename)); 2540224092Sdougb result = dns_name_fromtext(servname, &buf, dns_rootname, 0, NULL); 2541193149Sdougb if (result != ISC_R_SUCCESS) 2542193149Sdougb fatal("dns_name_fromtext(servname) failed: %s", 2543193149Sdougb isc_result_totext(result)); 2544193149Sdougb 2545193149Sdougb dns_fixedname_init(&fkname); 2546193149Sdougb keyname = dns_fixedname_name(&fkname); 2547193149Sdougb 2548193149Sdougb isc_random_get(&val); 2549193149Sdougb result = isc_string_printf(keystr, sizeof(keystr), "%u.sig-%s", 2550193149Sdougb val, namestr); 2551193149Sdougb if (result != ISC_R_SUCCESS) 2552193149Sdougb fatal("isc_string_printf(keystr) failed: %s", 2553193149Sdougb isc_result_totext(result)); 2554193149Sdougb isc_buffer_init(&buf, keystr, strlen(keystr)); 2555193149Sdougb isc_buffer_add(&buf, strlen(keystr)); 2556193149Sdougb 2557224092Sdougb result = dns_name_fromtext(keyname, &buf, dns_rootname, 0, NULL); 2558193149Sdougb if (result != ISC_R_SUCCESS) 2559193149Sdougb fatal("dns_name_fromtext(keyname) failed: %s", 2560193149Sdougb isc_result_totext(result)); 2561193149Sdougb 2562193149Sdougb /* Windows doesn't recognize name compression in the key name. */ 2563193149Sdougb keyname->attributes |= DNS_NAMEATTR_NOCOMPRESS; 2564193149Sdougb 2565193149Sdougb rmsg = NULL; 2566193149Sdougb result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &rmsg); 2567193149Sdougb if (result != ISC_R_SUCCESS) 2568193149Sdougb fatal("dns_message_create failed: %s", 2569193149Sdougb isc_result_totext(result)); 2570193149Sdougb 2571193149Sdougb /* Build first request. */ 2572193149Sdougb context = GSS_C_NO_CONTEXT; 2573193149Sdougb result = dns_tkey_buildgssquery(rmsg, keyname, servname, NULL, 0, 2574224092Sdougb &context, use_win2k_gsstsig, 2575224092Sdougb mctx, &err_message); 2576193149Sdougb if (result == ISC_R_FAILURE) 2577224092Sdougb fatal("tkey query failed: %s", 2578224092Sdougb err_message != NULL ? err_message : "unknown error"); 2579193149Sdougb if (result != ISC_R_SUCCESS) 2580193149Sdougb fatal("dns_tkey_buildgssquery failed: %s", 2581193149Sdougb isc_result_totext(result)); 2582193149Sdougb 2583193149Sdougb send_gssrequest(localaddr, kserver, rmsg, &request, context); 2584193149Sdougb} 2585193149Sdougb 2586193149Sdougbstatic void 2587193149Sdougbsend_gssrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, 2588193149Sdougb dns_message_t *msg, dns_request_t **request, 2589193149Sdougb gss_ctx_id_t context) 2590193149Sdougb{ 2591193149Sdougb isc_result_t result; 2592193149Sdougb nsu_gssinfo_t *reqinfo; 2593193149Sdougb unsigned int options = 0; 2594193149Sdougb 2595193149Sdougb debug("send_gssrequest"); 2596193149Sdougb reqinfo = isc_mem_get(mctx, sizeof(nsu_gssinfo_t)); 2597193149Sdougb if (reqinfo == NULL) 2598193149Sdougb fatal("out of memory"); 2599193149Sdougb reqinfo->msg = msg; 2600193149Sdougb reqinfo->addr = destaddr; 2601193149Sdougb reqinfo->context = context; 2602193149Sdougb 2603193149Sdougb options |= DNS_REQUESTOPT_TCP; 2604193149Sdougb result = dns_request_createvia3(requestmgr, msg, srcaddr, destaddr, 2605193149Sdougb options, tsigkey, FIND_TIMEOUT * 20, 2606193149Sdougb FIND_TIMEOUT, 3, global_task, recvgss, 2607193149Sdougb reqinfo, request); 2608193149Sdougb check_result(result, "dns_request_createvia3"); 2609193149Sdougb if (debugging) 2610193149Sdougb show_message(stdout, msg, "Outgoing update query:"); 2611193149Sdougb requests++; 2612193149Sdougb} 2613193149Sdougb 2614193149Sdougbstatic void 2615193149Sdougbrecvgss(isc_task_t *task, isc_event_t *event) { 2616193149Sdougb dns_requestevent_t *reqev = NULL; 2617193149Sdougb dns_request_t *request = NULL; 2618193149Sdougb isc_result_t result, eresult; 2619193149Sdougb dns_message_t *rcvmsg = NULL; 2620193149Sdougb nsu_gssinfo_t *reqinfo; 2621193149Sdougb dns_message_t *tsigquery = NULL; 2622193149Sdougb isc_sockaddr_t *addr; 2623193149Sdougb gss_ctx_id_t context; 2624193149Sdougb isc_buffer_t buf; 2625193149Sdougb dns_name_t *servname; 2626193149Sdougb dns_fixedname_t fname; 2627224092Sdougb char *err_message = NULL; 2628193149Sdougb 2629193149Sdougb UNUSED(task); 2630193149Sdougb 2631193149Sdougb ddebug("recvgss()"); 2632193149Sdougb 2633193149Sdougb requests--; 2634193149Sdougb 2635193149Sdougb REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE); 2636193149Sdougb reqev = (dns_requestevent_t *)event; 2637193149Sdougb request = reqev->request; 2638193149Sdougb eresult = reqev->result; 2639193149Sdougb reqinfo = reqev->ev_arg; 2640193149Sdougb tsigquery = reqinfo->msg; 2641193149Sdougb context = reqinfo->context; 2642193149Sdougb addr = reqinfo->addr; 2643193149Sdougb 2644193149Sdougb if (shuttingdown) { 2645193149Sdougb dns_request_destroy(&request); 2646193149Sdougb dns_message_destroy(&tsigquery); 2647193149Sdougb isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_t)); 2648193149Sdougb isc_event_free(&event); 2649193149Sdougb maybeshutdown(); 2650193149Sdougb return; 2651193149Sdougb } 2652193149Sdougb 2653193149Sdougb if (eresult != ISC_R_SUCCESS) { 2654193149Sdougb char addrbuf[ISC_SOCKADDR_FORMATSIZE]; 2655193149Sdougb 2656193149Sdougb isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf)); 2657193149Sdougb fprintf(stderr, "; Communication with %s failed: %s\n", 2658193149Sdougb addrbuf, isc_result_totext(eresult)); 2659193149Sdougb if (userserver != NULL) 2660193149Sdougb fatal("could not talk to specified name server"); 2661193149Sdougb else if (++ns_inuse >= lwconf->nsnext) 2662193149Sdougb fatal("could not talk to any default name server"); 2663193149Sdougb ddebug("Destroying request [%p]", request); 2664193149Sdougb dns_request_destroy(&request); 2665193149Sdougb dns_message_renderreset(tsigquery); 2666193149Sdougb sendrequest(localaddr, &servers[ns_inuse], tsigquery, 2667193149Sdougb &request); 2668193149Sdougb isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_t)); 2669193149Sdougb isc_event_free(&event); 2670193149Sdougb return; 2671193149Sdougb } 2672193149Sdougb isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_t)); 2673193149Sdougb 2674193149Sdougb isc_event_free(&event); 2675193149Sdougb reqev = NULL; 2676193149Sdougb 2677193149Sdougb ddebug("recvgss creating rcvmsg"); 2678193149Sdougb result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &rcvmsg); 2679193149Sdougb check_result(result, "dns_message_create"); 2680193149Sdougb 2681193149Sdougb result = dns_request_getresponse(request, rcvmsg, 2682193149Sdougb DNS_MESSAGEPARSE_PRESERVEORDER); 2683193149Sdougb check_result(result, "dns_request_getresponse"); 2684193149Sdougb 2685193149Sdougb if (debugging) 2686193149Sdougb show_message(stderr, rcvmsg, 2687193149Sdougb "recvmsg reply from GSS-TSIG query"); 2688193149Sdougb 2689193149Sdougb if (rcvmsg->rcode == dns_rcode_formerr && !tried_other_gsstsig) { 2690193149Sdougb ddebug("recvgss trying %s GSS-TSIG", 2691193149Sdougb use_win2k_gsstsig ? "Standard" : "Win2k"); 2692193149Sdougb if (use_win2k_gsstsig) 2693193149Sdougb use_win2k_gsstsig = ISC_FALSE; 2694193149Sdougb else 2695193149Sdougb use_win2k_gsstsig = ISC_TRUE; 2696193149Sdougb tried_other_gsstsig = ISC_TRUE; 2697193149Sdougb start_gssrequest(&restart_master); 2698193149Sdougb goto done; 2699193149Sdougb } 2700193149Sdougb 2701193149Sdougb if (rcvmsg->rcode != dns_rcode_noerror && 2702193149Sdougb rcvmsg->rcode != dns_rcode_nxdomain) 2703193149Sdougb fatal("response to GSS-TSIG query was unsuccessful"); 2704193149Sdougb 2705193149Sdougb 2706193149Sdougb dns_fixedname_init(&fname); 2707193149Sdougb servname = dns_fixedname_name(&fname); 2708193149Sdougb isc_buffer_init(&buf, servicename, strlen(servicename)); 2709193149Sdougb isc_buffer_add(&buf, strlen(servicename)); 2710224092Sdougb result = dns_name_fromtext(servname, &buf, dns_rootname, 0, NULL); 2711193149Sdougb check_result(result, "dns_name_fromtext"); 2712193149Sdougb 2713193149Sdougb tsigkey = NULL; 2714193149Sdougb result = dns_tkey_gssnegotiate(tsigquery, rcvmsg, servname, 2715193149Sdougb &context, &tsigkey, gssring, 2716224092Sdougb use_win2k_gsstsig, 2717224092Sdougb &err_message); 2718193149Sdougb switch (result) { 2719193149Sdougb 2720193149Sdougb case DNS_R_CONTINUE: 2721193149Sdougb send_gssrequest(localaddr, kserver, tsigquery, &request, 2722193149Sdougb context); 2723193149Sdougb break; 2724193149Sdougb 2725193149Sdougb case ISC_R_SUCCESS: 2726193149Sdougb /* 2727193149Sdougb * XXXSRA Waaay too much fun here. There's no good 2728193149Sdougb * reason why we need a TSIG here (the people who put 2729193149Sdougb * it into the spec admitted at the time that it was 2730193149Sdougb * not a security issue), and Windows clients don't 2731193149Sdougb * seem to work if named complies with the spec and 2732193149Sdougb * includes the gratuitous TSIG. So we're in the 2733193149Sdougb * bizarre situation of having to choose between 2734193149Sdougb * complying with a useless requirement in the spec 2735193149Sdougb * and interoperating. This is nuts. If we can 2736193149Sdougb * confirm this behavior, we should ask the WG to 2737193149Sdougb * consider removing the requirement for the 2738193149Sdougb * gratuitous TSIG here. For the moment, we ignore 2739193149Sdougb * the TSIG -- this too is a spec violation, but it's 2740193149Sdougb * the least insane thing to do. 2741193149Sdougb */ 2742193149Sdougb#if 0 2743193149Sdougb /* 2744193149Sdougb * Verify the signature. 2745193149Sdougb */ 2746193149Sdougb rcvmsg->state = DNS_SECTION_ANY; 2747193149Sdougb dns_message_setquerytsig(rcvmsg, NULL); 2748193149Sdougb result = dns_message_settsigkey(rcvmsg, tsigkey); 2749193149Sdougb check_result(result, "dns_message_settsigkey"); 2750193149Sdougb result = dns_message_checksig(rcvmsg, NULL); 2751193149Sdougb ddebug("tsig verification: %s", dns_result_totext(result)); 2752193149Sdougb check_result(result, "dns_message_checksig"); 2753193149Sdougb#endif /* 0 */ 2754193149Sdougb 2755193149Sdougb send_update(&tmpzonename, serveraddr, localaddr); 2756193149Sdougb setzoneclass(dns_rdataclass_none); 2757193149Sdougb break; 2758193149Sdougb 2759193149Sdougb default: 2760224092Sdougb fatal("dns_tkey_negotiategss: %s %s", 2761224092Sdougb isc_result_totext(result), 2762224092Sdougb err_message != NULL ? err_message : ""); 2763193149Sdougb } 2764193149Sdougb 2765193149Sdougb done: 2766193149Sdougb dns_request_destroy(&request); 2767193149Sdougb dns_message_destroy(&tsigquery); 2768193149Sdougb 2769193149Sdougb dns_message_destroy(&rcvmsg); 2770193149Sdougb ddebug("Out of recvgss"); 2771193149Sdougb} 2772193149Sdougb#endif 2773193149Sdougb 2774193149Sdougbstatic void 2775135446Strhodesstart_update(void) { 2776135446Strhodes isc_result_t result; 2777135446Strhodes dns_rdataset_t *rdataset = NULL; 2778135446Strhodes dns_name_t *name = NULL; 2779135446Strhodes dns_request_t *request = NULL; 2780135446Strhodes dns_message_t *soaquery = NULL; 2781135446Strhodes dns_name_t *firstname; 2782135446Strhodes dns_section_t section = DNS_SECTION_UPDATE; 2783135446Strhodes 2784135446Strhodes ddebug("start_update()"); 2785135446Strhodes 2786135446Strhodes if (answer != NULL) 2787135446Strhodes dns_message_destroy(&answer); 2788135446Strhodes 2789193149Sdougb if (userzone != NULL && userserver != NULL && ! usegsstsig) { 2790135446Strhodes send_update(userzone, userserver, localaddr); 2791135446Strhodes setzoneclass(dns_rdataclass_none); 2792135446Strhodes return; 2793135446Strhodes } 2794135446Strhodes 2795135446Strhodes result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, 2796135446Strhodes &soaquery); 2797135446Strhodes check_result(result, "dns_message_create"); 2798135446Strhodes 2799170222Sdougb if (userserver == NULL) 2800170222Sdougb soaquery->flags |= DNS_MESSAGEFLAG_RD; 2801135446Strhodes 2802135446Strhodes result = dns_message_gettempname(soaquery, &name); 2803135446Strhodes check_result(result, "dns_message_gettempname"); 2804135446Strhodes 2805135446Strhodes result = dns_message_gettemprdataset(soaquery, &rdataset); 2806135446Strhodes check_result(result, "dns_message_gettemprdataset"); 2807135446Strhodes 2808135446Strhodes dns_rdataset_makequestion(rdataset, getzoneclass(), dns_rdatatype_soa); 2809135446Strhodes 2810170222Sdougb if (userzone != NULL) { 2811170222Sdougb dns_name_init(name, NULL); 2812170222Sdougb dns_name_clone(userzone, name); 2813170222Sdougb } else { 2814218384Sdougb dns_rdataset_t *tmprdataset; 2815170222Sdougb result = dns_message_firstname(updatemsg, section); 2816170222Sdougb if (result == ISC_R_NOMORE) { 2817170222Sdougb section = DNS_SECTION_PREREQUISITE; 2818170222Sdougb result = dns_message_firstname(updatemsg, section); 2819170222Sdougb } 2820170222Sdougb if (result != ISC_R_SUCCESS) { 2821174187Sdougb dns_message_puttempname(soaquery, &name); 2822174187Sdougb dns_rdataset_disassociate(rdataset); 2823174187Sdougb dns_message_puttemprdataset(soaquery, &rdataset); 2824174187Sdougb dns_message_destroy(&soaquery); 2825170222Sdougb done_update(); 2826170222Sdougb return; 2827170222Sdougb } 2828170222Sdougb firstname = NULL; 2829170222Sdougb dns_message_currentname(updatemsg, section, &firstname); 2830170222Sdougb dns_name_init(name, NULL); 2831170222Sdougb dns_name_clone(firstname, name); 2832218384Sdougb /* 2833218384Sdougb * Looks to see if the first name references a DS record 2834218384Sdougb * and if that name is not the root remove a label as DS 2835218384Sdougb * records live in the parent zone so we need to start our 2836218384Sdougb * search one label up. 2837218384Sdougb */ 2838218384Sdougb tmprdataset = ISC_LIST_HEAD(firstname->list); 2839218384Sdougb if (section == DNS_SECTION_UPDATE && 2840218384Sdougb !dns_name_equal(firstname, dns_rootname) && 2841218384Sdougb tmprdataset->type == dns_rdatatype_ds) { 2842218384Sdougb unsigned int labels = dns_name_countlabels(name); 2843218384Sdougb dns_name_getlabelsequence(name, 1, labels - 1, name); 2844218384Sdougb } 2845170222Sdougb } 2846135446Strhodes 2847135446Strhodes ISC_LIST_INIT(name->list); 2848135446Strhodes ISC_LIST_APPEND(name->list, rdataset, link); 2849135446Strhodes dns_message_addname(soaquery, name, DNS_SECTION_QUESTION); 2850135446Strhodes 2851135446Strhodes if (userserver != NULL) 2852135446Strhodes sendrequest(localaddr, userserver, soaquery, &request); 2853135446Strhodes else { 2854135446Strhodes ns_inuse = 0; 2855135446Strhodes sendrequest(localaddr, &servers[ns_inuse], soaquery, &request); 2856135446Strhodes } 2857135446Strhodes} 2858135446Strhodes 2859135446Strhodesstatic void 2860135446Strhodescleanup(void) { 2861135446Strhodes ddebug("cleanup()"); 2862135446Strhodes 2863135446Strhodes if (answer != NULL) 2864135446Strhodes dns_message_destroy(&answer); 2865193149Sdougb 2866193149Sdougb#ifdef GSSAPI 2867193149Sdougb if (tsigkey != NULL) { 2868193149Sdougb ddebug("detach tsigkey x%p", tsigkey); 2869193149Sdougb dns_tsigkey_detach(&tsigkey); 2870193149Sdougb } 2871193149Sdougb if (gssring != NULL) { 2872224092Sdougb ddebug("Detaching GSS-TSIG keyring"); 2873224092Sdougb dns_tsigkeyring_detach(&gssring); 2874193149Sdougb } 2875193149Sdougb if (kserver != NULL) { 2876193149Sdougb isc_mem_put(mctx, kserver, sizeof(isc_sockaddr_t)); 2877193149Sdougb kserver = NULL; 2878193149Sdougb } 2879218384Sdougb if (realm != NULL) { 2880218384Sdougb isc_mem_free(mctx, realm); 2881218384Sdougb realm = NULL; 2882218384Sdougb } 2883193149Sdougb#endif 2884193149Sdougb 2885225361Sdougb if (sig0key != NULL) 2886225361Sdougb dst_key_free(&sig0key); 2887225361Sdougb 2888135446Strhodes ddebug("Shutting down task manager"); 2889135446Strhodes isc_taskmgr_destroy(&taskmgr); 2890135446Strhodes 2891135446Strhodes ddebug("Destroying event"); 2892135446Strhodes isc_event_free(&global_event); 2893135446Strhodes 2894135446Strhodes ddebug("Shutting down socket manager"); 2895135446Strhodes isc_socketmgr_destroy(&socketmgr); 2896135446Strhodes 2897135446Strhodes ddebug("Shutting down timer manager"); 2898135446Strhodes isc_timermgr_destroy(&timermgr); 2899135446Strhodes 2900135446Strhodes ddebug("Destroying hash context"); 2901135446Strhodes isc_hash_destroy(); 2902135446Strhodes 2903170222Sdougb ddebug("Destroying name state"); 2904170222Sdougb dns_name_destroy(); 2905170222Sdougb 2906193149Sdougb ddebug("Removing log context"); 2907193149Sdougb isc_log_destroy(&lctx); 2908193149Sdougb 2909135446Strhodes ddebug("Destroying memory context"); 2910135446Strhodes if (memdebugging) 2911135446Strhodes isc_mem_stats(mctx, stderr); 2912135446Strhodes isc_mem_destroy(&mctx); 2913135446Strhodes} 2914135446Strhodes 2915135446Strhodesstatic void 2916135446Strhodesgetinput(isc_task_t *task, isc_event_t *event) { 2917135446Strhodes isc_boolean_t more; 2918135446Strhodes 2919135446Strhodes UNUSED(task); 2920135446Strhodes 2921135446Strhodes if (shuttingdown) { 2922135446Strhodes maybeshutdown(); 2923135446Strhodes return; 2924135446Strhodes } 2925135446Strhodes 2926135446Strhodes if (global_event == NULL) 2927135446Strhodes global_event = event; 2928135446Strhodes 2929135446Strhodes reset_system(); 2930135446Strhodes more = user_interaction(); 2931135446Strhodes if (!more) { 2932135446Strhodes isc_app_shutdown(); 2933135446Strhodes return; 2934135446Strhodes } 2935135446Strhodes start_update(); 2936135446Strhodes return; 2937135446Strhodes} 2938135446Strhodes 2939135446Strhodesint 2940135446Strhodesmain(int argc, char **argv) { 2941135446Strhodes isc_result_t result; 2942135446Strhodes style = &dns_master_style_debug; 2943135446Strhodes 2944135446Strhodes input = stdin; 2945135446Strhodes 2946135446Strhodes interactive = ISC_TF(isatty(0)); 2947135446Strhodes 2948135446Strhodes isc_app_start(); 2949135446Strhodes 2950193149Sdougb pre_parse_args(argc, argv); 2951135446Strhodes 2952193149Sdougb result = isc_mem_create(0, 0, &mctx); 2953193149Sdougb check_result(result, "isc_mem_create"); 2954193149Sdougb 2955193149Sdougb parse_args(argc, argv, mctx, &entropy); 2956193149Sdougb 2957135446Strhodes setup_system(); 2958135446Strhodes 2959135446Strhodes result = isc_app_onrun(mctx, global_task, getinput, NULL); 2960135446Strhodes check_result(result, "isc_app_onrun"); 2961135446Strhodes 2962135446Strhodes (void)isc_app_run(); 2963135446Strhodes 2964135446Strhodes cleanup(); 2965135446Strhodes 2966135446Strhodes isc_app_finish(); 2967135446Strhodes 2968135446Strhodes if (seenerror) 2969135446Strhodes return (2); 2970135446Strhodes else 2971135446Strhodes return (0); 2972135446Strhodes} 2973