nsupdate.c 85.4 KB
Newer Older
Michael Sawyer's avatar
Michael Sawyer committed
1
/*
2
 * Copyright (C) 2000-2017  Internet Systems Consortium, Inc. ("ISC")
3
 *
4
5
6
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
Michael Sawyer's avatar
Michael Sawyer committed
7
8
 */

9
/*! \file */
Michael Sawyer's avatar
Michael Sawyer committed
10
11

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

13
14
15
16
17
18
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <unistd.h>

19
#include <isc/app.h>
Michael Sawyer's avatar
Michael Sawyer committed
20
#include <isc/base64.h>
Michael Sawyer's avatar
Michael Sawyer committed
21
#include <isc/buffer.h>
Brian Wellington's avatar
Brian Wellington committed
22
#include <isc/commandline.h>
Michael Sawyer's avatar
Michael Sawyer committed
23
#include <isc/entropy.h>
24
#include <isc/event.h>
25
#include <isc/file.h>
26
#include <isc/hash.h>
Michael Sawyer's avatar
Michael Sawyer committed
27
#include <isc/lex.h>
28
#include <isc/log.h>
Michael Sawyer's avatar
Michael Sawyer committed
29
#include <isc/mem.h>
30
#include <isc/parseint.h>
Evan Hunt's avatar
Evan Hunt committed
31
#include <isc/print.h>
Evan Hunt's avatar
Evan Hunt committed
32
#include <isc/platform.h>
33
#include <isc/random.h>
Michael Sawyer's avatar
Michael Sawyer committed
34
#include <isc/region.h>
Michael Sawyer's avatar
Michael Sawyer committed
35
36
#include <isc/sockaddr.h>
#include <isc/socket.h>
37
#include <isc/stdio.h>
Michael Sawyer's avatar
Michael Sawyer committed
38
#include <isc/string.h>
Michael Sawyer's avatar
Michael Sawyer committed
39
#include <isc/task.h>
Michael Sawyer's avatar
Michael Sawyer committed
40
#include <isc/timer.h>
Michael Sawyer's avatar
Michael Sawyer committed
41
#include <isc/types.h>
Michael Sawyer's avatar
Michael Sawyer committed
42
#include <isc/util.h>
Michael Sawyer's avatar
Michael Sawyer committed
43

44
45
#include <pk11/site.h>

46
47
#include <isccfg/namedconf.h>

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

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

71
#include <irs/resconf.h>
72

73
74
#ifdef GSSAPI
#include <dst/gssapi.h>
75
76
77
#ifdef WIN32
#include <krb5/krb5.h>
#else
78
#include ISC_PLATFORM_KRB5HEADER
79
#endif
80
#endif
81
82
#include <bind9/getaddresses.h>

