nsupdate.c 78.7 KB
Newer Older
Michael Sawyer's avatar
Michael Sawyer committed
1
/*
Tinderbox User's avatar
Tinderbox User committed
2
 * Copyright (C) 2004-2014  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
 */

18
/* $Id: nsupdate.c,v 1.198 2011/12/16 23:01:16 each 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/file.h>
37
#include <isc/hash.h>
Michael Sawyer's avatar
Michael Sawyer committed
38
#include <isc/lex.h>
39
#include <isc/log.h>
Michael Sawyer's avatar
Michael Sawyer committed
40
#include <isc/mem.h>
41
#include <isc/parseint.h>
Evan Hunt's avatar
Evan Hunt committed
42
#include <isc/print.h>
43
#include <isc/random.h>
Michael Sawyer's avatar
Michael Sawyer committed
44
#include <isc/region.h>
Michael Sawyer's avatar
Michael Sawyer committed
45
46
#include <isc/sockaddr.h>
#include <isc/socket.h>
47
#include <isc/stdio.h>
Michael Sawyer's avatar
Michael Sawyer committed
48
#include <isc/string.h>
Michael Sawyer's avatar
Michael Sawyer committed
49
#include <isc/task.h>
Michael Sawyer's avatar
Michael Sawyer committed
50
#include <isc/timer.h>
Michael Sawyer's avatar
Michael Sawyer committed
51
#include <isc/types.h>
Michael Sawyer's avatar
Michael Sawyer committed
52
#include <isc/util.h>
Michael Sawyer's avatar
Michael Sawyer committed
53

54
55
#include <isccfg/namedconf.h>

Brian Wellington's avatar
Brian Wellington committed
56
57
#include <dns/callbacks.h>
#include <dns/dispatch.h>
58
#include <dns/dnssec.h>
Brian Wellington's avatar
Brian Wellington committed
59
#include <dns/events.h>
60
#include <dns/fixedname.h>
61
#include <dns/log.h>
62
#include <dns/masterdump.h>
Brian Wellington's avatar
Brian Wellington committed
63
64
#include <dns/message.h>
#include <dns/name.h>
65
#include <dns/rcode.h>
Brian Wellington's avatar
Brian Wellington committed
66
67
68
69
70
71
72
73
#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>
74
#include <dns/tkey.h>
Brian Wellington's avatar
Brian Wellington committed
75
#include <dns/tsig.h>
76

Brian Wellington's avatar
Brian Wellington committed
77
78
#include <dst/dst.h>

79
#include <lwres/lwres.h>
80
#include <lwres/net.h>
81

82
83
#ifdef GSSAPI
#include <dst/gssapi.h>
84
85
86
#ifdef WIN32
#include <krb5/krb5.h>
#else
87
#include ISC_PLATFORM_KRB5HEADER
88
#endif
89
#endif
90
91
#include <bind9/getaddresses.h>

92
93
94
95
#if defined(HAVE_READLINE)
#include <readline/readline.h>
#include <readline/history.h>
#endif
96

97
98
99
100
101
102
103
104
#ifdef HAVE_ADDRINFO
#ifdef HAVE_GETADDRINFO
#ifdef HAVE_GAISTRERROR
#define USE_GETADDRINFO
#endif
#endif
#endif

Danny Mayer's avatar
Danny Mayer committed
105
106
#ifndef USE_GETADDRINFO
#ifndef ISC_PLATFORM_NONSTDHERRNO
107
108
extern int h_errno;
#endif
Danny Mayer's avatar
Danny Mayer committed
109
#endif
110

111
#define MAXCMD (128 * 1024)
112
#define MAXWIRE (64 * 1024)
113
114
115
#define PACKETSIZE ((64 * 1024) - 1)
#define INITTEXT (2 * 1024)
#define MAXTEXT (128 * 1024)
Michael Sawyer's avatar
Michael Sawyer committed
116
#define FIND_TIMEOUT 5
117
#define TTL_MAX 2147483647U	/* Maximum signed 32 bit integer. */
Michael Sawyer's avatar
Michael Sawyer committed
118

119
120
#define DNSDEFAULTPORT 53

