Home | History | Annotate | Line # | Download | only in nsupdate
      1 /*	$NetBSD: nsupdate.c,v 1.17 2026/04/08 00:15:44 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5  *
      6  * SPDX-License-Identifier: MPL-2.0
      7  *
      8  * This Source Code Form is subject to the terms of the Mozilla Public
      9  * License, v. 2.0. If a copy of the MPL was not distributed with this
     10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
     11  *
     12  * See the COPYRIGHT file distributed with this work for additional
     13  * information regarding copyright ownership.
     14  */
     15 
     16 /*! \file */
     17 
     18 #include <ctype.h>
     19 #include <errno.h>
     20 #include <inttypes.h>
     21 #include <limits.h>
     22 #include <stdbool.h>
     23 #include <stdlib.h>
     24 #include <unistd.h>
     25 
     26 #include <isc/async.h>
     27 #include <isc/attributes.h>
     28 #include <isc/base64.h>
     29 #include <isc/buffer.h>
     30 #include <isc/commandline.h>
     31 #include <isc/file.h>
     32 #include <isc/getaddresses.h>
     33 #include <isc/hash.h>
     34 #include <isc/lex.h>
     35 #include <isc/log.h>
     36 #include <isc/loop.h>
     37 #include <isc/managers.h>
     38 #include <isc/mem.h>
     39 #include <isc/netmgr.h>
     40 #include <isc/nonce.h>
     41 #include <isc/parseint.h>
     42 #include <isc/portset.h>
     43 #include <isc/random.h>
     44 #include <isc/region.h>
     45 #include <isc/result.h>
     46 #include <isc/sockaddr.h>
     47 #include <isc/stdio.h>
     48 #include <isc/string.h>
     49 #include <isc/tls.h>
     50 #include <isc/types.h>
     51 #include <isc/util.h>
     52 
     53 #include <dns/callbacks.h>
     54 #include <dns/dispatch.h>
     55 #include <dns/dnssec.h>
     56 #include <dns/fixedname.h>
     57 #include <dns/log.h>
     58 #include <dns/masterdump.h>
     59 #include <dns/message.h>
     60 #include <dns/name.h>
     61 #include <dns/nsec3.h>
     62 #include <dns/rcode.h>
     63 #include <dns/rdata.h>
     64 #include <dns/rdataclass.h>
     65 #include <dns/rdatalist.h>
     66 #include <dns/rdataset.h>
     67 #include <dns/rdatastruct.h>
     68 #include <dns/rdatatype.h>
     69 #include <dns/request.h>
     70 #include <dns/tkey.h>
     71 #include <dns/transport.h>
     72 #include <dns/tsig.h>
     73 
     74 #include <dst/dst.h>
     75 
     76 #include <isccfg/namedconf.h>
     77 
     78 #include <irs/resconf.h>
     79 
     80 #if HAVE_GSSAPI
     81 #include <dst/gssapi.h>
     82 
     83 #if HAVE_KRB5_KRB5_H
     84 #include <krb5/krb5.h>
     85 #elif HAVE_KRB5_H
     86 #include <krb5.h>
     87 #endif
     88 
     89 #if HAVE_GSSAPI_GSSAPI_H
     90 #include <gssapi/gssapi.h>
     91 #elif HAVE_GSSAPI_H
     92 #include <gssapi.h>
     93 #endif
     94 
     95 #endif /* HAVE_GSSAPI */
     96 
     97 #include "../dig/readline.h"
     98 
     99 #define MAXCMD	 (128 * 1024)
    100 #define MAXWIRE	 (64 * 1024)
    101 #define INITTEXT (2 * 1024)
    102 #define MAXTEXT	 (128 * 1024)
    103 #define TTL_MAX	 2147483647U /* Maximum signed 32 bit integer. */
    104 
    105 #define DNSDEFAULTPORT 53
    106 
    107 #define DEFAULT_EDNS_BUFSIZE 1232
    108 
    109 /* Number of addresses to request from isc_getaddresses() */
    110 #define MAX_SERVERADDRS 4
    111 
    112 static uint16_t dnsport = DNSDEFAULTPORT;
    113 
    114 #ifndef RESOLV_CONF
    115 #define RESOLV_CONF "/etc/resolv.conf"
    116 #endif /* ifndef RESOLV_CONF */
    117 
    118 static bool debugging = false, ddebugging = false;
    119 static bool memdebugging = false;
    120 static bool have_ipv4 = false;
    121 static bool have_ipv6 = false;
    122 static bool is_dst_up = false;
    123 static bool use_tls = false;
    124 static bool usevc = false;
    125 static bool usegsstsig = false;
    126 static bool local_only = false;
    127 static isc_nm_t *netmgr = NULL;
    128 static isc_loopmgr_t *loopmgr = NULL;
    129 static isc_log_t *glctx = NULL;
    130 static isc_mem_t *gmctx = NULL;
    131 static dns_dispatchmgr_t *dispatchmgr = NULL;
    132 static dns_requestmgr_t *requestmgr = NULL;
    133 static dns_dispatch_t *dispatchv4 = NULL;
    134 static dns_dispatch_t *dispatchv6 = NULL;
    135 static dns_message_t *updatemsg = NULL;
    136 static dns_fixedname_t fuserzone;
    137 static dns_fixedname_t fzname;
    138 static dns_name_t *userzone = NULL;
    139 static dns_name_t *zname = NULL;
    140 static dns_name_t tmpzonename = DNS_NAME_INITEMPTY;
    141 static dns_name_t restart_primary = DNS_NAME_INITEMPTY;
    142 static dns_tsigkeyring_t *gssring = NULL;
    143 static dns_tsigkey_t *tsigkey = NULL;
    144 static dst_key_t *sig0key = NULL;
    145 static isc_sockaddr_t *servers = NULL;
    146 static isc_sockaddr_t *primary_servers = NULL;
    147 static dns_transport_list_t *transport_list = NULL;
    148 static dns_transport_t *transport = NULL;
    149 static isc_tlsctx_cache_t *tls_ctx_cache = NULL;
    150 static char *tls_hostname = NULL;
    151 static char *tls_client_key_file = NULL;
    152 static char *tls_client_cert_file = NULL;
    153 static char *tls_ca_file = NULL;
    154 static bool tls_always_verify_remote = true;
    155 static bool default_servers = true;
    156 static int ns_inuse = 0;
    157 static int primary_inuse = 0;
    158 static int ns_total = 0;
    159 static int ns_alloc = 0;
    160 static int primary_total = 0;
    161 static int primary_alloc = 0;
    162 static isc_sockaddr_t *localaddr4 = NULL;
    163 static isc_sockaddr_t *localaddr6 = NULL;
    164 static const char *keyfile = NULL;
    165 static char *keystr = NULL;
    166 static bool shuttingdown = false;
    167 static FILE *input;
    168 static bool interactive = true;
    169 static bool seenerror = false;
    170 static const dns_master_style_t *style;
    171 static int requests = 0;
    172 static unsigned int logdebuglevel = 0;
    173 static unsigned int timeout = 300;
    174 static unsigned int udp_timeout = 3;
    175 static unsigned int udp_retries = 3;
    176 static dns_rdataclass_t defaultclass = dns_rdataclass_in;
    177 static dns_rdataclass_t zoneclass = dns_rdataclass_none;
    178 static isc_mutex_t answer_lock;
    179 static dns_message_t *answer = NULL;
    180 static uint32_t default_ttl = 0;
    181 static bool default_ttl_set = false;
    182 static uint32_t lease = 0, keylease = 0;
    183 static bool lease_set = false, keylease_set = false;
    184 static bool checknames = true;
    185 static bool checksvcb = true;
    186 static const char *resolvconf = RESOLV_CONF;
    187 
    188 bool done = false;
    189 
    190 typedef struct nsu_requestinfo {
    191 	dns_message_t *msg;
    192 	isc_sockaddr_t *addr;
    193 } nsu_requestinfo_t;
    194 
    195 static void
    196 sendrequest(isc_sockaddr_t *destaddr, dns_message_t *msg,
    197 	    dns_request_t **request);
    198 static void
    199 send_update(dns_name_t *zonename, isc_sockaddr_t *primary);
    200 
    201 static void
    202 getinput(void *arg);
    203 
    204 noreturn static void
    205 fatal(const char *format, ...) ISC_FORMAT_PRINTF(1, 2);
    206 
    207 static void
    208 debug(const char *format, ...) ISC_FORMAT_PRINTF(1, 2);
    209 
    210 static void
    211 ddebug(const char *format, ...) ISC_FORMAT_PRINTF(1, 2);
    212 
    213 #if HAVE_GSSAPI
    214 static dns_fixedname_t fkname;
    215 static isc_sockaddr_t *kserver = NULL;
    216 static char *realm = NULL;
    217 static char servicename[DNS_NAME_FORMATSIZE];
    218 static dns_name_t *keyname;
    219 typedef struct nsu_gssinfo {
    220 	dns_message_t *msg;
    221 	isc_sockaddr_t *addr;
    222 	gss_ctx_id_t context;
    223 } nsu_gssinfo_t;
    224 
    225 static void
    226 failed_gssrequest(void);
    227 static void
    228 start_gssrequest(dns_name_t *primary);
    229 static void
    230 send_gssrequest(isc_sockaddr_t *destaddr, dns_message_t *msg,
    231 		dns_request_t **request, gss_ctx_id_t context);
    232 static void
    233 recvgss(void *arg);
    234 #endif /* HAVE_GSSAPI */
    235 
    236 static void
    237 error(const char *format, ...) ISC_FORMAT_PRINTF(1, 2);
    238 
    239 #define STATUS_MORE   (uint16_t)0
    240 #define STATUS_SEND   (uint16_t)1
    241 #define STATUS_QUIT   (uint16_t)2
    242 #define STATUS_SYNTAX (uint16_t)3
    243 
    244 static void
    245 primary_from_servers(void) {
    246 	if (primary_servers != NULL && primary_servers != servers) {
    247 		isc_mem_cput(gmctx, primary_servers, primary_alloc,
    248 			     sizeof(isc_sockaddr_t));
    249 	}
    250 	primary_servers = servers;
    251 	primary_total = ns_total;
    252 	primary_alloc = ns_alloc;
    253 	primary_inuse = ns_inuse;
    254 }
    255 
    256 static dns_rdataclass_t
    257 getzoneclass(void) {
    258 	if (zoneclass == dns_rdataclass_none) {
    259 		zoneclass = defaultclass;
    260 	}
    261 	return zoneclass;
    262 }
    263 
    264 static bool
    265 setzoneclass(dns_rdataclass_t rdclass) {
    266 	if (zoneclass == dns_rdataclass_none || rdclass == dns_rdataclass_none)
    267 	{
    268 		zoneclass = rdclass;
    269 	}
    270 	if (zoneclass != rdclass) {
    271 		return false;
    272 	}
    273 	return true;
    274 }
    275 
    276 static void
    277 fatal(const char *format, ...) {
    278 	va_list args;
    279 
    280 	va_start(args, format);
    281 	vfprintf(stderr, format, args);
    282 	va_end(args);
    283 	fprintf(stderr, "\n");
    284 	_exit(EXIT_FAILURE);
    285 }
    286 
    287 static void
    288 error(const char *format, ...) {
    289 	va_list args;
    290 
    291 	va_start(args, format);
    292 	vfprintf(stderr, format, args);
    293 	va_end(args);
    294 	fprintf(stderr, "\n");
    295 }
    296 
    297 static void
    298 debug(const char *format, ...) {
    299 	va_list args;
    300 
    301 	if (debugging) {
    302 		va_start(args, format);
    303 		vfprintf(stderr, format, args);
    304 		va_end(args);
    305 		fprintf(stderr, "\n");
    306 	}
    307 }
    308 
    309 static void
    310 ddebug(const char *format, ...) {
    311 	va_list args;
    312 
    313 	if (ddebugging) {
    314 		va_start(args, format);
    315 		vfprintf(stderr, format, args);
    316 		va_end(args);
    317 		fprintf(stderr, "\n");
    318 	}
    319 }
    320 
    321 ISC_NO_SANITIZE_ADDRESS static void
    322 check_result(isc_result_t result, const char *msg) {
    323 	if (result != ISC_R_SUCCESS) {
    324 		fatal("%s: %s", msg, isc_result_totext(result));
    325 	}
    326 }
    327 
    328 static char *
    329 nsu_strsep(char **stringp, const char *delim) {
    330 	char *string = *stringp;
    331 	*stringp = NULL;
    332 	char *s;
    333 	const char *d;
    334 	char sc, dc;
    335 
    336 	if (string == NULL) {
    337 		return NULL;
    338 	}
    339 
    340 	for (; *string != '\0'; string++) {
    341 		sc = *string;
    342 		for (d = delim; (dc = *d) != '\0'; d++) {
    343 			if (sc == dc) {
    344 				break;
    345 			}
    346 		}
    347 		if (dc == 0) {
    348 			break;
    349 		}
    350 	}
    351 
    352 	for (s = string; *s != '\0'; s++) {
    353 		sc = *s;
    354 		for (d = delim; (dc = *d) != '\0'; d++) {
    355 			if (sc == dc) {
    356 				*s++ = '\0';
    357 				*stringp = s;
    358 				return string;
    359 			}
    360 		}
    361 	}
    362 	return string;
    363 }
    364 
    365 static void
    366 reset_system(void) {
    367 	ddebug("reset_system()");
    368 	/* If the update message is still around, destroy it */
    369 	if (updatemsg != NULL) {
    370 		dns_message_reset(updatemsg, DNS_MESSAGE_INTENTRENDER);
    371 	} else {
    372 		dns_message_create(gmctx, NULL, NULL, DNS_MESSAGE_INTENTRENDER,
    373 				   &updatemsg);
    374 	}
    375 	updatemsg->opcode = dns_opcode_update;
    376 	if (usegsstsig) {
    377 		if (tsigkey != NULL) {
    378 			dns_tsigkey_detach(&tsigkey);
    379 		}
    380 		if (gssring != NULL) {
    381 			dns_tsigkeyring_detach(&gssring);
    382 		}
    383 	}
    384 }
    385 
    386 static bool
    387 parse_hmac(const char *hmacstr, size_t len, dst_algorithm_t *hmac_alg,
    388 	   uint16_t *digestbitsp) {
    389 	uint16_t digestbits = 0;
    390 	isc_result_t result;
    391 	char buf[20];
    392 
    393 	REQUIRE(hmac_alg != NULL);
    394 	REQUIRE(hmacstr != NULL);
    395 
    396 	if (len >= sizeof(buf)) {
    397 		error("unknown key type '%.*s'", (int)(len), hmacstr);
    398 		return false;
    399 	}
    400 
    401 	/* Copy len bytes and NUL terminate. */
    402 	strlcpy(buf, hmacstr, ISC_MIN(len + 1, sizeof(buf)));
    403 
    404 	if (strcasecmp(buf, "hmac-md5") == 0) {
    405 		*hmac_alg = DST_ALG_HMACMD5;
    406 	} else if (strncasecmp(buf, "hmac-md5-", 9) == 0) {
    407 		*hmac_alg = DST_ALG_HMACMD5;
    408 		result = isc_parse_uint16(&digestbits, &buf[9], 10);
    409 		if (result != ISC_R_SUCCESS || digestbits > 128) {
    410 			error("digest-bits out of range [0..128]");
    411 			return false;
    412 		}
    413 		*digestbitsp = (digestbits + 7) & ~0x7U;
    414 	} else if (strcasecmp(buf, "hmac-sha1") == 0) {
    415 		*hmac_alg = DST_ALG_HMACSHA1;
    416 	} else if (strncasecmp(buf, "hmac-sha1-", 10) == 0) {
    417 		*hmac_alg = DST_ALG_HMACSHA1;
    418 		result = isc_parse_uint16(&digestbits, &buf[10], 10);
    419 		if (result != ISC_R_SUCCESS || digestbits > 160) {
    420 			error("digest-bits out of range [0..160]");
    421 			return false;
    422 		}
    423 		*digestbitsp = (digestbits + 7) & ~0x7U;
    424 	} else if (strcasecmp(buf, "hmac-sha224") == 0) {
    425 		*hmac_alg = DST_ALG_HMACSHA224;
    426 	} else if (strncasecmp(buf, "hmac-sha224-", 12) == 0) {
    427 		*hmac_alg = DST_ALG_HMACSHA224;
    428 		result = isc_parse_uint16(&digestbits, &buf[12], 10);
    429 		if (result != ISC_R_SUCCESS || digestbits > 224) {
    430 			error("digest-bits out of range [0..224]");
    431 			return false;
    432 		}
    433 		*digestbitsp = (digestbits + 7) & ~0x7U;
    434 	} else if (strcasecmp(buf, "hmac-sha256") == 0) {
    435 		*hmac_alg = DST_ALG_HMACSHA256;
    436 	} else if (strncasecmp(buf, "hmac-sha256-", 12) == 0) {
    437 		*hmac_alg = DST_ALG_HMACSHA256;
    438 		result = isc_parse_uint16(&digestbits, &buf[12], 10);
    439 		if (result != ISC_R_SUCCESS || digestbits > 256) {
    440 			error("digest-bits out of range [0..256]");
    441 			return false;
    442 		}
    443 		*digestbitsp = (digestbits + 7) & ~0x7U;
    444 	} else if (strcasecmp(buf, "hmac-sha384") == 0) {
    445 		*hmac_alg = DST_ALG_HMACSHA384;
    446 	} else if (strncasecmp(buf, "hmac-sha384-", 12) == 0) {
    447 		*hmac_alg = DST_ALG_HMACSHA384;
    448 		result = isc_parse_uint16(&digestbits, &buf[12], 10);
    449 		if (result != ISC_R_SUCCESS || digestbits > 384) {
    450 			error("digest-bits out of range [0..384]");
    451 			return false;
    452 		}
    453 		*digestbitsp = (digestbits + 7) & ~0x7U;
    454 	} else if (strcasecmp(buf, "hmac-sha512") == 0) {
    455 		*hmac_alg = DST_ALG_HMACSHA512;
    456 	} else if (strncasecmp(buf, "hmac-sha512-", 12) == 0) {
    457 		*hmac_alg = DST_ALG_HMACSHA512;
    458 		result = isc_parse_uint16(&digestbits, &buf[12], 10);
    459 		if (result != ISC_R_SUCCESS || digestbits > 512) {
    460 			error("digest-bits out of range [0..512]");
    461 			return false;
    462 		}
    463 		*digestbitsp = (digestbits + 7) & ~0x7U;
    464 	} else {
    465 		error("unknown key type '%s'", buf);
    466 		return false;
    467 	}
    468 	return true;
    469 }
    470 
    471 static int
    472 basenamelen(const char *file) {
    473 	int len = strlen(file);
    474 
    475 	if (len > 1 && file[len - 1] == '.') {
    476 		len -= 1;
    477 	} else if (len > 8 && strcmp(file + len - 8, ".private") == 0) {
    478 		len -= 8;
    479 	} else if (len > 4 && strcmp(file + len - 4, ".key") == 0) {
    480 		len -= 4;
    481 	}
    482 	return len;
    483 }
    484 
    485 static void
    486 setup_keystr(void) {
    487 	unsigned char *secret = NULL;
    488 	int secretlen;
    489 	isc_buffer_t secretbuf;
    490 	isc_result_t result;
    491 	isc_buffer_t keynamesrc;
    492 	char *secretstr = NULL;
    493 	char *s = NULL, *n = NULL;
    494 	dns_fixedname_t fkeyname;
    495 	dns_name_t *mykeyname = NULL;
    496 	char *name = NULL;
    497 	dst_algorithm_t hmac_alg;
    498 	uint16_t digestbits = 0;
    499 
    500 	mykeyname = dns_fixedname_initname(&fkeyname);
    501 
    502 	debug("Creating key...");
    503 
    504 	s = strchr(keystr, ':');
    505 	if (s == NULL || s == keystr || s[1] == 0) {
    506 		fatal("key option must specify [hmac:]keyname:secret");
    507 	}
    508 	secretstr = s + 1;
    509 	n = strchr(secretstr, ':');
    510 	if (n != NULL) {
    511 		if (n == secretstr || n[1] == 0) {
    512 			fatal("key option must specify [hmac:]keyname:secret");
    513 		}
    514 		name = secretstr;
    515 		secretstr = n + 1;
    516 		if (!parse_hmac(keystr, s - keystr, &hmac_alg, &digestbits)) {
    517 			exit(EXIT_FAILURE);
    518 		}
    519 	} else {
    520 		hmac_alg = DST_ALG_HMACMD5;
    521 		name = keystr;
    522 		n = s;
    523 	}
    524 
    525 	isc_buffer_init(&keynamesrc, name, (unsigned int)(n - name));
    526 	isc_buffer_add(&keynamesrc, (unsigned int)(n - name));
    527 
    528 	debug("namefromtext");
    529 	result = dns_name_fromtext(mykeyname, &keynamesrc, dns_rootname, 0,
    530 				   NULL);
    531 	check_result(result, "dns_name_fromtext");
    532 
    533 	secretlen = strlen(secretstr) * 3 / 4;
    534 	secret = isc_mem_allocate(gmctx, secretlen);
    535 
    536 	isc_buffer_init(&secretbuf, secret, secretlen);
    537 	result = isc_base64_decodestring(secretstr, &secretbuf);
    538 	if (result != ISC_R_SUCCESS) {
    539 		fprintf(stderr, "could not create key from %s: %s\n", keystr,
    540 			isc_result_totext(result));
    541 		goto failure;
    542 	}
    543 
    544 	secretlen = isc_buffer_usedlength(&secretbuf);
    545 
    546 	debug("keycreate");
    547 	result = dns_tsigkey_create(mykeyname, hmac_alg, secret, secretlen,
    548 				    gmctx, &tsigkey);
    549 	if (result != ISC_R_SUCCESS) {
    550 		fprintf(stderr, "could not create key from %s: %s\n", keystr,
    551 			isc_result_totext(result));
    552 	} else {
    553 		dst_key_setbits(tsigkey->key, digestbits);
    554 	}
    555 failure:
    556 	if (secret != NULL) {
    557 		isc_mem_free(gmctx, secret);
    558 	}
    559 }
    560 
    561 /*
    562  * Get a key from a named.conf format keyfile
    563  */
    564 static isc_result_t
    565 read_sessionkey(isc_mem_t *mctx, isc_log_t *lctx) {
    566 	cfg_parser_t *pctx = NULL;
    567 	cfg_obj_t *sessionkey = NULL;
    568 	const cfg_obj_t *key = NULL;
    569 	const cfg_obj_t *secretobj = NULL;
    570 	const cfg_obj_t *algorithmobj = NULL;
    571 	const char *mykeyname;
    572 	const char *secretstr;
    573 	const char *algorithm;
    574 	isc_result_t result;
    575 	int len;
    576 
    577 	if (!isc_file_exists(keyfile)) {
    578 		return ISC_R_FILENOTFOUND;
    579 	}
    580 
    581 	result = cfg_parser_create(mctx, lctx, &pctx);
    582 	if (result != ISC_R_SUCCESS) {
    583 		goto cleanup;
    584 	}
    585 
    586 	result = cfg_parse_file(pctx, keyfile, &cfg_type_sessionkey,
    587 				&sessionkey);
    588 	if (result != ISC_R_SUCCESS) {
    589 		goto cleanup;
    590 	}
    591 
    592 	result = cfg_map_get(sessionkey, "key", &key);
    593 	if (result != ISC_R_SUCCESS) {
    594 		goto cleanup;
    595 	}
    596 
    597 	(void)cfg_map_get(key, "secret", &secretobj);
    598 	(void)cfg_map_get(key, "algorithm", &algorithmobj);
    599 	if (secretobj == NULL || algorithmobj == NULL) {
    600 		fatal("key must have algorithm and secret");
    601 	}
    602 
    603 	mykeyname = cfg_obj_asstring(cfg_map_getname(key));
    604 	secretstr = cfg_obj_asstring(secretobj);
    605 	algorithm = cfg_obj_asstring(algorithmobj);
    606 
    607 	len = strlen(algorithm) + strlen(mykeyname) + strlen(secretstr) + 3;
    608 	keystr = isc_mem_allocate(mctx, len);
    609 	snprintf(keystr, len, "%s:%s:%s", algorithm, mykeyname, secretstr);
    610 	setup_keystr();
    611 
    612 cleanup:
    613 	if (pctx != NULL) {
    614 		if (sessionkey != NULL) {
    615 			cfg_obj_destroy(pctx, &sessionkey);
    616 		}
    617 		cfg_parser_destroy(&pctx);
    618 	}
    619 
    620 	if (keystr != NULL) {
    621 		isc_mem_free(mctx, keystr);
    622 	}
    623 
    624 	return result;
    625 }
    626 
    627 static void
    628 setup_keyfile(isc_mem_t *mctx, isc_log_t *lctx) {
    629 	dst_key_t *dstkey = NULL;
    630 	isc_result_t result;
    631 	dst_algorithm_t hmac_alg = DST_ALG_UNKNOWN;
    632 
    633 	debug("Creating key...");
    634 
    635 	if (sig0key != NULL) {
    636 		dst_key_free(&sig0key);
    637 	}
    638 
    639 	/* Try reading the key from a K* pair */
    640 	result = dst_key_fromnamedfile(
    641 		keyfile, NULL, DST_TYPE_PRIVATE | DST_TYPE_KEY, mctx, &dstkey);
    642 
    643 	/* If that didn't work, try reading it as a session.key keyfile */
    644 	if (result != ISC_R_SUCCESS) {
    645 		result = read_sessionkey(mctx, lctx);
    646 		if (result == ISC_R_SUCCESS) {
    647 			return;
    648 		}
    649 	}
    650 
    651 	if (result != ISC_R_SUCCESS) {
    652 		fprintf(stderr,
    653 			"could not read key from %.*s.{private,key}: "
    654 			"%s\n",
    655 			basenamelen(keyfile), keyfile,
    656 			isc_result_totext(result));
    657 		return;
    658 	}
    659 
    660 	switch (dst_key_alg(dstkey)) {
    661 	case DST_ALG_HMACMD5:
    662 	case DST_ALG_HMACSHA1:
    663 	case DST_ALG_HMACSHA224:
    664 	case DST_ALG_HMACSHA256:
    665 	case DST_ALG_HMACSHA384:
    666 	case DST_ALG_HMACSHA512:
    667 		hmac_alg = dst_key_alg(dstkey);
    668 		break;
    669 	default:
    670 		dst_key_attach(dstkey, &sig0key);
    671 		dst_key_free(&dstkey);
    672 		return;
    673 	}
    674 
    675 	result = dns_tsigkey_createfromkey(dst_key_name(dstkey), hmac_alg,
    676 					   dstkey, false, false, NULL, 0, 0,
    677 					   mctx, &tsigkey);
    678 	dst_key_free(&dstkey);
    679 	if (result != ISC_R_SUCCESS) {
    680 		fprintf(stderr, "could not create key from %s: %s\n", keyfile,
    681 			isc_result_totext(result));
    682 	}
    683 }
    684 
    685 static void
    686 doshutdown(void) {
    687 	/*
    688 	 * The isc_mem_put of primary_servers must be before the
    689 	 * isc_mem_put of servers as it sets the servers pointer
    690 	 * to NULL.
    691 	 */
    692 	if (primary_servers != NULL && primary_servers != servers) {
    693 		isc_mem_cput(gmctx, primary_servers, primary_alloc,
    694 			     sizeof(isc_sockaddr_t));
    695 	}
    696 
    697 	if (servers != NULL) {
    698 		isc_mem_cput(gmctx, servers, ns_alloc, sizeof(isc_sockaddr_t));
    699 	}
    700 
    701 	if (localaddr4 != NULL) {
    702 		isc_mem_put(gmctx, localaddr4, sizeof(isc_sockaddr_t));
    703 	}
    704 
    705 	if (localaddr6 != NULL) {
    706 		isc_mem_put(gmctx, localaddr6, sizeof(isc_sockaddr_t));
    707 	}
    708 
    709 	if (tsigkey != NULL) {
    710 		ddebug("Freeing TSIG key");
    711 		dns_tsigkey_detach(&tsigkey);
    712 	}
    713 
    714 	if (sig0key != NULL) {
    715 		ddebug("Freeing SIG(0) key");
    716 		dst_key_free(&sig0key);
    717 	}
    718 
    719 	if (updatemsg != NULL) {
    720 		dns_message_detach(&updatemsg);
    721 	}
    722 
    723 	ddebug("Destroying request manager");
    724 	dns_requestmgr_detach(&requestmgr);
    725 
    726 	ddebug("Freeing the dispatchers");
    727 	if (have_ipv4) {
    728 		dns_dispatch_detach(&dispatchv4);
    729 	}
    730 	if (have_ipv6) {
    731 		dns_dispatch_detach(&dispatchv6);
    732 	}
    733 
    734 	ddebug("Shutting down dispatch manager");
    735 	dns_dispatchmgr_detach(&dispatchmgr);
    736 }
    737 
    738 static void
    739 maybeshutdown(void) {
    740 	/* when called from getinput, doshutdown might be already finished */
    741 	if (requestmgr == NULL) {
    742 		return;
    743 	}
    744 
    745 	ddebug("Shutting down request manager");
    746 	dns_requestmgr_shutdown(requestmgr);
    747 
    748 	if (requests != 0) {
    749 		return;
    750 	}
    751 
    752 	doshutdown();
    753 }
    754 
    755 static void
    756 shutdown_program(void *arg) {
    757 	UNUSED(arg);
    758 
    759 	ddebug("shutdown_program()");
    760 
    761 	shuttingdown = true;
    762 	maybeshutdown();
    763 }
    764 
    765 /*
    766  * Try honoring the operating system's preferred ephemeral port range.
    767  */
    768 static void
    769 set_source_ports(dns_dispatchmgr_t *manager) {
    770 	isc_portset_t *v4portset = NULL, *v6portset = NULL;
    771 	in_port_t udpport_low, udpport_high;
    772 	isc_result_t result;
    773 
    774 	result = isc_portset_create(gmctx, &v4portset);
    775 	check_result(result, "isc_portset_create (v4)");
    776 	isc_net_getportrange(AF_INET, &udpport_low, &udpport_high);
    777 	isc_portset_addrange(v4portset, udpport_low, udpport_high);
    778 
    779 	result = isc_portset_create(gmctx, &v6portset);
    780 	check_result(result, "isc_portset_create (v6)");
    781 	isc_net_getportrange(AF_INET6, &udpport_low, &udpport_high);
    782 	isc_portset_addrange(v6portset, udpport_low, udpport_high);
    783 
    784 	result = dns_dispatchmgr_setavailports(manager, v4portset, v6portset);
    785 	check_result(result, "dns_dispatchmgr_setavailports");
    786 
    787 	isc_portset_destroy(gmctx, &v4portset);
    788 	isc_portset_destroy(gmctx, &v6portset);
    789 }
    790 
    791 static isc_result_t
    792 create_name(const char *str, char *namedata, size_t len, dns_name_t *name) {
    793 	isc_buffer_t namesrc, namebuf;
    794 
    795 	dns_name_init(name, NULL);
    796 	isc_buffer_constinit(&namesrc, str, strlen(str));
    797 	isc_buffer_add(&namesrc, strlen(str));
    798 	isc_buffer_init(&namebuf, namedata, len);
    799 
    800 	return dns_name_fromtext(name, &namesrc, dns_rootname,
    801 				 DNS_NAME_DOWNCASE, &namebuf);
    802 }
    803 
    804 static void
    805 setup_system(void *arg ISC_ATTR_UNUSED) {
    806 	isc_result_t result;
    807 	isc_sockaddr_t bind_any, bind_any6;
    808 	isc_sockaddrlist_t *nslist;
    809 	isc_logconfig_t *logconfig = NULL;
    810 	irs_resconf_t *resconf = NULL;
    811 	dns_name_t tlsname;
    812 	char namedata[DNS_NAME_FORMATSIZE + 1];
    813 
    814 	ddebug("setup_system()");
    815 
    816 	isc_log_create(gmctx, &glctx, &logconfig);
    817 	isc_log_setcontext(glctx);
    818 	dns_log_init(glctx);
    819 	dns_log_setcontext(glctx);
    820 
    821 	result = isc_log_usechannel(logconfig, "default_debug", NULL, NULL);
    822 	check_result(result, "isc_log_usechannel");
    823 
    824 	isc_log_setdebuglevel(glctx, logdebuglevel);
    825 
    826 	result = irs_resconf_load(gmctx, resolvconf, &resconf);
    827 	if (result != ISC_R_SUCCESS && result != ISC_R_FILENOTFOUND) {
    828 		fatal("parse of %s failed", resolvconf);
    829 	}
    830 
    831 	nslist = irs_resconf_getnameservers(resconf);
    832 
    833 	if (servers != NULL) {
    834 		if (primary_servers == servers) {
    835 			primary_servers = NULL;
    836 		}
    837 		isc_mem_cput(gmctx, servers, ns_alloc, sizeof(isc_sockaddr_t));
    838 	}
    839 
    840 	ns_inuse = 0;
    841 	if (local_only || ISC_LIST_EMPTY(*nslist)) {
    842 		struct in_addr in;
    843 		struct in6_addr in6;
    844 
    845 		if (local_only && keyfile == NULL) {
    846 			keyfile = SESSION_KEYFILE;
    847 		}
    848 
    849 		default_servers = !local_only;
    850 
    851 		ns_total = ns_alloc = (have_ipv4 ? 1 : 0) + (have_ipv6 ? 1 : 0);
    852 		servers = isc_mem_cget(gmctx, ns_alloc, sizeof(isc_sockaddr_t));
    853 
    854 		if (have_ipv6) {
    855 			memset(&in6, 0, sizeof(in6));
    856 			in6.s6_addr[15] = 1;
    857 			isc_sockaddr_fromin6(&servers[0], &in6, dnsport);
    858 		}
    859 		if (have_ipv4) {
    860 			in.s_addr = htonl(INADDR_LOOPBACK);
    861 			isc_sockaddr_fromin(&servers[(have_ipv6 ? 1 : 0)], &in,
    862 					    dnsport);
    863 		}
    864 	} else {
    865 		isc_sockaddr_t *sa;
    866 		int i;
    867 
    868 		/*
    869 		 * Count the nameservers (skipping any that we can't use
    870 		 * because of address family restrictions) and allocate
    871 		 * the servers array.
    872 		 */
    873 		ns_total = 0;
    874 		for (sa = ISC_LIST_HEAD(*nslist); sa != NULL;
    875 		     sa = ISC_LIST_NEXT(sa, link))
    876 		{
    877 			switch (sa->type.sa.sa_family) {
    878 			case AF_INET:
    879 				if (have_ipv4) {
    880 					ns_total++;
    881 				}
    882 				break;
    883 			case AF_INET6:
    884 				if (have_ipv6) {
    885 					ns_total++;
    886 				}
    887 				break;
    888 			default:
    889 				fatal("bad family");
    890 			}
    891 		}
    892 
    893 		ns_alloc = ns_total;
    894 		servers = isc_mem_cget(gmctx, ns_alloc, sizeof(isc_sockaddr_t));
    895 
    896 		i = 0;
    897 		for (sa = ISC_LIST_HEAD(*nslist); sa != NULL;
    898 		     sa = ISC_LIST_NEXT(sa, link))
    899 		{
    900 			switch (sa->type.sa.sa_family) {
    901 			case AF_INET:
    902 				if (have_ipv4) {
    903 					sa->type.sin.sin_port = htons(dnsport);
    904 				} else {
    905 					continue;
    906 				}
    907 				break;
    908 			case AF_INET6:
    909 				if (have_ipv6) {
    910 					sa->type.sin6.sin6_port =
    911 						htons(dnsport);
    912 				} else {
    913 					continue;
    914 				}
    915 				break;
    916 			default:
    917 				fatal("bad family");
    918 			}
    919 			INSIST(i < ns_alloc);
    920 			servers[i++] = *sa;
    921 		}
    922 	}
    923 
    924 	irs_resconf_destroy(&resconf);
    925 
    926 	result = dns_dispatchmgr_create(gmctx, loopmgr, netmgr, &dispatchmgr);
    927 	check_result(result, "dns_dispatchmgr_create");
    928 
    929 	result = dst_lib_init(gmctx, NULL);
    930 	check_result(result, "dst_lib_init");
    931 	is_dst_up = true;
    932 
    933 	set_source_ports(dispatchmgr);
    934 
    935 	if (have_ipv6) {
    936 		isc_sockaddr_any6(&bind_any6);
    937 		result = dns_dispatch_createudp(dispatchmgr, &bind_any6,
    938 						&dispatchv6);
    939 		check_result(result, "dns_dispatch_createudp (v6)");
    940 	}
    941 
    942 	if (have_ipv4) {
    943 		isc_sockaddr_any(&bind_any);
    944 		result = dns_dispatch_createudp(dispatchmgr, &bind_any,
    945 						&dispatchv4);
    946 		check_result(result, "dns_dispatch_createudp (v4)");
    947 	}
    948 	transport_list = dns_transport_list_new(gmctx);
    949 
    950 	isc_tlsctx_cache_create(gmctx, &tls_ctx_cache);
    951 
    952 	if (tls_client_key_file == NULL) {
    953 		result = create_name("tls-non-auth-client", namedata,
    954 				     sizeof(namedata), &tlsname);
    955 		check_result(result, "create_name (tls-non-auth-client)");
    956 		transport = dns_transport_new(&tlsname, DNS_TRANSPORT_TLS,
    957 					      transport_list);
    958 		dns_transport_set_tlsname(transport, "tls-non-auth-client");
    959 	} else {
    960 		result = create_name("tls-auth-client", namedata,
    961 				     sizeof(namedata), &tlsname);
    962 		check_result(result, "create_name (tls-auth-client)");
    963 		transport = dns_transport_new(&tlsname, DNS_TRANSPORT_TLS,
    964 					      transport_list);
    965 		dns_transport_set_tlsname(transport, "tls-auth-client");
    966 		dns_transport_set_keyfile(transport, tls_client_key_file);
    967 		dns_transport_set_certfile(transport, tls_client_cert_file);
    968 	}
    969 	dns_transport_set_cafile(transport, tls_ca_file);
    970 	dns_transport_set_remote_hostname(transport, tls_hostname);
    971 	dns_transport_set_always_verify_remote(transport,
    972 					       tls_always_verify_remote);
    973 
    974 	result = dns_requestmgr_create(gmctx, loopmgr, dispatchmgr, dispatchv4,
    975 				       dispatchv6, &requestmgr);
    976 	check_result(result, "dns_requestmgr_create");
    977 
    978 	if (keystr != NULL) {
    979 		setup_keystr();
    980 	} else if (local_only) {
    981 		result = read_sessionkey(gmctx, glctx);
    982 		if (result != ISC_R_SUCCESS) {
    983 			fatal("can't read key from %s: %s\n", keyfile,
    984 			      isc_result_totext(result));
    985 		}
    986 	} else if (keyfile != NULL) {
    987 		setup_keyfile(gmctx, glctx);
    988 	}
    989 
    990 	isc_mutex_init(&answer_lock);
    991 }
    992 
    993 static int
    994 get_addresses(char *host, in_port_t port, isc_sockaddr_t *sockaddr,
    995 	      int naddrs) {
    996 	int count = 0;
    997 	isc_result_t result;
    998 
    999 	isc_loopmgr_blocking(loopmgr);
   1000 	result = isc_getaddresses(host, port, sockaddr, naddrs, &count);
   1001 	isc_loopmgr_nonblocking(loopmgr);
   1002 	if (result != ISC_R_SUCCESS) {
   1003 		error("couldn't get address for '%s': %s", host,
   1004 		      isc_result_totext(result));
   1005 	}
   1006 	return count;
   1007 }
   1008 
   1009 #define PARSE_ARGS_FMT "46A:C:dDE:ghH:iK:lL:MoOk:p:Pr:R:St:Tu:vVy:"
   1010 
   1011 static void
   1012 pre_parse_args(int argc, char **argv) {
   1013 	dns_rdatatype_t t;
   1014 	int ch;
   1015 	char buf[100];
   1016 	bool doexit = false;
   1017 	bool ipv4only = false, ipv6only = false;
   1018 
   1019 	while ((ch = isc_commandline_parse(argc, argv, PARSE_ARGS_FMT)) != -1) {
   1020 		switch (ch) {
   1021 		case 'M': /* was -dm */
   1022 			debugging = true;
   1023 			ddebugging = true;
   1024 			memdebugging = true;
   1025 			isc_mem_debugging = ISC_MEM_DEBUGTRACE |
   1026 					    ISC_MEM_DEBUGRECORD;
   1027 			break;
   1028 
   1029 		case '4':
   1030 			if (ipv6only) {
   1031 				fatal("only one of -4 and -6 allowed");
   1032 			}
   1033 			ipv4only = true;
   1034 			break;
   1035 
   1036 		case '6':
   1037 			if (ipv4only) {
   1038 				fatal("only one of -4 and -6 allowed");
   1039 			}
   1040 			ipv6only = true;
   1041 			break;
   1042 
   1043 		case '?':
   1044 		case 'h':
   1045 			if (isc_commandline_option != '?') {
   1046 				fprintf(stderr, "%s: invalid argument -%c\n",
   1047 					argv[0], isc_commandline_option);
   1048 			}
   1049 			fprintf(stderr, "usage: nsupdate [-CdDi] [-L level] "
   1050 					"[-l] [-g | -o | -y keyname:secret "
   1051 					"| -k keyfile] [-p port] "
   1052 					"[ -S [-K tlskeyfile] [-E tlscertfile] "
   1053 					"[-A tlscafile] [-H tlshostname] "
   1054 					"[-O] ] [-v] [-V] [-P] [-T] [-4 | -6] "
   1055 					"[filename]\n");
   1056 			exit(EXIT_FAILURE);
   1057 
   1058 		case 'P':
   1059 			for (t = 0xff00; t <= 0xfffe; t++) {
   1060 				if (dns_rdatatype_ismeta(t)) {
   1061 					continue;
   1062 				}
   1063 				dns_rdatatype_format(t, buf, sizeof(buf));
   1064 				if (strncmp(buf, "TYPE", 4) != 0) {
   1065 					fprintf(stdout, "%s\n", buf);
   1066 				}
   1067 			}
   1068 			doexit = true;
   1069 			break;
   1070 
   1071 		case 'T':
   1072 			for (t = 1; t <= 0xfeff; t++) {
   1073 				if (dns_rdatatype_ismeta(t)) {
   1074 					continue;
   1075 				}
   1076 				dns_rdatatype_format(t, buf, sizeof(buf));
   1077 				if (strncmp(buf, "TYPE", 4) != 0) {
   1078 					fprintf(stdout, "%s\n", buf);
   1079 				}
   1080 			}
   1081 			doexit = true;
   1082 			break;
   1083 
   1084 		case 'V':
   1085 			printf("nsupdate %s\n", PACKAGE_VERSION);
   1086 			doexit = true;
   1087 			break;
   1088 
   1089 		default:
   1090 			break;
   1091 		}
   1092 	}
   1093 	if (doexit) {
   1094 		exit(EXIT_SUCCESS);
   1095 	}
   1096 	isc_commandline_reset = true;
   1097 	isc_commandline_index = 1;
   1098 }
   1099 
   1100 static void
   1101 parse_args(int argc, char **argv) {
   1102 	int ch;
   1103 	uint32_t i;
   1104 	isc_result_t result;
   1105 	bool force_interactive = false;
   1106 
   1107 	debug("parse_args");
   1108 	while ((ch = isc_commandline_parse(argc, argv, PARSE_ARGS_FMT)) != -1) {
   1109 		switch (ch) {
   1110 		case '4':
   1111 			if (have_ipv4) {
   1112 				isc_net_disableipv6();
   1113 				have_ipv6 = false;
   1114 			} else {
   1115 				fatal("can't find IPv4 networking");
   1116 			}
   1117 			break;
   1118 		case '6':
   1119 			if (have_ipv6) {
   1120 				isc_net_disableipv4();
   1121 				have_ipv4 = false;
   1122 			} else {
   1123 				fatal("can't find IPv6 networking");
   1124 			}
   1125 			break;
   1126 		case 'A':
   1127 			use_tls = true;
   1128 			tls_ca_file = isc_commandline_argument;
   1129 			break;
   1130 		case 'C':
   1131 			resolvconf = isc_commandline_argument;
   1132 			break;
   1133 		case 'd':
   1134 			debugging = true;
   1135 			break;
   1136 		case 'D': /* was -dd */
   1137 			debugging = true;
   1138 			ddebugging = true;
   1139 			break;
   1140 		case 'E':
   1141 			use_tls = true;
   1142 			tls_client_cert_file = isc_commandline_argument;
   1143 			break;
   1144 		case 'H':
   1145 			use_tls = true;
   1146 			tls_hostname = isc_commandline_argument;
   1147 			break;
   1148 		case 'M':
   1149 			break;
   1150 		case 'i':
   1151 			force_interactive = true;
   1152 			interactive = true;
   1153 			break;
   1154 		case 'K':
   1155 			use_tls = true;
   1156 			tls_client_key_file = isc_commandline_argument;
   1157 			break;
   1158 		case 'l':
   1159 			local_only = true;
   1160 			break;
   1161 		case 'L':
   1162 			result = isc_parse_uint32(&i, isc_commandline_argument,
   1163 						  10);
   1164 			if (result != ISC_R_SUCCESS) {
   1165 				fprintf(stderr,
   1166 					"bad library debug value "
   1167 					"'%s'\n",
   1168 					isc_commandline_argument);
   1169 				exit(EXIT_FAILURE);
   1170 			}
   1171 			logdebuglevel = i;
   1172 			break;
   1173 		case 'y':
   1174 			keystr = isc_commandline_argument;
   1175 			break;
   1176 		case 'v':
   1177 			usevc = true;
   1178 			break;
   1179 		case 'k':
   1180 			keyfile = isc_commandline_argument;
   1181 			break;
   1182 		case 'g':
   1183 			usegsstsig = true;
   1184 			break;
   1185 		case 'o':
   1186 			usegsstsig = true;
   1187 			break;
   1188 		case 'O':
   1189 			use_tls = true;
   1190 			tls_always_verify_remote = false;
   1191 			break;
   1192 		case 'p':
   1193 			result = isc_parse_uint16(&dnsport,
   1194 						  isc_commandline_argument, 10);
   1195 			if (result != ISC_R_SUCCESS) {
   1196 				fprintf(stderr,
   1197 					"bad port number "
   1198 					"'%s'\n",
   1199 					isc_commandline_argument);
   1200 				exit(EXIT_FAILURE);
   1201 			}
   1202 			break;
   1203 		case 'S':
   1204 			use_tls = true;
   1205 			break;
   1206 		case 't':
   1207 			result = isc_parse_uint32(&timeout,
   1208 						  isc_commandline_argument, 10);
   1209 			if (result != ISC_R_SUCCESS) {
   1210 				fprintf(stderr, "bad timeout '%s'\n",
   1211 					isc_commandline_argument);
   1212 				exit(EXIT_FAILURE);
   1213 			}
   1214 			if (timeout == 0) {
   1215 				timeout = UINT_MAX;
   1216 			}
   1217 			break;
   1218 		case 'u':
   1219 			result = isc_parse_uint32(&udp_timeout,
   1220 						  isc_commandline_argument, 10);
   1221 			if (result != ISC_R_SUCCESS) {
   1222 				fprintf(stderr, "bad udp timeout '%s'\n",
   1223 					isc_commandline_argument);
   1224 				exit(EXIT_FAILURE);
   1225 			}
   1226 			break;
   1227 		case 'r':
   1228 			result = isc_parse_uint32(&udp_retries,
   1229 						  isc_commandline_argument, 10);
   1230 			if (result != ISC_R_SUCCESS) {
   1231 				fprintf(stderr, "bad udp retries '%s'\n",
   1232 					isc_commandline_argument);
   1233 				exit(EXIT_FAILURE);
   1234 			}
   1235 			break;
   1236 
   1237 		case 'R':
   1238 			fatal("The -R option has been deprecated.");
   1239 			break;
   1240 
   1241 		default:
   1242 			fprintf(stderr, "%s: unhandled option: %c\n", argv[0],
   1243 				isc_commandline_option);
   1244 			exit(EXIT_FAILURE);
   1245 		}
   1246 	}
   1247 	if (keyfile != NULL && keystr != NULL) {
   1248 		fprintf(stderr, "%s: cannot specify both -k and -y\n", argv[0]);
   1249 		exit(EXIT_FAILURE);
   1250 	}
   1251 
   1252 #if HAVE_GSSAPI
   1253 	if (usegsstsig && (keyfile != NULL || keystr != NULL)) {
   1254 		fprintf(stderr, "%s: cannot specify -g with -k or -y\n",
   1255 			argv[0]);
   1256 		exit(EXIT_FAILURE);
   1257 	}
   1258 #else  /* HAVE_GSSAPI */
   1259 	if (usegsstsig) {
   1260 		fprintf(stderr,
   1261 			"%s: cannot specify -g	or -o, "
   1262 			"program not linked with GSS API Library\n",
   1263 			argv[0]);
   1264 		exit(EXIT_FAILURE);
   1265 	}
   1266 #endif /* HAVE_GSSAPI */
   1267 
   1268 	if (use_tls) {
   1269 		usevc = true;
   1270 		if ((tls_client_key_file == NULL) !=
   1271 		    (tls_client_cert_file == NULL))
   1272 		{
   1273 			fprintf(stderr,
   1274 				"%s: cannot specify the -K option without"
   1275 				"the -E option, and vice versa.\n",
   1276 				argv[0]);
   1277 			exit(EXIT_FAILURE);
   1278 		}
   1279 		if (tls_ca_file != NULL && tls_always_verify_remote == false) {
   1280 			fprintf(stderr,
   1281 				"%s: cannot specify the -A option in "
   1282 				"conjuction with the -O option.\n",
   1283 				argv[0]);
   1284 			exit(EXIT_FAILURE);
   1285 		}
   1286 	}
   1287 
   1288 	if (argv[isc_commandline_index] != NULL) {
   1289 		if (strcmp(argv[isc_commandline_index], "-") == 0) {
   1290 			input = stdin;
   1291 		} else {
   1292 			result = isc_stdio_open(argv[isc_commandline_index],
   1293 						"r", &input);
   1294 			if (result != ISC_R_SUCCESS) {
   1295 				fprintf(stderr, "could not open '%s': %s\n",
   1296 					argv[isc_commandline_index],
   1297 					isc_result_totext(result));
   1298 				exit(EXIT_FAILURE);
   1299 			}
   1300 		}
   1301 		if (!force_interactive) {
   1302 			interactive = false;
   1303 		}
   1304 	}
   1305 }
   1306 
   1307 static uint16_t
   1308 parse_name(char **cmdlinep, dns_message_t *msg, dns_name_t **namep) {
   1309 	isc_result_t result;
   1310 	char *word;
   1311 	isc_buffer_t source;
   1312 
   1313 	word = nsu_strsep(cmdlinep, " \t\r\n");
   1314 	if (word == NULL || *word == 0) {
   1315 		fprintf(stderr, "could not read owner name\n");
   1316 		return STATUS_SYNTAX;
   1317 	}
   1318 
   1319 	dns_message_gettempname(msg, namep);
   1320 	isc_buffer_init(&source, word, strlen(word));
   1321 	isc_buffer_add(&source, strlen(word));
   1322 	result = dns_name_fromtext(*namep, &source, dns_rootname, 0, NULL);
   1323 	if (result != ISC_R_SUCCESS) {
   1324 		error("invalid owner name: %s", isc_result_totext(result));
   1325 		isc_buffer_invalidate(&source);
   1326 		dns_message_puttempname(msg, namep);
   1327 		return STATUS_SYNTAX;
   1328 	}
   1329 	isc_buffer_invalidate(&source);
   1330 	return STATUS_MORE;
   1331 }
   1332 
   1333 static uint16_t
   1334 parse_rdata(char **cmdlinep, dns_rdataclass_t rdataclass,
   1335 	    dns_rdatatype_t rdatatype, dns_message_t *msg, dns_rdata_t *rdata) {
   1336 	char *cmdline = *cmdlinep;
   1337 	isc_buffer_t source, *buf = NULL, *newbuf = NULL;
   1338 	isc_region_t r;
   1339 	isc_lex_t *lex = NULL;
   1340 	dns_rdatacallbacks_t callbacks;
   1341 	isc_result_t result;
   1342 
   1343 	if (cmdline == NULL) {
   1344 		rdata->flags = DNS_RDATA_UPDATE;
   1345 		return STATUS_MORE;
   1346 	}
   1347 
   1348 	while (*cmdline != 0 && isspace((unsigned char)*cmdline)) {
   1349 		cmdline++;
   1350 	}
   1351 
   1352 	if (*cmdline != 0) {
   1353 		dns_rdatacallbacks_init(&callbacks);
   1354 		isc_lex_create(gmctx, strlen(cmdline), &lex);
   1355 		isc_buffer_init(&source, cmdline, strlen(cmdline));
   1356 		isc_buffer_add(&source, strlen(cmdline));
   1357 		result = isc_lex_openbuffer(lex, &source);
   1358 		check_result(result, "isc_lex_openbuffer");
   1359 		isc_buffer_allocate(gmctx, &buf, MAXWIRE);
   1360 		result = dns_rdata_fromtext(NULL, rdataclass, rdatatype, lex,
   1361 					    dns_rootname, 0, gmctx, buf,
   1362 					    &callbacks);
   1363 		isc_lex_destroy(&lex);
   1364 		if (result == ISC_R_SUCCESS) {
   1365 			isc_buffer_usedregion(buf, &r);
   1366 			isc_buffer_allocate(gmctx, &newbuf, r.length);
   1367 			isc_buffer_putmem(newbuf, r.base, r.length);
   1368 			isc_buffer_usedregion(newbuf, &r);
   1369 			dns_rdata_fromregion(rdata, rdataclass, rdatatype, &r);
   1370 			isc_buffer_free(&buf);
   1371 			dns_message_takebuffer(msg, &newbuf);
   1372 		} else {
   1373 			fprintf(stderr, "invalid rdata format: %s\n",
   1374 				isc_result_totext(result));
   1375 			isc_buffer_free(&buf);
   1376 			return STATUS_SYNTAX;
   1377 		}
   1378 	} else {
   1379 		rdata->flags = DNS_RDATA_UPDATE;
   1380 	}
   1381 	*cmdlinep = cmdline;
   1382 	return STATUS_MORE;
   1383 }
   1384 
   1385 static uint16_t
   1386 make_prereq(char *cmdline, bool ispositive, bool isrrset) {
   1387 	isc_result_t result;
   1388 	char *word;
   1389 	dns_name_t *name = NULL;
   1390 	isc_textregion_t region;
   1391 	dns_rdataset_t *rdataset = NULL;
   1392 	dns_rdatalist_t *rdatalist = NULL;
   1393 	dns_rdataclass_t rdataclass;
   1394 	dns_rdatatype_t rdatatype;
   1395 	dns_rdata_t *rdata = NULL;
   1396 	uint16_t retval;
   1397 
   1398 	ddebug("make_prereq()");
   1399 
   1400 	/*
   1401 	 * Read the owner name
   1402 	 */
   1403 	retval = parse_name(&cmdline, updatemsg, &name);
   1404 	if (retval != STATUS_MORE) {
   1405 		return retval;
   1406 	}
   1407 
   1408 	/*
   1409 	 * If this is an rrset prereq, read the class or type.
   1410 	 */
   1411 	if (isrrset) {
   1412 		word = nsu_strsep(&cmdline, " \t\r\n");
   1413 		if (word == NULL || *word == 0) {
   1414 			fprintf(stderr, "could not read class or type\n");
   1415 			goto failure;
   1416 		}
   1417 		region.base = word;
   1418 		region.length = strlen(word);
   1419 		result = dns_rdataclass_fromtext(&rdataclass, &region);
   1420 		if (result == ISC_R_SUCCESS) {
   1421 			if (!setzoneclass(rdataclass)) {
   1422 				fprintf(stderr, "class mismatch: %s\n", word);
   1423 				goto failure;
   1424 			}
   1425 			/*
   1426 			 * Now read the type.
   1427 			 */
   1428 			word = nsu_strsep(&cmdline, " \t\r\n");
   1429 			if (word == NULL || *word == 0) {
   1430 				fprintf(stderr, "could not read type\n");
   1431 				goto failure;
   1432 			}
   1433 			region.base = word;
   1434 			region.length = strlen(word);
   1435 			result = dns_rdatatype_fromtext(&rdatatype, &region);
   1436 			if (result != ISC_R_SUCCESS) {
   1437 				fprintf(stderr, "invalid type: %s\n", word);
   1438 				goto failure;
   1439 			}
   1440 		} else {
   1441 			rdataclass = getzoneclass();
   1442 			result = dns_rdatatype_fromtext(&rdatatype, &region);
   1443 			if (result != ISC_R_SUCCESS) {
   1444 				fprintf(stderr, "invalid type: %s\n", word);
   1445 				goto failure;
   1446 			}
   1447 		}
   1448 	} else {
   1449 		rdatatype = dns_rdatatype_any;
   1450 	}
   1451 
   1452 	dns_message_gettemprdata(updatemsg, &rdata);
   1453 
   1454 	dns_rdata_init(rdata);
   1455 
   1456 	if (isrrset && ispositive) {
   1457 		retval = parse_rdata(&cmdline, rdataclass, rdatatype, updatemsg,
   1458 				     rdata);
   1459 		if (retval != STATUS_MORE) {
   1460 			goto failure;
   1461 		}
   1462 	} else {
   1463 		rdata->flags = DNS_RDATA_UPDATE;
   1464 	}
   1465 
   1466 	dns_message_gettemprdatalist(updatemsg, &rdatalist);
   1467 	dns_message_gettemprdataset(updatemsg, &rdataset);
   1468 	rdatalist->type = rdatatype;
   1469 	if (ispositive) {
   1470 		if (isrrset && rdata->data != NULL) {
   1471 			rdatalist->rdclass = rdataclass;
   1472 		} else {
   1473 			rdatalist->rdclass = dns_rdataclass_any;
   1474 		}
   1475 	} else {
   1476 		rdatalist->rdclass = dns_rdataclass_none;
   1477 	}
   1478 	rdata->rdclass = rdatalist->rdclass;
   1479 	rdata->type = rdatatype;
   1480 	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
   1481 	dns_rdatalist_tordataset(rdatalist, rdataset);
   1482 	ISC_LIST_INIT(name->list);
   1483 	ISC_LIST_APPEND(name->list, rdataset, link);
   1484 	dns_message_addname(updatemsg, name, DNS_SECTION_PREREQUISITE);
   1485 	return STATUS_MORE;
   1486 
   1487 failure:
   1488 	if (name != NULL) {
   1489 		dns_message_puttempname(updatemsg, &name);
   1490 	}
   1491 	return STATUS_SYNTAX;
   1492 }
   1493 
   1494 static uint16_t
   1495 evaluate_prereq(char *cmdline) {
   1496 	char *word;
   1497 	bool ispositive, isrrset;
   1498 
   1499 	ddebug("evaluate_prereq()");
   1500 	word = nsu_strsep(&cmdline, " \t\r\n");
   1501 	if (word == NULL || *word == 0) {
   1502 		fprintf(stderr, "could not read operation code\n");
   1503 		return STATUS_SYNTAX;
   1504 	}
   1505 	if (strcasecmp(word, "nxdomain") == 0) {
   1506 		ispositive = false;
   1507 		isrrset = false;
   1508 	} else if (strcasecmp(word, "yxdomain") == 0) {
   1509 		ispositive = true;
   1510 		isrrset = false;
   1511 	} else if (strcasecmp(word, "nxrrset") == 0) {
   1512 		ispositive = false;
   1513 		isrrset = true;
   1514 	} else if (strcasecmp(word, "yxrrset") == 0) {
   1515 		ispositive = true;
   1516 		isrrset = true;
   1517 	} else {
   1518 		fprintf(stderr, "incorrect operation code: %s\n", word);
   1519 		return STATUS_SYNTAX;
   1520 	}
   1521 	return make_prereq(cmdline, ispositive, isrrset);
   1522 }
   1523 
   1524 static void
   1525 updateopt(void) {
   1526 	isc_result_t result;
   1527 	dns_ednsopt_t ednsopts[1];
   1528 	unsigned char ul[8];
   1529 	unsigned int count = 0;
   1530 
   1531 	if (lease_set) {
   1532 		isc_buffer_t b;
   1533 		INSIST(count < ARRAY_SIZE(ednsopts));
   1534 		ednsopts[count++] = (dns_ednsopt_t){ .code = DNS_OPT_UL,
   1535 						     .length = keylease_set ? 8
   1536 									    : 4,
   1537 						     .value = ul };
   1538 
   1539 		isc_buffer_init(&b, ul, sizeof(ul));
   1540 		isc_buffer_putuint32(&b, lease);
   1541 		isc_buffer_putuint32(&b, keylease);
   1542 	}
   1543 
   1544 	if (count != 0) {
   1545 		dns_rdataset_t *opt = NULL;
   1546 		result = dns_message_buildopt(updatemsg, &opt, 0,
   1547 					      DEFAULT_EDNS_BUFSIZE, 0, ednsopts,
   1548 					      count);
   1549 		check_result(result, "dns_message_buildopt");
   1550 		result = dns_message_setopt(updatemsg, opt);
   1551 		check_result(result, "dns_message_setopt");
   1552 	} else {
   1553 		result = dns_message_setopt(updatemsg, NULL);
   1554 		check_result(result, "dns_message_setopt");
   1555 	}
   1556 }
   1557 
   1558 static uint16_t
   1559 evaluate_lease(char *cmdline) {
   1560 	char *word;
   1561 	isc_result_t result;
   1562 	uint32_t value1, value2;
   1563 
   1564 	word = nsu_strsep(&cmdline, " \t\r\n");
   1565 	if (word == NULL || *word == 0) {
   1566 		fprintf(stderr, "could not read ttl\n");
   1567 		return STATUS_SYNTAX;
   1568 	}
   1569 
   1570 	if (!strcasecmp(word, "none")) {
   1571 		lease = 0;
   1572 		lease_set = false;
   1573 		keylease = 0;
   1574 		keylease_set = false;
   1575 		updateopt();
   1576 		return STATUS_MORE;
   1577 	}
   1578 
   1579 	result = isc_parse_uint32(&value1, word, 10);
   1580 	if (result != ISC_R_SUCCESS) {
   1581 		return STATUS_SYNTAX;
   1582 	}
   1583 
   1584 	word = nsu_strsep(&cmdline, " \t\r\n");
   1585 	if (word == NULL || *word == 0) {
   1586 		lease = value1;
   1587 		lease_set = true;
   1588 		keylease = 0;
   1589 		keylease_set = false;
   1590 		updateopt();
   1591 		return STATUS_MORE;
   1592 	}
   1593 
   1594 	result = isc_parse_uint32(&value2, word, 10);
   1595 	if (result != ISC_R_SUCCESS) {
   1596 		return STATUS_SYNTAX;
   1597 	}
   1598 
   1599 	lease = value1;
   1600 	lease_set = true;
   1601 	keylease = value2;
   1602 	keylease_set = true;
   1603 	updateopt();
   1604 
   1605 	return STATUS_MORE;
   1606 }
   1607 
   1608 static uint16_t
   1609 evaluate_server(char *cmdline) {
   1610 	char *word, *server;
   1611 	long port;
   1612 
   1613 	if (local_only) {
   1614 		fprintf(stderr, "cannot reset server in localhost-only mode\n");
   1615 		return STATUS_SYNTAX;
   1616 	}
   1617 
   1618 	word = nsu_strsep(&cmdline, " \t\r\n");
   1619 	if (word == NULL || *word == 0) {
   1620 		fprintf(stderr, "could not read server name\n");
   1621 		return STATUS_SYNTAX;
   1622 	}
   1623 	server = word;
   1624 
   1625 	word = nsu_strsep(&cmdline, " \t\r\n");
   1626 	if (word == NULL || *word == 0) {
   1627 		port = dnsport;
   1628 	} else {
   1629 		char *endp;
   1630 		port = strtol(word, &endp, 10);
   1631 		if (*endp != 0) {
   1632 			fprintf(stderr, "port '%s' is not numeric\n", word);
   1633 			return STATUS_SYNTAX;
   1634 		} else if (port < 1 || port > 65535) {
   1635 			fprintf(stderr,
   1636 				"port '%s' is out of range "
   1637 				"(1 to 65535)\n",
   1638 				word);
   1639 			return STATUS_SYNTAX;
   1640 		}
   1641 	}
   1642 
   1643 	if (servers != NULL) {
   1644 		if (primary_servers == servers) {
   1645 			primary_servers = NULL;
   1646 		}
   1647 		isc_mem_cput(gmctx, servers, ns_alloc, sizeof(isc_sockaddr_t));
   1648 	}
   1649 
   1650 	default_servers = false;
   1651 
   1652 	ns_alloc = MAX_SERVERADDRS;
   1653 	ns_inuse = 0;
   1654 	servers = isc_mem_cget(gmctx, ns_alloc, sizeof(isc_sockaddr_t));
   1655 	ns_total = get_addresses(server, (in_port_t)port, servers, ns_alloc);
   1656 	if (ns_total == 0) {
   1657 		return STATUS_SYNTAX;
   1658 	}
   1659 
   1660 	return STATUS_MORE;
   1661 }
   1662 
   1663 static uint16_t
   1664 evaluate_local(char *cmdline) {
   1665 	char *word, *local;
   1666 	long port;
   1667 	struct in_addr in4;
   1668 	struct in6_addr in6;
   1669 
   1670 	word = nsu_strsep(&cmdline, " \t\r\n");
   1671 	if (word == NULL || *word == 0) {
   1672 		fprintf(stderr, "could not read server name\n");
   1673 		return STATUS_SYNTAX;
   1674 	}
   1675 	local = word;
   1676 
   1677 	word = nsu_strsep(&cmdline, " \t\r\n");
   1678 	if (word == NULL || *word == 0) {
   1679 		port = 0;
   1680 	} else {
   1681 		char *endp;
   1682 		port = strtol(word, &endp, 10);
   1683 		if (*endp != 0) {
   1684 			fprintf(stderr, "port '%s' is not numeric\n", word);
   1685 			return STATUS_SYNTAX;
   1686 		} else if (port < 1 || port > 65535) {
   1687 			fprintf(stderr,
   1688 				"port '%s' is out of range "
   1689 				"(1 to 65535)\n",
   1690 				word);
   1691 			return STATUS_SYNTAX;
   1692 		}
   1693 	}
   1694 
   1695 	if (have_ipv6 && inet_pton(AF_INET6, local, &in6) == 1) {
   1696 		if (localaddr6 == NULL) {
   1697 			localaddr6 = isc_mem_get(gmctx, sizeof(isc_sockaddr_t));
   1698 		}
   1699 		isc_sockaddr_fromin6(localaddr6, &in6, (in_port_t)port);
   1700 	} else if (have_ipv4 && inet_pton(AF_INET, local, &in4) == 1) {
   1701 		if (localaddr4 == NULL) {
   1702 			localaddr4 = isc_mem_get(gmctx, sizeof(isc_sockaddr_t));
   1703 		}
   1704 		isc_sockaddr_fromin(localaddr4, &in4, (in_port_t)port);
   1705 	} else {
   1706 		fprintf(stderr, "invalid address %s", local);
   1707 		return STATUS_SYNTAX;
   1708 	}
   1709 
   1710 	return STATUS_MORE;
   1711 }
   1712 
   1713 static uint16_t
   1714 evaluate_key(char *cmdline) {
   1715 	char *namestr;
   1716 	char *secretstr;
   1717 	isc_buffer_t b;
   1718 	isc_result_t result;
   1719 	dns_fixedname_t fkeyname;
   1720 	dns_name_t *mykeyname;
   1721 	int secretlen;
   1722 	unsigned char *secret = NULL;
   1723 	isc_buffer_t secretbuf;
   1724 	dst_algorithm_t hmac_alg = DST_ALG_UNKNOWN;
   1725 	uint16_t digestbits = 0;
   1726 	char *n;
   1727 
   1728 	namestr = nsu_strsep(&cmdline, " \t\r\n");
   1729 	if (namestr == NULL || *namestr == 0) {
   1730 		fprintf(stderr, "could not read key name\n");
   1731 		return STATUS_SYNTAX;
   1732 	}
   1733 
   1734 	mykeyname = dns_fixedname_initname(&fkeyname);
   1735 
   1736 	n = strchr(namestr, ':');
   1737 	if (n != NULL) {
   1738 		if (!parse_hmac(namestr, n - namestr, &hmac_alg, &digestbits)) {
   1739 			return STATUS_SYNTAX;
   1740 		}
   1741 		namestr = n + 1;
   1742 	} else {
   1743 		hmac_alg = DST_ALG_HMACMD5;
   1744 	}
   1745 
   1746 	isc_buffer_init(&b, namestr, strlen(namestr));
   1747 	isc_buffer_add(&b, strlen(namestr));
   1748 	result = dns_name_fromtext(mykeyname, &b, dns_rootname, 0, NULL);
   1749 	if (result != ISC_R_SUCCESS) {
   1750 		fprintf(stderr, "could not parse key name\n");
   1751 		return STATUS_SYNTAX;
   1752 	}
   1753 
   1754 	secretstr = nsu_strsep(&cmdline, "\r\n");
   1755 	if (secretstr == NULL || *secretstr == 0) {
   1756 		fprintf(stderr, "could not read key secret\n");
   1757 		return STATUS_SYNTAX;
   1758 	}
   1759 	secretlen = strlen(secretstr) * 3 / 4;
   1760 	secret = isc_mem_allocate(gmctx, secretlen);
   1761 
   1762 	isc_buffer_init(&secretbuf, secret, secretlen);
   1763 	result = isc_base64_decodestring(secretstr, &secretbuf);
   1764 	if (result != ISC_R_SUCCESS) {
   1765 		fprintf(stderr, "could not create key from %s: %s\n", secretstr,
   1766 			isc_result_totext(result));
   1767 		isc_mem_free(gmctx, secret);
   1768 		return STATUS_SYNTAX;
   1769 	}
   1770 	secretlen = isc_buffer_usedlength(&secretbuf);
   1771 
   1772 	if (tsigkey != NULL) {
   1773 		dns_tsigkey_detach(&tsigkey);
   1774 	}
   1775 	result = dns_tsigkey_create(mykeyname, hmac_alg, secret, secretlen,
   1776 				    gmctx, &tsigkey);
   1777 	isc_mem_free(gmctx, secret);
   1778 	if (result != ISC_R_SUCCESS) {
   1779 		fprintf(stderr, "could not create key from %s %s: %s\n",
   1780 			namestr, secretstr, isc_result_totext(result));
   1781 		return STATUS_SYNTAX;
   1782 	}
   1783 	dst_key_setbits(tsigkey->key, digestbits);
   1784 	return STATUS_MORE;
   1785 }
   1786 
   1787 static uint16_t
   1788 evaluate_zone(char *cmdline) {
   1789 	char *word;
   1790 	isc_buffer_t b;
   1791 	isc_result_t result;
   1792 
   1793 	word = nsu_strsep(&cmdline, " \t\r\n");
   1794 	if (word == NULL || *word == 0) {
   1795 		fprintf(stderr, "could not read zone name\n");
   1796 		return STATUS_SYNTAX;
   1797 	}
   1798 
   1799 	userzone = dns_fixedname_initname(&fuserzone);
   1800 	isc_buffer_init(&b, word, strlen(word));
   1801 	isc_buffer_add(&b, strlen(word));
   1802 	result = dns_name_fromtext(userzone, &b, dns_rootname, 0, NULL);
   1803 	if (result != ISC_R_SUCCESS) {
   1804 		userzone = NULL; /* Lest it point to an invalid name */
   1805 		fprintf(stderr, "could not parse zone name\n");
   1806 		return STATUS_SYNTAX;
   1807 	}
   1808 
   1809 	return STATUS_MORE;
   1810 }
   1811 
   1812 static uint16_t
   1813 evaluate_realm(char *cmdline) {
   1814 #if HAVE_GSSAPI
   1815 	char *word;
   1816 	char buf[1024];
   1817 	int n;
   1818 
   1819 	if (realm != NULL) {
   1820 		isc_mem_free(gmctx, realm);
   1821 		realm = NULL;
   1822 	}
   1823 
   1824 	word = nsu_strsep(&cmdline, " \t\r\n");
   1825 	if (word == NULL || *word == 0) {
   1826 		return STATUS_MORE;
   1827 	}
   1828 
   1829 	n = snprintf(buf, sizeof(buf), "@%s", word);
   1830 	if (n < 0 || (size_t)n >= sizeof(buf)) {
   1831 		error("realm is too long");
   1832 		return STATUS_SYNTAX;
   1833 	}
   1834 	realm = isc_mem_strdup(gmctx, buf);
   1835 	return STATUS_MORE;
   1836 #else  /* HAVE_GSSAPI */
   1837 	UNUSED(cmdline);
   1838 	return STATUS_SYNTAX;
   1839 #endif /* HAVE_GSSAPI */
   1840 }
   1841 
   1842 static uint16_t
   1843 evaluate_ttl(char *cmdline) {
   1844 	char *word;
   1845 	isc_result_t result;
   1846 	uint32_t ttl;
   1847 
   1848 	word = nsu_strsep(&cmdline, " \t\r\n");
   1849 	if (word == NULL || *word == 0) {
   1850 		fprintf(stderr, "could not read ttl\n");
   1851 		return STATUS_SYNTAX;
   1852 	}
   1853 
   1854 	if (!strcasecmp(word, "none")) {
   1855 		default_ttl = 0;
   1856 		default_ttl_set = false;
   1857 		return STATUS_MORE;
   1858 	}
   1859 
   1860 	result = isc_parse_uint32(&ttl, word, 10);
   1861 	if (result != ISC_R_SUCCESS) {
   1862 		return STATUS_SYNTAX;
   1863 	}
   1864 
   1865 	if (ttl > TTL_MAX) {
   1866 		fprintf(stderr, "ttl '%s' is out of range (0 to %u)\n", word,
   1867 			TTL_MAX);
   1868 		return STATUS_SYNTAX;
   1869 	}
   1870 	default_ttl = ttl;
   1871 	default_ttl_set = true;
   1872 
   1873 	return STATUS_MORE;
   1874 }
   1875 
   1876 static uint16_t
   1877 evaluate_class(char *cmdline) {
   1878 	char *word;
   1879 	isc_textregion_t r;
   1880 	isc_result_t result;
   1881 	dns_rdataclass_t rdclass;
   1882 
   1883 	word = nsu_strsep(&cmdline, " \t\r\n");
   1884 	if (word == NULL || *word == 0) {
   1885 		fprintf(stderr, "could not read class name\n");
   1886 		return STATUS_SYNTAX;
   1887 	}
   1888 
   1889 	r.base = word;
   1890 	r.length = strlen(word);
   1891 	result = dns_rdataclass_fromtext(&rdclass, &r);
   1892 	if (result != ISC_R_SUCCESS) {
   1893 		fprintf(stderr, "could not parse class name: %s\n", word);
   1894 		return STATUS_SYNTAX;
   1895 	}
   1896 	switch (rdclass) {
   1897 	case dns_rdataclass_none:
   1898 	case dns_rdataclass_any:
   1899 	case dns_rdataclass_reserved0:
   1900 		fprintf(stderr, "bad default class: %s\n", word);
   1901 		return STATUS_SYNTAX;
   1902 	default:
   1903 		defaultclass = rdclass;
   1904 	}
   1905 
   1906 	return STATUS_MORE;
   1907 }
   1908 
   1909 static uint16_t
   1910 update_addordelete(char *cmdline, bool isdelete) {
   1911 	isc_result_t result;
   1912 	dns_name_t *name = NULL;
   1913 	uint32_t ttl;
   1914 	char *word;
   1915 	dns_rdataclass_t rdataclass;
   1916 	dns_rdatatype_t rdatatype;
   1917 	dns_rdata_t *rdata = NULL;
   1918 	dns_rdatalist_t *rdatalist = NULL;
   1919 	dns_rdataset_t *rdataset = NULL;
   1920 	isc_textregion_t region;
   1921 	uint16_t retval;
   1922 
   1923 	ddebug("update_addordelete()");
   1924 
   1925 	/*
   1926 	 * Read the owner name.
   1927 	 */
   1928 	retval = parse_name(&cmdline, updatemsg, &name);
   1929 	if (retval != STATUS_MORE) {
   1930 		return retval;
   1931 	}
   1932 
   1933 	dns_message_gettemprdata(updatemsg, &rdata);
   1934 
   1935 	dns_rdata_init(rdata);
   1936 
   1937 	/*
   1938 	 * If this is an add, read the TTL and verify that it's in range.
   1939 	 * If it's a delete, ignore a TTL if present (for compatibility).
   1940 	 */
   1941 	word = nsu_strsep(&cmdline, " \t\r\n");
   1942 	if (word == NULL || *word == 0) {
   1943 		if (!isdelete) {
   1944 			fprintf(stderr, "could not read owner ttl\n");
   1945 			goto failure;
   1946 		} else {
   1947 			ttl = 0;
   1948 			rdataclass = dns_rdataclass_any;
   1949 			rdatatype = dns_rdatatype_any;
   1950 			rdata->flags = DNS_RDATA_UPDATE;
   1951 			goto doneparsing;
   1952 		}
   1953 	}
   1954 	result = isc_parse_uint32(&ttl, word, 10);
   1955 	if (result != ISC_R_SUCCESS) {
   1956 		if (isdelete) {
   1957 			ttl = 0;
   1958 			goto parseclass;
   1959 		} else if (default_ttl_set) {
   1960 			ttl = default_ttl;
   1961 			goto parseclass;
   1962 		} else {
   1963 			fprintf(stderr, "ttl '%s': %s\n", word,
   1964 				isc_result_totext(result));
   1965 			goto failure;
   1966 		}
   1967 	}
   1968 
   1969 	if (isdelete) {
   1970 		ttl = 0;
   1971 	} else if (ttl > TTL_MAX) {
   1972 		fprintf(stderr, "ttl '%s' is out of range (0 to %u)\n", word,
   1973 			TTL_MAX);
   1974 		goto failure;
   1975 	}
   1976 
   1977 	/*
   1978 	 * Read the class or type.
   1979 	 */
   1980 	word = nsu_strsep(&cmdline, " \t\r\n");
   1981 parseclass:
   1982 	if (word == NULL || *word == 0) {
   1983 		if (isdelete) {
   1984 			rdataclass = dns_rdataclass_any;
   1985 			rdatatype = dns_rdatatype_any;
   1986 			rdata->flags = DNS_RDATA_UPDATE;
   1987 			goto doneparsing;
   1988 		} else {
   1989 			fprintf(stderr, "could not read class or type\n");
   1990 			goto failure;
   1991 		}
   1992 	}
   1993 	region.base = word;
   1994 	region.length = strlen(word);
   1995 	rdataclass = dns_rdataclass_any;
   1996 	result = dns_rdataclass_fromtext(&rdataclass, &region);
   1997 	if (result == ISC_R_SUCCESS && rdataclass != dns_rdataclass_any) {
   1998 		if (!setzoneclass(rdataclass)) {
   1999 			fprintf(stderr, "class mismatch: %s\n", word);
   2000 			goto failure;
   2001 		}
   2002 		/*
   2003 		 * Now read the type.
   2004 		 */
   2005 		word = nsu_strsep(&cmdline, " \t\r\n");
   2006 		if (word == NULL || *word == 0) {
   2007 			if (isdelete) {
   2008 				rdataclass = dns_rdataclass_any;
   2009 				rdatatype = dns_rdatatype_any;
   2010 				rdata->flags = DNS_RDATA_UPDATE;
   2011 				goto doneparsing;
   2012 			} else {
   2013 				fprintf(stderr, "could not read type\n");
   2014 				goto failure;
   2015 			}
   2016 		}
   2017 		region.base = word;
   2018 		region.length = strlen(word);
   2019 		result = dns_rdatatype_fromtext(&rdatatype, &region);
   2020 		if (result != ISC_R_SUCCESS) {
   2021 			fprintf(stderr, "'%s' is not a valid type: %s\n", word,
   2022 				isc_result_totext(result));
   2023 			goto failure;
   2024 		}
   2025 	} else {
   2026 		rdataclass = getzoneclass();
   2027 		result = dns_rdatatype_fromtext(&rdatatype, &region);
   2028 		if (result != ISC_R_SUCCESS) {
   2029 			fprintf(stderr,
   2030 				"'%s' is not a valid class or type: "
   2031 				"%s\n",
   2032 				word, isc_result_totext(result));
   2033 			goto failure;
   2034 		}
   2035 	}
   2036 
   2037 	retval = parse_rdata(&cmdline, rdataclass, rdatatype, updatemsg, rdata);
   2038 	if (retval != STATUS_MORE) {
   2039 		goto failure;
   2040 	}
   2041 
   2042 	if (isdelete) {
   2043 		if ((rdata->flags & DNS_RDATA_UPDATE) != 0) {
   2044 			rdataclass = dns_rdataclass_any;
   2045 		} else {
   2046 			rdataclass = dns_rdataclass_none;
   2047 		}
   2048 	} else {
   2049 		if ((rdata->flags & DNS_RDATA_UPDATE) != 0) {
   2050 			fprintf(stderr, "could not read rdata\n");
   2051 			goto failure;
   2052 		}
   2053 	}
   2054 
   2055 	if (!isdelete && checknames) {
   2056 		dns_fixedname_t fixed;
   2057 		dns_name_t *bad;
   2058 
   2059 		if (!dns_rdata_checkowner(name, rdata->rdclass, rdata->type,
   2060 					  true))
   2061 		{
   2062 			char namebuf[DNS_NAME_FORMATSIZE];
   2063 
   2064 			dns_name_format(name, namebuf, sizeof(namebuf));
   2065 			fprintf(stderr, "check-names failed: bad owner '%s'\n",
   2066 				namebuf);
   2067 			goto failure;
   2068 		}
   2069 
   2070 		bad = dns_fixedname_initname(&fixed);
   2071 		if (!dns_rdata_checknames(rdata, name, bad)) {
   2072 			char namebuf[DNS_NAME_FORMATSIZE];
   2073 
   2074 			dns_name_format(bad, namebuf, sizeof(namebuf));
   2075 			fprintf(stderr, "check-names failed: bad name '%s'\n",
   2076 				namebuf);
   2077 			goto failure;
   2078 		}
   2079 	}
   2080 
   2081 	if (!isdelete && checksvcb && rdata->type == dns_rdatatype_svcb) {
   2082 		result = dns_rdata_checksvcb(name, rdata);
   2083 		if (result != ISC_R_SUCCESS) {
   2084 			fprintf(stderr, "check-svcb failed: %s\n",
   2085 				isc_result_totext(result));
   2086 			goto failure;
   2087 		}
   2088 	}
   2089 
   2090 	if (!isdelete && rdata->type == dns_rdatatype_nsec3param) {
   2091 		dns_rdata_nsec3param_t nsec3param;
   2092 
   2093 		result = dns_rdata_tostruct(rdata, &nsec3param, NULL);
   2094 		check_result(result, "dns_rdata_tostruct");
   2095 		if (nsec3param.iterations > dns_nsec3_maxiterations()) {
   2096 			fprintf(stderr,
   2097 				"NSEC3PARAM has excessive iterations (> %u)\n",
   2098 				dns_nsec3_maxiterations());
   2099 			goto failure;
   2100 		}
   2101 	}
   2102 
   2103 doneparsing:
   2104 
   2105 	dns_message_gettemprdatalist(updatemsg, &rdatalist);
   2106 	dns_message_gettemprdataset(updatemsg, &rdataset);
   2107 	rdatalist->type = rdatatype;
   2108 	rdatalist->rdclass = rdataclass;
   2109 	rdatalist->covers = rdatatype;
   2110 	rdatalist->ttl = (dns_ttl_t)ttl;
   2111 	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
   2112 	dns_rdatalist_tordataset(rdatalist, rdataset);
   2113 	ISC_LIST_INIT(name->list);
   2114 	ISC_LIST_APPEND(name->list, rdataset, link);
   2115 	dns_message_addname(updatemsg, name, DNS_SECTION_UPDATE);
   2116 	return STATUS_MORE;
   2117 
   2118 failure:
   2119 	if (name != NULL) {
   2120 		dns_message_puttempname(updatemsg, &name);
   2121 	}
   2122 	dns_message_puttemprdata(updatemsg, &rdata);
   2123 	return STATUS_SYNTAX;
   2124 }
   2125 
   2126 static uint16_t
   2127 evaluate_update(char *cmdline) {
   2128 	char *word;
   2129 	bool isdelete;
   2130 
   2131 	ddebug("evaluate_update()");
   2132 	word = nsu_strsep(&cmdline, " \t\r\n");
   2133 	if (word == NULL || *word == 0) {
   2134 		fprintf(stderr, "could not read operation code\n");
   2135 		return STATUS_SYNTAX;
   2136 	}
   2137 	if (strcasecmp(word, "delete") == 0) {
   2138 		isdelete = true;
   2139 	} else if (strcasecmp(word, "del") == 0) {
   2140 		isdelete = true;
   2141 	} else if (strcasecmp(word, "add") == 0) {
   2142 		isdelete = false;
   2143 	} else {
   2144 		fprintf(stderr, "incorrect operation code: %s\n", word);
   2145 		return STATUS_SYNTAX;
   2146 	}
   2147 	return update_addordelete(cmdline, isdelete);
   2148 }
   2149 
   2150 static uint16_t
   2151 evaluate_checknames(char *cmdline) {
   2152 	char *word;
   2153 
   2154 	ddebug("evaluate_checknames()");
   2155 	word = nsu_strsep(&cmdline, " \t\r\n");
   2156 	if (word == NULL || *word == 0) {
   2157 		fprintf(stderr, "could not read check-names directive\n");
   2158 		return STATUS_SYNTAX;
   2159 	}
   2160 	if (strcasecmp(word, "yes") == 0 || strcasecmp(word, "true") == 0 ||
   2161 	    strcasecmp(word, "on") == 0)
   2162 	{
   2163 		checknames = true;
   2164 	} else if (strcasecmp(word, "no") == 0 ||
   2165 		   strcasecmp(word, "false") == 0 ||
   2166 		   strcasecmp(word, "off") == 0)
   2167 	{
   2168 		checknames = false;
   2169 	} else {
   2170 		fprintf(stderr, "incorrect check-names directive: %s\n", word);
   2171 		return STATUS_SYNTAX;
   2172 	}
   2173 	return STATUS_MORE;
   2174 }
   2175 
   2176 static uint16_t
   2177 evaluate_checksvcb(char *cmdline) {
   2178 	char *word;
   2179 
   2180 	ddebug("evaluate_checksvcb()");
   2181 	word = nsu_strsep(&cmdline, " \t\r\n");
   2182 	if (word == NULL || *word == 0) {
   2183 		fprintf(stderr, "could not read check-svcb directive\n");
   2184 		return STATUS_SYNTAX;
   2185 	}
   2186 	if (strcasecmp(word, "yes") == 0 || strcasecmp(word, "true") == 0 ||
   2187 	    strcasecmp(word, "on") == 0)
   2188 	{
   2189 		checksvcb = true;
   2190 	} else if (strcasecmp(word, "no") == 0 ||
   2191 		   strcasecmp(word, "false") == 0 ||
   2192 		   strcasecmp(word, "off") == 0)
   2193 	{
   2194 		checksvcb = false;
   2195 	} else {
   2196 		fprintf(stderr, "incorrect check-svcb directive: %s\n", word);
   2197 		return STATUS_SYNTAX;
   2198 	}
   2199 	return STATUS_MORE;
   2200 }
   2201 
   2202 static void
   2203 setzone(dns_name_t *zonename) {
   2204 	isc_result_t result;
   2205 	dns_name_t *name = NULL;
   2206 	dns_rdataset_t *rdataset = NULL;
   2207 
   2208 	result = dns_message_firstname(updatemsg, DNS_SECTION_ZONE);
   2209 	if (result == ISC_R_SUCCESS) {
   2210 		dns_message_currentname(updatemsg, DNS_SECTION_ZONE, &name);
   2211 		dns_message_removename(updatemsg, name, DNS_SECTION_ZONE);
   2212 		for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL;
   2213 		     rdataset = ISC_LIST_HEAD(name->list))
   2214 		{
   2215 			ISC_LIST_UNLINK(name->list, rdataset, link);
   2216 			dns_rdataset_disassociate(rdataset);
   2217 			dns_message_puttemprdataset(updatemsg, &rdataset);
   2218 		}
   2219 		dns_message_puttempname(updatemsg, &name);
   2220 	}
   2221 
   2222 	if (zonename != NULL) {
   2223 		dns_message_gettempname(updatemsg, &name);
   2224 		dns_name_clone(zonename, name);
   2225 		dns_message_gettemprdataset(updatemsg, &rdataset);
   2226 		dns_rdataset_makequestion(rdataset, getzoneclass(),
   2227 					  dns_rdatatype_soa);
   2228 		ISC_LIST_INIT(name->list);
   2229 		ISC_LIST_APPEND(name->list, rdataset, link);
   2230 		dns_message_addname(updatemsg, name, DNS_SECTION_ZONE);
   2231 	}
   2232 }
   2233 
   2234 static void
   2235 show_message(FILE *stream, dns_message_t *msg, const char *description) {
   2236 	isc_result_t result;
   2237 	isc_buffer_t *buf = NULL;
   2238 	int bufsz;
   2239 
   2240 	ddebug("show_message()");
   2241 
   2242 	setzone(userzone);
   2243 
   2244 	bufsz = INITTEXT;
   2245 	do {
   2246 		if (bufsz > MAXTEXT) {
   2247 			fprintf(stderr, "could not allocate large enough "
   2248 					"buffer to display message\n");
   2249 			exit(EXIT_FAILURE);
   2250 		}
   2251 		if (buf != NULL) {
   2252 			isc_buffer_free(&buf);
   2253 		}
   2254 		isc_buffer_allocate(gmctx, &buf, bufsz);
   2255 		result = dns_message_totext(msg, style, 0, buf);
   2256 		bufsz *= 2;
   2257 	} while (result == ISC_R_NOSPACE);
   2258 	if (result != ISC_R_SUCCESS) {
   2259 		fprintf(stderr, "could not convert message to text format.\n");
   2260 		isc_buffer_free(&buf);
   2261 		return;
   2262 	}
   2263 	fprintf(stream, "%s\n%.*s", description,
   2264 		(int)isc_buffer_usedlength(buf), (char *)isc_buffer_base(buf));
   2265 	fflush(stream);
   2266 	isc_buffer_free(&buf);
   2267 }
   2268 
   2269 static uint16_t
   2270 do_next_command(char *cmdline) {
   2271 	char *word;
   2272 
   2273 	ddebug("do_next_command()");
   2274 	word = nsu_strsep(&cmdline, " \t\r\n");
   2275 
   2276 	if (word == NULL || *word == 0) {
   2277 		return STATUS_SEND;
   2278 	}
   2279 	if (word[0] == ';') {
   2280 		return STATUS_MORE;
   2281 	}
   2282 	if (strcasecmp(word, "quit") == 0) {
   2283 		return STATUS_QUIT;
   2284 	}
   2285 	if (strcasecmp(word, "prereq") == 0) {
   2286 		return evaluate_prereq(cmdline);
   2287 	}
   2288 	if (strcasecmp(word, "nxdomain") == 0) {
   2289 		return make_prereq(cmdline, false, false);
   2290 	}
   2291 	if (strcasecmp(word, "yxdomain") == 0) {
   2292 		return make_prereq(cmdline, true, false);
   2293 	}
   2294 	if (strcasecmp(word, "nxrrset") == 0) {
   2295 		return make_prereq(cmdline, false, true);
   2296 	}
   2297 	if (strcasecmp(word, "yxrrset") == 0) {
   2298 		return make_prereq(cmdline, true, true);
   2299 	}
   2300 	if (strcasecmp(word, "update") == 0) {
   2301 		return evaluate_update(cmdline);
   2302 	}
   2303 	if (strcasecmp(word, "delete") == 0) {
   2304 		return update_addordelete(cmdline, true);
   2305 	}
   2306 	if (strcasecmp(word, "del") == 0) {
   2307 		return update_addordelete(cmdline, true);
   2308 	}
   2309 	if (strcasecmp(word, "add") == 0) {
   2310 		return update_addordelete(cmdline, false);
   2311 	}
   2312 	if (strcasecmp(word, "lease") == 0) {
   2313 		return evaluate_lease(cmdline);
   2314 	}
   2315 	if (strcasecmp(word, "server") == 0) {
   2316 		return evaluate_server(cmdline);
   2317 	}
   2318 	if (strcasecmp(word, "local") == 0) {
   2319 		return evaluate_local(cmdline);
   2320 	}
   2321 	if (strcasecmp(word, "zone") == 0) {
   2322 		return evaluate_zone(cmdline);
   2323 	}
   2324 	if (strcasecmp(word, "class") == 0) {
   2325 		return evaluate_class(cmdline);
   2326 	}
   2327 	if (strcasecmp(word, "send") == 0) {
   2328 		return STATUS_SEND;
   2329 	}
   2330 	if (strcasecmp(word, "debug") == 0) {
   2331 		if (debugging) {
   2332 			ddebugging = true;
   2333 		} else {
   2334 			debugging = true;
   2335 		}
   2336 		return STATUS_MORE;
   2337 	}
   2338 	if (strcasecmp(word, "ttl") == 0) {
   2339 		return evaluate_ttl(cmdline);
   2340 	}
   2341 	if (strcasecmp(word, "show") == 0) {
   2342 		show_message(stdout, updatemsg, "Outgoing update query:");
   2343 		return STATUS_MORE;
   2344 	}
   2345 	if (strcasecmp(word, "answer") == 0) {
   2346 		LOCK(&answer_lock);
   2347 		if (answer != NULL) {
   2348 			show_message(stdout, answer, "Answer:");
   2349 		}
   2350 		UNLOCK(&answer_lock);
   2351 		return STATUS_MORE;
   2352 	}
   2353 	if (strcasecmp(word, "key") == 0) {
   2354 		usegsstsig = false;
   2355 		return evaluate_key(cmdline);
   2356 	}
   2357 	if (strcasecmp(word, "realm") == 0) {
   2358 		return evaluate_realm(cmdline);
   2359 	}
   2360 	if (strcasecmp(word, "check-names") == 0 ||
   2361 	    strcasecmp(word, "checknames") == 0)
   2362 	{
   2363 		return evaluate_checknames(cmdline);
   2364 	}
   2365 	if (strcasecmp(word, "check-svcb") == 0 ||
   2366 	    strcasecmp(word, "checksvcb") == 0)
   2367 	{
   2368 		return evaluate_checksvcb(cmdline);
   2369 	}
   2370 	if (strcasecmp(word, "gsstsig") == 0) {
   2371 #if HAVE_GSSAPI
   2372 		usegsstsig = true;
   2373 #else  /* HAVE_GSSAPI */
   2374 		fprintf(stderr, "gsstsig not supported\n");
   2375 #endif /* HAVE_GSSAPI */
   2376 		return STATUS_MORE;
   2377 	}
   2378 	if (strcasecmp(word, "oldgsstsig") == 0) {
   2379 #if HAVE_GSSAPI
   2380 		usegsstsig = true;
   2381 #else  /* HAVE_GSSAPI */
   2382 		fprintf(stderr, "gsstsig not supported\n");
   2383 #endif /* HAVE_GSSAPI */
   2384 		return STATUS_MORE;
   2385 	}
   2386 	if (strcasecmp(word, "help") == 0) {
   2387 		fprintf(stdout, "nsupdate " PACKAGE_VERSION ":\n"
   2388 				"local address [port]      (set local "
   2389 				"resolver)\n"
   2390 				"server address [port]     (set primary server "
   2391 				"for zone)\n"
   2392 				"send                      (send the update "
   2393 				"request)\n"
   2394 				"show                      (show the update "
   2395 				"request)\n"
   2396 				"answer                    (show the answer to "
   2397 				"the last request)\n"
   2398 				"quit                      (quit, any pending "
   2399 				"update is not sent)\n"
   2400 				"help                      (display this "
   2401 				"message)\n"
   2402 				"key [hmac:]keyname secret (use TSIG to sign "
   2403 				"the request)\n"
   2404 				"gsstsig                   (use GSS_TSIG to "
   2405 				"sign the request)\n"
   2406 				"zone name                 (set the zone to be "
   2407 				"updated)\n"
   2408 				"class CLASS               (set the zone's DNS "
   2409 				"class, e.g. IN (default), CH)\n"
   2410 				"check-names { on | off }  (enable / disable "
   2411 				"check-names)\n"
   2412 				"[prereq] nxdomain name    (require that this "
   2413 				"name does not exist)\n"
   2414 				"[prereq] yxdomain name    (require that this "
   2415 				"name exists)\n"
   2416 				"[prereq] nxrrset ....     (require that this "
   2417 				"RRset does not exist)\n"
   2418 				"[prereq] yxrrset ....     (require that this "
   2419 				"RRset exists)\n"
   2420 				"[update] add ....         (add the given "
   2421 				"record to the zone)\n"
   2422 				"[update] del[ete] ....    (remove the given "
   2423 				"record(s) from the zone)\n");
   2424 		return STATUS_MORE;
   2425 	}
   2426 	if (strcasecmp(word, "version") == 0) {
   2427 		fprintf(stdout, "nsupdate " PACKAGE_VERSION "\n");
   2428 		return STATUS_MORE;
   2429 	}
   2430 	fprintf(stderr, "incorrect section name: %s\n", word);
   2431 	return STATUS_SYNTAX;
   2432 }
   2433 
   2434 static uint16_t
   2435 get_next_command(void) {
   2436 	uint16_t result = STATUS_QUIT;
   2437 	char cmdlinebuf[MAXCMD];
   2438 	char *cmdline = NULL, *ptr = NULL;
   2439 
   2440 	if (interactive) {
   2441 		cmdline = ptr = readline("> ");
   2442 		if (ptr != NULL && *ptr != 0) {
   2443 			add_history(ptr);
   2444 		}
   2445 	} else {
   2446 		cmdline = fgets(cmdlinebuf, MAXCMD, input);
   2447 	}
   2448 
   2449 	if (cmdline != NULL) {
   2450 		char *tmp = cmdline;
   2451 
   2452 		/*
   2453 		 * Normalize input by removing any eol as readline()
   2454 		 * removes eol but fgets doesn't.
   2455 		 */
   2456 		(void)nsu_strsep(&tmp, "\r\n");
   2457 		result = do_next_command(cmdline);
   2458 	}
   2459 	if (ptr != NULL) {
   2460 		free(ptr);
   2461 	}
   2462 
   2463 	return result;
   2464 }
   2465 
   2466 static bool
   2467 user_interaction(void) {
   2468 	uint16_t result = STATUS_MORE;
   2469 
   2470 	ddebug("user_interaction()");
   2471 	while ((result == STATUS_MORE) || (result == STATUS_SYNTAX)) {
   2472 		result = get_next_command();
   2473 		if (!interactive && result == STATUS_SYNTAX) {
   2474 			fatal("syntax error");
   2475 		}
   2476 	}
   2477 	if (result == STATUS_SEND) {
   2478 		return true;
   2479 	}
   2480 	return false;
   2481 }
   2482 
   2483 static void
   2484 done_update(void) {
   2485 	ddebug("done_update()");
   2486 
   2487 	isc_async_current(getinput, NULL);
   2488 }
   2489 
   2490 static void
   2491 check_tsig_error(dns_rdataset_t *rdataset, isc_buffer_t *b) {
   2492 	isc_result_t result;
   2493 	dns_rdata_t rdata = DNS_RDATA_INIT;
   2494 	dns_rdata_any_tsig_t tsig;
   2495 
   2496 	result = dns_rdataset_first(rdataset);
   2497 	check_result(result, "dns_rdataset_first");
   2498 	dns_rdataset_current(rdataset, &rdata);
   2499 	result = dns_rdata_tostruct(&rdata, &tsig, NULL);
   2500 	check_result(result, "dns_rdata_tostruct");
   2501 	if (tsig.error != 0) {
   2502 		if (isc_buffer_remaininglength(b) < 1) {
   2503 			check_result(ISC_R_NOSPACE, "isc_buffer_"
   2504 						    "remaininglength");
   2505 		}
   2506 		isc_buffer_putstr(b, "(" /*)*/);
   2507 		result = dns_tsigrcode_totext(tsig.error, b);
   2508 		check_result(result, "dns_tsigrcode_totext");
   2509 		if (isc_buffer_remaininglength(b) < 1) {
   2510 			check_result(ISC_R_NOSPACE, "isc_buffer_"
   2511 						    "remaininglength");
   2512 		}
   2513 		isc_buffer_putstr(b, /*(*/ ")");
   2514 	}
   2515 }
   2516 
   2517 static bool
   2518 next_primary(const char *caller, isc_sockaddr_t *addr, isc_result_t eresult) {
   2519 	char addrbuf[ISC_SOCKADDR_FORMATSIZE];
   2520 
   2521 	isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf));
   2522 	fprintf(stderr, "; Communication with %s failed: %s\n", addrbuf,
   2523 		isc_result_totext(eresult));
   2524 	if (++primary_inuse >= primary_total) {
   2525 		return false;
   2526 	}
   2527 	ddebug("%s: trying next server", caller);
   2528 	return true;
   2529 }
   2530 
   2531 static void
   2532 update_completed(void *arg) {
   2533 	dns_request_t *request = (dns_request_t *)arg;
   2534 	isc_result_t result;
   2535 
   2536 	ddebug("update_completed()");
   2537 
   2538 	requests--;
   2539 
   2540 	if (shuttingdown) {
   2541 		dns_request_destroy(&request);
   2542 		maybeshutdown();
   2543 		return;
   2544 	}
   2545 
   2546 	result = dns_request_getresult(request);
   2547 	if (result != ISC_R_SUCCESS) {
   2548 		if (!next_primary("update_completed",
   2549 				  &primary_servers[primary_inuse], result))
   2550 		{
   2551 			seenerror = true;
   2552 			goto done;
   2553 		}
   2554 
   2555 		ddebug("Destroying request [%p]", request);
   2556 		dns_request_destroy(&request);
   2557 		dns_message_renderreset(updatemsg);
   2558 		dns_message_settsigkey(updatemsg, NULL);
   2559 		send_update(zname, &primary_servers[primary_inuse]);
   2560 		return;
   2561 	}
   2562 
   2563 	LOCK(&answer_lock);
   2564 	dns_message_create(gmctx, NULL, NULL, DNS_MESSAGE_INTENTPARSE, &answer);
   2565 	result = dns_request_getresponse(request, answer,
   2566 					 DNS_MESSAGEPARSE_PRESERVEORDER);
   2567 	switch (result) {
   2568 	case ISC_R_SUCCESS:
   2569 		if (answer->verify_attempted) {
   2570 			ddebug("tsig verification successful");
   2571 		}
   2572 		break;
   2573 	case DNS_R_CLOCKSKEW:
   2574 	case DNS_R_EXPECTEDTSIG:
   2575 	case DNS_R_TSIGERRORSET:
   2576 	case DNS_R_TSIGVERIFYFAILURE:
   2577 	case DNS_R_UNEXPECTEDTSIG:
   2578 	case ISC_R_FAILURE:
   2579 #if 0
   2580 		if (usegsstsig && answer->rcode == dns_rcode_noerror) {
   2581 			/*
   2582 			 * For MS DNS that violates RFC 2845, section 4.2
   2583 			 */
   2584 			break;
   2585 		}
   2586 #endif /* if 0 */
   2587 		fprintf(stderr, "; TSIG error with server: %s\n",
   2588 			isc_result_totext(result));
   2589 		seenerror = true;
   2590 		break;
   2591 	default:
   2592 		check_result(result, "dns_request_getresponse");
   2593 	}
   2594 
   2595 	if (answer->opcode != dns_opcode_update) {
   2596 		fatal("invalid OPCODE in response to UPDATE request");
   2597 	}
   2598 
   2599 	if (answer->rcode != dns_rcode_noerror) {
   2600 		seenerror = true;
   2601 		if (!debugging) {
   2602 			char buf[64];
   2603 			isc_buffer_t b;
   2604 			dns_rdataset_t *rds;
   2605 
   2606 			isc_buffer_init(&b, buf, sizeof(buf) - 1);
   2607 			result = dns_rcode_totext(answer->rcode, &b);
   2608 			check_result(result, "dns_rcode_totext");
   2609 			rds = dns_message_gettsig(answer, NULL);
   2610 			if (rds != NULL) {
   2611 				check_tsig_error(rds, &b);
   2612 			}
   2613 			fprintf(stderr, "update failed: %.*s\n",
   2614 				(int)isc_buffer_usedlength(&b), buf);
   2615 		}
   2616 	}
   2617 	if (debugging) {
   2618 		show_message(stderr, answer, "\nReply from update query:");
   2619 	}
   2620 	UNLOCK(&answer_lock);
   2621 
   2622 done:
   2623 	dns_request_destroy(&request);
   2624 	if (usegsstsig) {
   2625 		dns_name_free(&tmpzonename, gmctx);
   2626 		dns_name_free(&restart_primary, gmctx);
   2627 		dns_name_init(&tmpzonename, 0);
   2628 		dns_name_init(&restart_primary, 0);
   2629 	}
   2630 	done_update();
   2631 }
   2632 
   2633 static void
   2634 send_update(dns_name_t *zone, isc_sockaddr_t *primary) {
   2635 	isc_result_t result;
   2636 	dns_request_t *request = NULL;
   2637 	isc_sockaddr_t *srcaddr;
   2638 	unsigned int options = DNS_REQUESTOPT_CASE | DNS_REQUESTOPT_LARGE;
   2639 	dns_transport_t *req_transport = NULL;
   2640 	isc_tlsctx_cache_t *req_tls_ctx_cache = NULL;
   2641 
   2642 	ddebug("send_update()");
   2643 
   2644 	setzone(zone);
   2645 
   2646 	if (usevc) {
   2647 		options |= DNS_REQUESTOPT_TCP;
   2648 		if (use_tls) {
   2649 			req_transport = transport;
   2650 			req_tls_ctx_cache = tls_ctx_cache;
   2651 		}
   2652 	}
   2653 
   2654 	if (tsigkey == NULL && sig0key != NULL) {
   2655 		result = dns_message_setsig0key(updatemsg, sig0key);
   2656 		check_result(result, "dns_message_setsig0key");
   2657 	}
   2658 	if (debugging) {
   2659 		char addrbuf[ISC_SOCKADDR_FORMATSIZE];
   2660 
   2661 		isc_sockaddr_format(primary, addrbuf, sizeof(addrbuf));
   2662 		fprintf(stderr, "Sending update to %s\n", addrbuf);
   2663 	}
   2664 
   2665 	if (isc_sockaddr_pf(primary) == AF_INET6) {
   2666 		srcaddr = localaddr6;
   2667 	} else {
   2668 		srcaddr = localaddr4;
   2669 	}
   2670 
   2671 	/* Windows doesn't like the tsig name to be compressed. */
   2672 	if (updatemsg->tsigname) {
   2673 		updatemsg->tsigname->attributes.nocompress = true;
   2674 	}
   2675 
   2676 	result = dns_request_create(requestmgr, updatemsg, srcaddr, primary,
   2677 				    req_transport, req_tls_ctx_cache, options,
   2678 				    tsigkey, timeout, udp_timeout, udp_retries,
   2679 				    isc_loop_main(loopmgr), update_completed,
   2680 				    NULL, &request);
   2681 	check_result(result, "dns_request_create");
   2682 
   2683 	if (debugging) {
   2684 		show_message(stdout, updatemsg, "Outgoing update query:");
   2685 	}
   2686 
   2687 	requests++;
   2688 }
   2689 
   2690 static void
   2691 next_server(const char *caller, isc_sockaddr_t *addr, isc_result_t eresult) {
   2692 	char addrbuf[ISC_SOCKADDR_FORMATSIZE];
   2693 
   2694 	isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf));
   2695 	fprintf(stderr, "; Communication with %s failed: %s\n", addrbuf,
   2696 		isc_result_totext(eresult));
   2697 	if (++ns_inuse >= ns_total) {
   2698 		fatal("could not reach any name server");
   2699 	} else {
   2700 		ddebug("%s: trying next server", caller);
   2701 	}
   2702 }
   2703 
   2704 static void
   2705 recvsoa(void *arg) {
   2706 	dns_request_t *request = (dns_request_t *)arg;
   2707 	isc_result_t result, eresult = dns_request_getresult(request);
   2708 	nsu_requestinfo_t *reqinfo = dns_request_getarg(request);
   2709 	dns_message_t *soaquery = reqinfo->msg;
   2710 	dns_message_t *rcvmsg = NULL;
   2711 	dns_section_t section;
   2712 	dns_name_t *name = NULL;
   2713 	dns_rdataset_t *soaset = NULL;
   2714 	dns_rdata_soa_t soa;
   2715 	dns_rdata_t soarr = DNS_RDATA_INIT;
   2716 	int pass = 0;
   2717 	dns_name_t primary;
   2718 	isc_sockaddr_t *addr = reqinfo->addr;
   2719 	isc_sockaddr_t *srcaddr = NULL;
   2720 	bool seencname = false;
   2721 	dns_name_t tname;
   2722 	unsigned int nlabels;
   2723 
   2724 	ddebug("recvsoa()");
   2725 
   2726 	requests--;
   2727 
   2728 	if (shuttingdown) {
   2729 		dns_request_destroy(&request);
   2730 		dns_message_detach(&soaquery);
   2731 		isc_mem_put(gmctx, reqinfo, sizeof(nsu_requestinfo_t));
   2732 		maybeshutdown();
   2733 		return;
   2734 	}
   2735 
   2736 	if (eresult != ISC_R_SUCCESS) {
   2737 		next_server("recvsoa", addr, eresult);
   2738 		ddebug("Destroying request [%p]", request);
   2739 		dns_request_destroy(&request);
   2740 		dns_message_renderreset(soaquery);
   2741 		dns_message_settsigkey(soaquery, NULL);
   2742 		sendrequest(&servers[ns_inuse], soaquery, &request);
   2743 		isc_mem_put(gmctx, reqinfo, sizeof(nsu_requestinfo_t));
   2744 		setzoneclass(dns_rdataclass_none);
   2745 		return;
   2746 	}
   2747 
   2748 	isc_mem_put(gmctx, reqinfo, sizeof(nsu_requestinfo_t));
   2749 	reqinfo = NULL;
   2750 
   2751 	ddebug("About to create rcvmsg");
   2752 	dns_message_create(gmctx, NULL, NULL, DNS_MESSAGE_INTENTPARSE, &rcvmsg);
   2753 	result = dns_request_getresponse(request, rcvmsg,
   2754 					 DNS_MESSAGEPARSE_PRESERVEORDER);
   2755 	if (result == DNS_R_TSIGERRORSET && servers != NULL) {
   2756 		unsigned int options = DNS_REQUESTOPT_CASE;
   2757 		dns_transport_t *req_transport = NULL;
   2758 		isc_tlsctx_cache_t *req_tls_ctx_cache = NULL;
   2759 
   2760 		dns_message_detach(&rcvmsg);
   2761 		ddebug("Destroying request [%p]", request);
   2762 		dns_request_destroy(&request);
   2763 		reqinfo = isc_mem_get(gmctx, sizeof(nsu_requestinfo_t));
   2764 		reqinfo->msg = soaquery;
   2765 		reqinfo->addr = addr;
   2766 		dns_message_renderreset(soaquery);
   2767 		ddebug("retrying soa request without TSIG");
   2768 
   2769 		if (!default_servers && usevc) {
   2770 			options |= DNS_REQUESTOPT_TCP;
   2771 			if (use_tls) {
   2772 				req_transport = transport;
   2773 				req_tls_ctx_cache = tls_ctx_cache;
   2774 			}
   2775 		}
   2776 
   2777 		if (isc_sockaddr_pf(addr) == AF_INET6) {
   2778 			srcaddr = localaddr6;
   2779 		} else {
   2780 			srcaddr = localaddr4;
   2781 		}
   2782 
   2783 		result = dns_request_create(requestmgr, soaquery, srcaddr, addr,
   2784 					    req_transport, req_tls_ctx_cache,
   2785 					    options, NULL, timeout, udp_timeout,
   2786 					    udp_retries, isc_loop_main(loopmgr),
   2787 					    recvsoa, reqinfo, &request);
   2788 		check_result(result, "dns_request_create");
   2789 		requests++;
   2790 		return;
   2791 	}
   2792 	check_result(result, "dns_request_getresponse");
   2793 
   2794 	if (rcvmsg->rcode == dns_rcode_refused) {
   2795 		next_server("recvsoa", addr, DNS_R_REFUSED);
   2796 		dns_message_detach(&rcvmsg);
   2797 		dns_request_destroy(&request);
   2798 		dns_message_renderreset(soaquery);
   2799 		dns_message_settsigkey(soaquery, NULL);
   2800 		sendrequest(&servers[ns_inuse], soaquery, &request);
   2801 		return;
   2802 	}
   2803 
   2804 	section = DNS_SECTION_ANSWER;
   2805 	POST(section);
   2806 	if (debugging) {
   2807 		show_message(stderr, rcvmsg, "Reply from SOA query:");
   2808 	}
   2809 
   2810 	if (rcvmsg->opcode != dns_opcode_query) {
   2811 		fatal("invalid OPCODE in response to SOA query");
   2812 	}
   2813 
   2814 	if (rcvmsg->rcode != dns_rcode_noerror &&
   2815 	    rcvmsg->rcode != dns_rcode_nxdomain)
   2816 	{
   2817 		fatal("response to SOA query was unsuccessful");
   2818 	}
   2819 
   2820 	if (userzone != NULL && rcvmsg->rcode == dns_rcode_nxdomain) {
   2821 		char namebuf[DNS_NAME_FORMATSIZE];
   2822 		dns_name_format(userzone, namebuf, sizeof(namebuf));
   2823 		error("specified zone '%s' does not exist (NXDOMAIN)", namebuf);
   2824 		dns_message_detach(&rcvmsg);
   2825 		dns_request_destroy(&request);
   2826 		dns_message_detach(&soaquery);
   2827 		ddebug("Out of recvsoa");
   2828 		seenerror = true;
   2829 		done_update();
   2830 		return;
   2831 	}
   2832 
   2833 lookforsoa:
   2834 	if (pass == 0) {
   2835 		section = DNS_SECTION_ANSWER;
   2836 	} else if (pass == 1) {
   2837 		section = DNS_SECTION_AUTHORITY;
   2838 	} else {
   2839 		goto droplabel;
   2840 	}
   2841 
   2842 	result = dns_message_firstname(rcvmsg, section);
   2843 	if (result != ISC_R_SUCCESS) {
   2844 		pass++;
   2845 		goto lookforsoa;
   2846 	}
   2847 	while (result == ISC_R_SUCCESS) {
   2848 		name = NULL;
   2849 		dns_message_currentname(rcvmsg, section, &name);
   2850 		soaset = NULL;
   2851 		result = dns_message_findtype(name, dns_rdatatype_soa, 0,
   2852 					      &soaset);
   2853 		if (result == ISC_R_SUCCESS) {
   2854 			break;
   2855 		}
   2856 		if (section == DNS_SECTION_ANSWER) {
   2857 			dns_rdataset_t *tset = NULL;
   2858 			if (dns_message_findtype(name, dns_rdatatype_cname, 0,
   2859 						 &tset) == ISC_R_SUCCESS ||
   2860 			    dns_message_findtype(name, dns_rdatatype_dname, 0,
   2861 						 &tset) == ISC_R_SUCCESS)
   2862 			{
   2863 				seencname = true;
   2864 				break;
   2865 			}
   2866 		}
   2867 
   2868 		result = dns_message_nextname(rcvmsg, section);
   2869 	}
   2870 
   2871 	if (soaset == NULL && !seencname) {
   2872 		pass++;
   2873 		goto lookforsoa;
   2874 	}
   2875 
   2876 	if (seencname) {
   2877 		goto droplabel;
   2878 	}
   2879 
   2880 	if (debugging) {
   2881 		char namestr[DNS_NAME_FORMATSIZE];
   2882 		dns_name_format(name, namestr, sizeof(namestr));
   2883 		fprintf(stderr, "Found zone name: %s\n", namestr);
   2884 	}
   2885 
   2886 	result = dns_rdataset_first(soaset);
   2887 	check_result(result, "dns_rdataset_first");
   2888 
   2889 	dns_rdata_init(&soarr);
   2890 	dns_rdataset_current(soaset, &soarr);
   2891 	result = dns_rdata_tostruct(&soarr, &soa, NULL);
   2892 	check_result(result, "dns_rdata_tostruct");
   2893 
   2894 	dns_name_init(&primary, NULL);
   2895 	dns_name_clone(&soa.origin, &primary);
   2896 
   2897 	if (userzone != NULL) {
   2898 		zname = userzone;
   2899 	} else {
   2900 		/*
   2901 		 * Save the zone name in case we need to try a second
   2902 		 * address.
   2903 		 */
   2904 		zname = dns_fixedname_initname(&fzname);
   2905 		dns_name_copy(name, zname);
   2906 	}
   2907 
   2908 	if (debugging) {
   2909 		char namestr[DNS_NAME_FORMATSIZE];
   2910 		dns_name_format(&primary, namestr, sizeof(namestr));
   2911 		fprintf(stderr, "The primary is: %s\n", namestr);
   2912 	}
   2913 
   2914 	if (default_servers) {
   2915 		char serverstr[DNS_NAME_MAXTEXT + 1];
   2916 		isc_buffer_t buf;
   2917 
   2918 		isc_buffer_init(&buf, serverstr, sizeof(serverstr));
   2919 		result = dns_name_totext(&primary, DNS_NAME_OMITFINALDOT, &buf);
   2920 		check_result(result, "dns_name_totext");
   2921 		serverstr[isc_buffer_usedlength(&buf)] = 0;
   2922 
   2923 		if (primary_servers != NULL && primary_servers != servers) {
   2924 			isc_mem_cput(gmctx, primary_servers, primary_alloc,
   2925 				     sizeof(isc_sockaddr_t));
   2926 		}
   2927 		primary_alloc = MAX_SERVERADDRS;
   2928 		primary_servers = isc_mem_cget(gmctx, primary_alloc,
   2929 					       sizeof(isc_sockaddr_t));
   2930 		primary_total = get_addresses(serverstr, dnsport,
   2931 					      primary_servers, primary_alloc);
   2932 		if (primary_total == 0) {
   2933 			seenerror = true;
   2934 			dns_rdata_freestruct(&soa);
   2935 			dns_message_detach(&soaquery);
   2936 			dns_request_destroy(&request);
   2937 			dns_message_detach(&rcvmsg);
   2938 			ddebug("Out of recvsoa");
   2939 			done_update();
   2940 			return;
   2941 		}
   2942 		primary_inuse = 0;
   2943 	} else {
   2944 		primary_from_servers();
   2945 	}
   2946 	dns_rdata_freestruct(&soa);
   2947 
   2948 #if HAVE_GSSAPI
   2949 	if (usegsstsig) {
   2950 		dns_name_init(&tmpzonename, NULL);
   2951 		dns_name_dup(zname, gmctx, &tmpzonename);
   2952 		dns_name_init(&restart_primary, NULL);
   2953 		dns_name_dup(&primary, gmctx, &restart_primary);
   2954 		start_gssrequest(&primary);
   2955 	} else {
   2956 		send_update(zname, &primary_servers[primary_inuse]);
   2957 		setzoneclass(dns_rdataclass_none);
   2958 	}
   2959 #else  /* HAVE_GSSAPI */
   2960 	send_update(zname, &primary_servers[primary_inuse]);
   2961 	setzoneclass(dns_rdataclass_none);
   2962 #endif /* HAVE_GSSAPI */
   2963 
   2964 	dns_message_detach(&soaquery);
   2965 	dns_request_destroy(&request);
   2966 
   2967 out:
   2968 	dns_message_detach(&rcvmsg);
   2969 	ddebug("Out of recvsoa");
   2970 	return;
   2971 
   2972 droplabel:
   2973 	result = dns_message_firstname(soaquery, DNS_SECTION_QUESTION);
   2974 	INSIST(result == ISC_R_SUCCESS);
   2975 	name = NULL;
   2976 	dns_message_currentname(soaquery, DNS_SECTION_QUESTION, &name);
   2977 	nlabels = dns_name_countlabels(name);
   2978 	if (nlabels == 1) {
   2979 		fatal("could not find enclosing zone");
   2980 	}
   2981 	dns_name_init(&tname, NULL);
   2982 	dns_name_getlabelsequence(name, 1, nlabels - 1, &tname);
   2983 	dns_name_clone(&tname, name);
   2984 	dns_request_destroy(&request);
   2985 	dns_message_renderreset(soaquery);
   2986 	dns_message_settsigkey(soaquery, NULL);
   2987 	sendrequest(&servers[ns_inuse], soaquery, &request);
   2988 	goto out;
   2989 }
   2990 
   2991 static void
   2992 sendrequest(isc_sockaddr_t *destaddr, dns_message_t *msg,
   2993 	    dns_request_t **request) {
   2994 	isc_result_t result;
   2995 	nsu_requestinfo_t *reqinfo;
   2996 	isc_sockaddr_t *srcaddr;
   2997 	unsigned int options = DNS_REQUESTOPT_CASE;
   2998 	dns_transport_t *req_transport = NULL;
   2999 	isc_tlsctx_cache_t *req_tls_ctx_cache = NULL;
   3000 
   3001 	if (!default_servers && usevc) {
   3002 		options |= DNS_REQUESTOPT_TCP;
   3003 		if (use_tls) {
   3004 			req_transport = transport;
   3005 			req_tls_ctx_cache = tls_ctx_cache;
   3006 		}
   3007 	}
   3008 
   3009 	reqinfo = isc_mem_get(gmctx, sizeof(nsu_requestinfo_t));
   3010 	reqinfo->msg = msg;
   3011 	reqinfo->addr = destaddr;
   3012 
   3013 	if (isc_sockaddr_pf(destaddr) == AF_INET6) {
   3014 		srcaddr = localaddr6;
   3015 	} else {
   3016 		srcaddr = localaddr4;
   3017 	}
   3018 
   3019 	result = dns_request_create(
   3020 		requestmgr, msg, srcaddr, destaddr, req_transport,
   3021 		req_tls_ctx_cache, options, default_servers ? NULL : tsigkey,
   3022 		timeout, udp_timeout, udp_retries, isc_loop_main(loopmgr),
   3023 		recvsoa, reqinfo, request);
   3024 	check_result(result, "dns_request_create");
   3025 	requests++;
   3026 }
   3027 
   3028 #if HAVE_GSSAPI
   3029 
   3030 /*
   3031  * Get the realm from the users kerberos ticket if possible
   3032  */
   3033 static void
   3034 get_ticket_realm(isc_mem_t *mctx) {
   3035 	krb5_context ctx;
   3036 	krb5_error_code rc;
   3037 	krb5_ccache ccache;
   3038 	krb5_principal princ;
   3039 	char *name;
   3040 	const char *ticket_realm;
   3041 
   3042 	rc = krb5_init_context(&ctx);
   3043 	if (rc != 0) {
   3044 		return;
   3045 	}
   3046 
   3047 	rc = krb5_cc_default(ctx, &ccache);
   3048 	if (rc != 0) {
   3049 		krb5_free_context(ctx);
   3050 		return;
   3051 	}
   3052 
   3053 	rc = krb5_cc_get_principal(ctx, ccache, &princ);
   3054 	if (rc != 0) {
   3055 		krb5_cc_close(ctx, ccache);
   3056 		krb5_free_context(ctx);
   3057 		return;
   3058 	}
   3059 
   3060 	rc = krb5_unparse_name(ctx, princ, &name);
   3061 	if (rc != 0) {
   3062 		krb5_free_principal(ctx, princ);
   3063 		krb5_cc_close(ctx, ccache);
   3064 		krb5_free_context(ctx);
   3065 		return;
   3066 	}
   3067 
   3068 	ticket_realm = strrchr(name, '@');
   3069 	if (ticket_realm != NULL) {
   3070 		realm = isc_mem_strdup(mctx, ticket_realm);
   3071 	}
   3072 
   3073 	free(name);
   3074 	krb5_free_principal(ctx, princ);
   3075 	krb5_cc_close(ctx, ccache);
   3076 	krb5_free_context(ctx);
   3077 	if (realm != NULL && debugging) {
   3078 		fprintf(stderr, "Found realm from ticket: %s\n", realm + 1);
   3079 	}
   3080 }
   3081 
   3082 static void
   3083 failed_gssrequest(void) {
   3084 	seenerror = true;
   3085 
   3086 	dns_name_free(&tmpzonename, gmctx);
   3087 	dns_name_free(&restart_primary, gmctx);
   3088 	dns_name_init(&tmpzonename, NULL);
   3089 	dns_name_init(&restart_primary, NULL);
   3090 
   3091 	done_update();
   3092 }
   3093 
   3094 static void
   3095 start_gssrequest(dns_name_t *primary) {
   3096 	dns_gss_ctx_id_t context;
   3097 	isc_buffer_t buf;
   3098 	isc_result_t result;
   3099 	uint32_t val = 0;
   3100 	dns_message_t *rmsg = NULL;
   3101 	dns_request_t *request = NULL;
   3102 	dns_name_t *servname;
   3103 	dns_fixedname_t fname;
   3104 	char namestr[DNS_NAME_FORMATSIZE];
   3105 	char mykeystr[DNS_NAME_FORMATSIZE];
   3106 	char *err_message = NULL;
   3107 
   3108 	debug("start_gssrequest");
   3109 	usevc = true;
   3110 
   3111 	if (gssring != NULL) {
   3112 		dns_tsigkeyring_detach(&gssring);
   3113 	}
   3114 
   3115 	dns_tsigkeyring_create(gmctx, &gssring);
   3116 
   3117 	dns_name_format(primary, namestr, sizeof(namestr));
   3118 	if (kserver == NULL) {
   3119 		kserver = isc_mem_get(gmctx, sizeof(isc_sockaddr_t));
   3120 	}
   3121 
   3122 	memmove(kserver, &primary_servers[primary_inuse],
   3123 		sizeof(isc_sockaddr_t));
   3124 
   3125 	servname = dns_fixedname_initname(&fname);
   3126 
   3127 	if (realm == NULL) {
   3128 		get_ticket_realm(gmctx);
   3129 	}
   3130 
   3131 	result = snprintf(servicename, sizeof(servicename), "DNS/%s%s", namestr,
   3132 			  realm ? realm : "");
   3133 	RUNTIME_CHECK(result < sizeof(servicename));
   3134 	isc_buffer_init(&buf, servicename, strlen(servicename));
   3135 	isc_buffer_add(&buf, strlen(servicename));
   3136 	result = dns_name_fromtext(servname, &buf, dns_rootname, 0, NULL);
   3137 	if (result != ISC_R_SUCCESS) {
   3138 		fatal("dns_name_fromtext(servname) failed: %s",
   3139 		      isc_result_totext(result));
   3140 	}
   3141 
   3142 	keyname = dns_fixedname_initname(&fkname);
   3143 
   3144 	isc_nonce_buf(&val, sizeof(val));
   3145 
   3146 	result = snprintf(mykeystr, sizeof(mykeystr), "%u.sig-%s", val,
   3147 			  namestr);
   3148 	RUNTIME_CHECK(result <= sizeof(mykeystr));
   3149 
   3150 	isc_buffer_init(&buf, mykeystr, strlen(mykeystr));
   3151 	isc_buffer_add(&buf, strlen(mykeystr));
   3152 
   3153 	result = dns_name_fromtext(keyname, &buf, dns_rootname, 0, NULL);
   3154 	if (result != ISC_R_SUCCESS) {
   3155 		fatal("dns_name_fromtext(keyname) failed: %s",
   3156 		      isc_result_totext(result));
   3157 	}
   3158 
   3159 	/* Windows doesn't recognize name compression in the key name. */
   3160 	keyname->attributes.nocompress = true;
   3161 
   3162 	rmsg = NULL;
   3163 	dns_message_create(gmctx, NULL, NULL, DNS_MESSAGE_INTENTRENDER, &rmsg);
   3164 
   3165 	/* Build first request. */
   3166 	context = GSS_C_NO_CONTEXT;
   3167 	result = dns_tkey_buildgssquery(rmsg, keyname, servname, 0, &context,
   3168 					gmctx, &err_message);
   3169 	if (result == ISC_R_FAILURE) {
   3170 		fprintf(stderr, "tkey query failed: %s\n",
   3171 			err_message != NULL ? err_message : "unknown error");
   3172 		goto failure;
   3173 	}
   3174 	if (result != ISC_R_SUCCESS) {
   3175 		fatal("dns_tkey_buildgssquery failed: %s",
   3176 		      isc_result_totext(result));
   3177 	}
   3178 
   3179 	send_gssrequest(kserver, rmsg, &request, context);
   3180 	return;
   3181 
   3182 failure:
   3183 	if (rmsg != NULL) {
   3184 		dns_message_detach(&rmsg);
   3185 	}
   3186 	if (err_message != NULL) {
   3187 		isc_mem_free(gmctx, err_message);
   3188 	}
   3189 	failed_gssrequest();
   3190 }
   3191 
   3192 static void
   3193 send_gssrequest(isc_sockaddr_t *destaddr, dns_message_t *msg,
   3194 		dns_request_t **request, gss_ctx_id_t context) {
   3195 	isc_result_t result;
   3196 	nsu_gssinfo_t *reqinfo = NULL;
   3197 	isc_sockaddr_t *srcaddr = NULL;
   3198 	unsigned int options = DNS_REQUESTOPT_CASE | DNS_REQUESTOPT_TCP;
   3199 	dns_transport_t *req_transport = NULL;
   3200 	isc_tlsctx_cache_t *req_tls_ctx_cache = NULL;
   3201 
   3202 	if (!default_servers && use_tls) {
   3203 		req_transport = transport;
   3204 		req_tls_ctx_cache = tls_ctx_cache;
   3205 	}
   3206 
   3207 	debug("send_gssrequest");
   3208 	REQUIRE(destaddr != NULL);
   3209 
   3210 	reqinfo = isc_mem_get(gmctx, sizeof(nsu_gssinfo_t));
   3211 	*reqinfo = (nsu_gssinfo_t){
   3212 		.msg = msg,
   3213 		.addr = destaddr,
   3214 		.context = context,
   3215 	};
   3216 
   3217 	if (isc_sockaddr_pf(destaddr) == AF_INET6) {
   3218 		srcaddr = localaddr6;
   3219 	} else {
   3220 		srcaddr = localaddr4;
   3221 	}
   3222 
   3223 	result = dns_request_create(
   3224 		requestmgr, msg, srcaddr, destaddr, req_transport,
   3225 		req_tls_ctx_cache, options, tsigkey, timeout, udp_timeout,
   3226 		udp_retries, isc_loop_main(loopmgr), recvgss, reqinfo, request);
   3227 	check_result(result, "dns_request_create");
   3228 	if (debugging) {
   3229 		show_message(stdout, msg, "Outgoing update query:");
   3230 	}
   3231 	requests++;
   3232 }
   3233 
   3234 static void
   3235 recvgss(void *arg) {
   3236 	dns_request_t *request = (dns_request_t *)arg;
   3237 	nsu_gssinfo_t *reqinfo = dns_request_getarg(request);
   3238 	isc_result_t result, eresult = dns_request_getresult(request);
   3239 	dns_message_t *rcvmsg = NULL;
   3240 	dns_message_t *tsigquery = reqinfo->msg;
   3241 	dns_gss_ctx_id_t context = reqinfo->context;
   3242 	isc_sockaddr_t *addr = reqinfo->addr;
   3243 	isc_buffer_t buf;
   3244 	dns_name_t *servname = NULL;
   3245 	dns_fixedname_t fname;
   3246 	char *err_message = NULL;
   3247 
   3248 	ddebug("recvgss()");
   3249 
   3250 	requests--;
   3251 
   3252 	if (shuttingdown) {
   3253 		dns_request_destroy(&request);
   3254 		dns_message_detach(&tsigquery);
   3255 		isc_mem_put(gmctx, reqinfo, sizeof(nsu_gssinfo_t));
   3256 		maybeshutdown();
   3257 		return;
   3258 	}
   3259 
   3260 	if (eresult != ISC_R_SUCCESS) {
   3261 		ddebug("Destroying request [%p]", request);
   3262 		dns_request_destroy(&request);
   3263 		if (!next_primary("recvgss", addr, eresult)) {
   3264 			dns_message_detach(&tsigquery);
   3265 			failed_gssrequest();
   3266 		} else {
   3267 			dns_message_renderreset(tsigquery);
   3268 			memmove(kserver, &primary_servers[primary_inuse],
   3269 				sizeof(isc_sockaddr_t));
   3270 			send_gssrequest(kserver, tsigquery, &request, context);
   3271 		}
   3272 		isc_mem_put(gmctx, reqinfo, sizeof(nsu_gssinfo_t));
   3273 		return;
   3274 	}
   3275 	isc_mem_put(gmctx, reqinfo, sizeof(nsu_gssinfo_t));
   3276 
   3277 	ddebug("recvgss creating rcvmsg");
   3278 	dns_message_create(gmctx, NULL, NULL, DNS_MESSAGE_INTENTPARSE, &rcvmsg);
   3279 
   3280 	result = dns_request_getresponse(request, rcvmsg,
   3281 					 DNS_MESSAGEPARSE_PRESERVEORDER);
   3282 	check_result(result, "dns_request_getresponse");
   3283 
   3284 	if (debugging) {
   3285 		show_message(stderr, rcvmsg,
   3286 			     "recvmsg reply from GSS-TSIG query");
   3287 	}
   3288 
   3289 	if (rcvmsg->opcode != dns_opcode_query) {
   3290 		fatal("invalid OPCODE in response to GSS-TSIG query");
   3291 	}
   3292 
   3293 	if (rcvmsg->rcode != dns_rcode_noerror &&
   3294 	    rcvmsg->rcode != dns_rcode_nxdomain)
   3295 	{
   3296 		char rcode[64];
   3297 		isc_buffer_t b;
   3298 
   3299 		isc_buffer_init(&b, rcode, sizeof(rcode) - 1);
   3300 		result = dns_rcode_totext(rcvmsg->rcode, &b);
   3301 		check_result(result, "dns_rcode_totext");
   3302 		rcode[isc_buffer_usedlength(&b)] = 0;
   3303 
   3304 		fatal("response to GSS-TSIG query was unsuccessful (%s)",
   3305 		      rcode);
   3306 	}
   3307 
   3308 	servname = dns_fixedname_initname(&fname);
   3309 	isc_buffer_init(&buf, servicename, strlen(servicename));
   3310 	isc_buffer_add(&buf, strlen(servicename));
   3311 	result = dns_name_fromtext(servname, &buf, dns_rootname, 0, NULL);
   3312 	check_result(result, "dns_name_fromtext");
   3313 
   3314 	result = dns_tkey_gssnegotiate(tsigquery, rcvmsg, servname, &context,
   3315 				       &tsigkey, gssring, &err_message);
   3316 	switch (result) {
   3317 	case DNS_R_CONTINUE:
   3318 		dns_message_detach(&rcvmsg);
   3319 		dns_request_destroy(&request);
   3320 		send_gssrequest(kserver, tsigquery, &request, context);
   3321 		ddebug("Out of recvgss");
   3322 		return;
   3323 
   3324 	case ISC_R_SUCCESS:
   3325 		/*
   3326 		 * XXXSRA Waaay too much fun here.  There's no good
   3327 		 * reason why we need a TSIG here (the people who put
   3328 		 * it into the spec admitted at the time that it was
   3329 		 * not a security issue), and Windows clients don't
   3330 		 * seem to work if named complies with the spec and
   3331 		 * includes the gratuitous TSIG.  So we're in the
   3332 		 * bizarre situation of having to choose between
   3333 		 * complying with a useless requirement in the spec
   3334 		 * and interoperating.  This is nuts.  If we can
   3335 		 * confirm this behavior, we should ask the WG to
   3336 		 * consider removing the requirement for the
   3337 		 * gratuitous TSIG here.  For the moment, we ignore
   3338 		 * the TSIG -- this too is a spec violation, but it's
   3339 		 * the least insane thing to do.
   3340 		 */
   3341 
   3342 		send_update(&tmpzonename, &primary_servers[primary_inuse]);
   3343 		setzoneclass(dns_rdataclass_none);
   3344 		break;
   3345 
   3346 	default:
   3347 		fatal("dns_tkey_gssnegotiate: %s %s", isc_result_totext(result),
   3348 		      err_message != NULL ? err_message : "");
   3349 	}
   3350 
   3351 	dns_request_destroy(&request);
   3352 	dns_message_detach(&tsigquery);
   3353 
   3354 	dns_message_detach(&rcvmsg);
   3355 	ddebug("Out of recvgss");
   3356 }
   3357 #endif /* HAVE_GSSAPI */
   3358 
   3359 static void
   3360 start_update(void) {
   3361 	isc_result_t result;
   3362 	dns_rdataset_t *rdataset = NULL;
   3363 	dns_name_t *name = NULL;
   3364 	dns_request_t *request = NULL;
   3365 	dns_message_t *soaquery = NULL;
   3366 	dns_name_t *firstname;
   3367 	dns_section_t section = DNS_SECTION_UPDATE;
   3368 
   3369 	ddebug("start_update()");
   3370 
   3371 	LOCK(&answer_lock);
   3372 	if (answer != NULL) {
   3373 		dns_message_detach(&answer);
   3374 	}
   3375 	UNLOCK(&answer_lock);
   3376 
   3377 	/*
   3378 	 * If we have both the zone and the servers we have enough information
   3379 	 * to send the update straight away otherwise we need to discover
   3380 	 * the zone and / or the primary server.
   3381 	 */
   3382 	if (userzone != NULL && !default_servers && !usegsstsig) {
   3383 		primary_from_servers();
   3384 		send_update(userzone, &primary_servers[primary_inuse]);
   3385 		setzoneclass(dns_rdataclass_none);
   3386 		return;
   3387 	}
   3388 
   3389 	dns_message_create(gmctx, NULL, NULL, DNS_MESSAGE_INTENTRENDER,
   3390 			   &soaquery);
   3391 
   3392 	if (default_servers) {
   3393 		soaquery->flags |= DNS_MESSAGEFLAG_RD;
   3394 	}
   3395 
   3396 	dns_message_gettempname(soaquery, &name);
   3397 
   3398 	dns_message_gettemprdataset(soaquery, &rdataset);
   3399 
   3400 	dns_rdataset_makequestion(rdataset, getzoneclass(), dns_rdatatype_soa);
   3401 
   3402 	if (userzone != NULL) {
   3403 		dns_name_clone(userzone, name);
   3404 	} else {
   3405 		dns_rdataset_t *tmprdataset;
   3406 		result = dns_message_firstname(updatemsg, section);
   3407 		if (result == ISC_R_NOMORE) {
   3408 			section = DNS_SECTION_PREREQUISITE;
   3409 			result = dns_message_firstname(updatemsg, section);
   3410 		}
   3411 		if (result != ISC_R_SUCCESS) {
   3412 			dns_message_puttempname(soaquery, &name);
   3413 			dns_rdataset_disassociate(rdataset);
   3414 			dns_message_puttemprdataset(soaquery, &rdataset);
   3415 			dns_message_detach(&soaquery);
   3416 			done_update();
   3417 			return;
   3418 		}
   3419 		firstname = NULL;
   3420 		dns_message_currentname(updatemsg, section, &firstname);
   3421 		dns_name_clone(firstname, name);
   3422 		/*
   3423 		 * Looks to see if the first name references a DS record
   3424 		 * and if that name is not the root remove a label as DS
   3425 		 * records live in the parent zone so we need to start our
   3426 		 * search one label up.
   3427 		 */
   3428 		tmprdataset = ISC_LIST_HEAD(firstname->list);
   3429 		if (section == DNS_SECTION_UPDATE &&
   3430 		    !dns_name_equal(firstname, dns_rootname) &&
   3431 		    tmprdataset->type == dns_rdatatype_ds)
   3432 		{
   3433 			unsigned int labels = dns_name_countlabels(name);
   3434 			dns_name_getlabelsequence(name, 1, labels - 1, name);
   3435 		}
   3436 	}
   3437 
   3438 	ISC_LIST_INIT(name->list);
   3439 	ISC_LIST_APPEND(name->list, rdataset, link);
   3440 	dns_message_addname(soaquery, name, DNS_SECTION_QUESTION);
   3441 
   3442 	ns_inuse = 0;
   3443 	sendrequest(&servers[ns_inuse], soaquery, &request);
   3444 }
   3445 
   3446 static void
   3447 cleanup(void) {
   3448 	ddebug("cleanup()");
   3449 
   3450 	if (tls_ctx_cache != NULL) {
   3451 		isc_tlsctx_cache_detach(&tls_ctx_cache);
   3452 	}
   3453 
   3454 	if (transport_list != NULL) {
   3455 		dns_transport_list_detach(&transport_list);
   3456 	}
   3457 
   3458 	LOCK(&answer_lock);
   3459 	if (answer != NULL) {
   3460 		dns_message_detach(&answer);
   3461 	}
   3462 	UNLOCK(&answer_lock);
   3463 
   3464 #if HAVE_GSSAPI
   3465 	if (tsigkey != NULL) {
   3466 		ddebug("detach tsigkey x%p", tsigkey);
   3467 		dns_tsigkey_detach(&tsigkey);
   3468 	}
   3469 	if (gssring != NULL) {
   3470 		ddebug("Detaching GSS-TSIG keyring");
   3471 		dns_tsigkeyring_detach(&gssring);
   3472 	}
   3473 #endif /* ifdef HAVE_GSSAPI */
   3474 
   3475 	if (sig0key != NULL) {
   3476 		dst_key_free(&sig0key);
   3477 	}
   3478 
   3479 #ifdef HAVE_GSSAPI
   3480 	if (kserver != NULL) {
   3481 		isc_mem_put(gmctx, kserver, sizeof(isc_sockaddr_t));
   3482 		kserver = NULL;
   3483 	}
   3484 	if (realm != NULL) {
   3485 		isc_mem_free(gmctx, realm);
   3486 		realm = NULL;
   3487 	}
   3488 	if (dns_name_dynamic(&tmpzonename)) {
   3489 		dns_name_free(&tmpzonename, gmctx);
   3490 	}
   3491 	if (dns_name_dynamic(&restart_primary)) {
   3492 		dns_name_free(&restart_primary, gmctx);
   3493 	}
   3494 #endif /* ifdef HAVE_GSSAPI */
   3495 
   3496 	ddebug("Removing log context");
   3497 	isc_log_destroy(&glctx);
   3498 
   3499 	ddebug("Destroying memory context");
   3500 	if (memdebugging) {
   3501 		isc_mem_stats(gmctx, stderr);
   3502 	}
   3503 
   3504 	isc_mutex_destroy(&answer_lock);
   3505 
   3506 	if (is_dst_up) {
   3507 		ddebug("Destroy DST lib");
   3508 		dst_lib_destroy();
   3509 		is_dst_up = false;
   3510 	}
   3511 
   3512 	ddebug("Shutting down managers");
   3513 	isc_managers_destroy(&gmctx, &loopmgr, &netmgr);
   3514 }
   3515 
   3516 static void
   3517 getinput(void *arg) {
   3518 	bool more;
   3519 
   3520 	UNUSED(arg);
   3521 
   3522 	if (shuttingdown) {
   3523 		maybeshutdown();
   3524 		return;
   3525 	}
   3526 
   3527 	reset_system();
   3528 	isc_loopmgr_blocking(loopmgr);
   3529 	more = user_interaction();
   3530 	isc_loopmgr_nonblocking(loopmgr);
   3531 	if (!more) {
   3532 		isc_loopmgr_shutdown(loopmgr);
   3533 		return;
   3534 	}
   3535 
   3536 	done = false;
   3537 	start_update();
   3538 }
   3539 
   3540 int
   3541 main(int argc, char **argv) {
   3542 	uint32_t timeoutms;
   3543 
   3544 	style = &dns_master_style_debug;
   3545 
   3546 	input = stdin;
   3547 
   3548 	interactive = isatty(0);
   3549 
   3550 	if (isc_net_probeipv4() == ISC_R_SUCCESS) {
   3551 		have_ipv4 = true;
   3552 	}
   3553 	if (isc_net_probeipv6() == ISC_R_SUCCESS) {
   3554 		have_ipv6 = true;
   3555 	}
   3556 	if (!have_ipv4 && !have_ipv6) {
   3557 		fatal("could not find either IPv4 or IPv6");
   3558 	}
   3559 
   3560 	pre_parse_args(argc, argv);
   3561 
   3562 	isc_managers_create(&gmctx, 1, &loopmgr, &netmgr);
   3563 
   3564 	parse_args(argc, argv);
   3565 
   3566 	/* Set the network manager timeouts in milliseconds. */
   3567 	timeoutms = timeout * 1000;
   3568 	isc_nm_settimeouts(netmgr, timeoutms, timeoutms, timeoutms, timeoutms);
   3569 
   3570 	isc_loopmgr_setup(loopmgr, setup_system, NULL);
   3571 	isc_loopmgr_setup(loopmgr, getinput, NULL);
   3572 	isc_loopmgr_teardown(loopmgr, shutdown_program, NULL);
   3573 	isc_loopmgr_run(loopmgr);
   3574 
   3575 	cleanup();
   3576 
   3577 	if (seenerror) {
   3578 		return 2;
   3579 	}
   3580 
   3581 	return 0;
   3582 }
   3583