nsupdate.c 54.4 KB
Newer Older
Michael Sawyer's avatar
Michael Sawyer committed
1
/*
Mark Andrews's avatar
Mark Andrews committed
2
 * Copyright (C) 2004-2006  Internet Systems Consortium, Inc. ("ISC")
Mark Andrews's avatar
Mark Andrews committed
3
 * Copyright (C) 2000-2003  Internet Software Consortium.
4
 *
Michael Sawyer's avatar
Michael Sawyer committed
5
6
7
 * Permission to use, copy, modify, and distribute this software for any
 * 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.144 2006/06/09 07:26:42 marka 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>
Michael Sawyer's avatar
Michael Sawyer committed
38
#include <isc/mem.h>
39
#include <isc/parseint.h>
Michael Sawyer's avatar
Michael Sawyer committed
40
#include <isc/region.h>
Michael Sawyer's avatar
Michael Sawyer committed
41
42
#include <isc/sockaddr.h>
#include <isc/socket.h>
43
#include <isc/stdio.h>
Michael Sawyer's avatar
Michael Sawyer committed
44
#include <isc/string.h>
Michael Sawyer's avatar
Michael Sawyer committed
45
#include <isc/task.h>
Michael Sawyer's avatar
Michael Sawyer committed
46
#include <isc/timer.h>
Michael Sawyer's avatar
Michael Sawyer committed
47
#include <isc/types.h>
Michael Sawyer's avatar
Michael Sawyer committed
48
#include <isc/util.h>
Michael Sawyer's avatar
Michael Sawyer committed
49

Brian Wellington's avatar
Brian Wellington committed
50
51
#include <dns/callbacks.h>
#include <dns/dispatch.h>
52
#include <dns/dnssec.h>
Brian Wellington's avatar
Brian Wellington committed
53
#include <dns/events.h>
54
#include <dns/fixedname.h>
55
#include <dns/masterdump.h>
Brian Wellington's avatar
Brian Wellington committed
56
57
#include <dns/message.h>
#include <dns/name.h>
58
#include <dns/rcode.h>
Brian Wellington's avatar
Brian Wellington committed
59
60
61
62
63
64
65
66
67
#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>
#include <dns/tsig.h>
68

Brian Wellington's avatar
Brian Wellington committed
69
70
#include <dst/dst.h>

71
#include <lwres/lwres.h>
72
#include <lwres/net.h>
73

74
75
#include <bind9/getaddresses.h>

76
77
78
79
80
81
82
83
#ifdef HAVE_ADDRINFO
#ifdef HAVE_GETADDRINFO
#ifdef HAVE_GAISTRERROR
#define USE_GETADDRINFO
#endif
#endif
#endif

Danny Mayer's avatar
Danny Mayer committed
84
85
#ifndef USE_GETADDRINFO
#ifndef ISC_PLATFORM_NONSTDHERRNO
86
87
extern int h_errno;
#endif
Danny Mayer's avatar
Danny Mayer committed
88
#endif
89

90
#define MAXCMD (4 * 1024)
91
#define MAXWIRE (64 * 1024)
92
93
94
#define PACKETSIZE ((64 * 1024) - 1)
#define INITTEXT (2 * 1024)
#define MAXTEXT (128 * 1024)
Michael Sawyer's avatar
Michael Sawyer committed
95
#define FIND_TIMEOUT 5
96
#define TTL_MAX 2147483647U	/* Maximum signed 32 bit integer. */
Michael Sawyer's avatar
Michael Sawyer committed
97

98
99
#define DNSDEFAULTPORT 53

100
#ifndef RESOLV_CONF
Michael Sawyer's avatar
Michael Sawyer committed
101
#define RESOLV_CONF "/etc/resolv.conf"
102
#endif
Michael Sawyer's avatar
Michael Sawyer committed
103