121
122
123
/* Number of addresses to request from bind9_getaddresses() */
#define MAX_SERVERADDRS 4

124
125
static isc_uint16_t dnsport = DNSDEFAULTPORT;

126
#ifndef RESOLV_CONF
Michael Sawyer's avatar
Michael Sawyer committed
127
#define RESOLV_CONF "/etc/resolv.conf"
128
#endif
Michael Sawyer's avatar
Michael Sawyer committed
129

Brian Wellington's avatar
Brian Wellington committed
130
static isc_boolean_t debugging = ISC_FALSE, ddebugging = ISC_FALSE;
131
static isc_boolean_t memdebugging = ISC_FALSE;
Brian Wellington's avatar
Brian Wellington committed
132
static isc_boolean_t have_ipv4 = ISC_FALSE;
Brian Wellington's avatar
Brian Wellington committed
133
134
static isc_boolean_t have_ipv6 = ISC_FALSE;
static isc_boolean_t is_dst_up = ISC_FALSE;
Brian Wellington's avatar
Brian Wellington committed
135
static isc_boolean_t usevc = ISC_FALSE;
136
137
138
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;
139
static isc_boolean_t local_only = ISC_FALSE;
Brian Wellington's avatar
Brian Wellington committed
140
141
static isc_taskmgr_t *taskmgr = NULL;
static isc_task_t *global_task = NULL;
142
static isc_event_t *global_event = NULL;
143
static isc_log_t *lctx = NULL;
Brian Wellington's avatar
Brian Wellington committed
144
145
146
147
148
149
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
150
static dns_dispatch_t *dispatchv6 = NULL;
Brian Wellington's avatar
Brian Wellington committed
151
static dns_message_t *updatemsg = NULL;
152
153
static dns_fixedname_t fuserzone;
static dns_name_t *userzone = NULL;
154
155
156
157
static dns_name_t *zonename = NULL;
static dns_name_t tmpzonename;
static dns_name_t restart_master;
static dns_tsig_keyring_t *gssring = NULL;
158
static dns_tsigkey_t *tsigkey = NULL;
159
static dst_key_t *sig0key = NULL;
160
161
static lwres_context_t *lwctx = NULL;
static lwres_conf_t *lwconf;
162
163
static isc_sockaddr_t *servers = NULL;
static isc_boolean_t default_servers = ISC_TRUE;
Brian Wellington's avatar
Brian Wellington committed
164
static int ns_inuse = 0;
165
static int ns_total = 0;
166
static isc_sockaddr_t *localaddr = NULL;
167
168
static const char *keyfile = NULL;
static char *keystr = NULL;
169
static isc_entropy_t *entropy = NULL;
170
static isc_boolean_t shuttingdown = ISC_FALSE;
171
static FILE *input;
172
static isc_boolean_t interactive = ISC_TRUE;
173
static isc_boolean_t seenerror = ISC_FALSE;
Danny Mayer's avatar
Danny Mayer committed
174
static const dns_master_style_t *style;
175
static int requests = 0;
176
static unsigned int logdebuglevel = 0;
Michael Graff's avatar
Michael Graff committed
177
178
179
static unsigned int timeout = 300;
static unsigned int udp_timeout = 3;
static unsigned int udp_retries = 3;
180
181
static dns_rdataclass_t defaultclass = dns_rdataclass_in;
static dns_rdataclass_t zoneclass = dns_rdataclass_none;
182
static dns_message_t *answer = NULL;
183
184
static isc_uint32_t default_ttl = 0;
static isc_boolean_t default_ttl_set = ISC_FALSE;
Brian Wellington's avatar
Brian Wellington committed
185

186
187
188
189
190
typedef struct nsu_requestinfo {
	dns_message_t *msg;
	isc_sockaddr_t *addr;
} nsu_requestinfo_t;

191
static void
192
193
sendrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
	    dns_message_t *msg, dns_request_t **request);
Francis Dupont's avatar
Francis Dupont committed
194
195
196
197

ISC_PLATFORM_NORETURN_PRE static void
fatal(const char *format, ...)
ISC_FORMAT_PRINTF(1, 2) ISC_PLATFORM_NORETURN_POST;
198
199
200
201
202
203

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
204

