nsupdate.c 83 KB
Newer Older
Michael Sawyer's avatar
Michael Sawyer committed
1
/*
2
 * Copyright (C) 2000-2016  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>
32
#include <isc/random.h>
Michael Sawyer's avatar
Michael Sawyer committed
33
#include <isc/region.h>
Michael Sawyer's avatar
Michael Sawyer committed
34
35
#include <isc/sockaddr.h>
#include <isc/socket.h>
36
#include <isc/stdio.h>
Michael Sawyer's avatar
Michael Sawyer committed
37
#include <isc/string.h>
Michael Sawyer's avatar
Michael Sawyer committed
38
#include <isc/task.h>
Michael Sawyer's avatar
Michael Sawyer committed
39
#include <isc/timer.h>
Michael Sawyer's avatar
Michael Sawyer committed
40
#include <isc/types.h>
Michael Sawyer's avatar
Michael Sawyer committed
41
#include <isc/util.h>
Michael Sawyer's avatar
Michael Sawyer committed
42

43
44
#include <pk11/site.h>

45
46
#include <isccfg/namedconf.h>

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

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

70
#include <lwres/lwres.h>
71
#include <lwres/net.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
153
static dns_fixedname_t fuserzone;
static dns_name_t *userzone = NULL;
154
static dns_name_t *zname = NULL;
155
156
157
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
static isc_sockaddr_t *servers = NULL;
163
static isc_sockaddr_t *master_servers = NULL;
164
static isc_boolean_t default_servers = ISC_TRUE;
Brian Wellington's avatar
Brian Wellington committed
165
static int ns_inuse = 0;
166
static int master_inuse = 0;
167
static int ns_total = 0;
168
169
170
static int master_total = 0;
static isc_sockaddr_t *localaddr4 = NULL;
static isc_sockaddr_t *localaddr6 = NULL;
171
172
static const char *keyfile = NULL;
static char *keystr = NULL;
173
static isc_entropy_t *entropy = NULL;
174
static isc_boolean_t shuttingdown = ISC_FALSE;
175
static FILE *input;
176
static isc_boolean_t interactive = ISC_TRUE;
177
static isc_boolean_t seenerror = ISC_FALSE;
Danny Mayer's avatar
Danny Mayer committed
178
static const dns_master_style_t *style;
179
static int requests = 0;
180
static unsigned int logdebuglevel = 0;
Michael Graff's avatar
Michael Graff committed
181
182
183
static unsigned int timeout = 300;
static unsigned int udp_timeout = 3;
static unsigned int udp_retries = 3;
184
185
static dns_rdataclass_t defaultclass = dns_rdataclass_in;
static dns_rdataclass_t zoneclass = dns_rdataclass_none;
186
static dns_message_t *answer = NULL;
187
188
static isc_uint32_t default_ttl = 0;
static isc_boolean_t default_ttl_set = ISC_FALSE;
189
static isc_boolean_t checknames = ISC_TRUE;
Brian Wellington's avatar
Brian Wellington committed
190

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

196
static void
197
198
199
200
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
201
202
203
204

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

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
211

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

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

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

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

243
244
245
246
247
248
249
250
251
252
253
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
254
setup_entropy(isc_mem_t *mctx, const char *randomfile, isc_entropy_t **ectx) {
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
298
299
300
301
302
303
	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);
}

304
305
306
307
static void
master_from_servers(void) {

	if (master_servers != NULL && master_servers != servers)
308
		isc_mem_put(gmctx, master_servers,
309
310
311
312
313
			    master_total * sizeof(isc_sockaddr_t));
	master_servers = servers;
	master_total = ns_total;
	master_inuse = ns_inuse;
}
314

315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
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
332
333
334
335
static void
fatal(const char *format, ...) {
	va_list args;

336
	va_start(args, format);
Michael Sawyer's avatar
Michael Sawyer committed
337
338
339
	vfprintf(stderr, format, args);
	va_end(args);
	fprintf(stderr, "\n");
Brian Wellington's avatar
Brian Wellington committed
340
	exit(1);
Michael Sawyer's avatar
Michael Sawyer committed
341
342
}

343
344
345
346
347
348
349
350
351
352
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
353
354
355
356
357
static void
debug(const char *format, ...) {
	va_list args;

	if (debugging) {
358
		va_start(args, format);
Michael Sawyer's avatar
Michael Sawyer committed
359
360
361
362
363
364
		vfprintf(stderr, format, args);
		va_end(args);
		fprintf(stderr, "\n");
	}
}

365
366
367
368
369
static void
ddebug(const char *format, ...) {
	va_list args;

	if (ddebugging) {
370
		va_start(args, format);
371
372
373
374
375
376
		vfprintf(stderr, format, args);
		va_end(args);
		fprintf(stderr, "\n");
	}
}

377
static inline void
Michael Sawyer's avatar
Michael Sawyer committed
378
check_result(isc_result_t result, const char *msg) {
Brian Wellington's avatar
Brian Wellington committed
379
	if (result != ISC_R_SUCCESS)
Michael Sawyer's avatar
Michael Sawyer committed
380
381
382
		fatal("%s: %s", msg, isc_result_totext(result));
}

383
384
385
static void *
mem_alloc(void *arg, size_t size) {
	return (isc_mem_get(arg, size));
386
387
}

388
389
390
static void
mem_free(void *arg, void *mem, size_t size) {
	isc_mem_put(arg, mem, size);
391
392
393
394
395
396
397
398
399
400
401
402
}

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

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

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

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

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

450
static isc_uint16_t
451
parse_hmac(const dns_name_t **hmac, const char *hmacstr, size_t len) {
452
453
454
455
456
457
458
459
460
461
462
463
	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
464

465
#ifndef PK11_MD5_DISABLE
466
467
468
469
470
471
472
473
	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;
474
475
476
	} else
#endif
	if (strcasecmp(buf, "hmac-sha1") == 0) {
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
		*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);
}

521
522
static int
basenamelen(const char *file) {
Automatic Updater's avatar
Automatic Updater committed
523
524
525
526
527
528
529
530
	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;
531
532
533
	return (len);
}

534
static void
535
setup_keystr(void) {
536
537
538
539
	unsigned char *secret = NULL;
	int secretlen;
	isc_buffer_t secretbuf;
	isc_result_t result;
540
541
	isc_buffer_t keynamesrc;
	char *secretstr;
542
	char *s, *n;
543
	dns_fixedname_t fkeyname;
544
	dns_name_t *mykeyname;
545
	char *name;
546
	const dns_name_t *hmacname = NULL;
547
	isc_uint16_t digestbits = 0;
548

549
	dns_fixedname_init(&fkeyname);
550
	mykeyname = dns_fixedname_name(&fkeyname);
551

552
	debug("Creating key...");
553

554
	s = strchr(keystr, ':');
555
556
	if (s == NULL || s == keystr || s[1] == 0)
		fatal("key option must specify [hmac:]keyname:secret");
557
	secretstr = s + 1;
558
559
560
561
562
563
564
565
	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 {
566
#ifndef PK11_MD5_DISABLE
567
		hmacname = DNS_TSIG_HMACMD5_NAME;
568
569
570
#else
		hmacname = DNS_TSIG_HMACSHA256_NAME;
#endif
571
572
573
		name = keystr;
		n = s;
	}
574

575
576
	isc_buffer_init(&keynamesrc, name, (unsigned int)(n - name));
	isc_buffer_add(&keynamesrc, (unsigned int)(n - name));
577

578
	debug("namefromtext");
579
580
	result = dns_name_fromtext(mykeyname, &keynamesrc, dns_rootname, 0,
				   NULL);
581
	check_result(result, "dns_name_fromtext");
582

583
	secretlen = strlen(secretstr) * 3 / 4;
584
	secret = isc_mem_allocate(gmctx, secretlen);
585
586
	if (secret == NULL)
		fatal("out of memory");
587

588
589
590
591
592
593
	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;
594
	}
595

596
597
	secretlen = isc_buffer_usedlength(&secretbuf);

598
	debug("keycreate");
599
600
	result = dns_tsigkey_create(mykeyname, hmacname, secret, secretlen,
				    ISC_FALSE, NULL, 0, 0, gmctx, NULL,
601
				    &tsigkey);
602
	if (result != ISC_R_SUCCESS)
603
		fprintf(stderr, "could not create key from %s: %s\n",
604
			keystr, dns_result_totext(result));
605
606
	else
		dst_key_setbits(tsigkey->key, digestbits);
607
608
 failure:
	if (secret != NULL)
609
		isc_mem_free(gmctx, secret);
610
611
}

612
613
614
615
/*
 * Get a key from a named.conf format keyfile
 */
