dighost.c 65.4 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
 */

18
/* $Id: dighost.c,v 1.108 2000/08/02 19:49:57 tale 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/message.h>
Brian Wellington's avatar
Brian Wellington committed
40
#include <dns/name.h>
41
42
#include <dns/rdata.h>
#include <dns/rdataclass.h>
Michael Sawyer's avatar
Michael Sawyer committed
43
#include <dns/rdatalist.h>
44
#include <dns/rdataset.h>
Michael Sawyer's avatar
Michael Sawyer committed
45
#include <dns/rdatastruct.h>
46
47
#include <dns/rdatatype.h>
#include <dns/result.h>
48
#include <dns/tsig.h>
49
#include <dst/dst.h>
50

Michael Sawyer's avatar
Michael Sawyer committed
51
52
53
54
55
#include <isc/app.h>
#include <isc/base64.h>
#include <isc/entropy.h>
#include <isc/lang.h>
#include <isc/netdb.h>
Michael Sawyer's avatar
Michael Sawyer committed
56
#include <isc/result.h>
Michael Sawyer's avatar
Michael Sawyer committed
57
58
59
60
61
#include <isc/string.h>
#include <isc/task.h>
#include <isc/timer.h>
#include <isc/types.h>
#include <isc/util.h>
62

63
64
65
#include <dig/dig.h>

ISC_LIST(dig_lookup_t) lookup_list;
66
dig_serverlist_t server_list;
67
ISC_LIST(dig_searchlist_t) search_list;
68

69
70
71
72
isc_boolean_t
	have_ipv6 = ISC_FALSE,
	specified_source = ISC_FALSE,
	free_now = ISC_FALSE,
73
	cancel_now = ISC_FALSE,
74
75
76
	show_details = ISC_FALSE,
	usesearch = ISC_FALSE,
	qr = ISC_FALSE,
Michael Sawyer's avatar
Michael Sawyer committed
77
78
	is_dst_up = ISC_FALSE,
	have_domain = ISC_FALSE;
79

80
in_port_t port = 53;
81
unsigned int timeout = 0;
82
83
isc_mem_t *mctx = NULL;
isc_taskmgr_t *taskmgr = NULL;
84
isc_task_t *global_task = NULL;
85
86
isc_timermgr_t *timermgr = NULL;
isc_socketmgr_t *socketmgr = NULL;
87
isc_sockaddr_t bind_address;
Michael Sawyer's avatar
Michael Sawyer committed
88
isc_sockaddr_t bind_any;
89
isc_buffer_t rootbuf;
90
int sendcount = 0;
91
int recvcount = 0;
Michael Sawyer's avatar
Michael Sawyer committed
92
int sockcount = 0;
93
int ndots = -1;
94
int tries = 2;
95
int lookup_counter = 0;
96
char fixeddomain[MXNAME] = "";
97
int exitcode = 9;
98
char keynametext[MXNAME];
99
char keyfile[MXNAME] = "";
100
char keysecret[MXNAME] = "";
101
102
103
dns_name_t keyname;
isc_buffer_t *namebuf = NULL;
dns_tsigkey_t *key = NULL;
104
isc_boolean_t validated = ISC_TRUE;
105
isc_entropy_t *entp = NULL;
106
isc_mempool_t *commctx = NULL;
107
isc_boolean_t debugging = ISC_FALSE;
Michael Sawyer's avatar
Michael Sawyer committed
108
char *progname = NULL;
109
isc_mutex_t lookup_lock;
110
dig_lookup_t *current_lookup = NULL;
111
112
isc_uint32_t name_limit = INT_MAX;
isc_uint32_t rr_limit = INT_MAX;
113
114
115

/*
 * Apply and clear locks at the event level in global task.
116
 * Can I get rid of these using shutdown events?  XXX
117
118
119
120
121
122
123
124
125
126
127
 */
#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");\
}
128

129
static void
130
131
cancel_lookup(dig_lookup_t *lookup);

Michael Sawyer's avatar
Michael Sawyer committed
132
133
134
135
136
137
static void
recv_done(isc_task_t *task, isc_event_t *event);

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

138
139
140
static int
count_dots(char *string) {
	char *s;
141
	int i = 0;
142
143

	s = string;
144
	while (*s != '\0') {
145
146
147
148
149
150
151
		if (*s == '.')
			i++;
		s++;
	}
	return (i);
}