205
206
207
#ifdef GSSAPI
static dns_fixedname_t fkname;
static isc_sockaddr_t *kserver = NULL;
208
static char *realm = NULL;
209
210
211
212
213
214
215
216
217
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
218
start_gssrequest(dns_name_t *master);
219
220
static void
send_gssrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
Automatic Updater's avatar
Automatic Updater committed
221
		dns_message_t *msg, dns_request_t **request,
222
223
224
225
226
		gss_ctx_id_t context);
static void
recvgss(isc_task_t *task, isc_event_t *event);
#endif /* GSSAPI */

227
228
229
static void
error(const char *format, ...) ISC_FORMAT_PRINTF(1, 2);

230
231
232
233
#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
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
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
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);
}


298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
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
315
316
317
318
static void
fatal(const char *format, ...) {
	va_list args;

319
	va_start(args, format);
Michael Sawyer's avatar
Michael Sawyer committed
320
321
322
	vfprintf(stderr, format, args);
	va_end(args);
	fprintf(stderr, "\n");
Brian Wellington's avatar
Brian Wellington committed
323
	exit(1);
Michael Sawyer's avatar
Michael Sawyer committed
324
325
}

326
327
328
329
330
331
332
333
334
335
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
336
337
338
339
340
static void
debug(const char *format, ...) {
	va_list args;

	if (debugging) {
341
		va_start(args, format);
Michael Sawyer's avatar
Michael Sawyer committed
342
343
344
345
346
347
		vfprintf(stderr, format, args);
		va_end(args);
		fprintf(stderr, "\n");
	}
}

348
349
350
351
352
static void
ddebug(const char *format, ...) {
	va_list args;

	if (ddebugging) {
353
		va_start(args, format);
354
355
356
357
358
359
		vfprintf(stderr, format, args);
		va_end(args);
		fprintf(stderr, "\n");
	}
}

360
static inline void
Michael Sawyer's avatar
Michael Sawyer committed
361
check_result(isc_result_t result, const char *msg) {
Brian Wellington's avatar
Brian Wellington committed
362
	if (result != ISC_R_SUCCESS)
Michael Sawyer's avatar
Michael Sawyer committed
363
364
365
		fatal("%s: %s", msg, isc_result_totext(result));
}

366
367
368
static void *
mem_alloc(void *arg, size_t size) {
	return (isc_mem_get(arg, size));
369
370
}

371
372
373
static void
mem_free(void *arg, void *mem, size_t size) {
	isc_mem_put(arg, mem, size);
374
375
376
377
378
379
380
381
382
383
384
385
}

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);

386
387
388
389
390
391
392
393
394
395
	for (; *string != '\0'; string++) {
		sc = *string;
		for (d = delim; (dc = *d) != '\0'; d++) {
			if (sc == dc)
				break;
		}
		if (dc == 0)
			break;
	}

396
397
	for (s = string; *s != '\0'; s++) {
		sc = *s;
398
		for (d = delim; (dc = *d) != '\0'; d++) {
399
400
401
402
403
			if (sc == dc) {
				*s++ = '\0';
				*stringp = s;
				return (string);
			}
404
		}
405
406
407
408
409
	}
	*stringp = NULL;
	return (string);
}

Michael Sawyer's avatar
Michael Sawyer committed
410
static void
Brian Wellington's avatar
Brian Wellington committed
411
reset_system(void) {
Michael Sawyer's avatar
Michael Sawyer committed
412
413
	isc_result_t result;

414
	ddebug("reset_system()");
Michael Sawyer's avatar
Michael Sawyer committed
415
416
	/* If the update message is still around, destroy it */
	if (updatemsg != NULL)
Brian Wellington's avatar
Brian Wellington committed
417
418
419
420
		dns_message_reset(updatemsg, DNS_MESSAGE_INTENTRENDER);
	else {
		result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER,
					    &updatemsg);
421
		check_result(result, "dns_message_create");
Brian Wellington's avatar
Brian Wellington committed
422
	}
Michael Sawyer's avatar
Michael Sawyer committed
423
	updatemsg->opcode = dns_opcode_update;
