dighost.c 159 KB
Newer Older
1
/*
Tinderbox User's avatar
Tinderbox User committed
2
 * Copyright (C) 2004-2014  Internet Systems Consortium, Inc. ("ISC")
Mark Andrews's avatar
Mark Andrews committed
3
 * Copyright (C) 2000-2003  Internet Software Consortium.
4
 *
Automatic Updater's avatar
Automatic Updater committed
5
 * Permission to use, copy, modify, and/or distribute this software for any
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.
16
17
 */

18
19
/*! \file
 *  \note
20
21
22
23
24
25
26
27
 * Notice to programmers:  Do not use this code as an example of how to
 * use the ISC library to perform DNS lookups.  Dig and Host both operate
 * on the request level, since they allow fine-tuning of output and are
 * intended as debugging tools.  As a result, they perform many of the
 * functions which could be better handled using the dns_resolver
 * functions in most applications.
 */

28
29
30
#include <config.h>
#include <stdlib.h>
#include <unistd.h>
31
#include <string.h>
32
#include <limits.h>
33

34
35
36
37
38
39
40
41
42
43
44
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif

#ifdef WITH_IDN
#include <idn/result.h>
#include <idn/log.h>
#include <idn/resconf.h>
#include <idn/api.h>
#endif

45
#include <dns/byaddr.h>
46
#ifdef DIG_SIGCHASE
47
#include <dns/callbacks.h>
48
49
#include <dns/dnssec.h>
#include <dns/ds.h>
50
#include <dns/master.h>
51
52
53
54
#include <dns/nsec.h>
#include <isc/random.h>
#include <ctype.h>
#endif
55
#include <dns/fixedname.h>
56
#include <dns/log.h>
57
#include <dns/message.h>
Brian Wellington's avatar
Brian Wellington committed
58
#include <dns/name.h>
59
60
#include <dns/rdata.h>
#include <dns/rdataclass.h>
Michael Sawyer's avatar
Michael Sawyer committed
61
#include <dns/rdatalist.h>
62
#include <dns/rdataset.h>
Michael Sawyer's avatar
Michael Sawyer committed
63
#include <dns/rdatastruct.h>
64
65
#include <dns/rdatatype.h>
#include <dns/result.h>
66
#include <dns/tsig.h>
67

68
#include <dst/dst.h>
69
#include <dst/result.h>
70

Michael Sawyer's avatar
Michael Sawyer committed
71
72
73
#include <isc/app.h>
#include <isc/base64.h>
#include <isc/entropy.h>
74
#include <isc/file.h>
75
#include <isc/hex.h>
Michael Sawyer's avatar
Michael Sawyer committed
76
#include <isc/lang.h>
77
#include <isc/log.h>
78
#include <isc/netaddr.h>
79
#include <isc/netdb.h>
80
#include <isc/parseint.h>
Mark Andrews's avatar
Mark Andrews committed
81
#include <isc/print.h>
82
#include <isc/random.h>
Michael Sawyer's avatar
Michael Sawyer committed
83
#include <isc/result.h>
84
#include <isc/serial.h>
Evan Hunt's avatar
Evan Hunt committed
85
#include <isc/sockaddr.h>
Michael Sawyer's avatar
Michael Sawyer committed
86
87
88
89
90
#include <isc/string.h>
#include <isc/task.h>
#include <isc/timer.h>
#include <isc/types.h>
#include <isc/util.h>
91

92
93
#include <isccfg/namedconf.h>

94
95
96
#include <lwres/lwres.h>
#include <lwres/net.h>

97
#include <bind9/getaddresses.h>
98

99
#include <dig/dig.h>
100

101
102
103
104
105
106
107
108
#if ! defined(NS_INADDRSZ)
#define NS_INADDRSZ	 4
#endif

#if ! defined(NS_IN6ADDRSZ)
#define NS_IN6ADDRSZ	16
#endif

109
110
111
static lwres_context_t *lwctx = NULL;
static lwres_conf_t *lwconf;

112
dig_lookuplist_t lookup_list;
113
dig_serverlist_t server_list;
114
dig_searchlistlist_t search_list;
115

116
isc_boolean_t
117
	check_ra = ISC_FALSE,
118
	have_ipv4 = ISC_FALSE,
119
120
121
	have_ipv6 = ISC_FALSE,
	specified_source = ISC_FALSE,
	free_now = ISC_FALSE,
122
	cancel_now = ISC_FALSE,
123
	usesearch = ISC_FALSE,
124
	showsearch = ISC_FALSE,
125
	qr = ISC_FALSE,
126
	is_dst_up = ISC_FALSE,
127
128
	keep_open = ISC_FALSE,
	verbose = ISC_FALSE;
129
in_port_t port = 53;
130
unsigned int timeout = 0;
131
unsigned int extrabytes;
132
isc_mem_t *mctx = NULL;
133
isc_log_t *lctx = NULL;
134
isc_taskmgr_t *taskmgr = NULL;
135
isc_task_t *global_task = NULL;
136
137
isc_timermgr_t *timermgr = NULL;
isc_socketmgr_t *socketmgr = NULL;
138
isc_sockaddr_t bind_address;
Michael Sawyer's avatar
Michael Sawyer committed
139
isc_sockaddr_t bind_any;
140
int sendcount = 0;
141
int recvcount = 0;
Michael Sawyer's avatar
Michael Sawyer committed
142
int sockcount = 0;
143
int ndots = -1;
144
int tries = 3;
145
int lookup_counter = 0;
146

147
148
149
150
151
152
153
154
155
156
#ifdef WITH_IDN
static void		initialize_idn(void);
static isc_result_t	output_filter(isc_buffer_t *buffer,
				      unsigned int used_org,
				      isc_boolean_t absolute);
static idn_result_t	append_textname(char *name, const char *origin,
					size_t namesize);
static void		idn_check_result(idn_result_t r, const char *msg);

#define MAXDLEN		256
157
int  idnoptions	= 0;
158
159
#endif

160
161
162
isc_socket_t *keep = NULL;
isc_sockaddr_t keepaddr;

163
/*%
164
 * Exit Codes:
165
 *
166
167
168
169
170
171
 *\li	0   Everything went well, including things like NXDOMAIN
 *\li	1   Usage error
 *\li	7   Got too many RR's or Names
 *\li	8   Couldn't open batch file
 *\li	9   No reply from server
 *\li	10  Internal error
172
173
 */
