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