424
425
426
427
	if (usegsstsig) {
		if (tsigkey != NULL)
			dns_tsigkey_detach(&tsigkey);
		if (gssring != NULL)
428
			dns_tsigkeyring_detach(&gssring);
429
430
		tried_other_gsstsig = ISC_FALSE;
	}
Michael Sawyer's avatar
Michael Sawyer committed
431
432
}

433
434
435
436
437
438
439
440
441
442
443
444
445
446
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
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
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
	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);
}

501
502
static int
basenamelen(const char *file) {
Automatic Updater's avatar
Automatic Updater committed
503
504
505
506
507
508
509
510
	int len = strlen(file);

	if (len > 1 && file[len - 1] == '.')
		len -= 1;
	else if (len > 8 && strcmp(file + len - 8, ".private") == 0)
		len -= 8;
	else if (len > 4 && strcmp(file + len - 4, ".key") == 0)
		len -= 4;
511
512
513
	return (len);
}

514
static void
515
setup_keystr(void) {
516
517
518
519
	unsigned char *secret = NULL;
	int secretlen;
	isc_buffer_t secretbuf;
	isc_result_t result;
520
521
	isc_buffer_t keynamesrc;
	char *secretstr;
522
	char *s, *n;
523
524
	dns_fixedname_t fkeyname;
	dns_name_t *keyname;
525
526
527
	char *name;
	dns_name_t *hmacname = NULL;
	isc_uint16_t digestbits = 0;
528

529
530
531
	dns_fixedname_init(&fkeyname);
	keyname = dns_fixedname_name(&fkeyname);

532
	debug("Creating key...");
533

534
	s = strchr(keystr, ':');
535
536
	if (s == NULL || s == keystr || s[1] == 0)
		fatal("key option must specify [hmac:]keyname:secret");
537
	secretstr = s + 1;
538
539
540
541
542
543
544
545
546
547
548
549
	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;
	}
550

551
552
	isc_buffer_init(&keynamesrc, name, (unsigned int)(n - name));
	isc_buffer_add(&keynamesrc, (unsigned int)(n - name));
553

554
	debug("namefromtext");
555
	result = dns_name_fromtext(keyname, &keynamesrc, dns_rootname, 0, NULL);
556
	check_result(result, "dns_name_fromtext");
557

558
559
560
561
	secretlen = strlen(secretstr) * 3 / 4;
	secret = isc_mem_allocate(mctx, secretlen);
	if (secret == NULL)
		fatal("out of memory");
562

563
564
565
566
567
568
	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;
569
	}
570

571
572
	secretlen = isc_buffer_usedlength(&secretbuf);

573
	debug("keycreate");
574
	result = dns_tsigkey_create(keyname, hmacname, secret, secretlen,
575
576
				    ISC_FALSE, NULL, 0, 0, mctx, NULL,
				    &tsigkey);
577
	if (result != ISC_R_SUCCESS)
578
		fprintf(stderr, "could not create key from %s: %s\n",
579
			keystr, dns_result_totext(result));
580
581
	else
		dst_key_setbits(tsigkey->key, digestbits);
582
583
584
585
586
 failure:
	if (secret != NULL)
		isc_mem_free(mctx, secret);
}

587
588
589
590
/*
 * Get a key from a named.conf format keyfile
 */
