host.c revision 135446
1279264Sdelphij/*
2238405Sjkim * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3238405Sjkim * Copyright (C) 2000-2003  Internet Software Consortium.
4238405Sjkim *
5238405Sjkim * Permission to use, copy, modify, and distribute this software for any
6238405Sjkim * purpose with or without fee is hereby granted, provided that the above
7238405Sjkim * copyright notice and this permission notice appear in all copies.
8238405Sjkim *
9238405Sjkim * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10238405Sjkim * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11238405Sjkim * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12238405Sjkim * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13238405Sjkim * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14238405Sjkim * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15238405Sjkim * PERFORMANCE OF THIS SOFTWARE.
16238405Sjkim */
17238405Sjkim
18238405Sjkim/* $Id: host.c,v 1.76.2.5.2.9 2004/04/13 03:00:06 marka Exp $ */
19238405Sjkim
20238405Sjkim#include <config.h>
21238405Sjkim#include <limits.h>
22238405Sjkim
23238405Sjkim#include <isc/app.h>
24238405Sjkim#include <isc/commandline.h>
25238405Sjkim#include <isc/netaddr.h>
26238405Sjkim#include <isc/print.h>
27238405Sjkim#include <isc/string.h>
28238405Sjkim#include <isc/util.h>
29238405Sjkim#include <isc/task.h>
30238405Sjkim#include <isc/stdlib.h>
31238405Sjkim
32238405Sjkim#include <dns/byaddr.h>
33238405Sjkim#include <dns/fixedname.h>
34238405Sjkim#include <dns/message.h>
35238405Sjkim#include <dns/name.h>
36238405Sjkim#include <dns/rdata.h>
37238405Sjkim#include <dns/rdataclass.h>
38238405Sjkim#include <dns/rdataset.h>
39238405Sjkim#include <dns/rdatatype.h>
40238405Sjkim
41279264Sdelphij#include <dig/dig.h>
42279264Sdelphij
43238405Sjkimextern ISC_LIST(dig_lookup_t) lookup_list;
44238405Sjkimextern dig_serverlist_t server_list;
45238405Sjkimextern ISC_LIST(dig_searchlist_t) search_list;
46238405Sjkim
47238405Sjkimextern isc_boolean_t have_ipv4, have_ipv6;
48238405Sjkimextern isc_boolean_t usesearch;
49238405Sjkimextern isc_boolean_t debugging;
50238405Sjkimextern unsigned int timeout;
51238405Sjkimextern isc_mem_t *mctx;
52238405Sjkimextern int ndots;
53279264Sdelphijextern int tries;
54279264Sdelphijextern char *progname;
55279264Sdelphijextern isc_task_t *global_task;
56238405Sjkimextern int fatalexit;
57279264Sdelphij
58279264Sdelphijstatic isc_boolean_t short_form = ISC_TRUE, listed_server = ISC_FALSE;
59279264Sdelphijstatic isc_boolean_t default_lookups = ISC_TRUE;
60279264Sdelphijstatic int seen_error = -1;
61279264Sdelphijstatic isc_boolean_t list_addresses = ISC_TRUE;
62279264Sdelphijstatic dns_rdatatype_t list_type = dns_rdatatype_a;
63238405Sjkim
64279264Sdelphijstatic const char *opcodetext[] = {
65279264Sdelphij	"QUERY",
66279264Sdelphij	"IQUERY",
67279264Sdelphij	"STATUS",
68279264Sdelphij	"RESERVED3",
69238405Sjkim	"NOTIFY",
70279264Sdelphij	"UPDATE",
71238405Sjkim	"RESERVED6",
72238405Sjkim	"RESERVED7",
73238405Sjkim	"RESERVED8",
74238405Sjkim	"RESERVED9",
75238405Sjkim	"RESERVED10",
76238405Sjkim	"RESERVED11",
77238405Sjkim	"RESERVED12",
78238405Sjkim	"RESERVED13",
79238405Sjkim	"RESERVED14",
80238405Sjkim	"RESERVED15"
81238405Sjkim};
82238405Sjkim
83238405Sjkimstatic const char *rcodetext[] = {
84238405Sjkim	"NOERROR",
85238405Sjkim	"FORMERR",
86238405Sjkim	"SERVFAIL",
87238405Sjkim	"NXDOMAIN",
88238405Sjkim	"NOTIMP",
89238405Sjkim	"REFUSED",
90238405Sjkim	"YXDOMAIN",
91238405Sjkim	"YXRRSET",
92238405Sjkim	"NXRRSET",
93238405Sjkim	"NOTAUTH",
94238405Sjkim	"NOTZONE",
95238405Sjkim	"RESERVED11",
96238405Sjkim	"RESERVED12",
97238405Sjkim	"RESERVED13",
98238405Sjkim	"RESERVED14",
99238405Sjkim	"RESERVED15",
100238405Sjkim	"BADVERS"
101238405Sjkim};
102238405Sjkim
103238405Sjkimstruct rtype {
104238405Sjkim	unsigned int type;
105238405Sjkim	const char *text;
106238405Sjkim};
107238405Sjkim
108238405Sjkimstruct rtype rtypes[] = {
109238405Sjkim	{ 1, 	"has address" },
110238405Sjkim	{ 2, 	"name server" },
111238405Sjkim	{ 5, 	"is an alias for" },
112238405Sjkim	{ 11,	"has well known services" },
113238405Sjkim	{ 12,	"domain name pointer" },
114238405Sjkim	{ 13,	"host information" },
115238405Sjkim	{ 15,	"mail is handled by" },
116238405Sjkim	{ 16,	"descriptive text" },
117238405Sjkim	{ 19,	"x25 address" },
118238405Sjkim	{ 20,	"ISDN address" },
119238405Sjkim	{ 24,	"has signature" },
120238405Sjkim	{ 25,	"has key" },
121238405Sjkim	{ 28,	"has IPv6 address" },
122238405Sjkim	{ 29,	"location" },
123238405Sjkim	{ 0, NULL }
124238405Sjkim};
125238405Sjkim
126238405Sjkimstatic void
127238405Sjkimshow_usage(void) {
128238405Sjkim	fputs(
129238405Sjkim"Usage: host [-aCdlriTwv] [-c class] [-N ndots] [-t type] [-W time]\n"
130238405Sjkim"            [-R number] hostname [server]\n"
131238405Sjkim"       -a is equivalent to -v -t *\n"
132238405Sjkim"       -c specifies query class for non-IN data\n"
133238405Sjkim"       -C compares SOA records on authoritative nameservers\n"
134238405Sjkim"       -d is equivalent to -v\n"
135238405Sjkim"       -l lists all hosts in a domain, using AXFR\n"
136279264Sdelphij"       -i IP6.INT reverse lookups\n"
137238405Sjkim"       -N changes the number of dots allowed before root lookup is done\n"
138238405Sjkim"       -r disables recursive processing\n"
139238405Sjkim"       -R specifies number of retries for UDP packets\n"
140238405Sjkim"       -t specifies the query type\n"
141238405Sjkim"       -T enables TCP/IP mode\n"
142238405Sjkim"       -v enables verbose output\n"
143238405Sjkim"       -w specifies to wait forever for a reply\n"
144238405Sjkim"       -W specifies how long to wait for a reply\n"
145238405Sjkim"       -4 use IPv4 query transport only\n"
146238405Sjkim"       -6 use IPv6 query transport only\n", stderr);
147238405Sjkim	exit(1);
148238405Sjkim}
149238405Sjkim
150238405Sjkimvoid
151238405Sjkimdighost_shutdown(void) {
152238405Sjkim	isc_app_shutdown();
153238405Sjkim}
154238405Sjkim
155238405Sjkimvoid
156238405Sjkimreceived(int bytes, isc_sockaddr_t *from, dig_query_t *query) {
157238405Sjkim	isc_time_t now;
158238405Sjkim	int diff;
159238405Sjkim
160238405Sjkim	if (!short_form) {
161238405Sjkim		char fromtext[ISC_SOCKADDR_FORMATSIZE];
162238405Sjkim		isc_sockaddr_format(from, fromtext, sizeof(fromtext));
163238405Sjkim		TIME_NOW(&now);
164238405Sjkim		diff = (int) isc_time_microdiff(&now, &query->time_sent);
165238405Sjkim		printf("Received %u bytes from %s in %d ms\n",
166238405Sjkim		       bytes, fromtext, diff/1000);
167238405Sjkim	}
168238405Sjkim}
169238405Sjkim
170238405Sjkimvoid
171238405Sjkimtrying(char *frm, dig_lookup_t *lookup) {
172238405Sjkim	UNUSED(lookup);
173238405Sjkim
174238405Sjkim	if (!short_form)
175238405Sjkim		printf("Trying \"%s\"\n", frm);
176238405Sjkim}
177238405Sjkim
178238405Sjkimstatic void
179238405Sjkimsay_message(dns_name_t *name, const char *msg, dns_rdata_t *rdata,
180279264Sdelphij	    dig_query_t *query)
181279264Sdelphij{
182279264Sdelphij	isc_buffer_t *b = NULL;
183238405Sjkim	char namestr[DNS_NAME_FORMATSIZE];
184279264Sdelphij	isc_region_t r;
185238405Sjkim	isc_result_t result;
186238405Sjkim	unsigned int bufsize = BUFSIZ;
187279264Sdelphij
188238405Sjkim	dns_name_format(name, namestr, sizeof(namestr));
189238405Sjkim retry:
190279264Sdelphij	result = isc_buffer_allocate(mctx, &b, bufsize);
191238405Sjkim	check_result(result, "isc_buffer_allocate");
192238405Sjkim	result = dns_rdata_totext(rdata, NULL, b);
193238405Sjkim	if (result == ISC_R_NOSPACE) {
194279264Sdelphij		isc_buffer_free(&b);
195238405Sjkim		bufsize *= 2;
196238405Sjkim		goto retry;
197279264Sdelphij	}
198238405Sjkim	check_result(result, "dns_rdata_totext");
199238405Sjkim	isc_buffer_usedregion(b, &r);
200238405Sjkim	if (query->lookup->identify_previous_line) {
201238405Sjkim		printf("Nameserver %s:\n\t",
202238405Sjkim			query->servname);
203238405Sjkim	}
204238405Sjkim	printf("%s %s %.*s", namestr,
205238405Sjkim	       msg, (int)r.length, (char *)r.base);
206238405Sjkim	if (query->lookup->identify) {
207238405Sjkim		printf(" on server %s", query->servname);
208238405Sjkim	}
209238405Sjkim	printf("\n");
210238405Sjkim	isc_buffer_free(&b);
211238405Sjkim}
212238405Sjkim#ifdef DIG_SIGCHASE
213238405Sjkim/* Just for compatibility : not use in host program */
214238405Sjkimisc_result_t
215238405Sjkimprintrdataset(dns_name_t *owner_name, dns_rdataset_t *rdataset,
216238405Sjkim	      isc_buffer_t *target)
217238405Sjkim{
218238405Sjkim  UNUSED(owner_name);
219238405Sjkim  UNUSED(rdataset);
220238405Sjkim  UNUSED(target);
221279264Sdelphij  return(ISC_FALSE);
222279264Sdelphij}
223238405Sjkim#endif
224238405Sjkimstatic isc_result_t
225238405Sjkimprintsection(dns_message_t *msg, dns_section_t sectionid,
226238405Sjkim	     const char *section_name, isc_boolean_t headers,
227246772Sjkim	     dig_query_t *query)
228238405Sjkim{
229238405Sjkim	dns_name_t *name, *print_name;
230238405Sjkim	dns_rdataset_t *rdataset;
231238405Sjkim	dns_rdata_t rdata = DNS_RDATA_INIT;
232	isc_buffer_t target;
233	isc_result_t result, loopresult;
234	isc_region_t r;
235	dns_name_t empty_name;
236	char t[4096];
237	isc_boolean_t first;
238	isc_boolean_t no_rdata;
239
240	if (sectionid == DNS_SECTION_QUESTION)
241		no_rdata = ISC_TRUE;
242	else
243		no_rdata = ISC_FALSE;
244
245	if (headers)
246		printf(";; %s SECTION:\n", section_name);
247
248	dns_name_init(&empty_name, NULL);
249
250	result = dns_message_firstname(msg, sectionid);
251	if (result == ISC_R_NOMORE)
252		return (ISC_R_SUCCESS);
253	else if (result != ISC_R_SUCCESS)
254		return (result);
255
256	for (;;) {
257		name = NULL;
258		dns_message_currentname(msg, sectionid, &name);
259
260		isc_buffer_init(&target, t, sizeof(t));
261		first = ISC_TRUE;
262		print_name = name;
263
264		for (rdataset = ISC_LIST_HEAD(name->list);
265		     rdataset != NULL;
266		     rdataset = ISC_LIST_NEXT(rdataset, link)) {
267			if (query->lookup->rdtype == dns_rdatatype_axfr &&
268			    !((!list_addresses &&
269			       (list_type == dns_rdatatype_any ||
270			        rdataset->type == list_type)) ||
271			      (list_addresses &&
272			       (rdataset->type == dns_rdatatype_a ||
273			        rdataset->type == dns_rdatatype_aaaa ||
274				rdataset->type == dns_rdatatype_ns ||
275				rdataset->type == dns_rdatatype_ptr))))
276				continue;
277			if (!short_form) {
278				result = dns_rdataset_totext(rdataset,
279							     print_name,
280							     ISC_FALSE,
281							     no_rdata,
282							     &target);
283				if (result != ISC_R_SUCCESS)
284					return (result);
285#ifdef USEINITALWS
286				if (first) {
287					print_name = &empty_name;
288					first = ISC_FALSE;
289				}
290#else
291				UNUSED(first); /* Shut up compiler. */
292#endif
293			} else {
294				loopresult = dns_rdataset_first(rdataset);
295				while (loopresult == ISC_R_SUCCESS) {
296					struct rtype *t;
297					const char *rtt;
298					char typebuf[DNS_RDATATYPE_FORMATSIZE];
299					char typebuf2[DNS_RDATATYPE_FORMATSIZE
300						     + 20];
301					dns_rdataset_current(rdataset, &rdata);
302
303					for (t = rtypes; t->text != NULL; t++) {
304						if (t->type == rdata.type) {
305							rtt = t->text;
306							goto found;
307						}
308					}
309
310					dns_rdatatype_format(rdata.type,
311							     typebuf,
312							     sizeof(typebuf));
313					snprintf(typebuf2, sizeof(typebuf2),
314						 "has %s record", typebuf);
315					rtt = typebuf2;
316				found:
317					say_message(print_name, rtt,
318						    &rdata, query);
319					dns_rdata_reset(&rdata);
320					loopresult =
321						dns_rdataset_next(rdataset);
322				}
323			}
324		}
325		if (!short_form) {
326			isc_buffer_usedregion(&target, &r);
327			if (no_rdata)
328				printf(";%.*s", (int)r.length,
329				       (char *)r.base);
330			else
331				printf("%.*s", (int)r.length, (char *)r.base);
332		}
333
334		result = dns_message_nextname(msg, sectionid);
335		if (result == ISC_R_NOMORE)
336			break;
337		else if (result != ISC_R_SUCCESS)
338			return (result);
339	}
340
341	return (ISC_R_SUCCESS);
342}
343
344static isc_result_t
345printrdata(dns_message_t *msg, dns_rdataset_t *rdataset, dns_name_t *owner,
346	   const char *set_name, isc_boolean_t headers)
347{
348	isc_buffer_t target;
349	isc_result_t result;
350	isc_region_t r;
351	char t[4096];
352
353	UNUSED(msg);
354	if (headers)
355		printf(";; %s SECTION:\n", set_name);
356
357	isc_buffer_init(&target, t, sizeof(t));
358
359	result = dns_rdataset_totext(rdataset, owner, ISC_FALSE, ISC_FALSE,
360				     &target);
361	if (result != ISC_R_SUCCESS)
362		return (result);
363	isc_buffer_usedregion(&target, &r);
364	printf("%.*s", (int)r.length, (char *)r.base);
365
366	return (ISC_R_SUCCESS);
367}
368
369isc_result_t
370printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) {
371	isc_boolean_t did_flag = ISC_FALSE;
372	dns_rdataset_t *opt, *tsig = NULL;
373	dns_name_t *tsigname;
374	isc_result_t result = ISC_R_SUCCESS;
375	int force_error;
376
377	UNUSED(headers);
378
379	/*
380	 * We get called multiple times.
381	 * Preserve any existing error status.
382	 */
383	force_error = (seen_error == 1) ? 1 : 0;
384	seen_error = 1;
385	if (listed_server) {
386		char sockstr[ISC_SOCKADDR_FORMATSIZE];
387
388		printf("Using domain server:\n");
389		printf("Name: %s\n", query->servname);
390		isc_sockaddr_format(&query->sockaddr, sockstr,
391				    sizeof(sockstr));
392		printf("Address: %s\n", sockstr);
393		printf("Aliases: \n\n");
394	}
395
396	if (msg->rcode != 0) {
397		char namestr[DNS_NAME_FORMATSIZE];
398		dns_name_format(query->lookup->name, namestr, sizeof(namestr));
399		printf("Host %s not found: %d(%s)\n", namestr,
400		       msg->rcode, rcodetext[msg->rcode]);
401		return (ISC_R_SUCCESS);
402	}
403
404	if (default_lookups && query->lookup->rdtype == dns_rdatatype_a) {
405		char namestr[DNS_NAME_FORMATSIZE];
406		dig_lookup_t *lookup;
407
408		/* Add AAAA and MX lookups. */
409
410		dns_name_format(query->lookup->name, namestr, sizeof(namestr));
411		lookup = clone_lookup(query->lookup, ISC_FALSE);
412		if (lookup != NULL) {
413			strncpy(lookup->textname, namestr,
414				sizeof(lookup->textname));
415			lookup->textname[sizeof(lookup->textname)-1] = 0;
416			lookup->rdtype = dns_rdatatype_aaaa;
417                        lookup->rdtypeset = ISC_TRUE;
418			lookup->origin = NULL;
419			lookup->retries = tries;
420			ISC_LIST_APPEND(lookup_list, lookup, link);
421		}
422		lookup = clone_lookup(query->lookup, ISC_FALSE);
423		if (lookup != NULL) {
424			strncpy(lookup->textname, namestr,
425				sizeof(lookup->textname));
426			lookup->textname[sizeof(lookup->textname)-1] = 0;
427			lookup->rdtype = dns_rdatatype_mx;
428                        lookup->rdtypeset = ISC_TRUE;
429			lookup->origin = NULL;
430			lookup->retries = tries;
431			ISC_LIST_APPEND(lookup_list, lookup, link);
432		}
433	}
434
435	if (!short_form) {
436		printf(";; ->>HEADER<<- opcode: %s, status: %s, id: %u\n",
437		       opcodetext[msg->opcode], rcodetext[msg->rcode],
438		       msg->id);
439		printf(";; flags: ");
440		if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) {
441			printf("qr");
442			did_flag = ISC_TRUE;
443		}
444		if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) {
445			printf("%saa", did_flag ? " " : "");
446			did_flag = ISC_TRUE;
447		}
448		if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) {
449			printf("%stc", did_flag ? " " : "");
450			did_flag = ISC_TRUE;
451		}
452		if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) {
453			printf("%srd", did_flag ? " " : "");
454			did_flag = ISC_TRUE;
455		}
456		if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) {
457			printf("%sra", did_flag ? " " : "");
458			did_flag = ISC_TRUE;
459		}
460		if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0) {
461			printf("%sad", did_flag ? " " : "");
462			did_flag = ISC_TRUE;
463		}
464		if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0) {
465			printf("%scd", did_flag ? " " : "");
466			did_flag = ISC_TRUE;
467		}
468		printf("; QUERY: %u, ANSWER: %u, "
469		       "AUTHORITY: %u, ADDITIONAL: %u\n",
470		       msg->counts[DNS_SECTION_QUESTION],
471		       msg->counts[DNS_SECTION_ANSWER],
472		       msg->counts[DNS_SECTION_AUTHORITY],
473		       msg->counts[DNS_SECTION_ADDITIONAL]);
474		opt = dns_message_getopt(msg);
475		if (opt != NULL)
476			printf(";; EDNS: version: %u, udp=%u\n",
477			       (unsigned int)((opt->ttl & 0x00ff0000) >> 16),
478			       (unsigned int)opt->rdclass);
479		tsigname = NULL;
480		tsig = dns_message_gettsig(msg, &tsigname);
481		if (tsig != NULL)
482			printf(";; PSEUDOSECTIONS: TSIG\n");
483	}
484	if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_QUESTION]) &&
485	    !short_form) {
486		printf("\n");
487		result = printsection(msg, DNS_SECTION_QUESTION, "QUESTION",
488				      ISC_TRUE, query);
489		if (result != ISC_R_SUCCESS)
490			return (result);
491	}
492	if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) {
493		if (!short_form)
494			printf("\n");
495		result = printsection(msg, DNS_SECTION_ANSWER, "ANSWER",
496				      ISC_TF(!short_form), query);
497		if (result != ISC_R_SUCCESS)
498			return (result);
499	}
500
501	if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_AUTHORITY]) &&
502	    !short_form) {
503		printf("\n");
504		result = printsection(msg, DNS_SECTION_AUTHORITY, "AUTHORITY",
505				      ISC_TRUE, query);
506		if (result != ISC_R_SUCCESS)
507			return (result);
508	}
509	if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ADDITIONAL]) &&
510	    !short_form) {
511		printf("\n");
512		result = printsection(msg, DNS_SECTION_ADDITIONAL,
513				      "ADDITIONAL", ISC_TRUE, query);
514		if (result != ISC_R_SUCCESS)
515			return (result);
516	}
517	if ((tsig != NULL) && !short_form) {
518		printf("\n");
519		result = printrdata(msg, tsig, tsigname,
520				    "PSEUDOSECTION TSIG", ISC_TRUE);
521		if (result != ISC_R_SUCCESS)
522			return (result);
523	}
524	if (!short_form)
525		printf("\n");
526
527	if (short_form && !default_lookups &&
528	    ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) {
529		char namestr[DNS_NAME_FORMATSIZE];
530		char typestr[DNS_RDATATYPE_FORMATSIZE];
531		dns_name_format(query->lookup->name, namestr, sizeof(namestr));
532		dns_rdatatype_format(query->lookup->rdtype, typestr,
533				     sizeof(typestr));
534		printf("%s has no %s record\n", namestr, typestr);
535	}
536	seen_error = force_error;
537	return (result);
538}
539
540static void
541parse_args(isc_boolean_t is_batchfile, int argc, char **argv) {
542	char hostname[MXNAME];
543	dig_lookup_t *lookup;
544	int c;
545	char store[MXNAME];
546	isc_textregion_t tr;
547	isc_result_t result = ISC_R_SUCCESS;
548	dns_rdatatype_t rdtype;
549	dns_rdataclass_t rdclass;
550	isc_uint32_t serial = 0;
551
552	UNUSED(is_batchfile);
553
554	lookup = make_empty_lookup();
555
556	while ((c = isc_commandline_parse(argc, argv, "lvwrdt:c:aTCN:R:W:Dni46"))
557	       != EOF) {
558		switch (c) {
559		case 'l':
560			lookup->tcp_mode = ISC_TRUE;
561			lookup->rdtype = dns_rdatatype_axfr;
562			lookup->rdtypeset = ISC_TRUE;
563			fatalexit = 3;
564			break;
565		case 'v':
566		case 'd':
567			short_form = ISC_FALSE;
568			break;
569		case 'r':
570			lookup->recurse = ISC_FALSE;
571			break;
572		case 't':
573			if (strncasecmp(isc_commandline_argument,
574					"ixfr=", 5) == 0) {
575				rdtype = dns_rdatatype_ixfr;
576				/* XXXMPA add error checking */
577				serial = strtoul(isc_commandline_argument + 5,
578						 NULL, 10);
579				result = ISC_R_SUCCESS;
580			} else {
581				tr.base = isc_commandline_argument;
582				tr.length = strlen(isc_commandline_argument);
583				result = dns_rdatatype_fromtext(&rdtype,
584						   (isc_textregion_t *)&tr);
585			}
586
587			if (result != ISC_R_SUCCESS) {
588				fatalexit = 2;
589				fatal("invalid type: %s\n",
590				      isc_commandline_argument);
591			}
592			if (!lookup->rdtypeset ||
593			    lookup->rdtype != dns_rdatatype_axfr)
594				lookup->rdtype = rdtype;
595			lookup->rdtypeset = ISC_TRUE;
596			if (rdtype == dns_rdatatype_axfr) {
597				/* -l -t any -v */
598				list_type = dns_rdatatype_any;
599				short_form = ISC_FALSE;
600				lookup->tcp_mode = ISC_TRUE;
601			} else if (rdtype == dns_rdatatype_ixfr) {
602				lookup->ixfr_serial = serial;
603				list_type = rdtype;
604			} else
605				list_type = rdtype;
606			list_addresses = ISC_FALSE;
607			break;
608		case 'c':
609			tr.base = isc_commandline_argument;
610			tr.length = strlen(isc_commandline_argument);
611			result = dns_rdataclass_fromtext(&rdclass,
612						   (isc_textregion_t *)&tr);
613
614			if (result != ISC_R_SUCCESS) {
615				fatalexit = 2;
616				fatal("invalid class: %s\n",
617				      isc_commandline_argument);
618			} else {
619				lookup->rdclass = rdclass;
620				lookup->rdclassset = ISC_TRUE;
621			}
622			default_lookups = ISC_FALSE;
623			break;
624		case 'a':
625			if (!lookup->rdtypeset ||
626			    lookup->rdtype != dns_rdatatype_axfr)
627				lookup->rdtype = dns_rdatatype_any;
628			list_type = dns_rdatatype_any;
629			list_addresses = ISC_FALSE;
630			lookup->rdtypeset = ISC_TRUE;
631			short_form = ISC_FALSE;
632			default_lookups = ISC_FALSE;
633			break;
634		case 'i':
635			lookup->ip6_int = ISC_TRUE;
636			break;
637		case 'n':
638			/* deprecated */
639			break;
640		case 'w':
641			/*
642			 * The timer routines are coded such that
643			 * timeout==MAXINT doesn't enable the timer
644			 */
645			timeout = INT_MAX;
646			break;
647		case 'W':
648			timeout = atoi(isc_commandline_argument);
649			if (timeout < 1)
650				timeout = 1;
651			break;
652		case 'R':
653			tries = atoi(isc_commandline_argument) + 1;
654			if (tries < 2)
655				tries = 2;
656			break;
657		case 'T':
658			lookup->tcp_mode = ISC_TRUE;
659			break;
660		case 'C':
661			debug("showing all SOAs");
662			lookup->rdtype = dns_rdatatype_ns;
663			lookup->rdtypeset = ISC_TRUE;
664			lookup->rdclass = dns_rdataclass_in;
665			lookup->rdclassset = ISC_TRUE;
666			lookup->ns_search_only = ISC_TRUE;
667			lookup->trace_root = ISC_TRUE;
668			lookup->identify_previous_line = ISC_TRUE;
669			default_lookups = ISC_FALSE;
670			break;
671		case 'N':
672			debug("setting NDOTS to %s",
673			      isc_commandline_argument);
674			ndots = atoi(isc_commandline_argument);
675			break;
676		case 'D':
677			debugging = ISC_TRUE;
678			break;
679		case '4':
680			if (have_ipv4) {
681				isc_net_disableipv6();
682				have_ipv6 = ISC_FALSE;
683			} else
684				fatal("can't find IPv4 networking");
685			break;
686		case '6':
687			if (have_ipv6) {
688				isc_net_disableipv4();
689				have_ipv4 = ISC_FALSE;
690			} else
691				fatal("can't find IPv6 networking");
692			break;
693		}
694	}
695
696	lookup->retries = tries;
697
698	if (isc_commandline_index >= argc)
699		show_usage();
700
701	strncpy(hostname, argv[isc_commandline_index], sizeof(hostname));
702	hostname[sizeof(hostname)-1]=0;
703	if (argc > isc_commandline_index + 1) {
704		set_nameserver(argv[isc_commandline_index+1]);
705		debug("server is %s", argv[isc_commandline_index+1]);
706		listed_server = ISC_TRUE;
707	}
708
709	lookup->pending = ISC_FALSE;
710	if (get_reverse(store, sizeof(store), hostname,
711			lookup->ip6_int, ISC_TRUE) == ISC_R_SUCCESS) {
712		strncpy(lookup->textname, store, sizeof(lookup->textname));
713		lookup->textname[sizeof(lookup->textname)-1] = 0;
714		lookup->rdtype = dns_rdatatype_ptr;
715		lookup->rdtypeset = ISC_TRUE;
716		default_lookups = ISC_FALSE;
717	} else {
718		strncpy(lookup->textname, hostname, sizeof(lookup->textname));
719		lookup->textname[sizeof(lookup->textname)-1]=0;
720	}
721	lookup->new_search = ISC_TRUE;
722	ISC_LIST_APPEND(lookup_list, lookup, link);
723
724	usesearch = ISC_TRUE;
725}
726
727int
728main(int argc, char **argv) {
729	isc_result_t result;
730
731	tries = 2;
732
733	ISC_LIST_INIT(lookup_list);
734	ISC_LIST_INIT(server_list);
735	ISC_LIST_INIT(search_list);
736
737	fatalexit = 1;
738
739	debug("main()");
740	progname = argv[0];
741	result = isc_app_start();
742	check_result(result, "isc_app_start");
743	setup_libs();
744	parse_args(ISC_FALSE, argc, argv);
745	setup_system();
746	result = isc_app_onrun(mctx, global_task, onrun_callback, NULL);
747	check_result(result, "isc_app_onrun");
748	isc_app_run();
749	cancel_all();
750	destroy_libs();
751	isc_app_finish();
752	return ((seen_error == 0) ? 0 : 1);
753}
754
755