dighost.c 74.7 KB
Newer Older
1
2
/*
 * Copyright (C) 2000  Internet Software Consortium.
3
 *
4
5
6
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
7
 *
8
9
10
11
12
13
14
15
 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
 * INTERNET SOFTWARE CONSORTIUM 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
 */

Mark Andrews's avatar
Mark Andrews committed
18
/* $Id: dighost.c,v 1.163 2000/11/20 13:02:15 marka Exp $ */
19

20
21
22
23
24
25
26
27
28
/*
 * 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.
 */

29
30
31
#include <config.h>
#include <stdlib.h>
#include <unistd.h>
32
33
#include <netdb.h>
#include <string.h>
34
#include <limits.h>
Michael Sawyer's avatar
Michael Sawyer committed
35
#if (!(defined(HAVE_ADDRINFO) && defined(HAVE_GETADDRINFO)))
36
extern int h_errno;
37
#endif
38

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

53
#include <dst/dst.h>
54

Michael Sawyer's avatar
Michael Sawyer committed
55
56
57
58
#include <isc/app.h>
#include <isc/base64.h>
#include <isc/entropy.h>
#include <isc/lang.h>
59
#include <isc/netaddr.h>
Michael Sawyer's avatar
Michael Sawyer committed
60
#include <isc/netdb.h>
Mark Andrews's avatar
Mark Andrews committed
61
#include <isc/print.h>
Michael Sawyer's avatar
Michael Sawyer committed
62
#include <isc/result.h>
Michael Sawyer's avatar
Michael Sawyer committed
63
64
65
66
67
#include <isc/string.h>
#include <isc/task.h>
#include <isc/timer.h>
#include <isc/types.h>
#include <isc/util.h>
68

69
70
71
#include <dig/dig.h>

ISC_LIST(dig_lookup_t) lookup_list;
72
dig_serverlist_t server_list;
73
ISC_LIST(dig_searchlist_t) search_list;
74

75
76
77
78
isc_boolean_t
	have_ipv6 = ISC_FALSE,
	specified_source = ISC_FALSE,
	free_now = ISC_FALSE,
79
	cancel_now = ISC_FALSE,
80
81
	usesearch = ISC_FALSE,
	qr = ISC_FALSE,
Michael Sawyer's avatar
Michael Sawyer committed
82
	is_dst_up = ISC_FALSE,
Michael Sawyer's avatar
Michael Sawyer committed
83
	have_domain = ISC_FALSE,
Mark Andrews's avatar
Mark Andrews committed
84
	is_blocking = ISC_FALSE;
85

86
in_port_t port = 53;
87
unsigned int timeout = 0;
88
89
isc_mem_t *mctx = NULL;
isc_taskmgr_t *taskmgr = NULL;
90
isc_task_t *global_task = NULL;
91
92
isc_timermgr_t *timermgr = NULL;
isc_socketmgr_t *socketmgr = NULL;
93
isc_sockaddr_t bind_address;
Michael Sawyer's avatar
Michael Sawyer committed
94
isc_sockaddr_t bind_any;
95
isc_buffer_t rootbuf;
96
int sendcount = 0;
97
int recvcount = 0;
Michael Sawyer's avatar
Michael Sawyer committed
98
int sockcount = 0;
99
int ndots = -1;
100
int tries = 2;
101
int lookup_counter = 0;
102
char fixeddomain[MXNAME] = "";
103
dig_searchlist_t *fixedsearch = NULL;
104
105
106
107
108
109
110
111
112
113
/*
 * Exit Codes:
 *   0   Everything went well, including things like NXDOMAIN
 *   1   Usage error
 *   7   Got too many RR's or Names
 *   8   Couldn't open batch file
 *   9   No reply from server
 *   10  Internal error
 */
int exitcode = 0;
114
char keynametext[MXNAME];
115
char keyfile[MXNAME] = "";
116
char keysecret[MXNAME] = "";
117
118
119
dns_name_t keyname;
isc_buffer_t *namebuf = NULL;
dns_tsigkey_t *key = NULL;
120
isc_boolean_t validated = ISC_TRUE;
121
isc_entropy_t *entp = NULL;
122
isc_mempool_t *commctx = NULL;
123
isc_boolean_t debugging = ISC_FALSE;
124
isc_boolean_t memdebugging = ISC_FALSE;
Michael Sawyer's avatar
Michael Sawyer committed
125
char *progname = NULL;
126
isc_mutex_t lookup_lock;
127
dig_lookup_t *current_lookup = NULL;
128
isc_uint32_t rr_limit = INT_MAX;
129
130
131

/*
 * Apply and clear locks at the event level in global task.
132
 * Can I get rid of these using shutdown events?  XXX
133
134
135
136
137
138
139
140
141
142
143
 */