int exitcode = 0;
174
int fatalexit = 0;
175
char keynametext[MXNAME];
176
char keyfile[MXNAME] = "";
177
char keysecret[MXNAME] = "";
178
179
unsigned char cookie_secret[33];
unsigned char cookie[8];
180
181
dns_name_t *hmacname = NULL;
unsigned int digestbits = 0;
182
183
isc_buffer_t *namebuf = NULL;
dns_tsigkey_t *key = NULL;
184
isc_boolean_t validated = ISC_TRUE;
185
isc_entropy_t *entp = NULL;
186
isc_mempool_t *commctx = NULL;
187
isc_boolean_t debugging = ISC_FALSE;
188
isc_boolean_t debugtiming = ISC_FALSE;
189
isc_boolean_t memdebugging = ISC_FALSE;
Michael Sawyer's avatar
Michael Sawyer committed
190
char *progname = NULL;
191
isc_mutex_t lookup_lock;
192
dig_lookup_t *current_lookup = NULL;
193

194
195
#ifdef DIG_SIGCHASE

196
isc_result_t	  get_trusted_key(isc_mem_t *mctx);
197
198
199
200
201
202
203
204
205
dns_rdataset_t *  sigchase_scanname(dns_rdatatype_t type,
				    dns_rdatatype_t covers,
				    isc_boolean_t *lookedup,
				    dns_name_t *rdata_name);
dns_rdataset_t *  chase_scanname_section(dns_message_t *msg,
					 dns_name_t *name,
					 dns_rdatatype_t type,
					 dns_rdatatype_t covers,
					 int section);
206
isc_result_t	  advanced_rrsearch(dns_rdataset_t **rdataset,
207
208
209
210
				    dns_name_t *name,
				    dns_rdatatype_t type,
				    dns_rdatatype_t covers,
				    isc_boolean_t *lookedup);
211
isc_result_t	  sigchase_verify_sig_key(dns_name_t *name,
212
213
214
215
					  dns_rdataset_t *rdataset,
					  dst_key_t* dnsseckey,
					  dns_rdataset_t *sigrdataset,
					  isc_mem_t *mctx);
216
isc_result_t	  sigchase_verify_sig(dns_name_t *name,
217
218
219
220
				      dns_rdataset_t *rdataset,
				      dns_rdataset_t *keyrdataset,
				      dns_rdataset_t *sigrdataset,
				      isc_mem_t *mctx);
221
isc_result_t	  sigchase_verify_ds(dns_name_t *name,
222
223
224
				     dns_rdataset_t *keyrdataset,
				     dns_rdataset_t *dsrdataset,
				     isc_mem_t *mctx);
225
226
227
void		  sigchase(dns_message_t *msg);
void		  print_rdata(dns_rdata_t *rdata, isc_mem_t *mctx);
void		  print_rdataset(dns_name_t *name,
228
				 dns_rdataset_t *rdataset, isc_mem_t *mctx);
229
void		  dup_name(dns_name_t *source, dns_name_t* target,
230
			   isc_mem_t *mctx);
231
232
233
void		  free_name(dns_name_t *name, isc_mem_t *mctx);
void		  dump_database(void);
void		  dump_database_section(dns_message_t *msg, int section);
234
235
dns_rdataset_t *  search_type(dns_name_t *name, dns_rdatatype_t type,
			      dns_rdatatype_t covers);
236
isc_result_t	  contains_trusted_key(dns_name_t *name,
237
238
239
				       dns_rdataset_t *rdataset,
				       dns_rdataset_t *sigrdataset,
				       isc_mem_t *mctx);
240
241
void		  print_type(dns_rdatatype_t type);
isc_result_t	  prove_nx_domain(dns_message_t * msg,
242
243
244
245
				  dns_name_t * name,
				  dns_name_t * rdata_name,
				  dns_rdataset_t ** rdataset,
				  dns_rdataset_t ** sigrdataset);
246
isc_result_t	  prove_nx_type(dns_message_t * msg, dns_name_t *name,
247
248
249
250
251
252
				dns_rdataset_t *nsec,
				dns_rdataclass_t class,
				dns_rdatatype_t type,
				dns_name_t * rdata_name,
				dns_rdataset_t ** rdataset,
				dns_rdataset_t ** sigrdataset);
253
isc_result_t	  prove_nx(dns_message_t * msg, dns_name_t * name,
254
255
256
257
258
			   dns_rdataclass_t class,
			   dns_rdatatype_t type,
			   dns_name_t * rdata_name,
			   dns_rdataset_t ** rdataset,
			   dns_rdataset_t ** sigrdataset);
259
static void	  nameFromString(const char *str, dns_name_t *p_ret);
260
261
262
int		  inf_name(dns_name_t * name1, dns_name_t * name2);
isc_result_t	  removetmpkey(isc_mem_t *mctx, const char *file);
void		  clean_trustedkey(void);
263
264
isc_result_t 	  insert_trustedkey(void *arg, dns_name_t *name,
				    dns_rdataset_t *rdataset);
265
#if DIG_SIGCHASE_BU
266
267
268
isc_result_t	  getneededrr(dns_message_t *msg);
void		  sigchase_bottom_up(dns_message_t *msg);
void		  sigchase_bu(dns_message_t *msg);
269
270
#endif
#if DIG_SIGCHASE_TD
271
272
273
isc_result_t	  initialization(dns_name_t *name);
isc_result_t	  prepare_lookup(dns_name_t *name);
isc_result_t	  grandfather_pb_test(dns_name_t * zone_name,
274
				      dns_rdataset_t *sigrdataset);
275
isc_result_t	  child_of_zone(dns_name_t *name,
276
277
				dns_name_t *zone_name,
				dns_name_t *child_name);
278
void		  sigchase_td(dns_message_t *msg);
279
280
281
#endif
char trustedkey[MXNAME] = "";

282
283
284
285
286
287
288
dns_rdataset_t *chase_rdataset = NULL;
dns_rdataset_t *chase_sigrdataset = NULL;
dns_rdataset_t *chase_dsrdataset = NULL;
dns_rdataset_t *chase_sigdsrdataset = NULL;
dns_rdataset_t *chase_keyrdataset = NULL;
dns_rdataset_t *chase_sigkeyrdataset = NULL;
dns_rdataset_t *chase_nsrdataset = NULL;
289

