nsupdate.c 70.1 KB
Newer Older
Michael Sawyer's avatar
Michael Sawyer committed
1
/*
Automatic Updater's avatar
Automatic Updater committed
2
 * Copyright (C) 2004-2009  Internet Systems Consortium, Inc. ("ISC")
Mark Andrews's avatar
Mark Andrews committed
3
 * Copyright (C) 2000-2003  Internet Software Consortium.
4
 *
Automatic Updater's avatar
Automatic Updater committed
5
 * Permission to use, copy, modify, and/or distribute this software for any
Michael Sawyer's avatar
Michael Sawyer committed
6 7
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
8
 *
Mark Andrews's avatar
Mark Andrews committed
9 10 11 12 13 14 15
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
Michael Sawyer's avatar
Michael Sawyer committed
16 17
 */

Automatic Updater's avatar
Automatic Updater committed
18
/* $Id: nsupdate.c,v 1.165 2009/01/17 23:47:42 tbox Exp $ */
19 20

/*! \file */
Michael Sawyer's avatar
Michael Sawyer committed
21 22

#include <config.h>
Brian Wellington's avatar
Brian Wellington committed
23

24 25 26 27 28 29
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <unistd.h>

30
#include <isc/app.h>
Michael Sawyer's avatar
Michael Sawyer committed
31
#include <isc/base64.h>
Michael Sawyer's avatar
Michael Sawyer committed
32
#include <isc/buffer.h>
Brian Wellington's avatar
Brian Wellington committed
33
#include <isc/commandline.h>
Michael Sawyer's avatar
Michael Sawyer committed
34
#include <isc/entropy.h>
35
#include <isc/event.h>
36
#include <isc/hash.h>
Michael Sawyer's avatar
Michael Sawyer committed
37
#include <isc/lex.h>
38
#include <isc/log.h>
Michael Sawyer's avatar
Michael Sawyer committed
39
#include <isc/mem.h>
40
#include <isc/parseint.h>
41
#include <isc/random.h>
Michael Sawyer's avatar
Michael Sawyer committed
42
#include <isc/region.h>
Michael Sawyer's avatar
Michael Sawyer committed
43 44
#include <isc/sockaddr.h>
#include <isc/socket.h>
45
#include <isc/stdio.h>
Michael Sawyer's avatar
Michael Sawyer committed
46
#include <isc/string.h>
Michael Sawyer's avatar
Michael Sawyer committed
47
#include <isc/task.h>
Michael Sawyer's avatar
Michael Sawyer committed
48
#include <isc/timer.h>
Michael Sawyer's avatar
Michael Sawyer committed
49
#include <isc/types.h>
Michael Sawyer's avatar
Michael Sawyer committed
50
#include <isc/util.h>
Michael Sawyer's avatar
Michael Sawyer committed
51

Brian Wellington's avatar
Brian Wellington committed
52 53
#include <dns/callbacks.h>
#include <dns/dispatch.h>
54
#include <dns/dnssec.h>
Brian Wellington's avatar
Brian Wellington committed
55
#include <dns/events.h>
56
#include <dns/fixedname.h>
57
#include <dns/log.h>
58
#include <dns/masterdump.h>
Brian Wellington's avatar
Brian Wellington committed
59 60
#include <dns/message.h>
#include <dns/name.h>
61
#include <dns/rcode.h>
Brian Wellington's avatar
Brian Wellington committed
62 63 64 65 66 67 68 69
#include <dns/rdata.h>
#include <dns/rdataclass.h>
#include <dns/rdatalist.h>
#include <dns/rdataset.h>
#include <dns/rdatastruct.h>
#include <dns/rdatatype.h>
#include <dns/request.h>
#include <dns/result.h>
70
#include <dns/tkey.h>
Brian Wellington's avatar
Brian Wellington committed
71
#include <dns/tsig.h>
72

Brian Wellington's avatar
Brian Wellington committed
73 74
#include <dst/dst.h>

75
#include <lwres/lwres.h>
76
#include <lwres/net.h>
77

78 79 80
#ifdef GSSAPI
#include <dst/gssapi.h>
#endif
81 82
#include <bind9/getaddresses.h>

83

84 85 86 87 88 89 90 91
#ifdef HAVE_ADDRINFO
#ifdef HAVE_GETADDRINFO
#ifdef HAVE_GAISTRERROR
#define USE_GETADDRINFO
#endif
#endif
#endif

Danny Mayer's avatar
Danny Mayer committed
92 93
#ifndef USE_GETADDRINFO
#ifndef ISC_PLATFORM_NONSTDHERRNO
94 95
extern int h_errno;
#endif
Danny Mayer's avatar
Danny Mayer committed
96
#endif
97

98
#define MAXCMD (4 * 1024)
99
#define MAXWIRE (64 * 1024)
100 101 102
#define PACKETSIZE ((64 * 1024) - 1)
#define INITTEXT (2 * 1024)
#define MAXTEXT (128 * 1024)
Michael Sawyer's avatar
Michael Sawyer committed
103
#define FIND_TIMEOUT 5
104
#define TTL_MAX 2147483647U	/* Maximum signed 32 bit integer. */
Michael Sawyer's avatar
Michael Sawyer committed
105

106 107
#define DNSDEFAULTPORT 53

108
#ifndef RESOLV_CONF
Michael Sawyer's avatar
Michael Sawyer committed
109
#define RESOLV_CONF "/etc/resolv.conf"
110
#endif
Michael Sawyer's avatar
Michael Sawyer committed
111

