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

18
/*! \file */
Michael Sawyer's avatar
Michael Sawyer committed
19 20

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

22 23 24 25 26 27
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <unistd.h>

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

52 53
#include <isccfg/namedconf.h>

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

Brian Wellington's avatar
Brian Wellington committed
75 76
#include <dst/dst.h>

77
#include <lwres/lwres.h>
78
#include <lwres/net.h>
79

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

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

95 96 97 98 99 100 101 102
#ifdef HAVE_ADDRINFO
#ifdef HAVE_GETADDRINFO
#ifdef HAVE_GAISTRERROR
#define USE_GETADDRINFO
#endif
#endif
#endif

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

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

117 118
#define DNSDEFAULTPORT 53

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

122 123
static isc_uint16_t dnsport = DNSDEFAULTPORT;

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

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

189 190 191 192 193
typedef struct nsu_requestinfo {
	dns_message_t *msg;
	isc_sockaddr_t *addr;
} nsu_requestinfo_t;

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

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

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
209

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

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

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

236 237 238 239
#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
240

241 242 243 244 245 246 247 248 249 250 251
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
252
setup_entropy(isc_mem_t *mctx, const char *randomfile, isc_entropy_t **ectx) {
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
	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);
}

302 303 304 305
static void
master_from_servers(void) {

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

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

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

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

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

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

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

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

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

386 387 388
static void
mem_free(void *arg, void *mem, size_t size) {
	isc_mem_put(arg, mem, size);
389 390 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 452 453 454 455 456 457 458 459 460 461
static isc_uint16_t
parse_hmac(dns_name_t **hmac, const char *hmacstr, size_t len) {
	isc_uint16_t digestbits = 0;
	isc_result_t result;
	char buf[20];

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

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

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

463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515
	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);
}

516 517
static int
basenamelen(const char *file) {
Automatic Updater's avatar
Automatic Updater committed
518 519 520 521 522 523 524 525
	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;
526 527 528
	return (len);
}

529
static void
530
setup_keystr(void) {
531 532 533 534
	unsigned char *secret = NULL;
	int secretlen;
	isc_buffer_t secretbuf;
	isc_result_t result;
535 536
	isc_buffer_t keynamesrc;
	char *secretstr;
537
	char *s, *n;
538
	dns_fixedname_t fkeyname;
539
	dns_name_t *mykeyname;
540 541 542
	char *name;
	dns_name_t *hmacname = NULL;
	isc_uint16_t digestbits = 0;
543

544
	dns_fixedname_init(&fkeyname);
545
	mykeyname = dns_fixedname_name(&fkeyname);
546

547
	debug("Creating key...");
548

549
	s = strchr(keystr, ':');
550 551
	if (s == NULL || s == keystr || s[1] == 0)
		fatal("key option must specify [hmac:]keyname:secret");
552
	secretstr = s + 1;
553 554 555 556 557 558 559 560 561 562 563 564
	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;
	}
565

566 567
	isc_buffer_init(&keynamesrc, name, (unsigned int)(n - name));
	isc_buffer_add(&keynamesrc, (unsigned int)(n - name));
568

569
	debug("namefromtext");
570 571
	result = dns_name_fromtext(mykeyname, &keynamesrc, dns_rootname, 0,
				   NULL);
572
	check_result(result, "dns_name_fromtext");
573

574
	secretlen = strlen(secretstr) * 3 / 4;
575
	secret = isc_mem_allocate(gmctx, secretlen);
576 577
	if (secret == NULL)
		fatal("out of memory");
578

579 580 581 582 583 584
	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;
585
	}
586

587 588
	secretlen = isc_buffer_usedlength(&secretbuf);

589
	debug("keycreate");
590 591
	result = dns_tsigkey_create(mykeyname, hmacname, secret, secretlen,
				    ISC_FALSE, NULL, 0, 0, gmctx, NULL,
592
				    &tsigkey);
593
	if (result != ISC_R_SUCCESS)
594
		fprintf(stderr, "could not create key from %s: %s\n",
595
			keystr, dns_result_totext(result));
596 597
	else
		dst_key_setbits(tsigkey->key, digestbits);
598 599
 failure:
	if (secret != NULL)
600
		isc_mem_free(gmctx, secret);
601 602
}

603 604 605 606
/*
 * Get a key from a named.conf format keyfile
 */