152
static void
153
hex_dump(isc_buffer_t *b) {
154
155
156
	unsigned int len;
	isc_region_t r;

157
	isc_buffer_remainingregion(b, &r);
158

159
	printf("Printing a buffer with length %d\n", r.length);
160
	for (len = 0; len < r.length; len++) {
161
162
163
164
165
166
167
168
169
		printf("%02x ", r.base[len]);
		if (len != 0 && len % 16 == 0)
			printf("\n");
	}
	if (len % 16 != 0)
		printf("\n");
}

void
David Lawrence's avatar
David Lawrence committed
170
fatal(const char *format, ...) {
171
172
	va_list args;

173
	fprintf(stderr, "%s: ", progname);
174
	va_start(args, format);
175
176
177
	vfprintf(stderr, format, args);
	va_end(args);
	fprintf(stderr, "\n");
178
179
	if (exitcode == 0)
		exitcode = 8;
180
	exit(exitcode);
181
182
}

183
void
David Lawrence's avatar
David Lawrence committed
184
debug(const char *format, ...) {
185
186
	va_list args;

187
	if (debugging) {
188
		va_start(args, format);
189
190
191
192
		vfprintf(stderr, format, args);
		va_end(args);
		fprintf(stderr, "\n");
	}
193
194
}

195
void
David Lawrence's avatar
David Lawrence committed
196
check_result(isc_result_t result, const char *msg) {
197
198
	if (result != ISC_R_SUCCESS) {
		exitcode = 1;
199
		fatal("%s: %s", msg, isc_result_totext(result));
200
	}
201
202
}

Michael Sawyer's avatar
Michael Sawyer committed
203
204
205
206
207
/*
 * 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
 */
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
dig_server_t *
make_server(const char *servname) {
	dig_server_t *srv;

	REQUIRE(servname != NULL);

	debug("make_server(%s)",servname);
	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);
	return (srv);
}

223
/*
Michael Sawyer's avatar
Michael Sawyer committed
224
225
226
 * Produce a cloned server list.  The dest list must have already had
 * ISC_LIST_INIT applied.
 */
227
void
228
clone_server_list(dig_serverlist_t src,
229
230
231
232
233
234
235
236
237
238
239
240
241
		  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);
		ISC_LIST_ENQUEUE(*dest, newsrv, link);
		srv = ISC_LIST_NEXT(srv, link);
	}
}

Michael Sawyer's avatar
Michael Sawyer committed
242
243
244
245
246
247
/*
 * 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).
 */
248
dig_lookup_t *
249
make_empty_lookup(void) {
250
251
	dig_lookup_t *looknew;

252
	debug("make_lookup()");
253

254
	INSIST(!free_now);
255

256
	looknew = isc_mem_allocate(mctx, sizeof(struct dig_lookup));
257
	if (looknew == NULL)
258
		fatal("Memory allocation failure in %s:%d",
259
		       __FILE__, __LINE__);
260
261
	looknew->pending = ISC_TRUE;
	looknew->textname[0]=0;
262
263
	looknew->rdtype=dns_rdatatype_a;
	looknew->rdclass=dns_rdataclass_in;
264
	looknew->sendspace = NULL;
265
266
267
	looknew->sendmsg = NULL;
	looknew->name = NULL;
	looknew->oname = NULL;
268
269
	looknew->timer = NULL;
	looknew->xfr_q = NULL;
270
271
272
273
274
275
276
277
	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;
	looknew->udpsize = 0;
	looknew->recurse = ISC_TRUE;
Michael Sawyer's avatar
Michael Sawyer committed
278
	looknew->aaonly = ISC_FALSE;
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
	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;
	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;
	ISC_LIST_INIT(looknew->q);
295
	ISC_LIST_INIT(looknew->my_server_list);
296
297
298
	return (looknew);
}

299
/*
Michael Sawyer's avatar
Michael Sawyer committed
300
301
302
 * 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.
303
304
305
 * Caution: If you don't clone the servers, you MUST clone the server
 * list seperately from somewhere else, or construct it by hand.
 */
306
307
308
309
310
311
312
313
314
315
316
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);
317
318
	looknew->rdtype = lookold->rdtype;
	looknew->rdclass = lookold->rdclass;
