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

Automatic Updater's avatar
Automatic Updater committed
18
/* $Id: nslookup.c,v 1.119 2008/12/16 23:47:57 tbox Exp $ */
19

20 21 22 23
#include <config.h>

#include <stdlib.h>

Michael Sawyer's avatar
Michael Sawyer committed
24 25 26
#include <isc/app.h>
#include <isc/buffer.h>
#include <isc/commandline.h>
27
#include <isc/event.h>
28
#include <isc/parseint.h>
Michael Sawyer's avatar
Michael Sawyer committed
29 30 31
#include <isc/string.h>
#include <isc/timer.h>
#include <isc/util.h>
32
#include <isc/task.h>
33
#include <isc/netaddr.h>
34

35 36
#include <dns/message.h>
#include <dns/name.h>
37
#include <dns/fixedname.h>
38 39 40
#include <dns/rdata.h>
#include <dns/rdataclass.h>
#include <dns/rdataset.h>
41
#include <dns/rdatastruct.h>
42
#include <dns/rdatatype.h>
43
#include <dns/byaddr.h>
44

45 46
#include <dig/dig.h>

Brian Wellington's avatar
Brian Wellington committed
47
static isc_boolean_t short_form = ISC_TRUE,
48
	tcpmode = ISC_FALSE,
Brian Wellington's avatar
Brian Wellington committed
49
	identify = ISC_FALSE, stats = ISC_TRUE,
50 51 52
	comments = ISC_TRUE, section_question = ISC_TRUE,
	section_answer = ISC_TRUE, section_authority = ISC_TRUE,
	section_additional = ISC_TRUE, recurse = ISC_TRUE,
53 54
	aaonly = ISC_FALSE, nofail = ISC_TRUE;

Brian Wellington's avatar
Brian Wellington committed
55 56 57 58
static isc_boolean_t in_use = ISC_FALSE;
static char defclass[MXRD] = "IN";
static char deftype[MXRD] = "A";
static isc_event_t *global_event = NULL;
59

Brian Wellington's avatar
Brian Wellington committed
60
static char domainopt[DNS_NAME_MAXTEXT];
61

62
static const char *rcodetext[] = {
63 64 65 66
	"NOERROR",
	"FORMERR",
	"SERVFAIL",
	"NXDOMAIN",
67
	"NOTIMP",
68 69 70 71 72 73 74 75 76 77 78 79 80 81
	"REFUSED",
	"YXDOMAIN",
	"YXRRSET",
	"NXRRSET",
	"NOTAUTH",
	"NOTZONE",
	"RESERVED11",
	"RESERVED12",
	"RESERVED13",
	"RESERVED14",
	"RESERVED15",
	"BADVERS"
};

82
static const char *rtypetext[] = {
83 84 85 86 87 88
	"rtype_0 = ",			/* 0 */
	"internet address = ",		/* 1 */
	"nameserver = ",		/* 2 */
	"md = ",			/* 3 */
	"mf = ",			/* 4 */
	"canonical name = ",		/* 5 */
Brian Wellington's avatar
Brian Wellington committed
89 90 91 92 93
	"soa = ",			/* 6 */
	"mb = ",			/* 7 */
	"mg = ",			/* 8 */
	"mr = ",			/* 9 */
	"rtype_10 = ",			/* 10 */
94 95 96 97
	"protocol = ",			/* 11 */
	"name = ",			/* 12 */
	"hinfo = ",			/* 13 */
	"minfo = ",			/* 14 */
Brian Wellington's avatar
Brian Wellington committed
98
	"mail exchanger = ",		/* 15 */
99 100 101 102 103
	"text = ",			/* 16 */
	"rp = ",       			/* 17 */
	"afsdb = ",			/* 18 */
	"x25 address = ",		/* 19 */
	"isdn address = ",		/* 20 */
104
	"rt = ",			/* 21 */
105 106 107 108
	"nsap = ",			/* 22 */
	"nsap_ptr = ",			/* 23 */
	"signature = ",			/* 24 */
	"key = ",			/* 25 */
Brian Wellington's avatar
Brian Wellington committed
109 110
	"px = ",			/* 26 */
	"gpos = ",			/* 27 */
111
	"has AAAA address ",		/* 28 */
Brian Wellington's avatar
Brian Wellington committed
112
	"loc = ",			/* 29 */
113 114 115
	"next = ",			/* 30 */
	"rtype_31 = ",			/* 31 */
	"rtype_32 = ",			/* 32 */
Brian Wellington's avatar
Brian Wellington committed
116
	"service = ",			/* 33 */
117 118 119 120 121 122
	"rtype_34 = ",			/* 34 */
	"naptr = ",			/* 35 */
	"kx = ",			/* 36 */
	"cert = ",			/* 37 */
	"v6 address = ",		/* 38 */
	"dname = ",			/* 39 */
Brian Wellington's avatar
Brian Wellington committed
123
	"rtype_40 = ",			/* 40 */
Andreas Gustafsson's avatar
style  
Andreas Gustafsson committed
124 125
	"optional = "			/* 41 */
};
126