#define LOCK_LOOKUP {\
        debug("lock_lookup %s:%d", __FILE__, __LINE__);\
        check_result(isc_mutex_lock((&lookup_lock)), "isc_mutex_lock");\
        debug("success");\
}
#define UNLOCK_LOOKUP {\
        debug("unlock_lookup %s:%d", __FILE__, __LINE__);\
        check_result(isc_mutex_unlock((&lookup_lock)),\
                     "isc_mutex_unlock");\
}
144

145
static void
146
147
cancel_lookup(dig_lookup_t *lookup);

Michael Sawyer's avatar
Michael Sawyer committed
148
149
150
151
152
153
static void
recv_done(isc_task_t *task, isc_event_t *event);

static void
connect_timeout(isc_task_t *task, isc_event_t *event);

Mark Andrews's avatar
Mark Andrews committed
154
char *
155
156
157
158
159
160
161
162
163
164
165
next_token(char **stringp, const char *delim) {
	char *res;

	do {
		res = strsep(stringp, delim);
		if (res == NULL)
			break;
	} while (*res == '\0');
	return (res);
}                       

166
167
168
static int
count_dots(char *string) {
	char *s;
169
	int i = 0;
170
171

	s = string;
172
	while (*s != '\0') {
173
174
175
176
177
178
179
		if (*s == '.')
			i++;
		s++;
	}
	return (i);
}

180
static void
181
hex_dump(isc_buffer_t *b) {
182
183
184
	unsigned int len;
	isc_region_t r;

185
	isc_buffer_usedregion(b, &r);
186

187
	printf("%d bytes\n", r.length);
188
	for (len = 0; len < r.length; len++) {
189
		printf("%02x ", r.base[len]);
190
		if (len % 16 == 15)
191
192
			printf("\n");
	}
Michael Sawyer's avatar
Michael Sawyer committed
193
	if (len % 16 != 0)
194
195
196
		printf("\n");
}

197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245

isc_result_t
get_reverse(char reverse[MXNAME], char *value, isc_boolean_t nibble) {
	int adrs[4];
	char working[MXNAME];
	int i, n;
	isc_result_t result;

	result = DNS_R_BADDOTTEDQUAD;

	debug("get_reverse(%s)", value);
	if (strspn(value, "0123456789.") == strlen(value)) {
		n = sscanf(value, "%d.%d.%d.%d",
			   &adrs[0], &adrs[1],
			   &adrs[2], &adrs[3]);
		if (n == 0) {
			return (DNS_R_BADDOTTEDQUAD);
		}
		for (i = n - 1; i >= 0; i--) {
			snprintf(working, MXNAME/8, "%d.",
				 adrs[i]);
			strncat(reverse, working, MXNAME);
		}
		strncat(reverse, "in-addr.arpa.", MXNAME);
		result = ISC_R_SUCCESS;
	} else if (strspn(value, "0123456789abcdefABCDEF:") 
		   == strlen(value)) {
		isc_netaddr_t addr;
		dns_fixedname_t fname;
		dns_name_t *name;
		isc_buffer_t b;
		
		addr.family = AF_INET6;
		n = inet_pton(AF_INET6, value, &addr.type.in6);
		if (n <= 0)
			return (DNS_R_BADDOTTEDQUAD);
		dns_fixedname_init(&fname);
		name = dns_fixedname_name(&fname);
		result = dns_byaddr_createptrname(&addr, nibble,
						  name);
		if (result != ISC_R_SUCCESS)
			return (result);
		isc_buffer_init(&b, reverse, MXNAME);
		result = dns_name_totext(name, ISC_FALSE, &b);
		isc_buffer_putuint8(&b, 0);
	}
	return (result);
}

246
void
David Lawrence's avatar
David Lawrence committed
247
fatal(const char *format, ...) {
248
249
	va_list args;

250
	fprintf(stderr, "%s: ", progname);
251
	va_start(args, format);
252
253
254
	vfprintf(stderr, format, args);
	va_end(args);
	fprintf(stderr, "\n");
255
256
	if (exitcode < 10)
		exitcode = 10;
257
	exit(exitcode);
258
259
}

260
void
David Lawrence's avatar
David Lawrence committed
261
debug(const char *format, ...) {
262
263
	va_list args;

264
	if (debugging) {
265
		va_start(args, format);
266
267
268
269
		vfprintf(stderr, format, args);
		va_end(args);
		fprintf(stderr, "\n");
	}
270
271
}

272
void
David Lawrence's avatar
David Lawrence committed
273
check_result(isc_result_t result, const char *msg) {
274
	if (result != ISC_R_SUCCESS) {
275
		fatal("%s: %s", msg, isc_result_totext(result));
276
	}
277
278
}

