dighost.c 112 KB
Newer Older
1
/*
2
 * Copyright (C) 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/.
7
8
9
 *
 * See the COPYRIGHT file distributed with this work for additional
 * information regarding copyright ownership.
10
11
 */

12
13
/*! \file
 *  \note
14
15
16
17
18
19
20
21
 * 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.
 */

22
#include <config.h>
23
24

#include <inttypes.h>
25
#include <stdbool.h>
26
27
#include <stdlib.h>
#include <unistd.h>
28
#include <string.h>
29
#include <limits.h>
Tomas Hozza's avatar
Tomas Hozza committed
30
#include <errno.h>
31

32
33
34
35
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif

Michał Kępień's avatar
Michał Kępień committed
36
#ifdef HAVE_LIBIDN2
Tomas Hozza's avatar
Tomas Hozza committed
37
#include <idn2.h>
Michał Kępień's avatar
Michał Kępień committed
38
#endif /* HAVE_LIBIDN2 */
Tomas Hozza's avatar
Tomas Hozza committed
39

40
#include <dns/byaddr.h>
41
#include <dns/fixedname.h>
42
#include <dns/log.h>
43
#include <dns/message.h>
Brian Wellington's avatar
Brian Wellington committed
44
#include <dns/name.h>
45
#include <dns/rcode.h>
46
47
#include <dns/rdata.h>
#include <dns/rdataclass.h>
Michael Sawyer's avatar
Michael Sawyer committed
48
#include <dns/rdatalist.h>
49
#include <dns/rdataset.h>
Michael Sawyer's avatar
Michael Sawyer committed
50
#include <dns/rdatastruct.h>
51
52
#include <dns/rdatatype.h>
#include <dns/result.h>
53
#include <dns/tsig.h>
54

55
#include <dst/dst.h>
56
#include <dst/result.h>
57

Michael Sawyer's avatar
Michael Sawyer committed
58
59
#include <isc/app.h>
#include <isc/base64.h>
60
#include <isc/file.h>
61
#include <isc/hex.h>
Michael Sawyer's avatar
Michael Sawyer committed
62
#include <isc/lang.h>
63
#include <isc/log.h>
64
#include <isc/netaddr.h>
65
#include <isc/netdb.h>
66
#include <isc/nonce.h>
67
#include <isc/parseint.h>
Mark Andrews's avatar
Mark Andrews committed
68
#include <isc/print.h>
69
#include <isc/random.h>
Michael Sawyer's avatar
Michael Sawyer committed
70
#include <isc/result.h>
71
#include <isc/safe.h>
72
#include <isc/serial.h>
Evan Hunt's avatar
Evan Hunt committed
73
#include <isc/sockaddr.h>
Michael Sawyer's avatar
Michael Sawyer committed
74
75
76
77
78
#include <isc/string.h>
#include <isc/task.h>
#include <isc/timer.h>
#include <isc/types.h>
#include <isc/util.h>
79

80
81
#include <pk11/site.h>

82
83
#include <isccfg/namedconf.h>

84
#include <irs/resconf.h>
85

86
#include <bind9/getaddresses.h>
87

88
#include <dig/dig.h>
89

Ondřej Surý's avatar
Ondřej Surý committed
90
#if USE_PKCS11
91
92
93
#include <pk11/result.h>
#endif

94
95
96
97
98
99
100
101
#if ! defined(NS_INADDRSZ)
#define NS_INADDRSZ	 4
#endif

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

102
dig_lookuplist_t lookup_list;
103
dig_serverlist_t server_list;
104
dig_searchlistlist_t search_list;
105

106
107
108
109
110
111
112
113
114
115
116
117
bool
	check_ra = false,
	have_ipv4 = false,
	have_ipv6 = false,
	specified_source = false,
	free_now = false,
	cancel_now = false,
	usesearch = false,
	showsearch = false,
	is_dst_up = false,
	keep_open = false,
	verbose = false;