319
	looknew->doing_xfr = lookold->doing_xfr;
Michael Sawyer's avatar
Michael Sawyer committed
320
	looknew->ixfr_serial = lookold->ixfr_serial;
321
322
323
324
325
326
	looknew->defname = lookold->defname;
	looknew->trace = lookold->trace;
	looknew->trace_root = lookold->trace_root;
	looknew->identify = lookold->identify;
	looknew->udpsize = lookold->udpsize;
	looknew->recurse = lookold->recurse;
Michael Sawyer's avatar
Michael Sawyer committed
327
        looknew->aaonly = lookold->aaonly;
328
329
	looknew->adflag = lookold->adflag;
	looknew->cdflag = lookold->cdflag;
330
331
332
333
334
335
336
337
338
	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;

339
340
341
	if (servers)
		clone_server_list(lookold->my_server_list,
				  &looknew->my_server_list);
342
343
344
	return (looknew);
}

Michael Sawyer's avatar
Michael Sawyer committed
345
346
347
348
349
350
351
352
/*
 * 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.
 */
353
354
355
356
357
358
359
360
361
362
363
364
365
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
366
	debug("before insertion, init@%p "
367
368
	       "-> %p, new@%p -> %p",
	      lookold, lookold->link.next, looknew, looknew->link.next);
Michael Sawyer's avatar
Michael Sawyer committed
369
	ISC_LIST_PREPEND(lookup_list, looknew, link);
Michael Sawyer's avatar
Michael Sawyer committed
370
	debug("after insertion, init -> "
371
	      "%p, new = %p, new -> %p",
372
	      lookold, looknew, looknew->link.next);
373
	return (looknew);
374
}
375

376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391

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;
392
	secretstore = isc_mem_allocate(mctx, secretsize);
393
394
395
396
397
398
399
400
401
	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));
402
		goto failure;
403
404
405
	}
	secretsize = isc_buffer_usedlength(&secretbuf);
	isc_stdtime_get(&now);
406

407
408
409
410
411
412
	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));
413
		goto failure;
414
415
416
417
	}
	result = dns_tsigkey_create(&keyname, dns_tsig_hmacmd5_name,
				    secretstore, secretsize,
				    ISC_TRUE, NULL, now, now, mctx,
418
				    NULL, &key);
419
420
421
422
	if (result != ISC_R_SUCCESS) {
		printf(";; Couldn't create key %s: %s\n",
		       keynametext, dns_result_totext(result));
	}
423
 failure:
424
	isc_mem_free(mctx, secretstore);
425
426
427
428
429
430
431
432
433
434
435
436
437
438
	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;

439

440
441
442
443
444
445
446
447
	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;
	}
448
449
450
	/*
	 * Get key size in bits, convert to bytes, rounding up (?)
	 */
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
	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,
468
				    NULL, &key);
469
470
471
472
473
474
475
476
477
478
479
	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
480
481
482
483
/*
 * Setup the system as a whole, reading key information and resolv.conf
 * settings.
 */