290
dns_name_t chase_name; /* the query name */
291
292
293
294
#if DIG_SIGCHASE_TD
/*
 * the current name is the parent name when we follow delegation
 */
Automatic Updater's avatar
Automatic Updater committed
295
dns_name_t chase_current_name;
296
297
298
/*
 * the child name is used for delegation (NS DS responses in AUTHORITY section)
 */
299
dns_name_t chase_authority_name;
300
301
#endif
#if DIG_SIGCHASE_BU
302
dns_name_t chase_signame;
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
#endif


isc_boolean_t chase_siglookedup = ISC_FALSE;
isc_boolean_t chase_keylookedup = ISC_FALSE;
isc_boolean_t chase_sigkeylookedup = ISC_FALSE;
isc_boolean_t chase_dslookedup = ISC_FALSE;
isc_boolean_t chase_sigdslookedup = ISC_FALSE;
#if DIG_SIGCHASE_TD
isc_boolean_t chase_nslookedup = ISC_FALSE;
isc_boolean_t chase_lookedup = ISC_FALSE;


isc_boolean_t delegation_follow = ISC_FALSE;
isc_boolean_t grandfather_pb = ISC_FALSE;
isc_boolean_t have_response = ISC_FALSE;
isc_boolean_t have_delegation_ns = ISC_FALSE;
dns_message_t * error_message = NULL;
#endif

isc_boolean_t dsvalidating = ISC_FALSE;
324
isc_boolean_t chase_name_dup = ISC_FALSE;
325
326
327
328
329
330
331

ISC_LIST(dig_message_t) chase_message_list;
ISC_LIST(dig_message_t) chase_message_list2;


#define MAX_TRUSTED_KEY 5
typedef struct struct_trusted_key_list {
332
333
	dst_key_t * key[MAX_TRUSTED_KEY];
	int nb_tk;
334
335
} struct_tk_list;

336
struct_tk_list tk_list = { {NULL, NULL, NULL, NULL, NULL}, 0};
337
338
339

#endif

340
341
#define DIG_MAX_ADDRESSES 20

342
/*%
343
 * Apply and clear locks at the event level in global task.
344
 * Can I get rid of these using shutdown events?  XXX
345
346
 */
#define LOCK_LOOKUP {\
Brian Wellington's avatar
Brian Wellington committed
347
348
349
	debug("lock_lookup %s:%d", __FILE__, __LINE__);\
	check_result(isc_mutex_lock((&lookup_lock)), "isc_mutex_lock");\
	debug("success");\
350
351
}
#define UNLOCK_LOOKUP {\
Brian Wellington's avatar
Brian Wellington committed
352
353
354
	debug("unlock_lookup %s:%d", __FILE__, __LINE__);\
	check_result(isc_mutex_unlock((&lookup_lock)),\
		     "isc_mutex_unlock");\
355
}
356

357
static void
358
359
cancel_lookup(dig_lookup_t *lookup);

Michael Sawyer's avatar
Michael Sawyer committed
360
361
362
static void
recv_done(isc_task_t *task, isc_event_t *event);

363
364
365
static void
send_udp(dig_query_t *query);

Michael Sawyer's avatar
Michael Sawyer committed
366
367
368
static void
connect_timeout(isc_task_t *task, isc_event_t *event);

369
370
371
static void
launch_next_query(dig_query_t *query, isc_boolean_t include_question);

372
373
374
375
376
377
378
379
380
381
382

static void *
mem_alloc(void *arg, size_t size) {
	return (isc_mem_get(arg, size));
}

static void
mem_free(void *arg, void *mem, size_t size) {
	isc_mem_put(arg, mem, size);
}

Mark Andrews's avatar
Mark Andrews committed
383
char *
384
385
386
387
388
389
390
391
392
next_token(char **stringp, const char *delim) {
	char *res;

	do {
		res = strsep(stringp, delim);
		if (res == NULL)
			break;
	} while (*res == '\0');
	return (res);
Brian Wellington's avatar
Brian Wellington committed
393
}
394

395
396
397
static int
count_dots(char *string) {
	char *s;
398
	int i = 0;
399
400

	s = string;
401
	while (*s != '\0') {
402
403
404
405
406
407
408
		if (*s == '.')
			i++;
		s++;
	}
	return (i);
}

409
static void
410
hex_dump(isc_buffer_t *b) {
411
	unsigned int len, i;
412
413
	isc_region_t r;

414
	isc_buffer_usedregion(b, &r);
415

416
	printf("%d bytes\n", r.length);
417
	for (len = 0; len < r.length; len++) {
418
		printf("%02x ", r.base[len]);
419
420
421
422
423
		if (len % 16 == 15) {
			fputs("         ", stdout);
			for (i = len - 15; i <= len; i++) {
				if (r.base[i] >= '!' && r.base[i] <= '}')
					putchar(r.base[i]);
Automatic Updater's avatar
Automatic Updater committed
424
				else
425
426
					putchar('.');
			}
427
			printf("\n");
428
		}
429
	}
430
431
432
433
434
435
436
	if (len % 16 != 0) {
		for (i = len; (i % 16) != 0; i++)
			fputs("   ", stdout);
		fputs("         ", stdout);
		for (i = ((len>>4)<<4); i < len; i++) {
			if (r.base[i] >= '!' && r.base[i] <= '}')
				putchar(r.base[i]);
Automatic Updater's avatar
Automatic Updater committed
437
			else
438
439
				putchar('.');
		}
440
		printf("\n");
441
	}
442
443
}

444
/*%
445
446
447
448
449
450
451
 * Append 'len' bytes of 'text' at '*p', failing with
 * ISC_R_NOSPACE if that would advance p past 'end'.
 */
static isc_result_t
append(const char *text, int len, char **p, char *end) {
	if (len > end - *p)
		return (ISC_R_NOSPACE);
452
	memmove(*p, text, len);
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
	*p += len;
	return (ISC_R_SUCCESS);
}

static isc_result_t
reverse_octets(const char *in, char **p, char *end) {
	char *dot = strchr(in, '.');
	int len;
	if (dot != NULL) {
		isc_result_t result;
		result = reverse_octets(dot + 1, p, end);
		if (result != ISC_R_SUCCESS)
			return (result);
		result = append(".", 1, p, end);
		if (result != ISC_R_SUCCESS)
			return (result);
469
		len = (int)(dot - in);
470
471
472
473
474
	} else {
		len = strlen(in);
	}
	return (append(in, len, p, end));
}
475
476