118
in_port_t port = 53;
119
unsigned int timeout = 0;
120
unsigned int extrabytes;
121
isc_mem_t *mctx = NULL;
122
isc_log_t *lctx = NULL;
123
isc_taskmgr_t *taskmgr = NULL;
124
isc_task_t *global_task = NULL;
125
126
isc_timermgr_t *timermgr = NULL;
isc_socketmgr_t *socketmgr = NULL;
127
isc_sockaddr_t bind_address;
Michael Sawyer's avatar
Michael Sawyer committed
128
isc_sockaddr_t bind_any;
129
int sendcount = 0;
130
int recvcount = 0;
Michael Sawyer's avatar
Michael Sawyer committed
131
int sockcount = 0;
132
int ndots = -1;
133
int tries = 3;
134
int lookup_counter = 0;
135

136
static char servercookie[256];
137

Michał Kępień's avatar
Michał Kępień committed
138
#ifdef HAVE_LIBIDN2
139
static void idn_locale_to_ace(const char *src, char *dst, size_t dstlen);
140
static void idn_ace_to_locale(const char *src, char **dst);
141
static isc_result_t idn_output_filter(isc_buffer_t *buffer,
142
				      unsigned int used_org);
Michał Kępień's avatar
Michał Kępień committed
143
#endif /* HAVE_LIBIDN2 */
144

145
146
147
isc_socket_t *keep = NULL;
isc_sockaddr_t keepaddr;

148
/*%
149
 * Exit Codes:
150
 *
151
152
153
154
155
156
 *\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
157
158
 */
int exitcode = 0;
159
int fatalexit = 0;
160
char keynametext[MXNAME];
161
char keyfile[MXNAME] = "";
162
char keysecret[MXNAME] = "";
163
164
unsigned char cookie_secret[33];
unsigned char cookie[8];
165
const dns_name_t *hmacname = NULL;
166
unsigned int digestbits = 0;
167
isc_buffer_t *namebuf = NULL;
168
dns_tsigkey_t *tsigkey = NULL;
169
bool validated = true;
170
isc_mempool_t *commctx = NULL;
171
172
173
bool debugging = false;
bool debugtiming = false;
bool memdebugging = false;
Michael Sawyer's avatar
Michael Sawyer committed
174
char *progname = NULL;
175
isc_mutex_t lookup_lock;
176
dig_lookup_t *current_lookup = NULL;
177

178
179
#define DIG_MAX_ADDRESSES 20

180
/*%
181
 * Apply and clear locks at the event level in global task.
182
 * Can I get rid of these using shutdown events?  XXX
183
184
 */
#define LOCK_LOOKUP {\
Brian Wellington's avatar
Brian Wellington committed
185
186
187
	debug("lock_lookup %s:%d", __FILE__, __LINE__);\
	check_result(isc_mutex_lock((&lookup_lock)), "isc_mutex_lock");\
	debug("success");\
188
189
}
#define UNLOCK_LOOKUP {\
Brian Wellington's avatar
Brian Wellington committed
190
191
192
	debug("unlock_lookup %s:%d", __FILE__, __LINE__);\
	check_result(isc_mutex_unlock((&lookup_lock)),\
		     "isc_mutex_unlock");\
193
}
194

195
196
197
198
/* dynamic callbacks */

isc_result_t
(*dighost_printmessage)(dig_query_t *query, dns_message_t *msg,
199
	bool headers);
200
201

void
Mark Andrews's avatar
Mark Andrews committed
202
(*dighost_received)(unsigned int bytes, isc_sockaddr_t *from, dig_query_t *query);
203
204
205
206
207
208
209
210
211

void
(*dighost_trying)(char *frm, dig_lookup_t *lookup);

void
(*dighost_shutdown)(void);

/* forward declarations */

212
static void
213
214
cancel_lookup(dig_lookup_t *lookup);

Michael Sawyer's avatar
Michael Sawyer committed
215
216
217
static void
recv_done(isc_task_t *task, isc_event_t *event);

218
219
220
static void
send_udp(dig_query_t *query);

Michael Sawyer's avatar
Michael Sawyer committed
221
222
223
static void
connect_timeout(isc_task_t *task, isc_event_t *event);

224
static void
225
launch_next_query(dig_query_t *query, bool include_question);
226

227
228
229
static void
check_next_lookup(dig_lookup_t *lookup);