127
#define N_KNOWN_RRTYPES (sizeof(rtypetext) / sizeof(rtypetext[0]))
128

129 130 131
static void flush_lookup_list(void);
static void getinput(isc_task_t *task, isc_event_t *event);

132
void
133
dighost_shutdown(void) {
134 135 136
	isc_event_t *event = global_event;

	flush_lookup_list();
Brian Wellington's avatar
Brian Wellington committed
137
	debug("dighost_shutdown()");
138 139 140 141 142 143 144

	if (!in_use) {
		isc_app_shutdown();
		return;
	}

	isc_task_send(global_task, &event);
145
}
Brian Wellington's avatar
Brian Wellington committed
146

147 148 149 150 151 152 153 154 155 156 157
static void
printsoa(dns_rdata_t *rdata) {
	dns_rdata_soa_t soa;
	isc_result_t result;
	char namebuf[DNS_NAME_FORMATSIZE];

	result = dns_rdata_tostruct(rdata, &soa, NULL);
	check_result(result, "dns_rdata_tostruct");

	dns_name_format(&soa.origin, namebuf, sizeof(namebuf));
	printf("\torigin = %s\n", namebuf);
158
	dns_name_format(&soa.contact, namebuf, sizeof(namebuf));
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
	printf("\tmail addr = %s\n", namebuf);
	printf("\tserial = %u\n", soa.serial);
	printf("\trefresh = %u\n", soa.refresh);
	printf("\tretry = %u\n", soa.retry);
	printf("\texpire = %u\n", soa.expire);
	printf("\tminimum = %u\n", soa.minimum);
	dns_rdata_freestruct(&soa);
}

static void
printa(dns_rdata_t *rdata) {
	isc_result_t result;
	char text[sizeof("255.255.255.255")];
	isc_buffer_t b;

	isc_buffer_init(&b, text, sizeof(text));
	result = dns_rdata_totext(rdata, NULL, &b);
	check_result(result, "dns_rdata_totext");
	printf("Address: %.*s\n", (int)isc_buffer_usedlength(&b),
	       (char *)isc_buffer_base(&b));
}
Mark Andrews's avatar
Mark Andrews committed
180
#ifdef DIG_SIGCHASE
181 182 183 184 185 186 187 188 189 190 191
/* Just for compatibility : not use in host program */
isc_result_t
printrdataset(dns_name_t *owner_name, dns_rdataset_t *rdataset,
	      isc_buffer_t *target)
{
	UNUSED(owner_name);
	UNUSED(rdataset);
	UNUSED(target);
	return(ISC_FALSE);
}
#endif
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
static void
printrdata(dns_rdata_t *rdata) {
	isc_result_t result;
	isc_buffer_t *b = NULL;
	unsigned int size = 1024;
	isc_boolean_t done = ISC_FALSE;

	if (rdata->type < N_KNOWN_RRTYPES)
		printf("%s", rtypetext[rdata->type]);
	else
		printf("rdata_%d = ", rdata->type);

	while (!done) {
		result = isc_buffer_allocate(mctx, &b, size);
		if (result != ISC_R_SUCCESS)
			check_result(result, "isc_buffer_allocate");
		result = dns_rdata_totext(rdata, NULL, b);
		if (result == ISC_R_SUCCESS) {
			printf("%.*s\n", (int)isc_buffer_usedlength(b),
			       (char *)isc_buffer_base(b));
			done = ISC_TRUE;
		} else if (result != ISC_R_NOSPACE)
			check_result(result, "dns_rdata_totext");
		isc_buffer_free(&b);
		size *= 2;
	}
}

