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