Brian Wellington's avatar
Brian Wellington committed
112
static isc_boolean_t debugging = ISC_FALSE, ddebugging = ISC_FALSE;
113
static isc_boolean_t memdebugging = ISC_FALSE;
Brian Wellington's avatar
Brian Wellington committed
114
static isc_boolean_t have_ipv4 = ISC_FALSE;
Brian Wellington's avatar
Brian Wellington committed
115 116
static isc_boolean_t have_ipv6 = ISC_FALSE;
static isc_boolean_t is_dst_up = ISC_FALSE;
Brian Wellington's avatar
Brian Wellington committed
117
static isc_boolean_t usevc = ISC_FALSE;
118 119 120
static isc_boolean_t usegsstsig = ISC_FALSE;
static isc_boolean_t use_win2k_gsstsig = ISC_FALSE;
static isc_boolean_t tried_other_gsstsig = ISC_FALSE;
Brian Wellington's avatar
Brian Wellington committed
121 122
static isc_taskmgr_t *taskmgr = NULL;
static isc_task_t *global_task = NULL;
123
static isc_event_t *global_event = NULL;
124
static isc_log_t *lctx = NULL;
Brian Wellington's avatar
Brian Wellington committed
125 126 127 128 129 130
static isc_mem_t *mctx = NULL;
static dns_dispatchmgr_t *dispatchmgr = NULL;
static dns_requestmgr_t *requestmgr = NULL;
static isc_socketmgr_t *socketmgr = NULL;
static isc_timermgr_t *timermgr = NULL;
static dns_dispatch_t *dispatchv4 = NULL;
Brian Wellington's avatar
Brian Wellington committed
131
static dns_dispatch_t *dispatchv6 = NULL;
Brian Wellington's avatar
Brian Wellington committed
132
static dns_message_t *updatemsg = NULL;
133 134
static dns_fixedname_t fuserzone;
static dns_name_t *userzone = NULL;
135 136 137 138
static dns_name_t *zonename = NULL;
static dns_name_t tmpzonename;
static dns_name_t restart_master;
static dns_tsig_keyring_t *gssring = NULL;
139 140
static dns_tsigkey_t *tsigkey = NULL;
static dst_key_t *sig0key;
141 142
static lwres_context_t *lwctx = NULL;
static lwres_conf_t *lwconf;
143
static isc_sockaddr_t *servers;
Brian Wellington's avatar
Brian Wellington committed
144
static int ns_inuse = 0;
145 146
static int ns_total = 0;
static isc_sockaddr_t *userserver = NULL;
147
static isc_sockaddr_t *localaddr = NULL;
148 149
static isc_sockaddr_t *serveraddr = NULL;
static isc_sockaddr_t tempaddr;
150
static char *keystr = NULL, *keyfile = NULL;
151
static isc_entropy_t *entropy = NULL;
152
static isc_boolean_t shuttingdown = ISC_FALSE;
153
static FILE *input;
154
static isc_boolean_t interactive = ISC_TRUE;
155
static isc_boolean_t seenerror = ISC_FALSE;
Danny Mayer's avatar
Danny Mayer committed
156
static const dns_master_style_t *style;
157
static int requests = 0;
158
static unsigned int logdebuglevel = 0;
Michael Graff's avatar
Michael Graff committed
159 160 161
static unsigned int timeout = 300;
static unsigned int udp_timeout = 3;
static unsigned int udp_retries = 3;
162 163
static dns_rdataclass_t defaultclass = dns_rdataclass_in;
static dns_rdataclass_t zoneclass = dns_rdataclass_none;
164
static dns_message_t *answer = NULL;
165 166
static isc_uint32_t default_ttl = 0;
static isc_boolean_t default_ttl_set = ISC_FALSE;
Brian Wellington's avatar
Brian Wellington committed
167

168 169 170 171 172
typedef struct nsu_requestinfo {
	dns_message_t *msg;
	isc_sockaddr_t *addr;
} nsu_requestinfo_t;

173
static void
174 175
sendrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
	    dns_message_t *msg, dns_request_t **request);
176 177 178 179 180 181 182 183
static void
fatal(const char *format, ...) ISC_FORMAT_PRINTF(1, 2);

static void
debug(const char *format, ...) ISC_FORMAT_PRINTF(1, 2);

static void
ddebug(const char *format, ...) ISC_FORMAT_PRINTF(1, 2);
Michael Sawyer's avatar
Michael Sawyer committed
184

185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
#ifdef GSSAPI
static dns_fixedname_t fkname;
static isc_sockaddr_t *kserver = NULL;
static char servicename[DNS_NAME_FORMATSIZE];
static dns_name_t *keyname;
typedef struct nsu_gssinfo {
	dns_message_t *msg;
	isc_sockaddr_t *addr;
	gss_ctx_id_t context;
} nsu_gssinfo_t;

static void
start_gssrequest(dns_name_t *master);
static void
send_gssrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
Automatic Updater's avatar
Automatic Updater committed
200
		dns_message_t *msg, dns_request_t **request,
201 202 203 204 205
		gss_ctx_id_t context);
static void
recvgss(isc_task_t *task, isc_event_t *event);
#endif /* GSSAPI */

206 207 208
static void
error(const char *format, ...) ISC_FORMAT_PRINTF(1, 2);

209 210 211 212
#define STATUS_MORE	(isc_uint16_t)0
#define STATUS_SEND	(isc_uint16_t)1
#define STATUS_QUIT	(isc_uint16_t)2
#define STATUS_SYNTAX	(isc_uint16_t)3
Michael Sawyer's avatar
Michael Sawyer committed
213

214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
typedef struct entropysource entropysource_t;

struct entropysource {
	isc_entropysource_t *source;
	isc_mem_t *mctx;
	ISC_LINK(entropysource_t) link;
};

static ISC_LIST(entropysource_t) sources;

static void
setup_entropy(isc_mem_t *mctx, const char *randomfile, isc_entropy_t **ectx)
{
	isc_result_t result;
	isc_entropysource_t *source = NULL;
	entropysource_t *elt;
	int usekeyboard = ISC_ENTROPY_KEYBOARDMAYBE;

	REQUIRE(ectx != NULL);

	if (*ectx == NULL) {
		result = isc_entropy_create(mctx, ectx);
		if (result != ISC_R_SUCCESS)
			fatal("could not create entropy object");
		ISC_LIST_INIT(sources);
	}

	if (randomfile != NULL && strcmp(randomfile, "keyboard") == 0) {
		usekeyboard = ISC_ENTROPY_KEYBOARDYES;
		randomfile = NULL;
	}

	result = isc_entropy_usebestsource(*ectx, &source, randomfile,
					   usekeyboard);

	if (result != ISC_R_SUCCESS)
		fatal("could not initialize entropy source: %s",
		      isc_result_totext(result));

	if (source != NULL) {
		elt = isc_mem_get(mctx, sizeof(*elt));
		if (elt == NULL)
			fatal("out of memory");
		elt->source = source;
		elt->mctx = mctx;
		ISC_LINK_INIT(elt, link);
		ISC_LIST_APPEND(sources, elt, link);
	}
}