Michael Sawyer's avatar
Michael Sawyer committed
279
280
281
282
283
/*
 * 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
 */
284
285
286
287
288
289
dig_server_t *
make_server(const char *servname) {
	dig_server_t *srv;

	REQUIRE(servname != NULL);

290
	debug("make_server(%s)", servname);
291
292
293
294
295
	srv = isc_mem_allocate(mctx, sizeof(struct dig_server));
	if (srv == NULL)
		fatal("Memory allocation failure in %s:%d",
		      __FILE__, __LINE__);
	strncpy(srv->servername, servname, MXNAME);
296
	srv->servername[MXNAME-1] = 0;
297
	ISC_LINK_INIT(srv, link);
298
299
300
	return (srv);
}

301
/*
Michael Sawyer's avatar
Michael Sawyer committed
302
303
304
 * Produce a cloned server list.  The dest list must have already had
 * ISC_LIST_INIT applied.
 */
305
void
306
clone_server_list(dig_serverlist_t src,
307
308
309
310
311
312
313
314
		  dig_serverlist_t *dest)
{
	dig_server_t *srv, *newsrv;

	debug("clone_server_list()");
	srv = ISC_LIST_HEAD(src);
	while (srv != NULL) {
		newsrv = make_server(srv->servername);
315
		ISC_LINK_INIT(newsrv, link);
316
317
318
319
320
		ISC_LIST_ENQUEUE(*dest, newsrv, link);
		srv = ISC_LIST_NEXT(srv, link);
	}
}

Michael Sawyer's avatar
Michael Sawyer committed
321
322
323
324
325
326
/*
 * 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).
 */
327
dig_lookup_t *
328
make_empty_lookup(void) {
329
330
	dig_lookup_t *looknew;

Michael Sawyer's avatar
Michael Sawyer committed
331
	debug("make_empty_lookup()");
332

333
	INSIST(!free_now);
334

335
	looknew = isc_mem_allocate(mctx, sizeof(struct dig_lookup));
336
	if (looknew == NULL)
337
		fatal("Memory allocation failure in %s:%d",
338
		       __FILE__, __LINE__);
339
	looknew->pending = ISC_TRUE;
Andreas Gustafsson's avatar
spacing    
Andreas Gustafsson committed
340
341
342
343
	looknew->textname[0] = 0;
	looknew->cmdline[0] = 0; /* Not copied in clone_lookup! */
	looknew->rdtype = dns_rdatatype_a;
	looknew->rdclass = dns_rdataclass_in;
344
	looknew->sendspace = NULL;
345
346
347
	looknew->sendmsg = NULL;
	looknew->name = NULL;
	looknew->oname = NULL;
348
349
	looknew->timer = NULL;
	looknew->xfr_q = NULL;
Michael Sawyer's avatar
Michael Sawyer committed
350
	looknew->current_query = NULL;
351
352
353
354
355
356
	looknew->doing_xfr = ISC_FALSE;
	looknew->ixfr_serial = ISC_FALSE;
	looknew->defname = ISC_FALSE;
	looknew->trace = ISC_FALSE;
	looknew->trace_root = ISC_FALSE;
	looknew->identify = ISC_FALSE;
Michael Sawyer's avatar
Michael Sawyer committed
357
	looknew->ignore = ISC_FALSE;
358
	looknew->servfail_stops = ISC_FALSE;
359
	looknew->besteffort = ISC_TRUE;
360
	looknew->dnssec = ISC_FALSE;
361
362
	looknew->udpsize = 0;
	looknew->recurse = ISC_TRUE;
Michael Sawyer's avatar
Michael Sawyer committed
363
	looknew->aaonly = ISC_FALSE;
364
365
366
367
368
369
370
371
	looknew->adflag = ISC_FALSE;
	looknew->cdflag = ISC_FALSE;
	looknew->ns_search_only = ISC_FALSE;
	looknew->origin = NULL;
	looknew->querysig = NULL;
	looknew->retries = tries;
	looknew->nsfound = 0;
	looknew->tcp_mode = ISC_FALSE;
372
	looknew->nibble = ISC_FALSE;
373
374
375
376
377
378
379
	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;
380
#ifdef DNS_OPT_NEWCODES_LIVE
381
382
	looknew->zonename[0] = 0;
	looknew->viewname[0] = 0;
383
#endif /* DNS_OPT_NEWCODES_LIVE */
384
	ISC_LINK_INIT(looknew, link);
385
	ISC_LIST_INIT(looknew->q);
386
	ISC_LIST_INIT(looknew->my_server_list);
387
388
389
	return (looknew);
}

390
/*
Michael Sawyer's avatar
Michael Sawyer committed
391
392
393
 * 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.
394
395
396
 * Caution: If you don't clone the servers, you MUST clone the server
 * list seperately from somewhere else, or construct it by hand.
 */