220
static isc_result_t
221 222
printsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers,
	     dns_section_t section) {
223
	isc_result_t result, loopresult;
224 225
	dns_name_t *name;
	dns_rdataset_t *rdataset = NULL;
226
	dns_rdata_t rdata = DNS_RDATA_INIT;
227
	char namebuf[DNS_NAME_FORMATSIZE];
228

Andreas Gustafsson's avatar
Andreas Gustafsson committed
229 230
	UNUSED(query);
	UNUSED(headers);
231

232
	debug("printsection()");
233

234
	result = dns_message_firstname(msg, section);
235 236 237 238 239 240
	if (result == ISC_R_NOMORE)
		return (ISC_R_SUCCESS);
	else if (result != ISC_R_SUCCESS)
		return (result);
	for (;;) {
		name = NULL;
241
		dns_message_currentname(msg, section,
242
					&name);
243 244 245
		for (rdataset = ISC_LIST_HEAD(name->list);
		     rdataset != NULL;
		     rdataset = ISC_LIST_NEXT(rdataset, link)) {
246 247
			loopresult = dns_rdataset_first(rdataset);
			while (loopresult == ISC_R_SUCCESS) {
Andreas Gustafsson's avatar
Andreas Gustafsson committed
248 249
				dns_rdataset_current(rdataset, &rdata);
				switch (rdata.type) {
250 251 252
				case dns_rdatatype_a:
					if (section != DNS_SECTION_ANSWER)
						goto def_short_section;
253 254
					dns_name_format(name, namebuf,
							sizeof(namebuf));
255 256
					printf("Name:\t%s\n", namebuf);
					printa(&rdata);
257 258
					break;
				case dns_rdatatype_soa:
259 260 261
					dns_name_format(name, namebuf,
							sizeof(namebuf));
					printf("%s\n", namebuf);
262
					printsoa(&rdata);
263 264 265
					break;
				default:
				def_short_section:
266 267
					dns_name_format(name, namebuf,
							sizeof(namebuf));
268 269 270
					printf("%s\t", namebuf);
					printrdata(&rdata);
					break;
271
				}
272
				dns_rdata_reset(&rdata);
273
				loopresult = dns_rdataset_next(rdataset);
274 275
			}
		}
276
		result = dns_message_nextname(msg, section);
277 278
		if (result == ISC_R_NOMORE)
			break;
279
		else if (result != ISC_R_SUCCESS) {
280
			return (result);
281
		}
282 283 284 285
	}
	return (ISC_R_SUCCESS);
}

286 287 288 289 290 291
static isc_result_t
detailsection(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers,
	     dns_section_t section) {
	isc_result_t result, loopresult;
	dns_name_t *name;
	dns_rdataset_t *rdataset = NULL;
292
	dns_rdata_t rdata = DNS_RDATA_INIT;
293
	char namebuf[DNS_NAME_FORMATSIZE];
294

Andreas Gustafsson's avatar
Andreas Gustafsson committed
295
	UNUSED(query);
296

Michael Sawyer's avatar
Michael Sawyer committed
297
	debug("detailsection()");
298 299 300 301

	if (headers) {
		switch (section) {
		case DNS_SECTION_QUESTION:
Andreas Gustafsson's avatar
Andreas Gustafsson committed
302
			puts("    QUESTIONS:");
303 304
			break;
		case DNS_SECTION_ANSWER:
Andreas Gustafsson's avatar
Andreas Gustafsson committed
305
			puts("    ANSWERS:");
306 307
			break;
		case DNS_SECTION_AUTHORITY:
Andreas Gustafsson's avatar
Andreas Gustafsson committed
308
			puts("    AUTHORITY RECORDS:");
309 310
			break;
		case DNS_SECTION_ADDITIONAL:
Andreas Gustafsson's avatar
Andreas Gustafsson committed
311
			puts("    ADDITIONAL RECORDS:");
312 313 314 315 316 317 318 319 320 321 322
			break;
		}
	}

	result = dns_message_firstname(msg, section);
	if (result == ISC_R_NOMORE)
		return (ISC_R_SUCCESS);
	else if (result != ISC_R_SUCCESS)
		return (result);
	for (;;) {
		name = NULL;
323
		dns_message_currentname(msg, section,
324 325 326 327
					&name);
		for (rdataset = ISC_LIST_HEAD(name->list);
		     rdataset != NULL;
		     rdataset = ISC_LIST_NEXT(rdataset, link)) {
328
			if (section == DNS_SECTION_QUESTION) {
329 330 331
				dns_name_format(name, namebuf,
						sizeof(namebuf));
				printf("\t%s, ", namebuf);
332
				dns_rdatatype_format(rdataset->type,
333 334 335
						     namebuf,
						     sizeof(namebuf));
				printf("type = %s, ", namebuf);
336
				dns_rdataclass_format(rdataset->rdclass,
337 338 339
						      namebuf,
						      sizeof(namebuf));
				printf("class = %s\n", namebuf);
340
			}
341 342 343
			loopresult = dns_rdataset_first(rdataset);
			while (loopresult == ISC_R_SUCCESS) {
				dns_rdataset_current(rdataset, &rdata);
344 345 346 347 348

				dns_name_format(name, namebuf,
						sizeof(namebuf));
				printf("    ->  %s\n", namebuf);

349 350
				switch (rdata.type) {
				case dns_rdatatype_soa:
351
					printsoa(&rdata);
352 353
					break;
				default:
354 355
					printf("\t");
					printrdata(&rdata);
356
				}
357
				dns_rdata_reset(&rdata);
358 359 360 361 362 363 364 365 366 367 368 369 370
				loopresult = dns_rdataset_next(rdataset);
			}
		}
		result = dns_message_nextname(msg, section);
		if (result == ISC_R_NOMORE)
			break;
		else if (result != ISC_R_SUCCESS) {
			return (result);
		}
	}
	return (ISC_R_SUCCESS);
}