230
static bool
231
next_origin(dig_lookup_t *oldlookup);
232

233
234
235
static int
count_dots(char *string) {
	char *s;
236
	int i = 0;
237
238

	s = string;
239
	while (*s != '\0') {
240
241
242
243
244
245
246
		if (*s == '.')
			i++;
		s++;
	}
	return (i);
}

247
static void
248
hex_dump(isc_buffer_t *b) {
249
	unsigned int len, i;
250
251
	isc_region_t r;

252
	isc_buffer_usedregion(b, &r);
253

Mark Andrews's avatar
Mark Andrews committed
254
	printf("%u bytes\n", r.length);
255
	for (len = 0; len < r.length; len++) {
256
		printf("%02x ", r.base[len]);
257
258
259
260
261
		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
262
				else
263
264
					putchar('.');
			}
265
			printf("\n");
266
		}
267
	}
268
269
270
271
272
273
274
	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
275
			else
276
277
				putchar('.');
		}
278
		printf("\n");
279
	}
280
281
}

282
/*%
283
284
285
286
 * Append 'len' bytes of 'text' at '*p', failing with
 * ISC_R_NOSPACE if that would advance p past 'end'.
 */
static isc_result_t
287
append(const char *text, size_t len, char **p, char *end) {
288
	if (*p + len > end)
289
		return (ISC_R_NOSPACE);
290
	memmove(*p, text, len);
291
292
293
294
295
296
	*p += len;
	return (ISC_R_SUCCESS);
}

static isc_result_t
reverse_octets(const char *in, char **p, char *end) {
297
	const char *dot = strchr(in, '.');
298
	size_t len;
299
300
301
302
303
304
305
306
	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);
Evan Hunt's avatar
Evan Hunt committed
307
		len = (int) (dot - in);
308
	} else {
Evan Hunt's avatar
Evan Hunt committed
309
		len = (int) strlen(in);
310
311
312
	}
	return (append(in, len, p, end));
}
313
314

isc_result_t
315
get_reverse(char *reverse, size_t len, char *value, bool strict)
316
317
{
	int r;
318
	isc_result_t result;
319
	isc_netaddr_t addr;
320

321
	addr.family = AF_INET6;
Andreas Gustafsson's avatar
spacing    
Andreas Gustafsson committed
322
	r = inet_pton(AF_INET6, value, &addr.type.in6);
323
324
	if (r > 0) {
		/* This is a valid IPv6 address. */
325
326
		dns_fixedname_t fname;
		dns_name_t *name;
Mark Andrews's avatar
Mark Andrews committed
327
328
		unsigned int options = 0;

329
		name = dns_fixedname_initname(&fname);
330
		result = dns_byaddr_createptrname(&addr, options, name);
331
332
		if (result != ISC_R_SUCCESS)
			return (result);
333
		dns_name_format(name, reverse, (unsigned int)len);
334
335
336
337
338
339
340
341
342
343
344
		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;
345
		char *end = reverse + len;
Michael Graff's avatar
Michael Graff committed
346
347
		if (strict && inet_pton(AF_INET, value, &addr.type.in) != 1)
			return (DNS_R_BADDOTTEDQUAD);
348
349
350
351
352
353
354
355
		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);
356
357
358
	}
}

359
360
361
void (*dighost_pre_exit_hook)(void) = NULL;

#if TARGET_OS_IPHONE
362
void
363
364
365
366
367
368
369
370
371
372
373
374
375
warn(const char *format, ...) {
	va_list args;

	fflush(stdout);
	fprintf(stderr, ";; Warning: ");
	va_start(args, format);
	vfprintf(stderr, format, args);
	va_end(args);
	fprintf(stderr, "\n");
}
#else
void
warn(const char *format, ...) {
376
377
	va_list args;

378
	fflush(stdout);
379
	fprintf(stderr, "%s: ", progname);
380
	va_start(args, format);
381
382
383
	vfprintf(stderr, format, args);
	va_end(args);
	fprintf(stderr, "\n");
384
385
386
387
388
}
#endif