static isc_result_t
616
read_sessionkey(isc_mem_t *mctx, isc_log_t *lctx) {
617
	cfg_parser_t *pctx = NULL;
618
	cfg_obj_t *sessionkey = NULL;
619
620
621
	const cfg_obj_t *key = NULL;
	const cfg_obj_t *secretobj = NULL;
	const cfg_obj_t *algorithmobj = NULL;
622
	const char *mykeyname;
623
624
625
626
627
628
629
630
631
632
633
634
	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;

635
	result = cfg_parse_file(pctx, keyfile, &cfg_type_sessionkey,
Automatic Updater's avatar
Automatic Updater committed
636
				&sessionkey);
637
638
639
	if (result != ISC_R_SUCCESS)
		goto cleanup;

640
	result = cfg_map_get(sessionkey, "key", &key);
641
642
643
644
645
646
647
648
	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");

649
	mykeyname = cfg_obj_asstring(cfg_map_getname(key));
650
651
652
	secretstr = cfg_obj_asstring(secretobj);
	algorithm = cfg_obj_asstring(algorithmobj);

653
	len = strlen(algorithm) + strlen(mykeyname) + strlen(secretstr) + 3;
654
	keystr = isc_mem_allocate(mctx, len);
655
656
	if (keystr == NULL)
		fatal("out of memory");
657
	snprintf(keystr, len, "%s:%s:%s", algorithm, mykeyname, secretstr);
658
659
660
661
	setup_keystr();

 cleanup:
	if (pctx != NULL) {
662
663
		if (sessionkey != NULL)
			cfg_obj_destroy(pctx, &sessionkey);
664
665
666
667
668
669
670
671
672
		cfg_parser_destroy(&pctx);
	}

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

	return (result);
}