static void
cleanup_entropy(isc_entropy_t **ectx) {
	entropysource_t *source;
	while (!ISC_LIST_EMPTY(sources)) {
		source = ISC_LIST_HEAD(sources);
		ISC_LIST_UNLINK(sources, source, link);
		isc_entropy_destroysource(&source->source);
		isc_mem_put(source->mctx, source, sizeof(*source));
	}
	isc_entropy_detach(ectx);
}


277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
static dns_rdataclass_t
getzoneclass(void) {
	if (zoneclass == dns_rdataclass_none)
		zoneclass = defaultclass;
	return (zoneclass);
}

static isc_boolean_t
setzoneclass(dns_rdataclass_t rdclass) {
	if (zoneclass == dns_rdataclass_none ||
	    rdclass == dns_rdataclass_none)
		zoneclass = rdclass;
	if (zoneclass != rdclass)
		return (ISC_FALSE);
	return (ISC_TRUE);
}

Michael Sawyer's avatar
Michael Sawyer committed
294 295 296 297
static void
fatal(const char *format, ...) {
	va_list args;

298
	va_start(args, format);
Michael Sawyer's avatar
Michael Sawyer committed
299 300 301
	vfprintf(stderr, format, args);
	va_end(args);
	fprintf(stderr, "\n");
Brian Wellington's avatar
Brian Wellington committed
302
	exit(1);
Michael Sawyer's avatar
Michael Sawyer committed
303 304
}

305 306 307 308 309 310 311 312 313 314
static void
error(const char *format, ...) {
	va_list args;

	va_start(args, format);
	vfprintf(stderr, format, args);
	va_end(args);
	fprintf(stderr, "\n");
}

Michael Sawyer's avatar
Michael Sawyer committed
315 316 317 318 319
static void
debug(const char *format, ...) {
	va_list args;

	if (debugging) {
320
		va_start(args, format);
Michael Sawyer's avatar
Michael Sawyer committed
321 322 323 324 325 326
		vfprintf(stderr, format, args);
		va_end(args);
		fprintf(stderr, "\n");
	}
}

327 328 329 330 331
static void
ddebug(const char *format, ...) {
	va_list args;

	if (ddebugging) {
332
		va_start(args, format);
333 334 335 336 337 338
		vfprintf(stderr, format, args);
		va_end(args);
		fprintf(stderr, "\n");
	}
}

339
static inline void
Michael Sawyer's avatar
Michael Sawyer committed
340
check_result(isc_result_t result, const char *msg) {
Brian Wellington's avatar
Brian Wellington committed
341
	if (result != ISC_R_SUCCESS)
Michael Sawyer's avatar
Michael Sawyer committed
342 343 344
		fatal("%s: %s", msg, isc_result_totext(result));
}

345 346 347
static void *
mem_alloc(void *arg, size_t size) {
	return (isc_mem_get(arg, size));
348 349
}

350 351 352
static void
mem_free(void *arg, void *mem, size_t size) {
	isc_mem_put(arg, mem, size);
353 354 355 356 357 358 359 360 361 362 363 364
}

static char *
nsu_strsep(char **stringp, const char *delim) {
	char *string = *stringp;
	char *s;
	const char *d;
	char sc, dc;

	if (string == NULL)
		return (NULL);

365 366 367 368 369 370 371 372 373 374
	for (; *string != '\0'; string++) {
		sc = *string;
		for (d = delim; (dc = *d) != '\0'; d++) {
			if (sc == dc)
				break;
		}
		if (dc == 0)
			break;
	}

375 376
	for (s = string; *s != '\0'; s++) {
		sc = *s;
377
		for (d = delim; (dc = *d) != '\0'; d++) {
378 379 380 381 382
			if (sc == dc) {
				*s++ = '\0';
				*stringp = s;
				return (string);
			}
383
		}
384 385 386 387 388
	}
	*stringp = NULL;
	return (string);
}

Michael Sawyer's avatar
Michael Sawyer committed
389
static void
Brian Wellington's avatar
Brian Wellington committed
390
reset_system(void) {
Michael Sawyer's avatar
Michael Sawyer committed
391 392
	isc_result_t result;

393
	ddebug("reset_system()");
Michael Sawyer's avatar
Michael Sawyer committed
394 395
	/* If the update message is still around, destroy it */
	if (updatemsg != NULL)
Brian Wellington's avatar
Brian Wellington committed
396 397 398 399
		dns_message_reset(updatemsg, DNS_MESSAGE_INTENTRENDER);
	else {
		result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER,
					    &updatemsg);
400
		check_result(result, "dns_message_create");
Brian Wellington's avatar
Brian Wellington committed
401
	}
Michael Sawyer's avatar
Michael Sawyer committed
402
	updatemsg->opcode = dns_opcode_update;
403 404 405 406 407 408 409
	if (usegsstsig) {
		if (tsigkey != NULL)
			dns_tsigkey_detach(&tsigkey);
		if (gssring != NULL)
			dns_tsigkeyring_destroy(&gssring);
		tried_other_gsstsig = ISC_FALSE;
	}
Michael Sawyer's avatar
Michael Sawyer committed
410 411
}