void
digexit(void) {
389
390
	if (exitcode < 10)
		exitcode = 10;
391
392
	if (fatalexit != 0)
		exitcode = fatalexit;
393
394
395
	if (dighost_pre_exit_hook != NULL) {
		dighost_pre_exit_hook();
	}
396
	exit(exitcode);
397
398
}

399
400
401
402
403
404
405
406
407
408
409
410
411
void
fatal(const char *format, ...) {
	va_list args;

	fflush(stdout);
	fprintf(stderr, "%s: ", progname);
	va_start(args, format);
	vfprintf(stderr, format, args);
	va_end(args);
	fprintf(stderr, "\n");
	digexit();
}

412
void
David Lawrence's avatar
David Lawrence committed
413
debug(const char *format, ...) {
414
	va_list args;
Evan Hunt's avatar
Evan Hunt committed
415
	isc_time_t t;
416

417
	if (debugging) {
418
		fflush(stdout);
419
		if (debugtiming) {
Evan Hunt's avatar
Evan Hunt committed
420
			TIME_NOW(&t);
Mark Andrews's avatar
Mark Andrews committed
421
			fprintf(stderr, "%u.%06u: ", isc_time_seconds(&t),
422
				isc_time_nanoseconds(&t) / 1000);
423
		}
424
		va_start(args, format);
425
426
427
428
		vfprintf(stderr, format, args);
		va_end(args);
		fprintf(stderr, "\n");
	}
429
430
}

431
void
David Lawrence's avatar
David Lawrence committed
432
check_result(isc_result_t result, const char *msg) {
433
	if (result != ISC_R_SUCCESS) {
434
		fatal("%s: %s", msg, isc_result_totext(result));
435
	}
436
437
}

438
/*%
Michael Sawyer's avatar
Michael Sawyer committed
439
440
441
442
 * 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
 */
443
dig_server_t *
444
make_server(const char *servname, const char *userarg) {
445
446
447
448
	dig_server_t *srv;

	REQUIRE(servname != NULL);

449
	debug("make_server(%s)", servname);
450
451
	srv = isc_mem_allocate(mctx, sizeof(struct dig_server));
	if (srv == NULL)
452
		fatal("memory allocation failure in %s:%d",
453
		      __FILE__, __LINE__);
454
455
	strlcpy(srv->servername, servname, MXNAME);
	strlcpy(srv->userarg, userarg, MXNAME);
456
	ISC_LINK_INIT(srv, link);
457
458
	return (srv);
}
459

460
/*%
461
 * Create a copy of the server list from the resolver configuration structure.
462
463
 * The dest list must have already had ISC_LIST_INIT applied.
 */
464
static void
465
466
467
get_server_list(irs_resconf_t *resconf) {
	isc_sockaddrlist_t *servers;
	isc_sockaddr_t *sa;
468
	dig_server_t *newsrv;
Mark Andrews's avatar
Mark Andrews committed
469
470
	char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") +
		 sizeof("%4000000000")];
471
472
473
474
475
476
477
478
479
480
	debug("get_server_list()");
	servers = irs_resconf_getnameservers(resconf);
	for (sa = ISC_LIST_HEAD(*servers);
	     sa != NULL;
	     sa = ISC_LIST_NEXT(sa, link))
	{
		int pf = isc_sockaddr_pf(sa);
		isc_netaddr_t na;
		isc_result_t result;
		isc_buffer_t b;
481

482
		if (pf == AF_INET && !have_ipv4)
483
			continue;
484
		if (pf == AF_INET6 && !have_ipv6)
485
486
			continue;

487
488
489
490
491
492
493
		isc_buffer_init(&b, tmp, sizeof(tmp));
		isc_netaddr_fromsockaddr(&na, sa);
		result = isc_netaddr_totext(&na, &b);
		if (result != ISC_R_SUCCESS)
			continue;
		isc_buffer_putuint8(&b, 0);
		if (pf == AF_INET6 && na.zone != 0) {
Mark Andrews's avatar
Mark Andrews committed
494
			char buf[sizeof("%4000000000")];
495
			snprintf(buf, sizeof(buf), "%%%u", na.zone);
Mark Andrews's avatar
Mark Andrews committed
496
497
			strlcat(tmp, buf, sizeof(tmp));
		}
498
		newsrv = make_server(tmp, tmp);
499
		ISC_LINK_INIT(newsrv, link);
500
		ISC_LIST_APPEND(server_list, newsrv, link);
501
502
	}
}
503