static isc_result_t
591
read_sessionkey(isc_mem_t *mctx, isc_log_t *lctx) {
592
	cfg_parser_t *pctx = NULL;
593
	cfg_obj_t *sessionkey = NULL;
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
	const cfg_obj_t *key = NULL;
	const cfg_obj_t *secretobj = NULL;
	const cfg_obj_t *algorithmobj = NULL;
	const char *keyname;
	const char *secretstr;
	const char *algorithm;
	isc_result_t result;
	int len;

	if (! isc_file_exists(keyfile))
		return (ISC_R_FILENOTFOUND);

	result = cfg_parser_create(mctx, lctx, &pctx);
	if (result != ISC_R_SUCCESS)
		goto cleanup;

610
	result = cfg_parse_file(pctx, keyfile, &cfg_type_sessionkey,
Automatic Updater's avatar
Automatic Updater committed
611
				&sessionkey);
612
613
614
	if (result != ISC_R_SUCCESS)
		goto cleanup;

615
	result = cfg_map_get(sessionkey, "key", &key);
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
	if (result != ISC_R_SUCCESS)
		goto cleanup;

	(void) cfg_map_get(key, "secret", &secretobj);
	(void) cfg_map_get(key, "algorithm", &algorithmobj);
	if (secretobj == NULL || algorithmobj == NULL)
		fatal("key must have algorithm and secret");

	keyname = cfg_obj_asstring(cfg_map_getname(key));
	secretstr = cfg_obj_asstring(secretobj);
	algorithm = cfg_obj_asstring(algorithmobj);

	len = strlen(algorithm) + strlen(keyname) + strlen(secretstr) + 3;
	keystr = isc_mem_allocate(mctx, len);
	snprintf(keystr, len, "%s:%s:%s", algorithm, keyname, secretstr);
	setup_keystr();

 cleanup:
	if (pctx != NULL) {
635
636
		if (sessionkey != NULL)
			cfg_obj_destroy(pctx, &sessionkey);
637
638
639
640
641
642
643
644
645
		cfg_parser_destroy(&pctx);
	}

	if (keystr != NULL)
		isc_mem_free(mctx, keystr);

	return (result);
}

646
static void
647
setup_keyfile(isc_mem_t *mctx, isc_log_t *lctx) {
648
649
	dst_key_t *dstkey = NULL;
	isc_result_t result;
650
	dns_name_t *hmacname = NULL;
651
652
653

	debug("Creating key...");

654
655
656
	if (sig0key != NULL)
		dst_key_free(&sig0key);

657
	/* Try reading the key from a K* pair */
658
	result = dst_key_fromnamedfile(keyfile, NULL,
659
				       DST_TYPE_PRIVATE | DST_TYPE_KEY, mctx,
660
				       &dstkey);
661

662
	/* If that didn't work, try reading it as a session.key keyfile */
663
	if (result != ISC_R_SUCCESS) {
664
		result = read_sessionkey(mctx, lctx);
665
666
667
668
		if (result == ISC_R_SUCCESS)
			return;
	}

669
	if (result != ISC_R_SUCCESS) {
670
671
672
		fprintf(stderr, "could not read key from %.*s.{private,key}: "
				"%s\n", basenamelen(keyfile), keyfile,
				isc_result_totext(result));
673
674
		return;
	}
675

676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
	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) {
697
		result = dns_tsigkey_createfromkey(dst_key_name(dstkey),
698
						   hmacname, dstkey, ISC_FALSE,
699
700
						   NULL, 0, 0, mctx, NULL,
						   &tsigkey);
701
		dst_key_free(&dstkey);
702
703
704
705
706
		if (result != ISC_R_SUCCESS) {
			fprintf(stderr, "could not create key from %s: %s\n",
				keyfile, isc_result_totext(result));
			return;
		}
707
	} else {
708
		dst_key_attach(dstkey, &sig0key);
709
710
		dst_key_free(&dstkey);
	}
711
712
}

713
static void
714
doshutdown(void) {
715
	isc_task_detach(&global_task);
716

717
718
	if (servers != NULL)
		isc_mem_put(mctx, servers, ns_total * sizeof(isc_sockaddr_t));
719
720
721
722

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

723
724
725
726
727
728
729
730
	if (tsigkey != NULL) {
		ddebug("Freeing TSIG key");
		dns_tsigkey_detach(&tsigkey);
	}

	if (sig0key != NULL) {
		ddebug("Freeing SIG(0) key");
		dst_key_free(&sig0key);
731
732
733
734
735
736
	}

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

	if (is_dst_up) {
737
		ddebug("Destroy DST lib");
738
739
740
741
		dst_lib_destroy();
		is_dst_up = ISC_FALSE;
	}

742
	cleanup_entropy(&entropy);
743
744
745
746

	lwres_conf_clear(lwctx);
	lwres_context_destroy(&lwctx);

747
	ddebug("Destroying request manager");
748
749
750
751
752
753
754
755
756
757
758
	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);

759
760
}