412 413 414 415 416 417 418 419 420 421 422 423 424 425
static isc_uint16_t
parse_hmac(dns_name_t **hmac, const char *hmacstr, size_t len) {
	isc_uint16_t digestbits = 0;
	isc_result_t result;
	char buf[20];

	REQUIRE(hmac != NULL && *hmac == NULL);
	REQUIRE(hmacstr != NULL);

	if (len >= sizeof(buf))
		fatal("unknown key type '%.*s'", (int)(len), hmacstr);

	strncpy(buf, hmacstr, len);
	buf[len] = 0;
Automatic Updater's avatar
Automatic Updater committed
426

427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479
	if (strcasecmp(buf, "hmac-md5") == 0) {
		*hmac = DNS_TSIG_HMACMD5_NAME;
	} else if (strncasecmp(buf, "hmac-md5-", 9) == 0) {
		*hmac = DNS_TSIG_HMACMD5_NAME;
		result = isc_parse_uint16(&digestbits, &buf[9], 10);
		if (result != ISC_R_SUCCESS || digestbits > 128)
			fatal("digest-bits out of range [0..128]");
		digestbits = (digestbits +7) & ~0x7U;
	} else if (strcasecmp(buf, "hmac-sha1") == 0) {
		*hmac = DNS_TSIG_HMACSHA1_NAME;
	} else if (strncasecmp(buf, "hmac-sha1-", 10) == 0) {
		*hmac = DNS_TSIG_HMACSHA1_NAME;
		result = isc_parse_uint16(&digestbits, &buf[10], 10);
		if (result != ISC_R_SUCCESS || digestbits > 160)
			fatal("digest-bits out of range [0..160]");
		digestbits = (digestbits +7) & ~0x7U;
	} else if (strcasecmp(buf, "hmac-sha224") == 0) {
		*hmac = DNS_TSIG_HMACSHA224_NAME;
	} else if (strncasecmp(buf, "hmac-sha224-", 12) == 0) {
		*hmac = DNS_TSIG_HMACSHA224_NAME;
		result = isc_parse_uint16(&digestbits, &buf[12], 10);
		if (result != ISC_R_SUCCESS || digestbits > 224)
			fatal("digest-bits out of range [0..224]");
		digestbits = (digestbits +7) & ~0x7U;
	} else if (strcasecmp(buf, "hmac-sha256") == 0) {
		*hmac = DNS_TSIG_HMACSHA256_NAME;
	} else if (strncasecmp(buf, "hmac-sha256-", 12) == 0) {
		*hmac = DNS_TSIG_HMACSHA256_NAME;
		result = isc_parse_uint16(&digestbits, &buf[12], 10);
		if (result != ISC_R_SUCCESS || digestbits > 256)
			fatal("digest-bits out of range [0..256]");
		digestbits = (digestbits +7) & ~0x7U;
	} else if (strcasecmp(buf, "hmac-sha384") == 0) {
		*hmac = DNS_TSIG_HMACSHA384_NAME;
	} else if (strncasecmp(buf, "hmac-sha384-", 12) == 0) {
		*hmac = DNS_TSIG_HMACSHA384_NAME;
		result = isc_parse_uint16(&digestbits, &buf[12], 10);
		if (result != ISC_R_SUCCESS || digestbits > 384)
			fatal("digest-bits out of range [0..384]");
		digestbits = (digestbits +7) & ~0x7U;
	} else if (strcasecmp(buf, "hmac-sha512") == 0) {
		*hmac = DNS_TSIG_HMACSHA512_NAME;
	} else if (strncasecmp(buf, "hmac-sha512-", 12) == 0) {
		*hmac = DNS_TSIG_HMACSHA512_NAME;
		result = isc_parse_uint16(&digestbits, &buf[12], 10);
		if (result != ISC_R_SUCCESS || digestbits > 512)
			fatal("digest-bits out of range [0..512]");
		digestbits = (digestbits +7) & ~0x7U;
	} else
		fatal("unknown key type '%s'", buf);
	return (digestbits);
}

480
static void
481
setup_keystr(void) {
482 483 484 485
	unsigned char *secret = NULL;
	int secretlen;
	isc_buffer_t secretbuf;
	isc_result_t result;
486 487
	isc_buffer_t keynamesrc;
	char *secretstr;
488
	char *s, *n;
489 490
	dns_fixedname_t fkeyname;
	dns_name_t *keyname;
491 492 493
	char *name;
	dns_name_t *hmacname = NULL;
	isc_uint16_t digestbits = 0;
494

495 496 497
	dns_fixedname_init(&fkeyname);
	keyname = dns_fixedname_name(&fkeyname);

498
	debug("Creating key...");
499

500
	s = strchr(keystr, ':');
501 502
	if (s == NULL || s == keystr || s[1] == 0)
		fatal("key option must specify [hmac:]keyname:secret");
503
	secretstr = s + 1;
504 505 506 507 508 509 510 511 512 513 514 515
	n = strchr(secretstr, ':');
	if (n != NULL) {
		if (n == secretstr || n[1] == 0)
			fatal("key option must specify [hmac:]keyname:secret");
		name = secretstr;
		secretstr = n + 1;
		digestbits = parse_hmac(&hmacname, keystr, s - keystr);
	} else {
		hmacname = DNS_TSIG_HMACMD5_NAME;
		name = keystr;
		n = s;
	}
516

517 518
	isc_buffer_init(&keynamesrc, name, n - name);
	isc_buffer_add(&keynamesrc, n - name);
519

520 521 522 523
	debug("namefromtext");
	result = dns_name_fromtext(keyname, &keynamesrc, dns_rootname,
				   ISC_FALSE, NULL);
	check_result(result, "dns_name_fromtext");
524

525 526 527 528
	secretlen = strlen(secretstr) * 3 / 4;
	secret = isc_mem_allocate(mctx, secretlen);
	if (secret == NULL)
		fatal("out of memory");
529

530 531 532 533 534 535
	isc_buffer_init(&secretbuf, secret, secretlen);
	result = isc_base64_decodestring(secretstr, &secretbuf);
	if (result != ISC_R_SUCCESS) {
		fprintf(stderr, "could not create key from %s: %s\n",
			keystr, isc_result_totext(result));
		goto failure;
536
	}
537

538 539
	secretlen = isc_buffer_usedlength(&secretbuf);

540
	debug("keycreate");
541 542
	result = dns_tsigkey_create(keyname, hmacname, secret, secretlen,
				    ISC_TRUE, NULL, 0, 0, mctx, NULL, &tsigkey);
543
	if (result != ISC_R_SUCCESS)
544
		fprintf(stderr, "could not create key from %s: %s\n",
545
			keystr, dns_result_totext(result));
546 547
	else
		dst_key_setbits(tsigkey->key, digestbits);
548 549 550 551 552
 failure:
	if (secret != NULL)
		isc_mem_free(mctx, secret);
}