484
void
485
setup_system(void) {
486
487
488
489
	char rcinput[MXNAME];
	FILE *fp;
	char *ptr;
	dig_server_t *srv;
490
491
	dig_searchlist_t *search;
	isc_boolean_t get_servers;
492

493
	debug("setup_system()");
Michael Sawyer's avatar
Michael Sawyer committed
494

495
	if (fixeddomain[0] != 0) {
Michael Sawyer's avatar
Michael Sawyer committed
496
		debug("using fixed domain %s", fixeddomain);
497
		search = isc_mem_allocate(mctx, sizeof(struct dig_server));
498
		if (search == NULL)
499
500
			fatal("Memory allocation failure in %s:%d",
			      __FILE__, __LINE__);
501
502
503
		strncpy(search->origin, fixeddomain,
			sizeof(search->origin) - 1);
		/* XXX Check ordering, with search -vs- domain */
504
505
506
		ISC_LIST_PREPEND(search_list, search, link);
	}

507
	free_now = ISC_FALSE;
508
	get_servers = ISC_TF(server_list.head == NULL);
509
	fp = fopen(RESOLVCONF, "r");
510
	/* XXX Use lwres resolv.conf reader */
511
512
	if (fp != NULL) {
		while (fgets(rcinput, MXNAME, fp) != 0) {
513
			ptr = strtok(rcinput, " \t\r\n");
514
515
			if (ptr != NULL) {
				if (get_servers &&
516
				    strcasecmp(ptr, "nameserver") == 0) {
Michael Sawyer's avatar
Michael Sawyer committed
517
					debug("got a nameserver line");
518
					ptr = strtok(NULL, " \t\r\n");
519
					if (ptr != NULL) {
520
521
522
523
						srv = make_server(ptr);
						ISC_LIST_APPEND
							(server_list,
							 srv, link);
524
					}
525
				} else if (strcasecmp(ptr, "options") == 0) {
526
527
					ptr = strtok(NULL, " \t\r\n");
					if (ptr != NULL) {
528
						if((strncasecmp(ptr, "ndots:",
529
530
531
532
							    6) == 0) &&
						    (ndots == -1)) {
							ndots = atoi(
							      &ptr[6]);
533
							debug("ndots is "
534
535
536
537
							       "%d.",
							       ndots);
						}
					}
Michael Sawyer's avatar
Michael Sawyer committed
538
				} else if (strcasecmp(ptr, "search") == 0){
539
540
					while ((ptr = strtok(NULL, " \t\r\n"))
					       != NULL) {
Michael Sawyer's avatar
Michael Sawyer committed
541
542
						debug("adding search %s",
						      ptr);
543
544
545
546
547
548
						search = isc_mem_allocate(
						   mctx, sizeof(struct
								dig_server));
						if (search == NULL)
							fatal("Memory "
							      "allocation "
549
							      "failure in %s:"
550
							      "%d", __FILE__,
551
							      __LINE__);
552
553
554
555
556
557
558
559
560
						strncpy(search->
							origin,
							ptr,
							MXNAME - 1);
						ISC_LIST_APPEND
							(search_list,
							 search,
							 link);
					}
561
				} else if ((strcasecmp(ptr, "domain") == 0) &&
562
					   (fixeddomain[0] == 0 )){
Michael Sawyer's avatar
Michael Sawyer committed
563
					have_domain = ISC_TRUE;
564
565
566
567
568
569
570
571
					while ((ptr = strtok(NULL, " \t\r\n"))
					       != NULL) {
						search = isc_mem_allocate(
						   mctx, sizeof(struct
								dig_server));
						if (search == NULL)
							fatal("Memory "
							      "allocation "
572
							      "failure in %s:"
573
							      "%d", __FILE__,
574
							      __LINE__);
575
576
577
578
579
580
581
582
583
						strncpy(search->
							origin,
							ptr,
							MXNAME - 1);
						ISC_LIST_PREPEND
							(search_list,
							 search,
							 link);
					}
584
585
586
				}
			}
		}
587
		fclose(fp);
588
	}
589

590
591
592
	if (ndots == -1)
		ndots = 1;

593
	if (server_list.head == NULL) {
594
		srv = make_server("127.0.0.1");
595
596
		ISC_LIST_APPEND(server_list, srv, link);
	}
597

598
599
600
601
	if (keyfile[0] != 0)
		setup_file_key();
	else if (keysecret[0] != 0)
		setup_text_key();
602
}
603

Michael Sawyer's avatar
Michael Sawyer committed
604
605
606
/*
 * Setup the ISC and DNS libraries for use by the system.
 */
607
void
608
setup_libs(void) {
609
610
	isc_result_t result;

611
	debug("setup_libs()");
612
613
614
615
616
617

	/*
	 * 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.
	 */
618
	srandom(getpid() + (int)&setup_libs);
619

620
	result = isc_net_probeipv4();
621
	check_result(result, "isc_net_probeipv4");
622
623
624

	result = isc_net_probeipv6();
	if (result == ISC_R_SUCCESS)
625
		have_ipv6 = ISC_TRUE;
626

627
628
	result = isc_mem_create(0, 0, &mctx);
	check_result(result, "isc_mem_create");
629

630
	result = isc_taskmgr_create(mctx, 1, 0, &taskmgr);
631
	check_result(result, "isc_taskmgr_create");
632

633
	result = isc_task_create(taskmgr, 0, &global_task);
634
	check_result(result, "isc_task_create");
635

636
	result = isc_timermgr_create(mctx, &timermgr);
637
	check_result(result, "isc_timermgr_create");
638

639
	result = isc_socketmgr_create(mctx, &socketmgr);
640
	check_result(result, "isc_socketmgr_create");
641

642
	result = isc_entropy_create(mctx, &entp);
643
644
	check_result(result, "isc_entropy_create");

645
	result = dst_lib_init(mctx, entp, 0);
646
647
	check_result(result, "dst_lib_init");
	is_dst_up = ISC_TRUE;
648
649
650
651
652
653
654
655
656
657

	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);
