nsupdate.c revision 193149
1135446Strhodes/* 2193149Sdougb * Copyright (C) 2004-2009 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 18193149Sdougb/* $Id: nsupdate.c,v 1.163.48.3 2009/04/30 07:12:49 marka Exp $ */ 19135446Strhodes 20170222Sdougb/*! \file */ 21170222Sdougb 22135446Strhodes#include <config.h> 23135446Strhodes 24135446Strhodes#include <ctype.h> 25135446Strhodes#include <errno.h> 26135446Strhodes#include <limits.h> 27135446Strhodes#include <stdlib.h> 28135446Strhodes#include <unistd.h> 29135446Strhodes 30135446Strhodes#include <isc/app.h> 31135446Strhodes#include <isc/base64.h> 32135446Strhodes#include <isc/buffer.h> 33135446Strhodes#include <isc/commandline.h> 34135446Strhodes#include <isc/entropy.h> 35135446Strhodes#include <isc/event.h> 36135446Strhodes#include <isc/hash.h> 37135446Strhodes#include <isc/lex.h> 38193149Sdougb#include <isc/log.h> 39135446Strhodes#include <isc/mem.h> 40135446Strhodes#include <isc/parseint.h> 41193149Sdougb#include <isc/random.h> 42135446Strhodes#include <isc/region.h> 43135446Strhodes#include <isc/sockaddr.h> 44135446Strhodes#include <isc/socket.h> 45135446Strhodes#include <isc/stdio.h> 46135446Strhodes#include <isc/string.h> 47135446Strhodes#include <isc/task.h> 48135446Strhodes#include <isc/timer.h> 49135446Strhodes#include <isc/types.h> 50135446Strhodes#include <isc/util.h> 51135446Strhodes 52135446Strhodes#include <dns/callbacks.h> 53135446Strhodes#include <dns/dispatch.h> 54135446Strhodes#include <dns/dnssec.h> 55135446Strhodes#include <dns/events.h> 56135446Strhodes#include <dns/fixedname.h> 57193149Sdougb#include <dns/log.h> 58135446Strhodes#include <dns/masterdump.h> 59135446Strhodes#include <dns/message.h> 60135446Strhodes#include <dns/name.h> 61135446Strhodes#include <dns/rcode.h> 62135446Strhodes#include <dns/rdata.h> 63135446Strhodes#include <dns/rdataclass.h> 64135446Strhodes#include <dns/rdatalist.h> 65135446Strhodes#include <dns/rdataset.h> 66135446Strhodes#include <dns/rdatastruct.h> 67135446Strhodes#include <dns/rdatatype.h> 68135446Strhodes#include <dns/request.h> 69135446Strhodes#include <dns/result.h> 70193149Sdougb#include <dns/tkey.h> 71135446Strhodes#include <dns/tsig.h> 72135446Strhodes 73135446Strhodes#include <dst/dst.h> 74135446Strhodes 75135446Strhodes#include <lwres/lwres.h> 76135446Strhodes#include <lwres/net.h> 77135446Strhodes 78193149Sdougb#ifdef GSSAPI 79193149Sdougb#include <dst/gssapi.h> 80193149Sdougb#endif 81135446Strhodes#include <bind9/getaddresses.h> 82135446Strhodes 83193149Sdougb 84135446Strhodes#ifdef HAVE_ADDRINFO 85135446Strhodes#ifdef HAVE_GETADDRINFO 86135446Strhodes#ifdef HAVE_GAISTRERROR 87135446Strhodes#define USE_GETADDRINFO 88135446Strhodes#endif 89135446Strhodes#endif 90135446Strhodes#endif 91135446Strhodes 92135446Strhodes#ifndef USE_GETADDRINFO 93135446Strhodes#ifndef ISC_PLATFORM_NONSTDHERRNO 94135446Strhodesextern int h_errno; 95135446Strhodes#endif 96135446Strhodes#endif 97135446Strhodes 98135446Strhodes#define MAXCMD (4 * 1024) 99135446Strhodes#define MAXWIRE (64 * 1024) 100135446Strhodes#define PACKETSIZE ((64 * 1024) - 1) 101135446Strhodes#define INITTEXT (2 * 1024) 102135446Strhodes#define MAXTEXT (128 * 1024) 103135446Strhodes#define FIND_TIMEOUT 5 104135446Strhodes#define TTL_MAX 2147483647U /* Maximum signed 32 bit integer. */ 105135446Strhodes 106135446Strhodes#define DNSDEFAULTPORT 53 107135446Strhodes 108135446Strhodes#ifndef RESOLV_CONF 109135446Strhodes#define RESOLV_CONF "/etc/resolv.conf" 110135446Strhodes#endif 111135446Strhodes 112135446Strhodesstatic isc_boolean_t debugging = ISC_FALSE, ddebugging = ISC_FALSE; 113135446Strhodesstatic isc_boolean_t memdebugging = ISC_FALSE; 114135446Strhodesstatic isc_boolean_t have_ipv4 = ISC_FALSE; 115135446Strhodesstatic isc_boolean_t have_ipv6 = ISC_FALSE; 116135446Strhodesstatic isc_boolean_t is_dst_up = ISC_FALSE; 117135446Strhodesstatic isc_boolean_t usevc = ISC_FALSE; 118193149Sdougbstatic isc_boolean_t usegsstsig = ISC_FALSE; 119193149Sdougbstatic isc_boolean_t use_win2k_gsstsig = ISC_FALSE; 120193149Sdougbstatic isc_boolean_t tried_other_gsstsig = ISC_FALSE; 121135446Strhodesstatic isc_taskmgr_t *taskmgr = NULL; 122135446Strhodesstatic isc_task_t *global_task = NULL; 123135446Strhodesstatic isc_event_t *global_event = NULL; 124193149Sdougbstatic isc_log_t *lctx = NULL; 125135446Strhodesstatic isc_mem_t *mctx = NULL; 126135446Strhodesstatic dns_dispatchmgr_t *dispatchmgr = NULL; 127135446Strhodesstatic dns_requestmgr_t *requestmgr = NULL; 128135446Strhodesstatic isc_socketmgr_t *socketmgr = NULL; 129135446Strhodesstatic isc_timermgr_t *timermgr = NULL; 130135446Strhodesstatic dns_dispatch_t *dispatchv4 = NULL; 131135446Strhodesstatic dns_dispatch_t *dispatchv6 = NULL; 132135446Strhodesstatic dns_message_t *updatemsg = NULL; 133135446Strhodesstatic dns_fixedname_t fuserzone; 134135446Strhodesstatic dns_name_t *userzone = NULL; 135193149Sdougbstatic dns_name_t *zonename = NULL; 136193149Sdougbstatic dns_name_t tmpzonename; 137193149Sdougbstatic dns_name_t restart_master; 138193149Sdougbstatic dns_tsig_keyring_t *gssring = NULL; 139135446Strhodesstatic dns_tsigkey_t *tsigkey = NULL; 140135446Strhodesstatic dst_key_t *sig0key; 141135446Strhodesstatic lwres_context_t *lwctx = NULL; 142135446Strhodesstatic lwres_conf_t *lwconf; 143135446Strhodesstatic isc_sockaddr_t *servers; 144135446Strhodesstatic int ns_inuse = 0; 145135446Strhodesstatic int ns_total = 0; 146135446Strhodesstatic isc_sockaddr_t *userserver = NULL; 147135446Strhodesstatic isc_sockaddr_t *localaddr = NULL; 148193149Sdougbstatic isc_sockaddr_t *serveraddr = NULL; 149193149Sdougbstatic isc_sockaddr_t tempaddr; 150135446Strhodesstatic char *keystr = NULL, *keyfile = NULL; 151193149Sdougbstatic isc_entropy_t *entropy = NULL; 152135446Strhodesstatic isc_boolean_t shuttingdown = ISC_FALSE; 153135446Strhodesstatic FILE *input; 154135446Strhodesstatic isc_boolean_t interactive = ISC_TRUE; 155135446Strhodesstatic isc_boolean_t seenerror = ISC_FALSE; 156135446Strhodesstatic const dns_master_style_t *style; 157135446Strhodesstatic int requests = 0; 158193149Sdougbstatic unsigned int logdebuglevel = 0; 159135446Strhodesstatic unsigned int timeout = 300; 160135446Strhodesstatic unsigned int udp_timeout = 3; 161135446Strhodesstatic unsigned int udp_retries = 3; 162135446Strhodesstatic dns_rdataclass_t defaultclass = dns_rdataclass_in; 163135446Strhodesstatic dns_rdataclass_t zoneclass = dns_rdataclass_none; 164135446Strhodesstatic dns_message_t *answer = NULL; 165193149Sdougbstatic isc_uint32_t default_ttl = 0; 166193149Sdougbstatic isc_boolean_t default_ttl_set = ISC_FALSE; 167135446Strhodes 168135446Strhodestypedef struct nsu_requestinfo { 169135446Strhodes dns_message_t *msg; 170135446Strhodes isc_sockaddr_t *addr; 171135446Strhodes} nsu_requestinfo_t; 172135446Strhodes 173135446Strhodesstatic void 174135446Strhodessendrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, 175135446Strhodes dns_message_t *msg, dns_request_t **request); 176135446Strhodesstatic void 177135446Strhodesfatal(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); 178135446Strhodes 179135446Strhodesstatic void 180135446Strhodesdebug(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); 181135446Strhodes 182135446Strhodesstatic void 183135446Strhodesddebug(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); 184135446Strhodes 185193149Sdougb#ifdef GSSAPI 186193149Sdougbstatic dns_fixedname_t fkname; 187193149Sdougbstatic isc_sockaddr_t *kserver = NULL; 188193149Sdougbstatic char servicename[DNS_NAME_FORMATSIZE]; 189193149Sdougbstatic dns_name_t *keyname; 190193149Sdougbtypedef struct nsu_gssinfo { 191193149Sdougb dns_message_t *msg; 192193149Sdougb isc_sockaddr_t *addr; 193193149Sdougb gss_ctx_id_t context; 194193149Sdougb} nsu_gssinfo_t; 195193149Sdougb 196170222Sdougbstatic void 197193149Sdougbstart_gssrequest(dns_name_t *master); 198193149Sdougbstatic void 199193149Sdougbsend_gssrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, 200193149Sdougb dns_message_t *msg, dns_request_t **request, 201193149Sdougb gss_ctx_id_t context); 202193149Sdougbstatic void 203193149Sdougbrecvgss(isc_task_t *task, isc_event_t *event); 204193149Sdougb#endif /* GSSAPI */ 205193149Sdougb 206193149Sdougbstatic void 207170222Sdougberror(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); 208170222Sdougb 209135446Strhodes#define STATUS_MORE (isc_uint16_t)0 210135446Strhodes#define STATUS_SEND (isc_uint16_t)1 211135446Strhodes#define STATUS_QUIT (isc_uint16_t)2 212135446Strhodes#define STATUS_SYNTAX (isc_uint16_t)3 213135446Strhodes 214193149Sdougbtypedef struct entropysource entropysource_t; 215193149Sdougb 216193149Sdougbstruct entropysource { 217193149Sdougb isc_entropysource_t *source; 218193149Sdougb isc_mem_t *mctx; 219193149Sdougb ISC_LINK(entropysource_t) link; 220193149Sdougb}; 221193149Sdougb 222193149Sdougbstatic ISC_LIST(entropysource_t) sources; 223193149Sdougb 224193149Sdougbstatic void 225193149Sdougbsetup_entropy(isc_mem_t *mctx, const char *randomfile, isc_entropy_t **ectx) 226193149Sdougb{ 227193149Sdougb isc_result_t result; 228193149Sdougb isc_entropysource_t *source = NULL; 229193149Sdougb entropysource_t *elt; 230193149Sdougb int usekeyboard = ISC_ENTROPY_KEYBOARDMAYBE; 231193149Sdougb 232193149Sdougb REQUIRE(ectx != NULL); 233193149Sdougb 234193149Sdougb if (*ectx == NULL) { 235193149Sdougb result = isc_entropy_create(mctx, ectx); 236193149Sdougb if (result != ISC_R_SUCCESS) 237193149Sdougb fatal("could not create entropy object"); 238193149Sdougb ISC_LIST_INIT(sources); 239193149Sdougb } 240193149Sdougb 241193149Sdougb if (randomfile != NULL && strcmp(randomfile, "keyboard") == 0) { 242193149Sdougb usekeyboard = ISC_ENTROPY_KEYBOARDYES; 243193149Sdougb randomfile = NULL; 244193149Sdougb } 245193149Sdougb 246193149Sdougb result = isc_entropy_usebestsource(*ectx, &source, randomfile, 247193149Sdougb usekeyboard); 248193149Sdougb 249193149Sdougb if (result != ISC_R_SUCCESS) 250193149Sdougb fatal("could not initialize entropy source: %s", 251193149Sdougb isc_result_totext(result)); 252193149Sdougb 253193149Sdougb if (source != NULL) { 254193149Sdougb elt = isc_mem_get(mctx, sizeof(*elt)); 255193149Sdougb if (elt == NULL) 256193149Sdougb fatal("out of memory"); 257193149Sdougb elt->source = source; 258193149Sdougb elt->mctx = mctx; 259193149Sdougb ISC_LINK_INIT(elt, link); 260193149Sdougb ISC_LIST_APPEND(sources, elt, link); 261193149Sdougb } 262193149Sdougb} 263193149Sdougb 264193149Sdougbstatic void 265193149Sdougbcleanup_entropy(isc_entropy_t **ectx) { 266193149Sdougb entropysource_t *source; 267193149Sdougb while (!ISC_LIST_EMPTY(sources)) { 268193149Sdougb source = ISC_LIST_HEAD(sources); 269193149Sdougb ISC_LIST_UNLINK(sources, source, link); 270193149Sdougb isc_entropy_destroysource(&source->source); 271193149Sdougb isc_mem_put(source->mctx, source, sizeof(*source)); 272193149Sdougb } 273193149Sdougb isc_entropy_detach(ectx); 274193149Sdougb} 275193149Sdougb 276193149Sdougb 277135446Strhodesstatic dns_rdataclass_t 278135446Strhodesgetzoneclass(void) { 279135446Strhodes if (zoneclass == dns_rdataclass_none) 280135446Strhodes zoneclass = defaultclass; 281135446Strhodes return (zoneclass); 282135446Strhodes} 283135446Strhodes 284135446Strhodesstatic isc_boolean_t 285135446Strhodessetzoneclass(dns_rdataclass_t rdclass) { 286135446Strhodes if (zoneclass == dns_rdataclass_none || 287135446Strhodes rdclass == dns_rdataclass_none) 288135446Strhodes zoneclass = rdclass; 289135446Strhodes if (zoneclass != rdclass) 290135446Strhodes return (ISC_FALSE); 291135446Strhodes return (ISC_TRUE); 292135446Strhodes} 293135446Strhodes 294135446Strhodesstatic void 295135446Strhodesfatal(const char *format, ...) { 296135446Strhodes va_list args; 297135446Strhodes 298135446Strhodes va_start(args, format); 299135446Strhodes vfprintf(stderr, format, args); 300135446Strhodes va_end(args); 301135446Strhodes fprintf(stderr, "\n"); 302135446Strhodes exit(1); 303135446Strhodes} 304135446Strhodes 305135446Strhodesstatic void 306170222Sdougberror(const char *format, ...) { 307170222Sdougb va_list args; 308170222Sdougb 309170222Sdougb va_start(args, format); 310170222Sdougb vfprintf(stderr, format, args); 311170222Sdougb va_end(args); 312170222Sdougb fprintf(stderr, "\n"); 313170222Sdougb} 314170222Sdougb 315170222Sdougbstatic void 316135446Strhodesdebug(const char *format, ...) { 317135446Strhodes va_list args; 318135446Strhodes 319135446Strhodes if (debugging) { 320135446Strhodes va_start(args, format); 321135446Strhodes vfprintf(stderr, format, args); 322135446Strhodes va_end(args); 323135446Strhodes fprintf(stderr, "\n"); 324135446Strhodes } 325135446Strhodes} 326135446Strhodes 327135446Strhodesstatic void 328135446Strhodesddebug(const char *format, ...) { 329135446Strhodes va_list args; 330135446Strhodes 331135446Strhodes if (ddebugging) { 332135446Strhodes va_start(args, format); 333135446Strhodes vfprintf(stderr, format, args); 334135446Strhodes va_end(args); 335135446Strhodes fprintf(stderr, "\n"); 336135446Strhodes } 337135446Strhodes} 338135446Strhodes 339135446Strhodesstatic inline void 340135446Strhodescheck_result(isc_result_t result, const char *msg) { 341135446Strhodes if (result != ISC_R_SUCCESS) 342135446Strhodes fatal("%s: %s", msg, isc_result_totext(result)); 343135446Strhodes} 344135446Strhodes 345135446Strhodesstatic void * 346135446Strhodesmem_alloc(void *arg, size_t size) { 347135446Strhodes return (isc_mem_get(arg, size)); 348135446Strhodes} 349135446Strhodes 350135446Strhodesstatic void 351135446Strhodesmem_free(void *arg, void *mem, size_t size) { 352135446Strhodes isc_mem_put(arg, mem, size); 353135446Strhodes} 354135446Strhodes 355135446Strhodesstatic char * 356135446Strhodesnsu_strsep(char **stringp, const char *delim) { 357135446Strhodes char *string = *stringp; 358135446Strhodes char *s; 359135446Strhodes const char *d; 360135446Strhodes char sc, dc; 361135446Strhodes 362135446Strhodes if (string == NULL) 363135446Strhodes return (NULL); 364135446Strhodes 365135446Strhodes for (; *string != '\0'; string++) { 366135446Strhodes sc = *string; 367135446Strhodes for (d = delim; (dc = *d) != '\0'; d++) { 368135446Strhodes if (sc == dc) 369135446Strhodes break; 370135446Strhodes } 371135446Strhodes if (dc == 0) 372135446Strhodes break; 373135446Strhodes } 374135446Strhodes 375135446Strhodes for (s = string; *s != '\0'; s++) { 376135446Strhodes sc = *s; 377135446Strhodes for (d = delim; (dc = *d) != '\0'; d++) { 378135446Strhodes if (sc == dc) { 379135446Strhodes *s++ = '\0'; 380135446Strhodes *stringp = s; 381135446Strhodes return (string); 382135446Strhodes } 383135446Strhodes } 384135446Strhodes } 385135446Strhodes *stringp = NULL; 386135446Strhodes return (string); 387135446Strhodes} 388135446Strhodes 389135446Strhodesstatic void 390135446Strhodesreset_system(void) { 391135446Strhodes isc_result_t result; 392135446Strhodes 393135446Strhodes ddebug("reset_system()"); 394135446Strhodes /* If the update message is still around, destroy it */ 395135446Strhodes if (updatemsg != NULL) 396135446Strhodes dns_message_reset(updatemsg, DNS_MESSAGE_INTENTRENDER); 397135446Strhodes else { 398135446Strhodes result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, 399135446Strhodes &updatemsg); 400135446Strhodes check_result(result, "dns_message_create"); 401135446Strhodes } 402135446Strhodes updatemsg->opcode = dns_opcode_update; 403193149Sdougb if (usegsstsig) { 404193149Sdougb if (tsigkey != NULL) 405193149Sdougb dns_tsigkey_detach(&tsigkey); 406193149Sdougb if (gssring != NULL) 407193149Sdougb dns_tsigkeyring_destroy(&gssring); 408193149Sdougb tried_other_gsstsig = ISC_FALSE; 409193149Sdougb } 410135446Strhodes} 411135446Strhodes 412170222Sdougbstatic isc_uint16_t 413170222Sdougbparse_hmac(dns_name_t **hmac, const char *hmacstr, size_t len) { 414170222Sdougb isc_uint16_t digestbits = 0; 415170222Sdougb isc_result_t result; 416170222Sdougb char buf[20]; 417170222Sdougb 418170222Sdougb REQUIRE(hmac != NULL && *hmac == NULL); 419170222Sdougb REQUIRE(hmacstr != NULL); 420170222Sdougb 421170222Sdougb if (len >= sizeof(buf)) 422170222Sdougb fatal("unknown key type '%.*s'", (int)(len), hmacstr); 423170222Sdougb 424170222Sdougb strncpy(buf, hmacstr, len); 425170222Sdougb buf[len] = 0; 426186462Sdougb 427170222Sdougb if (strcasecmp(buf, "hmac-md5") == 0) { 428170222Sdougb *hmac = DNS_TSIG_HMACMD5_NAME; 429170222Sdougb } else if (strncasecmp(buf, "hmac-md5-", 9) == 0) { 430170222Sdougb *hmac = DNS_TSIG_HMACMD5_NAME; 431170222Sdougb result = isc_parse_uint16(&digestbits, &buf[9], 10); 432170222Sdougb if (result != ISC_R_SUCCESS || digestbits > 128) 433170222Sdougb fatal("digest-bits out of range [0..128]"); 434170222Sdougb digestbits = (digestbits +7) & ~0x7U; 435170222Sdougb } else if (strcasecmp(buf, "hmac-sha1") == 0) { 436170222Sdougb *hmac = DNS_TSIG_HMACSHA1_NAME; 437170222Sdougb } else if (strncasecmp(buf, "hmac-sha1-", 10) == 0) { 438170222Sdougb *hmac = DNS_TSIG_HMACSHA1_NAME; 439170222Sdougb result = isc_parse_uint16(&digestbits, &buf[10], 10); 440170222Sdougb if (result != ISC_R_SUCCESS || digestbits > 160) 441170222Sdougb fatal("digest-bits out of range [0..160]"); 442170222Sdougb digestbits = (digestbits +7) & ~0x7U; 443170222Sdougb } else if (strcasecmp(buf, "hmac-sha224") == 0) { 444170222Sdougb *hmac = DNS_TSIG_HMACSHA224_NAME; 445170222Sdougb } else if (strncasecmp(buf, "hmac-sha224-", 12) == 0) { 446170222Sdougb *hmac = DNS_TSIG_HMACSHA224_NAME; 447170222Sdougb result = isc_parse_uint16(&digestbits, &buf[12], 10); 448170222Sdougb if (result != ISC_R_SUCCESS || digestbits > 224) 449170222Sdougb fatal("digest-bits out of range [0..224]"); 450170222Sdougb digestbits = (digestbits +7) & ~0x7U; 451170222Sdougb } else if (strcasecmp(buf, "hmac-sha256") == 0) { 452170222Sdougb *hmac = DNS_TSIG_HMACSHA256_NAME; 453170222Sdougb } else if (strncasecmp(buf, "hmac-sha256-", 12) == 0) { 454170222Sdougb *hmac = DNS_TSIG_HMACSHA256_NAME; 455170222Sdougb result = isc_parse_uint16(&digestbits, &buf[12], 10); 456170222Sdougb if (result != ISC_R_SUCCESS || digestbits > 256) 457170222Sdougb fatal("digest-bits out of range [0..256]"); 458170222Sdougb digestbits = (digestbits +7) & ~0x7U; 459170222Sdougb } else if (strcasecmp(buf, "hmac-sha384") == 0) { 460170222Sdougb *hmac = DNS_TSIG_HMACSHA384_NAME; 461170222Sdougb } else if (strncasecmp(buf, "hmac-sha384-", 12) == 0) { 462170222Sdougb *hmac = DNS_TSIG_HMACSHA384_NAME; 463170222Sdougb result = isc_parse_uint16(&digestbits, &buf[12], 10); 464170222Sdougb if (result != ISC_R_SUCCESS || digestbits > 384) 465170222Sdougb fatal("digest-bits out of range [0..384]"); 466170222Sdougb digestbits = (digestbits +7) & ~0x7U; 467170222Sdougb } else if (strcasecmp(buf, "hmac-sha512") == 0) { 468170222Sdougb *hmac = DNS_TSIG_HMACSHA512_NAME; 469170222Sdougb } else if (strncasecmp(buf, "hmac-sha512-", 12) == 0) { 470170222Sdougb *hmac = DNS_TSIG_HMACSHA512_NAME; 471170222Sdougb result = isc_parse_uint16(&digestbits, &buf[12], 10); 472170222Sdougb if (result != ISC_R_SUCCESS || digestbits > 512) 473170222Sdougb fatal("digest-bits out of range [0..512]"); 474170222Sdougb digestbits = (digestbits +7) & ~0x7U; 475170222Sdougb } else 476170222Sdougb fatal("unknown key type '%s'", buf); 477170222Sdougb return (digestbits); 478170222Sdougb} 479170222Sdougb 480135446Strhodesstatic void 481135446Strhodessetup_keystr(void) { 482135446Strhodes unsigned char *secret = NULL; 483135446Strhodes int secretlen; 484135446Strhodes isc_buffer_t secretbuf; 485135446Strhodes isc_result_t result; 486135446Strhodes isc_buffer_t keynamesrc; 487135446Strhodes char *secretstr; 488170222Sdougb char *s, *n; 489135446Strhodes dns_fixedname_t fkeyname; 490135446Strhodes dns_name_t *keyname; 491170222Sdougb char *name; 492170222Sdougb dns_name_t *hmacname = NULL; 493170222Sdougb isc_uint16_t digestbits = 0; 494135446Strhodes 495135446Strhodes dns_fixedname_init(&fkeyname); 496135446Strhodes keyname = dns_fixedname_name(&fkeyname); 497135446Strhodes 498135446Strhodes debug("Creating key..."); 499135446Strhodes 500135446Strhodes s = strchr(keystr, ':'); 501170222Sdougb if (s == NULL || s == keystr || s[1] == 0) 502170222Sdougb fatal("key option must specify [hmac:]keyname:secret"); 503135446Strhodes secretstr = s + 1; 504170222Sdougb n = strchr(secretstr, ':'); 505170222Sdougb if (n != NULL) { 506170222Sdougb if (n == secretstr || n[1] == 0) 507170222Sdougb fatal("key option must specify [hmac:]keyname:secret"); 508170222Sdougb name = secretstr; 509170222Sdougb secretstr = n + 1; 510170222Sdougb digestbits = parse_hmac(&hmacname, keystr, s - keystr); 511170222Sdougb } else { 512170222Sdougb hmacname = DNS_TSIG_HMACMD5_NAME; 513170222Sdougb name = keystr; 514170222Sdougb n = s; 515170222Sdougb } 516135446Strhodes 517170222Sdougb isc_buffer_init(&keynamesrc, name, n - name); 518170222Sdougb isc_buffer_add(&keynamesrc, n - name); 519135446Strhodes 520135446Strhodes debug("namefromtext"); 521135446Strhodes result = dns_name_fromtext(keyname, &keynamesrc, dns_rootname, 522135446Strhodes ISC_FALSE, NULL); 523135446Strhodes check_result(result, "dns_name_fromtext"); 524135446Strhodes 525135446Strhodes secretlen = strlen(secretstr) * 3 / 4; 526135446Strhodes secret = isc_mem_allocate(mctx, secretlen); 527135446Strhodes if (secret == NULL) 528135446Strhodes fatal("out of memory"); 529135446Strhodes 530135446Strhodes isc_buffer_init(&secretbuf, secret, secretlen); 531135446Strhodes result = isc_base64_decodestring(secretstr, &secretbuf); 532135446Strhodes if (result != ISC_R_SUCCESS) { 533135446Strhodes fprintf(stderr, "could not create key from %s: %s\n", 534135446Strhodes keystr, isc_result_totext(result)); 535135446Strhodes goto failure; 536135446Strhodes } 537135446Strhodes 538135446Strhodes secretlen = isc_buffer_usedlength(&secretbuf); 539135446Strhodes 540135446Strhodes debug("keycreate"); 541170222Sdougb result = dns_tsigkey_create(keyname, hmacname, secret, secretlen, 542170222Sdougb ISC_TRUE, NULL, 0, 0, mctx, NULL, &tsigkey); 543135446Strhodes if (result != ISC_R_SUCCESS) 544135446Strhodes fprintf(stderr, "could not create key from %s: %s\n", 545135446Strhodes keystr, dns_result_totext(result)); 546170222Sdougb else 547170222Sdougb dst_key_setbits(tsigkey->key, digestbits); 548135446Strhodes failure: 549135446Strhodes if (secret != NULL) 550135446Strhodes isc_mem_free(mctx, secret); 551135446Strhodes} 552135446Strhodes 553135446Strhodesstatic void 554135446Strhodessetup_keyfile(void) { 555135446Strhodes dst_key_t *dstkey = NULL; 556135446Strhodes isc_result_t result; 557170222Sdougb dns_name_t *hmacname = NULL; 558135446Strhodes 559135446Strhodes debug("Creating key..."); 560135446Strhodes 561135446Strhodes result = dst_key_fromnamedfile(keyfile, 562135446Strhodes DST_TYPE_PRIVATE | DST_TYPE_KEY, mctx, 563135446Strhodes &dstkey); 564135446Strhodes if (result != ISC_R_SUCCESS) { 565135446Strhodes fprintf(stderr, "could not read key from %s: %s\n", 566135446Strhodes keyfile, isc_result_totext(result)); 567135446Strhodes return; 568135446Strhodes } 569170222Sdougb switch (dst_key_alg(dstkey)) { 570170222Sdougb case DST_ALG_HMACMD5: 571170222Sdougb hmacname = DNS_TSIG_HMACMD5_NAME; 572170222Sdougb break; 573170222Sdougb case DST_ALG_HMACSHA1: 574170222Sdougb hmacname = DNS_TSIG_HMACSHA1_NAME; 575170222Sdougb break; 576170222Sdougb case DST_ALG_HMACSHA224: 577170222Sdougb hmacname = DNS_TSIG_HMACSHA224_NAME; 578170222Sdougb break; 579170222Sdougb case DST_ALG_HMACSHA256: 580170222Sdougb hmacname = DNS_TSIG_HMACSHA256_NAME; 581170222Sdougb break; 582170222Sdougb case DST_ALG_HMACSHA384: 583170222Sdougb hmacname = DNS_TSIG_HMACSHA384_NAME; 584170222Sdougb break; 585170222Sdougb case DST_ALG_HMACSHA512: 586170222Sdougb hmacname = DNS_TSIG_HMACSHA512_NAME; 587170222Sdougb break; 588170222Sdougb } 589170222Sdougb if (hmacname != NULL) { 590135446Strhodes result = dns_tsigkey_createfromkey(dst_key_name(dstkey), 591170222Sdougb hmacname, dstkey, ISC_FALSE, 592170222Sdougb NULL, 0, 0, mctx, NULL, 593170222Sdougb &tsigkey); 594135446Strhodes if (result != ISC_R_SUCCESS) { 595135446Strhodes fprintf(stderr, "could not create key from %s: %s\n", 596135446Strhodes keyfile, isc_result_totext(result)); 597135446Strhodes dst_key_free(&dstkey); 598135446Strhodes return; 599135446Strhodes } 600135446Strhodes } else 601135446Strhodes sig0key = dstkey; 602135446Strhodes} 603135446Strhodes 604135446Strhodesstatic void 605135446Strhodesdoshutdown(void) { 606135446Strhodes isc_task_detach(&global_task); 607135446Strhodes 608135446Strhodes if (userserver != NULL) 609135446Strhodes isc_mem_put(mctx, userserver, sizeof(isc_sockaddr_t)); 610135446Strhodes 611135446Strhodes if (localaddr != NULL) 612135446Strhodes isc_mem_put(mctx, localaddr, sizeof(isc_sockaddr_t)); 613135446Strhodes 614135446Strhodes if (tsigkey != NULL) { 615135446Strhodes ddebug("Freeing TSIG key"); 616135446Strhodes dns_tsigkey_detach(&tsigkey); 617135446Strhodes } 618135446Strhodes 619135446Strhodes if (sig0key != NULL) { 620135446Strhodes ddebug("Freeing SIG(0) key"); 621135446Strhodes dst_key_free(&sig0key); 622135446Strhodes } 623135446Strhodes 624135446Strhodes if (updatemsg != NULL) 625135446Strhodes dns_message_destroy(&updatemsg); 626135446Strhodes 627135446Strhodes if (is_dst_up) { 628135446Strhodes ddebug("Destroy DST lib"); 629135446Strhodes dst_lib_destroy(); 630135446Strhodes is_dst_up = ISC_FALSE; 631135446Strhodes } 632135446Strhodes 633193149Sdougb cleanup_entropy(&entropy); 634135446Strhodes 635135446Strhodes lwres_conf_clear(lwctx); 636135446Strhodes lwres_context_destroy(&lwctx); 637135446Strhodes 638135446Strhodes isc_mem_put(mctx, servers, ns_total * sizeof(isc_sockaddr_t)); 639135446Strhodes 640135446Strhodes ddebug("Destroying request manager"); 641135446Strhodes dns_requestmgr_detach(&requestmgr); 642135446Strhodes 643135446Strhodes ddebug("Freeing the dispatchers"); 644135446Strhodes if (have_ipv4) 645135446Strhodes dns_dispatch_detach(&dispatchv4); 646135446Strhodes if (have_ipv6) 647135446Strhodes dns_dispatch_detach(&dispatchv6); 648135446Strhodes 649135446Strhodes ddebug("Shutting down dispatch manager"); 650135446Strhodes dns_dispatchmgr_destroy(&dispatchmgr); 651135446Strhodes 652135446Strhodes} 653135446Strhodes 654135446Strhodesstatic void 655135446Strhodesmaybeshutdown(void) { 656135446Strhodes ddebug("Shutting down request manager"); 657135446Strhodes dns_requestmgr_shutdown(requestmgr); 658135446Strhodes 659135446Strhodes if (requests != 0) 660135446Strhodes return; 661135446Strhodes 662135446Strhodes doshutdown(); 663135446Strhodes} 664135446Strhodes 665135446Strhodesstatic void 666135446Strhodesshutdown_program(isc_task_t *task, isc_event_t *event) { 667135446Strhodes REQUIRE(task == global_task); 668135446Strhodes UNUSED(task); 669135446Strhodes 670135446Strhodes ddebug("shutdown_program()"); 671135446Strhodes isc_event_free(&event); 672135446Strhodes 673135446Strhodes shuttingdown = ISC_TRUE; 674135446Strhodes maybeshutdown(); 675135446Strhodes} 676135446Strhodes 677135446Strhodesstatic void 678135446Strhodessetup_system(void) { 679135446Strhodes isc_result_t result; 680135446Strhodes isc_sockaddr_t bind_any, bind_any6; 681135446Strhodes lwres_result_t lwresult; 682135446Strhodes unsigned int attrs, attrmask; 683135446Strhodes int i; 684193149Sdougb isc_logconfig_t *logconfig = NULL; 685135446Strhodes 686135446Strhodes ddebug("setup_system()"); 687135446Strhodes 688135446Strhodes dns_result_register(); 689135446Strhodes 690135446Strhodes result = isc_net_probeipv4(); 691135446Strhodes if (result == ISC_R_SUCCESS) 692135446Strhodes have_ipv4 = ISC_TRUE; 693135446Strhodes 694135446Strhodes result = isc_net_probeipv6(); 695135446Strhodes if (result == ISC_R_SUCCESS) 696135446Strhodes have_ipv6 = ISC_TRUE; 697135446Strhodes 698135446Strhodes if (!have_ipv4 && !have_ipv6) 699135446Strhodes fatal("could not find either IPv4 or IPv6"); 700135446Strhodes 701193149Sdougb result = isc_log_create(mctx, &lctx, &logconfig); 702193149Sdougb check_result(result, "isc_log_create"); 703135446Strhodes 704193149Sdougb isc_log_setcontext(lctx); 705193149Sdougb dns_log_init(lctx); 706193149Sdougb dns_log_setcontext(lctx); 707193149Sdougb 708193149Sdougb result = isc_log_usechannel(logconfig, "default_debug", NULL, NULL); 709193149Sdougb check_result(result, "isc_log_usechannel"); 710193149Sdougb 711193149Sdougb isc_log_setdebuglevel(lctx, logdebuglevel); 712193149Sdougb 713135446Strhodes lwresult = lwres_context_create(&lwctx, mctx, mem_alloc, mem_free, 1); 714135446Strhodes if (lwresult != LWRES_R_SUCCESS) 715135446Strhodes fatal("lwres_context_create failed"); 716135446Strhodes 717135446Strhodes (void)lwres_conf_parse(lwctx, RESOLV_CONF); 718135446Strhodes lwconf = lwres_conf_get(lwctx); 719135446Strhodes 720135446Strhodes ns_total = lwconf->nsnext; 721135446Strhodes if (ns_total <= 0) { 722135446Strhodes /* No name servers in resolv.conf; default to loopback. */ 723135446Strhodes struct in_addr localhost; 724135446Strhodes ns_total = 1; 725135446Strhodes servers = isc_mem_get(mctx, ns_total * sizeof(isc_sockaddr_t)); 726135446Strhodes if (servers == NULL) 727135446Strhodes fatal("out of memory"); 728135446Strhodes localhost.s_addr = htonl(INADDR_LOOPBACK); 729135446Strhodes isc_sockaddr_fromin(&servers[0], &localhost, DNSDEFAULTPORT); 730135446Strhodes } else { 731135446Strhodes servers = isc_mem_get(mctx, ns_total * sizeof(isc_sockaddr_t)); 732135446Strhodes if (servers == NULL) 733135446Strhodes fatal("out of memory"); 734135446Strhodes for (i = 0; i < ns_total; i++) { 735135446Strhodes if (lwconf->nameservers[i].family == LWRES_ADDRTYPE_V4) { 736135446Strhodes struct in_addr in4; 737135446Strhodes memcpy(&in4, lwconf->nameservers[i].address, 4); 738135446Strhodes isc_sockaddr_fromin(&servers[i], &in4, DNSDEFAULTPORT); 739135446Strhodes } else { 740135446Strhodes struct in6_addr in6; 741135446Strhodes memcpy(&in6, lwconf->nameservers[i].address, 16); 742135446Strhodes isc_sockaddr_fromin6(&servers[i], &in6, 743135446Strhodes DNSDEFAULTPORT); 744135446Strhodes } 745135446Strhodes } 746135446Strhodes } 747135446Strhodes 748193149Sdougb setup_entropy(mctx, NULL, &entropy); 749135446Strhodes 750193149Sdougb result = isc_hash_create(mctx, entropy, DNS_NAME_MAXWIRE); 751135446Strhodes check_result(result, "isc_hash_create"); 752135446Strhodes isc_hash_init(); 753135446Strhodes 754193149Sdougb result = dns_dispatchmgr_create(mctx, entropy, &dispatchmgr); 755135446Strhodes check_result(result, "dns_dispatchmgr_create"); 756135446Strhodes 757135446Strhodes result = isc_socketmgr_create(mctx, &socketmgr); 758135446Strhodes check_result(result, "dns_socketmgr_create"); 759135446Strhodes 760135446Strhodes result = isc_timermgr_create(mctx, &timermgr); 761135446Strhodes check_result(result, "dns_timermgr_create"); 762135446Strhodes 763135446Strhodes result = isc_taskmgr_create(mctx, 1, 0, &taskmgr); 764135446Strhodes check_result(result, "isc_taskmgr_create"); 765135446Strhodes 766135446Strhodes result = isc_task_create(taskmgr, 0, &global_task); 767135446Strhodes check_result(result, "isc_task_create"); 768135446Strhodes 769135446Strhodes result = isc_task_onshutdown(global_task, shutdown_program, NULL); 770135446Strhodes check_result(result, "isc_task_onshutdown"); 771135446Strhodes 772193149Sdougb result = dst_lib_init(mctx, entropy, 0); 773135446Strhodes check_result(result, "dst_lib_init"); 774135446Strhodes is_dst_up = ISC_TRUE; 775135446Strhodes 776135446Strhodes attrmask = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP; 777135446Strhodes attrmask |= DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6; 778135446Strhodes 779135446Strhodes if (have_ipv6) { 780135446Strhodes attrs = DNS_DISPATCHATTR_UDP; 781135446Strhodes attrs |= DNS_DISPATCHATTR_MAKEQUERY; 782135446Strhodes attrs |= DNS_DISPATCHATTR_IPV6; 783135446Strhodes isc_sockaddr_any6(&bind_any6); 784135446Strhodes result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, 785135446Strhodes &bind_any6, PACKETSIZE, 786135446Strhodes 4, 2, 3, 5, 787135446Strhodes attrs, attrmask, &dispatchv6); 788135446Strhodes check_result(result, "dns_dispatch_getudp (v6)"); 789135446Strhodes } 790135446Strhodes 791135446Strhodes if (have_ipv4) { 792135446Strhodes attrs = DNS_DISPATCHATTR_UDP; 793135446Strhodes attrs |= DNS_DISPATCHATTR_MAKEQUERY; 794135446Strhodes attrs |= DNS_DISPATCHATTR_IPV4; 795135446Strhodes isc_sockaddr_any(&bind_any); 796135446Strhodes result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, 797135446Strhodes &bind_any, PACKETSIZE, 798135446Strhodes 4, 2, 3, 5, 799135446Strhodes attrs, attrmask, &dispatchv4); 800135446Strhodes check_result(result, "dns_dispatch_getudp (v4)"); 801135446Strhodes } 802135446Strhodes 803135446Strhodes result = dns_requestmgr_create(mctx, timermgr, 804135446Strhodes socketmgr, taskmgr, dispatchmgr, 805135446Strhodes dispatchv4, dispatchv6, &requestmgr); 806135446Strhodes check_result(result, "dns_requestmgr_create"); 807135446Strhodes 808135446Strhodes if (keystr != NULL) 809135446Strhodes setup_keystr(); 810135446Strhodes else if (keyfile != NULL) 811135446Strhodes setup_keyfile(); 812135446Strhodes} 813135446Strhodes 814135446Strhodesstatic void 815135446Strhodesget_address(char *host, in_port_t port, isc_sockaddr_t *sockaddr) { 816135446Strhodes int count; 817135446Strhodes isc_result_t result; 818135446Strhodes 819135446Strhodes isc_app_block(); 820135446Strhodes result = bind9_getaddresses(host, port, sockaddr, 1, &count); 821135446Strhodes isc_app_unblock(); 822135446Strhodes if (result != ISC_R_SUCCESS) 823135446Strhodes fatal("couldn't get address for '%s': %s", 824135446Strhodes host, isc_result_totext(result)); 825135446Strhodes INSIST(count == 1); 826135446Strhodes} 827135446Strhodes 828193149Sdougb#define PARSE_ARGS_FMT "dDMl:y:govk:rR::t:u:" 829193149Sdougb 830135446Strhodesstatic void 831193149Sdougbpre_parse_args(int argc, char **argv) { 832135446Strhodes int ch; 833193149Sdougb 834193149Sdougb while ((ch = isc_commandline_parse(argc, argv, PARSE_ARGS_FMT)) != -1) { 835193149Sdougb switch (ch) { 836193149Sdougb case 'M': /* was -dm */ 837193149Sdougb debugging = ISC_TRUE; 838193149Sdougb ddebugging = ISC_TRUE; 839193149Sdougb memdebugging = ISC_TRUE; 840193149Sdougb isc_mem_debugging = ISC_MEM_DEBUGTRACE | 841193149Sdougb ISC_MEM_DEBUGRECORD; 842193149Sdougb break; 843193149Sdougb 844193149Sdougb case '?': 845193149Sdougb if (isc_commandline_option != '?') 846193149Sdougb fprintf(stderr, "%s: invalid argument -%c\n", 847193149Sdougb argv[0], isc_commandline_option); 848193149Sdougb fprintf(stderr, "usage: nsupdate [-d] " 849193149Sdougb "[-g | -o | -y keyname:secret | -k keyfile] " 850193149Sdougb "[-v] [filename]\n"); 851193149Sdougb exit(1); 852193149Sdougb 853193149Sdougb default: 854193149Sdougb break; 855193149Sdougb } 856193149Sdougb } 857193149Sdougb isc_commandline_reset = ISC_TRUE; 858193149Sdougb isc_commandline_index = 1; 859193149Sdougb} 860193149Sdougb 861193149Sdougbstatic void 862193149Sdougbparse_args(int argc, char **argv, isc_mem_t *mctx, isc_entropy_t **ectx) { 863193149Sdougb int ch; 864193149Sdougb isc_uint32_t i; 865135446Strhodes isc_result_t result; 866135446Strhodes 867135446Strhodes debug("parse_args"); 868193149Sdougb while ((ch = isc_commandline_parse(argc, argv, PARSE_ARGS_FMT)) != -1) { 869135446Strhodes switch (ch) { 870135446Strhodes case 'd': 871135446Strhodes debugging = ISC_TRUE; 872135446Strhodes break; 873135446Strhodes case 'D': /* was -dd */ 874135446Strhodes debugging = ISC_TRUE; 875135446Strhodes ddebugging = ISC_TRUE; 876135446Strhodes break; 877193149Sdougb case 'M': 878135446Strhodes break; 879193149Sdougb case 'l': 880193149Sdougb result = isc_parse_uint32(&i, isc_commandline_argument, 881193149Sdougb 10); 882193149Sdougb if (result != ISC_R_SUCCESS) { 883193149Sdougb fprintf(stderr, "bad library debug value " 884193149Sdougb "'%s'\n", isc_commandline_argument); 885193149Sdougb exit(1); 886193149Sdougb } 887193149Sdougb logdebuglevel = i; 888193149Sdougb break; 889135446Strhodes case 'y': 890135446Strhodes keystr = isc_commandline_argument; 891135446Strhodes break; 892135446Strhodes case 'v': 893135446Strhodes usevc = ISC_TRUE; 894135446Strhodes break; 895135446Strhodes case 'k': 896135446Strhodes keyfile = isc_commandline_argument; 897135446Strhodes break; 898193149Sdougb case 'g': 899193149Sdougb usegsstsig = ISC_TRUE; 900193149Sdougb use_win2k_gsstsig = ISC_FALSE; 901193149Sdougb break; 902193149Sdougb case 'o': 903193149Sdougb usegsstsig = ISC_TRUE; 904193149Sdougb use_win2k_gsstsig = ISC_TRUE; 905193149Sdougb break; 906135446Strhodes case 't': 907135446Strhodes result = isc_parse_uint32(&timeout, 908135446Strhodes isc_commandline_argument, 10); 909135446Strhodes if (result != ISC_R_SUCCESS) { 910135446Strhodes fprintf(stderr, "bad timeout '%s'\n", isc_commandline_argument); 911135446Strhodes exit(1); 912135446Strhodes } 913135446Strhodes if (timeout == 0) 914143731Sdougb timeout = UINT_MAX; 915135446Strhodes break; 916135446Strhodes case 'u': 917135446Strhodes result = isc_parse_uint32(&udp_timeout, 918135446Strhodes isc_commandline_argument, 10); 919135446Strhodes if (result != ISC_R_SUCCESS) { 920135446Strhodes fprintf(stderr, "bad udp timeout '%s'\n", isc_commandline_argument); 921135446Strhodes exit(1); 922135446Strhodes } 923135446Strhodes if (udp_timeout == 0) 924143731Sdougb udp_timeout = UINT_MAX; 925135446Strhodes break; 926135446Strhodes case 'r': 927135446Strhodes result = isc_parse_uint32(&udp_retries, 928135446Strhodes isc_commandline_argument, 10); 929135446Strhodes if (result != ISC_R_SUCCESS) { 930135446Strhodes fprintf(stderr, "bad udp retries '%s'\n", isc_commandline_argument); 931135446Strhodes exit(1); 932135446Strhodes } 933135446Strhodes break; 934193149Sdougb 935193149Sdougb case 'R': 936193149Sdougb setup_entropy(mctx, isc_commandline_argument, ectx); 937193149Sdougb break; 938193149Sdougb 939135446Strhodes default: 940193149Sdougb fprintf(stderr, "%s: unhandled option: %c\n", 941193149Sdougb argv[0], isc_commandline_option); 942135446Strhodes exit(1); 943135446Strhodes } 944135446Strhodes } 945135446Strhodes if (keyfile != NULL && keystr != NULL) { 946135446Strhodes fprintf(stderr, "%s: cannot specify both -k and -y\n", 947135446Strhodes argv[0]); 948135446Strhodes exit(1); 949135446Strhodes } 950135446Strhodes 951193149Sdougb#ifdef GSSAPI 952193149Sdougb if (usegsstsig && (keyfile != NULL || keystr != NULL)) { 953193149Sdougb fprintf(stderr, "%s: cannot specify -g with -k or -y\n", 954193149Sdougb argv[0]); 955193149Sdougb exit(1); 956193149Sdougb } 957193149Sdougb#else 958193149Sdougb if (usegsstsig) { 959193149Sdougb fprintf(stderr, "%s: cannot specify -g or -o, " \ 960193149Sdougb "program not linked with GSS API Library\n", 961193149Sdougb argv[0]); 962193149Sdougb exit(1); 963193149Sdougb } 964193149Sdougb#endif 965193149Sdougb 966135446Strhodes if (argv[isc_commandline_index] != NULL) { 967135446Strhodes if (strcmp(argv[isc_commandline_index], "-") == 0) { 968135446Strhodes input = stdin; 969135446Strhodes } else { 970135446Strhodes result = isc_stdio_open(argv[isc_commandline_index], 971135446Strhodes "r", &input); 972135446Strhodes if (result != ISC_R_SUCCESS) { 973135446Strhodes fprintf(stderr, "could not open '%s': %s\n", 974135446Strhodes argv[isc_commandline_index], 975135446Strhodes isc_result_totext(result)); 976135446Strhodes exit(1); 977135446Strhodes } 978135446Strhodes } 979135446Strhodes interactive = ISC_FALSE; 980135446Strhodes } 981135446Strhodes} 982135446Strhodes 983135446Strhodesstatic isc_uint16_t 984135446Strhodesparse_name(char **cmdlinep, dns_message_t *msg, dns_name_t **namep) { 985135446Strhodes isc_result_t result; 986135446Strhodes char *word; 987135446Strhodes isc_buffer_t *namebuf = NULL; 988135446Strhodes isc_buffer_t source; 989135446Strhodes 990135446Strhodes word = nsu_strsep(cmdlinep, " \t\r\n"); 991135446Strhodes if (*word == 0) { 992135446Strhodes fprintf(stderr, "could not read owner name\n"); 993135446Strhodes return (STATUS_SYNTAX); 994135446Strhodes } 995135446Strhodes 996135446Strhodes result = dns_message_gettempname(msg, namep); 997135446Strhodes check_result(result, "dns_message_gettempname"); 998135446Strhodes result = isc_buffer_allocate(mctx, &namebuf, DNS_NAME_MAXWIRE); 999135446Strhodes check_result(result, "isc_buffer_allocate"); 1000135446Strhodes dns_name_init(*namep, NULL); 1001135446Strhodes dns_name_setbuffer(*namep, namebuf); 1002135446Strhodes dns_message_takebuffer(msg, &namebuf); 1003135446Strhodes isc_buffer_init(&source, word, strlen(word)); 1004135446Strhodes isc_buffer_add(&source, strlen(word)); 1005135446Strhodes result = dns_name_fromtext(*namep, &source, dns_rootname, 1006135446Strhodes ISC_FALSE, NULL); 1007135446Strhodes check_result(result, "dns_name_fromtext"); 1008135446Strhodes isc_buffer_invalidate(&source); 1009135446Strhodes return (STATUS_MORE); 1010135446Strhodes} 1011135446Strhodes 1012135446Strhodesstatic isc_uint16_t 1013135446Strhodesparse_rdata(char **cmdlinep, dns_rdataclass_t rdataclass, 1014135446Strhodes dns_rdatatype_t rdatatype, dns_message_t *msg, 1015135446Strhodes dns_rdata_t *rdata) 1016135446Strhodes{ 1017135446Strhodes char *cmdline = *cmdlinep; 1018135446Strhodes isc_buffer_t source, *buf = NULL, *newbuf = NULL; 1019135446Strhodes isc_region_t r; 1020135446Strhodes isc_lex_t *lex = NULL; 1021135446Strhodes dns_rdatacallbacks_t callbacks; 1022135446Strhodes isc_result_t result; 1023135446Strhodes 1024135446Strhodes while (*cmdline != 0 && isspace((unsigned char)*cmdline)) 1025135446Strhodes cmdline++; 1026135446Strhodes 1027135446Strhodes if (*cmdline != 0) { 1028135446Strhodes dns_rdatacallbacks_init(&callbacks); 1029135446Strhodes result = isc_lex_create(mctx, strlen(cmdline), &lex); 1030135446Strhodes check_result(result, "isc_lex_create"); 1031135446Strhodes isc_buffer_init(&source, cmdline, strlen(cmdline)); 1032135446Strhodes isc_buffer_add(&source, strlen(cmdline)); 1033135446Strhodes result = isc_lex_openbuffer(lex, &source); 1034135446Strhodes check_result(result, "isc_lex_openbuffer"); 1035135446Strhodes result = isc_buffer_allocate(mctx, &buf, MAXWIRE); 1036135446Strhodes check_result(result, "isc_buffer_allocate"); 1037193149Sdougb result = dns_rdata_fromtext(NULL, rdataclass, rdatatype, lex, 1038135446Strhodes dns_rootname, 0, mctx, buf, 1039135446Strhodes &callbacks); 1040135446Strhodes isc_lex_destroy(&lex); 1041135446Strhodes if (result == ISC_R_SUCCESS) { 1042135446Strhodes isc_buffer_usedregion(buf, &r); 1043135446Strhodes result = isc_buffer_allocate(mctx, &newbuf, r.length); 1044135446Strhodes check_result(result, "isc_buffer_allocate"); 1045135446Strhodes isc_buffer_putmem(newbuf, r.base, r.length); 1046135446Strhodes isc_buffer_usedregion(newbuf, &r); 1047135446Strhodes dns_rdata_fromregion(rdata, rdataclass, rdatatype, &r); 1048135446Strhodes isc_buffer_free(&buf); 1049135446Strhodes dns_message_takebuffer(msg, &newbuf); 1050135446Strhodes } else { 1051135446Strhodes fprintf(stderr, "invalid rdata format: %s\n", 1052135446Strhodes isc_result_totext(result)); 1053135446Strhodes isc_buffer_free(&buf); 1054135446Strhodes return (STATUS_SYNTAX); 1055135446Strhodes } 1056135446Strhodes } else { 1057135446Strhodes rdata->flags = DNS_RDATA_UPDATE; 1058135446Strhodes } 1059135446Strhodes *cmdlinep = cmdline; 1060135446Strhodes return (STATUS_MORE); 1061135446Strhodes} 1062135446Strhodes 1063135446Strhodesstatic isc_uint16_t 1064135446Strhodesmake_prereq(char *cmdline, isc_boolean_t ispositive, isc_boolean_t isrrset) { 1065135446Strhodes isc_result_t result; 1066135446Strhodes char *word; 1067135446Strhodes dns_name_t *name = NULL; 1068135446Strhodes isc_textregion_t region; 1069135446Strhodes dns_rdataset_t *rdataset = NULL; 1070135446Strhodes dns_rdatalist_t *rdatalist = NULL; 1071135446Strhodes dns_rdataclass_t rdataclass; 1072135446Strhodes dns_rdatatype_t rdatatype; 1073135446Strhodes dns_rdata_t *rdata = NULL; 1074135446Strhodes isc_uint16_t retval; 1075135446Strhodes 1076135446Strhodes ddebug("make_prereq()"); 1077135446Strhodes 1078135446Strhodes /* 1079135446Strhodes * Read the owner name 1080135446Strhodes */ 1081135446Strhodes retval = parse_name(&cmdline, updatemsg, &name); 1082135446Strhodes if (retval != STATUS_MORE) 1083135446Strhodes return (retval); 1084135446Strhodes 1085135446Strhodes /* 1086135446Strhodes * If this is an rrset prereq, read the class or type. 1087135446Strhodes */ 1088135446Strhodes if (isrrset) { 1089135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1090135446Strhodes if (*word == 0) { 1091135446Strhodes fprintf(stderr, "could not read class or type\n"); 1092135446Strhodes goto failure; 1093135446Strhodes } 1094135446Strhodes region.base = word; 1095135446Strhodes region.length = strlen(word); 1096135446Strhodes result = dns_rdataclass_fromtext(&rdataclass, ®ion); 1097135446Strhodes if (result == ISC_R_SUCCESS) { 1098135446Strhodes if (!setzoneclass(rdataclass)) { 1099135446Strhodes fprintf(stderr, "class mismatch: %s\n", word); 1100135446Strhodes goto failure; 1101135446Strhodes } 1102135446Strhodes /* 1103135446Strhodes * Now read the type. 1104135446Strhodes */ 1105135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1106135446Strhodes if (*word == 0) { 1107135446Strhodes fprintf(stderr, "could not read type\n"); 1108135446Strhodes goto failure; 1109135446Strhodes } 1110135446Strhodes region.base = word; 1111135446Strhodes region.length = strlen(word); 1112135446Strhodes result = dns_rdatatype_fromtext(&rdatatype, ®ion); 1113135446Strhodes if (result != ISC_R_SUCCESS) { 1114135446Strhodes fprintf(stderr, "invalid type: %s\n", word); 1115135446Strhodes goto failure; 1116135446Strhodes } 1117135446Strhodes } else { 1118135446Strhodes rdataclass = getzoneclass(); 1119135446Strhodes result = dns_rdatatype_fromtext(&rdatatype, ®ion); 1120135446Strhodes if (result != ISC_R_SUCCESS) { 1121135446Strhodes fprintf(stderr, "invalid type: %s\n", word); 1122135446Strhodes goto failure; 1123135446Strhodes } 1124135446Strhodes } 1125135446Strhodes } else 1126135446Strhodes rdatatype = dns_rdatatype_any; 1127135446Strhodes 1128135446Strhodes result = dns_message_gettemprdata(updatemsg, &rdata); 1129135446Strhodes check_result(result, "dns_message_gettemprdata"); 1130135446Strhodes 1131193149Sdougb dns_rdata_init(rdata); 1132135446Strhodes 1133135446Strhodes if (isrrset && ispositive) { 1134135446Strhodes retval = parse_rdata(&cmdline, rdataclass, rdatatype, 1135135446Strhodes updatemsg, rdata); 1136135446Strhodes if (retval != STATUS_MORE) 1137135446Strhodes goto failure; 1138135446Strhodes } else 1139135446Strhodes rdata->flags = DNS_RDATA_UPDATE; 1140135446Strhodes 1141135446Strhodes result = dns_message_gettemprdatalist(updatemsg, &rdatalist); 1142135446Strhodes check_result(result, "dns_message_gettemprdatalist"); 1143135446Strhodes result = dns_message_gettemprdataset(updatemsg, &rdataset); 1144135446Strhodes check_result(result, "dns_message_gettemprdataset"); 1145135446Strhodes dns_rdatalist_init(rdatalist); 1146135446Strhodes rdatalist->type = rdatatype; 1147135446Strhodes if (ispositive) { 1148135446Strhodes if (isrrset && rdata->data != NULL) 1149135446Strhodes rdatalist->rdclass = rdataclass; 1150135446Strhodes else 1151135446Strhodes rdatalist->rdclass = dns_rdataclass_any; 1152135446Strhodes } else 1153135446Strhodes rdatalist->rdclass = dns_rdataclass_none; 1154135446Strhodes rdatalist->covers = 0; 1155135446Strhodes rdatalist->ttl = 0; 1156135446Strhodes rdata->rdclass = rdatalist->rdclass; 1157135446Strhodes rdata->type = rdatatype; 1158135446Strhodes ISC_LIST_INIT(rdatalist->rdata); 1159135446Strhodes ISC_LIST_APPEND(rdatalist->rdata, rdata, link); 1160135446Strhodes dns_rdataset_init(rdataset); 1161135446Strhodes dns_rdatalist_tordataset(rdatalist, rdataset); 1162135446Strhodes ISC_LIST_INIT(name->list); 1163135446Strhodes ISC_LIST_APPEND(name->list, rdataset, link); 1164135446Strhodes dns_message_addname(updatemsg, name, DNS_SECTION_PREREQUISITE); 1165135446Strhodes return (STATUS_MORE); 1166135446Strhodes 1167135446Strhodes failure: 1168135446Strhodes if (name != NULL) 1169135446Strhodes dns_message_puttempname(updatemsg, &name); 1170135446Strhodes return (STATUS_SYNTAX); 1171135446Strhodes} 1172135446Strhodes 1173135446Strhodesstatic isc_uint16_t 1174135446Strhodesevaluate_prereq(char *cmdline) { 1175135446Strhodes char *word; 1176135446Strhodes isc_boolean_t ispositive, isrrset; 1177135446Strhodes 1178135446Strhodes ddebug("evaluate_prereq()"); 1179135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1180135446Strhodes if (*word == 0) { 1181135446Strhodes fprintf(stderr, "could not read operation code\n"); 1182135446Strhodes return (STATUS_SYNTAX); 1183135446Strhodes } 1184135446Strhodes if (strcasecmp(word, "nxdomain") == 0) { 1185135446Strhodes ispositive = ISC_FALSE; 1186135446Strhodes isrrset = ISC_FALSE; 1187135446Strhodes } else if (strcasecmp(word, "yxdomain") == 0) { 1188135446Strhodes ispositive = ISC_TRUE; 1189135446Strhodes isrrset = ISC_FALSE; 1190135446Strhodes } else if (strcasecmp(word, "nxrrset") == 0) { 1191135446Strhodes ispositive = ISC_FALSE; 1192135446Strhodes isrrset = ISC_TRUE; 1193135446Strhodes } else if (strcasecmp(word, "yxrrset") == 0) { 1194135446Strhodes ispositive = ISC_TRUE; 1195135446Strhodes isrrset = ISC_TRUE; 1196135446Strhodes } else { 1197135446Strhodes fprintf(stderr, "incorrect operation code: %s\n", word); 1198135446Strhodes return (STATUS_SYNTAX); 1199135446Strhodes } 1200135446Strhodes return (make_prereq(cmdline, ispositive, isrrset)); 1201135446Strhodes} 1202135446Strhodes 1203135446Strhodesstatic isc_uint16_t 1204135446Strhodesevaluate_server(char *cmdline) { 1205135446Strhodes char *word, *server; 1206135446Strhodes long port; 1207135446Strhodes 1208135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1209135446Strhodes if (*word == 0) { 1210135446Strhodes fprintf(stderr, "could not read server name\n"); 1211135446Strhodes return (STATUS_SYNTAX); 1212135446Strhodes } 1213135446Strhodes server = word; 1214135446Strhodes 1215135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1216135446Strhodes if (*word == 0) 1217135446Strhodes port = DNSDEFAULTPORT; 1218135446Strhodes else { 1219135446Strhodes char *endp; 1220135446Strhodes port = strtol(word, &endp, 10); 1221135446Strhodes if (*endp != 0) { 1222135446Strhodes fprintf(stderr, "port '%s' is not numeric\n", word); 1223135446Strhodes return (STATUS_SYNTAX); 1224135446Strhodes } else if (port < 1 || port > 65535) { 1225135446Strhodes fprintf(stderr, "port '%s' is out of range " 1226135446Strhodes "(1 to 65535)\n", word); 1227135446Strhodes return (STATUS_SYNTAX); 1228135446Strhodes } 1229135446Strhodes } 1230135446Strhodes 1231135446Strhodes if (userserver == NULL) { 1232135446Strhodes userserver = isc_mem_get(mctx, sizeof(isc_sockaddr_t)); 1233135446Strhodes if (userserver == NULL) 1234135446Strhodes fatal("out of memory"); 1235135446Strhodes } 1236135446Strhodes 1237135446Strhodes get_address(server, (in_port_t)port, userserver); 1238135446Strhodes 1239135446Strhodes return (STATUS_MORE); 1240135446Strhodes} 1241135446Strhodes 1242135446Strhodesstatic isc_uint16_t 1243135446Strhodesevaluate_local(char *cmdline) { 1244135446Strhodes char *word, *local; 1245135446Strhodes long port; 1246135446Strhodes struct in_addr in4; 1247135446Strhodes struct in6_addr in6; 1248135446Strhodes 1249135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1250135446Strhodes if (*word == 0) { 1251135446Strhodes fprintf(stderr, "could not read server name\n"); 1252135446Strhodes return (STATUS_SYNTAX); 1253135446Strhodes } 1254135446Strhodes local = word; 1255135446Strhodes 1256135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1257135446Strhodes if (*word == 0) 1258135446Strhodes port = 0; 1259135446Strhodes else { 1260135446Strhodes char *endp; 1261135446Strhodes port = strtol(word, &endp, 10); 1262135446Strhodes if (*endp != 0) { 1263135446Strhodes fprintf(stderr, "port '%s' is not numeric\n", word); 1264135446Strhodes return (STATUS_SYNTAX); 1265135446Strhodes } else if (port < 1 || port > 65535) { 1266135446Strhodes fprintf(stderr, "port '%s' is out of range " 1267135446Strhodes "(1 to 65535)\n", word); 1268135446Strhodes return (STATUS_SYNTAX); 1269135446Strhodes } 1270135446Strhodes } 1271135446Strhodes 1272135446Strhodes if (localaddr == NULL) { 1273135446Strhodes localaddr = isc_mem_get(mctx, sizeof(isc_sockaddr_t)); 1274135446Strhodes if (localaddr == NULL) 1275135446Strhodes fatal("out of memory"); 1276135446Strhodes } 1277135446Strhodes 1278135446Strhodes if (have_ipv6 && inet_pton(AF_INET6, local, &in6) == 1) 1279135446Strhodes isc_sockaddr_fromin6(localaddr, &in6, (in_port_t)port); 1280135446Strhodes else if (have_ipv4 && inet_pton(AF_INET, local, &in4) == 1) 1281135446Strhodes isc_sockaddr_fromin(localaddr, &in4, (in_port_t)port); 1282135446Strhodes else { 1283135446Strhodes fprintf(stderr, "invalid address %s", local); 1284135446Strhodes return (STATUS_SYNTAX); 1285135446Strhodes } 1286135446Strhodes 1287135446Strhodes return (STATUS_MORE); 1288135446Strhodes} 1289135446Strhodes 1290135446Strhodesstatic isc_uint16_t 1291135446Strhodesevaluate_key(char *cmdline) { 1292135446Strhodes char *namestr; 1293135446Strhodes char *secretstr; 1294135446Strhodes isc_buffer_t b; 1295135446Strhodes isc_result_t result; 1296135446Strhodes dns_fixedname_t fkeyname; 1297135446Strhodes dns_name_t *keyname; 1298135446Strhodes int secretlen; 1299135446Strhodes unsigned char *secret = NULL; 1300135446Strhodes isc_buffer_t secretbuf; 1301170222Sdougb dns_name_t *hmacname = NULL; 1302170222Sdougb isc_uint16_t digestbits = 0; 1303170222Sdougb char *n; 1304135446Strhodes 1305135446Strhodes namestr = nsu_strsep(&cmdline, " \t\r\n"); 1306135446Strhodes if (*namestr == 0) { 1307135446Strhodes fprintf(stderr, "could not read key name\n"); 1308135446Strhodes return (STATUS_SYNTAX); 1309135446Strhodes } 1310135446Strhodes 1311135446Strhodes dns_fixedname_init(&fkeyname); 1312135446Strhodes keyname = dns_fixedname_name(&fkeyname); 1313135446Strhodes 1314170222Sdougb n = strchr(namestr, ':'); 1315170222Sdougb if (n != NULL) { 1316170222Sdougb digestbits = parse_hmac(&hmacname, namestr, n - namestr); 1317170222Sdougb namestr = n + 1; 1318170222Sdougb } else 1319170222Sdougb hmacname = DNS_TSIG_HMACMD5_NAME; 1320170222Sdougb 1321135446Strhodes isc_buffer_init(&b, namestr, strlen(namestr)); 1322135446Strhodes isc_buffer_add(&b, strlen(namestr)); 1323135446Strhodes result = dns_name_fromtext(keyname, &b, dns_rootname, ISC_FALSE, NULL); 1324135446Strhodes if (result != ISC_R_SUCCESS) { 1325135446Strhodes fprintf(stderr, "could not parse key name\n"); 1326135446Strhodes return (STATUS_SYNTAX); 1327135446Strhodes } 1328135446Strhodes 1329135446Strhodes secretstr = nsu_strsep(&cmdline, "\r\n"); 1330135446Strhodes if (*secretstr == 0) { 1331135446Strhodes fprintf(stderr, "could not read key secret\n"); 1332135446Strhodes return (STATUS_SYNTAX); 1333135446Strhodes } 1334135446Strhodes secretlen = strlen(secretstr) * 3 / 4; 1335135446Strhodes secret = isc_mem_allocate(mctx, secretlen); 1336135446Strhodes if (secret == NULL) 1337135446Strhodes fatal("out of memory"); 1338186462Sdougb 1339135446Strhodes isc_buffer_init(&secretbuf, secret, secretlen); 1340135446Strhodes result = isc_base64_decodestring(secretstr, &secretbuf); 1341135446Strhodes if (result != ISC_R_SUCCESS) { 1342135446Strhodes fprintf(stderr, "could not create key from %s: %s\n", 1343135446Strhodes secretstr, isc_result_totext(result)); 1344135446Strhodes isc_mem_free(mctx, secret); 1345135446Strhodes return (STATUS_SYNTAX); 1346135446Strhodes } 1347135446Strhodes secretlen = isc_buffer_usedlength(&secretbuf); 1348135446Strhodes 1349135446Strhodes if (tsigkey != NULL) 1350135446Strhodes dns_tsigkey_detach(&tsigkey); 1351170222Sdougb result = dns_tsigkey_create(keyname, hmacname, secret, secretlen, 1352170222Sdougb ISC_TRUE, NULL, 0, 0, mctx, NULL, 1353170222Sdougb &tsigkey); 1354135446Strhodes isc_mem_free(mctx, secret); 1355135446Strhodes if (result != ISC_R_SUCCESS) { 1356135446Strhodes fprintf(stderr, "could not create key from %s %s: %s\n", 1357135446Strhodes namestr, secretstr, dns_result_totext(result)); 1358135446Strhodes return (STATUS_SYNTAX); 1359135446Strhodes } 1360170222Sdougb dst_key_setbits(tsigkey->key, digestbits); 1361135446Strhodes return (STATUS_MORE); 1362135446Strhodes} 1363135446Strhodes 1364135446Strhodesstatic isc_uint16_t 1365135446Strhodesevaluate_zone(char *cmdline) { 1366135446Strhodes char *word; 1367135446Strhodes isc_buffer_t b; 1368135446Strhodes isc_result_t result; 1369135446Strhodes 1370135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1371135446Strhodes if (*word == 0) { 1372135446Strhodes fprintf(stderr, "could not read zone name\n"); 1373135446Strhodes return (STATUS_SYNTAX); 1374135446Strhodes } 1375135446Strhodes 1376135446Strhodes dns_fixedname_init(&fuserzone); 1377135446Strhodes userzone = dns_fixedname_name(&fuserzone); 1378135446Strhodes isc_buffer_init(&b, word, strlen(word)); 1379135446Strhodes isc_buffer_add(&b, strlen(word)); 1380135446Strhodes result = dns_name_fromtext(userzone, &b, dns_rootname, ISC_FALSE, 1381135446Strhodes NULL); 1382135446Strhodes if (result != ISC_R_SUCCESS) { 1383135446Strhodes userzone = NULL; /* Lest it point to an invalid name */ 1384135446Strhodes fprintf(stderr, "could not parse zone name\n"); 1385135446Strhodes return (STATUS_SYNTAX); 1386135446Strhodes } 1387135446Strhodes 1388135446Strhodes return (STATUS_MORE); 1389135446Strhodes} 1390135446Strhodes 1391135446Strhodesstatic isc_uint16_t 1392193149Sdougbevaluate_ttl(char *cmdline) { 1393193149Sdougb char *word; 1394193149Sdougb isc_result_t result; 1395193149Sdougb isc_uint32_t ttl; 1396193149Sdougb 1397193149Sdougb word = nsu_strsep(&cmdline, " \t\r\n"); 1398193149Sdougb if (*word == 0) { 1399193149Sdougb fprintf(stderr, "could not ttl\n"); 1400193149Sdougb return (STATUS_SYNTAX); 1401193149Sdougb } 1402193149Sdougb 1403193149Sdougb if (!strcasecmp(word, "none")) { 1404193149Sdougb default_ttl = 0; 1405193149Sdougb default_ttl_set = ISC_FALSE; 1406193149Sdougb return (STATUS_MORE); 1407193149Sdougb } 1408193149Sdougb 1409193149Sdougb result = isc_parse_uint32(&ttl, word, 10); 1410193149Sdougb if (result != ISC_R_SUCCESS) 1411193149Sdougb return (STATUS_SYNTAX); 1412193149Sdougb 1413193149Sdougb if (ttl > TTL_MAX) { 1414193149Sdougb fprintf(stderr, "ttl '%s' is out of range (0 to %u)\n", 1415193149Sdougb word, TTL_MAX); 1416193149Sdougb return (STATUS_SYNTAX); 1417193149Sdougb } 1418193149Sdougb default_ttl = ttl; 1419193149Sdougb default_ttl_set = ISC_TRUE; 1420193149Sdougb 1421193149Sdougb return (STATUS_MORE); 1422193149Sdougb} 1423193149Sdougb 1424193149Sdougbstatic isc_uint16_t 1425135446Strhodesevaluate_class(char *cmdline) { 1426135446Strhodes char *word; 1427135446Strhodes isc_textregion_t r; 1428135446Strhodes isc_result_t result; 1429135446Strhodes dns_rdataclass_t rdclass; 1430135446Strhodes 1431135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1432135446Strhodes if (*word == 0) { 1433135446Strhodes fprintf(stderr, "could not read class name\n"); 1434135446Strhodes return (STATUS_SYNTAX); 1435135446Strhodes } 1436135446Strhodes 1437135446Strhodes r.base = word; 1438186462Sdougb r.length = strlen(word); 1439186462Sdougb result = dns_rdataclass_fromtext(&rdclass, &r); 1440135446Strhodes if (result != ISC_R_SUCCESS) { 1441135446Strhodes fprintf(stderr, "could not parse class name: %s\n", word); 1442135446Strhodes return (STATUS_SYNTAX); 1443135446Strhodes } 1444135446Strhodes switch (rdclass) { 1445135446Strhodes case dns_rdataclass_none: 1446135446Strhodes case dns_rdataclass_any: 1447135446Strhodes case dns_rdataclass_reserved0: 1448135446Strhodes fprintf(stderr, "bad default class: %s\n", word); 1449135446Strhodes return (STATUS_SYNTAX); 1450135446Strhodes default: 1451135446Strhodes defaultclass = rdclass; 1452135446Strhodes } 1453135446Strhodes 1454135446Strhodes return (STATUS_MORE); 1455135446Strhodes} 1456135446Strhodes 1457135446Strhodesstatic isc_uint16_t 1458135446Strhodesupdate_addordelete(char *cmdline, isc_boolean_t isdelete) { 1459135446Strhodes isc_result_t result; 1460135446Strhodes dns_name_t *name = NULL; 1461135446Strhodes isc_uint32_t ttl; 1462135446Strhodes char *word; 1463135446Strhodes dns_rdataclass_t rdataclass; 1464135446Strhodes dns_rdatatype_t rdatatype; 1465135446Strhodes dns_rdata_t *rdata = NULL; 1466135446Strhodes dns_rdatalist_t *rdatalist = NULL; 1467135446Strhodes dns_rdataset_t *rdataset = NULL; 1468135446Strhodes isc_textregion_t region; 1469135446Strhodes isc_uint16_t retval; 1470135446Strhodes 1471135446Strhodes ddebug("update_addordelete()"); 1472135446Strhodes 1473135446Strhodes /* 1474135446Strhodes * Read the owner name. 1475135446Strhodes */ 1476135446Strhodes retval = parse_name(&cmdline, updatemsg, &name); 1477135446Strhodes if (retval != STATUS_MORE) 1478135446Strhodes return (retval); 1479135446Strhodes 1480135446Strhodes result = dns_message_gettemprdata(updatemsg, &rdata); 1481135446Strhodes check_result(result, "dns_message_gettemprdata"); 1482135446Strhodes 1483193149Sdougb dns_rdata_init(rdata); 1484135446Strhodes 1485135446Strhodes /* 1486135446Strhodes * If this is an add, read the TTL and verify that it's in range. 1487135446Strhodes * If it's a delete, ignore a TTL if present (for compatibility). 1488135446Strhodes */ 1489135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1490135446Strhodes if (*word == 0) { 1491135446Strhodes if (!isdelete) { 1492135446Strhodes fprintf(stderr, "could not read owner ttl\n"); 1493135446Strhodes goto failure; 1494135446Strhodes } 1495135446Strhodes else { 1496135446Strhodes ttl = 0; 1497135446Strhodes rdataclass = dns_rdataclass_any; 1498135446Strhodes rdatatype = dns_rdatatype_any; 1499135446Strhodes rdata->flags = DNS_RDATA_UPDATE; 1500135446Strhodes goto doneparsing; 1501135446Strhodes } 1502135446Strhodes } 1503135446Strhodes result = isc_parse_uint32(&ttl, word, 10); 1504135446Strhodes if (result != ISC_R_SUCCESS) { 1505135446Strhodes if (isdelete) { 1506135446Strhodes ttl = 0; 1507135446Strhodes goto parseclass; 1508193149Sdougb } else if (default_ttl_set) { 1509193149Sdougb ttl = default_ttl; 1510193149Sdougb goto parseclass; 1511135446Strhodes } else { 1512135446Strhodes fprintf(stderr, "ttl '%s': %s\n", word, 1513135446Strhodes isc_result_totext(result)); 1514135446Strhodes goto failure; 1515135446Strhodes } 1516135446Strhodes } 1517135446Strhodes 1518135446Strhodes if (isdelete) 1519135446Strhodes ttl = 0; 1520135446Strhodes else if (ttl > TTL_MAX) { 1521135446Strhodes fprintf(stderr, "ttl '%s' is out of range (0 to %u)\n", 1522135446Strhodes word, TTL_MAX); 1523135446Strhodes goto failure; 1524135446Strhodes } 1525135446Strhodes 1526135446Strhodes /* 1527135446Strhodes * Read the class or type. 1528135446Strhodes */ 1529135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1530135446Strhodes parseclass: 1531135446Strhodes if (*word == 0) { 1532135446Strhodes if (isdelete) { 1533135446Strhodes rdataclass = dns_rdataclass_any; 1534135446Strhodes rdatatype = dns_rdatatype_any; 1535135446Strhodes rdata->flags = DNS_RDATA_UPDATE; 1536135446Strhodes goto doneparsing; 1537135446Strhodes } else { 1538135446Strhodes fprintf(stderr, "could not read class or type\n"); 1539135446Strhodes goto failure; 1540135446Strhodes } 1541135446Strhodes } 1542135446Strhodes region.base = word; 1543135446Strhodes region.length = strlen(word); 1544193149Sdougb rdataclass = dns_rdataclass_any; 1545135446Strhodes result = dns_rdataclass_fromtext(&rdataclass, ®ion); 1546193149Sdougb if (result == ISC_R_SUCCESS && rdataclass != dns_rdataclass_any) { 1547135446Strhodes if (!setzoneclass(rdataclass)) { 1548135446Strhodes fprintf(stderr, "class mismatch: %s\n", word); 1549135446Strhodes goto failure; 1550135446Strhodes } 1551135446Strhodes /* 1552135446Strhodes * Now read the type. 1553135446Strhodes */ 1554135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1555135446Strhodes if (*word == 0) { 1556135446Strhodes if (isdelete) { 1557135446Strhodes rdataclass = dns_rdataclass_any; 1558135446Strhodes rdatatype = dns_rdatatype_any; 1559135446Strhodes rdata->flags = DNS_RDATA_UPDATE; 1560135446Strhodes goto doneparsing; 1561135446Strhodes } else { 1562135446Strhodes fprintf(stderr, "could not read type\n"); 1563135446Strhodes goto failure; 1564135446Strhodes } 1565135446Strhodes } 1566135446Strhodes region.base = word; 1567135446Strhodes region.length = strlen(word); 1568135446Strhodes result = dns_rdatatype_fromtext(&rdatatype, ®ion); 1569135446Strhodes if (result != ISC_R_SUCCESS) { 1570135446Strhodes fprintf(stderr, "'%s' is not a valid type: %s\n", 1571135446Strhodes word, isc_result_totext(result)); 1572135446Strhodes goto failure; 1573135446Strhodes } 1574135446Strhodes } else { 1575135446Strhodes rdataclass = getzoneclass(); 1576135446Strhodes result = dns_rdatatype_fromtext(&rdatatype, ®ion); 1577135446Strhodes if (result != ISC_R_SUCCESS) { 1578135446Strhodes fprintf(stderr, "'%s' is not a valid class or type: " 1579135446Strhodes "%s\n", word, isc_result_totext(result)); 1580135446Strhodes goto failure; 1581135446Strhodes } 1582135446Strhodes } 1583135446Strhodes 1584135446Strhodes retval = parse_rdata(&cmdline, rdataclass, rdatatype, updatemsg, 1585135446Strhodes rdata); 1586135446Strhodes if (retval != STATUS_MORE) 1587135446Strhodes goto failure; 1588135446Strhodes 1589135446Strhodes if (isdelete) { 1590135446Strhodes if ((rdata->flags & DNS_RDATA_UPDATE) != 0) 1591135446Strhodes rdataclass = dns_rdataclass_any; 1592135446Strhodes else 1593135446Strhodes rdataclass = dns_rdataclass_none; 1594135446Strhodes } else { 1595135446Strhodes if ((rdata->flags & DNS_RDATA_UPDATE) != 0) { 1596135446Strhodes fprintf(stderr, "could not read rdata\n"); 1597135446Strhodes goto failure; 1598135446Strhodes } 1599135446Strhodes } 1600135446Strhodes 1601135446Strhodes doneparsing: 1602135446Strhodes 1603135446Strhodes result = dns_message_gettemprdatalist(updatemsg, &rdatalist); 1604135446Strhodes check_result(result, "dns_message_gettemprdatalist"); 1605135446Strhodes result = dns_message_gettemprdataset(updatemsg, &rdataset); 1606135446Strhodes check_result(result, "dns_message_gettemprdataset"); 1607135446Strhodes dns_rdatalist_init(rdatalist); 1608135446Strhodes rdatalist->type = rdatatype; 1609135446Strhodes rdatalist->rdclass = rdataclass; 1610135446Strhodes rdatalist->covers = rdatatype; 1611135446Strhodes rdatalist->ttl = (dns_ttl_t)ttl; 1612135446Strhodes ISC_LIST_INIT(rdatalist->rdata); 1613135446Strhodes ISC_LIST_APPEND(rdatalist->rdata, rdata, link); 1614135446Strhodes dns_rdataset_init(rdataset); 1615135446Strhodes dns_rdatalist_tordataset(rdatalist, rdataset); 1616135446Strhodes ISC_LIST_INIT(name->list); 1617135446Strhodes ISC_LIST_APPEND(name->list, rdataset, link); 1618135446Strhodes dns_message_addname(updatemsg, name, DNS_SECTION_UPDATE); 1619135446Strhodes return (STATUS_MORE); 1620135446Strhodes 1621135446Strhodes failure: 1622135446Strhodes if (name != NULL) 1623135446Strhodes dns_message_puttempname(updatemsg, &name); 1624186462Sdougb dns_message_puttemprdata(updatemsg, &rdata); 1625135446Strhodes return (STATUS_SYNTAX); 1626135446Strhodes} 1627135446Strhodes 1628135446Strhodesstatic isc_uint16_t 1629135446Strhodesevaluate_update(char *cmdline) { 1630135446Strhodes char *word; 1631135446Strhodes isc_boolean_t isdelete; 1632135446Strhodes 1633135446Strhodes ddebug("evaluate_update()"); 1634135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1635135446Strhodes if (*word == 0) { 1636135446Strhodes fprintf(stderr, "could not read operation code\n"); 1637135446Strhodes return (STATUS_SYNTAX); 1638135446Strhodes } 1639135446Strhodes if (strcasecmp(word, "delete") == 0) 1640135446Strhodes isdelete = ISC_TRUE; 1641135446Strhodes else if (strcasecmp(word, "add") == 0) 1642135446Strhodes isdelete = ISC_FALSE; 1643135446Strhodes else { 1644135446Strhodes fprintf(stderr, "incorrect operation code: %s\n", word); 1645135446Strhodes return (STATUS_SYNTAX); 1646135446Strhodes } 1647135446Strhodes return (update_addordelete(cmdline, isdelete)); 1648135446Strhodes} 1649135446Strhodes 1650135446Strhodesstatic void 1651170222Sdougbsetzone(dns_name_t *zonename) { 1652170222Sdougb isc_result_t result; 1653170222Sdougb dns_name_t *name = NULL; 1654170222Sdougb dns_rdataset_t *rdataset = NULL; 1655170222Sdougb 1656170222Sdougb result = dns_message_firstname(updatemsg, DNS_SECTION_ZONE); 1657170222Sdougb if (result == ISC_R_SUCCESS) { 1658170222Sdougb dns_message_currentname(updatemsg, DNS_SECTION_ZONE, &name); 1659170222Sdougb dns_message_removename(updatemsg, name, DNS_SECTION_ZONE); 1660170222Sdougb for (rdataset = ISC_LIST_HEAD(name->list); 1661170222Sdougb rdataset != NULL; 1662170222Sdougb rdataset = ISC_LIST_HEAD(name->list)) { 1663170222Sdougb ISC_LIST_UNLINK(name->list, rdataset, link); 1664170222Sdougb dns_rdataset_disassociate(rdataset); 1665170222Sdougb dns_message_puttemprdataset(updatemsg, &rdataset); 1666170222Sdougb } 1667170222Sdougb dns_message_puttempname(updatemsg, &name); 1668170222Sdougb } 1669170222Sdougb 1670170222Sdougb if (zonename != NULL) { 1671170222Sdougb result = dns_message_gettempname(updatemsg, &name); 1672170222Sdougb check_result(result, "dns_message_gettempname"); 1673170222Sdougb dns_name_init(name, NULL); 1674170222Sdougb dns_name_clone(zonename, name); 1675170222Sdougb result = dns_message_gettemprdataset(updatemsg, &rdataset); 1676170222Sdougb check_result(result, "dns_message_gettemprdataset"); 1677170222Sdougb dns_rdataset_makequestion(rdataset, getzoneclass(), 1678170222Sdougb dns_rdatatype_soa); 1679170222Sdougb ISC_LIST_INIT(name->list); 1680170222Sdougb ISC_LIST_APPEND(name->list, rdataset, link); 1681170222Sdougb dns_message_addname(updatemsg, name, DNS_SECTION_ZONE); 1682170222Sdougb } 1683170222Sdougb} 1684170222Sdougb 1685170222Sdougbstatic void 1686193149Sdougbshow_message(FILE *stream, dns_message_t *msg, const char *description) { 1687135446Strhodes isc_result_t result; 1688135446Strhodes isc_buffer_t *buf = NULL; 1689135446Strhodes int bufsz; 1690135446Strhodes 1691135446Strhodes ddebug("show_message()"); 1692170222Sdougb 1693170222Sdougb setzone(userzone); 1694170222Sdougb 1695135446Strhodes bufsz = INITTEXT; 1696186462Sdougb do { 1697135446Strhodes if (bufsz > MAXTEXT) { 1698135446Strhodes fprintf(stderr, "could not allocate large enough " 1699135446Strhodes "buffer to display message\n"); 1700135446Strhodes exit(1); 1701135446Strhodes } 1702135446Strhodes if (buf != NULL) 1703135446Strhodes isc_buffer_free(&buf); 1704135446Strhodes result = isc_buffer_allocate(mctx, &buf, bufsz); 1705135446Strhodes check_result(result, "isc_buffer_allocate"); 1706135446Strhodes result = dns_message_totext(msg, style, 0, buf); 1707135446Strhodes bufsz *= 2; 1708135446Strhodes } while (result == ISC_R_NOSPACE); 1709135446Strhodes if (result != ISC_R_SUCCESS) { 1710135446Strhodes fprintf(stderr, "could not convert message to text format.\n"); 1711135446Strhodes isc_buffer_free(&buf); 1712135446Strhodes return; 1713135446Strhodes } 1714193149Sdougb fprintf(stream, "%s\n%.*s", description, 1715193149Sdougb (int)isc_buffer_usedlength(buf), (char*)isc_buffer_base(buf)); 1716135446Strhodes isc_buffer_free(&buf); 1717135446Strhodes} 1718135446Strhodes 1719135446Strhodes 1720135446Strhodesstatic isc_uint16_t 1721135446Strhodesget_next_command(void) { 1722135446Strhodes char cmdlinebuf[MAXCMD]; 1723135446Strhodes char *cmdline; 1724135446Strhodes char *word; 1725135446Strhodes 1726135446Strhodes ddebug("get_next_command()"); 1727165071Sdougb if (interactive) { 1728135446Strhodes fprintf(stdout, "> "); 1729165071Sdougb fflush(stdout); 1730165071Sdougb } 1731135446Strhodes isc_app_block(); 1732135446Strhodes cmdline = fgets(cmdlinebuf, MAXCMD, input); 1733135446Strhodes isc_app_unblock(); 1734135446Strhodes if (cmdline == NULL) 1735135446Strhodes return (STATUS_QUIT); 1736135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1737135446Strhodes 1738135446Strhodes if (feof(input)) 1739135446Strhodes return (STATUS_QUIT); 1740135446Strhodes if (*word == 0) 1741135446Strhodes return (STATUS_SEND); 1742135446Strhodes if (word[0] == ';') 1743135446Strhodes return (STATUS_MORE); 1744135446Strhodes if (strcasecmp(word, "quit") == 0) 1745135446Strhodes return (STATUS_QUIT); 1746135446Strhodes if (strcasecmp(word, "prereq") == 0) 1747135446Strhodes return (evaluate_prereq(cmdline)); 1748135446Strhodes if (strcasecmp(word, "update") == 0) 1749135446Strhodes return (evaluate_update(cmdline)); 1750135446Strhodes if (strcasecmp(word, "server") == 0) 1751135446Strhodes return (evaluate_server(cmdline)); 1752135446Strhodes if (strcasecmp(word, "local") == 0) 1753135446Strhodes return (evaluate_local(cmdline)); 1754135446Strhodes if (strcasecmp(word, "zone") == 0) 1755135446Strhodes return (evaluate_zone(cmdline)); 1756135446Strhodes if (strcasecmp(word, "class") == 0) 1757135446Strhodes return (evaluate_class(cmdline)); 1758135446Strhodes if (strcasecmp(word, "send") == 0) 1759135446Strhodes return (STATUS_SEND); 1760193149Sdougb if (strcasecmp(word, "debug") == 0) { 1761193149Sdougb if (debugging) 1762193149Sdougb ddebugging = ISC_TRUE; 1763193149Sdougb else 1764193149Sdougb debugging = ISC_TRUE; 1765193149Sdougb return (STATUS_MORE); 1766193149Sdougb } 1767193149Sdougb if (strcasecmp(word, "ttl") == 0) 1768193149Sdougb return (evaluate_ttl(cmdline)); 1769135446Strhodes if (strcasecmp(word, "show") == 0) { 1770193149Sdougb show_message(stdout, updatemsg, "Outgoing update query:"); 1771135446Strhodes return (STATUS_MORE); 1772135446Strhodes } 1773135446Strhodes if (strcasecmp(word, "answer") == 0) { 1774135446Strhodes if (answer != NULL) 1775193149Sdougb show_message(stdout, answer, "Answer:"); 1776135446Strhodes return (STATUS_MORE); 1777135446Strhodes } 1778193149Sdougb if (strcasecmp(word, "key") == 0) { 1779193149Sdougb usegsstsig = ISC_FALSE; 1780135446Strhodes return (evaluate_key(cmdline)); 1781193149Sdougb } 1782193149Sdougb if (strcasecmp(word, "gsstsig") == 0) { 1783193149Sdougb#ifdef GSSAPI 1784193149Sdougb usegsstsig = ISC_TRUE; 1785193149Sdougb use_win2k_gsstsig = ISC_FALSE; 1786193149Sdougb#else 1787193149Sdougb fprintf(stderr, "gsstsig not supported\n"); 1788193149Sdougb#endif 1789193149Sdougb return (STATUS_MORE); 1790193149Sdougb } 1791193149Sdougb if (strcasecmp(word, "oldgsstsig") == 0) { 1792193149Sdougb#ifdef GSSAPI 1793193149Sdougb usegsstsig = ISC_TRUE; 1794193149Sdougb use_win2k_gsstsig = ISC_TRUE; 1795193149Sdougb#else 1796193149Sdougb fprintf(stderr, "gsstsig not supported\n"); 1797193149Sdougb#endif 1798193149Sdougb return (STATUS_MORE); 1799193149Sdougb } 1800193149Sdougb if (strcasecmp(word, "help") == 0) { 1801193149Sdougb fprintf(stdout, 1802193149Sdougb"local address [port] (set local resolver)\n" 1803193149Sdougb"server address [port] (set master server for zone)\n" 1804193149Sdougb"send (send the update request)\n" 1805193149Sdougb"show (show the update request)\n" 1806193149Sdougb"answer (show the answer to the last request)\n" 1807193149Sdougb"quit (quit, any pending update is not sent\n" 1808193149Sdougb"help (display this message_\n" 1809193149Sdougb"key [hmac:]keyname secret (use TSIG to sign the request)\n" 1810193149Sdougb"gsstsig (use GSS_TSIG to sign the request)\n" 1811193149Sdougb"oldgsstsig (use Microsoft's GSS_TSIG to sign the request)\n" 1812193149Sdougb"zone name (set the zone to be updated)\n" 1813193149Sdougb"class CLASS (set the zone's DNS class, e.g. IN (default), CH)\n" 1814193149Sdougb"prereq nxdomain name (does this name not exist)\n" 1815193149Sdougb"prereq yxdomain name (does this name exist)\n" 1816193149Sdougb"prereq nxrrset .... (does this RRset exist)\n" 1817193149Sdougb"prereq yxrrset .... (does this RRset not exist)\n" 1818193149Sdougb"update add .... (add the given record to the zone)\n" 1819193149Sdougb"update delete .... (remove the given record(s) from the zone)\n"); 1820193149Sdougb return (STATUS_MORE); 1821193149Sdougb } 1822135446Strhodes fprintf(stderr, "incorrect section name: %s\n", word); 1823135446Strhodes return (STATUS_SYNTAX); 1824135446Strhodes} 1825135446Strhodes 1826135446Strhodesstatic isc_boolean_t 1827135446Strhodesuser_interaction(void) { 1828135446Strhodes isc_uint16_t result = STATUS_MORE; 1829135446Strhodes 1830135446Strhodes ddebug("user_interaction()"); 1831174187Sdougb while ((result == STATUS_MORE) || (result == STATUS_SYNTAX)) { 1832135446Strhodes result = get_next_command(); 1833174187Sdougb if (!interactive && result == STATUS_SYNTAX) 1834174187Sdougb fatal("syntax error"); 1835174187Sdougb } 1836135446Strhodes if (result == STATUS_SEND) 1837135446Strhodes return (ISC_TRUE); 1838135446Strhodes return (ISC_FALSE); 1839135446Strhodes 1840135446Strhodes} 1841135446Strhodes 1842135446Strhodesstatic void 1843135446Strhodesdone_update(void) { 1844135446Strhodes isc_event_t *event = global_event; 1845135446Strhodes ddebug("done_update()"); 1846135446Strhodes isc_task_send(global_task, &event); 1847135446Strhodes} 1848135446Strhodes 1849135446Strhodesstatic void 1850135446Strhodescheck_tsig_error(dns_rdataset_t *rdataset, isc_buffer_t *b) { 1851135446Strhodes isc_result_t result; 1852135446Strhodes dns_rdata_t rdata = DNS_RDATA_INIT; 1853135446Strhodes dns_rdata_any_tsig_t tsig; 1854135446Strhodes 1855135446Strhodes result = dns_rdataset_first(rdataset); 1856135446Strhodes check_result(result, "dns_rdataset_first"); 1857135446Strhodes dns_rdataset_current(rdataset, &rdata); 1858135446Strhodes result = dns_rdata_tostruct(&rdata, &tsig, NULL); 1859135446Strhodes check_result(result, "dns_rdata_tostruct"); 1860135446Strhodes if (tsig.error != 0) { 1861135446Strhodes if (isc_buffer_remaininglength(b) < 1) 1862135446Strhodes check_result(ISC_R_NOSPACE, "isc_buffer_remaininglength"); 1863135446Strhodes isc__buffer_putstr(b, "(" /*)*/); 1864135446Strhodes result = dns_tsigrcode_totext(tsig.error, b); 1865135446Strhodes check_result(result, "dns_tsigrcode_totext"); 1866135446Strhodes if (isc_buffer_remaininglength(b) < 1) 1867135446Strhodes check_result(ISC_R_NOSPACE, "isc_buffer_remaininglength"); 1868135446Strhodes isc__buffer_putstr(b, /*(*/ ")"); 1869135446Strhodes } 1870135446Strhodes} 1871135446Strhodes 1872135446Strhodesstatic void 1873135446Strhodesupdate_completed(isc_task_t *task, isc_event_t *event) { 1874135446Strhodes dns_requestevent_t *reqev = NULL; 1875135446Strhodes isc_result_t result; 1876135446Strhodes dns_request_t *request; 1877135446Strhodes 1878135446Strhodes UNUSED(task); 1879135446Strhodes 1880135446Strhodes ddebug("update_completed()"); 1881135446Strhodes 1882135446Strhodes requests--; 1883135446Strhodes 1884135446Strhodes REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE); 1885135446Strhodes reqev = (dns_requestevent_t *)event; 1886135446Strhodes request = reqev->request; 1887135446Strhodes 1888135446Strhodes if (shuttingdown) { 1889135446Strhodes dns_request_destroy(&request); 1890135446Strhodes isc_event_free(&event); 1891135446Strhodes maybeshutdown(); 1892135446Strhodes return; 1893135446Strhodes } 1894135446Strhodes 1895135446Strhodes if (reqev->result != ISC_R_SUCCESS) { 1896135446Strhodes fprintf(stderr, "; Communication with server failed: %s\n", 1897135446Strhodes isc_result_totext(reqev->result)); 1898135446Strhodes seenerror = ISC_TRUE; 1899135446Strhodes goto done; 1900135446Strhodes } 1901135446Strhodes 1902135446Strhodes result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &answer); 1903135446Strhodes check_result(result, "dns_message_create"); 1904135446Strhodes result = dns_request_getresponse(request, answer, 1905135446Strhodes DNS_MESSAGEPARSE_PRESERVEORDER); 1906135446Strhodes switch (result) { 1907135446Strhodes case ISC_R_SUCCESS: 1908193149Sdougb if (answer->verify_attempted) 1909193149Sdougb ddebug("tsig verification successful"); 1910135446Strhodes break; 1911135446Strhodes case DNS_R_CLOCKSKEW: 1912135446Strhodes case DNS_R_EXPECTEDTSIG: 1913135446Strhodes case DNS_R_TSIGERRORSET: 1914135446Strhodes case DNS_R_TSIGVERIFYFAILURE: 1915135446Strhodes case DNS_R_UNEXPECTEDTSIG: 1916193149Sdougb case ISC_R_FAILURE: 1917193149Sdougb#if 0 1918193149Sdougb if (usegsstsig && answer->rcode == dns_rcode_noerror) { 1919193149Sdougb /* 1920193149Sdougb * For MS DNS that violates RFC 2845, section 4.2 1921193149Sdougb */ 1922193149Sdougb break; 1923193149Sdougb } 1924193149Sdougb#endif 1925135446Strhodes fprintf(stderr, "; TSIG error with server: %s\n", 1926135446Strhodes isc_result_totext(result)); 1927135446Strhodes seenerror = ISC_TRUE; 1928135446Strhodes break; 1929135446Strhodes default: 1930135446Strhodes check_result(result, "dns_request_getresponse"); 1931135446Strhodes } 1932135446Strhodes 1933135446Strhodes if (answer->rcode != dns_rcode_noerror) { 1934135446Strhodes seenerror = ISC_TRUE; 1935135446Strhodes if (!debugging) { 1936135446Strhodes char buf[64]; 1937135446Strhodes isc_buffer_t b; 1938135446Strhodes dns_rdataset_t *rds; 1939186462Sdougb 1940135446Strhodes isc_buffer_init(&b, buf, sizeof(buf) - 1); 1941135446Strhodes result = dns_rcode_totext(answer->rcode, &b); 1942135446Strhodes check_result(result, "dns_rcode_totext"); 1943135446Strhodes rds = dns_message_gettsig(answer, NULL); 1944135446Strhodes if (rds != NULL) 1945135446Strhodes check_tsig_error(rds, &b); 1946135446Strhodes fprintf(stderr, "update failed: %.*s\n", 1947135446Strhodes (int)isc_buffer_usedlength(&b), buf); 1948135446Strhodes } 1949135446Strhodes } 1950193149Sdougb if (debugging) 1951193149Sdougb show_message(stderr, answer, "\nReply from update query:"); 1952135446Strhodes 1953135446Strhodes done: 1954135446Strhodes dns_request_destroy(&request); 1955193149Sdougb if (usegsstsig) { 1956193149Sdougb dns_name_free(&tmpzonename, mctx); 1957193149Sdougb dns_name_free(&restart_master, mctx); 1958193149Sdougb } 1959135446Strhodes isc_event_free(&event); 1960135446Strhodes done_update(); 1961135446Strhodes} 1962135446Strhodes 1963135446Strhodesstatic void 1964135446Strhodessend_update(dns_name_t *zonename, isc_sockaddr_t *master, 1965135446Strhodes isc_sockaddr_t *srcaddr) 1966135446Strhodes{ 1967135446Strhodes isc_result_t result; 1968135446Strhodes dns_request_t *request = NULL; 1969135446Strhodes unsigned int options = 0; 1970135446Strhodes 1971135446Strhodes ddebug("send_update()"); 1972135446Strhodes 1973170222Sdougb setzone(zonename); 1974135446Strhodes 1975135446Strhodes if (usevc) 1976135446Strhodes options |= DNS_REQUESTOPT_TCP; 1977135446Strhodes if (tsigkey == NULL && sig0key != NULL) { 1978135446Strhodes result = dns_message_setsig0key(updatemsg, sig0key); 1979135446Strhodes check_result(result, "dns_message_setsig0key"); 1980135446Strhodes } 1981135446Strhodes if (debugging) { 1982135446Strhodes char addrbuf[ISC_SOCKADDR_FORMATSIZE]; 1983135446Strhodes 1984135446Strhodes isc_sockaddr_format(master, addrbuf, sizeof(addrbuf)); 1985135446Strhodes fprintf(stderr, "Sending update to %s\n", addrbuf); 1986135446Strhodes } 1987193149Sdougb 1988135446Strhodes result = dns_request_createvia3(requestmgr, updatemsg, srcaddr, 1989135446Strhodes master, options, tsigkey, timeout, 1990135446Strhodes udp_timeout, udp_retries, global_task, 1991135446Strhodes update_completed, NULL, &request); 1992135446Strhodes check_result(result, "dns_request_createvia3"); 1993135446Strhodes 1994135446Strhodes if (debugging) 1995193149Sdougb show_message(stdout, updatemsg, "Outgoing update query:"); 1996135446Strhodes 1997135446Strhodes requests++; 1998135446Strhodes} 1999135446Strhodes 2000135446Strhodesstatic void 2001135446Strhodesrecvsoa(isc_task_t *task, isc_event_t *event) { 2002135446Strhodes dns_requestevent_t *reqev = NULL; 2003135446Strhodes dns_request_t *request = NULL; 2004135446Strhodes isc_result_t result, eresult; 2005135446Strhodes dns_message_t *rcvmsg = NULL; 2006135446Strhodes dns_section_t section; 2007135446Strhodes dns_name_t *name = NULL; 2008135446Strhodes dns_rdataset_t *soaset = NULL; 2009135446Strhodes dns_rdata_soa_t soa; 2010135446Strhodes dns_rdata_t soarr = DNS_RDATA_INIT; 2011135446Strhodes int pass = 0; 2012135446Strhodes dns_name_t master; 2013135446Strhodes nsu_requestinfo_t *reqinfo; 2014135446Strhodes dns_message_t *soaquery = NULL; 2015135446Strhodes isc_sockaddr_t *addr; 2016135446Strhodes isc_boolean_t seencname = ISC_FALSE; 2017143731Sdougb dns_name_t tname; 2018143731Sdougb unsigned int nlabels; 2019135446Strhodes 2020135446Strhodes UNUSED(task); 2021135446Strhodes 2022135446Strhodes ddebug("recvsoa()"); 2023135446Strhodes 2024135446Strhodes requests--; 2025186462Sdougb 2026135446Strhodes REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE); 2027135446Strhodes reqev = (dns_requestevent_t *)event; 2028135446Strhodes request = reqev->request; 2029135446Strhodes eresult = reqev->result; 2030135446Strhodes reqinfo = reqev->ev_arg; 2031135446Strhodes soaquery = reqinfo->msg; 2032135446Strhodes addr = reqinfo->addr; 2033135446Strhodes 2034135446Strhodes if (shuttingdown) { 2035135446Strhodes dns_request_destroy(&request); 2036135446Strhodes dns_message_destroy(&soaquery); 2037135446Strhodes isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t)); 2038135446Strhodes isc_event_free(&event); 2039135446Strhodes maybeshutdown(); 2040135446Strhodes return; 2041135446Strhodes } 2042135446Strhodes 2043135446Strhodes if (eresult != ISC_R_SUCCESS) { 2044135446Strhodes char addrbuf[ISC_SOCKADDR_FORMATSIZE]; 2045135446Strhodes 2046135446Strhodes isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf)); 2047135446Strhodes fprintf(stderr, "; Communication with %s failed: %s\n", 2048193149Sdougb addrbuf, isc_result_totext(eresult)); 2049135446Strhodes if (userserver != NULL) 2050135446Strhodes fatal("could not talk to specified name server"); 2051135446Strhodes else if (++ns_inuse >= lwconf->nsnext) 2052135446Strhodes fatal("could not talk to any default name server"); 2053135446Strhodes ddebug("Destroying request [%p]", request); 2054135446Strhodes dns_request_destroy(&request); 2055135446Strhodes dns_message_renderreset(soaquery); 2056153816Sdougb dns_message_settsigkey(soaquery, NULL); 2057135446Strhodes sendrequest(localaddr, &servers[ns_inuse], soaquery, &request); 2058135446Strhodes isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t)); 2059135446Strhodes isc_event_free(&event); 2060135446Strhodes setzoneclass(dns_rdataclass_none); 2061135446Strhodes return; 2062135446Strhodes } 2063170222Sdougb 2064135446Strhodes isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t)); 2065170222Sdougb reqinfo = NULL; 2066135446Strhodes isc_event_free(&event); 2067135446Strhodes reqev = NULL; 2068135446Strhodes 2069135446Strhodes ddebug("About to create rcvmsg"); 2070135446Strhodes result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &rcvmsg); 2071135446Strhodes check_result(result, "dns_message_create"); 2072135446Strhodes result = dns_request_getresponse(request, rcvmsg, 2073135446Strhodes DNS_MESSAGEPARSE_PRESERVEORDER); 2074135446Strhodes if (result == DNS_R_TSIGERRORSET && userserver != NULL) { 2075135446Strhodes dns_message_destroy(&rcvmsg); 2076135446Strhodes ddebug("Destroying request [%p]", request); 2077135446Strhodes dns_request_destroy(&request); 2078135446Strhodes reqinfo = isc_mem_get(mctx, sizeof(nsu_requestinfo_t)); 2079135446Strhodes if (reqinfo == NULL) 2080135446Strhodes fatal("out of memory"); 2081135446Strhodes reqinfo->msg = soaquery; 2082135446Strhodes reqinfo->addr = addr; 2083135446Strhodes dns_message_renderreset(soaquery); 2084135446Strhodes ddebug("retrying soa request without TSIG"); 2085135446Strhodes result = dns_request_createvia3(requestmgr, soaquery, 2086135446Strhodes localaddr, addr, 0, NULL, 2087135446Strhodes FIND_TIMEOUT * 20, 2088165071Sdougb FIND_TIMEOUT, 3, 2089135446Strhodes global_task, recvsoa, reqinfo, 2090135446Strhodes &request); 2091135446Strhodes check_result(result, "dns_request_createvia"); 2092135446Strhodes requests++; 2093135446Strhodes return; 2094135446Strhodes } 2095135446Strhodes check_result(result, "dns_request_getresponse"); 2096135446Strhodes section = DNS_SECTION_ANSWER; 2097193149Sdougb if (debugging) 2098193149Sdougb show_message(stderr, rcvmsg, "Reply from SOA query:"); 2099135446Strhodes 2100135446Strhodes if (rcvmsg->rcode != dns_rcode_noerror && 2101135446Strhodes rcvmsg->rcode != dns_rcode_nxdomain) 2102135446Strhodes fatal("response to SOA query was unsuccessful"); 2103135446Strhodes 2104170222Sdougb if (userzone != NULL && rcvmsg->rcode == dns_rcode_nxdomain) { 2105170222Sdougb char namebuf[DNS_NAME_FORMATSIZE]; 2106170222Sdougb dns_name_format(userzone, namebuf, sizeof(namebuf)); 2107170222Sdougb error("specified zone '%s' does not exist (NXDOMAIN)", 2108170222Sdougb namebuf); 2109170222Sdougb dns_message_destroy(&rcvmsg); 2110170222Sdougb dns_request_destroy(&request); 2111170222Sdougb dns_message_destroy(&soaquery); 2112170222Sdougb ddebug("Out of recvsoa"); 2113170222Sdougb done_update(); 2114170222Sdougb return; 2115170222Sdougb } 2116170222Sdougb 2117135446Strhodes lookforsoa: 2118135446Strhodes if (pass == 0) 2119135446Strhodes section = DNS_SECTION_ANSWER; 2120135446Strhodes else if (pass == 1) 2121135446Strhodes section = DNS_SECTION_AUTHORITY; 2122186462Sdougb else 2123143731Sdougb goto droplabel; 2124135446Strhodes 2125135446Strhodes result = dns_message_firstname(rcvmsg, section); 2126135446Strhodes if (result != ISC_R_SUCCESS) { 2127135446Strhodes pass++; 2128135446Strhodes goto lookforsoa; 2129135446Strhodes } 2130135446Strhodes while (result == ISC_R_SUCCESS) { 2131135446Strhodes name = NULL; 2132135446Strhodes dns_message_currentname(rcvmsg, section, &name); 2133135446Strhodes soaset = NULL; 2134135446Strhodes result = dns_message_findtype(name, dns_rdatatype_soa, 0, 2135135446Strhodes &soaset); 2136135446Strhodes if (result == ISC_R_SUCCESS) 2137135446Strhodes break; 2138135446Strhodes if (section == DNS_SECTION_ANSWER) { 2139135446Strhodes dns_rdataset_t *tset = NULL; 2140135446Strhodes if (dns_message_findtype(name, dns_rdatatype_cname, 0, 2141193149Sdougb &tset) == ISC_R_SUCCESS || 2142135446Strhodes dns_message_findtype(name, dns_rdatatype_dname, 0, 2143193149Sdougb &tset) == ISC_R_SUCCESS ) { 2144135446Strhodes seencname = ISC_TRUE; 2145135446Strhodes break; 2146135446Strhodes } 2147135446Strhodes } 2148186462Sdougb 2149135446Strhodes result = dns_message_nextname(rcvmsg, section); 2150135446Strhodes } 2151135446Strhodes 2152135446Strhodes if (soaset == NULL && !seencname) { 2153135446Strhodes pass++; 2154135446Strhodes goto lookforsoa; 2155135446Strhodes } 2156135446Strhodes 2157143731Sdougb if (seencname) 2158143731Sdougb goto droplabel; 2159135446Strhodes 2160135446Strhodes if (debugging) { 2161135446Strhodes char namestr[DNS_NAME_FORMATSIZE]; 2162135446Strhodes dns_name_format(name, namestr, sizeof(namestr)); 2163135446Strhodes fprintf(stderr, "Found zone name: %s\n", namestr); 2164135446Strhodes } 2165135446Strhodes 2166135446Strhodes result = dns_rdataset_first(soaset); 2167135446Strhodes check_result(result, "dns_rdataset_first"); 2168135446Strhodes 2169135446Strhodes dns_rdata_init(&soarr); 2170135446Strhodes dns_rdataset_current(soaset, &soarr); 2171135446Strhodes result = dns_rdata_tostruct(&soarr, &soa, NULL); 2172135446Strhodes check_result(result, "dns_rdata_tostruct"); 2173135446Strhodes 2174135446Strhodes dns_name_init(&master, NULL); 2175135446Strhodes dns_name_clone(&soa.origin, &master); 2176135446Strhodes 2177135446Strhodes if (userzone != NULL) 2178135446Strhodes zonename = userzone; 2179135446Strhodes else 2180135446Strhodes zonename = name; 2181135446Strhodes 2182135446Strhodes if (debugging) { 2183135446Strhodes char namestr[DNS_NAME_FORMATSIZE]; 2184135446Strhodes dns_name_format(&master, namestr, sizeof(namestr)); 2185135446Strhodes fprintf(stderr, "The master is: %s\n", namestr); 2186135446Strhodes } 2187135446Strhodes 2188135446Strhodes if (userserver != NULL) 2189135446Strhodes serveraddr = userserver; 2190135446Strhodes else { 2191135446Strhodes char serverstr[DNS_NAME_MAXTEXT+1]; 2192135446Strhodes isc_buffer_t buf; 2193135446Strhodes 2194135446Strhodes isc_buffer_init(&buf, serverstr, sizeof(serverstr)); 2195135446Strhodes result = dns_name_totext(&master, ISC_TRUE, &buf); 2196135446Strhodes check_result(result, "dns_name_totext"); 2197135446Strhodes serverstr[isc_buffer_usedlength(&buf)] = 0; 2198135446Strhodes get_address(serverstr, DNSDEFAULTPORT, &tempaddr); 2199135446Strhodes serveraddr = &tempaddr; 2200135446Strhodes } 2201143731Sdougb dns_rdata_freestruct(&soa); 2202135446Strhodes 2203193149Sdougb#ifdef GSSAPI 2204193149Sdougb if (usegsstsig) { 2205193149Sdougb dns_name_init(&tmpzonename, NULL); 2206193149Sdougb dns_name_dup(zonename, mctx, &tmpzonename); 2207193149Sdougb dns_name_init(&restart_master, NULL); 2208193149Sdougb dns_name_dup(&master, mctx, &restart_master); 2209193149Sdougb start_gssrequest(&master); 2210193149Sdougb } else { 2211193149Sdougb send_update(zonename, serveraddr, localaddr); 2212193149Sdougb setzoneclass(dns_rdataclass_none); 2213193149Sdougb } 2214193149Sdougb#else 2215135446Strhodes send_update(zonename, serveraddr, localaddr); 2216143731Sdougb setzoneclass(dns_rdataclass_none); 2217193149Sdougb#endif 2218135446Strhodes 2219135446Strhodes dns_message_destroy(&soaquery); 2220135446Strhodes dns_request_destroy(&request); 2221135446Strhodes 2222135446Strhodes out: 2223135446Strhodes dns_message_destroy(&rcvmsg); 2224135446Strhodes ddebug("Out of recvsoa"); 2225143731Sdougb return; 2226186462Sdougb 2227143731Sdougb droplabel: 2228143731Sdougb result = dns_message_firstname(soaquery, DNS_SECTION_QUESTION); 2229143731Sdougb INSIST(result == ISC_R_SUCCESS); 2230143731Sdougb name = NULL; 2231143731Sdougb dns_message_currentname(soaquery, DNS_SECTION_QUESTION, &name); 2232143731Sdougb nlabels = dns_name_countlabels(name); 2233143731Sdougb if (nlabels == 1) 2234143731Sdougb fatal("could not find enclosing zone"); 2235143731Sdougb dns_name_init(&tname, NULL); 2236143731Sdougb dns_name_getlabelsequence(name, 1, nlabels - 1, &tname); 2237143731Sdougb dns_name_clone(&tname, name); 2238143731Sdougb dns_request_destroy(&request); 2239143731Sdougb dns_message_renderreset(soaquery); 2240153816Sdougb dns_message_settsigkey(soaquery, NULL); 2241143731Sdougb if (userserver != NULL) 2242143731Sdougb sendrequest(localaddr, userserver, soaquery, &request); 2243143731Sdougb else 2244193149Sdougb sendrequest(localaddr, &servers[ns_inuse], soaquery, &request); 2245143731Sdougb goto out; 2246135446Strhodes} 2247135446Strhodes 2248135446Strhodesstatic void 2249135446Strhodessendrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, 2250135446Strhodes dns_message_t *msg, dns_request_t **request) 2251135446Strhodes{ 2252135446Strhodes isc_result_t result; 2253135446Strhodes nsu_requestinfo_t *reqinfo; 2254135446Strhodes 2255135446Strhodes reqinfo = isc_mem_get(mctx, sizeof(nsu_requestinfo_t)); 2256135446Strhodes if (reqinfo == NULL) 2257135446Strhodes fatal("out of memory"); 2258135446Strhodes reqinfo->msg = msg; 2259135446Strhodes reqinfo->addr = destaddr; 2260135446Strhodes result = dns_request_createvia3(requestmgr, msg, srcaddr, destaddr, 0, 2261135446Strhodes (userserver != NULL) ? tsigkey : NULL, 2262135446Strhodes FIND_TIMEOUT * 20, FIND_TIMEOUT, 3, 2263135446Strhodes global_task, recvsoa, reqinfo, request); 2264135446Strhodes check_result(result, "dns_request_createvia"); 2265135446Strhodes requests++; 2266135446Strhodes} 2267135446Strhodes 2268193149Sdougb#ifdef GSSAPI 2269135446Strhodesstatic void 2270193149Sdougbstart_gssrequest(dns_name_t *master) 2271193149Sdougb{ 2272193149Sdougb gss_ctx_id_t context; 2273193149Sdougb isc_buffer_t buf; 2274193149Sdougb isc_result_t result; 2275193149Sdougb isc_uint32_t val = 0; 2276193149Sdougb dns_message_t *rmsg; 2277193149Sdougb dns_request_t *request = NULL; 2278193149Sdougb dns_name_t *servname; 2279193149Sdougb dns_fixedname_t fname; 2280193149Sdougb char namestr[DNS_NAME_FORMATSIZE]; 2281193149Sdougb char keystr[DNS_NAME_FORMATSIZE]; 2282193149Sdougb 2283193149Sdougb debug("start_gssrequest"); 2284193149Sdougb usevc = ISC_TRUE; 2285193149Sdougb 2286193149Sdougb if (gssring != NULL) 2287193149Sdougb dns_tsigkeyring_destroy(&gssring); 2288193149Sdougb gssring = NULL; 2289193149Sdougb result = dns_tsigkeyring_create(mctx, &gssring); 2290193149Sdougb 2291193149Sdougb if (result != ISC_R_SUCCESS) 2292193149Sdougb fatal("dns_tsigkeyring_create failed: %s", 2293193149Sdougb isc_result_totext(result)); 2294193149Sdougb 2295193149Sdougb dns_name_format(master, namestr, sizeof(namestr)); 2296193149Sdougb if (kserver == NULL) { 2297193149Sdougb kserver = isc_mem_get(mctx, sizeof(isc_sockaddr_t)); 2298193149Sdougb if (kserver == NULL) 2299193149Sdougb fatal("out of memory"); 2300193149Sdougb } 2301193149Sdougb if (userserver == NULL) 2302193149Sdougb get_address(namestr, DNSDEFAULTPORT, kserver); 2303193149Sdougb else 2304193149Sdougb (void)memcpy(kserver, userserver, sizeof(isc_sockaddr_t)); 2305193149Sdougb 2306193149Sdougb dns_fixedname_init(&fname); 2307193149Sdougb servname = dns_fixedname_name(&fname); 2308193149Sdougb 2309193149Sdougb result = isc_string_printf(servicename, sizeof(servicename), 2310193149Sdougb "DNS/%s", namestr); 2311193149Sdougb if (result != ISC_R_SUCCESS) 2312193149Sdougb fatal("isc_string_printf(servicename) failed: %s", 2313193149Sdougb isc_result_totext(result)); 2314193149Sdougb isc_buffer_init(&buf, servicename, strlen(servicename)); 2315193149Sdougb isc_buffer_add(&buf, strlen(servicename)); 2316193149Sdougb result = dns_name_fromtext(servname, &buf, dns_rootname, 2317193149Sdougb ISC_FALSE, NULL); 2318193149Sdougb if (result != ISC_R_SUCCESS) 2319193149Sdougb fatal("dns_name_fromtext(servname) failed: %s", 2320193149Sdougb isc_result_totext(result)); 2321193149Sdougb 2322193149Sdougb dns_fixedname_init(&fkname); 2323193149Sdougb keyname = dns_fixedname_name(&fkname); 2324193149Sdougb 2325193149Sdougb isc_random_get(&val); 2326193149Sdougb result = isc_string_printf(keystr, sizeof(keystr), "%u.sig-%s", 2327193149Sdougb val, namestr); 2328193149Sdougb if (result != ISC_R_SUCCESS) 2329193149Sdougb fatal("isc_string_printf(keystr) failed: %s", 2330193149Sdougb isc_result_totext(result)); 2331193149Sdougb isc_buffer_init(&buf, keystr, strlen(keystr)); 2332193149Sdougb isc_buffer_add(&buf, strlen(keystr)); 2333193149Sdougb 2334193149Sdougb result = dns_name_fromtext(keyname, &buf, dns_rootname, 2335193149Sdougb ISC_FALSE, NULL); 2336193149Sdougb if (result != ISC_R_SUCCESS) 2337193149Sdougb fatal("dns_name_fromtext(keyname) failed: %s", 2338193149Sdougb isc_result_totext(result)); 2339193149Sdougb 2340193149Sdougb /* Windows doesn't recognize name compression in the key name. */ 2341193149Sdougb keyname->attributes |= DNS_NAMEATTR_NOCOMPRESS; 2342193149Sdougb 2343193149Sdougb rmsg = NULL; 2344193149Sdougb result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &rmsg); 2345193149Sdougb if (result != ISC_R_SUCCESS) 2346193149Sdougb fatal("dns_message_create failed: %s", 2347193149Sdougb isc_result_totext(result)); 2348193149Sdougb 2349193149Sdougb /* Build first request. */ 2350193149Sdougb 2351193149Sdougb context = GSS_C_NO_CONTEXT; 2352193149Sdougb result = dns_tkey_buildgssquery(rmsg, keyname, servname, NULL, 0, 2353193149Sdougb &context, use_win2k_gsstsig); 2354193149Sdougb if (result == ISC_R_FAILURE) 2355193149Sdougb fatal("Check your Kerberos ticket, it may have expired."); 2356193149Sdougb if (result != ISC_R_SUCCESS) 2357193149Sdougb fatal("dns_tkey_buildgssquery failed: %s", 2358193149Sdougb isc_result_totext(result)); 2359193149Sdougb 2360193149Sdougb send_gssrequest(localaddr, kserver, rmsg, &request, context); 2361193149Sdougb} 2362193149Sdougb 2363193149Sdougbstatic void 2364193149Sdougbsend_gssrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, 2365193149Sdougb dns_message_t *msg, dns_request_t **request, 2366193149Sdougb gss_ctx_id_t context) 2367193149Sdougb{ 2368193149Sdougb isc_result_t result; 2369193149Sdougb nsu_gssinfo_t *reqinfo; 2370193149Sdougb unsigned int options = 0; 2371193149Sdougb 2372193149Sdougb debug("send_gssrequest"); 2373193149Sdougb reqinfo = isc_mem_get(mctx, sizeof(nsu_gssinfo_t)); 2374193149Sdougb if (reqinfo == NULL) 2375193149Sdougb fatal("out of memory"); 2376193149Sdougb reqinfo->msg = msg; 2377193149Sdougb reqinfo->addr = destaddr; 2378193149Sdougb reqinfo->context = context; 2379193149Sdougb 2380193149Sdougb options |= DNS_REQUESTOPT_TCP; 2381193149Sdougb result = dns_request_createvia3(requestmgr, msg, srcaddr, destaddr, 2382193149Sdougb options, tsigkey, FIND_TIMEOUT * 20, 2383193149Sdougb FIND_TIMEOUT, 3, global_task, recvgss, 2384193149Sdougb reqinfo, request); 2385193149Sdougb check_result(result, "dns_request_createvia3"); 2386193149Sdougb if (debugging) 2387193149Sdougb show_message(stdout, msg, "Outgoing update query:"); 2388193149Sdougb requests++; 2389193149Sdougb} 2390193149Sdougb 2391193149Sdougbstatic void 2392193149Sdougbrecvgss(isc_task_t *task, isc_event_t *event) { 2393193149Sdougb dns_requestevent_t *reqev = NULL; 2394193149Sdougb dns_request_t *request = NULL; 2395193149Sdougb isc_result_t result, eresult; 2396193149Sdougb dns_message_t *rcvmsg = NULL; 2397193149Sdougb nsu_gssinfo_t *reqinfo; 2398193149Sdougb dns_message_t *tsigquery = NULL; 2399193149Sdougb isc_sockaddr_t *addr; 2400193149Sdougb gss_ctx_id_t context; 2401193149Sdougb isc_buffer_t buf; 2402193149Sdougb dns_name_t *servname; 2403193149Sdougb dns_fixedname_t fname; 2404193149Sdougb 2405193149Sdougb UNUSED(task); 2406193149Sdougb 2407193149Sdougb ddebug("recvgss()"); 2408193149Sdougb 2409193149Sdougb requests--; 2410193149Sdougb 2411193149Sdougb REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE); 2412193149Sdougb reqev = (dns_requestevent_t *)event; 2413193149Sdougb request = reqev->request; 2414193149Sdougb eresult = reqev->result; 2415193149Sdougb reqinfo = reqev->ev_arg; 2416193149Sdougb tsigquery = reqinfo->msg; 2417193149Sdougb context = reqinfo->context; 2418193149Sdougb addr = reqinfo->addr; 2419193149Sdougb 2420193149Sdougb if (shuttingdown) { 2421193149Sdougb dns_request_destroy(&request); 2422193149Sdougb dns_message_destroy(&tsigquery); 2423193149Sdougb isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_t)); 2424193149Sdougb isc_event_free(&event); 2425193149Sdougb maybeshutdown(); 2426193149Sdougb return; 2427193149Sdougb } 2428193149Sdougb 2429193149Sdougb if (eresult != ISC_R_SUCCESS) { 2430193149Sdougb char addrbuf[ISC_SOCKADDR_FORMATSIZE]; 2431193149Sdougb 2432193149Sdougb isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf)); 2433193149Sdougb fprintf(stderr, "; Communication with %s failed: %s\n", 2434193149Sdougb addrbuf, isc_result_totext(eresult)); 2435193149Sdougb if (userserver != NULL) 2436193149Sdougb fatal("could not talk to specified name server"); 2437193149Sdougb else if (++ns_inuse >= lwconf->nsnext) 2438193149Sdougb fatal("could not talk to any default name server"); 2439193149Sdougb ddebug("Destroying request [%p]", request); 2440193149Sdougb dns_request_destroy(&request); 2441193149Sdougb dns_message_renderreset(tsigquery); 2442193149Sdougb sendrequest(localaddr, &servers[ns_inuse], tsigquery, 2443193149Sdougb &request); 2444193149Sdougb isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_t)); 2445193149Sdougb isc_event_free(&event); 2446193149Sdougb return; 2447193149Sdougb } 2448193149Sdougb isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_t)); 2449193149Sdougb 2450193149Sdougb isc_event_free(&event); 2451193149Sdougb reqev = NULL; 2452193149Sdougb 2453193149Sdougb ddebug("recvgss creating rcvmsg"); 2454193149Sdougb result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &rcvmsg); 2455193149Sdougb check_result(result, "dns_message_create"); 2456193149Sdougb 2457193149Sdougb result = dns_request_getresponse(request, rcvmsg, 2458193149Sdougb DNS_MESSAGEPARSE_PRESERVEORDER); 2459193149Sdougb check_result(result, "dns_request_getresponse"); 2460193149Sdougb 2461193149Sdougb if (debugging) 2462193149Sdougb show_message(stderr, rcvmsg, 2463193149Sdougb "recvmsg reply from GSS-TSIG query"); 2464193149Sdougb 2465193149Sdougb if (rcvmsg->rcode == dns_rcode_formerr && !tried_other_gsstsig) { 2466193149Sdougb ddebug("recvgss trying %s GSS-TSIG", 2467193149Sdougb use_win2k_gsstsig ? "Standard" : "Win2k"); 2468193149Sdougb if (use_win2k_gsstsig) 2469193149Sdougb use_win2k_gsstsig = ISC_FALSE; 2470193149Sdougb else 2471193149Sdougb use_win2k_gsstsig = ISC_TRUE; 2472193149Sdougb tried_other_gsstsig = ISC_TRUE; 2473193149Sdougb start_gssrequest(&restart_master); 2474193149Sdougb goto done; 2475193149Sdougb } 2476193149Sdougb 2477193149Sdougb if (rcvmsg->rcode != dns_rcode_noerror && 2478193149Sdougb rcvmsg->rcode != dns_rcode_nxdomain) 2479193149Sdougb fatal("response to GSS-TSIG query was unsuccessful"); 2480193149Sdougb 2481193149Sdougb 2482193149Sdougb dns_fixedname_init(&fname); 2483193149Sdougb servname = dns_fixedname_name(&fname); 2484193149Sdougb isc_buffer_init(&buf, servicename, strlen(servicename)); 2485193149Sdougb isc_buffer_add(&buf, strlen(servicename)); 2486193149Sdougb result = dns_name_fromtext(servname, &buf, dns_rootname, 2487193149Sdougb ISC_FALSE, NULL); 2488193149Sdougb check_result(result, "dns_name_fromtext"); 2489193149Sdougb 2490193149Sdougb tsigkey = NULL; 2491193149Sdougb result = dns_tkey_gssnegotiate(tsigquery, rcvmsg, servname, 2492193149Sdougb &context, &tsigkey, gssring, 2493193149Sdougb use_win2k_gsstsig); 2494193149Sdougb switch (result) { 2495193149Sdougb 2496193149Sdougb case DNS_R_CONTINUE: 2497193149Sdougb send_gssrequest(localaddr, kserver, tsigquery, &request, 2498193149Sdougb context); 2499193149Sdougb break; 2500193149Sdougb 2501193149Sdougb case ISC_R_SUCCESS: 2502193149Sdougb /* 2503193149Sdougb * XXXSRA Waaay too much fun here. There's no good 2504193149Sdougb * reason why we need a TSIG here (the people who put 2505193149Sdougb * it into the spec admitted at the time that it was 2506193149Sdougb * not a security issue), and Windows clients don't 2507193149Sdougb * seem to work if named complies with the spec and 2508193149Sdougb * includes the gratuitous TSIG. So we're in the 2509193149Sdougb * bizarre situation of having to choose between 2510193149Sdougb * complying with a useless requirement in the spec 2511193149Sdougb * and interoperating. This is nuts. If we can 2512193149Sdougb * confirm this behavior, we should ask the WG to 2513193149Sdougb * consider removing the requirement for the 2514193149Sdougb * gratuitous TSIG here. For the moment, we ignore 2515193149Sdougb * the TSIG -- this too is a spec violation, but it's 2516193149Sdougb * the least insane thing to do. 2517193149Sdougb */ 2518193149Sdougb#if 0 2519193149Sdougb /* 2520193149Sdougb * Verify the signature. 2521193149Sdougb */ 2522193149Sdougb rcvmsg->state = DNS_SECTION_ANY; 2523193149Sdougb dns_message_setquerytsig(rcvmsg, NULL); 2524193149Sdougb result = dns_message_settsigkey(rcvmsg, tsigkey); 2525193149Sdougb check_result(result, "dns_message_settsigkey"); 2526193149Sdougb result = dns_message_checksig(rcvmsg, NULL); 2527193149Sdougb ddebug("tsig verification: %s", dns_result_totext(result)); 2528193149Sdougb check_result(result, "dns_message_checksig"); 2529193149Sdougb#endif /* 0 */ 2530193149Sdougb 2531193149Sdougb send_update(&tmpzonename, serveraddr, localaddr); 2532193149Sdougb setzoneclass(dns_rdataclass_none); 2533193149Sdougb break; 2534193149Sdougb 2535193149Sdougb default: 2536193149Sdougb fatal("dns_tkey_negotiategss: %s", isc_result_totext(result)); 2537193149Sdougb } 2538193149Sdougb 2539193149Sdougb done: 2540193149Sdougb dns_request_destroy(&request); 2541193149Sdougb dns_message_destroy(&tsigquery); 2542193149Sdougb 2543193149Sdougb dns_message_destroy(&rcvmsg); 2544193149Sdougb ddebug("Out of recvgss"); 2545193149Sdougb} 2546193149Sdougb#endif 2547193149Sdougb 2548193149Sdougbstatic void 2549135446Strhodesstart_update(void) { 2550135446Strhodes isc_result_t result; 2551135446Strhodes dns_rdataset_t *rdataset = NULL; 2552135446Strhodes dns_name_t *name = NULL; 2553135446Strhodes dns_request_t *request = NULL; 2554135446Strhodes dns_message_t *soaquery = NULL; 2555135446Strhodes dns_name_t *firstname; 2556135446Strhodes dns_section_t section = DNS_SECTION_UPDATE; 2557135446Strhodes 2558135446Strhodes ddebug("start_update()"); 2559135446Strhodes 2560135446Strhodes if (answer != NULL) 2561135446Strhodes dns_message_destroy(&answer); 2562135446Strhodes 2563193149Sdougb if (userzone != NULL && userserver != NULL && ! usegsstsig) { 2564135446Strhodes send_update(userzone, userserver, localaddr); 2565135446Strhodes setzoneclass(dns_rdataclass_none); 2566135446Strhodes return; 2567135446Strhodes } 2568135446Strhodes 2569135446Strhodes result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, 2570135446Strhodes &soaquery); 2571135446Strhodes check_result(result, "dns_message_create"); 2572135446Strhodes 2573170222Sdougb if (userserver == NULL) 2574170222Sdougb soaquery->flags |= DNS_MESSAGEFLAG_RD; 2575135446Strhodes 2576135446Strhodes result = dns_message_gettempname(soaquery, &name); 2577135446Strhodes check_result(result, "dns_message_gettempname"); 2578135446Strhodes 2579135446Strhodes result = dns_message_gettemprdataset(soaquery, &rdataset); 2580135446Strhodes check_result(result, "dns_message_gettemprdataset"); 2581135446Strhodes 2582135446Strhodes dns_rdataset_makequestion(rdataset, getzoneclass(), dns_rdatatype_soa); 2583135446Strhodes 2584170222Sdougb if (userzone != NULL) { 2585170222Sdougb dns_name_init(name, NULL); 2586170222Sdougb dns_name_clone(userzone, name); 2587170222Sdougb } else { 2588170222Sdougb result = dns_message_firstname(updatemsg, section); 2589170222Sdougb if (result == ISC_R_NOMORE) { 2590170222Sdougb section = DNS_SECTION_PREREQUISITE; 2591170222Sdougb result = dns_message_firstname(updatemsg, section); 2592170222Sdougb } 2593170222Sdougb if (result != ISC_R_SUCCESS) { 2594174187Sdougb dns_message_puttempname(soaquery, &name); 2595174187Sdougb dns_rdataset_disassociate(rdataset); 2596174187Sdougb dns_message_puttemprdataset(soaquery, &rdataset); 2597174187Sdougb dns_message_destroy(&soaquery); 2598170222Sdougb done_update(); 2599170222Sdougb return; 2600170222Sdougb } 2601170222Sdougb firstname = NULL; 2602170222Sdougb dns_message_currentname(updatemsg, section, &firstname); 2603170222Sdougb dns_name_init(name, NULL); 2604170222Sdougb dns_name_clone(firstname, name); 2605170222Sdougb } 2606135446Strhodes 2607135446Strhodes ISC_LIST_INIT(name->list); 2608135446Strhodes ISC_LIST_APPEND(name->list, rdataset, link); 2609135446Strhodes dns_message_addname(soaquery, name, DNS_SECTION_QUESTION); 2610135446Strhodes 2611135446Strhodes if (userserver != NULL) 2612135446Strhodes sendrequest(localaddr, userserver, soaquery, &request); 2613135446Strhodes else { 2614135446Strhodes ns_inuse = 0; 2615135446Strhodes sendrequest(localaddr, &servers[ns_inuse], soaquery, &request); 2616135446Strhodes } 2617135446Strhodes} 2618135446Strhodes 2619135446Strhodesstatic void 2620135446Strhodescleanup(void) { 2621135446Strhodes ddebug("cleanup()"); 2622135446Strhodes 2623135446Strhodes if (answer != NULL) 2624135446Strhodes dns_message_destroy(&answer); 2625193149Sdougb 2626193149Sdougb#ifdef GSSAPI 2627193149Sdougb if (tsigkey != NULL) { 2628193149Sdougb ddebug("detach tsigkey x%p", tsigkey); 2629193149Sdougb dns_tsigkey_detach(&tsigkey); 2630193149Sdougb } 2631193149Sdougb if (gssring != NULL) { 2632193149Sdougb ddebug("Destroying GSS-TSIG keyring"); 2633193149Sdougb dns_tsigkeyring_destroy(&gssring); 2634193149Sdougb } 2635193149Sdougb if (kserver != NULL) { 2636193149Sdougb isc_mem_put(mctx, kserver, sizeof(isc_sockaddr_t)); 2637193149Sdougb kserver = NULL; 2638193149Sdougb } 2639193149Sdougb#endif 2640193149Sdougb 2641135446Strhodes ddebug("Shutting down task manager"); 2642135446Strhodes isc_taskmgr_destroy(&taskmgr); 2643135446Strhodes 2644135446Strhodes ddebug("Destroying event"); 2645135446Strhodes isc_event_free(&global_event); 2646135446Strhodes 2647135446Strhodes ddebug("Shutting down socket manager"); 2648135446Strhodes isc_socketmgr_destroy(&socketmgr); 2649135446Strhodes 2650135446Strhodes ddebug("Shutting down timer manager"); 2651135446Strhodes isc_timermgr_destroy(&timermgr); 2652135446Strhodes 2653135446Strhodes ddebug("Destroying hash context"); 2654135446Strhodes isc_hash_destroy(); 2655135446Strhodes 2656170222Sdougb ddebug("Destroying name state"); 2657170222Sdougb dns_name_destroy(); 2658170222Sdougb 2659193149Sdougb ddebug("Removing log context"); 2660193149Sdougb isc_log_destroy(&lctx); 2661193149Sdougb 2662135446Strhodes ddebug("Destroying memory context"); 2663135446Strhodes if (memdebugging) 2664135446Strhodes isc_mem_stats(mctx, stderr); 2665135446Strhodes isc_mem_destroy(&mctx); 2666135446Strhodes} 2667135446Strhodes 2668135446Strhodesstatic void 2669135446Strhodesgetinput(isc_task_t *task, isc_event_t *event) { 2670135446Strhodes isc_boolean_t more; 2671135446Strhodes 2672135446Strhodes UNUSED(task); 2673135446Strhodes 2674135446Strhodes if (shuttingdown) { 2675135446Strhodes maybeshutdown(); 2676135446Strhodes return; 2677135446Strhodes } 2678135446Strhodes 2679135446Strhodes if (global_event == NULL) 2680135446Strhodes global_event = event; 2681135446Strhodes 2682135446Strhodes reset_system(); 2683135446Strhodes more = user_interaction(); 2684135446Strhodes if (!more) { 2685135446Strhodes isc_app_shutdown(); 2686135446Strhodes return; 2687135446Strhodes } 2688135446Strhodes start_update(); 2689135446Strhodes return; 2690135446Strhodes} 2691135446Strhodes 2692135446Strhodesint 2693135446Strhodesmain(int argc, char **argv) { 2694135446Strhodes isc_result_t result; 2695135446Strhodes style = &dns_master_style_debug; 2696135446Strhodes 2697135446Strhodes input = stdin; 2698135446Strhodes 2699135446Strhodes interactive = ISC_TF(isatty(0)); 2700135446Strhodes 2701135446Strhodes isc_app_start(); 2702135446Strhodes 2703193149Sdougb pre_parse_args(argc, argv); 2704135446Strhodes 2705193149Sdougb result = isc_mem_create(0, 0, &mctx); 2706193149Sdougb check_result(result, "isc_mem_create"); 2707193149Sdougb 2708193149Sdougb parse_args(argc, argv, mctx, &entropy); 2709193149Sdougb 2710135446Strhodes setup_system(); 2711135446Strhodes 2712135446Strhodes result = isc_app_onrun(mctx, global_task, getinput, NULL); 2713135446Strhodes check_result(result, "isc_app_onrun"); 2714135446Strhodes 2715135446Strhodes (void)isc_app_run(); 2716135446Strhodes 2717135446Strhodes cleanup(); 2718135446Strhodes 2719135446Strhodes isc_app_finish(); 2720135446Strhodes 2721135446Strhodes if (seenerror) 2722135446Strhodes return (2); 2723135446Strhodes else 2724135446Strhodes return (0); 2725135446Strhodes} 2726