isc_result_t
477
get_reverse(char *reverse, size_t len, char *value, isc_boolean_t ip6_int,
478
479
480
	    isc_boolean_t strict)
{
	int r;
481
	isc_result_t result;
482
	isc_netaddr_t addr;
483

484
	addr.family = AF_INET6;
Andreas Gustafsson's avatar
spacing    
Andreas Gustafsson committed
485
	r = inet_pton(AF_INET6, value, &addr.type.in6);
486
487
	if (r > 0) {
		/* This is a valid IPv6 address. */
488
489
		dns_fixedname_t fname;
		dns_name_t *name;
Mark Andrews's avatar
Mark Andrews committed
490
491
		unsigned int options = 0;

492
493
		if (ip6_int)
			options |= DNS_BYADDROPT_IPV6INT;
494
495
		dns_fixedname_init(&fname);
		name = dns_fixedname_name(&fname);
496
		result = dns_byaddr_createptrname2(&addr, options, name);
497
498
		if (result != ISC_R_SUCCESS)
			return (result);
499
		dns_name_format(name, reverse, (unsigned int)len);
500
501
502
503
504
505
506
507
508
509
510
		return (ISC_R_SUCCESS);
	} else {
		/*
		 * Not a valid IPv6 address.  Assume IPv4.
		 * If 'strict' is not set, construct the
		 * in-addr.arpa name by blindly reversing
		 * octets whether or not they look like integers,
		 * so that this can be used for RFC2317 names
		 * and such.
		 */
		char *p = reverse;
511
		char *end = reverse + len;
Michael Graff's avatar
Michael Graff committed
512
513
		if (strict && inet_pton(AF_INET, value, &addr.type.in) != 1)
			return (DNS_R_BADDOTTEDQUAD);
514
515
516
517
518
519
520
521
		result = reverse_octets(value, &p, end);
		if (result != ISC_R_SUCCESS)
			return (result);
		/* Append .in-addr.arpa. and a terminating NUL. */
		result = append(".in-addr.arpa.", 15, &p, end);
		if (result != ISC_R_SUCCESS)
			return (result);
		return (ISC_R_SUCCESS);
522
523
524
	}
}

525
void
David Lawrence's avatar
David Lawrence committed
526
fatal(const char *format, ...) {
527
528
	va_list args;

529
	fflush(stdout);
530
	fprintf(stderr, "%s: ", progname);
531
	va_start(args, format);
532
533
534
	vfprintf(stderr, format, args);
	va_end(args);
	fprintf(stderr, "\n");
535
536
	if (exitcode < 10)
		exitcode = 10;
537
538
	if (fatalexit != 0)
		exitcode = fatalexit;
539
	exit(exitcode);
540
541
}

542
void
David Lawrence's avatar
David Lawrence committed
543
debug(const char *format, ...) {
544
	va_list args;
Evan Hunt's avatar
Evan Hunt committed
545
	isc_time_t t;
546

547
	if (debugging) {
548
		fflush(stdout);
549
		if (debugtiming) {
Evan Hunt's avatar
Evan Hunt committed
550
			TIME_NOW(&t);
551
552
			fprintf(stderr, "%d.%06d: ", isc_time_seconds(&t),
				isc_time_nanoseconds(&t) / 1000);
553
		}
554
		va_start(args, format);
555
556
557
558
		vfprintf(stderr, format, args);
		va_end(args);
		fprintf(stderr, "\n");
	}
559
560
}

561
void
David Lawrence's avatar
David Lawrence committed
562
check_result(isc_result_t result, const char *msg) {
563
	if (result != ISC_R_SUCCESS) {
564
		fatal("%s: %s", msg, isc_result_totext(result));
565
	}
566
567
}

568
/*%
Michael Sawyer's avatar
Michael Sawyer committed
569
570
571
572
 * Create a server structure, which is part of the lookup structure.
 * This is little more than a linked list of servers to query in hopes
 * of finding the answer the user is looking for
 */
573
dig_server_t *
574
make_server(const char *servname, const char *userarg) {
575
576
577
578
	dig_server_t *srv;

	REQUIRE(servname != NULL);

579
	debug("make_server(%s)", servname);
580
581
	srv = isc_mem_allocate(mctx, sizeof(struct dig_server));
	if (srv == NULL)
582
		fatal("memory allocation failure in %s:%d",
583
		      __FILE__, __LINE__);
584
585
	strlcpy(srv->servername, servname, MXNAME);
	strlcpy(srv->userarg, userarg, MXNAME);
586
	ISC_LINK_INIT(srv, link);
587
588
	return (srv);
}
589

590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
static int
addr2af(int lwresaddrtype)
{
	int af = 0;

	switch (lwresaddrtype) {
	case LWRES_ADDRTYPE_V4:
		af = AF_INET;
		break;

	case LWRES_ADDRTYPE_V6:
		af = AF_INET6;
		break;
	}

	return (af);
}
607

608
/*%
609
610
611
 * Create a copy of the server list from the lwres configuration structure.
 * The dest list must have already had ISC_LIST_INIT applied.
 */
612
static void
613
614
copy_server_list(lwres_conf_t *confdata, dig_serverlist_t *dest) {
	dig_server_t *newsrv;
Mark Andrews's avatar
Mark Andrews committed
615
616
	char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") +
		 sizeof("%4000000000")];
617
618
619
620
621
622
623
	int af;
	int i;

	debug("copy_server_list()");
	for (i = 0; i < confdata->nsnext; i++) {
		af = addr2af(confdata->nameservers[i].family);

624
625
626
627
628
		if (af == AF_INET && !have_ipv4)
			continue;
		if (af == AF_INET6 && !have_ipv6)
			continue;

629
630
		lwres_net_ntop(af, confdata->nameservers[i].address,
				   tmp, sizeof(tmp));
Mark Andrews's avatar
Mark Andrews committed
631
632
633
634
635
636
		if (af == AF_INET6 && confdata->nameservers[i].zone != 0) {
			char buf[sizeof("%4000000000")];
			snprintf(buf, sizeof(buf), "%%%u",
				 confdata->nameservers[i].zone);
			strlcat(tmp, buf, sizeof(tmp));
		}
637
		newsrv = make_server(tmp, tmp);
638
639
640
641
		ISC_LINK_INIT(newsrv, link);
		ISC_LIST_ENQUEUE(*dest, newsrv, link);
	}
}
642