553 554 555 556
static void
setup_keyfile(void) {
	dst_key_t *dstkey = NULL;
	isc_result_t result;
557
	dns_name_t *hmacname = NULL;
558 559 560

	debug("Creating key...");

561 562
	result = dst_key_fromnamedfile(keyfile,
				       DST_TYPE_PRIVATE | DST_TYPE_KEY, mctx,
563 564 565 566 567 568
				       &dstkey);
	if (result != ISC_R_SUCCESS) {
		fprintf(stderr, "could not read key from %s: %s\n",
			keyfile, isc_result_totext(result));
		return;
	}
569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589
	switch (dst_key_alg(dstkey)) {
	case DST_ALG_HMACMD5:
		hmacname = DNS_TSIG_HMACMD5_NAME;
		break;
	case DST_ALG_HMACSHA1:
		hmacname = DNS_TSIG_HMACSHA1_NAME;
		break;
	case DST_ALG_HMACSHA224:
		hmacname = DNS_TSIG_HMACSHA224_NAME;
		break;
	case DST_ALG_HMACSHA256:
		hmacname = DNS_TSIG_HMACSHA256_NAME;
		break;
	case DST_ALG_HMACSHA384:
		hmacname = DNS_TSIG_HMACSHA384_NAME;
		break;
	case DST_ALG_HMACSHA512:
		hmacname = DNS_TSIG_HMACSHA512_NAME;
		break;
	}
	if (hmacname != NULL) {
590
		result = dns_tsigkey_createfromkey(dst_key_name(dstkey),
591 592 593
						   hmacname, dstkey, ISC_FALSE,
						   NULL, 0, 0, mctx, NULL,
						   &tsigkey);
594 595 596 597 598 599 600 601
		if (result != ISC_R_SUCCESS) {
			fprintf(stderr, "could not create key from %s: %s\n",
				keyfile, isc_result_totext(result));
			dst_key_free(&dstkey);
			return;
		}
	} else
		sig0key = dstkey;
602 603
}

604
static void
605
doshutdown(void) {
606
	isc_task_detach(&global_task);
607 608 609 610 611 612 613

	if (userserver != NULL)
		isc_mem_put(mctx, userserver, sizeof(isc_sockaddr_t));

	if (localaddr != NULL)
		isc_mem_put(mctx, localaddr, sizeof(isc_sockaddr_t));

614 615 616 617 618 619 620 621
	if (tsigkey != NULL) {
		ddebug("Freeing TSIG key");
		dns_tsigkey_detach(&tsigkey);
	}

	if (sig0key != NULL) {
		ddebug("Freeing SIG(0) key");
		dst_key_free(&sig0key);
622 623 624 625 626 627
	}

	if (updatemsg != NULL)
		dns_message_destroy(&updatemsg);

	if (is_dst_up) {
628
		ddebug("Destroy DST lib");
629 630 631 632
		dst_lib_destroy();
		is_dst_up = ISC_FALSE;
	}

633
	cleanup_entropy(&entropy);
634 635 636 637 638 639

	lwres_conf_clear(lwctx);
	lwres_context_destroy(&lwctx);

	isc_mem_put(mctx, servers, ns_total * sizeof(isc_sockaddr_t));

640
	ddebug("Destroying request manager");
641 642 643 644 645 646 647 648 649 650 651
	dns_requestmgr_detach(&requestmgr);

	ddebug("Freeing the dispatchers");
	if (have_ipv4)
		dns_dispatch_detach(&dispatchv4);
	if (have_ipv6)
		dns_dispatch_detach(&dispatchv6);

	ddebug("Shutting down dispatch manager");
	dns_dispatchmgr_destroy(&dispatchmgr);

652 653
}

654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676
static void
maybeshutdown(void) {
	ddebug("Shutting down request manager");
	dns_requestmgr_shutdown(requestmgr);

	if (requests != 0)
		return;

	doshutdown();
}

static void
shutdown_program(isc_task_t *task, isc_event_t *event) {
	REQUIRE(task == global_task);
	UNUSED(task);

	ddebug("shutdown_program()");
	isc_event_free(&event);

	shuttingdown = ISC_TRUE;
	maybeshutdown();
}