673
static void
674
setup_keyfile(isc_mem_t *mctx, isc_log_t *lctx) {
675
676
	dst_key_t *dstkey = NULL;
	isc_result_t result;
677
	const dns_name_t *hmacname = NULL;
678
679
680

	debug("Creating key...");

681
682
683
	if (sig0key != NULL)
		dst_key_free(&sig0key);

684
	/* Try reading the key from a K* pair */
685
	result = dst_key_fromnamedfile(keyfile, NULL,
686
				       DST_TYPE_PRIVATE | DST_TYPE_KEY, mctx,
687
				       &dstkey);
688

689
	/* If that didn't work, try reading it as a session.key keyfile */
690
	if (result != ISC_R_SUCCESS) {
691
		result = read_sessionkey(mctx, lctx);
692
693
694
695
		if (result == ISC_R_SUCCESS)
			return;
	}

696
	if (result != ISC_R_SUCCESS) {
697
698
699
		fprintf(stderr, "could not read key from %.*s.{private,key}: "
				"%s\n", basenamelen(keyfile), keyfile,
				isc_result_totext(result));
700
701
		return;
	}
702

703
	switch (dst_key_alg(dstkey)) {
704
#ifndef PK11_MD5_DISABLE
705
706
707
	case DST_ALG_HMACMD5:
		hmacname = DNS_TSIG_HMACMD5_NAME;
		break;
708
#endif
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
	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) {
726
		result = dns_tsigkey_createfromkey(dst_key_name(dstkey),
727
						   hmacname, dstkey, ISC_FALSE,
728
729
						   NULL, 0, 0, mctx, NULL,
						   &tsigkey);
730
		dst_key_free(&dstkey);
731
732
733
734
735
		if (result != ISC_R_SUCCESS) {
			fprintf(stderr, "could not create key from %s: %s\n",
				keyfile, isc_result_totext(result));
			return;
		}
736
	} else {
737
		dst_key_attach(dstkey, &sig0key);
738
739
		dst_key_free(&dstkey);
	}
740
741
}