Brian Wellington's avatar
Brian Wellington committed
104
static isc_boolean_t debugging = ISC_FALSE, ddebugging = ISC_FALSE;
105
static isc_boolean_t memdebugging = ISC_FALSE;
Brian Wellington's avatar
Brian Wellington committed
106
static isc_boolean_t have_ipv4 = ISC_FALSE;
Brian Wellington's avatar
Brian Wellington committed
107
108
static isc_boolean_t have_ipv6 = ISC_FALSE;
static isc_boolean_t is_dst_up = ISC_FALSE;
Brian Wellington's avatar
Brian Wellington committed
109
static isc_boolean_t usevc = ISC_FALSE;
Brian Wellington's avatar
Brian Wellington committed
110
111
static isc_taskmgr_t *taskmgr = NULL;
static isc_task_t *global_task = NULL;
112
static isc_event_t *global_event = NULL;
Brian Wellington's avatar
Brian Wellington committed
113
114
115
116
117
118
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
119
static dns_dispatch_t *dispatchv6 = NULL;
Brian Wellington's avatar
Brian Wellington committed
120
static dns_message_t *updatemsg = NULL;
121
122
static dns_fixedname_t fuserzone;
static dns_name_t *userzone = NULL;
123
124
static dns_tsigkey_t *tsigkey = NULL;
static dst_key_t *sig0key;
125
126
static lwres_context_t *lwctx = NULL;
static lwres_conf_t *lwconf;
127
static isc_sockaddr_t *servers;
Brian Wellington's avatar
Brian Wellington committed
128
static int ns_inuse = 0;
129
130
static int ns_total = 0;
static isc_sockaddr_t *userserver = NULL;
131
static isc_sockaddr_t *localaddr = NULL;
132
static char *keystr = NULL, *keyfile = NULL;
Brian Wellington's avatar
Brian Wellington committed
133
static isc_entropy_t *entp = NULL;
134
static isc_boolean_t shuttingdown = ISC_FALSE;
135
static FILE *input;
136
static isc_boolean_t interactive = ISC_TRUE;
137
static isc_boolean_t seenerror = ISC_FALSE;
Danny Mayer's avatar
Danny Mayer committed
138
static const dns_master_style_t *style;
139
static int requests = 0;
Michael Graff's avatar
Michael Graff committed
140
141
142
static unsigned int timeout = 300;
static unsigned int udp_timeout = 3;
static unsigned int udp_retries = 3;
143
144
static dns_rdataclass_t defaultclass = dns_rdataclass_in;
static dns_rdataclass_t zoneclass = dns_rdataclass_none;
145
static dns_message_t *answer = NULL;
Brian Wellington's avatar
Brian Wellington committed
146

147
148
149
150
151
typedef struct nsu_requestinfo {
	dns_message_t *msg;
	isc_sockaddr_t *addr;
} nsu_requestinfo_t;

152
static void
153
154
sendrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
	    dns_message_t *msg, dns_request_t **request);
155
156
157
158
159
160
161
162
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
163

164
165
166
167
#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
168

169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
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
186
187
188
189
static void
fatal(const char *format, ...) {
	va_list args;

190
	va_start(args, format);
Michael Sawyer's avatar
Michael Sawyer committed
191
192
193
	vfprintf(stderr, format, args);
	va_end(args);
	fprintf(stderr, "\n");
Brian Wellington's avatar
Brian Wellington committed
194
	exit(1);
Michael Sawyer's avatar
Michael Sawyer committed
195
196
197
198
199
200
201
}

static void
debug(const char *format, ...) {
	va_list args;

	if (debugging) {
202
		va_start(args, format);
Michael Sawyer's avatar
Michael Sawyer committed
203
204
205
206
207
208
		vfprintf(stderr, format, args);
		va_end(args);
		fprintf(stderr, "\n");
	}
}

209
210
211
212
213
static void
ddebug(const char *format, ...) {
	va_list args;

	if (ddebugging) {
214
		va_start(args, format);
215
216
217
218
219
220
		vfprintf(stderr, format, args);
		va_end(args);
		fprintf(stderr, "\n");
	}
}

221
static inline void
Michael Sawyer's avatar
Michael Sawyer committed
222
check_result(isc_result_t result, const char *msg) {
Brian Wellington's avatar
Brian Wellington committed
223
	if (result != ISC_R_SUCCESS)
Michael Sawyer's avatar
Michael Sawyer committed
224
225
226
		fatal("%s: %s", msg, isc_result_totext(result));
}

227
228
229
static void *
mem_alloc(void *arg, size_t size) {
	return (isc_mem_get(arg, size));
230
231
}

232
233
234
static void
mem_free(void *arg, void *mem, size_t size) {
	isc_mem_put(arg, mem, size);
235
236
237
238
239
240
241
242
243
244
245
246
}

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

247
248
249
250
251
252
253
254
255
256
	for (; *string != '\0'; string++) {
		sc = *string;
		for (d = delim; (dc = *d) != '\0'; d++) {
			if (sc == dc)
				break;
		}
		if (dc == 0)
			break;
	}

257
258
	for (s = string; *s != '\0'; s++) {
		sc = *s;
259
		for (d = delim; (dc = *d) != '\0'; d++) {
260
261
262
263
264
			if (sc == dc) {
				*s++ = '\0';
				*stringp = s;
				return (string);
			}
265
		}
266
267
268
269
270
	}
	*stringp = NULL;
	return (string);
}