504
505
506
507
508
509
510
511
512
513
514
515
516
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);
	}
}
517

518
519
void
set_nameserver(char *opt) {
520
521
522
	isc_result_t result;
	isc_sockaddr_t sockaddrs[DIG_MAX_ADDRESSES];
	isc_netaddr_t netaddr;
Mark Andrews's avatar
Mark Andrews committed
523
	int count, i;
524
	dig_server_t *srv;
525
	char tmp[ISC_NETADDR_FORMATSIZE];
526
527
528
529

	if (opt == NULL)
		return;

530
	result = bind9_getaddresses(opt, 0, sockaddrs,
Automatic Updater's avatar
Automatic Updater committed
531
				    DIG_MAX_ADDRESSES, &count);
532
533
534
535
	if (result != ISC_R_SUCCESS)
		fatal("couldn't get address for '%s': %s",
		      opt, isc_result_totext(result));

536
	flush_server_list();
Automatic Updater's avatar
Automatic Updater committed
537

538
539
540
541
542
543
544
545
	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);
	}
546
547
}

548
/*%
Michael Sawyer's avatar
Michael Sawyer committed
549
550
551
 * Produce a cloned server list.  The dest list must have already had
 * ISC_LIST_INIT applied.
 */
552
void
553
clone_server_list(dig_serverlist_t src, dig_serverlist_t *dest) {
554
555
556
557
558
	dig_server_t *srv, *newsrv;

	debug("clone_server_list()");
	srv = ISC_LIST_HEAD(src);
	while (srv != NULL) {
559
		newsrv = make_server(srv->servername, srv->userarg);
560
		ISC_LINK_INIT(newsrv, link);
561
562
563
564
565
		ISC_LIST_ENQUEUE(*dest, newsrv, link);
		srv = ISC_LIST_NEXT(srv, link);
	}
}

566
/*%
Michael Sawyer's avatar
Michael Sawyer committed
567
568
569
570
571
 * 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).
 */