static isc_result_t
607
read_sessionkey(isc_mem_t *mctx, isc_log_t *lctx) {
608
	cfg_parser_t *pctx = NULL;
609
	cfg_obj_t *sessionkey = NULL;
610 611 612
	const cfg_obj_t *key = NULL;
	const cfg_obj_t *secretobj = NULL;
	const cfg_obj_t *algorithmobj = NULL;
613
	const char *mykeyname;
614 615 616 617 618 619 620 621 622 623 624 625
	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;

626
	result = cfg_parse_file(pctx, keyfile, &cfg_type_sessionkey,
Automatic Updater's avatar
Automatic Updater committed
627
				&sessionkey);
628 629 630
	if (result != ISC_R_SUCCESS)
		goto cleanup;

631
	result = cfg_map_get(sessionkey, "key", &key);
632 633 634 635 636 637 638 639
	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");

640
	mykeyname = cfg_obj_asstring(cfg_map_getname(key));
641 642 643
	secretstr = cfg_obj_asstring(secretobj);
	algorithm = cfg_obj_asstring(algorithmobj);

644
	len = strlen(algorithm) + strlen(mykeyname) + strlen(secretstr) + 3;
645
	keystr = isc_mem_allocate(mctx, len);
646 647
	if (keystr == NULL)
		fatal("out of memory");
648
	snprintf(keystr, len, "%s:%s:%s", algorithm, mykeyname, secretstr);
649 650 651 652
	setup_keystr();

 cleanup:
	if (pctx != NULL) {
653 654
		if (sessionkey != NULL)
			cfg_obj_destroy(pctx, &sessionkey);
655 656 657 658 659 660 661 662 663
		cfg_parser_destroy(&pctx);
	}

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

	return (result);
}

664
static void
665
setup_keyfile(isc_mem_t *mctx, isc_log_t *lctx) {
666 667
	dst_key_t *dstkey = NULL;
	isc_result_t result;
668
	dns_name_t *hmacname = NULL;
669 670 671

	debug("Creating key...");

672 673 674
	if (sig0key != NULL)
		dst_key_free(&sig0key);

675
	/* Try reading the key from a K* pair */
676
	result = dst_key_fromnamedfile(keyfile, NULL,
677
				       DST_TYPE_PRIVATE | DST_TYPE_KEY, mctx,
678
				       &dstkey);
679

680
	/* If that didn't work, try reading it as a session.key keyfile */
681
	if (result != ISC_R_SUCCESS) {
682
		result = read_sessionkey(mctx, lctx);
683 684 685 686
		if (result == ISC_R_SUCCESS)
			return;
	}

687
	if (result != ISC_R_SUCCESS) {
688 689 690
		fprintf(stderr, "could not read key from %.*s.{private,key}: "
				"%s\n", basenamelen(keyfile), keyfile,
				isc_result_totext(result));
691 692
		return;
	}
693

694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714
	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) {
715
		result = dns_tsigkey_createfromkey(dst_key_name(dstkey),
716
						   hmacname, dstkey, ISC_FALSE,
717 718
						   NULL, 0, 0, mctx, NULL,
						   &tsigkey);
719
		dst_key_free(&dstkey);
720 721 722 723 724
		if (result != ISC_R_SUCCESS) {
			fprintf(stderr, "could not create key from %s: %s\n",
				keyfile, isc_result_totext(result));
			return;
		}
725
	} else {
726
		dst_key_attach(dstkey, &sig0key);
727 728
		dst_key_free(&dstkey);
	}
729 730
}

731
static void
732
doshutdown(void) {
733
	isc_task_detach(&global_task);
734

735 736
	/*
	 * The isc_mem_put of master_servers must be before the
Mark Andrews's avatar
Mark Andrews committed
737 738
	 * isc_mem_put of servers as it sets the servers pointer
	 * to NULL.
739 740
	 */
	if (master_servers != NULL && master_servers != servers)
741
		isc_mem_put(gmctx, master_servers,
742 743
			    master_total * sizeof(isc_sockaddr_t));

744
	if (servers != NULL)
745
		isc_mem_put(gmctx, servers, ns_total * sizeof(isc_sockaddr_t));
746

747
	if (localaddr4 != NULL)
748
		isc_mem_put(gmctx, localaddr4, sizeof(isc_sockaddr_t));
749 750

	if (localaddr6 != NULL)
751
		isc_mem_put(gmctx, localaddr6, sizeof(isc_sockaddr_t));
752

753 754 755 756 757 758 759 760
	if (tsigkey != NULL) {
		ddebug("Freeing TSIG key");
		dns_tsigkey_detach(&tsigkey);
	}

	if (sig0key != NULL) {
		ddebug("Freeing SIG(0) key");
		dst_key_free(&sig0key);
761 762 763 764 765 766
	}

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

	if (is_dst_up) {
767
		ddebug("Destroy DST lib");
768 769 770 771
		dst_lib_destroy();
		is_dst_up = ISC_FALSE;
	}

772
	cleanup_entropy(&entropy);
773 774 775 776

	lwres_conf_clear(lwctx);
	lwres_context_destroy(&lwctx);

777
	ddebug("Destroying request manager");
778 779 780 781 782 783 784 785 786 787 788
	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);