761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
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
784
static void
Brian Wellington's avatar
Brian Wellington committed
785
setup_system(void) {
Michael Sawyer's avatar
Michael Sawyer committed
786
	isc_result_t result;
Brian Wellington's avatar
Brian Wellington committed
787
	isc_sockaddr_t bind_any, bind_any6;
788
	lwres_result_t lwresult;
Brian Wellington's avatar
Brian Wellington committed
789
	unsigned int attrs, attrmask;
790
	int i;
791
	isc_logconfig_t *logconfig = NULL;
Michael Sawyer's avatar
Michael Sawyer committed
792

793
	ddebug("setup_system()");
Michael Sawyer's avatar
Michael Sawyer committed
794

795
796
	dns_result_register();

Michael Sawyer's avatar
Michael Sawyer committed
797
	result = isc_net_probeipv4();
Brian Wellington's avatar
Brian Wellington committed
798
799
	if (result == ISC_R_SUCCESS)
		have_ipv4 = ISC_TRUE;
Michael Sawyer's avatar
Michael Sawyer committed
800
801
802

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

Brian Wellington's avatar
Brian Wellington committed
805
	if (!have_ipv4 && !have_ipv6)
806
		fatal("could not find either IPv4 or IPv6");
Brian Wellington's avatar
Brian Wellington committed
807

808
809
810
811
812
813
814
815
816
817
818
819
	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);

820
821
822
823
	lwresult = lwres_context_create(&lwctx, mctx, mem_alloc, mem_free, 1);
	if (lwresult != LWRES_R_SUCCESS)
		fatal("lwres_context_create failed");

824
	(void)lwres_conf_parse(lwctx, RESOLV_CONF);
825
	lwconf = lwres_conf_get(lwctx);
Brian Wellington's avatar
Brian Wellington committed
826

827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
	ns_inuse = 0;
	if (local_only || lwconf->nsnext <= 0) {
		struct in_addr in;
		struct in6_addr in6;

		if (local_only && keyfile == NULL)
			keyfile = SESSION_KEYFILE;

		default_servers = ISC_FALSE;

		if (servers != NULL)
			isc_mem_put(mctx, servers,
				    ns_total * sizeof(isc_sockaddr_t));

		ns_total = (have_ipv4 ? 1 : 0) + (have_ipv6 ? 1 : 0);
842
843
844
		servers = isc_mem_get(mctx, ns_total * sizeof(isc_sockaddr_t));
		if (servers == NULL)
			fatal("out of memory");
845
846
847
848
849
850
851
852
853
854
855

		if (have_ipv4) {
			in.s_addr = htonl(INADDR_LOOPBACK);
			isc_sockaddr_fromin(&servers[0], &in, dnsport);
		}
		if (have_ipv6) {
			memset(&in6, 0, sizeof(in6));
			in6.s6_addr[15] = 1;
			isc_sockaddr_fromin6(&servers[(have_ipv4 ? 1 : 0)],
					     &in6, dnsport);
		}
856
	} else {
857
		ns_total = lwconf->nsnext;
858
859
860
861
		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++) {
862
863
			if (lwconf->nameservers[i].family == LWRES_ADDRTYPE_V4)
			{
864
				struct in_addr in4;
865
866
				memmove(&in4,
					lwconf->nameservers[i].address, 4);
867
868
				isc_sockaddr_fromin(&servers[i],
						    &in4, dnsport);
869
870
			} else {
				struct in6_addr in6;
871
872
				memmove(&in6,
					lwconf->nameservers[i].address, 16);
873
874
				isc_sockaddr_fromin6(&servers[i],
						     &in6, dnsport);
875
			}
876
877
878
		}
	}

879
	setup_entropy(mctx, NULL, &entropy);
880

881
	result = isc_hash_create(mctx, entropy, DNS_NAME_MAXWIRE);
882
883
884
	check_result(result, "isc_hash_create");
	isc_hash_init();

885
	result = dns_dispatchmgr_create(mctx, entropy, &dispatchmgr);
Michael Sawyer's avatar
Michael Sawyer committed
886
887
888
889
890
891
892
893
	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");

894
	result = isc_taskmgr_create(mctx, 1, 0, &taskmgr);