658
659
660

	result = isc_mutex_init(&lookup_lock);
	check_result(result, "isc_mutex_init");
661
662
}

Michael Sawyer's avatar
Michael Sawyer committed
663
664
665
666
/*
 * Add EDNS0 option record to a message.  Currently, the only supported
 * option is UDP buffer size.
 */
667
static void
668
add_opt(dns_message_t *msg, isc_uint16_t udpsize) {
669
670
671
672
673
	dns_rdataset_t *rdataset = NULL;
	dns_rdatalist_t *rdatalist = NULL;
	dns_rdata_t *rdata = NULL;
	isc_result_t result;

674
	debug("add_opt()");
675
	result = dns_message_gettemprdataset(msg, &rdataset);
676
677
	check_result(result, "dns_message_gettemprdataset");
	dns_rdataset_init(rdataset);
678
	result = dns_message_gettemprdatalist(msg, &rdatalist);
679
	check_result(result, "dns_message_gettemprdatalist");
680
	result = dns_message_gettemprdata(msg, &rdata);
681
	check_result(result, "dns_message_gettemprdata");
682

Michael Sawyer's avatar
Michael Sawyer committed
683
	debug("setting udp size of %d", udpsize);
684
685
686
687
688
689
690
691
692
693
	rdatalist->type = dns_rdatatype_opt;
	rdatalist->covers = 0;
	rdatalist->rdclass = udpsize;
	rdatalist->ttl = 0;
	rdata->data = NULL;
	rdata->length = 0;
	ISC_LIST_INIT(rdatalist->rdata);
	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
	dns_rdatalist_tordataset(rdatalist, rdataset);
	result = dns_message_setopt(msg, rdataset);
694
	check_result(result, "dns_message_setopt");
695
696
}

Michael Sawyer's avatar
Michael Sawyer committed
697
/*
698
 * Add a question section to a message, asking for the specified name,
Michael Sawyer's avatar
Michael Sawyer committed
699
700
 * type, and class.
 */
701
static void
Michael Sawyer's avatar
Michael Sawyer committed
702
703
add_question(dns_message_t *message, dns_name_t *name,
	     dns_rdataclass_t rdclass, dns_rdatatype_t rdtype)
704
705
706
707
{
	dns_rdataset_t *rdataset;
	isc_result_t result;

708
	debug("add_question()");
709
710
711
712
713
714
715
716
	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
717
/*
Michael Sawyer's avatar
Michael Sawyer committed
718
719
720
721
722
723
 * 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
724
 */
725
726
727
static void
check_if_done(void) {
	debug("check_if_done()");
728
729
730
731
732
	debug("list %s", ISC_LIST_EMPTY(lookup_list)?"empty":"full");
	if (ISC_LIST_EMPTY(lookup_list) && current_lookup == NULL) {
		INSIST(sockcount == 0);
		INSIST(recvcount == 0);
		INSIST(sendcount == 0);
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
		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);

748
749
	debug("clear_query(%p)",query);

750
	lookup = query->lookup;
751

752
753
754
755
756
757
758
	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);
759
	INSIST(query->recvspace != NULL);
760
761
762
763
764
	if (query->sock != NULL) {
		isc_socket_detach(&query->sock);
		sockcount--;
		debug("sockcount=%d", sockcount);
	}
765
	isc_mempool_put(commctx, query->recvspace);
766
767
768
769
	isc_buffer_invalidate(&query->recvbuf);
	isc_buffer_invalidate(&query->lengthbuf);
	isc_mem_free(mctx, query);
}
770