83
#if defined(HAVE_READLINE)
84
85
86
87
88
89
#if defined(HAVE_EDIT_READLINE_READLINE_H)
#include <edit/readline/readline.h>
#if defined(HAVE_EDIT_READLINE_HISTORY_H)
#include <edit/readline/history.h>
#endif
#elif defined(HAVE_EDITLINE_READLINE_H)
90
91
#include <editline/readline.h>
#else
92
93
94
#include <readline/readline.h>
#include <readline/history.h>
#endif
95
#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
144
static isc_log_t *glctx = NULL;
static isc_mem_t *gmctx = NULL;
Brian Wellington's avatar
Brian Wellington committed
145
146
147
148
149
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
static dns_fixedname_t fuserzone;
153
static dns_fixedname_t fzname;
154
static dns_name_t *userzone = NULL;
155
static dns_name_t *zname = NULL;
156
157
158
static dns_name_t tmpzonename;
static dns_name_t restart_master;
static dns_tsig_keyring_t *gssring = NULL;
159
static dns_tsigkey_t *tsigkey = NULL;
160
static dst_key_t *sig0key = NULL;
161
static isc_sockaddr_t *servers = NULL;
162
static isc_sockaddr_t *master_servers = NULL;
163
static isc_boolean_t default_servers = ISC_TRUE;
Brian Wellington's avatar
Brian Wellington committed
164
static int ns_inuse = 0;
165
static int master_inuse = 0;
166
static int ns_total = 0;
167
static int ns_alloc = 0;
168
static int master_total = 0;
169
static int master_alloc = 0;
170
171
static isc_sockaddr_t *localaddr4 = NULL;
static isc_sockaddr_t *localaddr6 = NULL;
172
173
static const char *keyfile = NULL;
static char *keystr = NULL;
174
static isc_entropy_t *entropy = NULL;
175
static isc_boolean_t shuttingdown = ISC_FALSE;
176
static FILE *input;
177
static isc_boolean_t interactive = ISC_TRUE;
178
static isc_boolean_t seenerror = ISC_FALSE;
Danny Mayer's avatar
Danny Mayer committed
179
static const dns_master_style_t *style;
180
static int requests = 0;
181
static unsigned int logdebuglevel = 0;
Michael Graff's avatar
Michael Graff committed
182
183
184
static unsigned int timeout = 300;
static unsigned int udp_timeout = 3;
static unsigned int udp_retries = 3;
185
186
static dns_rdataclass_t defaultclass = dns_rdataclass_in;
static dns_rdataclass_t zoneclass = dns_rdataclass_none;
187
static dns_message_t *answer = NULL;
188
189
static isc_uint32_t default_ttl = 0;
static isc_boolean_t default_ttl_set = ISC_FALSE;
190
static isc_boolean_t checknames = ISC_TRUE;
Brian Wellington's avatar
Brian Wellington committed
191

192
193
194
195
196
typedef struct nsu_requestinfo {
	dns_message_t *msg;
	isc_sockaddr_t *addr;
} nsu_requestinfo_t;

197
static void
198
199
200
201
sendrequest(isc_sockaddr_t *destaddr, dns_message_t *msg,
	    dns_request_t **request);
static void
send_update(dns_name_t *zonename, isc_sockaddr_t *master);
Francis Dupont's avatar
Francis Dupont committed
202
203
204
205

ISC_PLATFORM_NORETURN_PRE static void
fatal(const char *format, ...)
ISC_FORMAT_PRINTF(1, 2) ISC_PLATFORM_NORETURN_POST;
206
207
208
209
210
211

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
212

213
214
215
#ifdef GSSAPI
static dns_fixedname_t fkname;
static isc_sockaddr_t *kserver = NULL;
216
static char *realm = NULL;
217
218
219
220
221
222
223
224
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;

225
226
static void
failed_gssrequest();
227
static void
228
start_gssrequest(dns_name_t *master);
229
static void
230
231
send_gssrequest(isc_sockaddr_t *destaddr, dns_message_t *msg,
		dns_request_t **request, gss_ctx_id_t context);
232
233
234
235
static void
recvgss(isc_task_t *task, isc_event_t *event);
#endif /* GSSAPI */

236
237
238
static void
error(const char *format, ...) ISC_FORMAT_PRINTF(1, 2);

239
240
241
242
#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
243

244
245
246
247
248
249
250
251
252
253
254
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
255
setup_entropy(isc_mem_t *mctx, const char *randomfile, isc_entropy_t **ectx) {
256
257
258
259
260
261
262
263
264
265
	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)
Evan Hunt's avatar
Evan Hunt committed
266
267
			fatal("could not create entropy object: %s",
			      isc_result_totext(result));
268
269
270
271
272
273
274
275
		ISC_LIST_INIT(sources);
	}

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

Evan Hunt's avatar
Evan Hunt committed
276
#ifdef ISC_PLATFORM_CRYPTORANDOM
277
	if (randomfile == NULL) {
Evan Hunt's avatar
Evan Hunt committed
278
279
280
		isc_entropy_usehook(*ectx, ISC_TRUE);
	}