397
398
399
400
401
402
403
404
405
406
407
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);
	strncpy(looknew->textname, lookold-> textname, MXNAME);
408
	looknew->textname[MXNAME-1]=0;
409
410
	looknew->rdtype = lookold->rdtype;
	looknew->rdclass = lookold->rdclass;
411
	looknew->doing_xfr = lookold->doing_xfr;
Michael Sawyer's avatar
Michael Sawyer committed
412
	looknew->ixfr_serial = lookold->ixfr_serial;
413
414
415
416
	looknew->defname = lookold->defname;
	looknew->trace = lookold->trace;
	looknew->trace_root = lookold->trace_root;
	looknew->identify = lookold->identify;
Michael Sawyer's avatar
Michael Sawyer committed
417
	looknew->ignore = lookold->ignore;
418
	looknew->servfail_stops = lookold->servfail_stops;
419
	looknew->besteffort = lookold->besteffort;
420
	looknew->dnssec = lookold->dnssec;
421
422
	looknew->udpsize = lookold->udpsize;
	looknew->recurse = lookold->recurse;
Michael Sawyer's avatar
Michael Sawyer committed
423
        looknew->aaonly = lookold->aaonly;
424
425
	looknew->adflag = lookold->adflag;
	looknew->cdflag = lookold->cdflag;
426
427
428
429
430
431
432
433
	looknew->ns_search_only = lookold->ns_search_only;
	looknew->tcp_mode = lookold->tcp_mode;
	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
434
	looknew->retries = lookold->retries;
435
#ifdef DNS_OPT_NEWCODES_LIVE
436
437
	strncpy(looknew->viewname, lookold-> viewname, MXNAME);
	strncpy(looknew->zonename, lookold-> zonename, MXNAME);
438
#endif /* DNS_OPT_NEWCODES_LIVE */
439

440
441
442
	if (servers)
		clone_server_list(lookold->my_server_list,
				  &looknew->my_server_list);
443
444
445
	return (looknew);
}

Michael Sawyer's avatar
Michael Sawyer committed
446
447
448
449
450
451
452
453
/*
 * 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.
 */
454
455
456
457
458
459
460
461
462
463
464
465
466
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)
		fatal("Too many lookups");

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

Michael Sawyer's avatar
Michael Sawyer committed
467
	debug("before insertion, init@%p "
468
469
	       "-> %p, new@%p -> %p",
	      lookold, lookold->link.next, looknew, looknew->link.next);
Michael Sawyer's avatar
Michael Sawyer committed
470
	ISC_LIST_PREPEND(lookup_list, looknew, link);
Michael Sawyer's avatar
Michael Sawyer committed
471
	debug("after insertion, init -> "
472
	      "%p, new = %p, new -> %p",
473
	      lookold, looknew, looknew->link.next);
474
	return (looknew);
475
}
476

477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492

static void
setup_text_key(void) {
	isc_result_t result;
	isc_buffer_t secretbuf;
	int secretsize;
	unsigned char *secretstore;
	isc_stdtime_t now;

	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;
493
	secretstore = isc_mem_allocate(mctx, secretsize);
494
495
496
497
498
499
500
501
502
	if (secretstore == NULL)
		fatal("Memory allocation failure in %s:%d",
		      __FILE__, __LINE__);
	isc_buffer_init(&secretbuf, secretstore, secretsize);
	result = isc_base64_decodestring(mctx, keysecret,
					 &secretbuf);
	if (result != ISC_R_SUCCESS) {
		printf(";; Couldn't create key %s: %s\n",
		       keynametext, isc_result_totext(result));
503
		goto failure;
504
505
506
	}
	secretsize = isc_buffer_usedlength(&secretbuf);
	isc_stdtime_get(&now);
507

508
509
510
511
512
513
	result = dns_name_fromtext(&keyname, namebuf,
				   dns_rootname, ISC_FALSE,
				   namebuf);
	if (result != ISC_R_SUCCESS) {
		printf(";; Couldn't create key %s: %s\n",
		       keynametext, dns_result_totext(result));
514
		goto failure;
515
516
517
518
	}
	result = dns_tsigkey_create(&keyname, dns_tsig_hmacmd5_name,
				    secretstore, secretsize,
				    ISC_TRUE, NULL, now, now, mctx,
519
				    NULL, &key);
520
521
522
523
	if (result != ISC_R_SUCCESS) {
		printf(";; Couldn't create key %s: %s\n",
		       keynametext, dns_result_totext(result));
	}
524
 failure:
525
	isc_mem_free(mctx, secretstore);
526
527
528
529
530
531
532
533
534
535
536
537
538
539
	dns_name_invalidate(&keyname);
	isc_buffer_free(&namebuf);
}