Michael Sawyer's avatar
Michael Sawyer committed
677
static void
Brian Wellington's avatar
Brian Wellington committed
678
setup_system(void) {
Michael Sawyer's avatar
Michael Sawyer committed
679
	isc_result_t result;
Brian Wellington's avatar
Brian Wellington committed
680
	isc_sockaddr_t bind_any, bind_any6;
681
	lwres_result_t lwresult;
Brian Wellington's avatar
Brian Wellington committed
682
	unsigned int attrs, attrmask;
683
	int i;
684
	isc_logconfig_t *logconfig = NULL;
Michael Sawyer's avatar
Michael Sawyer committed
685

686
	ddebug("setup_system()");
Michael Sawyer's avatar
Michael Sawyer committed
687

688 689
	dns_result_register();

Michael Sawyer's avatar
Michael Sawyer committed
690
	result = isc_net_probeipv4();
Brian Wellington's avatar
Brian Wellington committed
691 692
	if (result == ISC_R_SUCCESS)
		have_ipv4 = ISC_TRUE;
Michael Sawyer's avatar
Michael Sawyer committed
693 694 695

	result = isc_net_probeipv6();
	if (result == ISC_R_SUCCESS)
Brian Wellington's avatar
Brian Wellington committed
696
		have_ipv6 = ISC_TRUE;
Michael Sawyer's avatar
Michael Sawyer committed
697

Brian Wellington's avatar
Brian Wellington committed
698
	if (!have_ipv4 && !have_ipv6)
699
		fatal("could not find either IPv4 or IPv6");
Brian Wellington's avatar
Brian Wellington committed
700

701 702 703 704 705 706 707 708 709 710 711 712
	result = isc_log_create(mctx, &lctx, &logconfig);
	check_result(result, "isc_log_create");

	isc_log_setcontext(lctx);
	dns_log_init(lctx);
	dns_log_setcontext(lctx);

	result = isc_log_usechannel(logconfig, "default_debug", NULL, NULL);
	check_result(result, "isc_log_usechannel");

	isc_log_setdebuglevel(lctx, logdebuglevel);

713 714 715 716
	lwresult = lwres_context_create(&lwctx, mctx, mem_alloc, mem_free, 1);
	if (lwresult != LWRES_R_SUCCESS)
		fatal("lwres_context_create failed");

717
	(void)lwres_conf_parse(lwctx, RESOLV_CONF);
718
	lwconf = lwres_conf_get(lwctx);
Brian Wellington's avatar
Brian Wellington committed
719

720
	ns_total = lwconf->nsnext;
721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744
	if (ns_total <= 0) {
		/* No name servers in resolv.conf; default to loopback. */
		struct in_addr localhost;
		ns_total = 1;
		servers = isc_mem_get(mctx, ns_total * sizeof(isc_sockaddr_t));
		if (servers == NULL)
			fatal("out of memory");
		localhost.s_addr = htonl(INADDR_LOOPBACK);
		isc_sockaddr_fromin(&servers[0], &localhost, DNSDEFAULTPORT);
	} else {
		servers = isc_mem_get(mctx, ns_total * sizeof(isc_sockaddr_t));
		if (servers == NULL)
			fatal("out of memory");
		for (i = 0; i < ns_total; i++) {
			if (lwconf->nameservers[i].family == LWRES_ADDRTYPE_V4) {
				struct in_addr in4;
				memcpy(&in4, lwconf->nameservers[i].address, 4);
				isc_sockaddr_fromin(&servers[i], &in4, DNSDEFAULTPORT);
			} else {
				struct in6_addr in6;
				memcpy(&in6, lwconf->nameservers[i].address, 16);
				isc_sockaddr_fromin6(&servers[i], &in6,
						     DNSDEFAULTPORT);
			}
745 746 747
		}
	}

748
	setup_entropy(mctx, NULL, &entropy);
749

750
	result = isc_hash_create(mctx, entropy, DNS_NAME_MAXWIRE);
751 752 753
	check_result(result, "isc_hash_create");
	isc_hash_init();

754
	result = dns_dispatchmgr_create(mctx, entropy, &dispatchmgr);
Michael Sawyer's avatar
Michael Sawyer committed
755 756 757 758 759 760 761 762
	check_result(result, "dns_dispatchmgr_create");

	result = isc_socketmgr_create(mctx, &socketmgr);
	check_result(result, "dns_socketmgr_create");

	result = isc_timermgr_create(mctx, &timermgr);
	check_result(result, "dns_timermgr_create");

763
	result = isc_taskmgr_create(mctx, 1, 0, &taskmgr);
Michael Sawyer's avatar
Michael Sawyer committed
764 765
	check_result(result, "isc_taskmgr_create");

766
	result = isc_task_create(taskmgr, 0, &global_task);
Michael Sawyer's avatar
Michael Sawyer committed
767 768
	check_result(result, "isc_task_create");

769 770 771
	result = isc_task_onshutdown(global_task, shutdown_program, NULL);
	check_result(result, "isc_task_onshutdown");

772
	result = dst_lib_init(mctx, entropy, 0);
Michael Sawyer's avatar
Michael Sawyer committed
773 774 775
	check_result(result, "dst_lib_init");
	is_dst_up = ISC_TRUE;

Brian Wellington's avatar
Brian Wellington committed
776 777 778 779 780 781 782 783 784 785 786 787 788 789
	attrmask = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP;
	attrmask |= DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6;

	if (have_ipv6) {
		attrs = DNS_DISPATCHATTR_UDP;
		attrs |= DNS_DISPATCHATTR_MAKEQUERY;
		attrs |= DNS_DISPATCHATTR_IPV6;
		isc_sockaddr_any6(&bind_any6);
		result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr,
					     &bind_any6, PACKETSIZE,
					     4, 2, 3, 5,
					     attrs, attrmask, &dispatchv6);
		check_result(result, "dns_dispatch_getudp (v6)");
	}
Michael Sawyer's avatar
Michael Sawyer committed
790

Brian Wellington's avatar
Brian Wellington committed
791 792 793 794 795 796 797 798 799 800 801
	if (have_ipv4) {
		attrs = DNS_DISPATCHATTR_UDP;
		attrs |= DNS_DISPATCHATTR_MAKEQUERY;
		attrs |= DNS_DISPATCHATTR_IPV4;
		isc_sockaddr_any(&bind_any);
		result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr,
					     &bind_any, PACKETSIZE,
					     4, 2, 3, 5,
					     attrs, attrmask, &dispatchv4);
		check_result(result, "dns_dispatch_getudp (v4)");
	}
802

Michael Sawyer's avatar
Michael Sawyer committed
803 804
	result = dns_requestmgr_create(mctx, timermgr,
				       socketmgr, taskmgr, dispatchmgr,
Brian Wellington's avatar
Brian Wellington committed
805
				       dispatchv4, dispatchv6, &requestmgr);
Michael Sawyer's avatar
Michael Sawyer committed
806 807
	check_result(result, "dns_requestmgr_create");

808 809 810 811
	if (keystr != NULL)
		setup_keystr();
	else if (keyfile != NULL)
		setup_keyfile();
Michael Sawyer's avatar
Michael Sawyer committed
812
}
Michael Sawyer's avatar
Michael Sawyer committed
813

814 815
static void
get_address(char *host, in_port_t port, isc_sockaddr_t *sockaddr) {
816 817
	int count;
	isc_result_t result;
818

819 820 821 822 823 824 825
	isc_app_block();
	result = bind9_getaddresses(host, port, sockaddr, 1, &count);
	isc_app_unblock();
	if (result != ISC_R_SUCCESS)
		fatal("couldn't get address for '%s': %s",
		      host, isc_result_totext(result));
	INSIST(count == 1);
826 827
}

828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860
#define PARSE_ARGS_FMT "dDMl:y:govk:rR::t:u:"