Michael Sawyer's avatar
Michael Sawyer committed
271
static void
Brian Wellington's avatar
Brian Wellington committed
272
reset_system(void) {
Michael Sawyer's avatar
Michael Sawyer committed
273
274
	isc_result_t result;

275
	ddebug("reset_system()");
Michael Sawyer's avatar
Michael Sawyer committed
276
277
	/* If the update message is still around, destroy it */
	if (updatemsg != NULL)
Brian Wellington's avatar
Brian Wellington committed
278
279
280
281
		dns_message_reset(updatemsg, DNS_MESSAGE_INTENTRENDER);
	else {
		result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER,
					    &updatemsg);
282
		check_result(result, "dns_message_create");
Brian Wellington's avatar
Brian Wellington committed
283
	}
Michael Sawyer's avatar
Michael Sawyer committed
284
285
286
	updatemsg->opcode = dns_opcode_update;
}

287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
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;
	
	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);
}

355
static void
356
setup_keystr(void) {
357
358
359
360
	unsigned char *secret = NULL;
	int secretlen;
	isc_buffer_t secretbuf;
	isc_result_t result;
361
362
	isc_buffer_t keynamesrc;
	char *secretstr;
363
	char *s, *n;
364
365
	dns_fixedname_t fkeyname;
	dns_name_t *keyname;
366
367
368
	char *name;
	dns_name_t *hmacname = NULL;
	isc_uint16_t digestbits = 0;
369

370
371
372
	dns_fixedname_init(&fkeyname);
	keyname = dns_fixedname_name(&fkeyname);

373
	debug("Creating key...");
374

375
	s = strchr(keystr, ':');
376
377
	if (s == NULL || s == keystr || s[1] == 0)
		fatal("key option must specify [hmac:]keyname:secret");
378
	secretstr = s + 1;
379
380
381
382
383
384
385
386
387
388
389
390
	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;
	}
391

392
393
	isc_buffer_init(&keynamesrc, name, n - name);
	isc_buffer_add(&keynamesrc, n - name);
394

395
396
397
398
	debug("namefromtext");
	result = dns_name_fromtext(keyname, &keynamesrc, dns_rootname,
				   ISC_FALSE, NULL);
	check_result(result, "dns_name_fromtext");
399

400
401
402
403
	secretlen = strlen(secretstr) * 3 / 4;
	secret = isc_mem_allocate(mctx, secretlen);
	if (secret == NULL)
		fatal("out of memory");
404

405
406
407
408
409
410
	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;
411
	}
412

413
414
	secretlen = isc_buffer_usedlength(&secretbuf);

415
	debug("keycreate");
416
417
	result = dns_tsigkey_create(keyname, hmacname, secret, secretlen,
				    ISC_TRUE, NULL, 0, 0, mctx, NULL, &tsigkey);
418
	if (result != ISC_R_SUCCESS)
419
		fprintf(stderr, "could not create key from %s: %s\n",
420
			keystr, dns_result_totext(result));
421
422
	else
		dst_key_setbits(tsigkey->key, digestbits);
423
424
425
426
427
 failure:
	if (secret != NULL)
		isc_mem_free(mctx, secret);
}

428
429
430
431
static void
setup_keyfile(void) {
	dst_key_t *dstkey = NULL;
	isc_result_t result;
432
	dns_name_t *hmacname = NULL;
433
434
435

	debug("Creating key...");

436
437
	result = dst_key_fromnamedfile(keyfile,
				       DST_TYPE_PRIVATE | DST_TYPE_KEY, mctx,
438
439
440
441
442
443
				       &dstkey);
	if (result != ISC_R_SUCCESS) {
		fprintf(stderr, "could not read key from %s: %s\n",
			keyfile, isc_result_totext(result));
		return;
	}
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
	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) {
465
		result = dns_tsigkey_createfromkey(dst_key_name(dstkey),
466
467
468
						   hmacname, dstkey, ISC_FALSE,
						   NULL, 0, 0, mctx, NULL,
						   &tsigkey);
469
470
471
472
473
474
475
476
		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;
477
478
}