#endif
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
	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);
}

311
312
313
314
static void
master_from_servers(void) {

	if (master_servers != NULL && master_servers != servers)
315
		isc_mem_put(gmctx, master_servers,
316
			    master_alloc * sizeof(isc_sockaddr_t));
317
318
	master_servers = servers;
	master_total = ns_total;
319
	master_alloc = ns_alloc;
320
321
	master_inuse = ns_inuse;
}
322

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

344
	va_start(args, format);
Michael Sawyer's avatar
Michael Sawyer committed
345
346
347
	vfprintf(stderr, format, args);
	va_end(args);
	fprintf(stderr, "\n");
Brian Wellington's avatar
Brian Wellington committed
348
	exit(1);
Michael Sawyer's avatar
Michael Sawyer committed
349
350
}

351
352
353
354
355
356
357
358
359
360
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
361
362
363
364
365
static void
debug(const char *format, ...) {
	va_list args;

	if (debugging) {
366
		va_start(args, format);
Michael Sawyer's avatar
Michael Sawyer committed
367
368
369
370
371
372
		vfprintf(stderr, format, args);
		va_end(args);
		fprintf(stderr, "\n");
	}
}

373
374
375
376
377
static void
ddebug(const char *format, ...) {
	va_list args;

	if (ddebugging) {
378
		va_start(args, format);
379
380
381
382
383
384
		vfprintf(stderr, format, args);
		va_end(args);
		fprintf(stderr, "\n");
	}
}

385
static inline void
Michael Sawyer's avatar
Michael Sawyer committed
386
check_result(isc_result_t result, const char *msg) {
Brian Wellington's avatar
Brian Wellington committed
387
	if (result != ISC_R_SUCCESS)
Michael Sawyer's avatar
Michael Sawyer committed
388
389
390
		fatal("%s: %s", msg, isc_result_totext(result));
}

391
392
393
394
395
396
397
398
399
400
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);

401
402
403
404
405
406
407
408
409
410
	for (; *string != '\0'; string++) {
		sc = *string;
		for (d = delim; (dc = *d) != '\0'; d++) {
			if (sc == dc)
				break;
		}
		if (dc == 0)
			break;
	}

411
412
	for (s = string; *s != '\0'; s++) {
		sc = *s;
413
		for (d = delim; (dc = *d) != '\0'; d++) {
414
415
416
417
418
			if (sc == dc) {
				*s++ = '\0';
				*stringp = s;
				return (string);
			}
419
		}
420
421
422
423
424
	}
	*stringp = NULL;
	return (string);
}

Michael Sawyer's avatar
Michael Sawyer committed
425
static void
Brian Wellington's avatar
Brian Wellington committed
426
reset_system(void) {
Michael Sawyer's avatar
Michael Sawyer committed
427
428
	isc_result_t result;

429
	ddebug("reset_system()");
Michael Sawyer's avatar
Michael Sawyer committed
430
431
	/* If the update message is still around, destroy it */
	if (updatemsg != NULL)
Brian Wellington's avatar
Brian Wellington committed
432
433
		dns_message_reset(updatemsg, DNS_MESSAGE_INTENTRENDER);
	else {
434
		result = dns_message_create(gmctx, DNS_MESSAGE_INTENTRENDER,
Brian Wellington's avatar
Brian Wellington committed
435
					    &updatemsg);
436
		check_result(result, "dns_message_create");
Brian Wellington's avatar
Brian Wellington committed
437
	}
Michael Sawyer's avatar
Michael Sawyer committed
438
	updatemsg->opcode = dns_opcode_update;
439
440
441
442
	if (usegsstsig) {
		if (tsigkey != NULL)
			dns_tsigkey_detach(&tsigkey);
		if (gssring != NULL)
443
			dns_tsigkeyring_detach(&gssring);
444
445
		tried_other_gsstsig = ISC_FALSE;
	}
Michael Sawyer's avatar
Michael Sawyer committed
446
447
}

