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 */
18int		verbosity;
19
20static int
21is_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
33static void
34usage(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 */
91static void
92version(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 */
107int
108main(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