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