448
449
450
451
static isc_boolean_t
parse_hmac(const dns_name_t **hmac, const char *hmacstr, size_t len,
	   isc_uint16_t *digestbitsp)
{
452
453
454
455
456
457
458
	isc_uint16_t digestbits = 0;
	isc_result_t result;
	char buf[20];

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

459
460
461
462
	if (len >= sizeof(buf)) {
		error("unknown key type '%.*s'", (int)(len), hmacstr);
		return (ISC_FALSE);
	}
463

464
465
	/* Copy len bytes and NUL terminate. */
	strlcpy(buf, hmacstr, ISC_MIN(len + 1, sizeof(buf)));
Automatic Updater's avatar
Automatic Updater committed
466

467
#ifndef PK11_MD5_DISABLE
468
469
470
471
472
	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);
473
474
475
476
477
		if (result != ISC_R_SUCCESS || digestbits > 128) {
			error("digest-bits out of range [0..128]");
			return (ISC_FALSE);
		}
		*digestbitsp = (digestbits + 7) & ~0x7U;
478
479
480
	} else
#endif
	if (strcasecmp(buf, "hmac-sha1") == 0) {
481
482
483
484
		*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);
485
486
487
488
489
		if (result != ISC_R_SUCCESS || digestbits > 160) {
			error("digest-bits out of range [0..160]");
			return (ISC_FALSE);
		}
		*digestbitsp = (digestbits + 7) & ~0x7U;
490
491
492
493
494
	} 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);
495
496
497
498
499
		if (result != ISC_R_SUCCESS || digestbits > 224) {
			error("digest-bits out of range [0..224]");
			return (ISC_FALSE);
		}
		*digestbitsp = (digestbits + 7) & ~0x7U;
500
501
502
503
504
	} 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);
505
506
507
508
509
		if (result != ISC_R_SUCCESS || digestbits > 256) {
			error("digest-bits out of range [0..256]");
			return (ISC_FALSE);
		}
		*digestbitsp = (digestbits + 7) & ~0x7U;
510
511
512
513
514
	} 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);
515
516
517
518
519
		if (result != ISC_R_SUCCESS || digestbits > 384) {
			error("digest-bits out of range [0..384]");
			return (ISC_FALSE);
		}
		*digestbitsp = (digestbits + 7) & ~0x7U;
520
521
522
523
524
	} 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);
525
526
527
528
529
530
531
532
533
534
		if (result != ISC_R_SUCCESS || digestbits > 512) {
			error("digest-bits out of range [0..512]");
			return (ISC_FALSE);
		}
		*digestbitsp = (digestbits + 7) & ~0x7U;
	} else {
		error("unknown key type '%s'", buf);
		return (ISC_FALSE);
	}
	return (ISC_TRUE);
535
536
}

537
538
static int
basenamelen(const char *file) {
Automatic Updater's avatar
Automatic Updater committed
539
540
541
542
543
544
545
546
	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;
547
548
549
	return (len);
}

550
static void
551
setup_keystr(void) {
552
553
554
555
	unsigned char *secret = NULL;
	int secretlen;
	isc_buffer_t secretbuf;
	isc_result_t result;
556
557
	isc_buffer_t keynamesrc;
	char *secretstr;
558
	char *s, *n;
559
	dns_fixedname_t fkeyname;
560
	dns_name_t *mykeyname;
561
	char *name;
562
	const dns_name_t *hmacname = NULL;
563
	isc_uint16_t digestbits = 0;
564

565
	dns_fixedname_init(&fkeyname);
566
	mykeyname = dns_fixedname_name(&fkeyname);
567

568
	debug("Creating key...");
569

570
	s = strchr(keystr, ':');
571
572
	if (s == NULL || s == keystr || s[1] == 0)
		fatal("key option must specify [hmac:]keyname:secret");
573
	secretstr = s + 1;
574
575
576
577
578
579
	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;
580
581
582
		if (!parse_hmac(&hmacname, keystr, s - keystr, &digestbits)) {
			exit(1);
		}
583
	} else {
584
#ifndef PK11_MD5_DISABLE
585
		hmacname = DNS_TSIG_HMACMD5_NAME;
586
587
588
#else
		hmacname = DNS_TSIG_HMACSHA256_NAME;
#endif
589
590
591
		name = keystr;
		n = s;
	}