479
static void
480
doshutdown(void) {
481
	isc_task_detach(&global_task);
482
483
484
485
486
487
488

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

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

489
490
491
492
493
494
495
496
	if (tsigkey != NULL) {
		ddebug("Freeing TSIG key");
		dns_tsigkey_detach(&tsigkey);
	}

	if (sig0key != NULL) {
		ddebug("Freeing SIG(0) key");
		dst_key_free(&sig0key);
497
498
499
500
501
502
	}

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

	if (is_dst_up) {
503
		ddebug("Destroy DST lib");
504
505
506
507
508
		dst_lib_destroy();
		is_dst_up = ISC_FALSE;
	}

	if (entp != NULL) {
509
		ddebug("Detach from entropy");
510
511
512
513
514
515
516
517
		isc_entropy_detach(&entp);
	}

	lwres_conf_clear(lwctx);
	lwres_context_destroy(&lwctx);

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

518
	ddebug("Destroying request manager");
519
520
521
522
523
524
525
526
527
528
529
	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);

530
531
}

532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
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
555
static void
Brian Wellington's avatar
Brian Wellington committed
556
setup_system(void) {
Michael Sawyer's avatar
Michael Sawyer committed
557
	isc_result_t result;
Brian Wellington's avatar
Brian Wellington committed
558
	isc_sockaddr_t bind_any, bind_any6;
559
	lwres_result_t lwresult;
Brian Wellington's avatar
Brian Wellington committed
560
	unsigned int attrs, attrmask;
561
	int i;
Michael Sawyer's avatar
Michael Sawyer committed
562

563
	ddebug("setup_system()");
Michael Sawyer's avatar
Michael Sawyer committed
564

565
566
	dns_result_register();

Michael Sawyer's avatar
Michael Sawyer committed
567
	result = isc_net_probeipv4();
Brian Wellington's avatar
Brian Wellington committed
568
569
	if (result == ISC_R_SUCCESS)
		have_ipv4 = ISC_TRUE;
Michael Sawyer's avatar
Michael Sawyer committed
570
571
572

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

Brian Wellington's avatar
Brian Wellington committed
575
	if (!have_ipv4 && !have_ipv6)
576
		fatal("could not find either IPv4 or IPv6");
Brian Wellington's avatar
Brian Wellington committed
577

Michael Sawyer's avatar
Michael Sawyer committed
578
579
580
	result = isc_mem_create(0, 0, &mctx);
	check_result(result, "isc_mem_create");

581
582
583
584
	lwresult = lwres_context_create(&lwctx, mctx, mem_alloc, mem_free, 1);
	if (lwresult != LWRES_R_SUCCESS)
		fatal("lwres_context_create failed");

585
	(void)lwres_conf_parse(lwctx, RESOLV_CONF);
586
	lwconf = lwres_conf_get(lwctx);
Brian Wellington's avatar
Brian Wellington committed
587

588
	ns_total = lwconf->nsnext;
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
	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);
			}
613
614
615
		}
	}

616
617
618
	result = isc_entropy_create(mctx, &entp);
	check_result(result, "isc_entropy_create");

619
620
621
622
	result = isc_hash_create(mctx, entp, DNS_NAME_MAXWIRE);
	check_result(result, "isc_hash_create");
	isc_hash_init();

623
	result = dns_dispatchmgr_create(mctx, entp, &dispatchmgr);
Michael Sawyer's avatar
Michael Sawyer committed
624
625
626
627
628
629
630
631
	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");

632
	result = isc_taskmgr_create(mctx, 1, 0, &taskmgr);
Michael Sawyer's avatar
Michael Sawyer committed
633
634
	check_result(result, "isc_taskmgr_create");

635
	result = isc_task_create(taskmgr, 0, &global_task);
Michael Sawyer's avatar
Michael Sawyer committed
636
637
	check_result(result, "isc_task_create");

638
639
640
	result = isc_task_onshutdown(global_task, shutdown_program, NULL);
	check_result(result, "isc_task_onshutdown");

641
	result = dst_lib_init(mctx, entp, 0);
Michael Sawyer's avatar
Michael Sawyer committed
642
643
644
	check_result(result, "dst_lib_init");
	is_dst_up = ISC_TRUE;

Brian Wellington's avatar
Brian Wellington committed
645
646
647
648
649
650
651
652
653
654
655
656
657
658
	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
659

Brian Wellington's avatar
Brian Wellington committed
660
661
662
663
664
665
666
667
668
669
670
	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)");
	}
671

Michael Sawyer's avatar
Michael Sawyer committed
672
673
	result = dns_requestmgr_create(mctx, timermgr,
				       socketmgr, taskmgr, dispatchmgr,
Brian Wellington's avatar
Brian Wellington committed
674
				       dispatchv4, dispatchv6, &requestmgr);
Michael Sawyer's avatar
Michael Sawyer committed
675
676
	check_result(result, "dns_requestmgr_create");

677
678
679
680
	if (keystr != NULL)
		setup_keystr();
	else if (keyfile != NULL)
		setup_keyfile();