static void
pre_parse_args(int argc, char **argv) {
	int ch;

	while ((ch = isc_commandline_parse(argc, argv, PARSE_ARGS_FMT)) != -1) {
		switch (ch) {
		case 'M': /* was -dm */
			debugging = ISC_TRUE;
			ddebugging = ISC_TRUE;
			memdebugging = ISC_TRUE;
			isc_mem_debugging = ISC_MEM_DEBUGTRACE |
					    ISC_MEM_DEBUGRECORD;
			break;

		case '?':
			if (isc_commandline_option != '?')
				fprintf(stderr, "%s: invalid argument -%c\n",
					argv[0], isc_commandline_option);
			fprintf(stderr, "usage: nsupdate [-d] "
				"[-g | -o | -y keyname:secret | -k keyfile] "
				"[-v] [filename]\n");
			exit(1);

		default:
			break;
		}
	}
	isc_commandline_reset = ISC_TRUE;
	isc_commandline_index = 1;
}

Michael Sawyer's avatar
Michael Sawyer committed
861
static void
862
parse_args(int argc, char **argv, isc_mem_t *mctx, isc_entropy_t **ectx) {
Brian Wellington's avatar
Brian Wellington committed
863
	int ch;
864
	isc_uint32_t i;
865
	isc_result_t result;
Michael Sawyer's avatar
Michael Sawyer committed
866

Michael Sawyer's avatar
Michael Sawyer committed
867
	debug("parse_args");
868
	while ((ch = isc_commandline_parse(argc, argv, PARSE_ARGS_FMT)) != -1) {
Brian Wellington's avatar
Brian Wellington committed
869 870 871 872 873
		switch (ch) {
		case 'd':
			debugging = ISC_TRUE;
			break;
		case 'D': /* was -dd */
Michael Sawyer's avatar
Michael Sawyer committed
874 875
			debugging = ISC_TRUE;
			ddebugging = ISC_TRUE;
Brian Wellington's avatar
Brian Wellington committed
876
			break;
877
		case 'M':
Brian Wellington's avatar
Brian Wellington committed
878
			break;
879 880 881 882 883 884 885 886 887 888
		case 'l':
			result = isc_parse_uint32(&i, isc_commandline_argument,
						  10);
			if (result != ISC_R_SUCCESS) {
				fprintf(stderr, "bad library debug value "
					"'%s'\n", isc_commandline_argument);
				exit(1);
			}
			logdebuglevel = i;
			break;
Brian Wellington's avatar
Brian Wellington committed
889 890 891 892
		case 'y':
			keystr = isc_commandline_argument;
			break;
		case 'v':
Brian Wellington's avatar
Brian Wellington committed
893
			usevc = ISC_TRUE;
Brian Wellington's avatar
Brian Wellington committed
894 895
			break;
		case 'k':
896
			keyfile = isc_commandline_argument;
Brian Wellington's avatar
Brian Wellington committed
897
			break;
898 899 900 901 902 903 904 905
		case 'g':
			usegsstsig = ISC_TRUE;
			use_win2k_gsstsig = ISC_FALSE;
			break;
		case 'o':
			usegsstsig = ISC_TRUE;
			use_win2k_gsstsig = ISC_TRUE;
			break;
Michael Graff's avatar
Michael Graff committed
906 907 908 909 910 911 912 913
		case 't':
			result = isc_parse_uint32(&timeout,
						  isc_commandline_argument, 10);
			if (result != ISC_R_SUCCESS) {
				fprintf(stderr, "bad timeout '%s'\n",						isc_commandline_argument);
				exit(1);
			}
			if (timeout == 0)
Mark Andrews's avatar
Mark Andrews committed
914
				timeout = UINT_MAX;
Michael Graff's avatar
Michael Graff committed
915 916 917 918 919 920 921 922 923
			break;
		case 'u':
			result = isc_parse_uint32(&udp_timeout,
						  isc_commandline_argument, 10);
			if (result != ISC_R_SUCCESS) {
				fprintf(stderr, "bad udp timeout '%s'\n",						isc_commandline_argument);
				exit(1);
			}
			if (udp_timeout == 0)
Mark Andrews's avatar
Mark Andrews committed
924
				udp_timeout = UINT_MAX;
Michael Graff's avatar
Michael Graff committed
925 926 927 928 929 930 931 932 933
			break;
		case 'r':
			result = isc_parse_uint32(&udp_retries,
						  isc_commandline_argument, 10);
			if (result != ISC_R_SUCCESS) {
				fprintf(stderr, "bad udp retries '%s'\n",						isc_commandline_argument);
				exit(1);
			}
			break;
934 935 936 937

		case 'R':
			setup_entropy(mctx, isc_commandline_argument, ectx);
			break;
938 939 940 941 942

		default:
			fprintf(stderr, "%s: unhandled option: %c\n",
				argv[0], isc_commandline_option);
			exit(1);
Brian Wellington's avatar
Brian Wellington committed
943
		}
Michael Sawyer's avatar
Michael Sawyer committed
944
	}
945
	if (keyfile != NULL && keystr != NULL) {
946 947
		fprintf(stderr, "%s: cannot specify both -k and -y\n",
			argv[0]);
948 949
		exit(1);
	}
950

951 952 953 954 955 956 957 958 959 960 961 962 963 964 965
#ifdef GSSAPI
	if (usegsstsig && (keyfile != NULL || keystr != NULL)) {
		fprintf(stderr, "%s: cannot specify -g with -k or -y\n",
			argv[0]);
		exit(1);
	}
#else
	if (usegsstsig) {
		fprintf(stderr, "%s: cannot specify -g  or -o, " \
			"program not linked with GSS API Library\n",
			argv[0]);
		exit(1);
	}
#endif

966
	if (argv[isc_commandline_index] != NULL) {
967 968 969 970 971 972
		if (strcmp(argv[isc_commandline_index], "-") == 0) {
			input = stdin;
		} else {
			result = isc_stdio_open(argv[isc_commandline_index],
						"r", &input);
			if (result != ISC_R_SUCCESS) {
973
				fprintf(stderr, "could not open '%s': %s\n",
974 975 976 977
					argv[isc_commandline_index],
					isc_result_totext(result));
				exit(1);
			}
978
		}
979
		interactive = ISC_FALSE;
980
	}
Michael Sawyer's avatar
Michael Sawyer committed
981 982 983
}