371 372 373 374 375 376 377 378 379
void
received(int bytes, isc_sockaddr_t *from, dig_query_t *query)
{
	UNUSED(bytes);
	UNUSED(from);
	UNUSED(query);
}

void
Brian Wellington's avatar
Brian Wellington committed
380
trying(char *frm, dig_lookup_t *lookup) {
381 382 383 384 385
	UNUSED(frm);
	UNUSED(lookup);

}

386 387
isc_result_t
printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) {
Automatic Updater's avatar
Automatic Updater committed
388
	char servtext[ISC_SOCKADDR_FORMATSIZE];
389

Andreas Gustafsson's avatar
Andreas Gustafsson committed
390
	debug("printmessage()");
391 392

	isc_sockaddr_format(&query->sockaddr, servtext, sizeof(servtext));
393
	printf("Server:\t\t%s\n", query->userarg);
394
	printf("Address:\t%s\n", servtext);
Automatic Updater's avatar
Automatic Updater committed
395

396
	puts("");
397

Andreas Gustafsson's avatar
Andreas Gustafsson committed
398
	if (!short_form) {
399
		isc_boolean_t headers = ISC_TRUE;
Andreas Gustafsson's avatar
Andreas Gustafsson committed
400
		puts("------------");
401 402 403 404 405
		/*		detailheader(query, msg);*/
		detailsection(query, msg, headers, DNS_SECTION_QUESTION);
		detailsection(query, msg, headers, DNS_SECTION_ANSWER);
		detailsection(query, msg, headers, DNS_SECTION_AUTHORITY);
		detailsection(query, msg, headers, DNS_SECTION_ADDITIONAL);
Andreas Gustafsson's avatar
Andreas Gustafsson committed
406
		puts("------------");
407
	}
408

409 410 411 412
	if (msg->rcode != 0) {
		char nametext[DNS_NAME_FORMATSIZE];
		dns_name_format(query->lookup->name,
				nametext, sizeof(nametext));
413 414 415
		printf("** server can't find %s: %s\n",
		       (msg->rcode != dns_rcode_nxdomain) ? nametext :
		       query->lookup->textname, rcodetext[msg->rcode]);
416 417 418 419
		debug("returning with rcode == 0");
		return (ISC_R_SUCCESS);
	}

420
	if ((msg->flags & DNS_MESSAGEFLAG_AA) == 0)
Michael Sawyer's avatar
Michael Sawyer committed
421
		puts("Non-authoritative answer:");
422 423 424 425 426
	if (!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER]))
		printsection(query, msg, headers, DNS_SECTION_ANSWER);
	else
		printf("*** Can't find %s: No answer\n",
		       query->lookup->textname);
427

428
	if (((msg->flags & DNS_MESSAGEFLAG_AA) == 0) &&
429
	    (query->lookup->rdtype != dns_rdatatype_a)) {
Michael Sawyer's avatar
Michael Sawyer committed
430
		puts("\nAuthoritative answers can be found from:");
431 432 433 434
		printsection(query, msg, headers,
			     DNS_SECTION_AUTHORITY);
		printsection(query, msg, headers,
			     DNS_SECTION_ADDITIONAL);
435
	}
436
	return (ISC_R_SUCCESS);
437 438 439
}