Michael Sawyer's avatar
Michael Sawyer committed
681
}
Michael Sawyer's avatar
Michael Sawyer committed
682

683
684
static void
get_address(char *host, in_port_t port, isc_sockaddr_t *sockaddr) {
685
686
	int count;
	isc_result_t result;
687

688
689
690
691
692
693
694
	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);
695
696
}

Michael Sawyer's avatar
Michael Sawyer committed
697
static void
Michael Sawyer's avatar
Michael Sawyer committed
698
parse_args(int argc, char **argv) {
Brian Wellington's avatar
Brian Wellington committed
699
	int ch;
700
	isc_result_t result;
Michael Sawyer's avatar
Michael Sawyer committed
701

Michael Sawyer's avatar
Michael Sawyer committed
702
	debug("parse_args");
Michael Graff's avatar
Michael Graff committed
703
704
	while ((ch = isc_commandline_parse(argc, argv, "dDMy:vk:r:t:u:")) != -1)
	{
Brian Wellington's avatar
Brian Wellington committed
705
706
707
708
709
		switch (ch) {
		case 'd':
			debugging = ISC_TRUE;
			break;
		case 'D': /* was -dd */
Michael Sawyer's avatar
Michael Sawyer committed
710
711
			debugging = ISC_TRUE;
			ddebugging = ISC_TRUE;
Brian Wellington's avatar
Brian Wellington committed
712
713
714
			break;
		case 'M': /* was -dm */
			debugging = ISC_TRUE;
Michael Sawyer's avatar
Michael Sawyer committed
715
			ddebugging = ISC_TRUE;
716
717
718
			memdebugging = ISC_TRUE;
			isc_mem_debugging = ISC_MEM_DEBUGTRACE |
					    ISC_MEM_DEBUGRECORD;
Brian Wellington's avatar
Brian Wellington committed
719
720
721
722
723
			break;
		case 'y':
			keystr = isc_commandline_argument;
			break;
		case 'v':
Brian Wellington's avatar
Brian Wellington committed
724
			usevc = ISC_TRUE;
Brian Wellington's avatar
Brian Wellington committed
725
726
			break;
		case 'k':
727
			keyfile = isc_commandline_argument;
Brian Wellington's avatar
Brian Wellington committed
728
			break;
Michael Graff's avatar
Michael Graff committed
729
730
731
732
733
734
735
736
		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
737
				timeout = UINT_MAX;
Michael Graff's avatar
Michael Graff committed
738
739
740
741
742
743
744
745
746
			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
747
				udp_timeout = UINT_MAX;
Michael Graff's avatar
Michael Graff committed
748
749
750
751
752
753
754
755
756
			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;
Brian Wellington's avatar
Brian Wellington committed
757
758
759
		default:
			fprintf(stderr, "%s: invalid argument -%c\n",
				argv[0], ch);
760
			fprintf(stderr, "usage: nsupdate [-d] "
761
762
				"[-y keyname:secret | -k keyfile] [-v] "
				"[filename]\n");
Brian Wellington's avatar
Brian Wellington committed
763
764
			exit(1);
		}
Michael Sawyer's avatar
Michael Sawyer committed
765
	}
766
	if (keyfile != NULL && keystr != NULL) {
767
768
		fprintf(stderr, "%s: cannot specify both -k and -y\n",
			argv[0]);
769
770
		exit(1);
	}
771
772

	if (argv[isc_commandline_index] != NULL) {
773
774
775
776
777
778
		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) {
779
				fprintf(stderr, "could not open '%s': %s\n",
780
781
782
783
					argv[isc_commandline_index],
					isc_result_totext(result));
				exit(1);
			}
784
		}
785
		interactive = ISC_FALSE;
786
	}
Michael Sawyer's avatar
Michael Sawyer committed
787
788
789
}