789 790
}

791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813
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
814
static void
Brian Wellington's avatar
Brian Wellington committed
815
setup_system(void) {
Michael Sawyer's avatar
Michael Sawyer committed
816
	isc_result_t result;
Brian Wellington's avatar
Brian Wellington committed
817
	isc_sockaddr_t bind_any, bind_any6;
818
	lwres_result_t lwresult;
Brian Wellington's avatar
Brian Wellington committed
819
	unsigned int attrs, attrmask;
820
	int i;
821
	isc_logconfig_t *logconfig = NULL;
Michael Sawyer's avatar
Michael Sawyer committed
822

823
	ddebug("setup_system()");
Michael Sawyer's avatar
Michael Sawyer committed
824

825 826
	dns_result_register();

Michael Sawyer's avatar
Michael Sawyer committed
827
	result = isc_net_probeipv4();
Brian Wellington's avatar
Brian Wellington committed
828 829
	if (result == ISC_R_SUCCESS)
		have_ipv4 = ISC_TRUE;
Michael Sawyer's avatar
Michael Sawyer committed
830 831 832

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

Brian Wellington's avatar
Brian Wellington committed
835
	if (!have_ipv4 && !have_ipv6)
836
		fatal("could not find either IPv4 or IPv6");
Brian Wellington's avatar
Brian Wellington committed
837

838
	result = isc_log_create(gmctx, &glctx, &logconfig);
839 840
	check_result(result, "isc_log_create");

841 842 843
	isc_log_setcontext(glctx);
	dns_log_init(glctx);
	dns_log_setcontext(glctx);
844 845 846 847

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

848
	isc_log_setdebuglevel(glctx, logdebuglevel);
849

850
	lwresult = lwres_context_create(&lwctx, gmctx, mem_alloc, mem_free, 1);
851 852 853
	if (lwresult != LWRES_R_SUCCESS)
		fatal("lwres_context_create failed");

854
	(void)lwres_conf_parse(lwctx, RESOLV_CONF);
855
	lwconf = lwres_conf_get(lwctx);
Brian Wellington's avatar
Brian Wellington committed
856

857 858 859
	if (servers != NULL) {
		if (master_servers == servers)
			master_servers = NULL;
860
		isc_mem_put(gmctx, servers, ns_total * sizeof(isc_sockaddr_t));
861 862
	}

863 864 865 866 867 868 869 870
	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;

871
		default_servers = !local_only;
872 873

		ns_total = (have_ipv4 ? 1 : 0) + (have_ipv6 ? 1 : 0);
874
		servers = isc_mem_get(gmctx, ns_total * sizeof(isc_sockaddr_t));
875 876
		if (servers == NULL)
			fatal("out of memory");
877 878 879 880 881 882 883 884 885 886 887

		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);
		}
888
	} else {
889
		ns_total = lwconf->nsnext;
890
		servers = isc_mem_get(gmctx, ns_total * sizeof(isc_sockaddr_t));
891 892 893
		if (servers == NULL)
			fatal("out of memory");
		for (i = 0; i < ns_total; i++) {
894 895
			if (lwconf->nameservers[i].family == LWRES_ADDRTYPE_V4)
			{
896
				struct in_addr in4;
897 898
				memmove(&in4,
					lwconf->nameservers[i].address, 4);
899 900
				isc_sockaddr_fromin(&servers[i],
						    &in4, dnsport);
901 902
			} else {
				struct in6_addr in6;
903 904
				memmove(&in6,
					lwconf->nameservers[i].address, 16);
905 906
				isc_sockaddr_fromin6(&servers[i],
						     &in6, dnsport);
907
			}
908 909 910
		}
	}

911
	setup_entropy(gmctx, NULL, &entropy);
912

913
	result = isc_hash_create(gmctx, entropy, DNS_NAME_MAXWIRE);
914 915 916
	check_result(result, "isc_hash_create");
	isc_hash_init();

917
	result = dns_dispatchmgr_create(gmctx, entropy, &dispatchmgr);
Michael Sawyer's avatar
Michael Sawyer committed
918 919
	check_result(result, "dns_dispatchmgr_create");

920
	result = isc_socketmgr_create(gmctx, &socketmgr);
Michael Sawyer's avatar
Michael Sawyer committed
921 922
	check_result(result, "dns_socketmgr_create");