643
644
645
646
647
648
649
650
651
652
653
654
655
void
flush_server_list(void) {
	dig_server_t *s, *ps;

	debug("flush_server_list()");
	s = ISC_LIST_HEAD(server_list);
	while (s != NULL) {
		ps = s;
		s = ISC_LIST_NEXT(s, link);
		ISC_LIST_DEQUEUE(server_list, ps, link);
		isc_mem_free(mctx, ps);
	}
}
656

657
658
void
set_nameserver(char *opt) {
659
660
661
	isc_result_t result;
	isc_sockaddr_t sockaddrs[DIG_MAX_ADDRESSES];
	isc_netaddr_t netaddr;
Mark Andrews's avatar
Mark Andrews committed
662
	int count, i;
663
	dig_server_t *srv;
664
	char tmp[ISC_NETADDR_FORMATSIZE];
665
666
667
668

	if (opt == NULL)
		return;

669
	result = bind9_getaddresses(opt, 0, sockaddrs,
Automatic Updater's avatar
Automatic Updater committed
670
				    DIG_MAX_ADDRESSES, &count);
671
672
673
674
	if (result != ISC_R_SUCCESS)
		fatal("couldn't get address for '%s': %s",
		      opt, isc_result_totext(result));

675
	flush_server_list();
Automatic Updater's avatar
Automatic Updater committed
676

677
678
679
680
681
682
683
684
	for (i = 0; i < count; i++) {
		isc_netaddr_fromsockaddr(&netaddr, &sockaddrs[i]);
		isc_netaddr_format(&netaddr, tmp, sizeof(tmp));
		srv = make_server(tmp, opt);
		if (srv == NULL)
			fatal("memory allocation failure");
		ISC_LIST_APPEND(server_list, srv, link);
	}
685
686
}

687
static isc_result_t
Mark Andrews's avatar
Mark Andrews committed
688
add_nameserver(lwres_conf_t *confdata, const char *addr, int af) {
689
690
691
692
693
694

	int i = confdata->nsnext;

	if (confdata->nsnext >= LWRES_CONFMAXNAMESERVERS)
		return (ISC_R_FAILURE);

695
696
697
698
699
700
701
702
703
704
705
706
707
708
	switch (af) {
	case AF_INET:
		confdata->nameservers[i].family = LWRES_ADDRTYPE_V4;
		confdata->nameservers[i].length = NS_INADDRSZ;
		break;
	case AF_INET6:
		confdata->nameservers[i].family = LWRES_ADDRTYPE_V6;
		confdata->nameservers[i].length = NS_IN6ADDRSZ;
		break;
	default:
		return (ISC_R_FAILURE);
	}

	if (lwres_net_pton(af, addr, &confdata->nameservers[i].address) == 1) {
709
710
711
712
713
		confdata->nsnext++;
		return (ISC_R_SUCCESS);
	}
	return (ISC_R_FAILURE);
}
714

715
/*%
Michael Sawyer's avatar
Michael Sawyer committed
716
717
718
 * Produce a cloned server list.  The dest list must have already had
 * ISC_LIST_INIT applied.
 */
719
void
720
clone_server_list(dig_serverlist_t src, dig_serverlist_t *dest) {
721
722
723
724
725
	dig_server_t *srv, *newsrv;

	debug("clone_server_list()");
	srv = ISC_LIST_HEAD(src);
	while (srv != NULL) {
726
		newsrv = make_server(srv->servername, srv->userarg);
727
		ISC_LINK_INIT(newsrv, link);
728
729
730
731
732
		ISC_LIST_ENQUEUE(*dest, newsrv, link);
		srv = ISC_LIST_NEXT(srv, link);
	}
}

733
/*%
Michael Sawyer's avatar
Michael Sawyer committed
734
735
736
737
738
 * Create an empty lookup structure, which holds all the information needed
 * to get an answer to a user's question.  This structure contains two
 * linked lists: the server list (servers to query) and the query list
 * (outstanding queries which have been made to the listed servers).
 */