592

593
594
	isc_buffer_init(&keynamesrc, name, (unsigned int)(n - name));
	isc_buffer_add(&keynamesrc, (unsigned int)(n - name));
595

596
	debug("namefromtext");
597
598
	result = dns_name_fromtext(mykeyname, &keynamesrc, dns_rootname, 0,
				   NULL);
599
	check_result(result, "dns_name_fromtext");
600

601
	secretlen = strlen(secretstr) * 3 / 4;
602
	secret = isc_mem_allocate(gmctx, secretlen);
603
604
	if (secret == NULL)
		fatal("out of memory");
605

606
607
608
609
610
611
	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;
612
	}
613

614
615
	secretlen = isc_buffer_usedlength(&secretbuf);

616
	debug("keycreate");
617
618
	result = dns_tsigkey_create(mykeyname, hmacname, secret, secretlen,
				    ISC_FALSE, NULL, 0, 0, gmctx, NULL,
619
				    &tsigkey);
620
	if (result != ISC_R_SUCCESS)
621
		fprintf(stderr, "could not create key from %s: %s\n",
622
			keystr, dns_result_totext(result));
623
624
	else
		dst_key_setbits(tsigkey->key, digestbits);
625
626
 failure:
	if (secret != NULL)
627
		isc_mem_free(gmctx, secret);
628
629
}

630
631
632
633
/*
 * Get a key from a named.conf format keyfile
 */
static isc_result_t
634
read_sessionkey(isc_mem_t *mctx, isc_log_t *lctx) {
635
	cfg_parser_t *pctx = NULL;
636
	cfg_obj_t *sessionkey = NULL;
637
638
639
	const cfg_obj_t *key = NULL;
	const cfg_obj_t *secretobj = NULL;
	const cfg_obj_t *algorithmobj = NULL;
640
	const char *mykeyname;
641
642
643
644
645
646
647
648
649
650
651
652
	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;

653
	result = cfg_parse_file(pctx, keyfile, &cfg_type_sessionkey,
Automatic Updater's avatar
Automatic Updater committed
654
				&sessionkey);
655
656
657
	if (result != ISC_R_SUCCESS)
		goto cleanup;

658
	result = cfg_map_get(sessionkey, "key", &key);
659
660
661
662
663
664
665
666
	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");

667
	mykeyname = cfg_obj_asstring(cfg_map_getname(key));
668
669
670
	secretstr = cfg_obj_asstring(secretobj);
	algorithm = cfg_obj_asstring(algorithmobj);

671
	len = strlen(algorithm) + strlen(mykeyname) + strlen(secretstr) + 3;
672
	keystr = isc_mem_allocate(mctx, len);
673
674
	if (keystr == NULL)
		fatal("out of memory");
675
	snprintf(keystr, len, "%s:%s:%s", algorithm, mykeyname, secretstr);
676
677
678
679
	setup_keystr();

 cleanup:
	if (pctx != NULL) {
680
681
		if (sessionkey != NULL)
			cfg_obj_destroy(pctx, &sessionkey);
682
683
684
685
686
687
688
689
690
		cfg_parser_destroy(&pctx);
	}

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

	return (result);
}