static void
setup_file_key(void) {
	isc_result_t result;
	isc_buffer_t secretbuf;
	unsigned char *secretstore = NULL;
	int secretlen;
	dst_key_t *dstkey = NULL;
	isc_stdtime_t now;

540

541
542
543
544
545
546
547
548
	debug("setup_file_key()");
	result = dst_key_fromnamedfile(keyfile, DST_TYPE_PRIVATE,
				       mctx, &dstkey);
	if (result != ISC_R_SUCCESS) {
		fprintf(stderr, "Couldn't read key from %s: %s\n",
			keyfile, isc_result_totext(result));
		goto failure;
	}
549
550
551
	/*
	 * Get key size in bits, convert to bytes, rounding up (?)
	 */
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
	secretlen = (dst_key_size(dstkey) + 7) >> 3;
	secretstore = isc_mem_allocate(mctx, secretlen);
	if (secretstore == NULL)
		fatal("out of memory");
	isc_buffer_init(&secretbuf, secretstore, secretlen);
	result = dst_key_tobuffer(dstkey, &secretbuf);
	if (result != ISC_R_SUCCESS) {
		fprintf(stderr, "Couldn't read key from %s: %s\n",
			keyfile, isc_result_totext(result));
		goto failure;
	}
	isc_stdtime_get(&now);
	dns_name_init(&keyname, NULL);
	dns_name_clone(dst_key_name(dstkey), &keyname);
	result = dns_tsigkey_create(&keyname, dns_tsig_hmacmd5_name,
				    secretstore, secretlen,
				    ISC_TRUE, NULL, now, now, mctx,
569
				    NULL, &key);
570
571
572
573
574
575
576
577
578
579
580
	if (result != ISC_R_SUCCESS) {
		printf(";; Couldn't create key %s: %s\n",
		       keynametext, dns_result_totext(result));
	}
 failure:
	if (dstkey != NULL)
		dst_key_free(&dstkey);
	if (secretstore != NULL)
		isc_mem_free(mctx, secretstore);
}

Michael Sawyer's avatar
Michael Sawyer committed
581
582
583
584
/*
 * Setup the system as a whole, reading key information and resolv.conf
 * settings.
 */
585
void
586
setup_system(void) {
587
588
589
590
	char rcinput[MXNAME];
	FILE *fp;
	char *ptr;
	dig_server_t *srv;
591
592
	dig_searchlist_t *search;
	isc_boolean_t get_servers;
593
	char *input;
594

595
	debug("setup_system()");
Michael Sawyer's avatar
Michael Sawyer committed
596

597
	free_now = ISC_FALSE;
598
	get_servers = ISC_TF(server_list.head == NULL);
599
	fp = fopen(RESOLVCONF, "r");
600
	/* XXX Use lwres resolv.conf reader */
601
602
	if (fp != NULL) {
		while (fgets(rcinput, MXNAME, fp) != 0) {
603
			input = rcinput;
604
			ptr = next_token(&input, " \t\r\n");
605
606
			if (ptr != NULL) {
				if (get_servers &&
607
				    strcasecmp(ptr, "nameserver") == 0) {
Michael Sawyer's avatar
Michael Sawyer committed
608
					debug("got a nameserver line");
609
					ptr = next_token(&input, " \t\r\n");
610
					if (ptr != NULL) {
611
612
613
614
						srv = make_server(ptr);
						ISC_LIST_APPEND
							(server_list,
							 srv, link);
615
					}
616
				} else if (strcasecmp(ptr, "options") == 0) {
617
					ptr = next_token(&input, " \t\r\n");
618
					if (ptr != NULL) {
619
						if((strncasecmp(ptr, "ndots:",
620
621
622
623
							    6) == 0) &&
						    (ndots == -1)) {
							ndots = atoi(
							      &ptr[6]);
624
							debug("ndots is "
625
626
627
628
							       "%d.",
							       ndots);
						}
					}
Michael Sawyer's avatar
Michael Sawyer committed
629
				} else if (strcasecmp(ptr, "search") == 0){
630
					while ((ptr = next_token(&input, " \t\r\n"))
631
					       != NULL) {
Michael Sawyer's avatar
Michael Sawyer committed
632
633
						debug("adding search %s",
						      ptr);
634
635
636
637
638
639
						search = isc_mem_allocate(
						   mctx, sizeof(struct
								dig_server));
						if (search == NULL)
							fatal("Memory "
							      "allocation "
640
							      "failure in %s:"
641
							      "%d", __FILE__,
642
							      __LINE__);
643
644
645
						strncpy(search->
							origin,
							ptr,
646
647
							MXNAME);
						search->origin[MXNAME-1]=0;
648
						ISC_LIST_APPENDUNSAFE
649
650
651
652
							(search_list,
							 search,
							 link);
					}
653
				} else if ((strcasecmp(ptr, "domain") == 0) &&
654
					   (fixeddomain[0] == 0 )){
Michael Sawyer's avatar
Michael Sawyer committed
655
					have_domain = ISC_TRUE;
656
					while ((ptr = next_token(&input, " \t\r\n"))
657
658
659
660
661
662
663
					       != NULL) {
						search = isc_mem_allocate(
						   mctx, sizeof(struct
								dig_server));
						if (search == NULL)
							fatal("Memory "
							      "allocation "
664
							      "failure in %s:"
665
							      "%d", __FILE__,
666
							      __LINE__);
667
668
669
670
						strncpy(search->
							origin,
							ptr,
							MXNAME - 1);
671
						search->origin[MXNAME-1]=0;
672
						ISC_LIST_PREPENDUNSAFE
673
674
675
676
							(search_list,
							 search,
							 link);
					}
677
678
679
				}
			}
		}
680
		fclose(fp);
681
	}
682

683
684
685
	if (ndots == -1)
		ndots = 1;

686
	if (server_list.head == NULL) {
687
		srv = make_server("127.0.0.1");
688
689
		ISC_LIST_APPEND(server_list, srv, link);
	}
690

691
692
693
694
	if (keyfile[0] != 0)
		setup_file_key();
	else if (keysecret[0] != 0)
		setup_text_key();
695
}
696