572
dig_lookup_t *
573
make_empty_lookup(void) {
574
575
	dig_lookup_t *looknew;

Michael Sawyer's avatar
Michael Sawyer committed
576
	debug("make_empty_lookup()");
577

578
	INSIST(!free_now);
579

580
	looknew = isc_mem_allocate(mctx, sizeof(struct dig_lookup));
581
	if (looknew == NULL)
582
		fatal("memory allocation failure in %s:%d",
583
		       __FILE__, __LINE__);
584
	looknew->pending = true;
Andreas Gustafsson's avatar
spacing    
Andreas Gustafsson committed
585
	looknew->textname[0] = 0;
586
	looknew->cmdline[0] = 0;
Ben Cottrell's avatar
Ben Cottrell committed
587
	looknew->rdtype = dns_rdatatype_a;
588
	looknew->qrdtype = dns_rdatatype_a;
Ben Cottrell's avatar
Ben Cottrell committed
589
	looknew->rdclass = dns_rdataclass_in;
590
591
	looknew->rdtypeset = false;
	looknew->rdclassset = false;
592
	looknew->sendspace = NULL;
593
594
595
	looknew->sendmsg = NULL;
	looknew->name = NULL;
	looknew->oname = NULL;
596
	looknew->xfr_q = NULL;
Michael Sawyer's avatar
Michael Sawyer committed
597
	looknew->current_query = NULL;
598
	looknew->doing_xfr = false;
599
	looknew->ixfr_serial = 0;
600
601
602
603
604
605
606
607
	looknew->trace = false;
	looknew->trace_root = false;
	looknew->identify = false;
	looknew->identify_previous_line = false;
	looknew->ignore = false;
	looknew->servfail_stops = true;
	looknew->besteffort = true;
	looknew->dnssec = false;
608
	looknew->ednsflags = 0;
609
	looknew->opcode = dns_opcode_query;
610
611
612
	looknew->expire = false;
	looknew->nsid = false;
	looknew->tcp_keepalive = false;
613
	looknew->padding = 0;
614
615
616
617
618
619
620
621
622
623
624
625
626
	looknew->header_only = false;
	looknew->sendcookie = false;
	looknew->seenbadcookie = false;
	looknew->badcookie = true;
	looknew->multiline = false;
	looknew->nottl = false;
	looknew->noclass = false;
	looknew->onesoa = false;
	looknew->use_usec = false;
	looknew->nocrypto = false;
	looknew->ttlunits = false;
	looknew->ttlunits = false;
	looknew->qr = false;
Michał Kępień's avatar
Michał Kępień committed
627
#ifdef HAVE_LIBIDN2
628
	looknew->idnin = isatty(1)?(getenv("IDN_DISABLE") == NULL):false;
629
	looknew->idnout = looknew->idnin;
630
#else
631
632
	looknew->idnin = false;
	looknew->idnout = false;
Michał Kępień's avatar
Michał Kępień committed
633
#endif /* HAVE_LIBIDN2 */
634
	looknew->udpsize = 0;
635
	looknew->edns = -1;
636
637
638
639
640
641
642
643
644
	looknew->recurse = true;
	looknew->aaonly = false;
	looknew->adflag = false;
	looknew->cdflag = false;
	looknew->raflag = false;
	looknew->tcflag = false;
	looknew->print_unknown_format = false;
	looknew->zflag = false;
	looknew->ns_search_only = false;
645
	looknew->origin = NULL;
646
	looknew->tsigctx = NULL;
647
648
649
	looknew->querysig = NULL;
	looknew->retries = tries;
	looknew->nsfound = 0;
650
651
652
653
654
655
656
657
658
659
660
	looknew->tcp_mode = false;
	looknew->tcp_mode_set = false;
	looknew->comments = true;
	looknew->stats = true;
	looknew->section_question = true;
	looknew->section_answer = true;
	looknew->section_authority = true;
	looknew->section_additional = true;
	looknew->new_search = false;
	looknew->done_as_is = false;
	looknew->need_search = false;
Evan Hunt's avatar
Evan Hunt committed
661
	looknew->ecs_addr = NULL;
662
	looknew->cookie = NULL;
663
664
	looknew->ednsopts = NULL;
	looknew->ednsoptscnt = 0;
665
666
	looknew->ednsneg = true;
	looknew->mapped = true;
667
	looknew->dscp = -1;
668
	looknew->rrcomments = 0;
669
	looknew->eoferr = 0;
670
	dns_fixedname_init(&looknew->fdomain);
671
	ISC_LINK_INIT(looknew, link);
672
	ISC_LIST_INIT(looknew->q);
673
	ISC_LIST_INIT(looknew->connecting);
674
	ISC_LIST_INIT(looknew->my_server_list);
675
676
677
	return (looknew);
}

678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
#define EDNSOPT_OPTIONS 100U

static void
cloneopts(dig_lookup_t *looknew, dig_lookup_t *lookold) {
	size_t len = sizeof(looknew->ednsopts[0]) * EDNSOPT_OPTIONS;
	size_t i;
	looknew->ednsopts = isc_mem_allocate(mctx, len);
	if (looknew->ednsopts == NULL)
		fatal("out of memory");
	for (i = 0; i < EDNSOPT_OPTIONS; i++) {
		looknew->ednsopts[i].code = 0;
		looknew->ednsopts[i].length = 0;
		looknew->ednsopts[i].value = NULL;
	}
	looknew->ednsoptscnt = 0;
	if (lookold == NULL || lookold->ednsopts == NULL)
		return;

	for (i = 0; i < lookold->ednsoptscnt; i++) {
		len = lookold->ednsopts[i].length;
		if (len != 0) {
			INSIST(lookold->ednsopts[i].value != NULL);
			looknew->ednsopts[i].value =
				 isc_mem_allocate(mctx, len);
			if (looknew->ednsopts[i].value == NULL)
				fatal("out of memory");
			memmove(looknew->ednsopts[i].value,
				lookold->ednsopts[i].value, len);
		}
		looknew->ednsopts[i].code = lookold->ednsopts[i].code;
		looknew->ednsopts[i].length = len;
	}
	looknew->ednsoptscnt = lookold->ednsoptscnt;
}