Michael Sawyer's avatar
Michael Sawyer committed
771
772
773
774
775
/*
 * 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
776
static isc_boolean_t
777
778
try_clear_lookup(dig_lookup_t *lookup) {
	dig_server_t *s;
779
	dig_query_t *q;
780
781
782
783
	void *ptr;

	REQUIRE(lookup != NULL);

784
785
786
	debug("try_clear_lookup(%p)", lookup);

	if (ISC_LIST_HEAD(lookup->q) != NULL) {
787
788
789
790
791
792
793
		if (debugging) {
			q = ISC_LIST_HEAD(lookup->q);
			while (q != NULL) {
				debug ("query to %s still pending",
				       q->servname);
				q = ISC_LIST_NEXT(q, link);
			}
794
		return (ISC_FALSE);
795
		}
796
	}
797
798
799
800
	/*
	 * At this point, we know there are no queries on the lookup,
	 * so can make it go away also.
	 */
801
	debug("cleared");
802
803
804
805
806
807
	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);
808
		ISC_LIST_DEQUEUE(lookup->my_server_list,
809
810
				 (dig_server_t *)ptr, link);
		isc_mem_free(mctx, ptr);
811
812
813
814
815
816
817
818
819
	}
	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);
820
	if (lookup->sendspace != NULL)
821
		isc_mempool_put(commctx, lookup->sendspace);
822

823
	isc_mem_free(mctx, lookup);
824
	return (ISC_TRUE);
825
826
}

827
828
829
830

/*
 * 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
831
832
 * started yet.  It also removes the lookup from the head of the queue,
 * setting the current_lookup pointer pointing to it.
833
 */
834
835
836
void
start_lookup(void) {
	debug("start_lookup()");
837
838
	if (cancel_now)
		return;
839
840
841
842
843
844
845

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

846
	current_lookup = ISC_LIST_HEAD(lookup_list);
847
848
849
	/*
	 * Put the current lookup somewhere so cancel_all can find it
	 */
850
851
852
853
	if (current_lookup != NULL) {
		ISC_LIST_DEQUEUE(lookup_list, current_lookup, link);
		setup_lookup(current_lookup);
		do_lookup(current_lookup);
854
855
	} else {
		check_if_done();
856
	}
857
858
859
}

/*
Michael Sawyer's avatar
Michael Sawyer committed
860
861
 * If we can, clear the current lookup and start the next one running.
 * This calls try_clear_lookup, so may invalidate the lookup pointer.
862
863
864
 */
static void
check_next_lookup(dig_lookup_t *lookup) {
865

866
	INSIST(!free_now);
867

868
	debug("check_next_lookup(%p)", lookup);
869

870
871
	if (ISC_LIST_HEAD(lookup->q) != NULL) {
		debug("still have a worker");
872
		return;
873
	}
874
875
876
877
	if (try_clear_lookup(lookup)) {
		current_lookup = NULL;
		start_lookup();
	}
878
879
}

Michael Sawyer's avatar
Michael Sawyer committed
880
881
882
883
884
885
/*
 * 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
 * name server search modes to start a new lookup using servers from
 * NS records in a reply.
 */