static void
Michael Sawyer's avatar
Michael Sawyer committed
440
show_settings(isc_boolean_t full, isc_boolean_t serv_only) {
441
	dig_server_t *srv;
442
	isc_sockaddr_t sockaddr;
443
	dig_searchlist_t *listent;
444
	isc_result_t result;
445

446
	srv = ISC_LIST_HEAD(server_list);
447

448
	while (srv != NULL) {
Brian Wellington's avatar
Brian Wellington committed
449 450
		char sockstr[ISC_SOCKADDR_FORMATSIZE];

451 452 453
		result = get_address(srv->servername, port, &sockaddr);
		check_result(result, "get_address");

Brian Wellington's avatar
Brian Wellington committed
454 455
		isc_sockaddr_format(&sockaddr, sockstr, sizeof(sockstr));
		printf("Default server: %s\nAddress: %s\n",
456
			srv->userarg, sockstr);
457 458
		if (!full)
			return;
459
		srv = ISC_LIST_NEXT(srv, link);
460
	}
Michael Sawyer's avatar
Michael Sawyer committed
461 462
	if (serv_only)
		return;
463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482
	printf("\nSet options:\n");
	printf("  %s\t\t\t%s\t\t%s\n",
	       tcpmode ? "vc" : "novc",
	       short_form ? "nodebug" : "debug",
	       debugging ? "d2" : "nod2");
	printf("  %s\t\t%s\n",
	       usesearch ? "search" : "nosearch",
	       recurse ? "recurse" : "norecurse");
	printf("  timeout = %d\t\tretry = %d\tport = %d\n",
	       timeout, tries, port);
	printf("  querytype = %-8s\tclass = %s\n", deftype, defclass);
	printf("  srchlist = ");
	for (listent = ISC_LIST_HEAD(search_list);
	     listent != NULL;
	     listent = ISC_LIST_NEXT(listent, link)) {
		     printf("%s", listent->origin);
		     if (ISC_LIST_NEXT(listent, link) != NULL)
			     printf("/");
	}
	printf("\n");
483 484
}

485 486 487 488 489 490 491 492 493
static isc_boolean_t
testtype(char *typetext) {
	isc_result_t result;
	isc_textregion_t tr;
	dns_rdatatype_t rdtype;

	tr.base = typetext;
	tr.length = strlen(typetext);
	result = dns_rdatatype_fromtext(&rdtype, &tr);
494 495 496 497 498 499
	if (result == ISC_R_SUCCESS)
		return (ISC_TRUE);
	else {
		printf("unknown query type: %s\n", typetext);
		return (ISC_FALSE);
	}
500 501 502 503 504 505 506 507 508 509 510
}

static isc_boolean_t
testclass(char *typetext) {
	isc_result_t result;
	isc_textregion_t tr;
	dns_rdataclass_t rdclass;

	tr.base = typetext;
	tr.length = strlen(typetext);
	result = dns_rdataclass_fromtext(&rdclass, &tr);
Automatic Updater's avatar
Automatic Updater committed
511
	if (result == ISC_R_SUCCESS)
512 513 514 515 516
		return (ISC_TRUE);
	else {
		printf("unknown query class: %s\n", typetext);
		return (ISC_FALSE);
	}
517 518
}

519 520 521
static void
safecpy(char *dest, char *src, int size) {
	strncpy(dest, src, size);
Andreas Gustafsson's avatar
Andreas Gustafsson committed
522
	dest[size-1] = 0;
523
}
524 525

static isc_result_t
526 527
parse_uint(isc_uint32_t *uip, const char *value, isc_uint32_t max,
	   const char *desc) {
528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545
	isc_uint32_t n;
	isc_result_t result = isc_parse_uint32(&n, value, 10);
	if (result == ISC_R_SUCCESS && n > max)
		result = ISC_R_RANGE;
	if (result != ISC_R_SUCCESS) {
		printf("invalid %s '%s': %s\n", desc,
		       value, isc_result_totext(result));
		return result;
	}
	*uip = n;
	return (ISC_R_SUCCESS);
}

static void
set_port(const char *value) {
	isc_uint32_t n;
	isc_result_t result = parse_uint(&n, value, 65535, "port");
	if (result == ISC_R_SUCCESS)
546
		port = (isc_uint16_t) n;
547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563
}

static void
set_timeout(const char *value) {
	isc_uint32_t n;
	isc_result_t result = parse_uint(&n, value, UINT_MAX, "timeout");
	if (result == ISC_R_SUCCESS)
		timeout = n;
}

static void
set_tries(const char *value) {
	isc_uint32_t n;
	isc_result_t result = parse_uint(&n, value, INT_MAX, "tries");
	if (result == ISC_R_SUCCESS)
		tries = n;
}
564

