GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/bind/bin/dig/dig.c Lines: 0 852 0.0 %
Date: 2016-12-06 Branches: 0 727 0.0 %

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