739
dig_lookup_t *
740
make_empty_lookup(void) {
741
742
	dig_lookup_t *looknew;

Michael Sawyer's avatar
Michael Sawyer committed
743
	debug("make_empty_lookup()");
744

745
	INSIST(!free_now);
746

747
	looknew = isc_mem_allocate(mctx, sizeof(struct dig_lookup));
748
	if (looknew == NULL)
749
		fatal("memory allocation failure in %s:%d",
750
		       __FILE__, __LINE__);
751
	looknew->pending = ISC_TRUE;
Andreas Gustafsson's avatar
spacing    
Andreas Gustafsson committed
752
	looknew->textname[0] = 0;
753
	looknew->cmdline[0] = 0;
Ben Cottrell's avatar
Ben Cottrell committed
754
	looknew->rdtype = dns_rdatatype_a;
755
	looknew->qrdtype = dns_rdatatype_a;
Ben Cottrell's avatar
Ben Cottrell committed
756
	looknew->rdclass = dns_rdataclass_in;
Michael Sawyer's avatar
Michael Sawyer committed
757
758
	looknew->rdtypeset = ISC_FALSE;
	looknew->rdclassset = ISC_FALSE;
759
	looknew->sendspace = NULL;
760
761
762
	looknew->sendmsg = NULL;
	looknew->name = NULL;
	looknew->oname = NULL;
763
764
	looknew->timer = NULL;
	looknew->xfr_q = NULL;
Michael Sawyer's avatar
Michael Sawyer committed
765
	looknew->current_query = NULL;
766
	looknew->doing_xfr = ISC_FALSE;
767
	looknew->ixfr_serial = 0;
768
769
770
	looknew->trace = ISC_FALSE;
	looknew->trace_root = ISC_FALSE;
	looknew->identify = ISC_FALSE;
Ben Cottrell's avatar
Ben Cottrell committed
771
	looknew->identify_previous_line = ISC_FALSE;
Michael Sawyer's avatar
Michael Sawyer committed
772
	looknew->ignore = ISC_FALSE;
773
	looknew->servfail_stops = ISC_TRUE;
774
	looknew->besteffort = ISC_TRUE;
775
	looknew->dnssec = ISC_FALSE;
776
	looknew->expire = ISC_FALSE;
777
	looknew->nsid = ISC_FALSE;
778
779
780
#ifdef ISC_PLATFORM_USESIT
	looknew->sit = ISC_FALSE;
#endif
781
782
783
#ifdef DIG_SIGCHASE
	looknew->sigchase = ISC_FALSE;
#if DIG_SIGCHASE_TD
784
	looknew->do_topdown = ISC_FALSE;
785
786
787
788
789
	looknew->trace_root_sigchase = ISC_FALSE;
	looknew->rdtype_sigchaseset = ISC_FALSE;
	looknew->rdtype_sigchase = dns_rdatatype_any;
	looknew->qrdtype_sigchase = dns_rdatatype_any;
	looknew->rdclass_sigchase = dns_rdataclass_in;
790
	looknew->rdclass_sigchaseset = ISC_FALSE;
791
792
#endif
#endif
793
	looknew->udpsize = 0;
794
	looknew->edns = -1;
795
	looknew->recurse = ISC_TRUE;
Michael Sawyer's avatar
Michael Sawyer committed
796
	looknew->aaonly = ISC_FALSE;
797
798
799
800
	looknew->adflag = ISC_FALSE;
	looknew->cdflag = ISC_FALSE;
	looknew->ns_search_only = ISC_FALSE;
	looknew->origin = NULL;
801
	looknew->tsigctx = NULL;
802
803
804
805
	looknew->querysig = NULL;
	looknew->retries = tries;
	looknew->nsfound = 0;
	looknew->tcp_mode = ISC_FALSE;
806
	looknew->tcp_mode_set = ISC_FALSE;
807
	looknew->ip6_int = ISC_FALSE;
808
809
810
811
812
813
814
	looknew->comments = ISC_TRUE;
	looknew->stats = ISC_TRUE;
	looknew->section_question = ISC_TRUE;
	looknew->section_answer = ISC_TRUE;
	looknew->section_authority = ISC_TRUE;
	looknew->section_additional = ISC_TRUE;
	looknew->new_search = ISC_FALSE;
815
816
	looknew->done_as_is = ISC_FALSE;
	looknew->need_search = ISC_FALSE;
Evan Hunt's avatar
Evan Hunt committed
817
	looknew->ecs_addr = NULL;
818
819
820
#ifdef ISC_PLATFORM_USESIT
	looknew->sitvalue = NULL;
#endif
821
822
	looknew->ednsopts = NULL;
	looknew->ednsoptscnt = 0;
823
	looknew->dscp = -1;
824
	dns_fixedname_init(&looknew->fdomain);
825
	ISC_LINK_INIT(looknew, link);
826
	ISC_LIST_INIT(looknew->q);
827
	ISC_LIST_INIT(looknew->connecting);
828
	ISC_LIST_INIT(looknew->my_server_list);
829
830
831
	return (looknew);
}

832
/*%
Michael Sawyer's avatar
Michael Sawyer committed
833
834
835
 * Clone a lookup, perhaps copying the server list.  This does not clone
 * the query list, since it will be regenerated by the setup_lookup()
 * function, nor does it queue up the new lookup for processing.
836
 * Caution: If you don't clone the servers, you MUST clone the server
Francis Dupont's avatar
Francis Dupont committed
837
 * list separately from somewhere else, or construct it by hand.
838
 */
839
840
841
842
843
844
845
846
847
848
dig_lookup_t *
clone_lookup(dig_lookup_t *lookold, isc_boolean_t servers) {
	dig_lookup_t *looknew;

	debug("clone_lookup()");

	INSIST(!free_now);

	looknew = make_empty_lookup();
	INSIST(looknew != NULL);
Evan Hunt's avatar
Evan Hunt committed
849
	strlcpy(looknew->textname, lookold->textname, MXNAME);
850
#if DIG_SIGCHASE_TD
Evan Hunt's avatar
Evan Hunt committed
851
	strlcpy(looknew->textnamesigchase, lookold->textnamesigchase, MXNAME);
852
#endif
Evan Hunt's avatar
Evan Hunt committed
853
	strlcpy(looknew->cmdline, lookold->cmdline, MXNAME);
Andreas Gustafsson's avatar
spacing    
Andreas Gustafsson committed
854
	looknew->textname[MXNAME-1] = 0;
855
	looknew->rdtype = lookold->rdtype;
856
	looknew->qrdtype = lookold->qrdtype;
857
	looknew->rdclass = lookold->rdclass;
Michael Sawyer's avatar
Michael Sawyer committed
858
859
	looknew->rdtypeset = lookold->rdtypeset;
	looknew->rdclassset = lookold->rdclassset;
860
	looknew->doing_xfr = lookold->doing_xfr;
Michael Sawyer's avatar
Michael Sawyer committed
861
	looknew->ixfr_serial = lookold->ixfr_serial;
862
863
864
	looknew->trace = lookold->trace;
	looknew->trace_root = lookold->trace_root;
	looknew->identify = lookold->identify;
Ben Cottrell's avatar
Ben Cottrell committed
865
	looknew->identify_previous_line = lookold->identify_previous_line;
Michael Sawyer's avatar
Michael Sawyer committed
866
	looknew->ignore = lookold->ignore;
867
	looknew->servfail_stops = lookold->servfail_stops;
868
	looknew->besteffort = lookold->besteffort;
869
	looknew->dnssec = lookold->dnssec;
870
	looknew->expire = lookold->expire;
871
	looknew->nsid = lookold->nsid;
872
873
874
875
#ifdef ISC_PLATFORM_USESIT
	looknew->sit = lookold->sit;
	looknew->sitvalue = lookold->sitvalue;
#endif
876
877
	looknew->ednsopts = lookold->ednsopts;
	looknew->ednsoptscnt = lookold->ednsoptscnt;
878
879
880
#ifdef DIG_SIGCHASE
	looknew->sigchase = lookold->sigchase;
#if DIG_SIGCHASE_TD
881
	looknew->do_topdown = lookold->do_topdown;
882
	looknew->trace_root_sigchase = lookold->trace_root_sigchase;
883
	looknew->rdtype_sigchaseset = lookold->rdtype_sigchaseset;
884
885
886
887
888
889
	looknew->rdtype_sigchase = lookold->rdtype_sigchase;
	looknew->qrdtype_sigchase = lookold->qrdtype_sigchase;
	looknew->rdclass_sigchase = lookold->rdclass_sigchase;
	looknew->rdclass_sigchaseset = lookold->rdclass_sigchaseset;
#endif
#endif
890
	looknew->udpsize = lookold->udpsize;
891
	looknew->edns = lookold->edns;
892
	looknew->recurse = lookold->recurse;
Brian Wellington's avatar
Brian Wellington committed
893
	looknew->aaonly = lookold->aaonly;
894
895
	looknew->adflag = lookold->adflag;
	looknew->cdflag = lookold->cdflag;
896
897
	looknew->ns_search_only = lookold->ns_search_only;
	looknew->tcp_mode = lookold->tcp_mode;
898
	looknew->tcp_mode_set = lookold->tcp_mode_set;
899
900
901
902
903
904
	looknew->comments = lookold->comments;
	looknew->stats = lookold->stats;
	looknew->section_question = lookold->section_question;
	looknew->section_answer = lookold->section_answer;
	looknew->section_authority = lookold->section_authority;
	looknew->section_additional = lookold->section_additional;
Michael Sawyer's avatar
Michael Sawyer committed
905
	looknew->retries = lookold->retries;
906
	looknew->tsigctx = NULL;
907
908
	looknew->need_search = lookold->need_search;
	looknew->done_as_is = lookold->done_as_is;
909
	looknew->dscp = lookold->dscp;
910

Evan Hunt's avatar
Evan Hunt committed
911
912
913
914
915
916
	if (lookold->ecs_addr != NULL) {
		size_t len = sizeof(isc_sockaddr_t);
		looknew->ecs_addr = isc_mem_allocate(mctx, len);
		memmove(looknew->ecs_addr, lookold->ecs_addr, len);
	}

917
918
919
	dns_name_copy(dns_fixedname_name(&lookold->fdomain),
		      dns_fixedname_name(&looknew->fdomain), NULL);

920
921
922
	if (servers)
		clone_server_list(lookold->my_server_list,
				  &looknew->my_server_list);
923
924
925
	return (looknew);
}