713
/*%
Michael Sawyer's avatar
Michael Sawyer committed
714
715
716
 * 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.
717
 * Caution: If you don't clone the servers, you MUST clone the server
Francis Dupont's avatar
Francis Dupont committed
718
 * list separately from somewhere else, or construct it by hand.
719
 */
720
dig_lookup_t *
721
clone_lookup(dig_lookup_t *lookold, bool servers) {
722
723
724
725
726
727
728
729
	dig_lookup_t *looknew;

	debug("clone_lookup()");

	INSIST(!free_now);

	looknew = make_empty_lookup();
	INSIST(looknew != NULL);
Evan Hunt's avatar
Evan Hunt committed
730
731
	strlcpy(looknew->textname, lookold->textname, MXNAME);
	strlcpy(looknew->cmdline, lookold->cmdline, MXNAME);
Andreas Gustafsson's avatar
spacing    
Andreas Gustafsson committed
732
	looknew->textname[MXNAME-1] = 0;
733
	looknew->rdtype = lookold->rdtype;
734
	looknew->qrdtype = lookold->qrdtype;
735
	looknew->rdclass = lookold->rdclass;
Michael Sawyer's avatar
Michael Sawyer committed
736
737
	looknew->rdtypeset = lookold->rdtypeset;
	looknew->rdclassset = lookold->rdclassset;
738
	looknew->doing_xfr = lookold->doing_xfr;
Michael Sawyer's avatar
Michael Sawyer committed
739
	looknew->ixfr_serial = lookold->ixfr_serial;
740
741
742
	looknew->trace = lookold->trace;
	looknew->trace_root = lookold->trace_root;
	looknew->identify = lookold->identify;
Ben Cottrell's avatar
Ben Cottrell committed
743
	looknew->identify_previous_line = lookold->identify_previous_line;
Michael Sawyer's avatar
Michael Sawyer committed
744
	looknew->ignore = lookold->ignore;
745
	looknew->servfail_stops = lookold->servfail_stops;
746
	looknew->besteffort = lookold->besteffort;
747
	looknew->dnssec = lookold->dnssec;
748
	looknew->ednsflags = lookold->ednsflags;
749
	looknew->opcode = lookold->opcode;
750
	looknew->expire = lookold->expire;
751
	looknew->nsid = lookold->nsid;
752
	looknew->tcp_keepalive = lookold->tcp_keepalive;
753
	looknew->header_only = lookold->header_only;
754
755
756
757
	looknew->sendcookie = lookold->sendcookie;
	looknew->seenbadcookie = lookold->seenbadcookie;
	looknew->badcookie = lookold->badcookie;
	looknew->cookie = lookold->cookie;
758
759
760
761
762
763
	if (lookold->ednsopts != NULL) {
		cloneopts(looknew, lookold);
	} else {
		looknew->ednsopts = NULL;
		looknew->ednsoptscnt = 0;
	}
764
	looknew->ednsneg = lookold->ednsneg;
765
	looknew->padding = lookold->padding;
766
	looknew->mapped = lookold->mapped;
767
768
769
770
771
772
773
774
	looknew->multiline = lookold->multiline;
	looknew->nottl = lookold->nottl;
	looknew->noclass = lookold->noclass;
	looknew->onesoa = lookold->onesoa;
	looknew->use_usec = lookold->use_usec;
	looknew->nocrypto = lookold->nocrypto;
	looknew->ttlunits = lookold->ttlunits;
	looknew->qr = lookold->qr;
775
	looknew->idnin = lookold->idnin;
776
	looknew->idnout = lookold->idnout;
777
	looknew->udpsize = lookold->udpsize;
778
	looknew->edns = lookold->edns;
779
	looknew->recurse = lookold->recurse;
Brian Wellington's avatar
Brian Wellington committed
780
	looknew->aaonly = lookold->aaonly;
781
782
	looknew->adflag = lookold->adflag;
	looknew->cdflag = lookold->cdflag;
783
784
	looknew->raflag = lookold->raflag;
	looknew->tcflag = lookold->tcflag;
785
	looknew->print_unknown_format = lookold->print_unknown_format;
786
	looknew->zflag = lookold->zflag;
787
788
	looknew->ns_search_only = lookold->ns_search_only;
	looknew->tcp_mode = lookold->tcp_mode;
789
	looknew->tcp_mode_set = lookold->tcp_mode_set;
790
791
792
793
794
795
	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;
796
	looknew->origin = lookold->origin;
Michael Sawyer's avatar
Michael Sawyer committed
797
	looknew->retries = lookold->retries;
798
	looknew->tsigctx = NULL;
799
800
	looknew->need_search = lookold->need_search;
	looknew->done_as_is = lookold->done_as_is;
801
	looknew->dscp = lookold->dscp;
802
	looknew->rrcomments = lookold->rrcomments;
803
	looknew->eoferr = lookold->eoferr;
804

Evan Hunt's avatar
Evan Hunt committed
805
806
807
	if (lookold->ecs_addr != NULL) {
		size_t len = sizeof(isc_sockaddr_t);
		looknew->ecs_addr = isc_mem_allocate(mctx, len);
808
809
		if (looknew->ecs_addr == NULL)
			fatal("out of memory");
Evan Hunt's avatar
Evan Hunt committed
810
811
812
		memmove(looknew->ecs_addr, lookold->ecs_addr, len);
	}

813
814
815
	dns_name_copy(dns_fixedname_name(&lookold->fdomain),
		      dns_fixedname_name(&looknew->fdomain), NULL);

816
817
818
	if (servers)
		clone_server_list(lookold->my_server_list,
				  &looknew->my_server_list);
819
820
821
	return (looknew);
}

