1/*
2 * Copyright (C) 2004-2011  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000-2003  Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/* $Id: dig.c,v 1.237.124.4 2011/12/07 17:23:55 each Exp $ */
19
20/*! \file */
21
22#include <config.h>
23#include <stdlib.h>
24#include <time.h>
25#include <ctype.h>
26
27#include <isc/app.h>
28#include <isc/netaddr.h>
29#include <isc/parseint.h>
30#include <isc/print.h>
31#include <isc/string.h>
32#include <isc/util.h>
33#include <isc/task.h>
34
35#include <dns/byaddr.h>
36#include <dns/fixedname.h>
37#include <dns/masterdump.h>
38#include <dns/message.h>
39#include <dns/name.h>
40#include <dns/rdata.h>
41#include <dns/rdataset.h>
42#include <dns/rdatatype.h>
43#include <dns/rdataclass.h>
44#include <dns/result.h>
45#include <dns/tsig.h>
46
47#include <dig/dig.h>
48
49#define ADD_STRING(b, s) { 				\
50	if (strlen(s) >= isc_buffer_availablelength(b)) \
51		return (ISC_R_NOSPACE); 		\
52	else 						\
53		isc_buffer_putstr(b, s); 		\
54}
55
56#define DIG_MAX_ADDRESSES 20
57
58dig_lookup_t *default_lookup = NULL;
59
60static char *batchname = NULL;
61static FILE *batchfp = NULL;
62static char *argv0;
63static int addresscount = 0;
64
65static char domainopt[DNS_NAME_MAXTEXT];
66
67static isc_boolean_t short_form = ISC_FALSE, printcmd = ISC_TRUE,
68	ip6_int = ISC_FALSE, plusquest = ISC_FALSE, pluscomm = ISC_FALSE,
69	multiline = ISC_FALSE, nottl = ISC_FALSE, noclass = ISC_FALSE,
70	onesoa = ISC_FALSE;
71
72/*% opcode text */
73static const char * const opcodetext[] = {
74	"QUERY",
75	"IQUERY",
76	"STATUS",
77	"RESERVED3",
78	"NOTIFY",
79	"UPDATE",
80	"RESERVED6",
81	"RESERVED7",
82	"RESERVED8",
83	"RESERVED9",
84	"RESERVED10",
85	"RESERVED11",
86	"RESERVED12",
87	"RESERVED13",
88	"RESERVED14",
89	"RESERVED15"
90};
91
92/*% return code text */
93static const char * const rcodetext[] = {
94	"NOERROR",
95	"FORMERR",
96	"SERVFAIL",
97	"NXDOMAIN",
98	"NOTIMP",
99	"REFUSED",
100	"YXDOMAIN",
101	"YXRRSET",
102	"NXRRSET",
103	"NOTAUTH",
104	"NOTZONE",
105	"RESERVED11",
106	"RESERVED12",
107	"RESERVED13",
108	"RESERVED14",
109	"RESERVED15",
110	"BADVERS"
111};
112
113/*% safe rcodetext[] */
114static char *
115rcode_totext(dns_rcode_t rcode)
116{
117	static char buf[sizeof("?65535")];
118	union {
119		const char *consttext;
120		char *deconsttext;
121	} totext;
122
123	if (rcode >= (sizeof(rcodetext)/sizeof(rcodetext[0]))) {
124		snprintf(buf, sizeof(buf), "?%u", rcode);
125		totext.deconsttext = buf;
126	} else
127		totext.consttext = rcodetext[rcode];
128	return totext.deconsttext;
129}
130
131/*% print usage */
132static void
133print_usage(FILE *fp) {
134	fputs(
135"Usage:  dig [@global-server] [domain] [q-type] [q-class] {q-opt}\n"
136"            {global-d-opt} host [@local-server] {local-d-opt}\n"
137"            [ host [@local-server] {local-d-opt} [...]]\n", fp);
138}
139
140ISC_PLATFORM_NORETURN_PRE static void
141usage(void) ISC_PLATFORM_NORETURN_POST;
142
143static void
144usage(void) {
145	print_usage(stderr);
146	fputs("\nUse \"dig -h\" (or \"dig -h | more\") "
147	      "for complete list of options\n", stderr);
148	exit(1);
149}
150
151/*% version */
152static void
153version(void) {
154	fputs("DiG " VERSION "\n", stderr);
155}
156
157/*% help */
158static void
159help(void) {
160	print_usage(stdout);
161	fputs(
162"Where:  domain	  is in the Domain Name System\n"
163"        q-class  is one of (in,hs,ch,...) [default: in]\n"
164"        q-type   is one of (a,any,mx,ns,soa,hinfo,axfr,txt,...) [default:a]\n"
165"                 (Use ixfr=version for type ixfr)\n"
166"        q-opt    is one of:\n"
167"                 -x dot-notation     (shortcut for reverse lookups)\n"
168"                 -i                  (use IP6.INT for IPv6 reverse lookups)\n"
169"                 -f filename         (batch mode)\n"
170"                 -b address[#port]   (bind to source address/port)\n"
171"                 -p port             (specify port number)\n"
172"                 -q name             (specify query name)\n"
173"                 -t type             (specify query type)\n"
174"                 -c class            (specify query class)\n"
175"                 -k keyfile          (specify tsig key file)\n"
176"                 -y [hmac:]name:key  (specify named base64 tsig key)\n"
177"                 -4                  (use IPv4 query transport only)\n"
178"                 -6                  (use IPv6 query transport only)\n"
179"                 -m                  (enable memory usage debugging)\n"
180"        d-opt    is of the form +keyword[=value], where keyword is:\n"
181"                 +[no]vc             (TCP mode)\n"
182"                 +[no]tcp            (TCP mode, alternate syntax)\n"
183"                 +time=###           (Set query timeout) [5]\n"
184"                 +tries=###          (Set number of UDP attempts) [3]\n"
185"                 +retry=###          (Set number of UDP retries) [2]\n"
186"                 +domain=###         (Set default domainname)\n"
187"                 +bufsize=###        (Set EDNS0 Max UDP packet size)\n"
188"                 +ndots=###          (Set NDOTS value)\n"
189"                 +edns=###           (Set EDNS version)\n"
190"                 +[no]search         (Set whether to use searchlist)\n"
191"                 +[no]showsearch     (Search with intermediate results)\n"
192"                 +[no]defname        (Ditto)\n"
193"                 +[no]recurse        (Recursive mode)\n"
194"                 +[no]ignore         (Don't revert to TCP for TC responses.)"
195"\n"
196"                 +[no]fail           (Don't try next server on SERVFAIL)\n"
197"                 +[no]besteffort     (Try to parse even illegal messages)\n"
198"                 +[no]aaonly         (Set AA flag in query (+[no]aaflag))\n"
199"                 +[no]adflag         (Set AD flag in query)\n"
200"                 +[no]cdflag         (Set CD flag in query)\n"
201"                 +[no]cl             (Control display of class in records)\n"
202"                 +[no]cmd            (Control display of command line)\n"
203"                 +[no]comments       (Control display of comment lines)\n"
204"                 +[no]question       (Control display of question)\n"
205"                 +[no]answer         (Control display of answer)\n"
206"                 +[no]authority      (Control display of authority)\n"
207"                 +[no]additional     (Control display of additional)\n"
208"                 +[no]stats          (Control display of statistics)\n"
209"                 +[no]short          (Disable everything except short\n"
210"                                      form of answer)\n"
211"                 +[no]ttlid          (Control display of ttls in records)\n"
212"                 +[no]all            (Set or clear all display flags)\n"
213"                 +[no]qr             (Print question before sending)\n"
214"                 +[no]nssearch       (Search all authoritative nameservers)\n"
215"                 +[no]identify       (ID responders in short answers)\n"
216"                 +[no]trace          (Trace delegation down from root)\n"
217"                 +[no]dnssec         (Request DNSSEC records)\n"
218"                 +[no]nsid           (Request Name Server ID)\n"
219#ifdef DIG_SIGCHASE
220"                 +[no]sigchase       (Chase DNSSEC signatures)\n"
221"                 +trusted-key=####   (Trusted Key when chasing DNSSEC sigs)\n"
222#if DIG_SIGCHASE_TD
223"                 +[no]topdown        (Do DNSSEC validation top down mode)\n"
224#endif
225#endif
226"                 +[no]multiline      (Print records in an expanded format)\n"
227"                 +[no]onesoa         (AXFR prints only one soa record)\n"
228"        global d-opts and servers (before host name) affect all queries.\n"
229"        local d-opts and servers (after host name) affect only that lookup.\n"
230"        -h                           (print help and exit)\n"
231"        -v                           (print version and exit)\n",
232	stdout);
233}
234
235/*%
236 * Callback from dighost.c to print the received message.
237 */
238void
239received(int bytes, isc_sockaddr_t *from, dig_query_t *query) {
240	isc_uint64_t diff;
241	isc_time_t now;
242	time_t tnow;
243	char fromtext[ISC_SOCKADDR_FORMATSIZE];
244
245	isc_sockaddr_format(from, fromtext, sizeof(fromtext));
246
247	TIME_NOW(&now);
248
249	if (query->lookup->stats && !short_form) {
250		diff = isc_time_microdiff(&now, &query->time_sent);
251		printf(";; Query time: %ld msec\n", (long int)diff/1000);
252		printf(";; SERVER: %s(%s)\n", fromtext, query->servname);
253		time(&tnow);
254		printf(";; WHEN: %s", ctime(&tnow));
255		if (query->lookup->doing_xfr) {
256			printf(";; XFR size: %u records (messages %u, "
257			       "bytes %" ISC_PRINT_QUADFORMAT "u)\n",
258			       query->rr_count, query->msg_count,
259			       query->byte_count);
260		} else {
261			printf(";; MSG SIZE  rcvd: %u\n", bytes);
262
263		}
264		if (key != NULL) {
265			if (!validated)
266				puts(";; WARNING -- Some TSIG could not "
267				     "be validated");
268		}
269		if ((key == NULL) && (keysecret[0] != 0)) {
270			puts(";; WARNING -- TSIG key was not used.");
271		}
272		puts("");
273	} else if (query->lookup->identify && !short_form) {
274		diff = isc_time_microdiff(&now, &query->time_sent);
275		printf(";; Received %" ISC_PRINT_QUADFORMAT "u bytes "
276		       "from %s(%s) in %d ms\n\n",
277		       query->lookup->doing_xfr ?
278				query->byte_count : (isc_uint64_t)bytes,
279		       fromtext, query->servname,
280		       (int)diff/1000);
281	}
282}
283
284/*
285 * Callback from dighost.c to print that it is trying a server.
286 * Not used in dig.
287 * XXX print_trying
288 */
289void
290trying(char *frm, dig_lookup_t *lookup) {
291	UNUSED(frm);
292	UNUSED(lookup);
293}
294
295/*%
296 * Internal print routine used to print short form replies.
297 */
298static isc_result_t
299say_message(dns_rdata_t *rdata, dig_query_t *query, isc_buffer_t *buf) {
300	isc_result_t result;
301	isc_uint64_t diff;
302	isc_time_t now;
303	char store[sizeof("12345678901234567890")];
304
305	if (query->lookup->trace || query->lookup->ns_search_only) {
306		result = dns_rdatatype_totext(rdata->type, buf);
307		if (result != ISC_R_SUCCESS)
308			return (result);
309		ADD_STRING(buf, " ");
310	}
311	result = dns_rdata_totext(rdata, NULL, buf);
312	if (result == ISC_R_NOSPACE)
313		return (result);
314	check_result(result, "dns_rdata_totext");
315	if (query->lookup->identify) {
316		TIME_NOW(&now);
317		diff = isc_time_microdiff(&now, &query->time_sent);
318		ADD_STRING(buf, " from server ");
319		ADD_STRING(buf, query->servname);
320		snprintf(store, 19, " in %d ms.", (int)diff/1000);
321		ADD_STRING(buf, store);
322	}
323	ADD_STRING(buf, "\n");
324	return (ISC_R_SUCCESS);
325}
326
327/*%
328 * short_form message print handler.  Calls above say_message()
329 */
330static isc_result_t
331short_answer(dns_message_t *msg, dns_messagetextflag_t flags,
332	     isc_buffer_t *buf, dig_query_t *query)
333{
334	dns_name_t *name;
335	dns_rdataset_t *rdataset;
336	isc_result_t result, loopresult;
337	dns_name_t empty_name;
338	dns_rdata_t rdata = DNS_RDATA_INIT;
339
340	UNUSED(flags);
341
342	dns_name_init(&empty_name, NULL);
343	result = dns_message_firstname(msg, DNS_SECTION_ANSWER);
344	if (result == ISC_R_NOMORE)
345		return (ISC_R_SUCCESS);
346	else if (result != ISC_R_SUCCESS)
347		return (result);
348
349	for (;;) {
350		name = NULL;
351		dns_message_currentname(msg, DNS_SECTION_ANSWER, &name);
352
353		for (rdataset = ISC_LIST_HEAD(name->list);
354		     rdataset != NULL;
355		     rdataset = ISC_LIST_NEXT(rdataset, link)) {
356			loopresult = dns_rdataset_first(rdataset);
357			while (loopresult == ISC_R_SUCCESS) {
358				dns_rdataset_current(rdataset, &rdata);
359				result = say_message(&rdata, query,
360						     buf);
361				if (result == ISC_R_NOSPACE)
362					return (result);
363				check_result(result, "say_message");
364				loopresult = dns_rdataset_next(rdataset);
365				dns_rdata_reset(&rdata);
366			}
367		}
368		result = dns_message_nextname(msg, DNS_SECTION_ANSWER);
369		if (result == ISC_R_NOMORE)
370			break;
371		else if (result != ISC_R_SUCCESS)
372			return (result);
373	}
374
375	return (ISC_R_SUCCESS);
376}
377#ifdef DIG_SIGCHASE
378isc_result_t
379printrdataset(dns_name_t *owner_name, dns_rdataset_t *rdataset,
380	      isc_buffer_t *target)
381{
382	isc_result_t result;
383	dns_master_style_t *style = NULL;
384	unsigned int styleflags = 0;
385
386	if (rdataset == NULL || owner_name == NULL || target == NULL)
387		return(ISC_FALSE);
388
389	styleflags |= DNS_STYLEFLAG_REL_OWNER;
390	if (nottl)
391		styleflags |= DNS_STYLEFLAG_NO_TTL;
392	if (noclass)
393		styleflags |= DNS_STYLEFLAG_NO_CLASS;
394	if (multiline) {
395		styleflags |= DNS_STYLEFLAG_OMIT_OWNER;
396		styleflags |= DNS_STYLEFLAG_OMIT_CLASS;
397		styleflags |= DNS_STYLEFLAG_REL_DATA;
398		styleflags |= DNS_STYLEFLAG_OMIT_TTL;
399		styleflags |= DNS_STYLEFLAG_TTL;
400		styleflags |= DNS_STYLEFLAG_MULTILINE;
401		styleflags |= DNS_STYLEFLAG_COMMENT;
402	}
403	if (multiline || (nottl && noclass))
404		result = dns_master_stylecreate(&style, styleflags,
405						24, 24, 24, 32, 80, 8, mctx);
406	else if (nottl || noclass)
407		result = dns_master_stylecreate(&style, styleflags,
408						24, 24, 32, 40, 80, 8, mctx);
409	else
410		result = dns_master_stylecreate(&style, styleflags,
411						24, 32, 40, 48, 80, 8, mctx);
412	check_result(result, "dns_master_stylecreate");
413
414	result = dns_master_rdatasettotext(owner_name, rdataset, style, target);
415
416	if (style != NULL)
417		dns_master_styledestroy(&style, mctx);
418
419	return(result);
420}
421#endif
422
423/*
424 * Callback from dighost.c to print the reply from a server
425 */
426isc_result_t
427printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) {
428	isc_result_t result;
429	dns_messagetextflag_t flags;
430	isc_buffer_t *buf = NULL;
431	unsigned int len = OUTPUTBUF;
432	dns_master_style_t *style = NULL;
433	unsigned int styleflags = 0;
434
435	styleflags |= DNS_STYLEFLAG_REL_OWNER;
436	if (nottl)
437		styleflags |= DNS_STYLEFLAG_NO_TTL;
438	if (noclass)
439		styleflags |= DNS_STYLEFLAG_NO_CLASS;
440	if (multiline) {
441		styleflags |= DNS_STYLEFLAG_OMIT_OWNER;
442		styleflags |= DNS_STYLEFLAG_OMIT_CLASS;
443		styleflags |= DNS_STYLEFLAG_REL_DATA;
444		styleflags |= DNS_STYLEFLAG_OMIT_TTL;
445		styleflags |= DNS_STYLEFLAG_TTL;
446		styleflags |= DNS_STYLEFLAG_MULTILINE;
447		styleflags |= DNS_STYLEFLAG_COMMENT;
448	}
449	if (multiline || (nottl && noclass))
450		result = dns_master_stylecreate(&style, styleflags,
451						24, 24, 24, 32, 80, 8, mctx);
452	else if (nottl || noclass)
453		result = dns_master_stylecreate(&style, styleflags,
454						24, 24, 32, 40, 80, 8, mctx);
455	else
456		result = dns_master_stylecreate(&style, styleflags,
457						24, 32, 40, 48, 80, 8, mctx);
458	check_result(result, "dns_master_stylecreate");
459
460	if (query->lookup->cmdline[0] != 0) {
461		if (!short_form)
462			fputs(query->lookup->cmdline, stdout);
463		query->lookup->cmdline[0]=0;
464	}
465	debug("printmessage(%s %s %s)", headers ? "headers" : "noheaders",
466	      query->lookup->comments ? "comments" : "nocomments",
467	      short_form ? "short_form" : "long_form");
468
469	flags = 0;
470	if (!headers) {
471		flags |= DNS_MESSAGETEXTFLAG_NOHEADERS;
472		flags |= DNS_MESSAGETEXTFLAG_NOCOMMENTS;
473	}
474	if (onesoa && query->lookup->rdtype == dns_rdatatype_axfr)
475		flags |= (query->msg_count == 0) ? DNS_MESSAGETEXTFLAG_ONESOA :
476						   DNS_MESSAGETEXTFLAG_OMITSOA;
477	if (!query->lookup->comments)
478		flags |= DNS_MESSAGETEXTFLAG_NOCOMMENTS;
479
480	result = isc_buffer_allocate(mctx, &buf, len);
481	check_result(result, "isc_buffer_allocate");
482
483	if (query->lookup->comments && !short_form) {
484		if (query->lookup->cmdline[0] != 0)
485			printf("; %s\n", query->lookup->cmdline);
486		if (msg == query->lookup->sendmsg)
487			printf(";; Sending:\n");
488		else
489			printf(";; Got answer:\n");
490
491		if (headers) {
492			printf(";; ->>HEADER<<- opcode: %s, status: %s, "
493			       "id: %u\n",
494			       opcodetext[msg->opcode],
495			       rcode_totext(msg->rcode),
496			       msg->id);
497			printf(";; flags:");
498			if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0)
499				printf(" qr");
500			if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0)
501				printf(" aa");
502			if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0)
503				printf(" tc");
504			if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0)
505				printf(" rd");
506			if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0)
507				printf(" ra");
508			if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0)
509				printf(" ad");
510			if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0)
511				printf(" cd");
512			if ((msg->flags & 0x0040U) != 0)
513				printf("; MBZ: 0x4");
514
515			printf("; QUERY: %u, ANSWER: %u, "
516			       "AUTHORITY: %u, ADDITIONAL: %u\n",
517			       msg->counts[DNS_SECTION_QUESTION],
518			       msg->counts[DNS_SECTION_ANSWER],
519			       msg->counts[DNS_SECTION_AUTHORITY],
520			       msg->counts[DNS_SECTION_ADDITIONAL]);
521
522			if (msg != query->lookup->sendmsg &&
523			    (msg->flags & DNS_MESSAGEFLAG_RD) != 0 &&
524			    (msg->flags & DNS_MESSAGEFLAG_RA) == 0)
525				printf(";; WARNING: recursion requested "
526				       "but not available\n");
527		}
528		if (msg != query->lookup->sendmsg && extrabytes != 0U)
529			printf(";; WARNING: Messages has %u extra byte%s at "
530			       "end\n", extrabytes, extrabytes != 0 ? "s" : "");
531	}
532
533repopulate_buffer:
534
535	if (query->lookup->comments && headers && !short_form) {
536		result = dns_message_pseudosectiontotext(msg,
537			 DNS_PSEUDOSECTION_OPT,
538			 style, flags, buf);
539		if (result == ISC_R_NOSPACE) {
540buftoosmall:
541			len += OUTPUTBUF;
542			isc_buffer_free(&buf);
543			result = isc_buffer_allocate(mctx, &buf, len);
544			if (result == ISC_R_SUCCESS)
545				goto repopulate_buffer;
546			else
547				goto cleanup;
548		}
549		check_result(result,
550		     "dns_message_pseudosectiontotext");
551	}
552
553	if (query->lookup->section_question && headers) {
554		if (!short_form) {
555			result = dns_message_sectiontotext(msg,
556						       DNS_SECTION_QUESTION,
557						       style, flags, buf);
558			if (result == ISC_R_NOSPACE)
559				goto buftoosmall;
560			check_result(result, "dns_message_sectiontotext");
561		}
562	}
563	if (query->lookup->section_answer) {
564		if (!short_form) {
565			result = dns_message_sectiontotext(msg,
566						       DNS_SECTION_ANSWER,
567						       style, flags, buf);
568			if (result == ISC_R_NOSPACE)
569				goto buftoosmall;
570			check_result(result, "dns_message_sectiontotext");
571		} else {
572			result = short_answer(msg, flags, buf, query);
573			if (result == ISC_R_NOSPACE)
574				goto buftoosmall;
575			check_result(result, "short_answer");
576		}
577	}
578	if (query->lookup->section_authority) {
579		if (!short_form) {
580			result = dns_message_sectiontotext(msg,
581						       DNS_SECTION_AUTHORITY,
582						       style, flags, buf);
583			if (result == ISC_R_NOSPACE)
584				goto buftoosmall;
585			check_result(result, "dns_message_sectiontotext");
586		}
587	}
588	if (query->lookup->section_additional) {
589		if (!short_form) {
590			result = dns_message_sectiontotext(msg,
591						      DNS_SECTION_ADDITIONAL,
592						      style, flags, buf);
593			if (result == ISC_R_NOSPACE)
594				goto buftoosmall;
595			check_result(result, "dns_message_sectiontotext");
596			/*
597			 * Only print the signature on the first record.
598			 */
599			if (headers) {
600				result = dns_message_pseudosectiontotext(
601						   msg,
602						   DNS_PSEUDOSECTION_TSIG,
603						   style, flags, buf);
604				if (result == ISC_R_NOSPACE)
605					goto buftoosmall;
606				check_result(result,
607					  "dns_message_pseudosectiontotext");
608				result = dns_message_pseudosectiontotext(
609						   msg,
610						   DNS_PSEUDOSECTION_SIG0,
611						   style, flags, buf);
612				if (result == ISC_R_NOSPACE)
613					goto buftoosmall;
614				check_result(result,
615					   "dns_message_pseudosectiontotext");
616			}
617		}
618	}
619
620	if (headers && query->lookup->comments && !short_form)
621		printf("\n");
622
623	printf("%.*s", (int)isc_buffer_usedlength(buf),
624	       (char *)isc_buffer_base(buf));
625	isc_buffer_free(&buf);
626
627cleanup:
628	if (style != NULL)
629		dns_master_styledestroy(&style, mctx);
630	return (result);
631}
632
633/*%
634 * print the greeting message when the program first starts up.
635 */
636static void
637printgreeting(int argc, char **argv, dig_lookup_t *lookup) {
638	int i;
639	int remaining;
640	static isc_boolean_t first = ISC_TRUE;
641	char append[MXNAME];
642
643	if (printcmd) {
644		lookup->cmdline[sizeof(lookup->cmdline) - 1] = 0;
645		snprintf(lookup->cmdline, sizeof(lookup->cmdline),
646			 "%s; <<>> DiG " VERSION " <<>>",
647			 first?"\n":"");
648		i = 1;
649		while (i < argc) {
650			snprintf(append, sizeof(append), " %s", argv[i++]);
651			remaining = sizeof(lookup->cmdline) -
652				    strlen(lookup->cmdline) - 1;
653			strncat(lookup->cmdline, append, remaining);
654		}
655		remaining = sizeof(lookup->cmdline) -
656			    strlen(lookup->cmdline) - 1;
657		strncat(lookup->cmdline, "\n", remaining);
658		if (first && addresscount != 0) {
659			snprintf(append, sizeof(append),
660				 "; (%d server%s found)\n",
661				 addresscount,
662				 addresscount > 1 ? "s" : "");
663			remaining = sizeof(lookup->cmdline) -
664				    strlen(lookup->cmdline) - 1;
665			strncat(lookup->cmdline, append, remaining);
666		}
667		if (first) {
668			snprintf(append, sizeof(append),
669				 ";; global options:%s%s\n",
670				 short_form ? " +short" : "",
671				 printcmd ? " +cmd" : "");
672			first = ISC_FALSE;
673			remaining = sizeof(lookup->cmdline) -
674				    strlen(lookup->cmdline) - 1;
675			strncat(lookup->cmdline, append, remaining);
676		}
677	}
678}
679
680/*%
681 * We're not using isc_commandline_parse() here since the command line
682 * syntax of dig is quite a bit different from that which can be described
683 * by that routine.
684 * XXX doc options
685 */
686
687static void
688plus_option(char *option, isc_boolean_t is_batchfile,
689	    dig_lookup_t *lookup)
690{
691	isc_result_t result;
692	char option_store[256];
693	char *cmd, *value, *ptr;
694	isc_uint32_t num;
695	isc_boolean_t state = ISC_TRUE;
696#ifdef DIG_SIGCHASE
697	size_t n;
698#endif
699
700	strncpy(option_store, option, sizeof(option_store));
701	option_store[sizeof(option_store)-1]=0;
702	ptr = option_store;
703	cmd = next_token(&ptr,"=");
704	if (cmd == NULL) {
705		printf(";; Invalid option %s\n", option_store);
706		return;
707	}
708	value = ptr;
709	if (strncasecmp(cmd, "no", 2)==0) {
710		cmd += 2;
711		state = ISC_FALSE;
712	}
713
714#define FULLCHECK(A) \
715	do { \
716		size_t _l = strlen(cmd); \
717		if (_l >= sizeof(A) || strncasecmp(cmd, A, _l) != 0) \
718			goto invalid_option; \
719	} while (0)
720#define FULLCHECK2(A, B) \
721	do { \
722		size_t _l = strlen(cmd); \
723		if ((_l >= sizeof(A) || strncasecmp(cmd, A, _l) != 0) && \
724		    (_l >= sizeof(B) || strncasecmp(cmd, B, _l) != 0)) \
725			goto invalid_option; \
726	} while (0)
727
728	switch (cmd[0]) {
729	case 'a':
730		switch (cmd[1]) {
731		case 'a': /* aaonly / aaflag */
732			FULLCHECK2("aaonly", "aaflag");
733			lookup->aaonly = state;
734			break;
735		case 'd':
736			switch (cmd[2]) {
737			case 'd': /* additional */
738				FULLCHECK("additional");
739				lookup->section_additional = state;
740				break;
741			case 'f': /* adflag */
742			case '\0': /* +ad is a synonym for +adflag */
743				FULLCHECK("adflag");
744				lookup->adflag = state;
745				break;
746			default:
747				goto invalid_option;
748			}
749			break;
750		case 'l': /* all */
751			FULLCHECK("all");
752			lookup->section_question = state;
753			lookup->section_authority = state;
754			lookup->section_answer = state;
755			lookup->section_additional = state;
756			lookup->comments = state;
757			lookup->stats = state;
758			printcmd = state;
759			break;
760		case 'n': /* answer */
761			FULLCHECK("answer");
762			lookup->section_answer = state;
763			break;
764		case 'u': /* authority */
765			FULLCHECK("authority");
766			lookup->section_authority = state;
767			break;
768		default:
769			goto invalid_option;
770		}
771		break;
772	case 'b':
773		switch (cmd[1]) {
774		case 'e':/* besteffort */
775			FULLCHECK("besteffort");
776			lookup->besteffort = state;
777			break;
778		case 'u':/* bufsize */
779			FULLCHECK("bufsize");
780			if (value == NULL)
781				goto need_value;
782			if (!state)
783				goto invalid_option;
784			result = parse_uint(&num, value, COMMSIZE,
785					    "buffer size");
786			if (result != ISC_R_SUCCESS)
787				fatal("Couldn't parse buffer size");
788			lookup->udpsize = num;
789			break;
790		default:
791			goto invalid_option;
792		}
793		break;
794	case 'c':
795		switch (cmd[1]) {
796		case 'd':/* cdflag */
797			switch (cmd[2]) {
798			case 'f': /* cdflag */
799			case '\0': /* +cd is a synonym for +cdflag */
800				FULLCHECK("cdflag");
801				lookup->cdflag = state;
802				break;
803			default:
804				goto invalid_option;
805			}
806			break;
807		case 'l': /* cl */
808			FULLCHECK("cl");
809			noclass = ISC_TF(!state);
810			break;
811		case 'm': /* cmd */
812			FULLCHECK("cmd");
813			printcmd = state;
814			break;
815		case 'o': /* comments */
816			FULLCHECK("comments");
817			lookup->comments = state;
818			if (lookup == default_lookup)
819				pluscomm = state;
820			break;
821		default:
822			goto invalid_option;
823		}
824		break;
825	case 'd':
826		switch (cmd[1]) {
827		case 'e': /* defname */
828			FULLCHECK("defname");
829			if (!lookup->trace) {
830				usesearch = state;
831			}
832			break;
833		case 'n': /* dnssec */
834			FULLCHECK("dnssec");
835			if (state && lookup->edns == -1)
836				lookup->edns = 0;
837			lookup->dnssec = state;
838			break;
839		case 'o': /* domain */
840			FULLCHECK("domain");
841			if (value == NULL)
842				goto need_value;
843			if (!state)
844				goto invalid_option;
845			strncpy(domainopt, value, sizeof(domainopt));
846			domainopt[sizeof(domainopt)-1] = '\0';
847			break;
848		default:
849			goto invalid_option;
850		}
851		break;
852	case 'e':
853		FULLCHECK("edns");
854		if (!state) {
855			lookup->edns = -1;
856			break;
857		}
858		if (value == NULL)
859			goto need_value;
860		result = parse_uint(&num, value, 255, "edns");
861		if (result != ISC_R_SUCCESS)
862			fatal("Couldn't parse edns");
863		lookup->edns = num;
864		break;
865	case 'f': /* fail */
866		FULLCHECK("fail");
867		lookup->servfail_stops = state;
868		break;
869	case 'i':
870		switch (cmd[1]) {
871		case 'd': /* identify */
872			FULLCHECK("identify");
873			lookup->identify = state;
874			break;
875		case 'g': /* ignore */
876		default: /* Inherits default for compatibility */
877			FULLCHECK("ignore");
878			lookup->ignore = ISC_TRUE;
879		}
880		break;
881	case 'm': /* multiline */
882		FULLCHECK("multiline");
883		multiline = state;
884		break;
885	case 'n':
886		switch (cmd[1]) {
887		case 'd': /* ndots */
888			FULLCHECK("ndots");
889			if (value == NULL)
890				goto need_value;
891			if (!state)
892				goto invalid_option;
893			result = parse_uint(&num, value, MAXNDOTS, "ndots");
894			if (result != ISC_R_SUCCESS)
895				fatal("Couldn't parse ndots");
896			ndots = num;
897			break;
898		case 's':
899			switch (cmd[2]) {
900			case 'i': /* nsid */
901				FULLCHECK("nsid");
902				if (state && lookup->edns == -1)
903					lookup->edns = 0;
904				lookup->nsid = state;
905				break;
906			case 's': /* nssearch */
907				FULLCHECK("nssearch");
908				lookup->ns_search_only = state;
909				if (state) {
910					lookup->trace_root = ISC_TRUE;
911					lookup->recurse = ISC_TRUE;
912					lookup->identify = ISC_TRUE;
913					lookup->stats = ISC_FALSE;
914					lookup->comments = ISC_FALSE;
915					lookup->section_additional = ISC_FALSE;
916					lookup->section_authority = ISC_FALSE;
917					lookup->section_question = ISC_FALSE;
918					lookup->rdtype = dns_rdatatype_ns;
919					lookup->rdtypeset = ISC_TRUE;
920					short_form = ISC_TRUE;
921				}
922				break;
923			default:
924				goto invalid_option;
925			}
926			break;
927		default:
928			goto invalid_option;
929		}
930		break;
931	case 'o':
932		FULLCHECK("onesoa");
933		onesoa = state;
934		break;
935	case 'q':
936		switch (cmd[1]) {
937		case 'r': /* qr */
938			FULLCHECK("qr");
939			qr = state;
940			break;
941		case 'u': /* question */
942			FULLCHECK("question");
943			lookup->section_question = state;
944			if (lookup == default_lookup)
945				plusquest = state;
946			break;
947		default:
948			goto invalid_option;
949		}
950		break;
951	case 'r':
952		switch (cmd[1]) {
953		case 'e':
954			switch (cmd[2]) {
955			case 'c': /* recurse */
956				FULLCHECK("recurse");
957				lookup->recurse = state;
958				break;
959			case 't': /* retry / retries */
960				FULLCHECK2("retry", "retries");
961				if (value == NULL)
962					goto need_value;
963				if (!state)
964					goto invalid_option;
965				result = parse_uint(&lookup->retries, value,
966						    MAXTRIES - 1, "retries");
967				if (result != ISC_R_SUCCESS)
968					fatal("Couldn't parse retries");
969				lookup->retries++;
970				break;
971			default:
972				goto invalid_option;
973			}
974			break;
975		default:
976			goto invalid_option;
977		}
978		break;
979	case 's':
980		switch (cmd[1]) {
981		case 'e': /* search */
982			FULLCHECK("search");
983			if (!lookup->trace) {
984				usesearch = state;
985			}
986			break;
987		case 'h':
988			if (cmd[2] != 'o')
989				goto invalid_option;
990			switch (cmd[3]) {
991			case 'r': /* short */
992				FULLCHECK("short");
993				short_form = state;
994				if (state) {
995					printcmd = ISC_FALSE;
996					lookup->section_additional = ISC_FALSE;
997					lookup->section_answer = ISC_TRUE;
998					lookup->section_authority = ISC_FALSE;
999					lookup->section_question = ISC_FALSE;
1000					lookup->comments = ISC_FALSE;
1001					lookup->stats = ISC_FALSE;
1002				}
1003				break;
1004			case 'w': /* showsearch */
1005				FULLCHECK("showsearch");
1006				if (!lookup->trace) {
1007					showsearch = state;
1008					usesearch = state;
1009				}
1010				break;
1011			default:
1012				goto invalid_option;
1013			}
1014			break;
1015#ifdef DIG_SIGCHASE
1016		case 'i': /* sigchase */
1017			FULLCHECK("sigchase");
1018			lookup->sigchase = state;
1019			if (lookup->sigchase)
1020				lookup->dnssec = ISC_TRUE;
1021			break;
1022#endif
1023		case 't': /* stats */
1024			FULLCHECK("stats");
1025			lookup->stats = state;
1026			break;
1027		default:
1028			goto invalid_option;
1029		}
1030		break;
1031	case 't':
1032		switch (cmd[1]) {
1033		case 'c': /* tcp */
1034			FULLCHECK("tcp");
1035			if (!is_batchfile)
1036				lookup->tcp_mode = state;
1037			break;
1038		case 'i': /* timeout */
1039			FULLCHECK("timeout");
1040			if (value == NULL)
1041				goto need_value;
1042			if (!state)
1043				goto invalid_option;
1044			result = parse_uint(&timeout, value, MAXTIMEOUT,
1045					    "timeout");
1046			if (result != ISC_R_SUCCESS)
1047				fatal("Couldn't parse timeout");
1048			if (timeout == 0)
1049				timeout = 1;
1050			break;
1051#if DIG_SIGCHASE_TD
1052		case 'o': /* topdown */
1053			FULLCHECK("topdown");
1054			lookup->do_topdown = state;
1055			break;
1056#endif
1057		case 'r':
1058			switch (cmd[2]) {
1059			case 'a': /* trace */
1060				FULLCHECK("trace");
1061				lookup->trace = state;
1062				lookup->trace_root = state;
1063				if (state) {
1064					lookup->recurse = ISC_FALSE;
1065					lookup->identify = ISC_TRUE;
1066					lookup->comments = ISC_FALSE;
1067					lookup->stats = ISC_FALSE;
1068					lookup->section_additional = ISC_FALSE;
1069					lookup->section_authority = ISC_TRUE;
1070					lookup->section_question = ISC_FALSE;
1071					usesearch = ISC_FALSE;
1072				}
1073				break;
1074			case 'i': /* tries */
1075				FULLCHECK("tries");
1076				if (value == NULL)
1077					goto need_value;
1078				if (!state)
1079					goto invalid_option;
1080				result = parse_uint(&lookup->retries, value,
1081						    MAXTRIES, "tries");
1082				if (result != ISC_R_SUCCESS)
1083					fatal("Couldn't parse tries");
1084				if (lookup->retries == 0)
1085					lookup->retries = 1;
1086				break;
1087#ifdef DIG_SIGCHASE
1088			case 'u': /* trusted-key */
1089				FULLCHECK("trusted-key");
1090				if (value == NULL)
1091					goto need_value;
1092				if (!state)
1093					goto invalid_option;
1094				n = strlcpy(trustedkey, ptr,
1095					    sizeof(trustedkey));
1096				if (n >= sizeof(trustedkey))
1097					fatal("trusted key too large");
1098				break;
1099#endif
1100			default:
1101				goto invalid_option;
1102			}
1103			break;
1104		case 't': /* ttlid */
1105			FULLCHECK("ttlid");
1106			nottl = ISC_TF(!state);
1107			break;
1108		default:
1109			goto invalid_option;
1110		}
1111		break;
1112	case 'v':
1113		FULLCHECK("vc");
1114		if (!is_batchfile)
1115			lookup->tcp_mode = state;
1116		break;
1117	default:
1118	invalid_option:
1119	need_value:
1120		fprintf(stderr, "Invalid option: +%s\n",
1121			 option);
1122		usage();
1123	}
1124	return;
1125}
1126
1127/*%
1128 * #ISC_TRUE returned if value was used
1129 */
1130static const char *single_dash_opts = "46dhimnv";
1131static const char *dash_opts = "46bcdfhikmnptvyx";
1132static isc_boolean_t
1133dash_option(char *option, char *next, dig_lookup_t **lookup,
1134	    isc_boolean_t *open_type_class, isc_boolean_t *need_clone,
1135	    isc_boolean_t config_only, int argc, char **argv,
1136	    isc_boolean_t *firstarg)
1137{
1138	char opt, *value, *ptr, *ptr2, *ptr3;
1139	isc_result_t result;
1140	isc_boolean_t value_from_next;
1141	isc_textregion_t tr;
1142	dns_rdatatype_t rdtype;
1143	dns_rdataclass_t rdclass;
1144	char textname[MXNAME];
1145	struct in_addr in4;
1146	struct in6_addr in6;
1147	in_port_t srcport;
1148	char *hash, *cmd;
1149	isc_uint32_t num;
1150
1151	while (strpbrk(option, single_dash_opts) == &option[0]) {
1152		/*
1153		 * Since the -[46dhimnv] options do not take an argument,
1154		 * account for them (in any number and/or combination)
1155		 * if they appear as the first character(s) of a q-opt.
1156		 */
1157		opt = option[0];
1158		switch (opt) {
1159		case '4':
1160			if (have_ipv4) {
1161				isc_net_disableipv6();
1162				have_ipv6 = ISC_FALSE;
1163			} else {
1164				fatal("can't find IPv4 networking");
1165				/* NOTREACHED */
1166				return (ISC_FALSE);
1167			}
1168			break;
1169		case '6':
1170			if (have_ipv6) {
1171				isc_net_disableipv4();
1172				have_ipv4 = ISC_FALSE;
1173			} else {
1174				fatal("can't find IPv6 networking");
1175				/* NOTREACHED */
1176				return (ISC_FALSE);
1177			}
1178			break;
1179		case 'd':
1180			ptr = strpbrk(&option[1], dash_opts);
1181			if (ptr != &option[1]) {
1182				cmd = option;
1183				FULLCHECK("debug");
1184				debugging = ISC_TRUE;
1185				return (ISC_FALSE);
1186			} else
1187				debugging = ISC_TRUE;
1188			break;
1189		case 'h':
1190			help();
1191			exit(0);
1192			break;
1193		case 'i':
1194			ip6_int = ISC_TRUE;
1195			break;
1196		case 'm': /* memdebug */
1197			/* memdebug is handled in preparse_args() */
1198			break;
1199		case 'n':
1200			/* deprecated */
1201			break;
1202		case 'v':
1203			version();
1204			exit(0);
1205			break;
1206		}
1207		if (strlen(option) > 1U)
1208			option = &option[1];
1209		else
1210			return (ISC_FALSE);
1211	}
1212	opt = option[0];
1213	if (strlen(option) > 1U) {
1214		value_from_next = ISC_FALSE;
1215		value = &option[1];
1216	} else {
1217		value_from_next = ISC_TRUE;
1218		value = next;
1219	}
1220	if (value == NULL)
1221		goto invalid_option;
1222	switch (opt) {
1223	case 'b':
1224		hash = strchr(value, '#');
1225		if (hash != NULL) {
1226			result = parse_uint(&num, hash + 1, MAXPORT,
1227					    "port number");
1228			if (result != ISC_R_SUCCESS)
1229				fatal("Couldn't parse port number");
1230			srcport = num;
1231			*hash = '\0';
1232		} else
1233			srcport = 0;
1234		if (have_ipv6 && inet_pton(AF_INET6, value, &in6) == 1) {
1235			isc_sockaddr_fromin6(&bind_address, &in6, srcport);
1236			isc_net_disableipv4();
1237		} else if (have_ipv4 && inet_pton(AF_INET, value, &in4) == 1) {
1238			isc_sockaddr_fromin(&bind_address, &in4, srcport);
1239			isc_net_disableipv6();
1240		} else {
1241			if (hash != NULL)
1242				*hash = '#';
1243			fatal("invalid address %s", value);
1244		}
1245		if (hash != NULL)
1246			*hash = '#';
1247		specified_source = ISC_TRUE;
1248		return (value_from_next);
1249	case 'c':
1250		if ((*lookup)->rdclassset) {
1251			fprintf(stderr, ";; Warning, extra class option\n");
1252		}
1253		*open_type_class = ISC_FALSE;
1254		tr.base = value;
1255		tr.length = strlen(value);
1256		result = dns_rdataclass_fromtext(&rdclass,
1257						 (isc_textregion_t *)&tr);
1258		if (result == ISC_R_SUCCESS) {
1259			(*lookup)->rdclass = rdclass;
1260			(*lookup)->rdclassset = ISC_TRUE;
1261		} else
1262			fprintf(stderr, ";; Warning, ignoring "
1263				"invalid class %s\n",
1264				value);
1265		return (value_from_next);
1266	case 'f':
1267		batchname = value;
1268		return (value_from_next);
1269	case 'k':
1270		strncpy(keyfile, value, sizeof(keyfile));
1271		keyfile[sizeof(keyfile)-1]=0;
1272		return (value_from_next);
1273	case 'p':
1274		result = parse_uint(&num, value, MAXPORT, "port number");
1275		if (result != ISC_R_SUCCESS)
1276			fatal("Couldn't parse port number");
1277		port = num;
1278		return (value_from_next);
1279	case 'q':
1280		if (!config_only) {
1281			if (*need_clone)
1282				(*lookup) = clone_lookup(default_lookup,
1283							 ISC_TRUE);
1284			*need_clone = ISC_TRUE;
1285			strncpy((*lookup)->textname, value,
1286				sizeof((*lookup)->textname));
1287			(*lookup)->textname[sizeof((*lookup)->textname)-1]=0;
1288			(*lookup)->trace_root = ISC_TF((*lookup)->trace  ||
1289						     (*lookup)->ns_search_only);
1290			(*lookup)->new_search = ISC_TRUE;
1291			if (*firstarg) {
1292				printgreeting(argc, argv, *lookup);
1293				*firstarg = ISC_FALSE;
1294			}
1295			ISC_LIST_APPEND(lookup_list, (*lookup), link);
1296			debug("looking up %s", (*lookup)->textname);
1297		}
1298		return (value_from_next);
1299	case 't':
1300		*open_type_class = ISC_FALSE;
1301		if (strncasecmp(value, "ixfr=", 5) == 0) {
1302			rdtype = dns_rdatatype_ixfr;
1303			result = ISC_R_SUCCESS;
1304		} else {
1305			tr.base = value;
1306			tr.length = strlen(value);
1307			result = dns_rdatatype_fromtext(&rdtype,
1308						(isc_textregion_t *)&tr);
1309			if (result == ISC_R_SUCCESS &&
1310			    rdtype == dns_rdatatype_ixfr) {
1311				result = DNS_R_UNKNOWN;
1312			}
1313		}
1314		if (result == ISC_R_SUCCESS) {
1315			if ((*lookup)->rdtypeset) {
1316				fprintf(stderr, ";; Warning, "
1317						"extra type option\n");
1318			}
1319			if (rdtype == dns_rdatatype_ixfr) {
1320				isc_uint32_t serial;
1321				(*lookup)->rdtype = dns_rdatatype_ixfr;
1322				(*lookup)->rdtypeset = ISC_TRUE;
1323				result = parse_uint(&serial, &value[5],
1324					   MAXSERIAL, "serial number");
1325				if (result != ISC_R_SUCCESS)
1326					fatal("Couldn't parse serial number");
1327				(*lookup)->ixfr_serial = serial;
1328				(*lookup)->section_question = plusquest;
1329				(*lookup)->comments = pluscomm;
1330				(*lookup)->tcp_mode = ISC_TRUE;
1331			} else {
1332				(*lookup)->rdtype = rdtype;
1333				(*lookup)->rdtypeset = ISC_TRUE;
1334				if (rdtype == dns_rdatatype_axfr) {
1335					(*lookup)->section_question = plusquest;
1336					(*lookup)->comments = pluscomm;
1337				}
1338				(*lookup)->ixfr_serial = ISC_FALSE;
1339			}
1340		} else
1341			fprintf(stderr, ";; Warning, ignoring "
1342				 "invalid type %s\n",
1343				 value);
1344		return (value_from_next);
1345	case 'y':
1346		ptr = next_token(&value,":");	/* hmac type or name */
1347		if (ptr == NULL) {
1348			usage();
1349		}
1350		ptr2 = next_token(&value, ":");	/* name or secret */
1351		if (ptr2 == NULL)
1352			usage();
1353		ptr3 = next_token(&value,":"); /* secret or NULL */
1354		if (ptr3 != NULL) {
1355			parse_hmac(ptr);
1356			ptr = ptr2;
1357			ptr2 = ptr3;
1358		} else  {
1359			hmacname = DNS_TSIG_HMACMD5_NAME;
1360			digestbits = 0;
1361		}
1362		strncpy(keynametext, ptr, sizeof(keynametext));
1363		keynametext[sizeof(keynametext)-1]=0;
1364		strncpy(keysecret, ptr2, sizeof(keysecret));
1365		keysecret[sizeof(keysecret)-1]=0;
1366		return (value_from_next);
1367	case 'x':
1368		if (*need_clone)
1369			*lookup = clone_lookup(default_lookup, ISC_TRUE);
1370		*need_clone = ISC_TRUE;
1371		if (get_reverse(textname, sizeof(textname), value,
1372				ip6_int, ISC_FALSE) == ISC_R_SUCCESS) {
1373			strncpy((*lookup)->textname, textname,
1374				sizeof((*lookup)->textname));
1375			debug("looking up %s", (*lookup)->textname);
1376			(*lookup)->trace_root = ISC_TF((*lookup)->trace  ||
1377						(*lookup)->ns_search_only);
1378			(*lookup)->ip6_int = ip6_int;
1379			if (!(*lookup)->rdtypeset)
1380				(*lookup)->rdtype = dns_rdatatype_ptr;
1381			if (!(*lookup)->rdclassset)
1382				(*lookup)->rdclass = dns_rdataclass_in;
1383			(*lookup)->new_search = ISC_TRUE;
1384			if (*firstarg) {
1385				printgreeting(argc, argv, *lookup);
1386				*firstarg = ISC_FALSE;
1387			}
1388			ISC_LIST_APPEND(lookup_list, *lookup, link);
1389		} else {
1390			fprintf(stderr, "Invalid IP address %s\n", value);
1391			exit(1);
1392		}
1393		return (value_from_next);
1394	invalid_option:
1395	default:
1396		fprintf(stderr, "Invalid option: -%s\n", option);
1397		usage();
1398	}
1399	/* NOTREACHED */
1400	return (ISC_FALSE);
1401}
1402
1403/*%
1404 * Because we may be trying to do memory allocation recording, we're going
1405 * to need to parse the arguments for the -m *before* we start the main
1406 * argument parsing routine.
1407 *
1408 * I'd prefer not to have to do this, but I am not quite sure how else to
1409 * fix the problem.  Argument parsing in dig involves memory allocation
1410 * by its nature, so it can't be done in the main argument parser.
1411 */
1412static void
1413preparse_args(int argc, char **argv) {
1414	int rc;
1415	char **rv;
1416	char *option;
1417
1418	rc = argc;
1419	rv = argv;
1420	for (rc--, rv++; rc > 0; rc--, rv++) {
1421		if (rv[0][0] != '-')
1422			continue;
1423		option = &rv[0][1];
1424		while (strpbrk(option, single_dash_opts) == &option[0]) {
1425			if (option[0] == 'm') {
1426				memdebugging = ISC_TRUE;
1427				isc_mem_debugging = ISC_MEM_DEBUGTRACE |
1428					ISC_MEM_DEBUGRECORD;
1429				return;
1430			}
1431			option = &option[1];
1432		}
1433	}
1434}
1435
1436static void
1437parse_args(isc_boolean_t is_batchfile, isc_boolean_t config_only,
1438	   int argc, char **argv) {
1439	isc_result_t result;
1440	isc_textregion_t tr;
1441	isc_boolean_t firstarg = ISC_TRUE;
1442	dig_lookup_t *lookup = NULL;
1443	dns_rdatatype_t rdtype;
1444	dns_rdataclass_t rdclass;
1445	isc_boolean_t open_type_class = ISC_TRUE;
1446	char batchline[MXNAME];
1447	int bargc;
1448	char *bargv[64];
1449	int rc;
1450	char **rv;
1451#ifndef NOPOSIX
1452	char *homedir;
1453	char rcfile[256];
1454#endif
1455	char *input;
1456	int i;
1457	isc_boolean_t need_clone = ISC_TRUE;
1458
1459	/*
1460	 * The semantics for parsing the args is a bit complex; if
1461	 * we don't have a host yet, make the arg apply globally,
1462	 * otherwise make it apply to the latest host.  This is
1463	 * a bit different than the previous versions, but should
1464	 * form a consistent user interface.
1465	 *
1466	 * First, create a "default lookup" which won't actually be used
1467	 * anywhere, except for cloning into new lookups
1468	 */
1469
1470	debug("parse_args()");
1471	if (!is_batchfile) {
1472		debug("making new lookup");
1473		default_lookup = make_empty_lookup();
1474
1475#ifndef NOPOSIX
1476		/*
1477		 * Treat ${HOME}/.digrc as a special batchfile
1478		 */
1479		INSIST(batchfp == NULL);
1480		homedir = getenv("HOME");
1481		if (homedir != NULL) {
1482			unsigned int n;
1483			n = snprintf(rcfile, sizeof(rcfile), "%s/.digrc",
1484				     homedir);
1485			if (n < sizeof(rcfile))
1486				batchfp = fopen(rcfile, "r");
1487		}
1488		if (batchfp != NULL) {
1489			while (fgets(batchline, sizeof(batchline),
1490				     batchfp) != 0) {
1491				debug("config line %s", batchline);
1492				bargc = 1;
1493				input = batchline;
1494				bargv[bargc] = next_token(&input, " \t\r\n");
1495				while ((bargv[bargc] != NULL) &&
1496				       (bargc < 62)) {
1497					bargc++;
1498					bargv[bargc] =
1499						next_token(&input, " \t\r\n");
1500				}
1501
1502				bargv[0] = argv[0];
1503				argv0 = argv[0];
1504
1505				for(i = 0; i < bargc; i++)
1506					debug(".digrc argv %d: %s",
1507					      i, bargv[i]);
1508				parse_args(ISC_TRUE, ISC_TRUE, bargc,
1509					   (char **)bargv);
1510			}
1511			fclose(batchfp);
1512		}
1513#endif
1514	}
1515
1516	if (is_batchfile && !config_only) {
1517		/* Processing '-f batchfile'. */
1518		lookup = clone_lookup(default_lookup, ISC_TRUE);
1519		need_clone = ISC_FALSE;
1520	} else
1521		lookup = default_lookup;
1522
1523	rc = argc;
1524	rv = argv;
1525	for (rc--, rv++; rc > 0; rc--, rv++) {
1526		debug("main parsing %s", rv[0]);
1527		if (strncmp(rv[0], "%", 1) == 0)
1528			break;
1529		if (strncmp(rv[0], "@", 1) == 0) {
1530			addresscount = getaddresses(lookup, &rv[0][1], NULL);
1531		} else if (rv[0][0] == '+') {
1532			plus_option(&rv[0][1], is_batchfile,
1533				    lookup);
1534		} else if (rv[0][0] == '-') {
1535			if (rc <= 1) {
1536				if (dash_option(&rv[0][1], NULL,
1537						&lookup, &open_type_class,
1538						&need_clone, config_only,
1539						argc, argv, &firstarg)) {
1540					rc--;
1541					rv++;
1542				}
1543			} else {
1544				if (dash_option(&rv[0][1], rv[1],
1545						&lookup, &open_type_class,
1546						&need_clone, config_only,
1547						argc, argv, &firstarg)) {
1548					rc--;
1549					rv++;
1550				}
1551			}
1552		} else {
1553			/*
1554			 * Anything which isn't an option
1555			 */
1556			if (open_type_class) {
1557				if (strncasecmp(rv[0], "ixfr=", 5) == 0) {
1558					rdtype = dns_rdatatype_ixfr;
1559					result = ISC_R_SUCCESS;
1560				} else {
1561					tr.base = rv[0];
1562					tr.length = strlen(rv[0]);
1563					result = dns_rdatatype_fromtext(&rdtype,
1564						(isc_textregion_t *)&tr);
1565					if (result == ISC_R_SUCCESS &&
1566					    rdtype == dns_rdatatype_ixfr) {
1567						fprintf(stderr, ";; Warning, "
1568							"ixfr requires a "
1569							"serial number\n");
1570						continue;
1571					}
1572				}
1573				if (result == ISC_R_SUCCESS) {
1574					if (lookup->rdtypeset) {
1575						fprintf(stderr, ";; Warning, "
1576							"extra type option\n");
1577					}
1578					if (rdtype == dns_rdatatype_ixfr) {
1579						isc_uint32_t serial;
1580						lookup->rdtype =
1581							dns_rdatatype_ixfr;
1582						lookup->rdtypeset = ISC_TRUE;
1583						result = parse_uint(&serial,
1584								    &rv[0][5],
1585								    MAXSERIAL,
1586							      "serial number");
1587						if (result != ISC_R_SUCCESS)
1588							fatal("Couldn't parse "
1589							      "serial number");
1590						lookup->ixfr_serial = serial;
1591						lookup->section_question =
1592							plusquest;
1593						lookup->comments = pluscomm;
1594						lookup->tcp_mode = ISC_TRUE;
1595					} else {
1596						lookup->rdtype = rdtype;
1597						lookup->rdtypeset = ISC_TRUE;
1598						if (rdtype ==
1599						    dns_rdatatype_axfr) {
1600						    lookup->section_question =
1601								plusquest;
1602						    lookup->comments = pluscomm;
1603						}
1604						lookup->ixfr_serial = ISC_FALSE;
1605					}
1606					continue;
1607				}
1608				result = dns_rdataclass_fromtext(&rdclass,
1609						     (isc_textregion_t *)&tr);
1610				if (result == ISC_R_SUCCESS) {
1611					if (lookup->rdclassset) {
1612						fprintf(stderr, ";; Warning, "
1613							"extra class option\n");
1614					}
1615					lookup->rdclass = rdclass;
1616					lookup->rdclassset = ISC_TRUE;
1617					continue;
1618				}
1619			}
1620
1621			if (!config_only) {
1622				if (need_clone)
1623					lookup = clone_lookup(default_lookup,
1624								      ISC_TRUE);
1625				need_clone = ISC_TRUE;
1626				strncpy(lookup->textname, rv[0],
1627					sizeof(lookup->textname));
1628				lookup->textname[sizeof(lookup->textname)-1]=0;
1629				lookup->trace_root = ISC_TF(lookup->trace  ||
1630						     lookup->ns_search_only);
1631				lookup->new_search = ISC_TRUE;
1632				if (firstarg) {
1633					printgreeting(argc, argv, lookup);
1634					firstarg = ISC_FALSE;
1635				}
1636				ISC_LIST_APPEND(lookup_list, lookup, link);
1637				debug("looking up %s", lookup->textname);
1638			}
1639			/* XXX Error message */
1640		}
1641	}
1642
1643	/*
1644	 * If we have a batchfile, seed the lookup list with the
1645	 * first entry, then trust the callback in dighost_shutdown
1646	 * to get the rest
1647	 */
1648	if ((batchname != NULL) && !(is_batchfile)) {
1649		if (strcmp(batchname, "-") == 0)
1650			batchfp = stdin;
1651		else
1652			batchfp = fopen(batchname, "r");
1653		if (batchfp == NULL) {
1654			perror(batchname);
1655			if (exitcode < 8)
1656				exitcode = 8;
1657			fatal("couldn't open specified batch file");
1658		}
1659		/* XXX Remove code dup from shutdown code */
1660	next_line:
1661		if (fgets(batchline, sizeof(batchline), batchfp) != 0) {
1662			bargc = 1;
1663			debug("batch line %s", batchline);
1664			if (batchline[0] == '\r' || batchline[0] == '\n'
1665			    || batchline[0] == '#' || batchline[0] == ';')
1666				goto next_line;
1667			input = batchline;
1668			bargv[bargc] = next_token(&input, " \t\r\n");
1669			while ((bargv[bargc] != NULL) && (bargc < 14)) {
1670				bargc++;
1671				bargv[bargc] = next_token(&input, " \t\r\n");
1672			}
1673
1674			bargv[0] = argv[0];
1675			argv0 = argv[0];
1676
1677			for(i = 0; i < bargc; i++)
1678				debug("batch argv %d: %s", i, bargv[i]);
1679			parse_args(ISC_TRUE, ISC_FALSE, bargc, (char **)bargv);
1680			return;
1681		}
1682		return;
1683	}
1684	/*
1685	 * If no lookup specified, search for root
1686	 */
1687	if ((lookup_list.head == NULL) && !config_only) {
1688		if (need_clone)
1689			lookup = clone_lookup(default_lookup, ISC_TRUE);
1690		need_clone = ISC_TRUE;
1691		lookup->trace_root = ISC_TF(lookup->trace ||
1692					    lookup->ns_search_only);
1693		lookup->new_search = ISC_TRUE;
1694		strcpy(lookup->textname, ".");
1695		lookup->rdtype = dns_rdatatype_ns;
1696		lookup->rdtypeset = ISC_TRUE;
1697		if (firstarg) {
1698			printgreeting(argc, argv, lookup);
1699			firstarg = ISC_FALSE;
1700		}
1701		ISC_LIST_APPEND(lookup_list, lookup, link);
1702	}
1703	if (!need_clone)
1704		destroy_lookup(lookup);
1705}
1706
1707/*
1708 * Callback from dighost.c to allow program-specific shutdown code.
1709 * Here, we're possibly reading from a batch file, then shutting down
1710 * for real if there's nothing in the batch file to read.
1711 */
1712void
1713dighost_shutdown(void) {
1714	char batchline[MXNAME];
1715	int bargc;
1716	char *bargv[16];
1717	char *input;
1718	int i;
1719
1720	if (batchname == NULL) {
1721		isc_app_shutdown();
1722		return;
1723	}
1724
1725	fflush(stdout);
1726	if (feof(batchfp)) {
1727		batchname = NULL;
1728		isc_app_shutdown();
1729		if (batchfp != stdin)
1730			fclose(batchfp);
1731		return;
1732	}
1733
1734	if (fgets(batchline, sizeof(batchline), batchfp) != 0) {
1735		debug("batch line %s", batchline);
1736		bargc = 1;
1737		input = batchline;
1738		bargv[bargc] = next_token(&input, " \t\r\n");
1739		while ((bargv[bargc] != NULL) && (bargc < 14)) {
1740			bargc++;
1741			bargv[bargc] = next_token(&input, " \t\r\n");
1742		}
1743
1744		bargv[0] = argv0;
1745
1746		for(i = 0; i < bargc; i++)
1747			debug("batch argv %d: %s", i, bargv[i]);
1748		parse_args(ISC_TRUE, ISC_FALSE, bargc, (char **)bargv);
1749		start_lookup();
1750	} else {
1751		batchname = NULL;
1752		if (batchfp != stdin)
1753			fclose(batchfp);
1754		isc_app_shutdown();
1755		return;
1756	}
1757}
1758
1759/*% Main processing routine for dig */
1760int
1761main(int argc, char **argv) {
1762	isc_result_t result;
1763
1764	ISC_LIST_INIT(lookup_list);
1765	ISC_LIST_INIT(server_list);
1766	ISC_LIST_INIT(search_list);
1767
1768	debug("main()");
1769	preparse_args(argc, argv);
1770	progname = argv[0];
1771	result = isc_app_start();
1772	check_result(result, "isc_app_start");
1773	setup_libs();
1774	parse_args(ISC_FALSE, ISC_FALSE, argc, argv);
1775	setup_system();
1776	if (domainopt[0] != '\0') {
1777		set_search_domain(domainopt);
1778		usesearch = ISC_TRUE;
1779	}
1780	result = isc_app_onrun(mctx, global_task, onrun_callback, NULL);
1781	check_result(result, "isc_app_onrun");
1782	isc_app_run();
1783	destroy_lookup(default_lookup);
1784	if (batchname != NULL) {
1785		if (batchfp != stdin)
1786			fclose(batchfp);
1787		batchname = NULL;
1788	}
1789#ifdef DIG_SIGCHASE
1790	clean_trustedkey();
1791#endif
1792	cancel_all();
1793	destroy_libs();
1794	isc_app_finish();
1795	return (exitcode);
1796}
1797