1135446Strhodes/* 2262706Serwin * Copyright (C) 2004-2014 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 18254897Serwin/* $Id$ */ 19135446Strhodes 20170222Sdougb/*! \file */ 21170222Sdougb 22135446Strhodes#include <config.h> 23135446Strhodes 24135446Strhodes#include <ctype.h> 25135446Strhodes#include <errno.h> 26135446Strhodes#include <limits.h> 27135446Strhodes#include <stdlib.h> 28135446Strhodes#include <unistd.h> 29135446Strhodes 30135446Strhodes#include <isc/app.h> 31135446Strhodes#include <isc/base64.h> 32135446Strhodes#include <isc/buffer.h> 33135446Strhodes#include <isc/commandline.h> 34135446Strhodes#include <isc/entropy.h> 35135446Strhodes#include <isc/event.h> 36224092Sdougb#include <isc/file.h> 37135446Strhodes#include <isc/hash.h> 38135446Strhodes#include <isc/lex.h> 39193149Sdougb#include <isc/log.h> 40135446Strhodes#include <isc/mem.h> 41135446Strhodes#include <isc/parseint.h> 42218384Sdougb#include <isc/print.h> 43193149Sdougb#include <isc/random.h> 44135446Strhodes#include <isc/region.h> 45135446Strhodes#include <isc/sockaddr.h> 46135446Strhodes#include <isc/socket.h> 47135446Strhodes#include <isc/stdio.h> 48135446Strhodes#include <isc/string.h> 49135446Strhodes#include <isc/task.h> 50135446Strhodes#include <isc/timer.h> 51135446Strhodes#include <isc/types.h> 52135446Strhodes#include <isc/util.h> 53135446Strhodes 54224092Sdougb#include <isccfg/namedconf.h> 55224092Sdougb 56135446Strhodes#include <dns/callbacks.h> 57135446Strhodes#include <dns/dispatch.h> 58135446Strhodes#include <dns/dnssec.h> 59135446Strhodes#include <dns/events.h> 60135446Strhodes#include <dns/fixedname.h> 61193149Sdougb#include <dns/log.h> 62135446Strhodes#include <dns/masterdump.h> 63135446Strhodes#include <dns/message.h> 64135446Strhodes#include <dns/name.h> 65135446Strhodes#include <dns/rcode.h> 66135446Strhodes#include <dns/rdata.h> 67135446Strhodes#include <dns/rdataclass.h> 68135446Strhodes#include <dns/rdatalist.h> 69135446Strhodes#include <dns/rdataset.h> 70135446Strhodes#include <dns/rdatastruct.h> 71135446Strhodes#include <dns/rdatatype.h> 72135446Strhodes#include <dns/request.h> 73135446Strhodes#include <dns/result.h> 74193149Sdougb#include <dns/tkey.h> 75135446Strhodes#include <dns/tsig.h> 76135446Strhodes 77135446Strhodes#include <dst/dst.h> 78135446Strhodes 79135446Strhodes#include <lwres/lwres.h> 80135446Strhodes#include <lwres/net.h> 81135446Strhodes 82193149Sdougb#ifdef GSSAPI 83193149Sdougb#include <dst/gssapi.h> 84262706Serwin#ifdef WIN32 85262706Serwin#include <krb5/krb5.h> 86262706Serwin#else 87224092Sdougb#include ISC_PLATFORM_KRB5HEADER 88193149Sdougb#endif 89262706Serwin#endif 90135446Strhodes#include <bind9/getaddresses.h> 91135446Strhodes 92254897Serwin#if defined(HAVE_READLINE) 93254897Serwin#include <readline/readline.h> 94254897Serwin#include <readline/history.h> 95254897Serwin#endif 96193149Sdougb 97135446Strhodes#ifdef HAVE_ADDRINFO 98135446Strhodes#ifdef HAVE_GETADDRINFO 99135446Strhodes#ifdef HAVE_GAISTRERROR 100135446Strhodes#define USE_GETADDRINFO 101135446Strhodes#endif 102135446Strhodes#endif 103135446Strhodes#endif 104135446Strhodes 105135446Strhodes#ifndef USE_GETADDRINFO 106135446Strhodes#ifndef ISC_PLATFORM_NONSTDHERRNO 107135446Strhodesextern int h_errno; 108135446Strhodes#endif 109135446Strhodes#endif 110135446Strhodes 111135446Strhodes#define MAXCMD (4 * 1024) 112135446Strhodes#define MAXWIRE (64 * 1024) 113135446Strhodes#define PACKETSIZE ((64 * 1024) - 1) 114135446Strhodes#define INITTEXT (2 * 1024) 115135446Strhodes#define MAXTEXT (128 * 1024) 116135446Strhodes#define FIND_TIMEOUT 5 117135446Strhodes#define TTL_MAX 2147483647U /* Maximum signed 32 bit integer. */ 118135446Strhodes 119135446Strhodes#define DNSDEFAULTPORT 53 120135446Strhodes 121224092Sdougbstatic isc_uint16_t dnsport = DNSDEFAULTPORT; 122224092Sdougb 123135446Strhodes#ifndef RESOLV_CONF 124135446Strhodes#define RESOLV_CONF "/etc/resolv.conf" 125135446Strhodes#endif 126135446Strhodes 127135446Strhodesstatic isc_boolean_t debugging = ISC_FALSE, ddebugging = ISC_FALSE; 128135446Strhodesstatic isc_boolean_t memdebugging = ISC_FALSE; 129135446Strhodesstatic isc_boolean_t have_ipv4 = ISC_FALSE; 130135446Strhodesstatic isc_boolean_t have_ipv6 = ISC_FALSE; 131135446Strhodesstatic isc_boolean_t is_dst_up = ISC_FALSE; 132135446Strhodesstatic isc_boolean_t usevc = ISC_FALSE; 133193149Sdougbstatic isc_boolean_t usegsstsig = ISC_FALSE; 134193149Sdougbstatic isc_boolean_t use_win2k_gsstsig = ISC_FALSE; 135193149Sdougbstatic isc_boolean_t tried_other_gsstsig = ISC_FALSE; 136224092Sdougbstatic isc_boolean_t local_only = ISC_FALSE; 137135446Strhodesstatic isc_taskmgr_t *taskmgr = NULL; 138135446Strhodesstatic isc_task_t *global_task = NULL; 139135446Strhodesstatic isc_event_t *global_event = NULL; 140193149Sdougbstatic isc_log_t *lctx = NULL; 141135446Strhodesstatic isc_mem_t *mctx = NULL; 142135446Strhodesstatic dns_dispatchmgr_t *dispatchmgr = NULL; 143135446Strhodesstatic dns_requestmgr_t *requestmgr = NULL; 144135446Strhodesstatic isc_socketmgr_t *socketmgr = NULL; 145135446Strhodesstatic isc_timermgr_t *timermgr = NULL; 146135446Strhodesstatic dns_dispatch_t *dispatchv4 = NULL; 147135446Strhodesstatic dns_dispatch_t *dispatchv6 = NULL; 148135446Strhodesstatic dns_message_t *updatemsg = NULL; 149135446Strhodesstatic dns_fixedname_t fuserzone; 150135446Strhodesstatic dns_name_t *userzone = NULL; 151193149Sdougbstatic dns_name_t *zonename = NULL; 152193149Sdougbstatic dns_name_t tmpzonename; 153193149Sdougbstatic dns_name_t restart_master; 154193149Sdougbstatic dns_tsig_keyring_t *gssring = NULL; 155135446Strhodesstatic dns_tsigkey_t *tsigkey = NULL; 156225361Sdougbstatic dst_key_t *sig0key = NULL; 157135446Strhodesstatic lwres_context_t *lwctx = NULL; 158135446Strhodesstatic lwres_conf_t *lwconf; 159135446Strhodesstatic isc_sockaddr_t *servers; 160135446Strhodesstatic int ns_inuse = 0; 161135446Strhodesstatic int ns_total = 0; 162135446Strhodesstatic isc_sockaddr_t *userserver = NULL; 163135446Strhodesstatic isc_sockaddr_t *localaddr = NULL; 164193149Sdougbstatic isc_sockaddr_t *serveraddr = NULL; 165193149Sdougbstatic isc_sockaddr_t tempaddr; 166224092Sdougbstatic const char *keyfile = NULL; 167224092Sdougbstatic char *keystr = NULL; 168193149Sdougbstatic isc_entropy_t *entropy = NULL; 169135446Strhodesstatic isc_boolean_t shuttingdown = ISC_FALSE; 170135446Strhodesstatic FILE *input; 171135446Strhodesstatic isc_boolean_t interactive = ISC_TRUE; 172135446Strhodesstatic isc_boolean_t seenerror = ISC_FALSE; 173135446Strhodesstatic const dns_master_style_t *style; 174135446Strhodesstatic int requests = 0; 175193149Sdougbstatic unsigned int logdebuglevel = 0; 176135446Strhodesstatic unsigned int timeout = 300; 177135446Strhodesstatic unsigned int udp_timeout = 3; 178135446Strhodesstatic unsigned int udp_retries = 3; 179135446Strhodesstatic dns_rdataclass_t defaultclass = dns_rdataclass_in; 180135446Strhodesstatic dns_rdataclass_t zoneclass = dns_rdataclass_none; 181135446Strhodesstatic dns_message_t *answer = NULL; 182193149Sdougbstatic isc_uint32_t default_ttl = 0; 183193149Sdougbstatic isc_boolean_t default_ttl_set = ISC_FALSE; 184135446Strhodes 185135446Strhodestypedef struct nsu_requestinfo { 186135446Strhodes dns_message_t *msg; 187135446Strhodes isc_sockaddr_t *addr; 188135446Strhodes} nsu_requestinfo_t; 189135446Strhodes 190135446Strhodesstatic void 191135446Strhodessendrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, 192135446Strhodes dns_message_t *msg, dns_request_t **request); 193135446Strhodes 194224092SdougbISC_PLATFORM_NORETURN_PRE static void 195224092Sdougbfatal(const char *format, ...) 196224092SdougbISC_FORMAT_PRINTF(1, 2) ISC_PLATFORM_NORETURN_POST; 197224092Sdougb 198135446Strhodesstatic void 199135446Strhodesdebug(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); 200135446Strhodes 201135446Strhodesstatic void 202135446Strhodesddebug(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); 203135446Strhodes 204193149Sdougb#ifdef GSSAPI 205193149Sdougbstatic dns_fixedname_t fkname; 206193149Sdougbstatic isc_sockaddr_t *kserver = NULL; 207218384Sdougbstatic char *realm = NULL; 208193149Sdougbstatic char servicename[DNS_NAME_FORMATSIZE]; 209193149Sdougbstatic dns_name_t *keyname; 210193149Sdougbtypedef struct nsu_gssinfo { 211193149Sdougb dns_message_t *msg; 212193149Sdougb isc_sockaddr_t *addr; 213193149Sdougb gss_ctx_id_t context; 214193149Sdougb} nsu_gssinfo_t; 215193149Sdougb 216170222Sdougbstatic void 217193149Sdougbstart_gssrequest(dns_name_t *master); 218193149Sdougbstatic void 219193149Sdougbsend_gssrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, 220193149Sdougb dns_message_t *msg, dns_request_t **request, 221193149Sdougb gss_ctx_id_t context); 222193149Sdougbstatic void 223193149Sdougbrecvgss(isc_task_t *task, isc_event_t *event); 224193149Sdougb#endif /* GSSAPI */ 225193149Sdougb 226193149Sdougbstatic void 227170222Sdougberror(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); 228170222Sdougb 229135446Strhodes#define STATUS_MORE (isc_uint16_t)0 230135446Strhodes#define STATUS_SEND (isc_uint16_t)1 231135446Strhodes#define STATUS_QUIT (isc_uint16_t)2 232135446Strhodes#define STATUS_SYNTAX (isc_uint16_t)3 233135446Strhodes 234193149Sdougbtypedef struct entropysource entropysource_t; 235193149Sdougb 236193149Sdougbstruct entropysource { 237193149Sdougb isc_entropysource_t *source; 238193149Sdougb isc_mem_t *mctx; 239193149Sdougb ISC_LINK(entropysource_t) link; 240193149Sdougb}; 241193149Sdougb 242193149Sdougbstatic ISC_LIST(entropysource_t) sources; 243193149Sdougb 244193149Sdougbstatic void 245193149Sdougbsetup_entropy(isc_mem_t *mctx, const char *randomfile, isc_entropy_t **ectx) 246193149Sdougb{ 247193149Sdougb isc_result_t result; 248193149Sdougb isc_entropysource_t *source = NULL; 249193149Sdougb entropysource_t *elt; 250193149Sdougb int usekeyboard = ISC_ENTROPY_KEYBOARDMAYBE; 251193149Sdougb 252193149Sdougb REQUIRE(ectx != NULL); 253193149Sdougb 254193149Sdougb if (*ectx == NULL) { 255193149Sdougb result = isc_entropy_create(mctx, ectx); 256193149Sdougb if (result != ISC_R_SUCCESS) 257193149Sdougb fatal("could not create entropy object"); 258193149Sdougb ISC_LIST_INIT(sources); 259193149Sdougb } 260193149Sdougb 261193149Sdougb if (randomfile != NULL && strcmp(randomfile, "keyboard") == 0) { 262193149Sdougb usekeyboard = ISC_ENTROPY_KEYBOARDYES; 263193149Sdougb randomfile = NULL; 264193149Sdougb } 265193149Sdougb 266193149Sdougb result = isc_entropy_usebestsource(*ectx, &source, randomfile, 267193149Sdougb usekeyboard); 268193149Sdougb 269193149Sdougb if (result != ISC_R_SUCCESS) 270193149Sdougb fatal("could not initialize entropy source: %s", 271193149Sdougb isc_result_totext(result)); 272193149Sdougb 273193149Sdougb if (source != NULL) { 274193149Sdougb elt = isc_mem_get(mctx, sizeof(*elt)); 275193149Sdougb if (elt == NULL) 276193149Sdougb fatal("out of memory"); 277193149Sdougb elt->source = source; 278193149Sdougb elt->mctx = mctx; 279193149Sdougb ISC_LINK_INIT(elt, link); 280193149Sdougb ISC_LIST_APPEND(sources, elt, link); 281193149Sdougb } 282193149Sdougb} 283193149Sdougb 284193149Sdougbstatic void 285193149Sdougbcleanup_entropy(isc_entropy_t **ectx) { 286193149Sdougb entropysource_t *source; 287193149Sdougb while (!ISC_LIST_EMPTY(sources)) { 288193149Sdougb source = ISC_LIST_HEAD(sources); 289193149Sdougb ISC_LIST_UNLINK(sources, source, link); 290193149Sdougb isc_entropy_destroysource(&source->source); 291193149Sdougb isc_mem_put(source->mctx, source, sizeof(*source)); 292193149Sdougb } 293193149Sdougb isc_entropy_detach(ectx); 294193149Sdougb} 295193149Sdougb 296193149Sdougb 297135446Strhodesstatic dns_rdataclass_t 298135446Strhodesgetzoneclass(void) { 299135446Strhodes if (zoneclass == dns_rdataclass_none) 300135446Strhodes zoneclass = defaultclass; 301135446Strhodes return (zoneclass); 302135446Strhodes} 303135446Strhodes 304135446Strhodesstatic isc_boolean_t 305135446Strhodessetzoneclass(dns_rdataclass_t rdclass) { 306135446Strhodes if (zoneclass == dns_rdataclass_none || 307135446Strhodes rdclass == dns_rdataclass_none) 308135446Strhodes zoneclass = rdclass; 309135446Strhodes if (zoneclass != rdclass) 310135446Strhodes return (ISC_FALSE); 311135446Strhodes return (ISC_TRUE); 312135446Strhodes} 313135446Strhodes 314135446Strhodesstatic void 315135446Strhodesfatal(const char *format, ...) { 316135446Strhodes va_list args; 317135446Strhodes 318135446Strhodes va_start(args, format); 319135446Strhodes vfprintf(stderr, format, args); 320135446Strhodes va_end(args); 321135446Strhodes fprintf(stderr, "\n"); 322135446Strhodes exit(1); 323135446Strhodes} 324135446Strhodes 325135446Strhodesstatic void 326170222Sdougberror(const char *format, ...) { 327170222Sdougb va_list args; 328170222Sdougb 329170222Sdougb va_start(args, format); 330170222Sdougb vfprintf(stderr, format, args); 331170222Sdougb va_end(args); 332170222Sdougb fprintf(stderr, "\n"); 333170222Sdougb} 334170222Sdougb 335170222Sdougbstatic void 336135446Strhodesdebug(const char *format, ...) { 337135446Strhodes va_list args; 338135446Strhodes 339135446Strhodes if (debugging) { 340135446Strhodes va_start(args, format); 341135446Strhodes vfprintf(stderr, format, args); 342135446Strhodes va_end(args); 343135446Strhodes fprintf(stderr, "\n"); 344135446Strhodes } 345135446Strhodes} 346135446Strhodes 347135446Strhodesstatic void 348135446Strhodesddebug(const char *format, ...) { 349135446Strhodes va_list args; 350135446Strhodes 351135446Strhodes if (ddebugging) { 352135446Strhodes va_start(args, format); 353135446Strhodes vfprintf(stderr, format, args); 354135446Strhodes va_end(args); 355135446Strhodes fprintf(stderr, "\n"); 356135446Strhodes } 357135446Strhodes} 358135446Strhodes 359135446Strhodesstatic inline void 360135446Strhodescheck_result(isc_result_t result, const char *msg) { 361135446Strhodes if (result != ISC_R_SUCCESS) 362135446Strhodes fatal("%s: %s", msg, isc_result_totext(result)); 363135446Strhodes} 364135446Strhodes 365135446Strhodesstatic void * 366135446Strhodesmem_alloc(void *arg, size_t size) { 367135446Strhodes return (isc_mem_get(arg, size)); 368135446Strhodes} 369135446Strhodes 370135446Strhodesstatic void 371135446Strhodesmem_free(void *arg, void *mem, size_t size) { 372135446Strhodes isc_mem_put(arg, mem, size); 373135446Strhodes} 374135446Strhodes 375135446Strhodesstatic char * 376135446Strhodesnsu_strsep(char **stringp, const char *delim) { 377135446Strhodes char *string = *stringp; 378135446Strhodes char *s; 379135446Strhodes const char *d; 380135446Strhodes char sc, dc; 381135446Strhodes 382135446Strhodes if (string == NULL) 383135446Strhodes return (NULL); 384135446Strhodes 385135446Strhodes for (; *string != '\0'; string++) { 386135446Strhodes sc = *string; 387135446Strhodes for (d = delim; (dc = *d) != '\0'; d++) { 388135446Strhodes if (sc == dc) 389135446Strhodes break; 390135446Strhodes } 391135446Strhodes if (dc == 0) 392135446Strhodes break; 393135446Strhodes } 394135446Strhodes 395135446Strhodes for (s = string; *s != '\0'; s++) { 396135446Strhodes sc = *s; 397135446Strhodes for (d = delim; (dc = *d) != '\0'; d++) { 398135446Strhodes if (sc == dc) { 399135446Strhodes *s++ = '\0'; 400135446Strhodes *stringp = s; 401135446Strhodes return (string); 402135446Strhodes } 403135446Strhodes } 404135446Strhodes } 405135446Strhodes *stringp = NULL; 406135446Strhodes return (string); 407135446Strhodes} 408135446Strhodes 409135446Strhodesstatic void 410135446Strhodesreset_system(void) { 411135446Strhodes isc_result_t result; 412135446Strhodes 413135446Strhodes ddebug("reset_system()"); 414135446Strhodes /* If the update message is still around, destroy it */ 415135446Strhodes if (updatemsg != NULL) 416135446Strhodes dns_message_reset(updatemsg, DNS_MESSAGE_INTENTRENDER); 417135446Strhodes else { 418135446Strhodes result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, 419135446Strhodes &updatemsg); 420135446Strhodes check_result(result, "dns_message_create"); 421135446Strhodes } 422135446Strhodes updatemsg->opcode = dns_opcode_update; 423193149Sdougb if (usegsstsig) { 424193149Sdougb if (tsigkey != NULL) 425193149Sdougb dns_tsigkey_detach(&tsigkey); 426193149Sdougb if (gssring != NULL) 427224092Sdougb dns_tsigkeyring_detach(&gssring); 428193149Sdougb tried_other_gsstsig = ISC_FALSE; 429193149Sdougb } 430135446Strhodes} 431135446Strhodes 432170222Sdougbstatic isc_uint16_t 433170222Sdougbparse_hmac(dns_name_t **hmac, const char *hmacstr, size_t len) { 434170222Sdougb isc_uint16_t digestbits = 0; 435170222Sdougb isc_result_t result; 436170222Sdougb char buf[20]; 437170222Sdougb 438170222Sdougb REQUIRE(hmac != NULL && *hmac == NULL); 439170222Sdougb REQUIRE(hmacstr != NULL); 440170222Sdougb 441170222Sdougb if (len >= sizeof(buf)) 442170222Sdougb fatal("unknown key type '%.*s'", (int)(len), hmacstr); 443170222Sdougb 444170222Sdougb strncpy(buf, hmacstr, len); 445170222Sdougb buf[len] = 0; 446186462Sdougb 447170222Sdougb if (strcasecmp(buf, "hmac-md5") == 0) { 448170222Sdougb *hmac = DNS_TSIG_HMACMD5_NAME; 449170222Sdougb } else if (strncasecmp(buf, "hmac-md5-", 9) == 0) { 450170222Sdougb *hmac = DNS_TSIG_HMACMD5_NAME; 451170222Sdougb result = isc_parse_uint16(&digestbits, &buf[9], 10); 452170222Sdougb if (result != ISC_R_SUCCESS || digestbits > 128) 453170222Sdougb fatal("digest-bits out of range [0..128]"); 454170222Sdougb digestbits = (digestbits +7) & ~0x7U; 455170222Sdougb } else if (strcasecmp(buf, "hmac-sha1") == 0) { 456170222Sdougb *hmac = DNS_TSIG_HMACSHA1_NAME; 457170222Sdougb } else if (strncasecmp(buf, "hmac-sha1-", 10) == 0) { 458170222Sdougb *hmac = DNS_TSIG_HMACSHA1_NAME; 459170222Sdougb result = isc_parse_uint16(&digestbits, &buf[10], 10); 460170222Sdougb if (result != ISC_R_SUCCESS || digestbits > 160) 461170222Sdougb fatal("digest-bits out of range [0..160]"); 462170222Sdougb digestbits = (digestbits +7) & ~0x7U; 463170222Sdougb } else if (strcasecmp(buf, "hmac-sha224") == 0) { 464170222Sdougb *hmac = DNS_TSIG_HMACSHA224_NAME; 465170222Sdougb } else if (strncasecmp(buf, "hmac-sha224-", 12) == 0) { 466170222Sdougb *hmac = DNS_TSIG_HMACSHA224_NAME; 467170222Sdougb result = isc_parse_uint16(&digestbits, &buf[12], 10); 468170222Sdougb if (result != ISC_R_SUCCESS || digestbits > 224) 469170222Sdougb fatal("digest-bits out of range [0..224]"); 470170222Sdougb digestbits = (digestbits +7) & ~0x7U; 471170222Sdougb } else if (strcasecmp(buf, "hmac-sha256") == 0) { 472170222Sdougb *hmac = DNS_TSIG_HMACSHA256_NAME; 473170222Sdougb } else if (strncasecmp(buf, "hmac-sha256-", 12) == 0) { 474170222Sdougb *hmac = DNS_TSIG_HMACSHA256_NAME; 475170222Sdougb result = isc_parse_uint16(&digestbits, &buf[12], 10); 476170222Sdougb if (result != ISC_R_SUCCESS || digestbits > 256) 477170222Sdougb fatal("digest-bits out of range [0..256]"); 478170222Sdougb digestbits = (digestbits +7) & ~0x7U; 479170222Sdougb } else if (strcasecmp(buf, "hmac-sha384") == 0) { 480170222Sdougb *hmac = DNS_TSIG_HMACSHA384_NAME; 481170222Sdougb } else if (strncasecmp(buf, "hmac-sha384-", 12) == 0) { 482170222Sdougb *hmac = DNS_TSIG_HMACSHA384_NAME; 483170222Sdougb result = isc_parse_uint16(&digestbits, &buf[12], 10); 484170222Sdougb if (result != ISC_R_SUCCESS || digestbits > 384) 485170222Sdougb fatal("digest-bits out of range [0..384]"); 486170222Sdougb digestbits = (digestbits +7) & ~0x7U; 487170222Sdougb } else if (strcasecmp(buf, "hmac-sha512") == 0) { 488170222Sdougb *hmac = DNS_TSIG_HMACSHA512_NAME; 489170222Sdougb } else if (strncasecmp(buf, "hmac-sha512-", 12) == 0) { 490170222Sdougb *hmac = DNS_TSIG_HMACSHA512_NAME; 491170222Sdougb result = isc_parse_uint16(&digestbits, &buf[12], 10); 492170222Sdougb if (result != ISC_R_SUCCESS || digestbits > 512) 493170222Sdougb fatal("digest-bits out of range [0..512]"); 494170222Sdougb digestbits = (digestbits +7) & ~0x7U; 495170222Sdougb } else 496170222Sdougb fatal("unknown key type '%s'", buf); 497170222Sdougb return (digestbits); 498170222Sdougb} 499170222Sdougb 500224092Sdougbstatic int 501224092Sdougbbasenamelen(const char *file) { 502224092Sdougb int len = strlen(file); 503224092Sdougb 504224092Sdougb if (len > 1 && file[len - 1] == '.') 505224092Sdougb len -= 1; 506224092Sdougb else if (len > 8 && strcmp(file + len - 8, ".private") == 0) 507224092Sdougb len -= 8; 508224092Sdougb else if (len > 4 && strcmp(file + len - 4, ".key") == 0) 509224092Sdougb len -= 4; 510224092Sdougb return (len); 511224092Sdougb} 512224092Sdougb 513135446Strhodesstatic void 514135446Strhodessetup_keystr(void) { 515135446Strhodes unsigned char *secret = NULL; 516135446Strhodes int secretlen; 517135446Strhodes isc_buffer_t secretbuf; 518135446Strhodes isc_result_t result; 519135446Strhodes isc_buffer_t keynamesrc; 520135446Strhodes char *secretstr; 521170222Sdougb char *s, *n; 522135446Strhodes dns_fixedname_t fkeyname; 523135446Strhodes dns_name_t *keyname; 524170222Sdougb char *name; 525170222Sdougb dns_name_t *hmacname = NULL; 526170222Sdougb isc_uint16_t digestbits = 0; 527135446Strhodes 528135446Strhodes dns_fixedname_init(&fkeyname); 529135446Strhodes keyname = dns_fixedname_name(&fkeyname); 530135446Strhodes 531135446Strhodes debug("Creating key..."); 532135446Strhodes 533135446Strhodes s = strchr(keystr, ':'); 534170222Sdougb if (s == NULL || s == keystr || s[1] == 0) 535170222Sdougb fatal("key option must specify [hmac:]keyname:secret"); 536135446Strhodes secretstr = s + 1; 537170222Sdougb n = strchr(secretstr, ':'); 538170222Sdougb if (n != NULL) { 539170222Sdougb if (n == secretstr || n[1] == 0) 540170222Sdougb fatal("key option must specify [hmac:]keyname:secret"); 541170222Sdougb name = secretstr; 542170222Sdougb secretstr = n + 1; 543170222Sdougb digestbits = parse_hmac(&hmacname, keystr, s - keystr); 544170222Sdougb } else { 545170222Sdougb hmacname = DNS_TSIG_HMACMD5_NAME; 546170222Sdougb name = keystr; 547170222Sdougb n = s; 548170222Sdougb } 549135446Strhodes 550262706Serwin isc_buffer_init(&keynamesrc, name, (unsigned int)(n - name)); 551262706Serwin isc_buffer_add(&keynamesrc, (unsigned int)(n - name)); 552135446Strhodes 553135446Strhodes debug("namefromtext"); 554224092Sdougb result = dns_name_fromtext(keyname, &keynamesrc, dns_rootname, 0, NULL); 555135446Strhodes check_result(result, "dns_name_fromtext"); 556135446Strhodes 557135446Strhodes secretlen = strlen(secretstr) * 3 / 4; 558135446Strhodes secret = isc_mem_allocate(mctx, secretlen); 559135446Strhodes if (secret == NULL) 560135446Strhodes fatal("out of memory"); 561135446Strhodes 562135446Strhodes isc_buffer_init(&secretbuf, secret, secretlen); 563135446Strhodes result = isc_base64_decodestring(secretstr, &secretbuf); 564135446Strhodes if (result != ISC_R_SUCCESS) { 565135446Strhodes fprintf(stderr, "could not create key from %s: %s\n", 566135446Strhodes keystr, isc_result_totext(result)); 567135446Strhodes goto failure; 568135446Strhodes } 569135446Strhodes 570135446Strhodes secretlen = isc_buffer_usedlength(&secretbuf); 571135446Strhodes 572135446Strhodes debug("keycreate"); 573170222Sdougb result = dns_tsigkey_create(keyname, hmacname, secret, secretlen, 574218384Sdougb ISC_FALSE, NULL, 0, 0, mctx, NULL, 575218384Sdougb &tsigkey); 576135446Strhodes if (result != ISC_R_SUCCESS) 577135446Strhodes fprintf(stderr, "could not create key from %s: %s\n", 578135446Strhodes keystr, dns_result_totext(result)); 579170222Sdougb else 580170222Sdougb dst_key_setbits(tsigkey->key, digestbits); 581135446Strhodes failure: 582135446Strhodes if (secret != NULL) 583135446Strhodes isc_mem_free(mctx, secret); 584135446Strhodes} 585135446Strhodes 586224092Sdougb/* 587224092Sdougb * Get a key from a named.conf format keyfile 588224092Sdougb */ 589224092Sdougbstatic isc_result_t 590224092Sdougbread_sessionkey(isc_mem_t *mctx, isc_log_t *lctx) { 591224092Sdougb cfg_parser_t *pctx = NULL; 592224092Sdougb cfg_obj_t *sessionkey = NULL; 593224092Sdougb const cfg_obj_t *key = NULL; 594224092Sdougb const cfg_obj_t *secretobj = NULL; 595224092Sdougb const cfg_obj_t *algorithmobj = NULL; 596224092Sdougb const char *keyname; 597224092Sdougb const char *secretstr; 598224092Sdougb const char *algorithm; 599224092Sdougb isc_result_t result; 600224092Sdougb int len; 601218384Sdougb 602224092Sdougb if (! isc_file_exists(keyfile)) 603224092Sdougb return (ISC_R_FILENOTFOUND); 604224092Sdougb 605224092Sdougb result = cfg_parser_create(mctx, lctx, &pctx); 606224092Sdougb if (result != ISC_R_SUCCESS) 607224092Sdougb goto cleanup; 608224092Sdougb 609224092Sdougb result = cfg_parse_file(pctx, keyfile, &cfg_type_sessionkey, 610224092Sdougb &sessionkey); 611224092Sdougb if (result != ISC_R_SUCCESS) 612224092Sdougb goto cleanup; 613224092Sdougb 614224092Sdougb result = cfg_map_get(sessionkey, "key", &key); 615224092Sdougb if (result != ISC_R_SUCCESS) 616224092Sdougb goto cleanup; 617224092Sdougb 618224092Sdougb (void) cfg_map_get(key, "secret", &secretobj); 619224092Sdougb (void) cfg_map_get(key, "algorithm", &algorithmobj); 620224092Sdougb if (secretobj == NULL || algorithmobj == NULL) 621224092Sdougb fatal("key must have algorithm and secret"); 622224092Sdougb 623224092Sdougb keyname = cfg_obj_asstring(cfg_map_getname(key)); 624224092Sdougb secretstr = cfg_obj_asstring(secretobj); 625224092Sdougb algorithm = cfg_obj_asstring(algorithmobj); 626224092Sdougb 627224092Sdougb len = strlen(algorithm) + strlen(keyname) + strlen(secretstr) + 3; 628224092Sdougb keystr = isc_mem_allocate(mctx, len); 629224092Sdougb snprintf(keystr, len, "%s:%s:%s", algorithm, keyname, secretstr); 630224092Sdougb setup_keystr(); 631224092Sdougb 632224092Sdougb cleanup: 633224092Sdougb if (pctx != NULL) { 634224092Sdougb if (sessionkey != NULL) 635224092Sdougb cfg_obj_destroy(pctx, &sessionkey); 636224092Sdougb cfg_parser_destroy(&pctx); 637224092Sdougb } 638224092Sdougb 639224092Sdougb if (keystr != NULL) 640224092Sdougb isc_mem_free(mctx, keystr); 641224092Sdougb 642224092Sdougb return (result); 643218384Sdougb} 644218384Sdougb 645135446Strhodesstatic void 646224092Sdougbsetup_keyfile(isc_mem_t *mctx, isc_log_t *lctx) { 647135446Strhodes dst_key_t *dstkey = NULL; 648135446Strhodes isc_result_t result; 649170222Sdougb dns_name_t *hmacname = NULL; 650135446Strhodes 651135446Strhodes debug("Creating key..."); 652135446Strhodes 653218384Sdougb if (sig0key != NULL) 654218384Sdougb dst_key_free(&sig0key); 655218384Sdougb 656224092Sdougb /* Try reading the key from a K* pair */ 657224092Sdougb result = dst_key_fromnamedfile(keyfile, NULL, 658135446Strhodes DST_TYPE_PRIVATE | DST_TYPE_KEY, mctx, 659135446Strhodes &dstkey); 660224092Sdougb 661224092Sdougb /* If that didn't work, try reading it as a session.key keyfile */ 662135446Strhodes if (result != ISC_R_SUCCESS) { 663224092Sdougb result = read_sessionkey(mctx, lctx); 664224092Sdougb if (result == ISC_R_SUCCESS) 665224092Sdougb return; 666224092Sdougb } 667224092Sdougb 668224092Sdougb if (result != ISC_R_SUCCESS) { 669218384Sdougb fprintf(stderr, "could not read key from %.*s.{private,key}: " 670218384Sdougb "%s\n", basenamelen(keyfile), keyfile, 671218384Sdougb isc_result_totext(result)); 672135446Strhodes return; 673135446Strhodes } 674224092Sdougb 675170222Sdougb switch (dst_key_alg(dstkey)) { 676170222Sdougb case DST_ALG_HMACMD5: 677170222Sdougb hmacname = DNS_TSIG_HMACMD5_NAME; 678170222Sdougb break; 679170222Sdougb case DST_ALG_HMACSHA1: 680170222Sdougb hmacname = DNS_TSIG_HMACSHA1_NAME; 681170222Sdougb break; 682170222Sdougb case DST_ALG_HMACSHA224: 683170222Sdougb hmacname = DNS_TSIG_HMACSHA224_NAME; 684170222Sdougb break; 685170222Sdougb case DST_ALG_HMACSHA256: 686170222Sdougb hmacname = DNS_TSIG_HMACSHA256_NAME; 687170222Sdougb break; 688170222Sdougb case DST_ALG_HMACSHA384: 689170222Sdougb hmacname = DNS_TSIG_HMACSHA384_NAME; 690170222Sdougb break; 691170222Sdougb case DST_ALG_HMACSHA512: 692170222Sdougb hmacname = DNS_TSIG_HMACSHA512_NAME; 693170222Sdougb break; 694170222Sdougb } 695170222Sdougb if (hmacname != NULL) { 696135446Strhodes result = dns_tsigkey_createfromkey(dst_key_name(dstkey), 697170222Sdougb hmacname, dstkey, ISC_FALSE, 698170222Sdougb NULL, 0, 0, mctx, NULL, 699170222Sdougb &tsigkey); 700218384Sdougb dst_key_free(&dstkey); 701135446Strhodes if (result != ISC_R_SUCCESS) { 702135446Strhodes fprintf(stderr, "could not create key from %s: %s\n", 703135446Strhodes keyfile, isc_result_totext(result)); 704135446Strhodes return; 705135446Strhodes } 706222395Sdougb } else { 707218384Sdougb dst_key_attach(dstkey, &sig0key); 708222395Sdougb dst_key_free(&dstkey); 709222395Sdougb } 710135446Strhodes} 711135446Strhodes 712135446Strhodesstatic void 713135446Strhodesdoshutdown(void) { 714135446Strhodes isc_task_detach(&global_task); 715135446Strhodes 716135446Strhodes if (userserver != NULL) 717135446Strhodes isc_mem_put(mctx, userserver, sizeof(isc_sockaddr_t)); 718135446Strhodes 719135446Strhodes if (localaddr != NULL) 720135446Strhodes isc_mem_put(mctx, localaddr, sizeof(isc_sockaddr_t)); 721135446Strhodes 722135446Strhodes if (tsigkey != NULL) { 723135446Strhodes ddebug("Freeing TSIG key"); 724135446Strhodes dns_tsigkey_detach(&tsigkey); 725135446Strhodes } 726135446Strhodes 727135446Strhodes if (sig0key != NULL) { 728135446Strhodes ddebug("Freeing SIG(0) key"); 729135446Strhodes dst_key_free(&sig0key); 730135446Strhodes } 731135446Strhodes 732135446Strhodes if (updatemsg != NULL) 733135446Strhodes dns_message_destroy(&updatemsg); 734135446Strhodes 735135446Strhodes if (is_dst_up) { 736135446Strhodes ddebug("Destroy DST lib"); 737135446Strhodes dst_lib_destroy(); 738135446Strhodes is_dst_up = ISC_FALSE; 739135446Strhodes } 740135446Strhodes 741193149Sdougb cleanup_entropy(&entropy); 742135446Strhodes 743135446Strhodes lwres_conf_clear(lwctx); 744135446Strhodes lwres_context_destroy(&lwctx); 745135446Strhodes 746135446Strhodes isc_mem_put(mctx, servers, ns_total * sizeof(isc_sockaddr_t)); 747135446Strhodes 748135446Strhodes ddebug("Destroying request manager"); 749135446Strhodes dns_requestmgr_detach(&requestmgr); 750135446Strhodes 751135446Strhodes ddebug("Freeing the dispatchers"); 752135446Strhodes if (have_ipv4) 753135446Strhodes dns_dispatch_detach(&dispatchv4); 754135446Strhodes if (have_ipv6) 755135446Strhodes dns_dispatch_detach(&dispatchv6); 756135446Strhodes 757135446Strhodes ddebug("Shutting down dispatch manager"); 758135446Strhodes dns_dispatchmgr_destroy(&dispatchmgr); 759135446Strhodes 760135446Strhodes} 761135446Strhodes 762135446Strhodesstatic void 763135446Strhodesmaybeshutdown(void) { 764135446Strhodes ddebug("Shutting down request manager"); 765135446Strhodes dns_requestmgr_shutdown(requestmgr); 766135446Strhodes 767135446Strhodes if (requests != 0) 768135446Strhodes return; 769135446Strhodes 770135446Strhodes doshutdown(); 771135446Strhodes} 772135446Strhodes 773135446Strhodesstatic void 774135446Strhodesshutdown_program(isc_task_t *task, isc_event_t *event) { 775135446Strhodes REQUIRE(task == global_task); 776135446Strhodes UNUSED(task); 777135446Strhodes 778135446Strhodes ddebug("shutdown_program()"); 779135446Strhodes isc_event_free(&event); 780135446Strhodes 781135446Strhodes shuttingdown = ISC_TRUE; 782135446Strhodes maybeshutdown(); 783135446Strhodes} 784135446Strhodes 785135446Strhodesstatic void 786135446Strhodessetup_system(void) { 787135446Strhodes isc_result_t result; 788135446Strhodes isc_sockaddr_t bind_any, bind_any6; 789135446Strhodes lwres_result_t lwresult; 790135446Strhodes unsigned int attrs, attrmask; 791135446Strhodes int i; 792193149Sdougb isc_logconfig_t *logconfig = NULL; 793135446Strhodes 794135446Strhodes ddebug("setup_system()"); 795135446Strhodes 796135446Strhodes dns_result_register(); 797135446Strhodes 798135446Strhodes result = isc_net_probeipv4(); 799135446Strhodes if (result == ISC_R_SUCCESS) 800135446Strhodes have_ipv4 = ISC_TRUE; 801135446Strhodes 802135446Strhodes result = isc_net_probeipv6(); 803135446Strhodes if (result == ISC_R_SUCCESS) 804135446Strhodes have_ipv6 = ISC_TRUE; 805135446Strhodes 806135446Strhodes if (!have_ipv4 && !have_ipv6) 807135446Strhodes fatal("could not find either IPv4 or IPv6"); 808135446Strhodes 809193149Sdougb result = isc_log_create(mctx, &lctx, &logconfig); 810193149Sdougb check_result(result, "isc_log_create"); 811135446Strhodes 812193149Sdougb isc_log_setcontext(lctx); 813193149Sdougb dns_log_init(lctx); 814193149Sdougb dns_log_setcontext(lctx); 815193149Sdougb 816193149Sdougb result = isc_log_usechannel(logconfig, "default_debug", NULL, NULL); 817193149Sdougb check_result(result, "isc_log_usechannel"); 818193149Sdougb 819193149Sdougb isc_log_setdebuglevel(lctx, logdebuglevel); 820193149Sdougb 821135446Strhodes lwresult = lwres_context_create(&lwctx, mctx, mem_alloc, mem_free, 1); 822135446Strhodes if (lwresult != LWRES_R_SUCCESS) 823135446Strhodes fatal("lwres_context_create failed"); 824135446Strhodes 825135446Strhodes (void)lwres_conf_parse(lwctx, RESOLV_CONF); 826135446Strhodes lwconf = lwres_conf_get(lwctx); 827135446Strhodes 828135446Strhodes ns_total = lwconf->nsnext; 829135446Strhodes if (ns_total <= 0) { 830135446Strhodes /* No name servers in resolv.conf; default to loopback. */ 831135446Strhodes struct in_addr localhost; 832135446Strhodes ns_total = 1; 833135446Strhodes servers = isc_mem_get(mctx, ns_total * sizeof(isc_sockaddr_t)); 834135446Strhodes if (servers == NULL) 835135446Strhodes fatal("out of memory"); 836135446Strhodes localhost.s_addr = htonl(INADDR_LOOPBACK); 837224092Sdougb isc_sockaddr_fromin(&servers[0], &localhost, dnsport); 838135446Strhodes } else { 839135446Strhodes servers = isc_mem_get(mctx, ns_total * sizeof(isc_sockaddr_t)); 840135446Strhodes if (servers == NULL) 841135446Strhodes fatal("out of memory"); 842135446Strhodes for (i = 0; i < ns_total; i++) { 843262706Serwin if (lwconf->nameservers[i].family == LWRES_ADDRTYPE_V4) 844262706Serwin { 845135446Strhodes struct in_addr in4; 846262706Serwin memmove(&in4, 847262706Serwin lwconf->nameservers[i].address, 4); 848224092Sdougb isc_sockaddr_fromin(&servers[i], &in4, dnsport); 849135446Strhodes } else { 850135446Strhodes struct in6_addr in6; 851262706Serwin memmove(&in6, 852262706Serwin lwconf->nameservers[i].address, 16); 853135446Strhodes isc_sockaddr_fromin6(&servers[i], &in6, 854224092Sdougb dnsport); 855135446Strhodes } 856135446Strhodes } 857135446Strhodes } 858135446Strhodes 859193149Sdougb setup_entropy(mctx, NULL, &entropy); 860135446Strhodes 861193149Sdougb result = isc_hash_create(mctx, entropy, DNS_NAME_MAXWIRE); 862135446Strhodes check_result(result, "isc_hash_create"); 863135446Strhodes isc_hash_init(); 864135446Strhodes 865193149Sdougb result = dns_dispatchmgr_create(mctx, entropy, &dispatchmgr); 866135446Strhodes check_result(result, "dns_dispatchmgr_create"); 867135446Strhodes 868135446Strhodes result = isc_socketmgr_create(mctx, &socketmgr); 869135446Strhodes check_result(result, "dns_socketmgr_create"); 870135446Strhodes 871135446Strhodes result = isc_timermgr_create(mctx, &timermgr); 872135446Strhodes check_result(result, "dns_timermgr_create"); 873135446Strhodes 874135446Strhodes result = isc_taskmgr_create(mctx, 1, 0, &taskmgr); 875135446Strhodes check_result(result, "isc_taskmgr_create"); 876135446Strhodes 877135446Strhodes result = isc_task_create(taskmgr, 0, &global_task); 878135446Strhodes check_result(result, "isc_task_create"); 879135446Strhodes 880135446Strhodes result = isc_task_onshutdown(global_task, shutdown_program, NULL); 881135446Strhodes check_result(result, "isc_task_onshutdown"); 882135446Strhodes 883193149Sdougb result = dst_lib_init(mctx, entropy, 0); 884135446Strhodes check_result(result, "dst_lib_init"); 885135446Strhodes is_dst_up = ISC_TRUE; 886135446Strhodes 887135446Strhodes attrmask = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP; 888135446Strhodes attrmask |= DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6; 889135446Strhodes 890135446Strhodes if (have_ipv6) { 891135446Strhodes attrs = DNS_DISPATCHATTR_UDP; 892135446Strhodes attrs |= DNS_DISPATCHATTR_MAKEQUERY; 893135446Strhodes attrs |= DNS_DISPATCHATTR_IPV6; 894135446Strhodes isc_sockaddr_any6(&bind_any6); 895135446Strhodes result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, 896135446Strhodes &bind_any6, PACKETSIZE, 897135446Strhodes 4, 2, 3, 5, 898135446Strhodes attrs, attrmask, &dispatchv6); 899135446Strhodes check_result(result, "dns_dispatch_getudp (v6)"); 900135446Strhodes } 901135446Strhodes 902135446Strhodes if (have_ipv4) { 903135446Strhodes attrs = DNS_DISPATCHATTR_UDP; 904135446Strhodes attrs |= DNS_DISPATCHATTR_MAKEQUERY; 905135446Strhodes attrs |= DNS_DISPATCHATTR_IPV4; 906135446Strhodes isc_sockaddr_any(&bind_any); 907135446Strhodes result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, 908135446Strhodes &bind_any, PACKETSIZE, 909135446Strhodes 4, 2, 3, 5, 910135446Strhodes attrs, attrmask, &dispatchv4); 911135446Strhodes check_result(result, "dns_dispatch_getudp (v4)"); 912135446Strhodes } 913135446Strhodes 914135446Strhodes result = dns_requestmgr_create(mctx, timermgr, 915135446Strhodes socketmgr, taskmgr, dispatchmgr, 916135446Strhodes dispatchv4, dispatchv6, &requestmgr); 917135446Strhodes check_result(result, "dns_requestmgr_create"); 918135446Strhodes 919135446Strhodes if (keystr != NULL) 920135446Strhodes setup_keystr(); 921224092Sdougb else if (local_only) { 922224092Sdougb result = read_sessionkey(mctx, lctx); 923224092Sdougb if (result != ISC_R_SUCCESS) 924224092Sdougb fatal("can't read key from %s: %s\n", 925224092Sdougb keyfile, isc_result_totext(result)); 926224092Sdougb } else if (keyfile != NULL) 927224092Sdougb setup_keyfile(mctx, lctx); 928135446Strhodes} 929135446Strhodes 930135446Strhodesstatic void 931135446Strhodesget_address(char *host, in_port_t port, isc_sockaddr_t *sockaddr) { 932135446Strhodes int count; 933135446Strhodes isc_result_t result; 934135446Strhodes 935135446Strhodes isc_app_block(); 936135446Strhodes result = bind9_getaddresses(host, port, sockaddr, 1, &count); 937135446Strhodes isc_app_unblock(); 938135446Strhodes if (result != ISC_R_SUCCESS) 939135446Strhodes fatal("couldn't get address for '%s': %s", 940135446Strhodes host, isc_result_totext(result)); 941135446Strhodes INSIST(count == 1); 942135446Strhodes} 943135446Strhodes 944254402Serwin#define PARSE_ARGS_FMT "dDML:y:ghlovk:p:r:R::t:u:" 945193149Sdougb 946135446Strhodesstatic void 947193149Sdougbpre_parse_args(int argc, char **argv) { 948135446Strhodes int ch; 949193149Sdougb 950193149Sdougb while ((ch = isc_commandline_parse(argc, argv, PARSE_ARGS_FMT)) != -1) { 951193149Sdougb switch (ch) { 952193149Sdougb case 'M': /* was -dm */ 953193149Sdougb debugging = ISC_TRUE; 954193149Sdougb ddebugging = ISC_TRUE; 955193149Sdougb memdebugging = ISC_TRUE; 956193149Sdougb isc_mem_debugging = ISC_MEM_DEBUGTRACE | 957193149Sdougb ISC_MEM_DEBUGRECORD; 958193149Sdougb break; 959193149Sdougb 960193149Sdougb case '?': 961224092Sdougb case 'h': 962193149Sdougb if (isc_commandline_option != '?') 963193149Sdougb fprintf(stderr, "%s: invalid argument -%c\n", 964193149Sdougb argv[0], isc_commandline_option); 965224092Sdougb fprintf(stderr, "usage: nsupdate [-dD] [-L level] [-l]" 966193149Sdougb "[-g | -o | -y keyname:secret | -k keyfile] " 967193149Sdougb "[-v] [filename]\n"); 968193149Sdougb exit(1); 969193149Sdougb 970193149Sdougb default: 971193149Sdougb break; 972193149Sdougb } 973193149Sdougb } 974193149Sdougb isc_commandline_reset = ISC_TRUE; 975193149Sdougb isc_commandline_index = 1; 976193149Sdougb} 977193149Sdougb 978193149Sdougbstatic void 979193149Sdougbparse_args(int argc, char **argv, isc_mem_t *mctx, isc_entropy_t **ectx) { 980193149Sdougb int ch; 981193149Sdougb isc_uint32_t i; 982135446Strhodes isc_result_t result; 983135446Strhodes 984135446Strhodes debug("parse_args"); 985193149Sdougb while ((ch = isc_commandline_parse(argc, argv, PARSE_ARGS_FMT)) != -1) { 986135446Strhodes switch (ch) { 987135446Strhodes case 'd': 988135446Strhodes debugging = ISC_TRUE; 989135446Strhodes break; 990135446Strhodes case 'D': /* was -dd */ 991135446Strhodes debugging = ISC_TRUE; 992135446Strhodes ddebugging = ISC_TRUE; 993135446Strhodes break; 994193149Sdougb case 'M': 995135446Strhodes break; 996193149Sdougb case 'l': 997224092Sdougb local_only = ISC_TRUE; 998224092Sdougb break; 999224092Sdougb case 'L': 1000193149Sdougb result = isc_parse_uint32(&i, isc_commandline_argument, 1001193149Sdougb 10); 1002193149Sdougb if (result != ISC_R_SUCCESS) { 1003193149Sdougb fprintf(stderr, "bad library debug value " 1004193149Sdougb "'%s'\n", isc_commandline_argument); 1005193149Sdougb exit(1); 1006193149Sdougb } 1007193149Sdougb logdebuglevel = i; 1008193149Sdougb break; 1009135446Strhodes case 'y': 1010135446Strhodes keystr = isc_commandline_argument; 1011135446Strhodes break; 1012135446Strhodes case 'v': 1013135446Strhodes usevc = ISC_TRUE; 1014135446Strhodes break; 1015135446Strhodes case 'k': 1016135446Strhodes keyfile = isc_commandline_argument; 1017135446Strhodes break; 1018193149Sdougb case 'g': 1019193149Sdougb usegsstsig = ISC_TRUE; 1020193149Sdougb use_win2k_gsstsig = ISC_FALSE; 1021193149Sdougb break; 1022193149Sdougb case 'o': 1023193149Sdougb usegsstsig = ISC_TRUE; 1024193149Sdougb use_win2k_gsstsig = ISC_TRUE; 1025193149Sdougb break; 1026224092Sdougb case 'p': 1027224092Sdougb result = isc_parse_uint16(&dnsport, 1028224092Sdougb isc_commandline_argument, 10); 1029224092Sdougb if (result != ISC_R_SUCCESS) { 1030224092Sdougb fprintf(stderr, "bad port number " 1031224092Sdougb "'%s'\n", isc_commandline_argument); 1032224092Sdougb exit(1); 1033224092Sdougb } 1034224092Sdougb break; 1035135446Strhodes case 't': 1036135446Strhodes result = isc_parse_uint32(&timeout, 1037135446Strhodes isc_commandline_argument, 10); 1038135446Strhodes if (result != ISC_R_SUCCESS) { 1039135446Strhodes fprintf(stderr, "bad timeout '%s'\n", isc_commandline_argument); 1040135446Strhodes exit(1); 1041135446Strhodes } 1042135446Strhodes if (timeout == 0) 1043143731Sdougb timeout = UINT_MAX; 1044135446Strhodes break; 1045135446Strhodes case 'u': 1046135446Strhodes result = isc_parse_uint32(&udp_timeout, 1047135446Strhodes isc_commandline_argument, 10); 1048135446Strhodes if (result != ISC_R_SUCCESS) { 1049135446Strhodes fprintf(stderr, "bad udp timeout '%s'\n", isc_commandline_argument); 1050135446Strhodes exit(1); 1051135446Strhodes } 1052135446Strhodes if (udp_timeout == 0) 1053143731Sdougb udp_timeout = UINT_MAX; 1054135446Strhodes break; 1055135446Strhodes case 'r': 1056135446Strhodes result = isc_parse_uint32(&udp_retries, 1057135446Strhodes isc_commandline_argument, 10); 1058135446Strhodes if (result != ISC_R_SUCCESS) { 1059135446Strhodes fprintf(stderr, "bad udp retries '%s'\n", isc_commandline_argument); 1060135446Strhodes exit(1); 1061135446Strhodes } 1062135446Strhodes break; 1063193149Sdougb 1064193149Sdougb case 'R': 1065193149Sdougb setup_entropy(mctx, isc_commandline_argument, ectx); 1066193149Sdougb break; 1067193149Sdougb 1068135446Strhodes default: 1069193149Sdougb fprintf(stderr, "%s: unhandled option: %c\n", 1070193149Sdougb argv[0], isc_commandline_option); 1071135446Strhodes exit(1); 1072135446Strhodes } 1073135446Strhodes } 1074135446Strhodes if (keyfile != NULL && keystr != NULL) { 1075135446Strhodes fprintf(stderr, "%s: cannot specify both -k and -y\n", 1076135446Strhodes argv[0]); 1077135446Strhodes exit(1); 1078135446Strhodes } 1079135446Strhodes 1080224092Sdougb if (local_only) { 1081224092Sdougb struct in_addr localhost; 1082224092Sdougb 1083224092Sdougb if (keyfile == NULL) 1084224092Sdougb keyfile = SESSION_KEYFILE; 1085224092Sdougb 1086224092Sdougb if (userserver == NULL) { 1087224092Sdougb userserver = isc_mem_get(mctx, sizeof(isc_sockaddr_t)); 1088224092Sdougb if (userserver == NULL) 1089224092Sdougb fatal("out of memory"); 1090224092Sdougb } 1091224092Sdougb 1092224092Sdougb localhost.s_addr = htonl(INADDR_LOOPBACK); 1093224092Sdougb isc_sockaddr_fromin(userserver, &localhost, dnsport); 1094224092Sdougb } 1095224092Sdougb 1096193149Sdougb#ifdef GSSAPI 1097193149Sdougb if (usegsstsig && (keyfile != NULL || keystr != NULL)) { 1098193149Sdougb fprintf(stderr, "%s: cannot specify -g with -k or -y\n", 1099193149Sdougb argv[0]); 1100193149Sdougb exit(1); 1101193149Sdougb } 1102193149Sdougb#else 1103193149Sdougb if (usegsstsig) { 1104224092Sdougb fprintf(stderr, "%s: cannot specify -g or -o, " \ 1105193149Sdougb "program not linked with GSS API Library\n", 1106193149Sdougb argv[0]); 1107193149Sdougb exit(1); 1108193149Sdougb } 1109193149Sdougb#endif 1110193149Sdougb 1111135446Strhodes if (argv[isc_commandline_index] != NULL) { 1112135446Strhodes if (strcmp(argv[isc_commandline_index], "-") == 0) { 1113135446Strhodes input = stdin; 1114135446Strhodes } else { 1115135446Strhodes result = isc_stdio_open(argv[isc_commandline_index], 1116135446Strhodes "r", &input); 1117135446Strhodes if (result != ISC_R_SUCCESS) { 1118135446Strhodes fprintf(stderr, "could not open '%s': %s\n", 1119135446Strhodes argv[isc_commandline_index], 1120135446Strhodes isc_result_totext(result)); 1121135446Strhodes exit(1); 1122135446Strhodes } 1123135446Strhodes } 1124135446Strhodes interactive = ISC_FALSE; 1125135446Strhodes } 1126135446Strhodes} 1127135446Strhodes 1128135446Strhodesstatic isc_uint16_t 1129135446Strhodesparse_name(char **cmdlinep, dns_message_t *msg, dns_name_t **namep) { 1130135446Strhodes isc_result_t result; 1131135446Strhodes char *word; 1132135446Strhodes isc_buffer_t *namebuf = NULL; 1133135446Strhodes isc_buffer_t source; 1134135446Strhodes 1135135446Strhodes word = nsu_strsep(cmdlinep, " \t\r\n"); 1136245163Serwin if (word == NULL || *word == 0) { 1137135446Strhodes fprintf(stderr, "could not read owner name\n"); 1138135446Strhodes return (STATUS_SYNTAX); 1139135446Strhodes } 1140135446Strhodes 1141135446Strhodes result = dns_message_gettempname(msg, namep); 1142135446Strhodes check_result(result, "dns_message_gettempname"); 1143135446Strhodes result = isc_buffer_allocate(mctx, &namebuf, DNS_NAME_MAXWIRE); 1144135446Strhodes check_result(result, "isc_buffer_allocate"); 1145135446Strhodes dns_name_init(*namep, NULL); 1146135446Strhodes dns_name_setbuffer(*namep, namebuf); 1147135446Strhodes dns_message_takebuffer(msg, &namebuf); 1148135446Strhodes isc_buffer_init(&source, word, strlen(word)); 1149135446Strhodes isc_buffer_add(&source, strlen(word)); 1150224092Sdougb result = dns_name_fromtext(*namep, &source, dns_rootname, 0, NULL); 1151135446Strhodes check_result(result, "dns_name_fromtext"); 1152135446Strhodes isc_buffer_invalidate(&source); 1153135446Strhodes return (STATUS_MORE); 1154135446Strhodes} 1155135446Strhodes 1156135446Strhodesstatic isc_uint16_t 1157135446Strhodesparse_rdata(char **cmdlinep, dns_rdataclass_t rdataclass, 1158135446Strhodes dns_rdatatype_t rdatatype, dns_message_t *msg, 1159135446Strhodes dns_rdata_t *rdata) 1160135446Strhodes{ 1161135446Strhodes char *cmdline = *cmdlinep; 1162135446Strhodes isc_buffer_t source, *buf = NULL, *newbuf = NULL; 1163135446Strhodes isc_region_t r; 1164135446Strhodes isc_lex_t *lex = NULL; 1165135446Strhodes dns_rdatacallbacks_t callbacks; 1166135446Strhodes isc_result_t result; 1167135446Strhodes 1168245163Serwin if (cmdline == NULL) { 1169245163Serwin rdata->flags = DNS_RDATA_UPDATE; 1170245163Serwin return (STATUS_MORE); 1171245163Serwin } 1172245163Serwin 1173135446Strhodes while (*cmdline != 0 && isspace((unsigned char)*cmdline)) 1174135446Strhodes cmdline++; 1175135446Strhodes 1176135446Strhodes if (*cmdline != 0) { 1177135446Strhodes dns_rdatacallbacks_init(&callbacks); 1178135446Strhodes result = isc_lex_create(mctx, strlen(cmdline), &lex); 1179135446Strhodes check_result(result, "isc_lex_create"); 1180135446Strhodes isc_buffer_init(&source, cmdline, strlen(cmdline)); 1181135446Strhodes isc_buffer_add(&source, strlen(cmdline)); 1182135446Strhodes result = isc_lex_openbuffer(lex, &source); 1183135446Strhodes check_result(result, "isc_lex_openbuffer"); 1184135446Strhodes result = isc_buffer_allocate(mctx, &buf, MAXWIRE); 1185135446Strhodes check_result(result, "isc_buffer_allocate"); 1186193149Sdougb result = dns_rdata_fromtext(NULL, rdataclass, rdatatype, lex, 1187135446Strhodes dns_rootname, 0, mctx, buf, 1188135446Strhodes &callbacks); 1189135446Strhodes isc_lex_destroy(&lex); 1190135446Strhodes if (result == ISC_R_SUCCESS) { 1191135446Strhodes isc_buffer_usedregion(buf, &r); 1192135446Strhodes result = isc_buffer_allocate(mctx, &newbuf, r.length); 1193135446Strhodes check_result(result, "isc_buffer_allocate"); 1194135446Strhodes isc_buffer_putmem(newbuf, r.base, r.length); 1195135446Strhodes isc_buffer_usedregion(newbuf, &r); 1196135446Strhodes dns_rdata_fromregion(rdata, rdataclass, rdatatype, &r); 1197135446Strhodes isc_buffer_free(&buf); 1198135446Strhodes dns_message_takebuffer(msg, &newbuf); 1199135446Strhodes } else { 1200135446Strhodes fprintf(stderr, "invalid rdata format: %s\n", 1201135446Strhodes isc_result_totext(result)); 1202135446Strhodes isc_buffer_free(&buf); 1203135446Strhodes return (STATUS_SYNTAX); 1204135446Strhodes } 1205135446Strhodes } else { 1206135446Strhodes rdata->flags = DNS_RDATA_UPDATE; 1207135446Strhodes } 1208135446Strhodes *cmdlinep = cmdline; 1209135446Strhodes return (STATUS_MORE); 1210135446Strhodes} 1211135446Strhodes 1212135446Strhodesstatic isc_uint16_t 1213135446Strhodesmake_prereq(char *cmdline, isc_boolean_t ispositive, isc_boolean_t isrrset) { 1214135446Strhodes isc_result_t result; 1215135446Strhodes char *word; 1216135446Strhodes dns_name_t *name = NULL; 1217135446Strhodes isc_textregion_t region; 1218135446Strhodes dns_rdataset_t *rdataset = NULL; 1219135446Strhodes dns_rdatalist_t *rdatalist = NULL; 1220135446Strhodes dns_rdataclass_t rdataclass; 1221135446Strhodes dns_rdatatype_t rdatatype; 1222135446Strhodes dns_rdata_t *rdata = NULL; 1223135446Strhodes isc_uint16_t retval; 1224135446Strhodes 1225135446Strhodes ddebug("make_prereq()"); 1226135446Strhodes 1227135446Strhodes /* 1228135446Strhodes * Read the owner name 1229135446Strhodes */ 1230135446Strhodes retval = parse_name(&cmdline, updatemsg, &name); 1231135446Strhodes if (retval != STATUS_MORE) 1232135446Strhodes return (retval); 1233135446Strhodes 1234135446Strhodes /* 1235135446Strhodes * If this is an rrset prereq, read the class or type. 1236135446Strhodes */ 1237135446Strhodes if (isrrset) { 1238135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1239245163Serwin if (word == NULL || *word == 0) { 1240135446Strhodes fprintf(stderr, "could not read class or type\n"); 1241135446Strhodes goto failure; 1242135446Strhodes } 1243135446Strhodes region.base = word; 1244135446Strhodes region.length = strlen(word); 1245135446Strhodes result = dns_rdataclass_fromtext(&rdataclass, ®ion); 1246135446Strhodes if (result == ISC_R_SUCCESS) { 1247135446Strhodes if (!setzoneclass(rdataclass)) { 1248135446Strhodes fprintf(stderr, "class mismatch: %s\n", word); 1249135446Strhodes goto failure; 1250135446Strhodes } 1251135446Strhodes /* 1252135446Strhodes * Now read the type. 1253135446Strhodes */ 1254135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1255245163Serwin if (word == NULL || *word == 0) { 1256135446Strhodes fprintf(stderr, "could not read type\n"); 1257135446Strhodes goto failure; 1258135446Strhodes } 1259135446Strhodes region.base = word; 1260135446Strhodes region.length = strlen(word); 1261135446Strhodes result = dns_rdatatype_fromtext(&rdatatype, ®ion); 1262135446Strhodes if (result != ISC_R_SUCCESS) { 1263135446Strhodes fprintf(stderr, "invalid type: %s\n", word); 1264135446Strhodes goto failure; 1265135446Strhodes } 1266135446Strhodes } else { 1267135446Strhodes rdataclass = getzoneclass(); 1268135446Strhodes result = dns_rdatatype_fromtext(&rdatatype, ®ion); 1269135446Strhodes if (result != ISC_R_SUCCESS) { 1270135446Strhodes fprintf(stderr, "invalid type: %s\n", word); 1271135446Strhodes goto failure; 1272135446Strhodes } 1273135446Strhodes } 1274135446Strhodes } else 1275135446Strhodes rdatatype = dns_rdatatype_any; 1276135446Strhodes 1277135446Strhodes result = dns_message_gettemprdata(updatemsg, &rdata); 1278135446Strhodes check_result(result, "dns_message_gettemprdata"); 1279135446Strhodes 1280193149Sdougb dns_rdata_init(rdata); 1281135446Strhodes 1282135446Strhodes if (isrrset && ispositive) { 1283135446Strhodes retval = parse_rdata(&cmdline, rdataclass, rdatatype, 1284135446Strhodes updatemsg, rdata); 1285135446Strhodes if (retval != STATUS_MORE) 1286135446Strhodes goto failure; 1287135446Strhodes } else 1288135446Strhodes rdata->flags = DNS_RDATA_UPDATE; 1289135446Strhodes 1290135446Strhodes result = dns_message_gettemprdatalist(updatemsg, &rdatalist); 1291135446Strhodes check_result(result, "dns_message_gettemprdatalist"); 1292135446Strhodes result = dns_message_gettemprdataset(updatemsg, &rdataset); 1293135446Strhodes check_result(result, "dns_message_gettemprdataset"); 1294135446Strhodes dns_rdatalist_init(rdatalist); 1295135446Strhodes rdatalist->type = rdatatype; 1296135446Strhodes if (ispositive) { 1297135446Strhodes if (isrrset && rdata->data != NULL) 1298135446Strhodes rdatalist->rdclass = rdataclass; 1299135446Strhodes else 1300135446Strhodes rdatalist->rdclass = dns_rdataclass_any; 1301135446Strhodes } else 1302135446Strhodes rdatalist->rdclass = dns_rdataclass_none; 1303135446Strhodes rdatalist->covers = 0; 1304135446Strhodes rdatalist->ttl = 0; 1305135446Strhodes rdata->rdclass = rdatalist->rdclass; 1306135446Strhodes rdata->type = rdatatype; 1307135446Strhodes ISC_LIST_INIT(rdatalist->rdata); 1308135446Strhodes ISC_LIST_APPEND(rdatalist->rdata, rdata, link); 1309135446Strhodes dns_rdataset_init(rdataset); 1310135446Strhodes dns_rdatalist_tordataset(rdatalist, rdataset); 1311135446Strhodes ISC_LIST_INIT(name->list); 1312135446Strhodes ISC_LIST_APPEND(name->list, rdataset, link); 1313135446Strhodes dns_message_addname(updatemsg, name, DNS_SECTION_PREREQUISITE); 1314135446Strhodes return (STATUS_MORE); 1315135446Strhodes 1316135446Strhodes failure: 1317135446Strhodes if (name != NULL) 1318135446Strhodes dns_message_puttempname(updatemsg, &name); 1319135446Strhodes return (STATUS_SYNTAX); 1320135446Strhodes} 1321135446Strhodes 1322135446Strhodesstatic isc_uint16_t 1323135446Strhodesevaluate_prereq(char *cmdline) { 1324135446Strhodes char *word; 1325135446Strhodes isc_boolean_t ispositive, isrrset; 1326135446Strhodes 1327135446Strhodes ddebug("evaluate_prereq()"); 1328135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1329245163Serwin if (word == NULL || *word == 0) { 1330135446Strhodes fprintf(stderr, "could not read operation code\n"); 1331135446Strhodes return (STATUS_SYNTAX); 1332135446Strhodes } 1333135446Strhodes if (strcasecmp(word, "nxdomain") == 0) { 1334135446Strhodes ispositive = ISC_FALSE; 1335135446Strhodes isrrset = ISC_FALSE; 1336135446Strhodes } else if (strcasecmp(word, "yxdomain") == 0) { 1337135446Strhodes ispositive = ISC_TRUE; 1338135446Strhodes isrrset = ISC_FALSE; 1339135446Strhodes } else if (strcasecmp(word, "nxrrset") == 0) { 1340135446Strhodes ispositive = ISC_FALSE; 1341135446Strhodes isrrset = ISC_TRUE; 1342135446Strhodes } else if (strcasecmp(word, "yxrrset") == 0) { 1343135446Strhodes ispositive = ISC_TRUE; 1344135446Strhodes isrrset = ISC_TRUE; 1345135446Strhodes } else { 1346135446Strhodes fprintf(stderr, "incorrect operation code: %s\n", word); 1347135446Strhodes return (STATUS_SYNTAX); 1348135446Strhodes } 1349135446Strhodes return (make_prereq(cmdline, ispositive, isrrset)); 1350135446Strhodes} 1351135446Strhodes 1352135446Strhodesstatic isc_uint16_t 1353135446Strhodesevaluate_server(char *cmdline) { 1354135446Strhodes char *word, *server; 1355135446Strhodes long port; 1356135446Strhodes 1357224092Sdougb if (local_only) { 1358224092Sdougb fprintf(stderr, "cannot reset server in localhost-only mode\n"); 1359224092Sdougb return (STATUS_SYNTAX); 1360224092Sdougb } 1361224092Sdougb 1362135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1363245163Serwin if (word == NULL || *word == 0) { 1364135446Strhodes fprintf(stderr, "could not read server name\n"); 1365135446Strhodes return (STATUS_SYNTAX); 1366135446Strhodes } 1367135446Strhodes server = word; 1368135446Strhodes 1369135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1370245163Serwin if (word == NULL || *word == 0) 1371224092Sdougb port = dnsport; 1372135446Strhodes else { 1373135446Strhodes char *endp; 1374135446Strhodes port = strtol(word, &endp, 10); 1375135446Strhodes if (*endp != 0) { 1376135446Strhodes fprintf(stderr, "port '%s' is not numeric\n", word); 1377135446Strhodes return (STATUS_SYNTAX); 1378135446Strhodes } else if (port < 1 || port > 65535) { 1379135446Strhodes fprintf(stderr, "port '%s' is out of range " 1380135446Strhodes "(1 to 65535)\n", word); 1381135446Strhodes return (STATUS_SYNTAX); 1382135446Strhodes } 1383135446Strhodes } 1384135446Strhodes 1385135446Strhodes if (userserver == NULL) { 1386135446Strhodes userserver = isc_mem_get(mctx, sizeof(isc_sockaddr_t)); 1387135446Strhodes if (userserver == NULL) 1388135446Strhodes fatal("out of memory"); 1389135446Strhodes } 1390135446Strhodes 1391135446Strhodes get_address(server, (in_port_t)port, userserver); 1392135446Strhodes 1393135446Strhodes return (STATUS_MORE); 1394135446Strhodes} 1395135446Strhodes 1396135446Strhodesstatic isc_uint16_t 1397135446Strhodesevaluate_local(char *cmdline) { 1398135446Strhodes char *word, *local; 1399135446Strhodes long port; 1400135446Strhodes struct in_addr in4; 1401135446Strhodes struct in6_addr in6; 1402135446Strhodes 1403135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1404245163Serwin if (word == NULL || *word == 0) { 1405135446Strhodes fprintf(stderr, "could not read server name\n"); 1406135446Strhodes return (STATUS_SYNTAX); 1407135446Strhodes } 1408135446Strhodes local = word; 1409135446Strhodes 1410135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1411245163Serwin if (word == NULL || *word == 0) 1412135446Strhodes port = 0; 1413135446Strhodes else { 1414135446Strhodes char *endp; 1415135446Strhodes port = strtol(word, &endp, 10); 1416135446Strhodes if (*endp != 0) { 1417135446Strhodes fprintf(stderr, "port '%s' is not numeric\n", word); 1418135446Strhodes return (STATUS_SYNTAX); 1419135446Strhodes } else if (port < 1 || port > 65535) { 1420135446Strhodes fprintf(stderr, "port '%s' is out of range " 1421135446Strhodes "(1 to 65535)\n", word); 1422135446Strhodes return (STATUS_SYNTAX); 1423135446Strhodes } 1424135446Strhodes } 1425135446Strhodes 1426135446Strhodes if (localaddr == NULL) { 1427135446Strhodes localaddr = isc_mem_get(mctx, sizeof(isc_sockaddr_t)); 1428135446Strhodes if (localaddr == NULL) 1429135446Strhodes fatal("out of memory"); 1430135446Strhodes } 1431135446Strhodes 1432135446Strhodes if (have_ipv6 && inet_pton(AF_INET6, local, &in6) == 1) 1433135446Strhodes isc_sockaddr_fromin6(localaddr, &in6, (in_port_t)port); 1434135446Strhodes else if (have_ipv4 && inet_pton(AF_INET, local, &in4) == 1) 1435135446Strhodes isc_sockaddr_fromin(localaddr, &in4, (in_port_t)port); 1436135446Strhodes else { 1437135446Strhodes fprintf(stderr, "invalid address %s", local); 1438135446Strhodes return (STATUS_SYNTAX); 1439135446Strhodes } 1440135446Strhodes 1441135446Strhodes return (STATUS_MORE); 1442135446Strhodes} 1443135446Strhodes 1444135446Strhodesstatic isc_uint16_t 1445135446Strhodesevaluate_key(char *cmdline) { 1446135446Strhodes char *namestr; 1447135446Strhodes char *secretstr; 1448135446Strhodes isc_buffer_t b; 1449135446Strhodes isc_result_t result; 1450135446Strhodes dns_fixedname_t fkeyname; 1451135446Strhodes dns_name_t *keyname; 1452135446Strhodes int secretlen; 1453135446Strhodes unsigned char *secret = NULL; 1454135446Strhodes isc_buffer_t secretbuf; 1455170222Sdougb dns_name_t *hmacname = NULL; 1456170222Sdougb isc_uint16_t digestbits = 0; 1457170222Sdougb char *n; 1458135446Strhodes 1459135446Strhodes namestr = nsu_strsep(&cmdline, " \t\r\n"); 1460245163Serwin if (namestr == NULL || *namestr == 0) { 1461135446Strhodes fprintf(stderr, "could not read key name\n"); 1462135446Strhodes return (STATUS_SYNTAX); 1463135446Strhodes } 1464135446Strhodes 1465135446Strhodes dns_fixedname_init(&fkeyname); 1466135446Strhodes keyname = dns_fixedname_name(&fkeyname); 1467135446Strhodes 1468170222Sdougb n = strchr(namestr, ':'); 1469170222Sdougb if (n != NULL) { 1470170222Sdougb digestbits = parse_hmac(&hmacname, namestr, n - namestr); 1471170222Sdougb namestr = n + 1; 1472170222Sdougb } else 1473170222Sdougb hmacname = DNS_TSIG_HMACMD5_NAME; 1474170222Sdougb 1475135446Strhodes isc_buffer_init(&b, namestr, strlen(namestr)); 1476135446Strhodes isc_buffer_add(&b, strlen(namestr)); 1477224092Sdougb result = dns_name_fromtext(keyname, &b, dns_rootname, 0, NULL); 1478135446Strhodes if (result != ISC_R_SUCCESS) { 1479135446Strhodes fprintf(stderr, "could not parse key name\n"); 1480135446Strhodes return (STATUS_SYNTAX); 1481135446Strhodes } 1482135446Strhodes 1483135446Strhodes secretstr = nsu_strsep(&cmdline, "\r\n"); 1484245163Serwin if (secretstr == NULL || *secretstr == 0) { 1485135446Strhodes fprintf(stderr, "could not read key secret\n"); 1486135446Strhodes return (STATUS_SYNTAX); 1487135446Strhodes } 1488135446Strhodes secretlen = strlen(secretstr) * 3 / 4; 1489135446Strhodes secret = isc_mem_allocate(mctx, secretlen); 1490135446Strhodes if (secret == NULL) 1491135446Strhodes fatal("out of memory"); 1492186462Sdougb 1493135446Strhodes isc_buffer_init(&secretbuf, secret, secretlen); 1494135446Strhodes result = isc_base64_decodestring(secretstr, &secretbuf); 1495135446Strhodes if (result != ISC_R_SUCCESS) { 1496135446Strhodes fprintf(stderr, "could not create key from %s: %s\n", 1497135446Strhodes secretstr, isc_result_totext(result)); 1498135446Strhodes isc_mem_free(mctx, secret); 1499135446Strhodes return (STATUS_SYNTAX); 1500135446Strhodes } 1501135446Strhodes secretlen = isc_buffer_usedlength(&secretbuf); 1502135446Strhodes 1503135446Strhodes if (tsigkey != NULL) 1504135446Strhodes dns_tsigkey_detach(&tsigkey); 1505170222Sdougb result = dns_tsigkey_create(keyname, hmacname, secret, secretlen, 1506218384Sdougb ISC_FALSE, NULL, 0, 0, mctx, NULL, 1507170222Sdougb &tsigkey); 1508135446Strhodes isc_mem_free(mctx, secret); 1509135446Strhodes if (result != ISC_R_SUCCESS) { 1510135446Strhodes fprintf(stderr, "could not create key from %s %s: %s\n", 1511135446Strhodes namestr, secretstr, dns_result_totext(result)); 1512135446Strhodes return (STATUS_SYNTAX); 1513135446Strhodes } 1514170222Sdougb dst_key_setbits(tsigkey->key, digestbits); 1515135446Strhodes return (STATUS_MORE); 1516135446Strhodes} 1517135446Strhodes 1518135446Strhodesstatic isc_uint16_t 1519135446Strhodesevaluate_zone(char *cmdline) { 1520135446Strhodes char *word; 1521135446Strhodes isc_buffer_t b; 1522135446Strhodes isc_result_t result; 1523135446Strhodes 1524135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1525245163Serwin if (word == NULL || *word == 0) { 1526135446Strhodes fprintf(stderr, "could not read zone name\n"); 1527135446Strhodes return (STATUS_SYNTAX); 1528135446Strhodes } 1529135446Strhodes 1530135446Strhodes dns_fixedname_init(&fuserzone); 1531135446Strhodes userzone = dns_fixedname_name(&fuserzone); 1532135446Strhodes isc_buffer_init(&b, word, strlen(word)); 1533135446Strhodes isc_buffer_add(&b, strlen(word)); 1534224092Sdougb result = dns_name_fromtext(userzone, &b, dns_rootname, 0, NULL); 1535135446Strhodes if (result != ISC_R_SUCCESS) { 1536135446Strhodes userzone = NULL; /* Lest it point to an invalid name */ 1537135446Strhodes fprintf(stderr, "could not parse zone name\n"); 1538135446Strhodes return (STATUS_SYNTAX); 1539135446Strhodes } 1540135446Strhodes 1541135446Strhodes return (STATUS_MORE); 1542135446Strhodes} 1543135446Strhodes 1544135446Strhodesstatic isc_uint16_t 1545218384Sdougbevaluate_realm(char *cmdline) { 1546218384Sdougb#ifdef GSSAPI 1547218384Sdougb char *word; 1548218384Sdougb char buf[1024]; 1549262706Serwin int n; 1550218384Sdougb 1551262706Serwin if (realm != NULL) { 1552262706Serwin isc_mem_free(mctx, realm); 1553218384Sdougb realm = NULL; 1554218384Sdougb } 1555218384Sdougb 1556262706Serwin word = nsu_strsep(&cmdline, " \t\r\n"); 1557262706Serwin if (word == NULL || *word == 0) 1558262706Serwin return (STATUS_MORE); 1559262706Serwin 1560262706Serwin n = snprintf(buf, sizeof(buf), "@%s", word); 1561262706Serwin if (n < 0 || (size_t)n >= sizeof(buf)) 1562262706Serwin fatal("realm is too long"); 1563218384Sdougb realm = isc_mem_strdup(mctx, buf); 1564218384Sdougb if (realm == NULL) 1565218384Sdougb fatal("out of memory"); 1566218384Sdougb return (STATUS_MORE); 1567218384Sdougb#else 1568218384Sdougb UNUSED(cmdline); 1569218384Sdougb return (STATUS_SYNTAX); 1570218384Sdougb#endif 1571218384Sdougb} 1572218384Sdougb 1573218384Sdougbstatic isc_uint16_t 1574193149Sdougbevaluate_ttl(char *cmdline) { 1575193149Sdougb char *word; 1576193149Sdougb isc_result_t result; 1577193149Sdougb isc_uint32_t ttl; 1578193149Sdougb 1579193149Sdougb word = nsu_strsep(&cmdline, " \t\r\n"); 1580245163Serwin if (word == NULL || *word == 0) { 1581193149Sdougb fprintf(stderr, "could not ttl\n"); 1582193149Sdougb return (STATUS_SYNTAX); 1583193149Sdougb } 1584193149Sdougb 1585193149Sdougb if (!strcasecmp(word, "none")) { 1586193149Sdougb default_ttl = 0; 1587193149Sdougb default_ttl_set = ISC_FALSE; 1588193149Sdougb return (STATUS_MORE); 1589193149Sdougb } 1590193149Sdougb 1591193149Sdougb result = isc_parse_uint32(&ttl, word, 10); 1592193149Sdougb if (result != ISC_R_SUCCESS) 1593193149Sdougb return (STATUS_SYNTAX); 1594193149Sdougb 1595193149Sdougb if (ttl > TTL_MAX) { 1596193149Sdougb fprintf(stderr, "ttl '%s' is out of range (0 to %u)\n", 1597193149Sdougb word, TTL_MAX); 1598193149Sdougb return (STATUS_SYNTAX); 1599193149Sdougb } 1600193149Sdougb default_ttl = ttl; 1601193149Sdougb default_ttl_set = ISC_TRUE; 1602193149Sdougb 1603193149Sdougb return (STATUS_MORE); 1604193149Sdougb} 1605193149Sdougb 1606193149Sdougbstatic isc_uint16_t 1607135446Strhodesevaluate_class(char *cmdline) { 1608135446Strhodes char *word; 1609135446Strhodes isc_textregion_t r; 1610135446Strhodes isc_result_t result; 1611135446Strhodes dns_rdataclass_t rdclass; 1612135446Strhodes 1613135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1614245163Serwin if (word == NULL || *word == 0) { 1615135446Strhodes fprintf(stderr, "could not read class name\n"); 1616135446Strhodes return (STATUS_SYNTAX); 1617135446Strhodes } 1618135446Strhodes 1619135446Strhodes r.base = word; 1620186462Sdougb r.length = strlen(word); 1621186462Sdougb result = dns_rdataclass_fromtext(&rdclass, &r); 1622135446Strhodes if (result != ISC_R_SUCCESS) { 1623135446Strhodes fprintf(stderr, "could not parse class name: %s\n", word); 1624135446Strhodes return (STATUS_SYNTAX); 1625135446Strhodes } 1626135446Strhodes switch (rdclass) { 1627135446Strhodes case dns_rdataclass_none: 1628135446Strhodes case dns_rdataclass_any: 1629135446Strhodes case dns_rdataclass_reserved0: 1630135446Strhodes fprintf(stderr, "bad default class: %s\n", word); 1631135446Strhodes return (STATUS_SYNTAX); 1632135446Strhodes default: 1633135446Strhodes defaultclass = rdclass; 1634135446Strhodes } 1635135446Strhodes 1636135446Strhodes return (STATUS_MORE); 1637135446Strhodes} 1638135446Strhodes 1639135446Strhodesstatic isc_uint16_t 1640135446Strhodesupdate_addordelete(char *cmdline, isc_boolean_t isdelete) { 1641135446Strhodes isc_result_t result; 1642135446Strhodes dns_name_t *name = NULL; 1643135446Strhodes isc_uint32_t ttl; 1644135446Strhodes char *word; 1645135446Strhodes dns_rdataclass_t rdataclass; 1646135446Strhodes dns_rdatatype_t rdatatype; 1647135446Strhodes dns_rdata_t *rdata = NULL; 1648135446Strhodes dns_rdatalist_t *rdatalist = NULL; 1649135446Strhodes dns_rdataset_t *rdataset = NULL; 1650135446Strhodes isc_textregion_t region; 1651135446Strhodes isc_uint16_t retval; 1652135446Strhodes 1653135446Strhodes ddebug("update_addordelete()"); 1654135446Strhodes 1655135446Strhodes /* 1656135446Strhodes * Read the owner name. 1657135446Strhodes */ 1658135446Strhodes retval = parse_name(&cmdline, updatemsg, &name); 1659135446Strhodes if (retval != STATUS_MORE) 1660135446Strhodes return (retval); 1661135446Strhodes 1662135446Strhodes result = dns_message_gettemprdata(updatemsg, &rdata); 1663135446Strhodes check_result(result, "dns_message_gettemprdata"); 1664135446Strhodes 1665193149Sdougb dns_rdata_init(rdata); 1666135446Strhodes 1667135446Strhodes /* 1668135446Strhodes * If this is an add, read the TTL and verify that it's in range. 1669135446Strhodes * If it's a delete, ignore a TTL if present (for compatibility). 1670135446Strhodes */ 1671135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1672245163Serwin if (word == NULL || *word == 0) { 1673135446Strhodes if (!isdelete) { 1674135446Strhodes fprintf(stderr, "could not read owner ttl\n"); 1675135446Strhodes goto failure; 1676135446Strhodes } 1677135446Strhodes else { 1678135446Strhodes ttl = 0; 1679135446Strhodes rdataclass = dns_rdataclass_any; 1680135446Strhodes rdatatype = dns_rdatatype_any; 1681135446Strhodes rdata->flags = DNS_RDATA_UPDATE; 1682135446Strhodes goto doneparsing; 1683135446Strhodes } 1684135446Strhodes } 1685135446Strhodes result = isc_parse_uint32(&ttl, word, 10); 1686135446Strhodes if (result != ISC_R_SUCCESS) { 1687135446Strhodes if (isdelete) { 1688135446Strhodes ttl = 0; 1689135446Strhodes goto parseclass; 1690193149Sdougb } else if (default_ttl_set) { 1691193149Sdougb ttl = default_ttl; 1692193149Sdougb goto parseclass; 1693135446Strhodes } else { 1694135446Strhodes fprintf(stderr, "ttl '%s': %s\n", word, 1695135446Strhodes isc_result_totext(result)); 1696135446Strhodes goto failure; 1697135446Strhodes } 1698135446Strhodes } 1699135446Strhodes 1700135446Strhodes if (isdelete) 1701135446Strhodes ttl = 0; 1702135446Strhodes else if (ttl > TTL_MAX) { 1703135446Strhodes fprintf(stderr, "ttl '%s' is out of range (0 to %u)\n", 1704135446Strhodes word, TTL_MAX); 1705135446Strhodes goto failure; 1706135446Strhodes } 1707135446Strhodes 1708135446Strhodes /* 1709135446Strhodes * Read the class or type. 1710135446Strhodes */ 1711135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1712135446Strhodes parseclass: 1713245163Serwin if (word == NULL || *word == 0) { 1714135446Strhodes if (isdelete) { 1715135446Strhodes rdataclass = dns_rdataclass_any; 1716135446Strhodes rdatatype = dns_rdatatype_any; 1717135446Strhodes rdata->flags = DNS_RDATA_UPDATE; 1718135446Strhodes goto doneparsing; 1719135446Strhodes } else { 1720135446Strhodes fprintf(stderr, "could not read class or type\n"); 1721135446Strhodes goto failure; 1722135446Strhodes } 1723135446Strhodes } 1724135446Strhodes region.base = word; 1725135446Strhodes region.length = strlen(word); 1726193149Sdougb rdataclass = dns_rdataclass_any; 1727135446Strhodes result = dns_rdataclass_fromtext(&rdataclass, ®ion); 1728193149Sdougb if (result == ISC_R_SUCCESS && rdataclass != dns_rdataclass_any) { 1729135446Strhodes if (!setzoneclass(rdataclass)) { 1730135446Strhodes fprintf(stderr, "class mismatch: %s\n", word); 1731135446Strhodes goto failure; 1732135446Strhodes } 1733135446Strhodes /* 1734135446Strhodes * Now read the type. 1735135446Strhodes */ 1736135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1737245163Serwin if (word == NULL || *word == 0) { 1738135446Strhodes if (isdelete) { 1739135446Strhodes rdataclass = dns_rdataclass_any; 1740135446Strhodes rdatatype = dns_rdatatype_any; 1741135446Strhodes rdata->flags = DNS_RDATA_UPDATE; 1742135446Strhodes goto doneparsing; 1743135446Strhodes } else { 1744135446Strhodes fprintf(stderr, "could not read type\n"); 1745135446Strhodes goto failure; 1746135446Strhodes } 1747135446Strhodes } 1748135446Strhodes region.base = word; 1749135446Strhodes region.length = strlen(word); 1750135446Strhodes result = dns_rdatatype_fromtext(&rdatatype, ®ion); 1751135446Strhodes if (result != ISC_R_SUCCESS) { 1752135446Strhodes fprintf(stderr, "'%s' is not a valid type: %s\n", 1753135446Strhodes word, isc_result_totext(result)); 1754135446Strhodes goto failure; 1755135446Strhodes } 1756135446Strhodes } else { 1757135446Strhodes rdataclass = getzoneclass(); 1758135446Strhodes result = dns_rdatatype_fromtext(&rdatatype, ®ion); 1759135446Strhodes if (result != ISC_R_SUCCESS) { 1760135446Strhodes fprintf(stderr, "'%s' is not a valid class or type: " 1761135446Strhodes "%s\n", word, isc_result_totext(result)); 1762135446Strhodes goto failure; 1763135446Strhodes } 1764135446Strhodes } 1765135446Strhodes 1766135446Strhodes retval = parse_rdata(&cmdline, rdataclass, rdatatype, updatemsg, 1767135446Strhodes rdata); 1768135446Strhodes if (retval != STATUS_MORE) 1769135446Strhodes goto failure; 1770135446Strhodes 1771135446Strhodes if (isdelete) { 1772135446Strhodes if ((rdata->flags & DNS_RDATA_UPDATE) != 0) 1773135446Strhodes rdataclass = dns_rdataclass_any; 1774135446Strhodes else 1775135446Strhodes rdataclass = dns_rdataclass_none; 1776135446Strhodes } else { 1777135446Strhodes if ((rdata->flags & DNS_RDATA_UPDATE) != 0) { 1778135446Strhodes fprintf(stderr, "could not read rdata\n"); 1779135446Strhodes goto failure; 1780135446Strhodes } 1781135446Strhodes } 1782135446Strhodes 1783135446Strhodes doneparsing: 1784135446Strhodes 1785135446Strhodes result = dns_message_gettemprdatalist(updatemsg, &rdatalist); 1786135446Strhodes check_result(result, "dns_message_gettemprdatalist"); 1787135446Strhodes result = dns_message_gettemprdataset(updatemsg, &rdataset); 1788135446Strhodes check_result(result, "dns_message_gettemprdataset"); 1789135446Strhodes dns_rdatalist_init(rdatalist); 1790135446Strhodes rdatalist->type = rdatatype; 1791135446Strhodes rdatalist->rdclass = rdataclass; 1792135446Strhodes rdatalist->covers = rdatatype; 1793135446Strhodes rdatalist->ttl = (dns_ttl_t)ttl; 1794135446Strhodes ISC_LIST_INIT(rdatalist->rdata); 1795135446Strhodes ISC_LIST_APPEND(rdatalist->rdata, rdata, link); 1796135446Strhodes dns_rdataset_init(rdataset); 1797135446Strhodes dns_rdatalist_tordataset(rdatalist, rdataset); 1798135446Strhodes ISC_LIST_INIT(name->list); 1799135446Strhodes ISC_LIST_APPEND(name->list, rdataset, link); 1800135446Strhodes dns_message_addname(updatemsg, name, DNS_SECTION_UPDATE); 1801135446Strhodes return (STATUS_MORE); 1802135446Strhodes 1803135446Strhodes failure: 1804135446Strhodes if (name != NULL) 1805135446Strhodes dns_message_puttempname(updatemsg, &name); 1806186462Sdougb dns_message_puttemprdata(updatemsg, &rdata); 1807135446Strhodes return (STATUS_SYNTAX); 1808135446Strhodes} 1809135446Strhodes 1810135446Strhodesstatic isc_uint16_t 1811135446Strhodesevaluate_update(char *cmdline) { 1812135446Strhodes char *word; 1813135446Strhodes isc_boolean_t isdelete; 1814135446Strhodes 1815135446Strhodes ddebug("evaluate_update()"); 1816135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1817245163Serwin if (word == NULL || *word == 0) { 1818135446Strhodes fprintf(stderr, "could not read operation code\n"); 1819135446Strhodes return (STATUS_SYNTAX); 1820135446Strhodes } 1821135446Strhodes if (strcasecmp(word, "delete") == 0) 1822135446Strhodes isdelete = ISC_TRUE; 1823254897Serwin else if (strcasecmp(word, "del") == 0) 1824254897Serwin isdelete = ISC_TRUE; 1825135446Strhodes else if (strcasecmp(word, "add") == 0) 1826135446Strhodes isdelete = ISC_FALSE; 1827135446Strhodes else { 1828135446Strhodes fprintf(stderr, "incorrect operation code: %s\n", word); 1829135446Strhodes return (STATUS_SYNTAX); 1830135446Strhodes } 1831135446Strhodes return (update_addordelete(cmdline, isdelete)); 1832135446Strhodes} 1833135446Strhodes 1834135446Strhodesstatic void 1835170222Sdougbsetzone(dns_name_t *zonename) { 1836170222Sdougb isc_result_t result; 1837170222Sdougb dns_name_t *name = NULL; 1838170222Sdougb dns_rdataset_t *rdataset = NULL; 1839170222Sdougb 1840170222Sdougb result = dns_message_firstname(updatemsg, DNS_SECTION_ZONE); 1841170222Sdougb if (result == ISC_R_SUCCESS) { 1842170222Sdougb dns_message_currentname(updatemsg, DNS_SECTION_ZONE, &name); 1843170222Sdougb dns_message_removename(updatemsg, name, DNS_SECTION_ZONE); 1844170222Sdougb for (rdataset = ISC_LIST_HEAD(name->list); 1845170222Sdougb rdataset != NULL; 1846170222Sdougb rdataset = ISC_LIST_HEAD(name->list)) { 1847170222Sdougb ISC_LIST_UNLINK(name->list, rdataset, link); 1848170222Sdougb dns_rdataset_disassociate(rdataset); 1849170222Sdougb dns_message_puttemprdataset(updatemsg, &rdataset); 1850170222Sdougb } 1851170222Sdougb dns_message_puttempname(updatemsg, &name); 1852170222Sdougb } 1853170222Sdougb 1854170222Sdougb if (zonename != NULL) { 1855170222Sdougb result = dns_message_gettempname(updatemsg, &name); 1856170222Sdougb check_result(result, "dns_message_gettempname"); 1857170222Sdougb dns_name_init(name, NULL); 1858170222Sdougb dns_name_clone(zonename, name); 1859170222Sdougb result = dns_message_gettemprdataset(updatemsg, &rdataset); 1860170222Sdougb check_result(result, "dns_message_gettemprdataset"); 1861170222Sdougb dns_rdataset_makequestion(rdataset, getzoneclass(), 1862170222Sdougb dns_rdatatype_soa); 1863170222Sdougb ISC_LIST_INIT(name->list); 1864170222Sdougb ISC_LIST_APPEND(name->list, rdataset, link); 1865170222Sdougb dns_message_addname(updatemsg, name, DNS_SECTION_ZONE); 1866170222Sdougb } 1867170222Sdougb} 1868170222Sdougb 1869170222Sdougbstatic void 1870193149Sdougbshow_message(FILE *stream, dns_message_t *msg, const char *description) { 1871135446Strhodes isc_result_t result; 1872135446Strhodes isc_buffer_t *buf = NULL; 1873135446Strhodes int bufsz; 1874135446Strhodes 1875135446Strhodes ddebug("show_message()"); 1876170222Sdougb 1877170222Sdougb setzone(userzone); 1878170222Sdougb 1879135446Strhodes bufsz = INITTEXT; 1880186462Sdougb do { 1881135446Strhodes if (bufsz > MAXTEXT) { 1882135446Strhodes fprintf(stderr, "could not allocate large enough " 1883135446Strhodes "buffer to display message\n"); 1884135446Strhodes exit(1); 1885135446Strhodes } 1886135446Strhodes if (buf != NULL) 1887135446Strhodes isc_buffer_free(&buf); 1888135446Strhodes result = isc_buffer_allocate(mctx, &buf, bufsz); 1889135446Strhodes check_result(result, "isc_buffer_allocate"); 1890135446Strhodes result = dns_message_totext(msg, style, 0, buf); 1891135446Strhodes bufsz *= 2; 1892135446Strhodes } while (result == ISC_R_NOSPACE); 1893135446Strhodes if (result != ISC_R_SUCCESS) { 1894135446Strhodes fprintf(stderr, "could not convert message to text format.\n"); 1895135446Strhodes isc_buffer_free(&buf); 1896135446Strhodes return; 1897135446Strhodes } 1898193149Sdougb fprintf(stream, "%s\n%.*s", description, 1899193149Sdougb (int)isc_buffer_usedlength(buf), (char*)isc_buffer_base(buf)); 1900135446Strhodes isc_buffer_free(&buf); 1901135446Strhodes} 1902135446Strhodes 1903135446Strhodesstatic isc_uint16_t 1904254897Serwindo_next_command(char *cmdline) { 1905135446Strhodes char *word; 1906135446Strhodes 1907254897Serwin ddebug("do_next_command()"); 1908135446Strhodes word = nsu_strsep(&cmdline, " \t\r\n"); 1909135446Strhodes 1910245163Serwin if (word == NULL || *word == 0) 1911135446Strhodes return (STATUS_SEND); 1912135446Strhodes if (word[0] == ';') 1913135446Strhodes return (STATUS_MORE); 1914135446Strhodes if (strcasecmp(word, "quit") == 0) 1915135446Strhodes return (STATUS_QUIT); 1916135446Strhodes if (strcasecmp(word, "prereq") == 0) 1917135446Strhodes return (evaluate_prereq(cmdline)); 1918254897Serwin if (strcasecmp(word, "nxdomain") == 0) 1919254897Serwin return (make_prereq(cmdline, ISC_FALSE, ISC_FALSE)); 1920254897Serwin if (strcasecmp(word, "yxdomain") == 0) 1921254897Serwin return (make_prereq(cmdline, ISC_TRUE, ISC_FALSE)); 1922254897Serwin if (strcasecmp(word, "nxrrset") == 0) 1923254897Serwin return (make_prereq(cmdline, ISC_FALSE, ISC_TRUE)); 1924254897Serwin if (strcasecmp(word, "yxrrset") == 0) 1925254897Serwin return (make_prereq(cmdline, ISC_TRUE, ISC_TRUE)); 1926135446Strhodes if (strcasecmp(word, "update") == 0) 1927135446Strhodes return (evaluate_update(cmdline)); 1928254897Serwin if (strcasecmp(word, "delete") == 0) 1929254897Serwin return (update_addordelete(cmdline, ISC_TRUE)); 1930254897Serwin if (strcasecmp(word, "del") == 0) 1931254897Serwin return (update_addordelete(cmdline, ISC_TRUE)); 1932254897Serwin if (strcasecmp(word, "add") == 0) 1933254897Serwin return (update_addordelete(cmdline, ISC_FALSE)); 1934135446Strhodes if (strcasecmp(word, "server") == 0) 1935135446Strhodes return (evaluate_server(cmdline)); 1936135446Strhodes if (strcasecmp(word, "local") == 0) 1937135446Strhodes return (evaluate_local(cmdline)); 1938135446Strhodes if (strcasecmp(word, "zone") == 0) 1939135446Strhodes return (evaluate_zone(cmdline)); 1940135446Strhodes if (strcasecmp(word, "class") == 0) 1941135446Strhodes return (evaluate_class(cmdline)); 1942135446Strhodes if (strcasecmp(word, "send") == 0) 1943135446Strhodes return (STATUS_SEND); 1944193149Sdougb if (strcasecmp(word, "debug") == 0) { 1945193149Sdougb if (debugging) 1946193149Sdougb ddebugging = ISC_TRUE; 1947193149Sdougb else 1948193149Sdougb debugging = ISC_TRUE; 1949193149Sdougb return (STATUS_MORE); 1950193149Sdougb } 1951193149Sdougb if (strcasecmp(word, "ttl") == 0) 1952193149Sdougb return (evaluate_ttl(cmdline)); 1953135446Strhodes if (strcasecmp(word, "show") == 0) { 1954193149Sdougb show_message(stdout, updatemsg, "Outgoing update query:"); 1955135446Strhodes return (STATUS_MORE); 1956135446Strhodes } 1957135446Strhodes if (strcasecmp(word, "answer") == 0) { 1958135446Strhodes if (answer != NULL) 1959193149Sdougb show_message(stdout, answer, "Answer:"); 1960135446Strhodes return (STATUS_MORE); 1961135446Strhodes } 1962193149Sdougb if (strcasecmp(word, "key") == 0) { 1963193149Sdougb usegsstsig = ISC_FALSE; 1964135446Strhodes return (evaluate_key(cmdline)); 1965193149Sdougb } 1966218384Sdougb if (strcasecmp(word, "realm") == 0) 1967218384Sdougb return (evaluate_realm(cmdline)); 1968193149Sdougb if (strcasecmp(word, "gsstsig") == 0) { 1969193149Sdougb#ifdef GSSAPI 1970193149Sdougb usegsstsig = ISC_TRUE; 1971193149Sdougb use_win2k_gsstsig = ISC_FALSE; 1972193149Sdougb#else 1973193149Sdougb fprintf(stderr, "gsstsig not supported\n"); 1974193149Sdougb#endif 1975193149Sdougb return (STATUS_MORE); 1976193149Sdougb } 1977193149Sdougb if (strcasecmp(word, "oldgsstsig") == 0) { 1978193149Sdougb#ifdef GSSAPI 1979193149Sdougb usegsstsig = ISC_TRUE; 1980193149Sdougb use_win2k_gsstsig = ISC_TRUE; 1981193149Sdougb#else 1982193149Sdougb fprintf(stderr, "gsstsig not supported\n"); 1983193149Sdougb#endif 1984193149Sdougb return (STATUS_MORE); 1985193149Sdougb } 1986193149Sdougb if (strcasecmp(word, "help") == 0) { 1987193149Sdougb fprintf(stdout, 1988193149Sdougb"local address [port] (set local resolver)\n" 1989193149Sdougb"server address [port] (set master server for zone)\n" 1990193149Sdougb"send (send the update request)\n" 1991193149Sdougb"show (show the update request)\n" 1992224092Sdougb"answer (show the answer to the last request)\n" 1993193149Sdougb"quit (quit, any pending update is not sent\n" 1994224092Sdougb"help (display this message_\n" 1995193149Sdougb"key [hmac:]keyname secret (use TSIG to sign the request)\n" 1996193149Sdougb"gsstsig (use GSS_TSIG to sign the request)\n" 1997193149Sdougb"oldgsstsig (use Microsoft's GSS_TSIG to sign the request)\n" 1998193149Sdougb"zone name (set the zone to be updated)\n" 1999193149Sdougb"class CLASS (set the zone's DNS class, e.g. IN (default), CH)\n" 2000254897Serwin"[prereq] nxdomain name (does this name not exist)\n" 2001254897Serwin"[prereq] yxdomain name (does this name exist)\n" 2002254897Serwin"[prereq] nxrrset .... (does this RRset exist)\n" 2003254897Serwin"[prereq] yxrrset .... (does this RRset not exist)\n" 2004254897Serwin"[update] add .... (add the given record to the zone)\n" 2005254897Serwin"[update] del[ete] .... (remove the given record(s) from the zone)\n"); 2006193149Sdougb return (STATUS_MORE); 2007193149Sdougb } 2008135446Strhodes fprintf(stderr, "incorrect section name: %s\n", word); 2009135446Strhodes return (STATUS_SYNTAX); 2010135446Strhodes} 2011135446Strhodes 2012254897Serwinstatic isc_uint16_t 2013254897Serwinget_next_command(void) { 2014254897Serwin isc_uint16_t result = STATUS_QUIT; 2015254897Serwin char cmdlinebuf[MAXCMD]; 2016254897Serwin char *cmdline; 2017254897Serwin 2018254897Serwin isc_app_block(); 2019254897Serwin if (interactive) { 2020254897Serwin#ifdef HAVE_READLINE 2021254897Serwin cmdline = readline("> "); 2022262706Serwin if (cmdline != NULL) 2023262706Serwin add_history(cmdline); 2024254897Serwin#else 2025254897Serwin fprintf(stdout, "> "); 2026254897Serwin fflush(stdout); 2027254897Serwin cmdline = fgets(cmdlinebuf, MAXCMD, input); 2028254897Serwin#endif 2029254897Serwin } else 2030254897Serwin cmdline = fgets(cmdlinebuf, MAXCMD, input); 2031254897Serwin isc_app_unblock(); 2032254897Serwin 2033254897Serwin if (cmdline != NULL) { 2034254897Serwin char *tmp = cmdline; 2035254897Serwin 2036254897Serwin /* 2037254897Serwin * Normalize input by removing any eol as readline() 2038254897Serwin * removes eol but fgets doesn't. 2039254897Serwin */ 2040254897Serwin (void)nsu_strsep(&tmp, "\r\n"); 2041254897Serwin result = do_next_command(cmdline); 2042254897Serwin } 2043254897Serwin#ifdef HAVE_READLINE 2044254897Serwin if (interactive) 2045254897Serwin free(cmdline); 2046254897Serwin#endif 2047254897Serwin return (result); 2048254897Serwin} 2049254897Serwin 2050135446Strhodesstatic isc_boolean_t 2051135446Strhodesuser_interaction(void) { 2052135446Strhodes isc_uint16_t result = STATUS_MORE; 2053135446Strhodes 2054135446Strhodes ddebug("user_interaction()"); 2055174187Sdougb while ((result == STATUS_MORE) || (result == STATUS_SYNTAX)) { 2056135446Strhodes result = get_next_command(); 2057174187Sdougb if (!interactive && result == STATUS_SYNTAX) 2058174187Sdougb fatal("syntax error"); 2059174187Sdougb } 2060135446Strhodes if (result == STATUS_SEND) 2061135446Strhodes return (ISC_TRUE); 2062135446Strhodes return (ISC_FALSE); 2063135446Strhodes 2064135446Strhodes} 2065135446Strhodes 2066135446Strhodesstatic void 2067135446Strhodesdone_update(void) { 2068135446Strhodes isc_event_t *event = global_event; 2069135446Strhodes ddebug("done_update()"); 2070135446Strhodes isc_task_send(global_task, &event); 2071135446Strhodes} 2072135446Strhodes 2073135446Strhodesstatic void 2074135446Strhodescheck_tsig_error(dns_rdataset_t *rdataset, isc_buffer_t *b) { 2075135446Strhodes isc_result_t result; 2076135446Strhodes dns_rdata_t rdata = DNS_RDATA_INIT; 2077135446Strhodes dns_rdata_any_tsig_t tsig; 2078135446Strhodes 2079135446Strhodes result = dns_rdataset_first(rdataset); 2080135446Strhodes check_result(result, "dns_rdataset_first"); 2081135446Strhodes dns_rdataset_current(rdataset, &rdata); 2082135446Strhodes result = dns_rdata_tostruct(&rdata, &tsig, NULL); 2083135446Strhodes check_result(result, "dns_rdata_tostruct"); 2084135446Strhodes if (tsig.error != 0) { 2085135446Strhodes if (isc_buffer_remaininglength(b) < 1) 2086135446Strhodes check_result(ISC_R_NOSPACE, "isc_buffer_remaininglength"); 2087135446Strhodes isc__buffer_putstr(b, "(" /*)*/); 2088135446Strhodes result = dns_tsigrcode_totext(tsig.error, b); 2089135446Strhodes check_result(result, "dns_tsigrcode_totext"); 2090135446Strhodes if (isc_buffer_remaininglength(b) < 1) 2091135446Strhodes check_result(ISC_R_NOSPACE, "isc_buffer_remaininglength"); 2092135446Strhodes isc__buffer_putstr(b, /*(*/ ")"); 2093135446Strhodes } 2094135446Strhodes} 2095135446Strhodes 2096135446Strhodesstatic void 2097135446Strhodesupdate_completed(isc_task_t *task, isc_event_t *event) { 2098135446Strhodes dns_requestevent_t *reqev = NULL; 2099135446Strhodes isc_result_t result; 2100135446Strhodes dns_request_t *request; 2101135446Strhodes 2102135446Strhodes UNUSED(task); 2103135446Strhodes 2104135446Strhodes ddebug("update_completed()"); 2105135446Strhodes 2106135446Strhodes requests--; 2107135446Strhodes 2108135446Strhodes REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE); 2109135446Strhodes reqev = (dns_requestevent_t *)event; 2110135446Strhodes request = reqev->request; 2111135446Strhodes 2112135446Strhodes if (shuttingdown) { 2113135446Strhodes dns_request_destroy(&request); 2114135446Strhodes isc_event_free(&event); 2115135446Strhodes maybeshutdown(); 2116135446Strhodes return; 2117135446Strhodes } 2118135446Strhodes 2119135446Strhodes if (reqev->result != ISC_R_SUCCESS) { 2120135446Strhodes fprintf(stderr, "; Communication with server failed: %s\n", 2121135446Strhodes isc_result_totext(reqev->result)); 2122135446Strhodes seenerror = ISC_TRUE; 2123135446Strhodes goto done; 2124135446Strhodes } 2125135446Strhodes 2126135446Strhodes result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &answer); 2127135446Strhodes check_result(result, "dns_message_create"); 2128135446Strhodes result = dns_request_getresponse(request, answer, 2129135446Strhodes DNS_MESSAGEPARSE_PRESERVEORDER); 2130135446Strhodes switch (result) { 2131135446Strhodes case ISC_R_SUCCESS: 2132193149Sdougb if (answer->verify_attempted) 2133193149Sdougb ddebug("tsig verification successful"); 2134135446Strhodes break; 2135135446Strhodes case DNS_R_CLOCKSKEW: 2136135446Strhodes case DNS_R_EXPECTEDTSIG: 2137135446Strhodes case DNS_R_TSIGERRORSET: 2138135446Strhodes case DNS_R_TSIGVERIFYFAILURE: 2139135446Strhodes case DNS_R_UNEXPECTEDTSIG: 2140193149Sdougb case ISC_R_FAILURE: 2141193149Sdougb#if 0 2142193149Sdougb if (usegsstsig && answer->rcode == dns_rcode_noerror) { 2143193149Sdougb /* 2144193149Sdougb * For MS DNS that violates RFC 2845, section 4.2 2145193149Sdougb */ 2146193149Sdougb break; 2147193149Sdougb } 2148193149Sdougb#endif 2149135446Strhodes fprintf(stderr, "; TSIG error with server: %s\n", 2150135446Strhodes isc_result_totext(result)); 2151135446Strhodes seenerror = ISC_TRUE; 2152135446Strhodes break; 2153135446Strhodes default: 2154135446Strhodes check_result(result, "dns_request_getresponse"); 2155135446Strhodes } 2156135446Strhodes 2157135446Strhodes if (answer->rcode != dns_rcode_noerror) { 2158135446Strhodes seenerror = ISC_TRUE; 2159135446Strhodes if (!debugging) { 2160135446Strhodes char buf[64]; 2161135446Strhodes isc_buffer_t b; 2162135446Strhodes dns_rdataset_t *rds; 2163186462Sdougb 2164135446Strhodes isc_buffer_init(&b, buf, sizeof(buf) - 1); 2165135446Strhodes result = dns_rcode_totext(answer->rcode, &b); 2166135446Strhodes check_result(result, "dns_rcode_totext"); 2167135446Strhodes rds = dns_message_gettsig(answer, NULL); 2168135446Strhodes if (rds != NULL) 2169135446Strhodes check_tsig_error(rds, &b); 2170135446Strhodes fprintf(stderr, "update failed: %.*s\n", 2171135446Strhodes (int)isc_buffer_usedlength(&b), buf); 2172135446Strhodes } 2173135446Strhodes } 2174193149Sdougb if (debugging) 2175193149Sdougb show_message(stderr, answer, "\nReply from update query:"); 2176135446Strhodes 2177135446Strhodes done: 2178135446Strhodes dns_request_destroy(&request); 2179193149Sdougb if (usegsstsig) { 2180193149Sdougb dns_name_free(&tmpzonename, mctx); 2181193149Sdougb dns_name_free(&restart_master, mctx); 2182193149Sdougb } 2183135446Strhodes isc_event_free(&event); 2184135446Strhodes done_update(); 2185135446Strhodes} 2186135446Strhodes 2187135446Strhodesstatic void 2188135446Strhodessend_update(dns_name_t *zonename, isc_sockaddr_t *master, 2189135446Strhodes isc_sockaddr_t *srcaddr) 2190135446Strhodes{ 2191135446Strhodes isc_result_t result; 2192135446Strhodes dns_request_t *request = NULL; 2193224092Sdougb unsigned int options = DNS_REQUESTOPT_CASE; 2194135446Strhodes 2195135446Strhodes ddebug("send_update()"); 2196135446Strhodes 2197170222Sdougb setzone(zonename); 2198135446Strhodes 2199135446Strhodes if (usevc) 2200135446Strhodes options |= DNS_REQUESTOPT_TCP; 2201135446Strhodes if (tsigkey == NULL && sig0key != NULL) { 2202135446Strhodes result = dns_message_setsig0key(updatemsg, sig0key); 2203135446Strhodes check_result(result, "dns_message_setsig0key"); 2204135446Strhodes } 2205135446Strhodes if (debugging) { 2206135446Strhodes char addrbuf[ISC_SOCKADDR_FORMATSIZE]; 2207135446Strhodes 2208135446Strhodes isc_sockaddr_format(master, addrbuf, sizeof(addrbuf)); 2209135446Strhodes fprintf(stderr, "Sending update to %s\n", addrbuf); 2210135446Strhodes } 2211193149Sdougb 2212218384Sdougb /* Windows doesn't like the tsig name to be compressed. */ 2213218384Sdougb if (updatemsg->tsigname) 2214218384Sdougb updatemsg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS; 2215218384Sdougb 2216135446Strhodes result = dns_request_createvia3(requestmgr, updatemsg, srcaddr, 2217135446Strhodes master, options, tsigkey, timeout, 2218135446Strhodes udp_timeout, udp_retries, global_task, 2219135446Strhodes update_completed, NULL, &request); 2220135446Strhodes check_result(result, "dns_request_createvia3"); 2221135446Strhodes 2222135446Strhodes if (debugging) 2223193149Sdougb show_message(stdout, updatemsg, "Outgoing update query:"); 2224135446Strhodes 2225135446Strhodes requests++; 2226135446Strhodes} 2227135446Strhodes 2228135446Strhodesstatic void 2229135446Strhodesrecvsoa(isc_task_t *task, isc_event_t *event) { 2230135446Strhodes dns_requestevent_t *reqev = NULL; 2231135446Strhodes dns_request_t *request = NULL; 2232135446Strhodes isc_result_t result, eresult; 2233135446Strhodes dns_message_t *rcvmsg = NULL; 2234135446Strhodes dns_section_t section; 2235135446Strhodes dns_name_t *name = NULL; 2236135446Strhodes dns_rdataset_t *soaset = NULL; 2237135446Strhodes dns_rdata_soa_t soa; 2238135446Strhodes dns_rdata_t soarr = DNS_RDATA_INIT; 2239135446Strhodes int pass = 0; 2240135446Strhodes dns_name_t master; 2241135446Strhodes nsu_requestinfo_t *reqinfo; 2242135446Strhodes dns_message_t *soaquery = NULL; 2243135446Strhodes isc_sockaddr_t *addr; 2244135446Strhodes isc_boolean_t seencname = ISC_FALSE; 2245143731Sdougb dns_name_t tname; 2246143731Sdougb unsigned int nlabels; 2247135446Strhodes 2248135446Strhodes UNUSED(task); 2249135446Strhodes 2250135446Strhodes ddebug("recvsoa()"); 2251135446Strhodes 2252135446Strhodes requests--; 2253186462Sdougb 2254135446Strhodes REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE); 2255135446Strhodes reqev = (dns_requestevent_t *)event; 2256135446Strhodes request = reqev->request; 2257135446Strhodes eresult = reqev->result; 2258135446Strhodes reqinfo = reqev->ev_arg; 2259135446Strhodes soaquery = reqinfo->msg; 2260135446Strhodes addr = reqinfo->addr; 2261135446Strhodes 2262135446Strhodes if (shuttingdown) { 2263135446Strhodes dns_request_destroy(&request); 2264135446Strhodes dns_message_destroy(&soaquery); 2265135446Strhodes isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t)); 2266135446Strhodes isc_event_free(&event); 2267135446Strhodes maybeshutdown(); 2268135446Strhodes return; 2269135446Strhodes } 2270135446Strhodes 2271135446Strhodes if (eresult != ISC_R_SUCCESS) { 2272135446Strhodes char addrbuf[ISC_SOCKADDR_FORMATSIZE]; 2273135446Strhodes 2274135446Strhodes isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf)); 2275135446Strhodes fprintf(stderr, "; Communication with %s failed: %s\n", 2276193149Sdougb addrbuf, isc_result_totext(eresult)); 2277135446Strhodes if (userserver != NULL) 2278135446Strhodes fatal("could not talk to specified name server"); 2279135446Strhodes else if (++ns_inuse >= lwconf->nsnext) 2280135446Strhodes fatal("could not talk to any default name server"); 2281135446Strhodes ddebug("Destroying request [%p]", request); 2282135446Strhodes dns_request_destroy(&request); 2283135446Strhodes dns_message_renderreset(soaquery); 2284153816Sdougb dns_message_settsigkey(soaquery, NULL); 2285135446Strhodes sendrequest(localaddr, &servers[ns_inuse], soaquery, &request); 2286135446Strhodes isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t)); 2287135446Strhodes isc_event_free(&event); 2288135446Strhodes setzoneclass(dns_rdataclass_none); 2289135446Strhodes return; 2290135446Strhodes } 2291170222Sdougb 2292135446Strhodes isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t)); 2293170222Sdougb reqinfo = NULL; 2294135446Strhodes isc_event_free(&event); 2295135446Strhodes reqev = NULL; 2296135446Strhodes 2297135446Strhodes ddebug("About to create rcvmsg"); 2298135446Strhodes result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &rcvmsg); 2299135446Strhodes check_result(result, "dns_message_create"); 2300135446Strhodes result = dns_request_getresponse(request, rcvmsg, 2301135446Strhodes DNS_MESSAGEPARSE_PRESERVEORDER); 2302135446Strhodes if (result == DNS_R_TSIGERRORSET && userserver != NULL) { 2303135446Strhodes dns_message_destroy(&rcvmsg); 2304135446Strhodes ddebug("Destroying request [%p]", request); 2305135446Strhodes dns_request_destroy(&request); 2306135446Strhodes reqinfo = isc_mem_get(mctx, sizeof(nsu_requestinfo_t)); 2307135446Strhodes if (reqinfo == NULL) 2308135446Strhodes fatal("out of memory"); 2309135446Strhodes reqinfo->msg = soaquery; 2310135446Strhodes reqinfo->addr = addr; 2311135446Strhodes dns_message_renderreset(soaquery); 2312135446Strhodes ddebug("retrying soa request without TSIG"); 2313135446Strhodes result = dns_request_createvia3(requestmgr, soaquery, 2314135446Strhodes localaddr, addr, 0, NULL, 2315135446Strhodes FIND_TIMEOUT * 20, 2316165071Sdougb FIND_TIMEOUT, 3, 2317135446Strhodes global_task, recvsoa, reqinfo, 2318135446Strhodes &request); 2319135446Strhodes check_result(result, "dns_request_createvia"); 2320135446Strhodes requests++; 2321135446Strhodes return; 2322135446Strhodes } 2323135446Strhodes check_result(result, "dns_request_getresponse"); 2324135446Strhodes section = DNS_SECTION_ANSWER; 2325225361Sdougb POST(section); 2326193149Sdougb if (debugging) 2327193149Sdougb show_message(stderr, rcvmsg, "Reply from SOA query:"); 2328135446Strhodes 2329135446Strhodes if (rcvmsg->rcode != dns_rcode_noerror && 2330135446Strhodes rcvmsg->rcode != dns_rcode_nxdomain) 2331135446Strhodes fatal("response to SOA query was unsuccessful"); 2332135446Strhodes 2333170222Sdougb if (userzone != NULL && rcvmsg->rcode == dns_rcode_nxdomain) { 2334170222Sdougb char namebuf[DNS_NAME_FORMATSIZE]; 2335170222Sdougb dns_name_format(userzone, namebuf, sizeof(namebuf)); 2336170222Sdougb error("specified zone '%s' does not exist (NXDOMAIN)", 2337170222Sdougb namebuf); 2338170222Sdougb dns_message_destroy(&rcvmsg); 2339170222Sdougb dns_request_destroy(&request); 2340170222Sdougb dns_message_destroy(&soaquery); 2341170222Sdougb ddebug("Out of recvsoa"); 2342170222Sdougb done_update(); 2343234010Sdougb seenerror = ISC_TRUE; 2344170222Sdougb return; 2345170222Sdougb } 2346170222Sdougb 2347135446Strhodes lookforsoa: 2348135446Strhodes if (pass == 0) 2349135446Strhodes section = DNS_SECTION_ANSWER; 2350135446Strhodes else if (pass == 1) 2351135446Strhodes section = DNS_SECTION_AUTHORITY; 2352186462Sdougb else 2353143731Sdougb goto droplabel; 2354135446Strhodes 2355135446Strhodes result = dns_message_firstname(rcvmsg, section); 2356135446Strhodes if (result != ISC_R_SUCCESS) { 2357135446Strhodes pass++; 2358135446Strhodes goto lookforsoa; 2359135446Strhodes } 2360135446Strhodes while (result == ISC_R_SUCCESS) { 2361135446Strhodes name = NULL; 2362135446Strhodes dns_message_currentname(rcvmsg, section, &name); 2363135446Strhodes soaset = NULL; 2364135446Strhodes result = dns_message_findtype(name, dns_rdatatype_soa, 0, 2365135446Strhodes &soaset); 2366135446Strhodes if (result == ISC_R_SUCCESS) 2367135446Strhodes break; 2368135446Strhodes if (section == DNS_SECTION_ANSWER) { 2369135446Strhodes dns_rdataset_t *tset = NULL; 2370135446Strhodes if (dns_message_findtype(name, dns_rdatatype_cname, 0, 2371193149Sdougb &tset) == ISC_R_SUCCESS || 2372135446Strhodes dns_message_findtype(name, dns_rdatatype_dname, 0, 2373193149Sdougb &tset) == ISC_R_SUCCESS ) { 2374135446Strhodes seencname = ISC_TRUE; 2375135446Strhodes break; 2376135446Strhodes } 2377135446Strhodes } 2378186462Sdougb 2379135446Strhodes result = dns_message_nextname(rcvmsg, section); 2380135446Strhodes } 2381135446Strhodes 2382135446Strhodes if (soaset == NULL && !seencname) { 2383135446Strhodes pass++; 2384135446Strhodes goto lookforsoa; 2385135446Strhodes } 2386135446Strhodes 2387143731Sdougb if (seencname) 2388143731Sdougb goto droplabel; 2389135446Strhodes 2390135446Strhodes if (debugging) { 2391135446Strhodes char namestr[DNS_NAME_FORMATSIZE]; 2392135446Strhodes dns_name_format(name, namestr, sizeof(namestr)); 2393135446Strhodes fprintf(stderr, "Found zone name: %s\n", namestr); 2394135446Strhodes } 2395135446Strhodes 2396135446Strhodes result = dns_rdataset_first(soaset); 2397135446Strhodes check_result(result, "dns_rdataset_first"); 2398135446Strhodes 2399135446Strhodes dns_rdata_init(&soarr); 2400135446Strhodes dns_rdataset_current(soaset, &soarr); 2401135446Strhodes result = dns_rdata_tostruct(&soarr, &soa, NULL); 2402135446Strhodes check_result(result, "dns_rdata_tostruct"); 2403135446Strhodes 2404135446Strhodes dns_name_init(&master, NULL); 2405135446Strhodes dns_name_clone(&soa.origin, &master); 2406135446Strhodes 2407135446Strhodes if (userzone != NULL) 2408135446Strhodes zonename = userzone; 2409135446Strhodes else 2410135446Strhodes zonename = name; 2411135446Strhodes 2412135446Strhodes if (debugging) { 2413135446Strhodes char namestr[DNS_NAME_FORMATSIZE]; 2414135446Strhodes dns_name_format(&master, namestr, sizeof(namestr)); 2415135446Strhodes fprintf(stderr, "The master is: %s\n", namestr); 2416135446Strhodes } 2417135446Strhodes 2418135446Strhodes if (userserver != NULL) 2419135446Strhodes serveraddr = userserver; 2420135446Strhodes else { 2421135446Strhodes char serverstr[DNS_NAME_MAXTEXT+1]; 2422135446Strhodes isc_buffer_t buf; 2423135446Strhodes 2424135446Strhodes isc_buffer_init(&buf, serverstr, sizeof(serverstr)); 2425135446Strhodes result = dns_name_totext(&master, ISC_TRUE, &buf); 2426135446Strhodes check_result(result, "dns_name_totext"); 2427135446Strhodes serverstr[isc_buffer_usedlength(&buf)] = 0; 2428224092Sdougb get_address(serverstr, dnsport, &tempaddr); 2429135446Strhodes serveraddr = &tempaddr; 2430135446Strhodes } 2431143731Sdougb dns_rdata_freestruct(&soa); 2432135446Strhodes 2433193149Sdougb#ifdef GSSAPI 2434193149Sdougb if (usegsstsig) { 2435193149Sdougb dns_name_init(&tmpzonename, NULL); 2436193149Sdougb dns_name_dup(zonename, mctx, &tmpzonename); 2437193149Sdougb dns_name_init(&restart_master, NULL); 2438193149Sdougb dns_name_dup(&master, mctx, &restart_master); 2439193149Sdougb start_gssrequest(&master); 2440193149Sdougb } else { 2441193149Sdougb send_update(zonename, serveraddr, localaddr); 2442193149Sdougb setzoneclass(dns_rdataclass_none); 2443193149Sdougb } 2444193149Sdougb#else 2445135446Strhodes send_update(zonename, serveraddr, localaddr); 2446143731Sdougb setzoneclass(dns_rdataclass_none); 2447193149Sdougb#endif 2448135446Strhodes 2449135446Strhodes dns_message_destroy(&soaquery); 2450135446Strhodes dns_request_destroy(&request); 2451135446Strhodes 2452135446Strhodes out: 2453135446Strhodes dns_message_destroy(&rcvmsg); 2454135446Strhodes ddebug("Out of recvsoa"); 2455143731Sdougb return; 2456186462Sdougb 2457143731Sdougb droplabel: 2458143731Sdougb result = dns_message_firstname(soaquery, DNS_SECTION_QUESTION); 2459143731Sdougb INSIST(result == ISC_R_SUCCESS); 2460143731Sdougb name = NULL; 2461143731Sdougb dns_message_currentname(soaquery, DNS_SECTION_QUESTION, &name); 2462143731Sdougb nlabels = dns_name_countlabels(name); 2463143731Sdougb if (nlabels == 1) 2464143731Sdougb fatal("could not find enclosing zone"); 2465143731Sdougb dns_name_init(&tname, NULL); 2466143731Sdougb dns_name_getlabelsequence(name, 1, nlabels - 1, &tname); 2467143731Sdougb dns_name_clone(&tname, name); 2468143731Sdougb dns_request_destroy(&request); 2469143731Sdougb dns_message_renderreset(soaquery); 2470153816Sdougb dns_message_settsigkey(soaquery, NULL); 2471143731Sdougb if (userserver != NULL) 2472143731Sdougb sendrequest(localaddr, userserver, soaquery, &request); 2473143731Sdougb else 2474193149Sdougb sendrequest(localaddr, &servers[ns_inuse], soaquery, &request); 2475143731Sdougb goto out; 2476135446Strhodes} 2477135446Strhodes 2478135446Strhodesstatic void 2479135446Strhodessendrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, 2480135446Strhodes dns_message_t *msg, dns_request_t **request) 2481135446Strhodes{ 2482135446Strhodes isc_result_t result; 2483135446Strhodes nsu_requestinfo_t *reqinfo; 2484135446Strhodes 2485135446Strhodes reqinfo = isc_mem_get(mctx, sizeof(nsu_requestinfo_t)); 2486135446Strhodes if (reqinfo == NULL) 2487135446Strhodes fatal("out of memory"); 2488135446Strhodes reqinfo->msg = msg; 2489135446Strhodes reqinfo->addr = destaddr; 2490135446Strhodes result = dns_request_createvia3(requestmgr, msg, srcaddr, destaddr, 0, 2491135446Strhodes (userserver != NULL) ? tsigkey : NULL, 2492135446Strhodes FIND_TIMEOUT * 20, FIND_TIMEOUT, 3, 2493135446Strhodes global_task, recvsoa, reqinfo, request); 2494135446Strhodes check_result(result, "dns_request_createvia"); 2495135446Strhodes requests++; 2496135446Strhodes} 2497135446Strhodes 2498193149Sdougb#ifdef GSSAPI 2499224092Sdougb 2500224092Sdougb/* 2501224092Sdougb * Get the realm from the users kerberos ticket if possible 2502224092Sdougb */ 2503135446Strhodesstatic void 2504224092Sdougbget_ticket_realm(isc_mem_t *mctx) 2505193149Sdougb{ 2506224092Sdougb krb5_context ctx; 2507224092Sdougb krb5_error_code rc; 2508224092Sdougb krb5_ccache ccache; 2509224092Sdougb krb5_principal princ; 2510224092Sdougb char *name, *ticket_realm; 2511224092Sdougb 2512224092Sdougb rc = krb5_init_context(&ctx); 2513224092Sdougb if (rc != 0) 2514224092Sdougb return; 2515224092Sdougb 2516224092Sdougb rc = krb5_cc_default(ctx, &ccache); 2517224092Sdougb if (rc != 0) { 2518224092Sdougb krb5_free_context(ctx); 2519224092Sdougb return; 2520224092Sdougb } 2521224092Sdougb 2522224092Sdougb rc = krb5_cc_get_principal(ctx, ccache, &princ); 2523224092Sdougb if (rc != 0) { 2524224092Sdougb krb5_cc_close(ctx, ccache); 2525224092Sdougb krb5_free_context(ctx); 2526224092Sdougb return; 2527224092Sdougb } 2528224092Sdougb 2529224092Sdougb rc = krb5_unparse_name(ctx, princ, &name); 2530224092Sdougb if (rc != 0) { 2531224092Sdougb krb5_free_principal(ctx, princ); 2532224092Sdougb krb5_cc_close(ctx, ccache); 2533224092Sdougb krb5_free_context(ctx); 2534224092Sdougb return; 2535224092Sdougb } 2536224092Sdougb 2537224092Sdougb ticket_realm = strrchr(name, '@'); 2538224092Sdougb if (ticket_realm != NULL) { 2539224092Sdougb realm = isc_mem_strdup(mctx, ticket_realm); 2540224092Sdougb } 2541224092Sdougb 2542224092Sdougb free(name); 2543224092Sdougb krb5_free_principal(ctx, princ); 2544224092Sdougb krb5_cc_close(ctx, ccache); 2545224092Sdougb krb5_free_context(ctx); 2546224092Sdougb if (realm != NULL && debugging) 2547224092Sdougb fprintf(stderr, "Found realm from ticket: %s\n", realm+1); 2548224092Sdougb} 2549224092Sdougb 2550224092Sdougb 2551224092Sdougbstatic void 2552224092Sdougbstart_gssrequest(dns_name_t *master) { 2553193149Sdougb gss_ctx_id_t context; 2554193149Sdougb isc_buffer_t buf; 2555193149Sdougb isc_result_t result; 2556193149Sdougb isc_uint32_t val = 0; 2557193149Sdougb dns_message_t *rmsg; 2558193149Sdougb dns_request_t *request = NULL; 2559193149Sdougb dns_name_t *servname; 2560193149Sdougb dns_fixedname_t fname; 2561193149Sdougb char namestr[DNS_NAME_FORMATSIZE]; 2562193149Sdougb char keystr[DNS_NAME_FORMATSIZE]; 2563224092Sdougb char *err_message = NULL; 2564193149Sdougb 2565193149Sdougb debug("start_gssrequest"); 2566193149Sdougb usevc = ISC_TRUE; 2567193149Sdougb 2568193149Sdougb if (gssring != NULL) 2569224092Sdougb dns_tsigkeyring_detach(&gssring); 2570193149Sdougb gssring = NULL; 2571193149Sdougb result = dns_tsigkeyring_create(mctx, &gssring); 2572193149Sdougb 2573193149Sdougb if (result != ISC_R_SUCCESS) 2574193149Sdougb fatal("dns_tsigkeyring_create failed: %s", 2575193149Sdougb isc_result_totext(result)); 2576193149Sdougb 2577193149Sdougb dns_name_format(master, namestr, sizeof(namestr)); 2578193149Sdougb if (kserver == NULL) { 2579193149Sdougb kserver = isc_mem_get(mctx, sizeof(isc_sockaddr_t)); 2580193149Sdougb if (kserver == NULL) 2581193149Sdougb fatal("out of memory"); 2582193149Sdougb } 2583193149Sdougb if (userserver == NULL) 2584224092Sdougb get_address(namestr, dnsport, kserver); 2585193149Sdougb else 2586262706Serwin (void)memmove(kserver, userserver, sizeof(isc_sockaddr_t)); 2587193149Sdougb 2588193149Sdougb dns_fixedname_init(&fname); 2589193149Sdougb servname = dns_fixedname_name(&fname); 2590193149Sdougb 2591224092Sdougb if (realm == NULL) 2592224092Sdougb get_ticket_realm(mctx); 2593224092Sdougb 2594193149Sdougb result = isc_string_printf(servicename, sizeof(servicename), 2595218384Sdougb "DNS/%s%s", namestr, realm ? realm : ""); 2596193149Sdougb if (result != ISC_R_SUCCESS) 2597193149Sdougb fatal("isc_string_printf(servicename) failed: %s", 2598193149Sdougb isc_result_totext(result)); 2599193149Sdougb isc_buffer_init(&buf, servicename, strlen(servicename)); 2600193149Sdougb isc_buffer_add(&buf, strlen(servicename)); 2601224092Sdougb result = dns_name_fromtext(servname, &buf, dns_rootname, 0, NULL); 2602193149Sdougb if (result != ISC_R_SUCCESS) 2603193149Sdougb fatal("dns_name_fromtext(servname) failed: %s", 2604193149Sdougb isc_result_totext(result)); 2605193149Sdougb 2606193149Sdougb dns_fixedname_init(&fkname); 2607193149Sdougb keyname = dns_fixedname_name(&fkname); 2608193149Sdougb 2609193149Sdougb isc_random_get(&val); 2610193149Sdougb result = isc_string_printf(keystr, sizeof(keystr), "%u.sig-%s", 2611193149Sdougb val, namestr); 2612193149Sdougb if (result != ISC_R_SUCCESS) 2613193149Sdougb fatal("isc_string_printf(keystr) failed: %s", 2614193149Sdougb isc_result_totext(result)); 2615193149Sdougb isc_buffer_init(&buf, keystr, strlen(keystr)); 2616193149Sdougb isc_buffer_add(&buf, strlen(keystr)); 2617193149Sdougb 2618224092Sdougb result = dns_name_fromtext(keyname, &buf, dns_rootname, 0, NULL); 2619193149Sdougb if (result != ISC_R_SUCCESS) 2620193149Sdougb fatal("dns_name_fromtext(keyname) failed: %s", 2621193149Sdougb isc_result_totext(result)); 2622193149Sdougb 2623193149Sdougb /* Windows doesn't recognize name compression in the key name. */ 2624193149Sdougb keyname->attributes |= DNS_NAMEATTR_NOCOMPRESS; 2625193149Sdougb 2626193149Sdougb rmsg = NULL; 2627193149Sdougb result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &rmsg); 2628193149Sdougb if (result != ISC_R_SUCCESS) 2629193149Sdougb fatal("dns_message_create failed: %s", 2630193149Sdougb isc_result_totext(result)); 2631193149Sdougb 2632193149Sdougb /* Build first request. */ 2633193149Sdougb context = GSS_C_NO_CONTEXT; 2634193149Sdougb result = dns_tkey_buildgssquery(rmsg, keyname, servname, NULL, 0, 2635224092Sdougb &context, use_win2k_gsstsig, 2636224092Sdougb mctx, &err_message); 2637193149Sdougb if (result == ISC_R_FAILURE) 2638224092Sdougb fatal("tkey query failed: %s", 2639224092Sdougb err_message != NULL ? err_message : "unknown error"); 2640193149Sdougb if (result != ISC_R_SUCCESS) 2641193149Sdougb fatal("dns_tkey_buildgssquery failed: %s", 2642193149Sdougb isc_result_totext(result)); 2643193149Sdougb 2644193149Sdougb send_gssrequest(localaddr, kserver, rmsg, &request, context); 2645193149Sdougb} 2646193149Sdougb 2647193149Sdougbstatic void 2648193149Sdougbsend_gssrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, 2649193149Sdougb dns_message_t *msg, dns_request_t **request, 2650193149Sdougb gss_ctx_id_t context) 2651193149Sdougb{ 2652193149Sdougb isc_result_t result; 2653193149Sdougb nsu_gssinfo_t *reqinfo; 2654193149Sdougb unsigned int options = 0; 2655193149Sdougb 2656193149Sdougb debug("send_gssrequest"); 2657193149Sdougb reqinfo = isc_mem_get(mctx, sizeof(nsu_gssinfo_t)); 2658193149Sdougb if (reqinfo == NULL) 2659193149Sdougb fatal("out of memory"); 2660193149Sdougb reqinfo->msg = msg; 2661193149Sdougb reqinfo->addr = destaddr; 2662193149Sdougb reqinfo->context = context; 2663193149Sdougb 2664193149Sdougb options |= DNS_REQUESTOPT_TCP; 2665193149Sdougb result = dns_request_createvia3(requestmgr, msg, srcaddr, destaddr, 2666193149Sdougb options, tsigkey, FIND_TIMEOUT * 20, 2667193149Sdougb FIND_TIMEOUT, 3, global_task, recvgss, 2668193149Sdougb reqinfo, request); 2669193149Sdougb check_result(result, "dns_request_createvia3"); 2670193149Sdougb if (debugging) 2671193149Sdougb show_message(stdout, msg, "Outgoing update query:"); 2672193149Sdougb requests++; 2673193149Sdougb} 2674193149Sdougb 2675193149Sdougbstatic void 2676193149Sdougbrecvgss(isc_task_t *task, isc_event_t *event) { 2677193149Sdougb dns_requestevent_t *reqev = NULL; 2678193149Sdougb dns_request_t *request = NULL; 2679193149Sdougb isc_result_t result, eresult; 2680193149Sdougb dns_message_t *rcvmsg = NULL; 2681193149Sdougb nsu_gssinfo_t *reqinfo; 2682193149Sdougb dns_message_t *tsigquery = NULL; 2683193149Sdougb isc_sockaddr_t *addr; 2684193149Sdougb gss_ctx_id_t context; 2685193149Sdougb isc_buffer_t buf; 2686193149Sdougb dns_name_t *servname; 2687193149Sdougb dns_fixedname_t fname; 2688224092Sdougb char *err_message = NULL; 2689193149Sdougb 2690193149Sdougb UNUSED(task); 2691193149Sdougb 2692193149Sdougb ddebug("recvgss()"); 2693193149Sdougb 2694193149Sdougb requests--; 2695193149Sdougb 2696193149Sdougb REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE); 2697193149Sdougb reqev = (dns_requestevent_t *)event; 2698193149Sdougb request = reqev->request; 2699193149Sdougb eresult = reqev->result; 2700193149Sdougb reqinfo = reqev->ev_arg; 2701193149Sdougb tsigquery = reqinfo->msg; 2702193149Sdougb context = reqinfo->context; 2703193149Sdougb addr = reqinfo->addr; 2704193149Sdougb 2705193149Sdougb if (shuttingdown) { 2706193149Sdougb dns_request_destroy(&request); 2707193149Sdougb dns_message_destroy(&tsigquery); 2708193149Sdougb isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_t)); 2709193149Sdougb isc_event_free(&event); 2710193149Sdougb maybeshutdown(); 2711193149Sdougb return; 2712193149Sdougb } 2713193149Sdougb 2714193149Sdougb if (eresult != ISC_R_SUCCESS) { 2715193149Sdougb char addrbuf[ISC_SOCKADDR_FORMATSIZE]; 2716193149Sdougb 2717193149Sdougb isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf)); 2718193149Sdougb fprintf(stderr, "; Communication with %s failed: %s\n", 2719193149Sdougb addrbuf, isc_result_totext(eresult)); 2720193149Sdougb if (userserver != NULL) 2721193149Sdougb fatal("could not talk to specified name server"); 2722193149Sdougb else if (++ns_inuse >= lwconf->nsnext) 2723193149Sdougb fatal("could not talk to any default name server"); 2724193149Sdougb ddebug("Destroying request [%p]", request); 2725193149Sdougb dns_request_destroy(&request); 2726193149Sdougb dns_message_renderreset(tsigquery); 2727193149Sdougb sendrequest(localaddr, &servers[ns_inuse], tsigquery, 2728193149Sdougb &request); 2729193149Sdougb isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_t)); 2730193149Sdougb isc_event_free(&event); 2731193149Sdougb return; 2732193149Sdougb } 2733193149Sdougb isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_t)); 2734193149Sdougb 2735193149Sdougb isc_event_free(&event); 2736193149Sdougb reqev = NULL; 2737193149Sdougb 2738193149Sdougb ddebug("recvgss creating rcvmsg"); 2739193149Sdougb result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &rcvmsg); 2740193149Sdougb check_result(result, "dns_message_create"); 2741193149Sdougb 2742193149Sdougb result = dns_request_getresponse(request, rcvmsg, 2743193149Sdougb DNS_MESSAGEPARSE_PRESERVEORDER); 2744193149Sdougb check_result(result, "dns_request_getresponse"); 2745193149Sdougb 2746193149Sdougb if (debugging) 2747193149Sdougb show_message(stderr, rcvmsg, 2748193149Sdougb "recvmsg reply from GSS-TSIG query"); 2749193149Sdougb 2750193149Sdougb if (rcvmsg->rcode == dns_rcode_formerr && !tried_other_gsstsig) { 2751193149Sdougb ddebug("recvgss trying %s GSS-TSIG", 2752193149Sdougb use_win2k_gsstsig ? "Standard" : "Win2k"); 2753193149Sdougb if (use_win2k_gsstsig) 2754193149Sdougb use_win2k_gsstsig = ISC_FALSE; 2755193149Sdougb else 2756193149Sdougb use_win2k_gsstsig = ISC_TRUE; 2757193149Sdougb tried_other_gsstsig = ISC_TRUE; 2758193149Sdougb start_gssrequest(&restart_master); 2759193149Sdougb goto done; 2760193149Sdougb } 2761193149Sdougb 2762193149Sdougb if (rcvmsg->rcode != dns_rcode_noerror && 2763193149Sdougb rcvmsg->rcode != dns_rcode_nxdomain) 2764193149Sdougb fatal("response to GSS-TSIG query was unsuccessful"); 2765193149Sdougb 2766193149Sdougb 2767193149Sdougb dns_fixedname_init(&fname); 2768193149Sdougb servname = dns_fixedname_name(&fname); 2769193149Sdougb isc_buffer_init(&buf, servicename, strlen(servicename)); 2770193149Sdougb isc_buffer_add(&buf, strlen(servicename)); 2771224092Sdougb result = dns_name_fromtext(servname, &buf, dns_rootname, 0, NULL); 2772193149Sdougb check_result(result, "dns_name_fromtext"); 2773193149Sdougb 2774193149Sdougb tsigkey = NULL; 2775193149Sdougb result = dns_tkey_gssnegotiate(tsigquery, rcvmsg, servname, 2776193149Sdougb &context, &tsigkey, gssring, 2777224092Sdougb use_win2k_gsstsig, 2778224092Sdougb &err_message); 2779193149Sdougb switch (result) { 2780193149Sdougb 2781193149Sdougb case DNS_R_CONTINUE: 2782193149Sdougb send_gssrequest(localaddr, kserver, tsigquery, &request, 2783193149Sdougb context); 2784193149Sdougb break; 2785193149Sdougb 2786193149Sdougb case ISC_R_SUCCESS: 2787193149Sdougb /* 2788193149Sdougb * XXXSRA Waaay too much fun here. There's no good 2789193149Sdougb * reason why we need a TSIG here (the people who put 2790193149Sdougb * it into the spec admitted at the time that it was 2791193149Sdougb * not a security issue), and Windows clients don't 2792193149Sdougb * seem to work if named complies with the spec and 2793193149Sdougb * includes the gratuitous TSIG. So we're in the 2794193149Sdougb * bizarre situation of having to choose between 2795193149Sdougb * complying with a useless requirement in the spec 2796193149Sdougb * and interoperating. This is nuts. If we can 2797193149Sdougb * confirm this behavior, we should ask the WG to 2798193149Sdougb * consider removing the requirement for the 2799193149Sdougb * gratuitous TSIG here. For the moment, we ignore 2800193149Sdougb * the TSIG -- this too is a spec violation, but it's 2801193149Sdougb * the least insane thing to do. 2802193149Sdougb */ 2803193149Sdougb#if 0 2804193149Sdougb /* 2805193149Sdougb * Verify the signature. 2806193149Sdougb */ 2807193149Sdougb rcvmsg->state = DNS_SECTION_ANY; 2808193149Sdougb dns_message_setquerytsig(rcvmsg, NULL); 2809193149Sdougb result = dns_message_settsigkey(rcvmsg, tsigkey); 2810193149Sdougb check_result(result, "dns_message_settsigkey"); 2811193149Sdougb result = dns_message_checksig(rcvmsg, NULL); 2812193149Sdougb ddebug("tsig verification: %s", dns_result_totext(result)); 2813193149Sdougb check_result(result, "dns_message_checksig"); 2814193149Sdougb#endif /* 0 */ 2815193149Sdougb 2816193149Sdougb send_update(&tmpzonename, serveraddr, localaddr); 2817193149Sdougb setzoneclass(dns_rdataclass_none); 2818193149Sdougb break; 2819193149Sdougb 2820193149Sdougb default: 2821224092Sdougb fatal("dns_tkey_negotiategss: %s %s", 2822224092Sdougb isc_result_totext(result), 2823224092Sdougb err_message != NULL ? err_message : ""); 2824193149Sdougb } 2825193149Sdougb 2826193149Sdougb done: 2827193149Sdougb dns_request_destroy(&request); 2828193149Sdougb dns_message_destroy(&tsigquery); 2829193149Sdougb 2830193149Sdougb dns_message_destroy(&rcvmsg); 2831193149Sdougb ddebug("Out of recvgss"); 2832193149Sdougb} 2833193149Sdougb#endif 2834193149Sdougb 2835193149Sdougbstatic void 2836135446Strhodesstart_update(void) { 2837135446Strhodes isc_result_t result; 2838135446Strhodes dns_rdataset_t *rdataset = NULL; 2839135446Strhodes dns_name_t *name = NULL; 2840135446Strhodes dns_request_t *request = NULL; 2841135446Strhodes dns_message_t *soaquery = NULL; 2842135446Strhodes dns_name_t *firstname; 2843135446Strhodes dns_section_t section = DNS_SECTION_UPDATE; 2844135446Strhodes 2845135446Strhodes ddebug("start_update()"); 2846135446Strhodes 2847135446Strhodes if (answer != NULL) 2848135446Strhodes dns_message_destroy(&answer); 2849135446Strhodes 2850193149Sdougb if (userzone != NULL && userserver != NULL && ! usegsstsig) { 2851135446Strhodes send_update(userzone, userserver, localaddr); 2852135446Strhodes setzoneclass(dns_rdataclass_none); 2853135446Strhodes return; 2854135446Strhodes } 2855135446Strhodes 2856135446Strhodes result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, 2857135446Strhodes &soaquery); 2858135446Strhodes check_result(result, "dns_message_create"); 2859135446Strhodes 2860170222Sdougb if (userserver == NULL) 2861170222Sdougb soaquery->flags |= DNS_MESSAGEFLAG_RD; 2862135446Strhodes 2863135446Strhodes result = dns_message_gettempname(soaquery, &name); 2864135446Strhodes check_result(result, "dns_message_gettempname"); 2865135446Strhodes 2866135446Strhodes result = dns_message_gettemprdataset(soaquery, &rdataset); 2867135446Strhodes check_result(result, "dns_message_gettemprdataset"); 2868135446Strhodes 2869135446Strhodes dns_rdataset_makequestion(rdataset, getzoneclass(), dns_rdatatype_soa); 2870135446Strhodes 2871170222Sdougb if (userzone != NULL) { 2872170222Sdougb dns_name_init(name, NULL); 2873170222Sdougb dns_name_clone(userzone, name); 2874170222Sdougb } else { 2875218384Sdougb dns_rdataset_t *tmprdataset; 2876170222Sdougb result = dns_message_firstname(updatemsg, section); 2877170222Sdougb if (result == ISC_R_NOMORE) { 2878170222Sdougb section = DNS_SECTION_PREREQUISITE; 2879170222Sdougb result = dns_message_firstname(updatemsg, section); 2880170222Sdougb } 2881170222Sdougb if (result != ISC_R_SUCCESS) { 2882174187Sdougb dns_message_puttempname(soaquery, &name); 2883174187Sdougb dns_rdataset_disassociate(rdataset); 2884174187Sdougb dns_message_puttemprdataset(soaquery, &rdataset); 2885174187Sdougb dns_message_destroy(&soaquery); 2886170222Sdougb done_update(); 2887170222Sdougb return; 2888170222Sdougb } 2889170222Sdougb firstname = NULL; 2890170222Sdougb dns_message_currentname(updatemsg, section, &firstname); 2891170222Sdougb dns_name_init(name, NULL); 2892170222Sdougb dns_name_clone(firstname, name); 2893218384Sdougb /* 2894218384Sdougb * Looks to see if the first name references a DS record 2895218384Sdougb * and if that name is not the root remove a label as DS 2896218384Sdougb * records live in the parent zone so we need to start our 2897218384Sdougb * search one label up. 2898218384Sdougb */ 2899218384Sdougb tmprdataset = ISC_LIST_HEAD(firstname->list); 2900218384Sdougb if (section == DNS_SECTION_UPDATE && 2901218384Sdougb !dns_name_equal(firstname, dns_rootname) && 2902218384Sdougb tmprdataset->type == dns_rdatatype_ds) { 2903218384Sdougb unsigned int labels = dns_name_countlabels(name); 2904218384Sdougb dns_name_getlabelsequence(name, 1, labels - 1, name); 2905218384Sdougb } 2906170222Sdougb } 2907135446Strhodes 2908135446Strhodes ISC_LIST_INIT(name->list); 2909135446Strhodes ISC_LIST_APPEND(name->list, rdataset, link); 2910135446Strhodes dns_message_addname(soaquery, name, DNS_SECTION_QUESTION); 2911135446Strhodes 2912135446Strhodes if (userserver != NULL) 2913135446Strhodes sendrequest(localaddr, userserver, soaquery, &request); 2914135446Strhodes else { 2915135446Strhodes ns_inuse = 0; 2916135446Strhodes sendrequest(localaddr, &servers[ns_inuse], soaquery, &request); 2917135446Strhodes } 2918135446Strhodes} 2919135446Strhodes 2920135446Strhodesstatic void 2921135446Strhodescleanup(void) { 2922135446Strhodes ddebug("cleanup()"); 2923135446Strhodes 2924135446Strhodes if (answer != NULL) 2925135446Strhodes dns_message_destroy(&answer); 2926193149Sdougb 2927193149Sdougb#ifdef GSSAPI 2928193149Sdougb if (tsigkey != NULL) { 2929193149Sdougb ddebug("detach tsigkey x%p", tsigkey); 2930193149Sdougb dns_tsigkey_detach(&tsigkey); 2931193149Sdougb } 2932193149Sdougb if (gssring != NULL) { 2933224092Sdougb ddebug("Detaching GSS-TSIG keyring"); 2934224092Sdougb dns_tsigkeyring_detach(&gssring); 2935193149Sdougb } 2936193149Sdougb if (kserver != NULL) { 2937193149Sdougb isc_mem_put(mctx, kserver, sizeof(isc_sockaddr_t)); 2938193149Sdougb kserver = NULL; 2939193149Sdougb } 2940218384Sdougb if (realm != NULL) { 2941218384Sdougb isc_mem_free(mctx, realm); 2942218384Sdougb realm = NULL; 2943218384Sdougb } 2944193149Sdougb#endif 2945193149Sdougb 2946225361Sdougb if (sig0key != NULL) 2947225361Sdougb dst_key_free(&sig0key); 2948225361Sdougb 2949135446Strhodes ddebug("Shutting down task manager"); 2950135446Strhodes isc_taskmgr_destroy(&taskmgr); 2951135446Strhodes 2952135446Strhodes ddebug("Destroying event"); 2953135446Strhodes isc_event_free(&global_event); 2954135446Strhodes 2955135446Strhodes ddebug("Shutting down socket manager"); 2956135446Strhodes isc_socketmgr_destroy(&socketmgr); 2957135446Strhodes 2958135446Strhodes ddebug("Shutting down timer manager"); 2959135446Strhodes isc_timermgr_destroy(&timermgr); 2960135446Strhodes 2961135446Strhodes ddebug("Destroying hash context"); 2962135446Strhodes isc_hash_destroy(); 2963135446Strhodes 2964170222Sdougb ddebug("Destroying name state"); 2965170222Sdougb dns_name_destroy(); 2966170222Sdougb 2967193149Sdougb ddebug("Removing log context"); 2968193149Sdougb isc_log_destroy(&lctx); 2969193149Sdougb 2970135446Strhodes ddebug("Destroying memory context"); 2971135446Strhodes if (memdebugging) 2972135446Strhodes isc_mem_stats(mctx, stderr); 2973135446Strhodes isc_mem_destroy(&mctx); 2974135446Strhodes} 2975135446Strhodes 2976135446Strhodesstatic void 2977135446Strhodesgetinput(isc_task_t *task, isc_event_t *event) { 2978135446Strhodes isc_boolean_t more; 2979135446Strhodes 2980135446Strhodes UNUSED(task); 2981135446Strhodes 2982135446Strhodes if (shuttingdown) { 2983135446Strhodes maybeshutdown(); 2984135446Strhodes return; 2985135446Strhodes } 2986135446Strhodes 2987135446Strhodes if (global_event == NULL) 2988135446Strhodes global_event = event; 2989135446Strhodes 2990135446Strhodes reset_system(); 2991135446Strhodes more = user_interaction(); 2992135446Strhodes if (!more) { 2993135446Strhodes isc_app_shutdown(); 2994135446Strhodes return; 2995135446Strhodes } 2996135446Strhodes start_update(); 2997135446Strhodes return; 2998135446Strhodes} 2999135446Strhodes 3000135446Strhodesint 3001135446Strhodesmain(int argc, char **argv) { 3002135446Strhodes isc_result_t result; 3003135446Strhodes style = &dns_master_style_debug; 3004135446Strhodes 3005135446Strhodes input = stdin; 3006135446Strhodes 3007135446Strhodes interactive = ISC_TF(isatty(0)); 3008135446Strhodes 3009135446Strhodes isc_app_start(); 3010135446Strhodes 3011193149Sdougb pre_parse_args(argc, argv); 3012135446Strhodes 3013193149Sdougb result = isc_mem_create(0, 0, &mctx); 3014193149Sdougb check_result(result, "isc_mem_create"); 3015193149Sdougb 3016193149Sdougb parse_args(argc, argv, mctx, &entropy); 3017193149Sdougb 3018135446Strhodes setup_system(); 3019135446Strhodes 3020135446Strhodes result = isc_app_onrun(mctx, global_task, getinput, NULL); 3021135446Strhodes check_result(result, "isc_app_onrun"); 3022135446Strhodes 3023135446Strhodes (void)isc_app_run(); 3024135446Strhodes 3025135446Strhodes cleanup(); 3026135446Strhodes 3027135446Strhodes isc_app_finish(); 3028135446Strhodes 3029135446Strhodes if (seenerror) 3030135446Strhodes return (2); 3031135446Strhodes else 3032135446Strhodes return (0); 3033135446Strhodes} 3034