Michael Sawyer's avatar
Michael Sawyer committed
697
698
699
/*
 * Setup the ISC and DNS libraries for use by the system.
 */
700
void
701
setup_libs(void) {
702
703
	isc_result_t result;

704
	debug("setup_libs()");
705
706
707
708
709
710

	/*
	 * Warning: This is not particularly good randomness.  We'll
	 * just use random() now for getting id values, but doing so
	 * does NOT insure that id's cann't be guessed.
	 */
711
	srandom(getpid() + (int)&setup_libs);
712

713
	result = isc_net_probeipv4();
714
	check_result(result, "isc_net_probeipv4");
715
716
717

	result = isc_net_probeipv6();
	if (result == ISC_R_SUCCESS)
718
		have_ipv6 = ISC_TRUE;
719

720
721
	result = isc_mem_create(0, 0, &mctx);
	check_result(result, "isc_mem_create");
722

723
	result = isc_taskmgr_create(mctx, 1, 0, &taskmgr);
724
	check_result(result, "isc_taskmgr_create");
725

726
	result = isc_task_create(taskmgr, 0, &global_task);
727
	check_result(result, "isc_task_create");
728

729
	result = isc_timermgr_create(mctx, &timermgr);
730
	check_result(result, "isc_timermgr_create");
731

732
	result = isc_socketmgr_create(mctx, &socketmgr);
733
	check_result(result, "isc_socketmgr_create");
734

735
	result = isc_entropy_create(mctx, &entp);
736
737
	check_result(result, "isc_entropy_create");

738
	result = dst_lib_init(mctx, entp, 0);
739
740
	check_result(result, "dst_lib_init");
	is_dst_up = ISC_TRUE;
741
742
743
744
745
746
747
748
749
750

	result = isc_mempool_create(mctx, COMMSIZE, &commctx);
	check_result(result, "isc_mempool_create");
	isc_mempool_setname(commctx, "COMMPOOL");
	/*
	 * 6 and 2 set as reasonable parameters for 3 or 4 nameserver
	 * systems.
	 */
	isc_mempool_setfreemax(commctx, 6);
	isc_mempool_setfillcount(commctx, 2);
751
752
753

	result = isc_mutex_init(&lookup_lock);
	check_result(result, "isc_mutex_init");
754
755

	dns_result_register();
756
757
}

Michael Sawyer's avatar
Michael Sawyer committed
758
759
760
761
/*
 * Add EDNS0 option record to a message.  Currently, the only supported
 * option is UDP buffer size.
 */