742
static void
743
doshutdown(void) {
744
	isc_task_detach(&global_task);
745

746
747
	/*
	 * The isc_mem_put of master_servers must be before the
Mark Andrews's avatar
Mark Andrews committed
748
749
	 * isc_mem_put of servers as it sets the servers pointer
	 * to NULL.
750
751
	 */
	if (master_servers != NULL && master_servers != servers)
752
		isc_mem_put(gmctx, master_servers,
753
754
			    master_total * sizeof(isc_sockaddr_t));

755
	if (servers != NULL)
756
		isc_mem_put(gmctx, servers, ns_total * sizeof(isc_sockaddr_t));
757

758
	if (localaddr4 != NULL)
759
		isc_mem_put(gmctx, localaddr4, sizeof(isc_sockaddr_t));
760
761

	if (localaddr6 != NULL)
762
		isc_mem_put(gmctx, localaddr6, sizeof(isc_sockaddr_t));
763

764
765
766
767
768
769
770
771
	if (tsigkey != NULL) {
		ddebug("Freeing TSIG key");
		dns_tsigkey_detach(&tsigkey);
	}

	if (sig0key != NULL) {
		ddebug("Freeing SIG(0) key");
		dst_key_free(&sig0key);
772
773
774
775
776
777
	}

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

	if (is_dst_up) {
778
		ddebug("Destroy DST lib");
779
780
781
782
		dst_lib_destroy();
		is_dst_up = ISC_FALSE;
	}

783
	cleanup_entropy(&entropy);
784
785
786
787

	lwres_conf_clear(lwctx);
	lwres_context_destroy(&lwctx);

788
	ddebug("Destroying request manager");
789
790
791
792
793
794
795
796
797
798
799
	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);

800
801
}

802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
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
825
static void
Brian Wellington's avatar
Brian Wellington committed
826
setup_system(void) {
Michael Sawyer's avatar
Michael Sawyer committed
827
	isc_result_t result;
Brian Wellington's avatar
Brian Wellington committed
828
	isc_sockaddr_t bind_any, bind_any6;
829
	lwres_result_t lwresult;
Brian Wellington's avatar
Brian Wellington committed
830
	unsigned int attrs, attrmask;
831
	int i;
832
	isc_logconfig_t *logconfig = NULL;
Michael Sawyer's avatar
Michael Sawyer committed
833

834
	ddebug("setup_system()");
Michael Sawyer's avatar
Michael Sawyer committed
835

836
837
	dns_result_register();

Michael Sawyer's avatar
Michael Sawyer committed
838
	result = isc_net_probeipv4();
Brian Wellington's avatar
Brian Wellington committed
839
840
	if (result == ISC_R_SUCCESS)
		have_ipv4 = ISC_TRUE;
Michael Sawyer's avatar
Michael Sawyer committed
841
842
843

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

Brian Wellington's avatar
Brian Wellington committed
846
	if (!have_ipv4 && !have_ipv6)
847
		fatal("could not find either IPv4 or IPv6");
Brian Wellington's avatar
Brian Wellington committed
848

849
	result = isc_log_create(gmctx, &glctx, &logconfig);
850
851
	check_result(result, "isc_log_create");

852
853
854
	isc_log_setcontext(glctx);
	dns_log_init(glctx);
	dns_log_setcontext(glctx);
855
856
857
858

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

859
	isc_log_setdebuglevel(glctx, logdebuglevel);
860

861
	lwresult = lwres_context_create(&lwctx, gmctx, mem_alloc, mem_free, 1);
862
863
864
	if (lwresult != LWRES_R_SUCCESS)
		fatal("lwres_context_create failed");

865
	(void)lwres_conf_parse(lwctx, RESOLV_CONF);
866
	lwconf = lwres_conf_get(lwctx);
Brian Wellington's avatar
Brian Wellington committed
867

868
869
870
	if (servers != NULL) {
		if (master_servers == servers)
			master_servers = NULL;
871
		isc_mem_put(gmctx, servers, ns_total * sizeof(isc_sockaddr_t));
872
873
	}

874
875
876
877
878
879
880
881
	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;

882
		default_servers = !local_only;
883
884

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

		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);
		}
