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