886
static void
887
888
followup_lookup(dns_message_t *msg, dig_query_t *query,
		dns_section_t section) {
889
890
891
892
893
894
895
896
	dig_lookup_t *lookup = NULL;
	dig_server_t *srv = NULL;
	dns_rdataset_t *rdataset = NULL;
	dns_rdata_t rdata;
	dns_name_t *name = NULL;
	isc_result_t result, loopresult;
	isc_buffer_t *b = NULL;
	isc_region_t r;
897
	isc_boolean_t success = ISC_FALSE;
898
899
	int len;

900
901
	INSIST(!free_now);

902
	debug("followup_lookup()");
903
	result = dns_message_firstname(msg,section);
904

905
	if (result != ISC_R_SUCCESS) {
Michael Sawyer's avatar
Michael Sawyer committed
906
		debug("firstname returned %s",
907
			isc_result_totext(result));
908
		if ((section == DNS_SECTION_ANSWER) &&
909
		    (query->lookup->trace || query->lookup->ns_search_only))
910
			followup_lookup(msg, query, DNS_SECTION_AUTHORITY);
911
912
913
                return;
	}

Michael Sawyer's avatar
Michael Sawyer committed
914
	debug("following up %s", query->lookup->textname);
915
916
917

	for (;;) {
		name = NULL;
918
		dns_message_currentname(msg, section, &name);
919
920
921
922
923
924
		for (rdataset = ISC_LIST_HEAD(name->list);
		     rdataset != NULL;
		     rdataset = ISC_LIST_NEXT(rdataset, link)) {
			loopresult = dns_rdataset_first(rdataset);
			while (loopresult == ISC_R_SUCCESS) {
				dns_rdataset_current(rdataset, &rdata);
Michael Sawyer's avatar
Michael Sawyer committed
925
				debug("got rdata with type %d",
926
927
928
				       rdata.type);
				if ((rdata.type == dns_rdatatype_ns) &&
				    (!query->lookup->trace_root ||
929
				     (query->lookup->nsfound < MXSERV)))
930
931
				{
					query->lookup->nsfound++;
932
933
					result = isc_buffer_allocate(mctx, &b,
								     BUFSIZE);
934
					check_result(result,
935
						      "isc_buffer_allocate");
936
937
938
939
					result = dns_rdata_totext(&rdata,
								  NULL,
								  b);
					check_result(result,
940
941
942
943
944
945
						      "dns_rdata_totext");
					isc_buffer_usedregion(b, &r);
					len = r.length-1;
					if (len >= MXNAME)
						len = MXNAME-1;
				/* Initialize lookup if we've not yet */
Michael Sawyer's avatar
Michael Sawyer committed
946
					debug("found NS %d %.*s",
947
948
						 (int)r.length, (int)r.length,
						 (char *)r.base);
949
950
951
					if (!success) {
						success = ISC_TRUE;
						lookup_counter++;
952
						cancel_lookup(query->lookup);
953
954
955
						lookup = requeue_lookup
							(query->lookup,
							 ISC_FALSE);
956
						lookup->doing_xfr = ISC_FALSE;
957
						lookup->defname = ISC_FALSE;
958
						if (section ==
959
960
						    DNS_SECTION_ANSWER) {
						      lookup->trace =
961
								ISC_FALSE;
962
963
964
965
966
						      lookup->ns_search_only =
								ISC_FALSE;
						}
						else {
						      lookup->trace =
967
968
								query->
								lookup->trace;
969
970
971
972
						      lookup->ns_search_only =
							query->
							lookup->ns_search_only;
						}
973
974
						lookup->trace_root = ISC_FALSE;
					}
975
976
977
					r.base[len]=0;
					srv = make_server(r.base);
					debug("adding server %s",
978
					       srv->servername);
979
980
981
					ISC_LIST_APPEND
						(lookup->my_server_list,
						 srv, link);
982
					isc_buffer_free(&b);
983
984
985
986
				}
				loopresult = dns_rdataset_next(rdataset);
			}
		}
987
		result = dns_message_nextname(msg, section);
988
989
		if (result != ISC_R_SUCCESS)
			break;
990
	}
991
	if ((lookup == NULL) && (section == DNS_SECTION_ANSWER) &&
992
	    (query->lookup->trace || query->lookup->ns_search_only))
993
		followup_lookup(msg, query, DNS_SECTION_AUTHORITY);
994
995
}

Michael Sawyer's avatar
Michael Sawyer committed
996
997
998
999
/*
 * Create and queue a new lookup using the next origin from the origin
 * list, read in setup_system().
 */
Michael Sawyer's avatar
Michael Sawyer committed
1000
static isc_boolean_t
1001
1002
1003
next_origin(dns_message_t *msg, dig_query_t *query) {
	dig_lookup_t *lookup;

1004
	UNUSED(msg);
1005

1006
1007
	INSIST(!free_now);

1008
	debug("next_origin()");
Michael Sawyer's avatar
Michael Sawyer committed
1009
	debug("following up %s", query->lookup->textname);
1010

Michael Sawyer's avatar
Michael Sawyer committed
1011
1012
1013
1014
1015
1016
1017
	if (!usesearch)
		/*
		 * We're not using a search list, so don't even think
		 * about finding the next entry.
		 */
		return (ISC_FALSE);
	if (query->lookup->origin == NULL)
1018
1019
1020
		/*
		 * Then we just did rootorg; there's nothing left.
		 */
Michael Sawyer's avatar
Michael Sawyer committed
1021
		return (ISC_FALSE);
1022
	cancel_lookup(query->lookup);
1023
	lookup = requeue_lookup(query->lookup, ISC_TRUE);
1024
	lookup->defname = ISC_FALSE;
1025
	lookup->origin = ISC_LIST_NEXT(query->lookup->origin, link);