899
	} else {
900
		ns_total = lwconf->nsnext;
901
		servers = isc_mem_get(gmctx, ns_total * sizeof(isc_sockaddr_t));
902
903
904
		if (servers == NULL)
			fatal("out of memory");
		for (i = 0; i < ns_total; i++) {
905
906
			if (lwconf->nameservers[i].family == LWRES_ADDRTYPE_V4)
			{
907
				struct in_addr in4;
908
909
				memmove(&in4,
					lwconf->nameservers[i].address, 4);
910
911
				isc_sockaddr_fromin(&servers[i],
						    &in4, dnsport);
912
913
			} else {
				struct in6_addr in6;
914
915
				memmove(&in6,
					lwconf->nameservers[i].address, 16);
916
917
				isc_sockaddr_fromin6(&servers[i],
						     &in6, dnsport);
918
			}
919
920
921
		}
	}

922
	setup_entropy(gmctx, NULL, &entropy);
923

924
	result = isc_hash_create(gmctx, entropy, DNS_NAME_MAXWIRE);
925
926
927
	check_result(result, "isc_hash_create");
	isc_hash_init();

928
	result = dns_dispatchmgr_create(gmctx, entropy, &dispatchmgr);
Michael Sawyer's avatar
Michael Sawyer committed
929
930
	check_result(result, "dns_dispatchmgr_create");

931
	result = isc_socketmgr_create(gmctx, &socketmgr);
Michael Sawyer's avatar
Michael Sawyer committed
932
933
	check_result(result, "dns_socketmgr_create");

934
	result = isc_timermgr_create(gmctx, &timermgr);
Michael Sawyer's avatar
Michael Sawyer committed
935
936
	check_result(result, "dns_timermgr_create");

937
	result = isc_taskmgr_create(gmctx, 1, 0, &taskmgr);
Michael Sawyer's avatar
Michael Sawyer committed
938
939
	check_result(result, "isc_taskmgr_create");

940
	result = isc_task_create(taskmgr, 0, &global_task);
Michael Sawyer's avatar
Michael Sawyer committed
941
942
	check_result(result, "isc_task_create");

943
944
945
	result = isc_task_onshutdown(global_task, shutdown_program, NULL);
	check_result(result, "isc_task_onshutdown");

946
	result = dst_lib_init(gmctx, entropy, 0);
Michael Sawyer's avatar
Michael Sawyer committed
947
948
949
	check_result(result, "dst_lib_init");
	is_dst_up = ISC_TRUE;

Brian Wellington's avatar
Brian Wellington committed
950
951
952
953
954
955
956
957
958
959
960
961
962
963
	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
964

Brian Wellington's avatar
Brian Wellington committed
965
966
967
968
969
970
971
972
973
974
975
	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)");
	}
976

977
	result = dns_requestmgr_create(gmctx, timermgr,
Michael Sawyer's avatar
Michael Sawyer committed
978
				       socketmgr, taskmgr, dispatchmgr,
Brian Wellington's avatar
Brian Wellington committed
979
				       dispatchv4, dispatchv6, &requestmgr);
Michael Sawyer's avatar
Michael Sawyer committed
980
981
	check_result(result, "dns_requestmgr_create");

982
983
	if (keystr != NULL)
		setup_keystr();
984
	else if (local_only) {
985
		result = read_sessionkey(gmctx, glctx);
986
987
988
989
		if (result != ISC_R_SUCCESS)
			fatal("can't read key from %s: %s\n",
			      keyfile, isc_result_totext(result));
	} else if (keyfile != NULL)
990
		setup_keyfile(gmctx, glctx);
Michael Sawyer's avatar
Michael Sawyer committed
991
}
Michael Sawyer's avatar
Michael Sawyer committed
992

993
static void
994
995
996
get_addresses(char *host, in_port_t port,
	      isc_sockaddr_t *sockaddr, int naddrs)
{
997
998
	int count;
	isc_result_t result;
999

1000
	isc_app_block();