drill.c revision 269257
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 */
20int		verbosity;
21
22static void
23usage(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 */
80static void
81version(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 */
96int
97main(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