565
static void
566
setoption(char *opt) {
Andreas Gustafsson's avatar
spacing  
Andreas Gustafsson committed
567
	if (strncasecmp(opt, "all", 4) == 0) {
Michael Sawyer's avatar
Michael Sawyer committed
568
		show_settings(ISC_TRUE, ISC_FALSE);
569
	} else if (strncasecmp(opt, "class=", 6) == 0) {
570
		if (testclass(&opt[6]))
Andreas Gustafsson's avatar
Andreas Gustafsson committed
571
			safecpy(defclass, &opt[6], sizeof(defclass));
572
	} else if (strncasecmp(opt, "cl=", 3) == 0) {
573
		if (testclass(&opt[3]))
Andreas Gustafsson's avatar
Andreas Gustafsson committed
574
			safecpy(defclass, &opt[3], sizeof(defclass));
575
	} else if (strncasecmp(opt, "type=", 5) == 0) {
576
		if (testtype(&opt[5]))
Andreas Gustafsson's avatar
Andreas Gustafsson committed
577
			safecpy(deftype, &opt[5], sizeof(deftype));
578
	} else if (strncasecmp(opt, "ty=", 3) == 0) {
579
		if (testtype(&opt[3]))
Andreas Gustafsson's avatar
Andreas Gustafsson committed
580
			safecpy(deftype, &opt[3], sizeof(deftype));
581
	} else if (strncasecmp(opt, "querytype=", 10) == 0) {
582
		if (testtype(&opt[10]))
Andreas Gustafsson's avatar
Andreas Gustafsson committed
583
			safecpy(deftype, &opt[10], sizeof(deftype));
584
	} else if (strncasecmp(opt, "query=", 6) == 0) {
585
		if (testtype(&opt[6]))
Andreas Gustafsson's avatar
Andreas Gustafsson committed
586
			safecpy(deftype, &opt[6], sizeof(deftype));
587
	} else if (strncasecmp(opt, "qu=", 3) == 0) {
588
		if (testtype(&opt[3]))
Andreas Gustafsson's avatar
Andreas Gustafsson committed
589
			safecpy(deftype, &opt[3], sizeof(deftype));
590 591 592
	} else if (strncasecmp(opt, "q=", 2) == 0) {
		if (testtype(&opt[2]))
			safecpy(deftype, &opt[2], sizeof(deftype));
593
	} else if (strncasecmp(opt, "domain=", 7) == 0) {
Andreas Gustafsson's avatar
Andreas Gustafsson committed
594 595
		safecpy(domainopt, &opt[7], sizeof(domainopt));
		set_search_domain(domainopt);
596
		usesearch = ISC_TRUE;
597
	} else if (strncasecmp(opt, "do=", 3) == 0) {
Andreas Gustafsson's avatar
Andreas Gustafsson committed
598
		safecpy(domainopt, &opt[3], sizeof(domainopt));
599
		set_search_domain(domainopt);
600
		usesearch = ISC_TRUE;
601
	} else if (strncasecmp(opt, "port=", 5) == 0) {
602
		set_port(&opt[5]);
603
	} else if (strncasecmp(opt, "po=", 3) == 0) {
604
		set_port(&opt[3]);
605
	} else if (strncasecmp(opt, "timeout=", 8) == 0) {
606
		set_timeout(&opt[8]);
607
	} else if (strncasecmp(opt, "t=", 2) == 0) {
608
		set_timeout(&opt[2]);
Automatic Updater's avatar
Automatic Updater committed
609
	} else if (strncasecmp(opt, "rec", 3) == 0) {
610 611 612
		recurse = ISC_TRUE;
	} else if (strncasecmp(opt, "norec", 5) == 0) {
		recurse = ISC_FALSE;
613
	} else if (strncasecmp(opt, "retry=", 6) == 0) {
614
		set_tries(&opt[6]);
615
	} else if (strncasecmp(opt, "ret=", 4) == 0) {
616
		set_tries(&opt[4]);
Automatic Updater's avatar
Automatic Updater committed
617
	} else if (strncasecmp(opt, "def", 3) == 0) {
618
		usesearch = ISC_TRUE;
619
	} else if (strncasecmp(opt, "nodef", 5) == 0) {
620
		usesearch = ISC_FALSE;
Automatic Updater's avatar
Automatic Updater committed
621
	} else if (strncasecmp(opt, "vc", 3) == 0) {
622 623 624
		tcpmode = ISC_TRUE;
	} else if (strncasecmp(opt, "novc", 5) == 0) {
		tcpmode = ISC_FALSE;
Automatic Updater's avatar
Automatic Updater committed
625
	} else if (strncasecmp(opt, "deb", 3) == 0) {
626
		short_form = ISC_FALSE;
627
		showsearch = ISC_TRUE;
628 629
	} else if (strncasecmp(opt, "nodeb", 5) == 0) {
		short_form = ISC_TRUE;
630
		showsearch = ISC_FALSE;
Automatic Updater's avatar
Automatic Updater committed
631
	} else if (strncasecmp(opt, "d2", 2) == 0) {
Michael Sawyer's avatar
Michael Sawyer committed
632 633 634
		debugging = ISC_TRUE;
	} else if (strncasecmp(opt, "nod2", 4) == 0) {
		debugging = ISC_FALSE;
Andreas Gustafsson's avatar
style  
Andreas Gustafsson committed
635
	} else if (strncasecmp(opt, "search", 3) == 0) {
636
		usesearch = ISC_TRUE;
Andreas Gustafsson's avatar
style  
Andreas Gustafsson committed
637
	} else if (strncasecmp(opt, "nosearch", 5) == 0) {
638
		usesearch = ISC_FALSE;
Andreas Gustafsson's avatar
style  
Andreas Gustafsson committed
639
	} else if (strncasecmp(opt, "sil", 3) == 0) {
640
		/* deprecation_msg = ISC_FALSE; */
641 642 643 644
	} else if (strncasecmp(opt, "fail", 3) == 0) {
		nofail=ISC_FALSE;
	} else if (strncasecmp(opt, "nofail", 3) == 0) {
		nofail=ISC_TRUE;
645
	} else {
Automatic Updater's avatar
Automatic Updater committed
646
		printf("*** Invalid option: %s\n", opt);
647 648 649
	}
}