static isc_uint16_t
790
parse_name(char **cmdlinep, dns_message_t *msg, dns_name_t **namep) {
Michael Sawyer's avatar
Michael Sawyer committed
791
	isc_result_t result;
792
	char *word;
Brian Wellington's avatar
Brian Wellington committed
793
	isc_buffer_t *namebuf = NULL;
Michael Sawyer's avatar
Michael Sawyer committed
794
	isc_buffer_t source;
Michael Sawyer's avatar
Michael Sawyer committed
795

796
	word = nsu_strsep(cmdlinep, " \t\r\n");
797
	if (*word == 0) {
798
		fprintf(stderr, "could not read owner name\n");
Brian Wellington's avatar
Brian Wellington committed
799
		return (STATUS_SYNTAX);
Michael Sawyer's avatar
Michael Sawyer committed
800
801
	}

802
	result = dns_message_gettempname(msg, namep);
Michael Sawyer's avatar
Michael Sawyer committed
803
	check_result(result, "dns_message_gettempname");
804
	result = isc_buffer_allocate(mctx, &namebuf, DNS_NAME_MAXWIRE);
Michael Sawyer's avatar
Michael Sawyer committed
805
	check_result(result, "isc_buffer_allocate");
806
807
808
	dns_name_init(*namep, NULL);
	dns_name_setbuffer(*namep, namebuf);
	dns_message_takebuffer(msg, &namebuf);
809
810
	isc_buffer_init(&source, word, strlen(word));
	isc_buffer_add(&source, strlen(word));
811
	result = dns_name_fromtext(*namep, &source, dns_rootname,
Michael Sawyer's avatar
Michael Sawyer committed
812
813
				   ISC_FALSE, NULL);
	check_result(result, "dns_name_fromtext");
814
815
816
817
818
819
	isc_buffer_invalidate(&source);
	return (STATUS_MORE);
}

static isc_uint16_t
parse_rdata(char **cmdlinep, dns_rdataclass_t rdataclass,
820
	    dns_rdatatype_t rdatatype, dns_message_t *msg,
821
	    dns_rdata_t *rdata)