762
static void
763
764
765
add_opt(dns_message_t *msg, isc_uint16_t udpsize, isc_boolean_t dnssec,
	dns_optlist_t optlist)
{
766
767
768
769
	dns_rdataset_t *rdataset = NULL;
	dns_rdatalist_t *rdatalist = NULL;
	dns_rdata_t *rdata = NULL;
	isc_result_t result;
770
#ifdef DNS_OPT_NEWCODES_LIVE
771
772
	isc_buffer_t *rdatabuf = NULL;
	unsigned int i, optsize = 0;
773
#else /* DNS_OPT_NEWCODES_LIVE */
774
775

	UNUSED(optlist);
776
#endif /* DNS_OPT_NEWCODES_LIVE */
777

778
	debug("add_opt()");
779
	result = dns_message_gettemprdataset(msg, &rdataset);
780
781
	check_result(result, "dns_message_gettemprdataset");
	dns_rdataset_init(rdataset);
782
	result = dns_message_gettemprdatalist(msg, &rdatalist);
783
	check_result(result, "dns_message_gettemprdatalist");
784
	result = dns_message_gettemprdata(msg, &rdata);
785
	check_result(result, "dns_message_gettemprdata");
786

Michael Sawyer's avatar
Michael Sawyer committed
787
	debug("setting udp size of %d", udpsize);
788
789
790
791
	rdatalist->type = dns_rdatatype_opt;
	rdatalist->covers = 0;
	rdatalist->rdclass = udpsize;
	rdatalist->ttl = 0;
792
793
	if (dnssec)
		rdatalist->ttl = DNS_MESSAGEEXTFLAG_DO;
794
795
	rdata->data = NULL;
	rdata->length = 0;
796
#ifdef DNS_OPT_NEWCODES_LIVE
797
798
799
800
801
802
803
	for (i=0; i<optlist.used; i++)
		optsize += optlist.attrs[i].value.length + 4;
	result = isc_buffer_allocate(mctx, &rdatabuf, optsize);
	check_result(result, "isc_buffer_allocate");
	result = dns_opt_add(rdata, &optlist, rdatabuf);
	check_result(result, "dns_opt_add");
	dns_message_takebuffer(msg, &rdatabuf);
804
#endif /* DNS_OPT_NEWCODES_LIVE */
805
806
807
808
	ISC_LIST_INIT(rdatalist->rdata);
	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
	dns_rdatalist_tordataset(rdatalist, rdataset);
	result = dns_message_setopt(msg, rdataset);
809
	check_result(result, "dns_message_setopt");
810
811
}

Michael Sawyer's avatar
Michael Sawyer committed
812
/*
813
 * Add a question section to a message, asking for the specified name,
Michael Sawyer's avatar
Michael Sawyer committed
814
815
 * type, and class.
 */
816
static void
Michael Sawyer's avatar
Michael Sawyer committed
817
818
add_question(dns_message_t *message, dns_name_t *name,
	     dns_rdataclass_t rdclass, dns_rdatatype_t rdtype)
819
820
821
822
{
	dns_rdataset_t *rdataset;
	isc_result_t result;

823
	debug("add_question()");
824
825
826
827
828
829
830
831
	rdataset = NULL;
	result = dns_message_gettemprdataset(message, &rdataset);
	check_result(result, "dns_message_gettemprdataset()");
	dns_rdataset_init(rdataset);
	dns_rdataset_makequestion(rdataset, rdclass, rdtype);
	ISC_LIST_APPEND(name->list, rdataset, link);
}

Michael Sawyer's avatar
Michael Sawyer committed
832
/*
Michael Sawyer's avatar
Michael Sawyer committed
833
834
835
836
837
838
 * Check if we're done with all the queued lookups, which is true iff
 * all sockets, sends, and recvs are accounted for (counters == 0),
 * and the lookup list is empty.
 * If we are done, pass control back out to dighost_shutdown() (which is
 * part of dig.c, host.c, or nslookup.c) to either shutdown the system as
 * a whole or reseed the lookup list.
Michael Sawyer's avatar
Michael Sawyer committed
839
 */
840
841
842
static void
check_if_done(void) {
	debug("check_if_done()");
Andreas Gustafsson's avatar
spacing    
Andreas Gustafsson committed
843
	debug("list %s", ISC_LIST_EMPTY(lookup_list) ? "empty" : "full");
844
845
	if (ISC_LIST_EMPTY(lookup_list) && current_lookup == NULL &&
	    sendcount == 0) {
846
847
		INSIST(sockcount == 0);
		INSIST(recvcount == 0);
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
		debug("shutting down");
		dighost_shutdown();
	}
}

/*
 * Clear out a query when we're done with it.  WARNING: This routine
 * WILL invalidate the query pointer.
 */
static void
clear_query(dig_query_t *query) {
	dig_lookup_t *lookup;

	REQUIRE(query != NULL);

863
864
	debug("clear_query(%p)",query);

865
	lookup = query->lookup;
866

Michael Sawyer's avatar
Michael Sawyer committed
867
868
869
	if (lookup->current_query == query)
		lookup->current_query = NULL;

870
871
872
873
874
875
876
	ISC_LIST_UNLINK(lookup->q, query, link);
	if (ISC_LINK_LINKED(&query->recvbuf, link))
		ISC_LIST_DEQUEUE(query->recvlist, &query->recvbuf,
				 link);
	if (ISC_LINK_LINKED(&query->lengthbuf, link))
		ISC_LIST_DEQUEUE(query->lengthlist, &query->lengthbuf,
				 link);
877
	INSIST(query->recvspace != NULL);
878
879
880
881
882
	if (query->sock != NULL) {
		isc_socket_detach(&query->sock);
		sockcount--;
		debug("sockcount=%d", sockcount);
	}
883
	isc_mempool_put(commctx, query->recvspace);
884
885
886
887
	isc_buffer_invalidate(&query->recvbuf);
	isc_buffer_invalidate(&query->lengthbuf);
	isc_mem_free(mctx, query);
}
888