650
static void
651
addlookup(char *opt) {
652
	dig_lookup_t *lookup;
653 654 655 656
	isc_result_t result;
	isc_textregion_t tr;
	dns_rdatatype_t rdtype;
	dns_rdataclass_t rdclass;
657
	char store[MXNAME];
658

Andreas Gustafsson's avatar
Andreas Gustafsson committed
659
	debug("addlookup()");
660 661 662
	tr.base = deftype;
	tr.length = strlen(deftype);
	result = dns_rdatatype_fromtext(&rdtype, &tr);
663
	if (result != ISC_R_SUCCESS) {
Andreas Gustafsson's avatar
spacing  
Andreas Gustafsson committed
664
		printf("unknown query type: %s\n", deftype);
665 666
		rdclass = dns_rdatatype_a;
	}
667 668 669
	tr.base = defclass;
	tr.length = strlen(defclass);
	result = dns_rdataclass_fromtext(&rdclass, &tr);
670
	if (result != ISC_R_SUCCESS) {
Andreas Gustafsson's avatar
spacing  
Andreas Gustafsson committed
671
		printf("unknown query class: %s\n", defclass);
672 673
		rdclass = dns_rdataclass_in;
	}
674
	lookup = make_empty_lookup();
675
	if (get_reverse(store, sizeof(store), opt, lookup->ip6_int, ISC_TRUE)
676
	    == ISC_R_SUCCESS) {
677
		safecpy(lookup->textname, store, sizeof(lookup->textname));
678
		lookup->rdtype = dns_rdatatype_ptr;
Michael Sawyer's avatar
Michael Sawyer committed
679
		lookup->rdtypeset = ISC_TRUE;
680
	} else {
681
		safecpy(lookup->textname, opt, sizeof(lookup->textname));
682
		lookup->rdtype = rdtype;
Michael Sawyer's avatar
Michael Sawyer committed
683
		lookup->rdtypeset = ISC_TRUE;
684
	}
685
	lookup->rdclass = rdclass;
Michael Sawyer's avatar
Michael Sawyer committed
686
	lookup->rdclassset = ISC_TRUE;
Brian Wellington's avatar
Brian Wellington committed
687 688 689
	lookup->trace = ISC_FALSE;
	lookup->trace_root = lookup->trace;
	lookup->ns_search_only = ISC_FALSE;
690 691 692
	lookup->identify = identify;
	lookup->recurse = recurse;
	lookup->aaonly = aaonly;
693
	lookup->retries = tries;
Brian Wellington's avatar
Brian Wellington committed
694
	lookup->udpsize = 0;
695
	lookup->comments = comments;
696
	lookup->tcp_mode = tcpmode;
697 698 699 700 701
	lookup->stats = stats;
	lookup->section_question = section_question;
	lookup->section_answer = section_answer;
	lookup->section_authority = section_authority;
	lookup->section_additional = section_additional;
702
	lookup->new_search = ISC_TRUE;
703 704
	if (nofail)
		lookup->servfail_stops = ISC_FALSE;
705
	ISC_LIST_INIT(lookup->q);
706
	ISC_LINK_INIT(lookup, link);
707 708 709
	ISC_LIST_APPEND(lookup_list, lookup, link);
	lookup->origin = NULL;
	ISC_LIST_INIT(lookup->my_server_list);
Michael Sawyer's avatar
Michael Sawyer committed
710
	debug("looking up %s", lookup->textname);
711 712
}