926
/*%
Michael Sawyer's avatar
Michael Sawyer committed
927
928
929
930
931
932
933
 * Requeue a lookup for further processing, perhaps copying the server
 * list.  The new lookup structure is returned to the caller, and is
 * queued for processing.  If servers are not cloned in the requeue, they
 * must be added before allowing the current event to complete, since the
 * completion of the event may result in the next entry on the lookup
 * queue getting run.
 */
934
935
936
937
938
939
940
941
dig_lookup_t *
requeue_lookup(dig_lookup_t *lookold, isc_boolean_t servers) {
	dig_lookup_t *looknew;

	debug("requeue_lookup()");

	lookup_counter++;
	if (lookup_counter > LOOKUP_LIMIT)
942
		fatal("too many lookups");
943
944
945
946

	looknew = clone_lookup(lookold, servers);
	INSIST(looknew != NULL);

Brian Wellington's avatar
Brian Wellington committed
947
	debug("before insertion, init@%p -> %p, new@%p -> %p",
948
	      lookold, lookold->link.next, looknew, looknew->link.next);
Michael Sawyer's avatar
Michael Sawyer committed
949
	ISC_LIST_PREPEND(lookup_list, looknew, link);
Brian Wellington's avatar
Brian Wellington committed
950
	debug("after insertion, init -> %p, new = %p, new -> %p",
951
	      lookold, looknew, looknew->link.next);
952
	return (looknew);
953
}
954

955

956
void
957
958
setup_text_key(void) {
	isc_result_t result;
Brian Wellington's avatar
Brian Wellington committed
959
	dns_name_t keyname;
960
961
962
963
964
965
966
967
968
969
970
	isc_buffer_t secretbuf;
	int secretsize;
	unsigned char *secretstore;

	debug("setup_text_key()");
	result = isc_buffer_allocate(mctx, &namebuf, MXNAME);
	check_result(result, "isc_buffer_allocate");
	dns_name_init(&keyname, NULL);
	check_result(result, "dns_name_init");
	isc_buffer_putstr(namebuf, keynametext);
	secretsize = strlen(keysecret) * 3 / 4;
971
	secretstore = isc_mem_allocate(mctx, secretsize);
972
	if (secretstore == NULL)
973
		fatal("memory allocation failure in %s:%d",
974
975
		      __FILE__, __LINE__);
	isc_buffer_init(&secretbuf, secretstore, secretsize);
976
	result = isc_base64_decodestring(keysecret, &secretbuf);
Brian Wellington's avatar
Brian Wellington committed
977
	if (result != ISC_R_SUCCESS)
978
		goto failure;
Automatic Updater's avatar
Automatic Updater committed
979

980
	secretsize = isc_buffer_usedlength(&secretbuf);
981

982
983
984
985
986
	if (hmacname == NULL) {
		result = DST_R_UNSUPPORTEDALG;
		goto failure;
	}

987
	result = dns_name_fromtext(&keyname, namebuf, dns_rootname, 0, namebuf);
Brian Wellington's avatar
Brian Wellington committed
988
	if (result != ISC_R_SUCCESS)
989
		goto failure;
Brian Wellington's avatar
Brian Wellington committed
990

991
992
	result = dns_tsigkey_create(&keyname, hmacname, secretstore,
				    secretsize, ISC_FALSE, NULL, 0, 0, mctx,
993
				    NULL, &key);
Brian Wellington's avatar
Brian Wellington committed
994
995
 failure:
	if (result != ISC_R_SUCCESS)
996
		printf(";; Couldn't create key %s: %s\n",
Brian Wellington's avatar
Brian Wellington committed
997
		       keynametext, isc_result_totext(result));
998
999
	else
		dst_key_setbits(key->key, digestbits);
Brian Wellington's avatar
Brian Wellington committed
1000

1001
	isc_mem_free(mctx, secretstore);
1002
1003
1004
1005
	dns_name_invalidate(&keyname);
	isc_buffer_free(&namebuf);
}

1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
isc_result_t
parse_uint(isc_uint32_t *uip, const char *value, isc_uint32_t max,
	   const char *desc) {
	isc_uint32_t n;
	isc_result_t result = isc_parse_uint32(&n, value, 10);
	if (result == ISC_R_SUCCESS && n > max)
		result = ISC_R_RANGE;
	if (result != ISC_R_SUCCESS) {
		printf("invalid %s '%s': %s\n", desc,
		       value, isc_result_totext(result));
		return (result);
	}
	*uip = n;
	return (ISC_R_SUCCESS);
}