691
static void
692
setup_keyfile(isc_mem_t *mctx, isc_log_t *lctx) {
693
694
	dst_key_t *dstkey = NULL;
	isc_result_t result;
695
	const dns_name_t *hmacname = NULL;
696
697
698

	debug("Creating key...");

699
700
701
	if (sig0key != NULL)
		dst_key_free(&sig0key);

702
	/* Try reading the key from a K* pair */
703
	result = dst_key_fromnamedfile(keyfile, NULL,
704
				       DST_TYPE_PRIVATE | DST_TYPE_KEY, mctx,
705
				       &dstkey);
706

707
	/* If that didn't work, try reading it as a session.key keyfile */
708
	if (result != ISC_R_SUCCESS) {
709
		result = read_sessionkey(mctx, lctx);
710
711
712
713
		if (result == ISC_R_SUCCESS)
			return;
	}

714
	if (result != ISC_R_SUCCESS) {
715
716
717
		fprintf(stderr, "could not read key from %.*s.{private,key}: "
				"%s\n", basenamelen(keyfile), keyfile,
				isc_result_totext(result));
718
719
		return;
	}
720

721
	switch (dst_key_alg(dstkey)) {
722
#ifndef PK11_MD5_DISABLE
723
724
725
	case DST_ALG_HMACMD5:
		hmacname = DNS_TSIG_HMACMD5_NAME;
		break;
726
#endif
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
	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) {
744
		result = dns_tsigkey_createfromkey(dst_key_name(dstkey),
745
						   hmacname, dstkey, ISC_FALSE,
746
747
						   NULL, 0, 0, mctx, NULL,
						   &tsigkey);
748
		dst_key_free(&dstkey);
749
750
751
752
753
		if (result != ISC_R_SUCCESS) {
			fprintf(stderr, "could not create key from %s: %s\n",
				keyfile, isc_result_totext(result));
			return;
		}
754
	} else {
755
		dst_key_attach(dstkey, &sig0key);
756
757
		dst_key_free(&dstkey);
	}
758
759
}

760
static void
761
doshutdown(void) {
762
	isc_task_detach(&global_task);
763

764
765
	/*
	 * The isc_mem_put of master_servers must be before the
Mark Andrews's avatar
Mark Andrews committed
766
767
	 * isc_mem_put of servers as it sets the servers pointer
	 * to NULL.
768
769
	 */
	if (master_servers != NULL && master_servers != servers)
770
		isc_mem_put(gmctx, master_servers,
771
			    master_alloc * sizeof(isc_sockaddr_t));
772

773
	if (servers != NULL)
774
		isc_mem_put(gmctx, servers, ns_alloc * sizeof(isc_sockaddr_t));
775

776
	if (localaddr4 != NULL)
777
		isc_mem_put(gmctx, localaddr4, sizeof(isc_sockaddr_t));
778
779

	if (localaddr6 != NULL)
780
		isc_mem_put(gmctx, localaddr6, sizeof(isc_sockaddr_t));
781

782
783
784
785
786
787
788
789
	if (tsigkey != NULL) {
		ddebug("Freeing TSIG key");
		dns_tsigkey_detach(&tsigkey);
	}

	if (sig0key != NULL) {
		ddebug("Freeing SIG(0) key");
		dst_key_free(&sig0key);
790
791
792
793
794
795
	}

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

	if (is_dst_up) {
796
		ddebug("Destroy DST lib");
797
798
799
800
		dst_lib_destroy();
		is_dst_up = ISC_FALSE;
	}

801
	cleanup_entropy(&entropy);
802

803
	ddebug("Destroying request manager");
804
805
806
807
808
809
810
811
812
813
814
	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);

815
816
}