713
static void
714
get_next_command(void) {
715
	char *buf;
716
	char *ptr, *arg;
717
	char *input;
718

719
	fflush(stdout);
720 721
	buf = isc_mem_allocate(mctx, COMMSIZE);
	if (buf == NULL)
Andreas Gustafsson's avatar
Andreas Gustafsson committed
722
		fatal("memory allocation failure");
723
	fputs("> ", stderr);
724
	fflush(stderr);
725
	isc_app_block();
726
	ptr = fgets(buf, COMMSIZE, stdin);
727
	isc_app_unblock();
728 729
	if (ptr == NULL) {
		in_use = ISC_FALSE;
730
		goto cleanup;
731
	}
732
	input = buf;
733
	ptr = next_token(&input, " \t\r\n");
734
	if (ptr == NULL)
735
		goto cleanup;
736
	arg = next_token(&input, " \t\r\n");
737 738 739
	if ((strcasecmp(ptr, "set") == 0) &&
	    (arg != NULL))
		setoption(arg);
Michael Sawyer's avatar
Michael Sawyer committed
740 741
	else if ((strcasecmp(ptr, "server") == 0) ||
		 (strcasecmp(ptr, "lserver") == 0)) {
742
		isc_app_block();
743
		set_nameserver(arg);
744
		check_ra = ISC_FALSE;
745
		isc_app_unblock();
Michael Sawyer's avatar
Michael Sawyer committed
746
		show_settings(ISC_TRUE, ISC_TRUE);
747 748
	} else if (strcasecmp(ptr, "exit") == 0) {
		in_use = ISC_FALSE;
749
		goto cleanup;
750
	} else if (strcasecmp(ptr, "help") == 0 ||
751
		   strcasecmp(ptr, "?") == 0) {
752
		printf("The '%s' command is not yet implemented.\n", ptr);
753
		goto cleanup;
754 755 756
	} else if (strcasecmp(ptr, "finger") == 0 ||
		   strcasecmp(ptr, "root") == 0 ||
		   strcasecmp(ptr, "ls") == 0 ||
757
		   strcasecmp(ptr, "view") == 0) {
758
		printf("The '%s' command is not implemented.\n", ptr);
759
		goto cleanup;
760
	} else
761
		addlookup(ptr);
762 763
 cleanup:
	isc_mem_free(mctx, buf);
764 765 766 767
}

static void
parse_args(int argc, char **argv) {
768
	isc_boolean_t have_lookup = ISC_FALSE;
769

770
	usesearch = ISC_TRUE;
771
	for (argc--, argv++; argc > 0; argc--, argv++) {
Andreas Gustafsson's avatar
Andreas Gustafsson committed
772
		debug("main parsing %s", argv[0]);
773 774 775
		if (argv[0][0] == '-') {
			if (argv[0][1] != 0)
				setoption(&argv[0][1]);
776 777
			else
				have_lookup = ISC_TRUE;
778
		} else {
779 780
			if (!have_lookup) {
				have_lookup = ISC_TRUE;
781
				in_use = ISC_TRUE;
782
				addlookup(argv[0]);
783
			} else {
784
				set_nameserver(argv[0]);
785 786
				check_ra = ISC_FALSE;
			}
787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819
		}
	}
}

static void
flush_lookup_list(void) {
	dig_lookup_t *l, *lp;
	dig_query_t *q, *qp;
	dig_server_t *s, *sp;

	lookup_counter = 0;
	l = ISC_LIST_HEAD(lookup_list);
	while (l != NULL) {
		q = ISC_LIST_HEAD(l->q);
		while (q != NULL) {
			if (q->sock != NULL) {
				isc_socket_cancel(q->sock, NULL,
						  ISC_SOCKCANCEL_ALL);
				isc_socket_detach(&q->sock);
			}
			if (ISC_LINK_LINKED(&q->recvbuf, link))
				ISC_LIST_DEQUEUE(q->recvlist, &q->recvbuf,
						 link);
			if (ISC_LINK_LINKED(&q->lengthbuf, link))
				ISC_LIST_DEQUEUE(q->lengthlist, &q->lengthbuf,
						 link);
			isc_buffer_invalidate(&q->recvbuf);
			isc_buffer_invalidate(&q->lengthbuf);
			qp = q;
			q = ISC_LIST_NEXT(q, link);
			ISC_LIST_DEQUEUE(l->q, qp, link);
			isc_mem_free(mctx, qp);
		}
820 821 822 823 824 825
		s = ISC_LIST_HEAD(l->my_server_list);
		while (s != NULL) {
			sp = s;
			s = ISC_LIST_NEXT(s, link);
			ISC_LIST_DEQUEUE(l->my_server_list, sp, link);
			isc_mem_free(mctx, sp);
826

827 828 829 830 831 832 833 834 835 836
		}
		if (l->sendmsg != NULL)
			dns_message_destroy(&l->sendmsg);
		if (l->timer != NULL)
			isc_timer_detach(&l->timer);
		lp = l;
		l = ISC_LIST_NEXT(l, link);
		ISC_LIST_DEQUEUE(lookup_list, lp, link);
		isc_mem_free(mctx, lp);
	}