Michael Sawyer's avatar
Michael Sawyer committed
889
890
891
892
893
/*
 * Try and clear out a lookup if we're done with it.  Return ISC_TRUE if
 * the lookup was successfully cleared.  If ISC_TRUE is returned, the
 * lookup pointer has been invalidated.
 */
Michael Sawyer's avatar
Michael Sawyer committed
894
static isc_boolean_t
895
896
try_clear_lookup(dig_lookup_t *lookup) {
	dig_server_t *s;
897
	dig_query_t *q;
898
899
900
901
	void *ptr;

	REQUIRE(lookup != NULL);

902
903
904
	debug("try_clear_lookup(%p)", lookup);

	if (ISC_LIST_HEAD(lookup->q) != NULL) {
905
906
907
		if (debugging) {
			q = ISC_LIST_HEAD(lookup->q);
			while (q != NULL) {
Andreas Gustafsson's avatar
spacing    
Andreas Gustafsson committed
908
				debug("query to %s still pending",
909
910
911
				       q->servname);
				q = ISC_LIST_NEXT(q, link);
			}
912
		return (ISC_FALSE);
913
		}
914
	}
915
916
917
918
	/*
	 * At this point, we know there are no queries on the lookup,
	 * so can make it go away also.
	 */
919
	debug("cleared");
920
921
922
923
924
925
	s = ISC_LIST_HEAD(lookup->my_server_list);
	while (s != NULL) {
		debug("freeing server %p belonging to %p",
		      s, lookup);
		ptr = s;
		s = ISC_LIST_NEXT(s, link);
926
		ISC_LIST_DEQUEUE(lookup->my_server_list,
927
928
				 (dig_server_t *)ptr, link);
		isc_mem_free(mctx, ptr);
929
930
931
932
933
934
935
936
937
	}
	if (lookup->sendmsg != NULL)
		dns_message_destroy(&lookup->sendmsg);
	if (lookup->querysig != NULL) {
		debug("freeing buffer %p", lookup->querysig);
		isc_buffer_free(&lookup->querysig);
	}
	if (lookup->timer != NULL)
		isc_timer_detach(&lookup->timer);
938
	if (lookup->sendspace != NULL)
939
		isc_mempool_put(commctx, lookup->sendspace);
940

941
	isc_mem_free(mctx, lookup);
942
	return (ISC_TRUE);
943
944
}

945
946
947
948

/*
 * If we can, start the next lookup in the queue running.
 * This assumes that the lookup on the head of the queue hasn't been
949
950
 * started yet.  It also removes the lookup from the head of the queue,
 * setting the current_lookup pointer pointing to it.
951
 */
952
953
954
void
start_lookup(void) {
	debug("start_lookup()");
955
956
	if (cancel_now)
		return;
957
958
959
960
961
962
963

	/*
	 * If there's a current lookup running, we really shouldn't get
	 * here.
	 */
	INSIST(current_lookup == NULL);

964
	current_lookup = ISC_LIST_HEAD(lookup_list);
965
966
967
	/*
	 * Put the current lookup somewhere so cancel_all can find it
	 */
968
969
970
971
	if (current_lookup != NULL) {
		ISC_LIST_DEQUEUE(lookup_list, current_lookup, link);
		setup_lookup(current_lookup);
		do_lookup(current_lookup);
972
973
	} else {
		check_if_done();
974
	}
975
976
977
}

/*
Michael Sawyer's avatar
Michael Sawyer committed
978
979
 * If we can, clear the current lookup and start the next one running.
 * This calls try_clear_lookup, so may invalidate the lookup pointer.
980
981
982
 */
static void
check_next_lookup(dig_lookup_t *lookup) {
983

984
	INSIST(!free_now);
985

986
	debug("check_next_lookup(%p)", lookup);
987

988
989
	if (ISC_LIST_HEAD(lookup->q) != NULL) {
		debug("still have a worker");
990
		return;
991
	}
992
993
994
995
	if (try_clear_lookup(lookup)) {
		current_lookup = NULL;
		start_lookup();
	}
996
997
}

Michael Sawyer's avatar
Michael Sawyer committed
998
999
1000
/*
 * Create and queue a new lookup as a followup to the current lookup,
 * based on the supplied message and section.  This is used in trace and
For faster browsing, not all history is shown. View entire blame