822
/*%
Michael Sawyer's avatar
Michael Sawyer committed
823
824
825
826
827
828
829
 * 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.
 */
830
dig_lookup_t *
831
requeue_lookup(dig_lookup_t *lookold, bool servers) {
832
833
834
835
836
837
	dig_lookup_t *looknew;

	debug("requeue_lookup()");

	lookup_counter++;
	if (lookup_counter > LOOKUP_LIMIT)
838
		fatal("too many lookups");
839
840
841
842

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

Brian Wellington's avatar
Brian Wellington committed
843
	debug("before insertion, init@%p -> %p, new@%p -> %p",
844
	      lookold, lookold->link.next, looknew, looknew->link.next);
Michael Sawyer's avatar
Michael Sawyer committed
845
	ISC_LIST_PREPEND(lookup_list, looknew, link);
Brian Wellington's avatar
Brian Wellington committed
846
	debug("after insertion, init -> %p, new = %p, new -> %p",
847
	      lookold, looknew, looknew->link.next);
848
	return (looknew);
849
}
850

851

852
void
853
854
setup_text_key(void) {
	isc_result_t result;
Brian Wellington's avatar
Brian Wellington committed
855
	dns_name_t keyname;
856
	isc_buffer_t secretbuf;
Evan Hunt's avatar
Evan Hunt committed
857
	unsigned int secretsize;
858
859
860
861
862
863
864
865
	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);
Evan Hunt's avatar
Evan Hunt committed
866
	secretsize = (unsigned int) strlen(keysecret) * 3 / 4;
867
	secretstore = isc_mem_allocate(mctx, secretsize);
868
	if (secretstore == NULL)
869
		fatal("memory allocation failure in %s:%d",
870
871
		      __FILE__, __LINE__);
	isc_buffer_init(&secretbuf, secretstore, secretsize);
872
	result = isc_base64_decodestring(keysecret, &secretbuf);
Brian Wellington's avatar
Brian Wellington committed
873
	if (result != ISC_R_SUCCESS)
874
		goto failure;
Automatic Updater's avatar
Automatic Updater committed
875

876
	secretsize = isc_buffer_usedlength(&secretbuf);
877

878
879
880
881
882
	if (hmacname == NULL) {
		result = DST_R_UNSUPPORTEDALG;
		goto failure;
	}

883
	result = dns_name_fromtext(&keyname, namebuf, dns_rootname, 0, namebuf);
Brian Wellington's avatar
Brian Wellington committed
884
	if (result != ISC