Michael Sawyer's avatar
Michael Sawyer committed
895
896
	check_result(result, "isc_taskmgr_create");

897
	result = isc_task_create(taskmgr, 0, &global_task);
Michael Sawyer's avatar
Michael Sawyer committed
898
899
	check_result(result, "isc_task_create");

900
901
902
	result = isc_task_onshutdown(global_task, shutdown_program, NULL);
	check_result(result, "isc_task_onshutdown");

903
	result = dst_lib_init(mctx, entropy, 0);
Michael Sawyer's avatar
Michael Sawyer committed
904
905
906
	check_result(result, "dst_lib_init");
	is_dst_up = ISC_TRUE;

Brian Wellington's avatar
Brian Wellington committed
907
908
909
910
911
912
913
914
915
916
917
918
919
920
	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
921

Brian Wellington's avatar
Brian Wellington committed
922
923
924
925
926
927
928
929
930
931
932
	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)");
	}
933

Michael Sawyer's avatar
Michael Sawyer committed
934
935
	result = dns_requestmgr_create(mctx, timermgr,
				       socketmgr, taskmgr, dispatchmgr,
Brian Wellington's avatar
Brian Wellington committed
936
				       dispatchv4, dispatchv6, &requestmgr);
Michael Sawyer's avatar
Michael Sawyer committed
937
938
	check_result(result, "dns_requestmgr_create");

939
940
	if (keystr != NULL)
		setup_keystr();
941
942
943
944
945
946
	else if (local_only) {
		result = read_sessionkey(mctx, lctx);
		if (result != ISC_R_SUCCESS)
			fatal("can't read key from %s: %s\n",
			      keyfile, isc_result_totext(result));
	} else if (keyfile != NULL)
947
		setup_keyfile(mctx, lctx);
Michael Sawyer's avatar
Michael Sawyer committed
948
}
Michael Sawyer's avatar
Michael Sawyer committed
949

950
static void
951
952
953
get_addresses(char *host, in_port_t port,
	      isc_sockaddr_t *sockaddr, int naddrs)
{
954
955
	int count;
	isc_result_t result;
956

957
	isc_app_block();
958
	result = bind9_getaddresses(host, port, sockaddr, naddrs, &count);
959
960
961
962
	isc_app_unblock();
	if (result != ISC_R_SUCCESS)
		fatal("couldn't get address for '%s': %s",
		      host, isc_result_totext(result));
963
964
}

965
#define PARSE_ARGS_FMT "dDML:y:ghlovk:p:Pr:R::t:Tu:V"
966
967
968

static void
pre_parse_args(int argc, char **argv) {
969
	dns_rdatatype_t t;
970
	int ch;
971
972
	char buf[100];
	isc_boolean_t doexit = ISC_FALSE;
973
974
975
976
977
978
979
980
981
982
983
984

	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 '?':
985
		case 'h':
986
987
988
			if (isc_commandline_option != '?')
				fprintf(stderr, "%s: invalid argument -%c\n",
					argv[0], isc_commandline_option);
989
			fprintf(stderr, "usage: nsupdate [-dD] [-L level] [-l]"
990
991
992
993
				"[-g | -o | -y keyname:secret | -k keyfile] "
				"[-v] [filename]\n");
			exit(1);

994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
		case 'P':
			for (t = 0xff00; t <= 0xfffe; t++) {
				if (dns_rdatatype_ismeta(t))
					continue;
				dns_rdatatype_format(t, buf, sizeof(buf));
				if (strncmp(buf, "TYPE", 4) != 0)
					fprintf(stdout, "%s\n", buf);
			}
			doexit = ISC_TRUE;
			break;

		case 'T':
			for (t = 1; t <= 0xfeff; t++) {
				if (dns_rdatatype_ismeta(t))
					continue;
				dns_rdatatype_format(t, buf, sizeof(buf));
				if (strncmp(buf, "TYPE", 4) != 0)
					fprintf(stdout, "%s\n", buf);
			}
			doexit = ISC_TRUE;
			break;

1016
1017
1018
1019
		default:
			break;
		}
	}
1020
	if (doexit)
Tinderbox User's avatar
Tinderbox User committed
1021
		exit(0);
