xref: /freebsd/contrib/ldns/drill/drill.c (revision b0b1dbdd)
1 /*
2  * drill.c
3  * the main file of drill
4  * (c) 2005-2008 NLnet Labs
5  *
6  * See the file LICENSE for the license
7  *
8  */
9 
10 #include "drill.h"
11 #include <ldns/ldns.h>
12 
13 #ifdef HAVE_SSL
14 #include <openssl/err.h>
15 #endif
16 
17 #define IP6_ARPA_MAX_LEN 65
18 
19 /* query debug, 2 hex dumps */
20 int		verbosity;
21 
22 static void
23 usage(FILE *stream, const char *progname)
24 {
25 	fprintf(stream, "  Usage: %s name [@server] [type] [class]\n", progname);
26 	fprintf(stream, "\t<name>  can be a domain name or an IP address (-x lookups)\n");
27 	fprintf(stream, "\t<type>  defaults to A\n");
28 	fprintf(stream, "\t<class> defaults to IN\n");
29 	fprintf(stream, "\n\targuments may be placed in random order\n");
30 	fprintf(stream, "\n  Options:\n");
31 	fprintf(stream, "\t-D\t\tenable DNSSEC (DO bit)\n");
32 #ifdef HAVE_SSL
33 	fprintf(stream, "\t-T\t\ttrace from the root down to <name>\n");
34 	fprintf(stream, "\t-S\t\tchase signature(s) from <name> to a know key [*]\n");
35 #endif /*HAVE_SSL*/
36 	fprintf(stream, "\t-I <address>\tsource address to query from\n");
37 	fprintf(stream, "\t-V <number>\tverbosity (0-5)\n");
38 	fprintf(stream, "\t-Q\t\tquiet mode (overrules -V)\n");
39 	fprintf(stream, "\n");
40 	fprintf(stream, "\t-f file\t\tread packet from file and send it\n");
41 	fprintf(stream, "\t-i file\t\tread packet from file and print it\n");
42 	fprintf(stream, "\t-w file\t\twrite answer packet to file\n");
43 	fprintf(stream, "\t-q file\t\twrite query packet to file\n");
44 	fprintf(stream, "\t-h\t\tshow this help\n");
45 	fprintf(stream, "\t-v\t\tshow version\n");
46 	fprintf(stream, "\n  Query options:\n");
47 	fprintf(stream, "\t-4\t\tstay on ip4\n");
48 	fprintf(stream, "\t-6\t\tstay on ip6\n");
49 	fprintf(stream, "\t-a\t\tfallback to EDNS0 and TCP if the answer is truncated\n");
50 	fprintf(stream, "\t-b <bufsize>\tuse <bufsize> as the buffer size (defaults to 512 b)\n");
51 	fprintf(stream, "\t-c <file>\tuse file for rescursive nameserver configuration"
52 			"\n\t\t\t(/etc/resolv.conf)\n");
53 	fprintf(stream, "\t-k <file>\tspecify a file that contains a trusted DNSSEC key [**]\n");
54 	fprintf(stream, "\t\t\tUsed to verify any signatures in the current answer.\n");
55 	fprintf(stream, "\t\t\tWhen DNSSEC enabled tracing (-TD) or signature\n"
56 			"\t\t\tchasing (-S) and no key files are given, keys are read\n"
57 			"\t\t\tfrom: %s\n",
58 			LDNS_TRUST_ANCHOR_FILE);
59 	fprintf(stream, "\t-o <mnemonic>\tset flags to:"
60 			"\n\t\t\t[QR|qr][AA|aa][TC|tc][RD|rd][CD|cd][RA|ra][AD|ad]\n");
61 	fprintf(stream, "\t\t\tlowercase: unset bit, uppercase: set bit\n");
62 	fprintf(stream, "\t-p <port>\tuse <port> as remote port number\n");
63 	fprintf(stream, "\t-s\t\tshow the DS RR for each key in a packet\n");
64 	fprintf(stream, "\t-u\t\tsend the query with udp (the default)\n");
65 	fprintf(stream, "\t-x\t\tdo a reverse lookup\n");
66 	fprintf(stream, "\twhen doing a secure trace:\n");
67 	fprintf(stream, "\t-r <file>\tuse file as root servers hint file\n");
68 	fprintf(stream, "\t-t\t\tsend the query with tcp (connected)\n");
69 	fprintf(stream, "\t-d <domain>\tuse domain as the start point for the trace\n");
70     fprintf(stream, "\t-y <name:key[:algo]>\tspecify named base64 tsig key, and optional an\n\t\t\talgorithm (defaults to hmac-md5.sig-alg.reg.int)\n");
71 	fprintf(stream, "\t-z\t\tdon't randomize the nameservers before use\n");
72 	fprintf(stream, "\n  [*] = enables/implies DNSSEC\n");
73 	fprintf(stream, "  [**] = can be given more than once\n");
74 	fprintf(stream, "\n  ldns-team@nlnetlabs.nl | http://www.nlnetlabs.nl/ldns/\n");
75 }
76 
77 /**
78  * Prints the drill version to stderr
79  */
80 static void
81 version(FILE *stream, const char *progname)
82 {
83         fprintf(stream, "%s version %s (ldns version %s)\n", progname, DRILL_VERSION, ldns_version());
84         fprintf(stream, "Written by NLnet Labs.\n");
85         fprintf(stream, "\nCopyright (c) 2004-2008 NLnet Labs.\n");
86         fprintf(stream, "Licensed under the revised BSD license.\n");
87         fprintf(stream, "There is NO warranty; not even for MERCHANTABILITY or FITNESS\n");
88         fprintf(stream, "FOR A PARTICULAR PURPOSE.\n");
89 }
90 
91 
92 /**
93  * Main function of drill
94  * parse the arguments and prepare a query
95  */
96 int
97 main(int argc, char *argv[])
98 {
99         ldns_resolver	*res = NULL;
100         ldns_resolver   *cmdline_res = NULL; /* only used to resolv @name names */
101 	ldns_rr_list	*cmdline_rr_list = NULL;
102 	ldns_rdf	*cmdline_dname = NULL;
103         ldns_rdf 	*qname, *qname_tmp;
104         ldns_pkt	*pkt;
105         ldns_pkt	*qpkt;
106         char 		*serv;
107         char 		*src = NULL;
108         const char 	*name;
109         char 		*name2;
110 	char		*progname;
111 	char 		*query_file = NULL;
112 	char		*answer_file = NULL;
113 	ldns_buffer	*query_buffer = NULL;
114 	ldns_rdf 	*serv_rdf;
115 	ldns_rdf 	*src_rdf = NULL;
116         ldns_rr_type 	type;
117         ldns_rr_class	clas;
118 #if 0
119 	ldns_pkt_opcode opcode = LDNS_PACKET_QUERY;
120 #endif
121 	int 		i, c;
122 	int 		int_type;
123 	int		int_clas;
124 	int		PURPOSE;
125 	char		*tsig_name = NULL;
126 	char		*tsig_data = NULL;
127 	char 		*tsig_algorithm = NULL;
128 	size_t		tsig_separator;
129 	size_t		tsig_separator2;
130 	ldns_rr		*axfr_rr;
131 	ldns_status	status;
132 	char *type_str;
133 
134 	/* list of keys used in dnssec operations */
135 	ldns_rr_list	*key_list = ldns_rr_list_new();
136 	/* what key verify the current answer */
137 	ldns_rr_list 	*key_verified;
138 
139 	/* resolver options */
140 	uint16_t	qflags;
141 	uint16_t 	qbuf;
142 	uint16_t	qport;
143 	uint8_t		qfamily;
144 	bool		qdnssec;
145 	bool		qfallback;
146 	bool		qds;
147 	bool		qusevc;
148 	bool 		qrandom;
149 
150 	char		*resolv_conf_file = NULL;
151 
152 	ldns_rdf *trace_start_name = NULL;
153 
154 	int		result = 0;
155 
156 #ifdef USE_WINSOCK
157 	int r;
158 	WSADATA wsa_data;
159 #endif
160 
161 	int_type = -1; serv = NULL; type = 0;
162 	int_clas = -1; name = NULL; clas = 0;
163 	qname = NULL; src = NULL;
164 	progname = strdup(argv[0]);
165 
166 #ifdef USE_WINSOCK
167 	r = WSAStartup(MAKEWORD(2,2), &wsa_data);
168 	if(r != 0) {
169 		printf("Failed WSAStartup: %d\n", r);
170 		result = EXIT_FAILURE;
171 		goto exit;
172 	}
173 #endif /* USE_WINSOCK */
174 
175 
176 	PURPOSE = DRILL_QUERY;
177 	qflags = LDNS_RD;
178 	qport = LDNS_PORT;
179 	verbosity = 2;
180 	qdnssec = false;
181 	qfamily = LDNS_RESOLV_INETANY;
182 	qfallback = false;
183 	qds = false;
184 	qbuf = 0;
185 	qusevc = false;
186 	qrandom = true;
187 	key_verified = NULL;
188 
189 	ldns_init_random(NULL, 0);
190 
191 	if (argc == 0) {
192 		usage(stdout, progname);
193 		result = EXIT_FAILURE;
194 		goto exit;
195 	}
196 
197 	/* string from orig drill: "i:w:I46Sk:TNp:b:DsvhVcuaq:f:xr" */
198 	/* global first, query opt next, option with parm's last
199 	 * and sorted */ /*  "46DITSVQf:i:w:q:achuvxzy:so:p:b:k:" */
200 
201 	while ((c = getopt(argc, argv, "46ab:c:d:Df:hi:I:k:o:p:q:Qr:sStTuvV:w:xy:z")) != -1) {
202 		switch(c) {
203 			/* global options */
204 			case '4':
205 				qfamily = LDNS_RESOLV_INET;
206 				break;
207 			case '6':
208 				qfamily = LDNS_RESOLV_INET6;
209 				break;
210 			case 'D':
211 				qdnssec = true;
212 				break;
213 			case 'I':
214 				src = optarg;
215 				break;
216 			case 'T':
217 				if (PURPOSE == DRILL_CHASE) {
218 					fprintf(stderr, "-T and -S cannot be used at the same time.\n");
219 					exit(EXIT_FAILURE);
220 				}
221 				PURPOSE = DRILL_TRACE;
222 				break;
223 #ifdef HAVE_SSL
224 			case 'S':
225 				if (PURPOSE == DRILL_TRACE) {
226 					fprintf(stderr, "-T and -S cannot be used at the same time.\n");
227 					exit(EXIT_FAILURE);
228 				}
229 				PURPOSE = DRILL_CHASE;
230 				break;
231 #endif /* HAVE_SSL */
232 			case 'V':
233 				if (strtok(optarg, "0123456789") != NULL) {
234 					fprintf(stderr, "-V expects an number as an argument.\n");
235 					exit(EXIT_FAILURE);
236 				}
237 				verbosity = atoi(optarg);
238 				break;
239 			case 'Q':
240 				verbosity = -1;
241 				break;
242 			case 'f':
243 				query_file = optarg;
244 				break;
245 			case 'i':
246 				answer_file = optarg;
247 				PURPOSE = DRILL_AFROMFILE;
248 				break;
249 			case 'w':
250 				answer_file = optarg;
251 				break;
252 			case 'q':
253 				query_file = optarg;
254 				PURPOSE = DRILL_QTOFILE;
255 				break;
256 			case 'r':
257 				if (global_dns_root) {
258 					fprintf(stderr, "There was already a series of root servers set\n");
259 					exit(EXIT_FAILURE);
260 				}
261 				global_dns_root = read_root_hints(optarg);
262 				if (!global_dns_root) {
263 					fprintf(stderr, "Unable to read root hints file %s, aborting\n", optarg);
264 					exit(EXIT_FAILURE);
265 				}
266 				break;
267 			/* query options */
268 			case 'a':
269 				qfallback = true;
270 				break;
271 			case 'b':
272 				qbuf = (uint16_t)atoi(optarg);
273 				if (qbuf == 0) {
274 					error("%s", "<bufsize> could not be converted");
275 				}
276 				break;
277 			case 'c':
278 				resolv_conf_file = optarg;
279 				break;
280 			case 't':
281 				qusevc = true;
282 				break;
283 			case 'k':
284 				status = read_key_file(optarg,
285 						key_list, false);
286 				if (status != LDNS_STATUS_OK) {
287 					error("Could not parse the key file %s: %s", optarg, ldns_get_errorstr_by_id(status));
288 				}
289 				qdnssec = true; /* enable that too */
290 				break;
291 			case 'o':
292 				/* only looks at the first hit: capital=ON, lowercase=OFF*/
293 				if (strstr(optarg, "QR")) {
294 					DRILL_ON(qflags, LDNS_QR);
295 				}
296 				if (strstr(optarg, "qr")) {
297 					DRILL_OFF(qflags, LDNS_QR);
298 				}
299 				if (strstr(optarg, "AA")) {
300 					DRILL_ON(qflags, LDNS_AA);
301 				}
302 				if (strstr(optarg, "aa")) {
303 					DRILL_OFF(qflags, LDNS_AA);
304 				}
305 				if (strstr(optarg, "TC")) {
306 					DRILL_ON(qflags, LDNS_TC);
307 				}
308 				if (strstr(optarg, "tc")) {
309 					DRILL_OFF(qflags, LDNS_TC);
310 				}
311 				if (strstr(optarg, "RD")) {
312 					DRILL_ON(qflags, LDNS_RD);
313 				}
314 				if (strstr(optarg, "rd")) {
315 					DRILL_OFF(qflags, LDNS_RD);
316 				}
317 				if (strstr(optarg, "CD")) {
318 					DRILL_ON(qflags, LDNS_CD);
319 				}
320 				if (strstr(optarg, "cd")) {
321 					DRILL_OFF(qflags, LDNS_CD);
322 				}
323 				if (strstr(optarg, "RA")) {
324 					DRILL_ON(qflags, LDNS_RA);
325 				}
326 				if (strstr(optarg, "ra")) {
327 					DRILL_OFF(qflags, LDNS_RA);
328 				}
329 				if (strstr(optarg, "AD")) {
330 					DRILL_ON(qflags, LDNS_AD);
331 				}
332 				if (strstr(optarg, "ad")) {
333 					DRILL_OFF(qflags, LDNS_AD);
334 				}
335 				break;
336 			case 'p':
337 				qport = (uint16_t)atoi(optarg);
338 				if (qport == 0) {
339 					error("%s", "<port> could not be converted");
340 				}
341 				break;
342 			case 's':
343 				qds = true;
344 				break;
345 			case 'u':
346 				qusevc = false;
347 				break;
348 			case 'v':
349 				version(stdout, progname);
350 				result = EXIT_SUCCESS;
351 				goto exit;
352 			case 'x':
353 				PURPOSE = DRILL_REVERSE;
354 				break;
355 			case 'y':
356 #ifdef HAVE_SSL
357 				if (strchr(optarg, ':')) {
358 					tsig_separator = (size_t) (strchr(optarg, ':') - optarg);
359 					if (strchr(optarg + tsig_separator + 1, ':')) {
360 						tsig_separator2 = (size_t) (strchr(optarg + tsig_separator + 1, ':') - optarg);
361 						tsig_algorithm = xmalloc(strlen(optarg) - tsig_separator2);
362 						strncpy(tsig_algorithm, optarg + tsig_separator2 + 1, strlen(optarg) - tsig_separator2);
363 						tsig_algorithm[strlen(optarg) - tsig_separator2 - 1] = '\0';
364 					} else {
365 						tsig_separator2 = strlen(optarg);
366 						tsig_algorithm = xmalloc(26);
367 						strncpy(tsig_algorithm, "hmac-md5.sig-alg.reg.int.", 25);
368 						tsig_algorithm[25] = '\0';
369 					}
370 					tsig_name = xmalloc(tsig_separator + 1);
371 					tsig_data = xmalloc(tsig_separator2 - tsig_separator);
372 					strncpy(tsig_name, optarg, tsig_separator);
373 					strncpy(tsig_data, optarg + tsig_separator + 1, tsig_separator2 - tsig_separator - 1);
374 					/* strncpy does not append \0 if source is longer than n */
375 					tsig_name[tsig_separator] = '\0';
376 					tsig_data[ tsig_separator2 - tsig_separator - 1] = '\0';
377 				}
378 #else
379 				fprintf(stderr, "TSIG requested, but SSL is not supported\n");
380 				result = EXIT_FAILURE;
381 				goto exit;
382 #endif /* HAVE_SSL */
383 				break;
384 			case 'z':
385 				qrandom = false;
386 				break;
387 			case 'd':
388 				trace_start_name = ldns_dname_new_frm_str(optarg);
389 				if (!trace_start_name) {
390 					fprintf(stderr, "Unable to parse argument for -%c\n", c);
391 					result = EXIT_FAILURE;
392 					goto exit;
393 				}
394 				break;
395 			case 'h':
396 				version(stdout, progname);
397 				usage(stdout, progname);
398 				result = EXIT_SUCCESS;
399 				goto exit;
400 				break;
401 			default:
402 				fprintf(stderr, "Unknown argument: -%c, use -h to see usage\n", c);
403 				result = EXIT_FAILURE;
404 				goto exit;
405 		}
406 	}
407 	argc -= optind;
408 	argv += optind;
409 
410 	if ((PURPOSE == DRILL_CHASE || (PURPOSE == DRILL_TRACE && qdnssec)) &&
411 			ldns_rr_list_rr_count(key_list) == 0) {
412 
413 		(void) read_key_file(LDNS_TRUST_ANCHOR_FILE, key_list, true);
414 	}
415 	if (ldns_rr_list_rr_count(key_list) > 0) {
416 		printf(";; Number of trusted keys: %d\n",
417 				(int) ldns_rr_list_rr_count(key_list));
418 	}
419 	/* do a secure trace when requested */
420 	if (PURPOSE == DRILL_TRACE && qdnssec) {
421 #ifdef HAVE_SSL
422 		if (ldns_rr_list_rr_count(key_list) == 0) {
423 			warning("%s", "No trusted keys were given. Will not be able to verify authenticity!");
424 		}
425 		PURPOSE = DRILL_SECTRACE;
426 #else
427 		fprintf(stderr, "ldns has not been compiled with OpenSSL support. Secure trace not available\n");
428 		exit(1);
429 #endif /* HAVE_SSL */
430 	}
431 
432 	/* parse the arguments, with multiple arguments, the last argument
433 	 * found is used */
434 	for(i = 0; i < argc; i++) {
435 
436 		/* if ^@ then it's a server */
437 		if (argv[i][0] == '@') {
438 			if (strlen(argv[i]) == 1) {
439 				warning("%s", "No nameserver given");
440 				exit(EXIT_FAILURE);
441 			}
442 			serv = argv[i] + 1;
443 			continue;
444 		}
445 		/* if has a dot, it's a name */
446 		if (strchr(argv[i], '.')) {
447 			name = argv[i];
448 			continue;
449 		}
450 		/* if it matches a type, it's a type */
451 		if (int_type == -1) {
452 			type = ldns_get_rr_type_by_name(argv[i]);
453 			if (type != 0) {
454 				int_type = 0;
455 				continue;
456 			}
457 		}
458 		/* if it matches a class, it's a class */
459 		if (int_clas == -1) {
460 			clas = ldns_get_rr_class_by_name(argv[i]);
461 			if (clas != 0) {
462 				int_clas = 0;
463 				continue;
464 			}
465 		}
466 		/* it all fails assume it's a name */
467 		name = argv[i];
468 	}
469 	/* act like dig and use for . NS */
470 	if (!name) {
471 		name = ".";
472 		int_type = 0;
473 		type = LDNS_RR_TYPE_NS;
474 	}
475 
476 	/* defaults if not given */
477 	if (int_clas == -1) {
478 		clas = LDNS_RR_CLASS_IN;
479 	}
480 	if (int_type == -1) {
481 		if (PURPOSE != DRILL_REVERSE) {
482 			type = LDNS_RR_TYPE_A;
483 		} else {
484 			type = LDNS_RR_TYPE_PTR;
485 		}
486 	}
487 
488 	if (src) {
489 		src_rdf = ldns_rdf_new_addr_frm_str(src);
490 		if(!src_rdf) {
491 			fprintf(stderr, "-I must be (or resolve) to a valid IP[v6] address.\n");
492 			exit(EXIT_FAILURE);
493 		}
494 	}
495 
496 	/* set the nameserver to use */
497 	if (!serv) {
498 		/* no server given make a resolver from /etc/resolv.conf */
499 		status = ldns_resolver_new_frm_file(&res, resolv_conf_file);
500 		if (status != LDNS_STATUS_OK) {
501 			warning("Could not create a resolver structure: %s (%s)\n"
502 					"Try drill @localhost if you have a resolver running on your machine.",
503 				    ldns_get_errorstr_by_id(status), resolv_conf_file);
504 			result = EXIT_FAILURE;
505 			goto exit;
506 		}
507 	} else {
508 		res = ldns_resolver_new();
509 		if (!res || strlen(serv) <= 0) {
510 			warning("Could not create a resolver structure");
511 			result = EXIT_FAILURE;
512 			goto exit;
513 		}
514 		/* add the nameserver */
515 		serv_rdf = ldns_rdf_new_addr_frm_str(serv);
516 		if (!serv_rdf) {
517 			/* try to resolv the name if possible */
518 			status = ldns_resolver_new_frm_file(&cmdline_res, resolv_conf_file);
519 
520 			if (status != LDNS_STATUS_OK) {
521 				error("%s", "@server ip could not be converted");
522 			}
523 			ldns_resolver_set_dnssec(cmdline_res, qdnssec);
524 			ldns_resolver_set_ip6(cmdline_res, qfamily);
525 			ldns_resolver_set_fallback(cmdline_res, qfallback);
526 			ldns_resolver_set_usevc(cmdline_res, qusevc);
527 			ldns_resolver_set_source(cmdline_res, src_rdf);
528 
529 			cmdline_dname = ldns_dname_new_frm_str(serv);
530 
531 			cmdline_rr_list = ldns_get_rr_list_addr_by_name(
532 						cmdline_res,
533 						cmdline_dname,
534 						LDNS_RR_CLASS_IN,
535 						qflags);
536 			ldns_rdf_deep_free(cmdline_dname);
537 			if (!cmdline_rr_list) {
538 				/* This error msg is not always accurate */
539 				error("%s `%s\'", "could not find any address for the name:", serv);
540 			} else {
541 				if (ldns_resolver_push_nameserver_rr_list(
542 						res,
543 						cmdline_rr_list
544 					) != LDNS_STATUS_OK) {
545 					error("%s", "pushing nameserver");
546 				}
547 			}
548 		} else {
549 			if (ldns_resolver_push_nameserver(res, serv_rdf) != LDNS_STATUS_OK) {
550 				error("%s", "pushing nameserver");
551 			} else {
552 				ldns_rdf_deep_free(serv_rdf);
553 			}
554 		}
555 	}
556 	/* set the resolver options */
557 	ldns_resolver_set_port(res, qport);
558 	ldns_resolver_set_source(res, src_rdf);
559 	if (verbosity >= 5) {
560 		ldns_resolver_set_debug(res, true);
561 	} else {
562 		ldns_resolver_set_debug(res, false);
563 	}
564 	ldns_resolver_set_dnssec(res, qdnssec);
565 /*	ldns_resolver_set_dnssec_cd(res, qdnssec);*/
566 	ldns_resolver_set_ip6(res, qfamily);
567 	ldns_resolver_set_fallback(res, qfallback);
568 	ldns_resolver_set_usevc(res, qusevc);
569 	ldns_resolver_set_random(res, qrandom);
570 	if (qbuf != 0) {
571 		ldns_resolver_set_edns_udp_size(res, qbuf);
572 	}
573 
574 	if (!name &&
575 	    PURPOSE != DRILL_AFROMFILE &&
576 	    !query_file
577 	   ) {
578 		usage(stdout, progname);
579 		result = EXIT_FAILURE;
580 		goto exit;
581 	}
582 
583 	if (tsig_name && tsig_data) {
584 		ldns_resolver_set_tsig_keyname(res, tsig_name);
585 		ldns_resolver_set_tsig_keydata(res, tsig_data);
586 		ldns_resolver_set_tsig_algorithm(res, tsig_algorithm);
587 	}
588 
589 	/* main switching part of drill */
590 	switch(PURPOSE) {
591 		case DRILL_TRACE:
592 			/* do a trace from the root down */
593 			if (!global_dns_root) {
594 				init_root();
595 			}
596 			qname = ldns_dname_new_frm_str(name);
597 			if (!qname) {
598 				error("%s", "parsing query name");
599 			}
600 			/* don't care about return packet */
601 			(void)do_trace(res, qname, type, clas);
602 			clear_root();
603 			break;
604 		case DRILL_SECTRACE:
605 			/* do a secure trace from the root down */
606 			if (!global_dns_root) {
607 				init_root();
608 			}
609 			qname = ldns_dname_new_frm_str(name);
610 			if (!qname) {
611 				error("%s", "making qname");
612 			}
613 			/* don't care about return packet */
614 #ifdef HAVE_SSL
615 			result = do_secure_trace(res, qname, type, clas, key_list, trace_start_name);
616 #endif /* HAVE_SSL */
617 			clear_root();
618 			break;
619 		case DRILL_CHASE:
620 			qname = ldns_dname_new_frm_str(name);
621 			if (!qname) {
622 				error("%s", "making qname");
623 			}
624 
625 			ldns_resolver_set_dnssec(res, true);
626 			ldns_resolver_set_dnssec_cd(res, true);
627 			/* set dnssec implies udp_size of 4096 */
628 			ldns_resolver_set_edns_udp_size(res, 4096);
629 			pkt = NULL;
630 			status = ldns_resolver_query_status(
631 					&pkt, res, qname, type, clas, qflags);
632 			if (status != LDNS_STATUS_OK) {
633 				error("error sending query: %s",
634 					ldns_get_errorstr_by_id(status));
635 			}
636 			if (!pkt) {
637 				if (status == LDNS_STATUS_OK) {
638 					error("%s", "error pkt sending");
639 				}
640 				result = EXIT_FAILURE;
641 			} else {
642 				if (verbosity >= 3) {
643 					ldns_pkt_print(stdout, pkt);
644 				}
645 
646 				if (!ldns_pkt_answer(pkt)) {
647 					mesg("No answer in packet");
648 				} else {
649 #ifdef HAVE_SSL
650 					ldns_resolver_set_dnssec_anchors(res, ldns_rr_list_clone(key_list));
651 					result = do_chase(res, qname, type,
652 					                  clas, key_list,
653 					                  pkt, qflags, NULL,
654 								   verbosity);
655 					if (result == LDNS_STATUS_OK) {
656 						if (verbosity != -1) {
657 							mesg("Chase successful");
658 						}
659 						result = 0;
660 					} else {
661 						if (verbosity != -1) {
662 							mesg("Chase failed.");
663 						}
664 					}
665 #endif /* HAVE_SSL */
666 				}
667 				ldns_pkt_free(pkt);
668 			}
669 			break;
670 		case DRILL_AFROMFILE:
671 			pkt = read_hex_pkt(answer_file);
672 			if (pkt) {
673 				if (verbosity != -1) {
674 					ldns_pkt_print(stdout, pkt);
675 				}
676 				ldns_pkt_free(pkt);
677 			}
678 
679 			break;
680 		case DRILL_QTOFILE:
681 			qname = ldns_dname_new_frm_str(name);
682 			if (!qname) {
683 				error("%s", "making qname");
684 			}
685 
686 			status = ldns_resolver_prepare_query_pkt(&qpkt, res, qname, type, clas, qflags);
687 			if(status != LDNS_STATUS_OK) {
688 				error("%s", "making query: %s",
689 					ldns_get_errorstr_by_id(status));
690 			}
691 			dump_hex(qpkt, query_file);
692 			ldns_pkt_free(qpkt);
693 			break;
694 		case DRILL_NSEC:
695 			break;
696 		case DRILL_REVERSE:
697 			/* ipv4 or ipv6 addr? */
698 			if (strchr(name, ':')) {
699 				if (strchr(name, '.')) {
700 					error("Syntax error: both '.' and ':' seen in address\n");
701 				}
702 				name2 = malloc(IP6_ARPA_MAX_LEN + 20);
703 				c = 0;
704 				for (i=0; i<(int)strlen(name); i++) {
705 					if (i >= IP6_ARPA_MAX_LEN) {
706 						error("%s", "reverse argument to long");
707 					}
708 					if (name[i] == ':') {
709 						if (i < (int) strlen(name) && name[i + 1] == ':') {
710 							error("%s", ":: not supported (yet)");
711 						} else {
712 							if (i + 2 == (int) strlen(name) || name[i + 2] == ':') {
713 								name2[c++] = '0';
714 								name2[c++] = '.';
715 								name2[c++] = '0';
716 								name2[c++] = '.';
717 								name2[c++] = '0';
718 								name2[c++] = '.';
719 							} else if (i + 3 == (int) strlen(name) || name[i + 3] == ':') {
720 								name2[c++] = '0';
721 								name2[c++] = '.';
722 								name2[c++] = '0';
723 								name2[c++] = '.';
724 							} else if (i + 4 == (int) strlen(name) || name[i + 4] == ':') {
725 								name2[c++] = '0';
726 								name2[c++] = '.';
727 							}
728 						}
729 					} else {
730 						name2[c++] = name[i];
731 						name2[c++] = '.';
732 					}
733 				}
734 				name2[c++] = '\0';
735 
736 				qname = ldns_dname_new_frm_str(name2);
737 				qname_tmp = ldns_dname_reverse(qname);
738 				ldns_rdf_deep_free(qname);
739 				qname = qname_tmp;
740 				qname_tmp = ldns_dname_new_frm_str("ip6.arpa.");
741 				status = ldns_dname_cat(qname, qname_tmp);
742 				if (status != LDNS_STATUS_OK) {
743 					error("%s", "could not create reverse address for ip6: %s\n", ldns_get_errorstr_by_id(status));
744 				}
745 				ldns_rdf_deep_free(qname_tmp);
746 
747 				free(name2);
748 			} else {
749 				qname = ldns_dname_new_frm_str(name);
750 				qname_tmp = ldns_dname_reverse(qname);
751 				ldns_rdf_deep_free(qname);
752 				qname = qname_tmp;
753 				qname_tmp = ldns_dname_new_frm_str("in-addr.arpa.");
754 				status = ldns_dname_cat(qname, qname_tmp);
755 				if (status != LDNS_STATUS_OK) {
756 					error("%s", "could not create reverse address for ip4: %s\n", ldns_get_errorstr_by_id(status));
757 				}
758 				ldns_rdf_deep_free(qname_tmp);
759 			}
760 			if (!qname) {
761 				error("%s", "-x implies an ip address");
762 			}
763 
764 			/* create a packet and set the RD flag on it */
765 			pkt = NULL;
766 			status = ldns_resolver_query_status(
767 					&pkt, res, qname, type, clas, qflags);
768 			if (status != LDNS_STATUS_OK) {
769 				error("error sending query: %s",
770 					ldns_get_errorstr_by_id(status));
771 			}
772 			if (!pkt)  {
773 				if (status == LDNS_STATUS_OK) {
774 					error("%s", "pkt sending");
775 				}
776 				result = EXIT_FAILURE;
777 			} else {
778 				if (verbosity != -1) {
779 					ldns_pkt_print(stdout, pkt);
780 				}
781 				ldns_pkt_free(pkt);
782 			}
783 			break;
784 		case DRILL_QUERY:
785 		default:
786 			if (query_file) {
787 				/* this old way, the query packet needed
788 				   to be parseable, but we want to be able
789 				   to send mangled packets, so we need
790 				   to do it directly */
791 				#if 0
792 				qpkt = read_hex_pkt(query_file);
793 				if (qpkt) {
794 					status = ldns_resolver_send_pkt(&pkt, res, qpkt);
795 					if (status != LDNS_STATUS_OK) {
796 						printf("Error: %s\n", ldns_get_errorstr_by_id(status));
797 						exit(1);
798 					}
799 				} else {
800 					/* qpkt was bogus, reset pkt */
801 					pkt = NULL;
802 				}
803 				#endif
804 				query_buffer = read_hex_buffer(query_file);
805 				if (query_buffer) {
806 					status = ldns_send_buffer(&pkt, res, query_buffer, NULL);
807 					ldns_buffer_free(query_buffer);
808 					if (status != LDNS_STATUS_OK) {
809 						printf("Error: %s\n", ldns_get_errorstr_by_id(status));
810 						exit(1);
811 					}
812 				} else {
813 					printf("NO BUFFER\n");
814 					pkt = NULL;
815 				}
816 			} else {
817 				qname = ldns_dname_new_frm_str(name);
818 				if (!qname) {
819 					error("%s", "error in making qname");
820 				}
821 
822 				if (type == LDNS_RR_TYPE_AXFR) {
823 					status = ldns_axfr_start(res, qname, clas);
824 					if(status != LDNS_STATUS_OK) {
825 						error("Error starting axfr: %s",
826 							ldns_get_errorstr_by_id(status));
827 					}
828 					axfr_rr = ldns_axfr_next(res);
829 					if(!axfr_rr) {
830 						fprintf(stderr, "AXFR failed.\n");
831 						ldns_pkt_print(stdout,
832 							ldns_axfr_last_pkt(res));
833 						goto exit;
834 					}
835 					while (axfr_rr) {
836 						if (verbosity != -1) {
837 							ldns_rr_print(stdout, axfr_rr);
838 						}
839 						ldns_rr_free(axfr_rr);
840 						axfr_rr = ldns_axfr_next(res);
841 					}
842 
843 					goto exit;
844 				} else {
845 					/* create a packet and set the RD flag on it */
846 					pkt = NULL;
847 					status = ldns_resolver_query_status(
848 							&pkt, res, qname,
849 							type, clas, qflags);
850 					if (status != LDNS_STATUS_OK) {
851 						error("error sending query: %s"
852 						     , ldns_get_errorstr_by_id(
853 							     status));
854 					}
855 				}
856 			}
857 
858 			if (!pkt)  {
859 				mesg("No packet received");
860 				result = EXIT_FAILURE;
861 			} else {
862 				if (verbosity != -1) {
863 					ldns_pkt_print(stdout, pkt);
864 					if (ldns_pkt_tc(pkt)) {
865 						fprintf(stdout,
866 							"\n;; WARNING: The answer packet was truncated; you might want to\n");
867 						fprintf(stdout,
868 							";; query again with TCP (-t argument), or EDNS0 (-b for buffer size)\n");
869 					}
870 				}
871 				if (qds) {
872 					if (verbosity != -1) {
873 						print_ds_of_keys(pkt);
874 						printf("\n");
875 					}
876 				}
877 
878 				if (ldns_rr_list_rr_count(key_list) > 0) {
879 					/* -k's were given on the cmd line */
880 					ldns_rr_list *rrset_verified;
881 					uint16_t key_count;
882 
883 					rrset_verified = ldns_pkt_rr_list_by_name_and_type(
884 							pkt, qname, type,
885 							LDNS_SECTION_ANY_NOQUESTION);
886 
887 					if (type == LDNS_RR_TYPE_ANY) {
888 						/* don't verify this */
889 						break;
890 					}
891 
892 					if (verbosity != -1) {
893 						printf("; ");
894 						ldns_rr_list_print(stdout, rrset_verified);
895 					}
896 
897 					/* verify */
898 #ifdef HAVE_SSL
899 					key_verified = ldns_rr_list_new();
900 					result = ldns_pkt_verify(pkt, type, qname, key_list, NULL, key_verified);
901 
902 					if (result == LDNS_STATUS_ERR) {
903 						/* is the existence denied then? */
904 						result = ldns_verify_denial(pkt, qname, type, NULL, NULL);
905 						if (result == LDNS_STATUS_OK) {
906 							if (verbosity != -1) {
907 								printf("Existence denied for ");
908 								ldns_rdf_print(stdout, qname);
909 								type_str = ldns_rr_type2str(type);
910 								printf("\t%s\n", type_str);
911 								LDNS_FREE(type_str);
912 							}
913 						} else {
914 							if (verbosity != -1) {
915 								printf("Bad data; RR for name and "
916 								       "type not found or failed to "
917 								       "verify, and denial of "
918 								       "existence failed.\n");
919 							}
920 						}
921 					} else if (result == LDNS_STATUS_OK) {
922 						for(key_count = 0; key_count < ldns_rr_list_rr_count(key_verified);
923 								key_count++) {
924 							if (verbosity != -1) {
925 								printf("; VALIDATED by id = %u, owner = ",
926 										(unsigned int)ldns_calc_keytag(
927 												      ldns_rr_list_rr(key_verified, key_count)));
928 								ldns_rdf_print(stdout, ldns_rr_owner(
929 											ldns_rr_list_rr(key_list, key_count)));
930 								printf("\n");
931 							}
932 						}
933 					} else {
934 						for(key_count = 0; key_count < ldns_rr_list_rr_count(key_list);
935 								key_count++) {
936 							if (verbosity != -1) {
937 								printf("; %s for id = %u, owner = ",
938 								       ldns_get_errorstr_by_id(result),
939 								       (unsigned int)ldns_calc_keytag(
940 												      ldns_rr_list_rr(key_list, key_count)));
941 								ldns_rdf_print(stdout, ldns_rr_owner(
942 
943 								ldns_rr_list_rr(key_list,
944 								key_count)));
945 								printf("\n");
946 							}
947 						}
948 					}
949 					ldns_rr_list_free(key_verified);
950 #else
951 					(void) key_count;
952 #endif /* HAVE_SSL */
953 				}
954 				if (answer_file) {
955 					dump_hex(pkt, answer_file);
956 				}
957 				ldns_pkt_free(pkt);
958 			}
959 
960 			break;
961 	}
962 
963 	exit:
964 	ldns_rdf_deep_free(qname);
965 	ldns_rdf_deep_free(src_rdf);
966 	ldns_resolver_deep_free(res);
967 	ldns_resolver_deep_free(cmdline_res);
968 	ldns_rr_list_deep_free(key_list);
969 	ldns_rr_list_deep_free(cmdline_rr_list);
970 	ldns_rdf_deep_free(trace_start_name);
971 	xfree(progname);
972 	xfree(tsig_name);
973 	xfree(tsig_data);
974 	xfree(tsig_algorithm);
975 
976 #ifdef HAVE_SSL
977 	ERR_remove_state(0);
978 	CRYPTO_cleanup_all_ex_data();
979 	ERR_free_strings();
980 	EVP_cleanup();
981 #endif
982 #ifdef USE_WINSOCK
983 	WSACleanup();
984 #endif
985 
986 	return result;
987 }
988