static isc_uint32_t
parse_bits(char *arg, const char *desc, isc_uint32_t max) {
Automatic Updater's avatar
Automatic Updater committed
1024
1025
1026
1027
1028
1029
1030
1031
	isc_result_t result;
	isc_uint32_t tmp;

	result = parse_uint(&tmp, arg, max, desc);
	if (result != ISC_R_SUCCESS)
		fatal("couldn't parse digest bits");
	tmp = (tmp + 7) & ~0x7U;
	return (tmp);
1032
1033
}

Evan Hunt's avatar
Evan Hunt committed
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
isc_result_t
parse_netprefix(isc_sockaddr_t **sap, const char *value) {
	isc_result_t result = ISC_R_SUCCESS;
	isc_sockaddr_t *sa = NULL;
	struct in_addr in4;
	struct in6_addr in6;
	isc_uint32_t netmask = 0;
	char *slash = NULL;
	isc_boolean_t parsed = ISC_FALSE;

	if ((slash = strchr(value, '/'))) {
		*slash = '\0';
		result = isc_parse_uint32(&netmask, slash + 1, 10);
		if (result != ISC_R_SUCCESS) {
			*slash = '/';
			fatal("invalid prefix length '%s': %s\n",
			      value, isc_result_totext(result));
		}
	}

	sa = isc_mem_allocate(mctx, sizeof(*sa));
	if (inet_pton(AF_INET6, value, &in6) == 1) {
		isc_sockaddr_fromin6(sa, &in6, 0);
		parsed = ISC_TRUE;
		if (netmask == 0 || netmask > 128)
			netmask = 128;
	} else if (inet_pton(AF_INET, value, &in4) == 1) {
		parsed = ISC_TRUE;
		isc_sockaddr_fromin(sa, &in4, 0);
		if (netmask == 0 || netmask > 32)
			netmask = 32;
	} else if (netmask != 0) {
		char buf[64];
		int i;

		strlcpy(buf, value, sizeof(buf));
		for (i = 0; i < 3; i++) {
			strlcat(buf, ".0", sizeof(buf));
			if (inet_pton(AF_INET, buf, &in4) == 1) {
				parsed = ISC_TRUE;
				isc_sockaddr_fromin(sa, &in4, 0);
				break;
			}
		}

	}

	if (slash != NULL)
		*slash = '/';

	if (!parsed)
		fatal("invalid address '%s'", value);

	sa->length = netmask;
	*sap = sa;

	return (ISC_R_SUCCESS);
}

1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104

/*
 * Parse HMAC algorithm specification
 */
void
parse_hmac(const char *hmac) {
	char buf[20];
	int len;

	REQUIRE(hmac != NULL);

	len = strlen(hmac);
Automatic Updater's avatar
Automatic Updater committed
1105
	if (len >= (int) sizeof(buf))
1106
		fatal("unknown key type '%.*s'", len, hmac);
Evan Hunt's avatar
Evan Hunt committed
1107
	strlcpy(buf, hmac, sizeof(buf));
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188

	digestbits = 0;

	if (strcasecmp(buf, "hmac-md5") == 0) {
		hmacname = DNS_TSIG_HMACMD5_NAME;
	} else if (strncasecmp(buf, "hmac-md5-", 9) == 0) {
		hmacname = DNS_TSIG_HMACMD5_NAME;
		digestbits = parse_bits(&buf[9], "digest-bits [0..128]", 128);
	} else if (strcasecmp(buf, "hmac-sha1") == 0) {
		hmacname = DNS_TSIG_HMACSHA1_NAME;
		digestbits = 0;
	} else if (strncasecmp(buf, "hmac-sha1-", 10) == 0) {
		hmacname = DNS_TSIG_HMACSHA1_NAME;
		digestbits = parse_bits(&buf[10], "digest-bits [0..160]", 160);
	} else if (strcasecmp(buf, "hmac-sha224") == 0) {
		hmacname = DNS_TSIG_HMACSHA224_NAME;
	} else if (strncasecmp(buf, "hmac-sha224-", 12) == 0) {
		hmacname = DNS_TSIG_HMACSHA224_NAME;
		digestbits = parse_bits(&buf[12], "digest-bits [0..224]", 224);
	} else if (strcasecmp(buf, "hmac-sha256") == 0) {
		hmacname = DNS_TSIG_HMACSHA256_NAME;
	} else if (strncasecmp(buf, "hmac-sha256-", 12) == 0) {
		hmacname = DNS_TSIG_HMACSHA256_NAME;
		digestbits = parse_bits(&buf[12], "digest-bits [0..256]", 256);
	} else if (strcasecmp(buf, "hmac-sha384") == 0) {
		hmacname = DNS_TSIG_HMACSHA384_NAME;
	} else if (strncasecmp(buf, "hmac-sha384-", 12) == 0) {
		hmacname = DNS_TSIG_HMACSHA384_NAME;
		digestbits = parse_bits(&buf[12], "digest-bits [0..384]", 384);
	} else if (strcasecmp(buf, "hmac-sha512") == 0) {
		hmacname = DNS_TSIG_HMACSHA512_NAME;
	} else if (strncasecmp(buf, "hmac-sha512-", 12) == 0) {
		hmacname = DNS_TSIG_HMACSHA512_NAME;
		digestbits = parse_bits(&buf[12], "digest-bits [0..512]", 512);
	} else {
		fprintf(stderr, ";; Warning, ignoring "
			"invalid TSIG algorithm %s\n", buf);
	}
}

/*
 * Get a key from a named.conf format keyfile
 */
static isc_result_t
read_confkey(void) {
	isc_log_t *lctx = NULL;
	cfg_parser_t *pctx = NULL;
	cfg_obj_t *file = NULL;
	const cfg_obj_t *key = NULL;
	const cfg_obj_t *secretobj = NULL;
	const cfg_obj_t *algorithmobj = NULL;
	const char *keyname;
	const char *secretstr;
	const char *algorithm;
	isc_result_t result;

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

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

	result = cfg_parse_file(pctx, keyfile, &cfg_type_sessionkey,
				&file);
	if (result != ISC_R_SUCCESS)
		goto cleanup;

	result = cfg_map_get(file, "key", &key);
	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");

	k