822
823
{
	char *cmdline = *cmdlinep;
824
825
	isc_buffer_t source, *buf = NULL, *newbuf = NULL;
	isc_region_t r;
826
827
828
829
	isc_lex_t *lex = NULL;
	dns_rdatacallbacks_t callbacks;
	isc_result_t result;

830
	while (*cmdline != 0 && isspace((unsigned char)*cmdline))
831
832
833
		cmdline++;

	if (*cmdline != 0) {
834
		dns_rdatacallbacks_init(&callbacks);
835
836
837
838
839
840
841
842
843
		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");
		result = dns_rdata_fromtext(rdata, rdataclass, rdatatype, lex,
844
					    dns_rootname, 0, mctx, buf,
845
846
847
848
849
					    &callbacks);
		isc_lex_destroy(&lex);
		if (result == ISC_R_SUCCESS) {
			isc_buffer_usedregion(buf, &r);
			result = isc_buffer_allocate(mctx, &newbuf, r.length);
850
			check_result(result, "isc_buffer_allocate");
851
852
853
854
855
856
			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 {
857
858
			fprintf(stderr, "invalid rdata format: %s\n",
				isc_result_totext(result));
859
			isc_buffer_free(&buf);
860
861
			return (STATUS_SYNTAX);
		}
862
863
	} else {
		rdata->flags = DNS_RDATA_UPDATE;
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
	}
	*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;

882
	ddebug("make_prereq()");
883
884
885
886
887
888
889
890

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

Brian Wellington's avatar
Brian Wellington committed
891
892
893
894
	/*
	 * If this is an rrset prereq, read the class or type.
	 */
	if (isrrset) {
895
		word = nsu_strsep(&cmdline, " \t\r\n");
896
		if (*word == 0) {
897
			fprintf(stderr, "could not read class or type\n");
898
			goto failure;
Brian Wellington's avatar
Brian Wellington committed
899
		}
900
901
		region.base = word;
		region.length = strlen(word);
Brian Wellington's avatar
Brian Wellington committed
902
903
		result = dns_rdataclass_fromtext(&rdataclass, &region);
		if (result == ISC_R_SUCCESS) {
904
905
906
907
			if (!setzoneclass(rdataclass)) {
				fprintf(stderr, "class mismatch: %s\n", word);
				goto failure;
			}
Brian Wellington's avatar
Brian Wellington committed
908
909
910
			/*
			 * Now read the type.
			 */
911
			word = nsu_strsep(&cmdline, " \t\r\n");
912
			if (*word == 0) {
913
				fprintf(stderr, "could not read type\n");
914
				goto failure;
Brian Wellington's avatar
Brian Wellington committed
915
			}
916
917
			region.base = word;
			region.length = strlen(word);
Brian Wellington's avatar
Brian Wellington committed
918
			result = dns_rdatatype_fromtext(&rdatatype, &region);
919
			if (result != ISC_R_SUCCESS) {
Brian Wellington's avatar
Brian Wellington committed
920
				fprintf(stderr, "invalid type: %s\n", word);
921
922
				goto failure;
			}
Brian Wellington's avatar
Brian Wellington committed
923
		} else {
924
			rdataclass = getzoneclass();
Brian Wellington's avatar
Brian Wellington committed
925
			result = dns_rdatatype_fromtext(&rdatatype, &region);
926
			if (result != ISC_R_SUCCESS) {
Brian Wellington's avatar
Brian Wellington committed
927
				fprintf(stderr, "invalid type: %s\n", word);
928
929
				goto failure;
			}
Brian Wellington's avatar
Brian Wellington committed
930
931
932
		}
	} else
		rdatatype = dns_rdatatype_any;
Michael Sawyer's avatar
Michael Sawyer committed
933

934
935
936
937
938
939
940
	result = dns_message_gettemprdata(updatemsg, &rdata);
	check_result(result, "dns_message_gettemprdata");

	rdata->data = NULL;
	rdata->length = 0;

	if (isrrset && ispositive) {
941
		retval = parse_rdata(&cmdline, rdataclass, rdatatype,
942
				     updatemsg, rdata);
943
		if (retval != STATUS_MORE)
944
			goto failure;
945
946
	} else
		rdata->flags = DNS_RDATA_UPDATE;
Michael Sawyer's avatar
Michael Sawyer committed
947

948
949
	result = dns_message_gettemprdatalist(updatemsg, &rdatalist);
	check_result(result, "dns_message_gettemprdatalist");
Michael Sawyer's avatar
Michael Sawyer committed
950
951
	result = dns_message_gettemprdataset(updatemsg, &rdataset);
	check_result(result, "dns_message_gettemprdataset");
952
	dns_rdatalist_init(rdatalist);
Brian Wellington's avatar
Brian Wellington committed
953
	rdatalist->type = rdatatype;
954
955
956
957
958
959
	if (ispositive) {
		if (isrrset && rdata->data != NULL)
			rdatalist->rdclass = rdataclass;
		else
			rdatalist->rdclass = dns_rdataclass_any;
	} else
Brian Wellington's avatar
Brian Wellington committed
960
		rdatalist->rdclass = dns_rdataclass_none;
961
962
	rdatalist->covers = 0;
	rdatalist->ttl = 0;
Brian Wellington's avatar
Brian Wellington committed
963
964
	rdata->rdclass = rdatalist->rdclass;
	rdata->type = rdatatype;
965
966
967
	ISC_LIST_INIT(rdatalist->rdata);
	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
	dns_rdataset_init(rdataset);
968
	dns_rdatalist_tordataset(rdatalist, rdataset);
Michael Sawyer's avatar
Michael Sawyer committed
969
970
971
	ISC_LIST_INIT(name->list);
	ISC_LIST_APPEND(name->list, rdataset, link);
	dns_message_addname(updatemsg, name, DNS_SECTION_PREREQUISITE);
Brian Wellington's avatar
Brian Wellington committed
972
	return (STATUS_MORE);
973
974
975
976
977

 failure:
	if (name != NULL)
		dns_message_puttempname(updatemsg, &name);
	return (STATUS_SYNTAX);
Michael Sawyer's avatar
Michael Sawyer committed
978
}
Brian Wellington's avatar
Brian Wellington committed
979

Michael Sawyer's avatar
Michael Sawyer committed
980
static isc_uint16_t
981
982
evaluate_prereq(char *cmdline) {
	char *word;
Brian Wellington's avatar
Brian Wellington committed
983
	isc_boolean_t ispositive, isrrset;
Michael Sawyer's avatar
Michael Sawyer committed
984

985
	ddebug("evaluate_prereq()");
986
	word = nsu_strsep(&cmdline, " \t\r\n");
987
	if (*word == 0) {
988
		fprintf(stderr, "could not read operation code\n");
Brian Wellington's avatar
Brian Wellington committed
989
990
		return (STATUS_SYNTAX);
	}
991
	if (strcasecmp(word, "nxdomain") == 0) {
Brian Wellington's avatar
Brian Wellington committed
992
993
		ispositive = ISC_FALSE;
		isrrset = ISC_FALSE;
994
	} else if (strcasecmp(word, "yxdomain") == 0) {
Brian Wellington's avatar
Brian Wellington committed
995
996
		ispositive = ISC_TRUE;
		isrrset = ISC_FALSE;
997
	} else if (strcasecmp(word, "nxrrset") == 0) {
Brian Wellington's avatar
Brian Wellington committed
998
999
		ispositive = ISC_FALSE;
		isrrset = ISC_TRUE;
1000
	} else if (strcasecmp(word, "yxrrset") == 0) {
Brian Wellington's avatar
Brian Wellington committed
1001
1002
1003
		ispositive = ISC_TRUE;
		isrrset = ISC_TRUE;
	} else {
1004
		fprintf(stderr, "incorrect operation code: %s\n", word);
Brian Wellington's avatar
Brian Wellington committed
1005
		return (STATUS_SYNTAX);
Michael Sawyer's avatar
Michael Sawyer committed
1006
	}
1007
	return (make_prereq(cmdline, ispositive, isrrset));
Michael Sawyer's avatar
Michael Sawyer committed
1008
1009
1010
}

static isc_uint16_t
1011
evaluate_server(char *cmdline) {
1012
	char *word, *server;
1013
	long port;
1014
1015
1016

	word = nsu_strsep(&cmdline, " \t\r\n");
	if (*word == 0) {
1017
		fprintf(stderr, "could not read server name\n");
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
		return (STATUS_SYNTAX);
	}
	server = word;

	word = nsu_strsep(&cmdline, " \t\r\n");
	if (*word == 0)
		port = DNSDEFAULTPORT;
	else {
		char *endp;
		port = strtol(word, &endp, 10);
		if (*endp != 0) {
1029
			fprintf(stderr, "port '%s' is not numeric\n", word);
1030
			return (STATUS_SYNTAX);
1031
1032
1033
1034
		} else if (port < 1 || port > 65535) {
			fprintf(stderr, "port '%s' is out of range "
				"(1 to 65535)\n", word);
			return (STATUS_SYNTAX);
1035
1036
1037
1038
1039
1040
1041
1042
1043
		}
	}

	if (userserver == NULL) {
		userserver = isc_mem_get(mctx, sizeof(isc_sockaddr_t));
		if (userserver == NULL)
			fatal("out of memory");
	}

1044
	get_address(server, (in_port_t)port, userserver);
1045

Brian Wellington's avatar
Brian Wellington committed
1046
	return (STATUS_MORE);
Michael Sawyer's avatar
Michael Sawyer committed
1047
1048
}

1049
1050
1051
1052
static isc_uint16_t
evaluate_local(char *cmdline) {
	char *word, *local;
	long port;
1053
1054
	struct in_addr in4;
	struct in6_addr in6;
1055
1056
1057

	word = nsu_strsep(&cmdline, " \t\r\n");
	if (*word == 0) {
1058
		fprintf(stderr, "could not read server name\n");
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
		return (STATUS_SYNTAX);
	}
	local = word;

	word = nsu_strsep(&cmdline, " \t\r\n");
	if (*word == 0)
		port = 0;
	else {
		char *endp;
		port = strtol(word, &endp, 10);
		if (*endp != 0) {
			fprintf(stderr, "port '%s' is not numeric\n", word);
			return (STATUS_SYNTAX);
		} else if (port < 1 || port > 65535) {
			fprintf(stderr, "port '%s' is out of range "
				"(1 to 65535)\n", word);
			return (STATUS_SYNTAX);
		}
	}

	if (localaddr == NULL) {
		localaddr = isc_mem_get(mctx, sizeof(isc_sockaddr_t));
		if (localaddr == NULL)
			fatal("out of memory");
	}

1085
1086
1087
1088
1089
1090
1091
1092
	if (have_ipv6 && inet_pton(AF_INET6, local, &in6) == 1)
		isc_sockaddr_fromin6(localaddr, &in6, (in_port_t)port);
	else if (have_ipv4 && inet_pton(AF_INET, local, &in4) == 1)
		isc_sockaddr_fromin(localaddr, &in4, (in_port_t)port);
	else {
		fprintf(stderr, "invalid address %s", local);
		return (STATUS_SYNTAX);
	}
1093
1094
1095
1096

	return (STATUS_MORE);
}

1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
static isc_uint16_t
evaluate_key(char *cmdline) {
	char *namestr;
	char *secretstr;
	isc_buffer_t b;
	isc_result_t result;
	dns_fixedname_t fkeyname;
	dns_name_t *keyname;
	int secretlen;
	unsigned char *secret = NULL;
	isc_buffer_t secretbuf;
1108
1109
1110
	dns_name_t *hmacname = NULL;
	isc_uint16_t digestbits = 0;
	char *n;
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120

	namestr = nsu_strsep(&cmdline, " \t\r\n");
	if (*namestr == 0) {
		fprintf(stderr, "could not read key name\n");
		return (STATUS_SYNTAX);
	}

	dns_fixedname_init(&fkeyname);
	keyname = dns_fixedname_name(&fkeyname);

1121
1122
1123
1124
1125
1126
1127
	n = strchr(namestr, ':');
	if (n != NULL) {
		digestbits = parse_hmac(&hmacname, namestr, n - namestr);
		namestr = n + 1;
	} else
		hmacname = DNS_TSIG_HMACMD5_NAME;

1128
1129