static isc_uint16_t
984
parse_name(char **cmdlinep, dns_message_t *msg, dns_name_t **namep) {
Michael Sawyer's avatar
Michael Sawyer committed
985
	isc_result_t result;
986
	char *word;
Brian Wellington's avatar
Brian Wellington committed
987
	isc_buffer_t *namebuf = NULL;
Michael Sawyer's avatar
Michael Sawyer committed
988
	isc_buffer_t source;
Michael Sawyer's avatar
Michael Sawyer committed
989

990
	word = nsu_strsep(cmdlinep, " \t\r\n");
991
	if (*word == 0) {
992
		fprintf(stderr, "could not read owner name\n");
Brian Wellington's avatar
Brian Wellington committed
993
		return (STATUS_SYNTAX);
Michael Sawyer's avatar
Michael Sawyer committed
994 995
	}

996
	result = dns_message_gettempname(msg, namep);
Michael Sawyer's avatar
Michael Sawyer committed
997
	check_result(result, "dns_message_gettempname");
998
	result = isc_buffer_allocate(mctx, &namebuf, DNS_NAME_MAXWIRE);
Michael Sawyer's avatar
Michael Sawyer committed
999
	check_result(result, "isc_buffer_allocate");
1000 1001 1002
	dns_name_init(*namep, NULL);
	dns_name_setbuffer(*namep, namebuf);
	dns_message_takebuffer(msg, &namebuf);
1003 1004
	isc_buffer_init(&source, word, strlen(word));
	isc_buffer_add(&source, strlen(word));
1005
	result = dns_name_fromtext(*namep, &source, dns_rootname,
Michael Sawyer's avatar
Michael Sawyer committed
1006 1007
				   ISC_FALSE, NULL);
	check_result(result, "dns_name_fromtext");
1008 1009 1010 1011 1012 1013
	isc_buffer_invalidate(&source);
	return (STATUS_MORE);
}

static isc_uint16_t
parse_rdata(char **cmdlinep, dns_rdataclass_t rdataclass,
1014
	    dns_rdatatype_t rdatatype, dns_message_t *msg,
1015
	    dns_rdata_t *rdata)
1016 1017
{
	char *cmdline = *cmdlinep;
1018 1019
	isc_buffer_t source, *buf = NULL, *newbuf = NULL;
	isc_region_t r;
1020 1021 1022 1023
	isc_lex_t *lex = NULL;
	dns_rdatacallbacks_t callbacks;
	isc_result_t result;

1024
	while (*cmdline != 0 && isspace((unsigned char)*cmdline))
1025 1026 1027
		cmdline++;

	if (*cmdline != 0) {
1028
		dns_rdatacallbacks_init(&callbacks);
1029 1030 1031 1032 1033 1034 1035 1036
		result = isc_lex_create(mctx, strlen(cmdline), &lex);
		check_result(result, "isc_lex_create");
		isc_buffer_init(&source, cmdline, strlen(cmdline));
		isc_buffer_add(&source, strlen(cmdline));
		result = isc_lex_openbuffer(lex, &source);
		check_result(result, "isc_lex_openbuffer");
		result = isc_buffer_allocate(mctx, &buf, MAXWIRE);
		check_result(result, "isc_buffer_allocate");
1037
		result = dns_rdata_fromtext(NULL, rdataclass, rdatatype, lex,
1038
					    dns_rootname, 0, mctx, buf,
1039 1040 1041 1042 1043
					    &callbacks);
		isc_lex_destroy(&lex);
		if (result == ISC_R_SUCCESS) {
			isc_buffer_usedregion(buf, &r);
			result = isc_buffer_allocate(mctx, &newbuf, r.length);
1044
			check_result(result, "isc_buffer_allocate");
1045 1046 1047 1048 1049 1050
			isc_buffer_putmem(newbuf, r.base, r.length);
			isc_buffer_usedregion(newbuf, &r);
			dns_rdata_fromregion(rdata, rdataclass, rdatatype, &r);
			isc_buffer_free(&buf);
			dns_message_takebuffer(msg, &newbuf);
		} else {
1051 1052
			fprintf(stderr, "invalid rdata format: %s\n",
				isc_result_totext(result));
1053
			isc_buffer_free(&buf);
1054 1055
			return (STATUS_SYNTAX);
		}
1056 1057
	} else {
		rdata->flags = DNS_RDATA_UPDATE;
1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075
	}
	*cmdlinep = cmdline;
	return (STATUS_MORE);
}

static isc_uint16_t
make_prereq(char *cmdline, isc_boolean_t ispositive, isc_boolean_t isrrset) {
	isc_result_t result;
	char *word;
	dns_name_t *name = NULL;
	isc_textregion_t region;
	dns_rdataset_t *rdataset = NULL;
	dns_rdatalist_t *rdatalist = NULL;
	dns_rdataclass_t rdataclass;
	dns_rdatatype_t rdatatype;
	dns_rdata_t *rdata = NULL;
	isc_uint16_t retval;

1076
	ddebug("make_prereq()");
1077 1078 1079 1080 1081 1082 1083 1084

	/*
	 * Read the owner name
	 */
	retval = parse_name(&cmdline, updatemsg, &name);
	if (retval != STATUS_MORE)
		return (retval);

Brian Wellington's avatar
Brian Wellington committed
1085 1086 1087 1088
	/*
	 * If this is an rrset prereq, read the class or type.
	 */
	if (isrrset) {
1089
		word = nsu_strsep(&cmdline, " \t\r\n");
1090
		if (*word == 0) {
1091
			fprintf(stderr, "could not read class or type\n");
1092
			goto failure;
Brian Wellington's avatar
Brian Wellington committed
1093
		}
1094 1095
		region.base = word;
		region.length = strlen(word);
Brian Wellington's avatar
Brian Wellington committed
1096 1097
		result = dns_rdataclass_fromtext(&rdataclass, &region);
		if (result == ISC_R_SUCCESS) {
1098 1099 1100 1101
			if (!setzoneclass(rdataclass)) {
				fprintf(stderr, "class mismatch: %s\n", word);
				goto failure;
			}
Brian Wellington's avatar
Brian Wellington committed
1102 1103 1104
			/*
			 * Now read the type.
			 */
1105
			word = nsu_strsep(&cmdline, " \t\r\n");
1106
			if (*word == 0) {