817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
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
840
static void
Brian Wellington's avatar
Brian Wellington committed
841
setup_system(void) {
Michael Sawyer's avatar
Michael Sawyer committed
842
	isc_result_t result;
Brian Wellington's avatar
Brian Wellington committed
843
	isc_sockaddr_t bind_any, bind_any6;
844
845
	unsigned int attrs, attrmask;
	isc_sockaddrlist_t *nslist;
846
	isc_logconfig_t *logconfig = NULL;
847
	irs_resconf_t *resconf = NULL;
Michael Sawyer's avatar
Michael Sawyer committed
848

849
	ddebug("setup_system()");
Michael Sawyer's avatar
Michael Sawyer committed
850

851
852
	dns_result_register();

853
	result = isc_log_create(gmctx, &glctx, &logconfig);
854
855
	check_result(result, "isc_log_create");

856
857
858
	isc_log_setcontext(glctx);
	dns_log_init(glctx);
	dns_log_setcontext(glctx);
859
860
861
862

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

863
	isc_log_setdebuglevel(glctx, logdebuglevel);
864

865
866
867
	result = irs_resconf_load(gmctx, RESOLV_CONF, &resconf);
	if (result != ISC_R_SUCCESS && result != ISC_R_FILENOTFOUND) {
		fatal("parse of %s failed", RESOLV_CONF);
868
869
	}

870
	nslist = irs_resconf_getnameservers(resconf);
Brian Wellington's avatar
Brian Wellington committed
871

872
873
874
	if (servers != NULL) {
		if (master_servers == servers)
			master_servers = NULL;
875
		isc_mem_put(gmctx, servers, ns_alloc * sizeof(isc_sockaddr_t));
876
877
	}

878
	ns_inuse = 0;
879
	if (local_only || ISC_LIST_EMPTY(*nslist)) {
880
881
882
883
884
885
		struct in_addr in;
		struct in6_addr in6;

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

886
		default_servers = !local_only;
887

888
889
		ns_total = ns_alloc = (have_ipv4 ? 1 : 0) + (have_ipv6 ? 1 : 0);
		servers = isc_mem_get(gmctx, ns_alloc * sizeof(isc_sockaddr_t));
890
891
		if (servers == NULL)
			fatal("out of memory");
892
893
894
895

		if (have_ipv6) {
			memset(&in6, 0, sizeof(in6));
			in6.s6_addr[15] = 1;
896
897
898
899
900
901
			isc_sockaddr_fromin6(&servers[0], &in6, dnsport);
		}
		if (have_ipv4) {
			in.s_addr = htonl(INADDR_LOOPBACK);
			isc_sockaddr_fromin(&servers[(have_ipv6 ? 1 : 0)],
					    &in, dnsport);
902
		}
903
	} else {
904
		isc_sockaddr_t *sa;
Mukund Sivaraman's avatar
Mukund Sivaraman committed
905
		int i;
906
907
908
909
910
911

		/*
		 * Count the nameservers (skipping any that we can't use
		 * because of address family restrictions) and allocate
		 * the servers array.
		 */
Mukund Sivaraman's avatar
Mukund Sivaraman committed
912
		ns_total = 0;
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
		for (sa = ISC_LIST_HEAD(*nslist);
		     sa != NULL;
		     sa = ISC_LIST_NEXT(sa, link))
		{
			switch (sa->type.sa.sa_family) {
			case AF_INET:
				if (have_ipv4) {
					ns_total++;
				}
				break;
			case AF_INET6:
				if (have_ipv6) {
					ns_total++;
				}
				break;
			default:
				fatal("bad family");
			}
		}

		ns_alloc = ns_total;
934
		servers = isc_mem_get(gmctx, ns_alloc * sizeof(isc_sockaddr_t));
935
936
		if (servers == NULL)
			fatal("out of memory");
937

Mukund Sivaraman's avatar
Mukund Sivaraman committed
938
		i = 0;
939
940
941
942
943
944
		for (sa = ISC_LIST_HEAD(*nslist);
		     sa != NULL;
		     sa = ISC_LIST_NEXT(sa, link))
		{
			switch (sa->type.sa.sa_family) {
			case AF_INET:
Mukund Sivaraman's avatar
Mukund Sivaraman committed
945
946
				if (have_ipv4) {
					sa->type.sin.sin_port = htons(dnsport);
947
948
				} else {
					continue;
949
950
951
				}
				break;
			case AF_INET6:
Mukund Sivaraman's avatar
Mukund Sivaraman committed
952
953
				if (have_ipv6) {
					sa->type.sin6.sin6_port = htons(dnsport);
954
955
				} else {
					continue;
956
957
958
959
				}
				break;
			default:
				fatal("bad family");
960
			}
961
			INSIST(i < ns_alloc);
962
			servers[i++] = *sa;
963
964
965
		}
	}

966
967
	irs_resconf_destroy(&resconf);

Evan Hunt's avatar
Evan Hunt committed
968
969
	if (entropy == NULL)
		setup_entropy(gmctx, NULL, &entropy);
970

971
	result = isc_hash_create(gmctx, entropy, DNS_NAME_MAXWIRE);
972
973
	check_result(result, "isc_hash_create");

974
	result = dns_dispatchmgr_create(gmctx, entropy, &dispatchmgr);
Michael Sawyer's avatar
Michael Sawyer committed
975
976
	check_result(result, "dns_dispatchmgr_create");

977
	result = isc_socketmgr_create(gmctx, &socketmgr);
Michael Sawyer's avatar
Michael Sawyer committed
978
979
	check_result(result, "dns_socketmgr_create");

980
	result = isc_timermgr_create(gmctx, &timermgr);
Michael Sawyer's avatar
Michael Sawyer committed
981
982
	check_result(result, "dns_timermgr_create");

983
	result = isc_taskmgr_create(gmctx, 1, 0, &taskmgr);
Michael Sawyer's avatar
Michael Sawyer committed
984
985
	check_result(result, "isc_taskmgr_create");

986
	result = isc_task_create(taskmgr, 0, &global_task);
Michael Sawyer's avatar
Michael Sawyer committed
987
988
	check_result(result, "isc_task_create");

989
990
991
	result = isc_task_onshutdown(global_task, shutdown_program, NULL);
	check_result(result, "isc_task_onshutdown");

992
	result = dst_lib_init(gmctx, entropy, 0);
Michael Sawyer's avatar
Michael Sawyer committed
993
994
995
	check_result(result, "dst_lib_init");
	is_dst_up = ISC_TRUE;

Evan Hunt's avatar
Evan Hunt committed
996
997
998
	/* moved after dst_lib_init() */
	isc_hash_init();

Brian Wellington's avatar
Brian Wellington committed
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
	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
1013

Brian Wellington's avatar
Brian Wellington committed
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
	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)");
	}
1025

1026
	result = dns_requestmgr_create(gmctx, timermgr,
Michael Sawyer's avatar
Michael Sawyer committed
1027
				       socketmgr, taskmgr, dispatchmgr,
Brian Wellington's avatar
Brian Wellington committed
1028
				       dispatchv4, dispatchv6, &requestmgr);
Michael Sawyer's avatar
Michael Sawyer committed
1029
1030
	check_result(result, "dns_requestmgr_create");

1031
1032
	if (keystr != NULL)
		setup_keystr();
1033
	else if (local_only) {
1034
		result = read_sessionkey(gmctx, glctx);
1035
1036
1037
1038
		if (result != ISC_R_SUCCESS)
			fatal("can't read key from %s: %s\n",
			      keyfile, isc_result_totext(result));
	} else if (keyfile != NULL)
1039
		setup_keyfile(gmctx, glctx);
Michael Sawyer's avatar
Michael Sawyer committed
1040
}
Michael Sawyer's avatar
Michael Sawyer committed
1041

1042
static int
1043
1044
1045
get_addresses(char *host, in_port_t port,
	      isc_sockaddr_t *sockaddr, int naddrs)
{
1046
	int count = 0;