1022
1023
1024
1025
	isc_commandline_reset = ISC_TRUE;
	isc_commandline_index = 1;
}

1026
1027
1028
1029
1030
static void
version(void) {
	fputs("nsupdate " VERSION "\n", stderr);
}

Michael Sawyer's avatar
Michael Sawyer committed
1031
static void
1032
parse_args(int argc, char **argv, isc_mem_t *mctx, isc_entropy_t **ectx) {
Brian Wellington's avatar
Brian Wellington committed
1033
	int ch;
1034
	isc_uint32_t i;
1035
	isc_result_t result;
Michael Sawyer's avatar
Michael Sawyer committed
1036

Michael Sawyer's avatar
Michael Sawyer committed
1037
	debug("parse_args");
1038
	while ((ch = isc_commandline_parse(argc, argv, PARSE_ARGS_FMT)) != -1) {
Brian Wellington's avatar
Brian Wellington committed
1039
1040
1041
1042
1043
		switch (ch) {
		case 'd':
			debugging = ISC_TRUE;
			break;
		case 'D': /* was -dd */
Michael Sawyer's avatar
Michael Sawyer committed
1044
1045
			debugging = ISC_TRUE;
			ddebugging = ISC_TRUE;
Brian Wellington's avatar
Brian Wellington committed
1046
			break;
1047
		case 'M':
Brian Wellington's avatar
Brian Wellington committed
1048
			break;
1049
		case 'l':
1050
1051
1052
			local_only = ISC_TRUE;
			break;
		case 'L':
1053
1054
1055
1056
1057
1058
1059
1060
1061
			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
1062
1063
1064
1065
		case 'y':
			keystr = isc_commandline_argument;
			break;
		case 'v':
Brian Wellington's avatar
Brian Wellington committed
1066
			usevc = ISC_TRUE;
Brian Wellington's avatar
Brian Wellington committed
1067
			break;
1068
1069
1070
1071
		case 'V':
			version();
			exit(0);
			break;
Brian Wellington's avatar
Brian Wellington committed
1072
		case 'k':
1073
			keyfile = isc_commandline_argument;
Brian Wellington's avatar
Brian Wellington committed
1074
			break;
1075
1076
1077
1078
1079
1080
1081
1082
		case 'g':
			usegsstsig = ISC_TRUE;
			use_win2k_gsstsig = ISC_FALSE;
			break;
		case 'o':
			usegsstsig = ISC_TRUE;
			use_win2k_gsstsig = ISC_TRUE;
			break;
1083
1084
1085
1086
1087
1088
1089
1090
1091
		case 'p':
			result = isc_parse_uint16(&dnsport,
						  isc_commandline_argument, 10);
			if (result != ISC_R_SUCCESS) {
				fprintf(stderr, "bad port number "
					"'%s'\n", isc_commandline_argument);
				exit(1);
			}
			break;
Michael Graff's avatar
Michael Graff committed
1092
1093
1094
1095
1096
1097
1098
1099
		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
1100
				timeout = UINT_MAX;
Michael Graff's avatar
Michael Graff committed
1101
1102
1103
1104
1105
1106
1107
1108
1109
			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
1110
				udp_timeout = UINT_MAX;
Michael Graff's avatar
Michael Graff committed
1111
1112
1113
1114
1115
1116
1117
1118
1119
			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;
1120
1121
1122
1123

		case 'R':
			setup_entropy(mctx, isc_commandline_argument, ectx);
			break;
1124
1125
1126
1127
1128

		default:
			fprintf(stderr, "%s: unhandled option: %c\n",
				argv[0], isc_commandline_option);
			exit(1);
Brian Wellington's avatar
Brian Wellington committed
1129
		}
Michael Sawyer's avatar
Michael Sawyer committed
1130
	}
1131
	if (keyfile != NULL && keystr != NULL) {
1132
1133
		fprintf(stderr, "%s: cannot specify both -k and -y\n",
			argv[0]);
1134
1135
		exit(1);
	}
1136

1137
1138
1139
1140
1141
1142
1143
1144
#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) {
1145
		fprintf(stderr, "%s: cannot specify -g	or -o, " \