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 |
|
|
} |