1238104Sdes/*
2238104Sdes * drill.c
3238104Sdes * the main file of drill
4238104Sdes * (c) 2005-2008 NLnet Labs
5238104Sdes *
6238104Sdes * See the file LICENSE for the license
7238104Sdes *
8238104Sdes */
9238104Sdes
10238104Sdes#include "drill.h"
11238104Sdes#include <ldns/ldns.h>
12238104Sdes
13238104Sdes#ifdef HAVE_SSL
14238104Sdes#include <openssl/err.h>
15238104Sdes#endif
16238104Sdes
17238104Sdes#define IP6_ARPA_MAX_LEN 65
18238104Sdes
19238104Sdes/* query debug, 2 hex dumps */
20238104Sdesint		verbosity;
21238104Sdes
22238104Sdesstatic void
23238104Sdesusage(FILE *stream, const char *progname)
24238104Sdes{
25238104Sdes	fprintf(stream, "  Usage: %s name [@server] [type] [class]\n", progname);
26238104Sdes	fprintf(stream, "\t<name>  can be a domain name or an IP address (-x lookups)\n");
27238104Sdes	fprintf(stream, "\t<type>  defaults to A\n");
28238104Sdes	fprintf(stream, "\t<class> defaults to IN\n");
29238104Sdes	fprintf(stream, "\n\targuments may be placed in random order\n");
30238104Sdes	fprintf(stream, "\n  Options:\n");
31238104Sdes	fprintf(stream, "\t-D\t\tenable DNSSEC (DO bit)\n");
32238104Sdes#ifdef HAVE_SSL
33238104Sdes	fprintf(stream, "\t-T\t\ttrace from the root down to <name>\n");
34238104Sdes	fprintf(stream, "\t-S\t\tchase signature(s) from <name> to a know key [*]\n");
35238104Sdes#endif /*HAVE_SSL*/
36269257Sdes	fprintf(stream, "\t-I <address>\tsource address to query from\n");
37238104Sdes	fprintf(stream, "\t-V <number>\tverbosity (0-5)\n");
38238104Sdes	fprintf(stream, "\t-Q\t\tquiet mode (overrules -V)\n");
39238104Sdes	fprintf(stream, "\n");
40238104Sdes	fprintf(stream, "\t-f file\t\tread packet from file and send it\n");
41238104Sdes	fprintf(stream, "\t-i file\t\tread packet from file and print it\n");
42238104Sdes	fprintf(stream, "\t-w file\t\twrite answer packet to file\n");
43238104Sdes	fprintf(stream, "\t-q file\t\twrite query packet to file\n");
44238104Sdes	fprintf(stream, "\t-h\t\tshow this help\n");
45238104Sdes	fprintf(stream, "\t-v\t\tshow version\n");
46238104Sdes	fprintf(stream, "\n  Query options:\n");
47238104Sdes	fprintf(stream, "\t-4\t\tstay on ip4\n");
48238104Sdes	fprintf(stream, "\t-6\t\tstay on ip6\n");
49238104Sdes	fprintf(stream, "\t-a\t\tfallback to EDNS0 and TCP if the answer is truncated\n");
50238104Sdes	fprintf(stream, "\t-b <bufsize>\tuse <bufsize> as the buffer size (defaults to 512 b)\n");
51246854Sdes	fprintf(stream, "\t-c <file>\tuse file for rescursive nameserver configuration"
52246854Sdes			"\n\t\t\t(/etc/resolv.conf)\n");
53246854Sdes	fprintf(stream, "\t-k <file>\tspecify a file that contains a trusted DNSSEC key [**]\n");
54246854Sdes	fprintf(stream, "\t\t\tUsed to verify any signatures in the current answer.\n");
55246854Sdes	fprintf(stream, "\t\t\tWhen DNSSEC enabled tracing (-TD) or signature\n"
56246854Sdes			"\t\t\tchasing (-S) and no key files are given, keys are read\n"
57246854Sdes			"\t\t\tfrom: %s\n",
58246854Sdes			LDNS_TRUST_ANCHOR_FILE);
59246854Sdes	fprintf(stream, "\t-o <mnemonic>\tset flags to:"
60246854Sdes			"\n\t\t\t[QR|qr][AA|aa][TC|tc][RD|rd][CD|cd][RA|ra][AD|ad]\n");
61238104Sdes	fprintf(stream, "\t\t\tlowercase: unset bit, uppercase: set bit\n");
62238104Sdes	fprintf(stream, "\t-p <port>\tuse <port> as remote port number\n");
63238104Sdes	fprintf(stream, "\t-s\t\tshow the DS RR for each key in a packet\n");
64238104Sdes	fprintf(stream, "\t-u\t\tsend the query with udp (the default)\n");
65238104Sdes	fprintf(stream, "\t-x\t\tdo a reverse lookup\n");
66238104Sdes	fprintf(stream, "\twhen doing a secure trace:\n");
67246854Sdes	fprintf(stream, "\t-r <file>\tuse file as root servers hint file\n");
68238104Sdes	fprintf(stream, "\t-t\t\tsend the query with tcp (connected)\n");
69246854Sdes	fprintf(stream, "\t-d <domain>\tuse domain as the start point for the trace\n");
70238104Sdes    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");
71238104Sdes	fprintf(stream, "\t-z\t\tdon't randomize the nameservers before use\n");
72238104Sdes	fprintf(stream, "\n  [*] = enables/implies DNSSEC\n");
73238104Sdes	fprintf(stream, "  [**] = can be given more than once\n");
74238104Sdes	fprintf(stream, "\n  ldns-team@nlnetlabs.nl | http://www.nlnetlabs.nl/ldns/\n");
75238104Sdes}
76238104Sdes
77238104Sdes/**
78238104Sdes * Prints the drill version to stderr
79238104Sdes */
80238104Sdesstatic void
81238104Sdesversion(FILE *stream, const char *progname)
82238104Sdes{
83238104Sdes        fprintf(stream, "%s version %s (ldns version %s)\n", progname, DRILL_VERSION, ldns_version());
84238104Sdes        fprintf(stream, "Written by NLnet Labs.\n");
85238104Sdes        fprintf(stream, "\nCopyright (c) 2004-2008 NLnet Labs.\n");
86238104Sdes        fprintf(stream, "Licensed under the revised BSD license.\n");
87238104Sdes        fprintf(stream, "There is NO warranty; not even for MERCHANTABILITY or FITNESS\n");
88238104Sdes        fprintf(stream, "FOR A PARTICULAR PURPOSE.\n");
89238104Sdes}
90238104Sdes
91238104Sdes
92238104Sdes/**
93238104Sdes * Main function of drill
94238104Sdes * parse the arguments and prepare a query
95238104Sdes */
96238104Sdesint
97238104Sdesmain(int argc, char *argv[])
98238104Sdes{
99238104Sdes        ldns_resolver	*res = NULL;
100238104Sdes        ldns_resolver   *cmdline_res = NULL; /* only used to resolv @name names */
101238104Sdes	ldns_rr_list	*cmdline_rr_list = NULL;
102238104Sdes	ldns_rdf	*cmdline_dname = NULL;
103238104Sdes        ldns_rdf 	*qname, *qname_tmp;
104238104Sdes        ldns_pkt	*pkt;
105238104Sdes        ldns_pkt	*qpkt;
106238104Sdes        char 		*serv;
107269257Sdes        char 		*src = NULL;
108238104Sdes        const char 	*name;
109238104Sdes        char 		*name2;
110238104Sdes	char		*progname;
111238104Sdes	char 		*query_file = NULL;
112238104Sdes	char		*answer_file = NULL;
113238104Sdes	ldns_buffer	*query_buffer = NULL;
114238104Sdes	ldns_rdf 	*serv_rdf;
115269257Sdes	ldns_rdf 	*src_rdf = NULL;
116238104Sdes        ldns_rr_type 	type;
117238104Sdes        ldns_rr_class	clas;
118238104Sdes#if 0
119238104Sdes	ldns_pkt_opcode opcode = LDNS_PACKET_QUERY;
120238104Sdes#endif
121238104Sdes	int 		i, c;
122238104Sdes	int 		int_type;
123238104Sdes	int		int_clas;
124238104Sdes	int		PURPOSE;
125238104Sdes	char		*tsig_name = NULL;
126238104Sdes	char		*tsig_data = NULL;
127238104Sdes	char 		*tsig_algorithm = NULL;
128238104Sdes	size_t		tsig_separator;
129238104Sdes	size_t		tsig_separator2;
130238104Sdes	ldns_rr		*axfr_rr;
131238104Sdes	ldns_status	status;
132238104Sdes	char *type_str;
133238104Sdes
134238104Sdes	/* list of keys used in dnssec operations */
135238104Sdes	ldns_rr_list	*key_list = ldns_rr_list_new();
136238104Sdes	/* what key verify the current answer */
137238104Sdes	ldns_rr_list 	*key_verified;
138238104Sdes
139238104Sdes	/* resolver options */
140238104Sdes	uint16_t	qflags;
141238104Sdes	uint16_t 	qbuf;
142238104Sdes	uint16_t	qport;
143238104Sdes	uint8_t		qfamily;
144238104Sdes	bool		qdnssec;
145238104Sdes	bool		qfallback;
146238104Sdes	bool		qds;
147238104Sdes	bool		qusevc;
148238104Sdes	bool 		qrandom;
149238104Sdes
150238104Sdes	char		*resolv_conf_file = NULL;
151238104Sdes
152238104Sdes	ldns_rdf *trace_start_name = NULL;
153238104Sdes
154238104Sdes	int		result = 0;
155238104Sdes
156238104Sdes#ifdef USE_WINSOCK
157238104Sdes	int r;
158238104Sdes	WSADATA wsa_data;
159238104Sdes#endif
160238104Sdes
161238104Sdes	int_type = -1; serv = NULL; type = 0;
162238104Sdes	int_clas = -1; name = NULL; clas = 0;
163269257Sdes	qname = NULL; src = NULL;
164238104Sdes	progname = strdup(argv[0]);
165238104Sdes
166238104Sdes#ifdef USE_WINSOCK
167238104Sdes	r = WSAStartup(MAKEWORD(2,2), &wsa_data);
168238104Sdes	if(r != 0) {
169238104Sdes		printf("Failed WSAStartup: %d\n", r);
170238104Sdes		result = EXIT_FAILURE;
171238104Sdes		goto exit;
172238104Sdes	}
173238104Sdes#endif /* USE_WINSOCK */
174238104Sdes
175238104Sdes
176238104Sdes	PURPOSE = DRILL_QUERY;
177238104Sdes	qflags = LDNS_RD;
178238104Sdes	qport = LDNS_PORT;
179238104Sdes	verbosity = 2;
180238104Sdes	qdnssec = false;
181238104Sdes	qfamily = LDNS_RESOLV_INETANY;
182238104Sdes	qfallback = false;
183238104Sdes	qds = false;
184238104Sdes	qbuf = 0;
185238104Sdes	qusevc = false;
186238104Sdes	qrandom = true;
187238104Sdes	key_verified = NULL;
188238104Sdes
189238104Sdes	ldns_init_random(NULL, 0);
190238104Sdes
191238104Sdes	if (argc == 0) {
192238104Sdes		usage(stdout, progname);
193238104Sdes		result = EXIT_FAILURE;
194238104Sdes		goto exit;
195238104Sdes	}
196238104Sdes
197238104Sdes	/* string from orig drill: "i:w:I46Sk:TNp:b:DsvhVcuaq:f:xr" */
198238104Sdes	/* global first, query opt next, option with parm's last
199238104Sdes	 * and sorted */ /*  "46DITSVQf:i:w:q:achuvxzy:so:p:b:k:" */
200238104Sdes
201269257Sdes	while ((c = getopt(argc, argv, "46ab:c:d:Df:hi:I:k:o:p:q:Qr:sStTuvV:w:xy:z")) != -1) {
202238104Sdes		switch(c) {
203238104Sdes			/* global options */
204238104Sdes			case '4':
205238104Sdes				qfamily = LDNS_RESOLV_INET;
206238104Sdes				break;
207238104Sdes			case '6':
208238104Sdes				qfamily = LDNS_RESOLV_INET6;
209238104Sdes				break;
210238104Sdes			case 'D':
211238104Sdes				qdnssec = true;
212238104Sdes				break;
213238104Sdes			case 'I':
214269257Sdes				src = optarg;
215238104Sdes				break;
216238104Sdes			case 'T':
217238104Sdes				if (PURPOSE == DRILL_CHASE) {
218238104Sdes					fprintf(stderr, "-T and -S cannot be used at the same time.\n");
219238104Sdes					exit(EXIT_FAILURE);
220238104Sdes				}
221238104Sdes				PURPOSE = DRILL_TRACE;
222238104Sdes				break;
223238104Sdes#ifdef HAVE_SSL
224238104Sdes			case 'S':
225238104Sdes				if (PURPOSE == DRILL_TRACE) {
226238104Sdes					fprintf(stderr, "-T and -S cannot be used at the same time.\n");
227238104Sdes					exit(EXIT_FAILURE);
228238104Sdes				}
229238104Sdes				PURPOSE = DRILL_CHASE;
230238104Sdes				break;
231238104Sdes#endif /* HAVE_SSL */
232238104Sdes			case 'V':
233238104Sdes				if (strtok(optarg, "0123456789") != NULL) {
234238104Sdes					fprintf(stderr, "-V expects an number as an argument.\n");
235238104Sdes					exit(EXIT_FAILURE);
236238104Sdes				}
237238104Sdes				verbosity = atoi(optarg);
238238104Sdes				break;
239238104Sdes			case 'Q':
240238104Sdes				verbosity = -1;
241238104Sdes				break;
242238104Sdes			case 'f':
243238104Sdes				query_file = optarg;
244238104Sdes				break;
245238104Sdes			case 'i':
246238104Sdes				answer_file = optarg;
247238104Sdes				PURPOSE = DRILL_AFROMFILE;
248238104Sdes				break;
249238104Sdes			case 'w':
250238104Sdes				answer_file = optarg;
251238104Sdes				break;
252238104Sdes			case 'q':
253238104Sdes				query_file = optarg;
254238104Sdes				PURPOSE = DRILL_QTOFILE;
255238104Sdes				break;
256238104Sdes			case 'r':
257238104Sdes				if (global_dns_root) {
258238104Sdes					fprintf(stderr, "There was already a series of root servers set\n");
259238104Sdes					exit(EXIT_FAILURE);
260238104Sdes				}
261238104Sdes				global_dns_root = read_root_hints(optarg);
262238104Sdes				if (!global_dns_root) {
263238104Sdes					fprintf(stderr, "Unable to read root hints file %s, aborting\n", optarg);
264238104Sdes					exit(EXIT_FAILURE);
265238104Sdes				}
266238104Sdes				break;
267238104Sdes			/* query options */
268238104Sdes			case 'a':
269238104Sdes				qfallback = true;
270238104Sdes				break;
271238104Sdes			case 'b':
272238104Sdes				qbuf = (uint16_t)atoi(optarg);
273238104Sdes				if (qbuf == 0) {
274238104Sdes					error("%s", "<bufsize> could not be converted");
275238104Sdes				}
276238104Sdes				break;
277238104Sdes			case 'c':
278238104Sdes				resolv_conf_file = optarg;
279238104Sdes				break;
280238104Sdes			case 't':
281238104Sdes				qusevc = true;
282238104Sdes				break;
283238104Sdes			case 'k':
284246854Sdes				status = read_key_file(optarg,
285246854Sdes						key_list, false);
286238104Sdes				if (status != LDNS_STATUS_OK) {
287238104Sdes					error("Could not parse the key file %s: %s", optarg, ldns_get_errorstr_by_id(status));
288238104Sdes				}
289238104Sdes				qdnssec = true; /* enable that too */
290238104Sdes				break;
291238104Sdes			case 'o':
292238104Sdes				/* only looks at the first hit: capital=ON, lowercase=OFF*/
293238104Sdes				if (strstr(optarg, "QR")) {
294238104Sdes					DRILL_ON(qflags, LDNS_QR);
295238104Sdes				}
296238104Sdes				if (strstr(optarg, "qr")) {
297238104Sdes					DRILL_OFF(qflags, LDNS_QR);
298238104Sdes				}
299238104Sdes				if (strstr(optarg, "AA")) {
300238104Sdes					DRILL_ON(qflags, LDNS_AA);
301238104Sdes				}
302238104Sdes				if (strstr(optarg, "aa")) {
303238104Sdes					DRILL_OFF(qflags, LDNS_AA);
304238104Sdes				}
305238104Sdes				if (strstr(optarg, "TC")) {
306238104Sdes					DRILL_ON(qflags, LDNS_TC);
307238104Sdes				}
308238104Sdes				if (strstr(optarg, "tc")) {
309238104Sdes					DRILL_OFF(qflags, LDNS_TC);
310238104Sdes				}
311238104Sdes				if (strstr(optarg, "RD")) {
312238104Sdes					DRILL_ON(qflags, LDNS_RD);
313238104Sdes				}
314238104Sdes				if (strstr(optarg, "rd")) {
315238104Sdes					DRILL_OFF(qflags, LDNS_RD);
316238104Sdes				}
317238104Sdes				if (strstr(optarg, "CD")) {
318238104Sdes					DRILL_ON(qflags, LDNS_CD);
319238104Sdes				}
320238104Sdes				if (strstr(optarg, "cd")) {
321238104Sdes					DRILL_OFF(qflags, LDNS_CD);
322238104Sdes				}
323238104Sdes				if (strstr(optarg, "RA")) {
324238104Sdes					DRILL_ON(qflags, LDNS_RA);
325238104Sdes				}
326238104Sdes				if (strstr(optarg, "ra")) {
327238104Sdes					DRILL_OFF(qflags, LDNS_RA);
328238104Sdes				}
329238104Sdes				if (strstr(optarg, "AD")) {
330238104Sdes					DRILL_ON(qflags, LDNS_AD);
331238104Sdes				}
332238104Sdes				if (strstr(optarg, "ad")) {
333238104Sdes					DRILL_OFF(qflags, LDNS_AD);
334238104Sdes				}
335238104Sdes				break;
336238104Sdes			case 'p':
337238104Sdes				qport = (uint16_t)atoi(optarg);
338238104Sdes				if (qport == 0) {
339238104Sdes					error("%s", "<port> could not be converted");
340238104Sdes				}
341238104Sdes				break;
342238104Sdes			case 's':
343238104Sdes				qds = true;
344238104Sdes				break;
345238104Sdes			case 'u':
346238104Sdes				qusevc = false;
347238104Sdes				break;
348238104Sdes			case 'v':
349238104Sdes				version(stdout, progname);
350238104Sdes				result = EXIT_SUCCESS;
351238104Sdes				goto exit;
352238104Sdes			case 'x':
353238104Sdes				PURPOSE = DRILL_REVERSE;
354238104Sdes				break;
355238104Sdes			case 'y':
356238104Sdes#ifdef HAVE_SSL
357238104Sdes				if (strchr(optarg, ':')) {
358238104Sdes					tsig_separator = (size_t) (strchr(optarg, ':') - optarg);
359238104Sdes					if (strchr(optarg + tsig_separator + 1, ':')) {
360238104Sdes						tsig_separator2 = (size_t) (strchr(optarg + tsig_separator + 1, ':') - optarg);
361238104Sdes						tsig_algorithm = xmalloc(strlen(optarg) - tsig_separator2);
362238104Sdes						strncpy(tsig_algorithm, optarg + tsig_separator2 + 1, strlen(optarg) - tsig_separator2);
363238104Sdes						tsig_algorithm[strlen(optarg) - tsig_separator2 - 1] = '\0';
364238104Sdes					} else {
365238104Sdes						tsig_separator2 = strlen(optarg);
366238104Sdes						tsig_algorithm = xmalloc(26);
367238104Sdes						strncpy(tsig_algorithm, "hmac-md5.sig-alg.reg.int.", 25);
368238104Sdes						tsig_algorithm[25] = '\0';
369238104Sdes					}
370238104Sdes					tsig_name = xmalloc(tsig_separator + 1);
371238104Sdes					tsig_data = xmalloc(tsig_separator2 - tsig_separator);
372238104Sdes					strncpy(tsig_name, optarg, tsig_separator);
373238104Sdes					strncpy(tsig_data, optarg + tsig_separator + 1, tsig_separator2 - tsig_separator - 1);
374238104Sdes					/* strncpy does not append \0 if source is longer than n */
375238104Sdes					tsig_name[tsig_separator] = '\0';
376238104Sdes					tsig_data[ tsig_separator2 - tsig_separator - 1] = '\0';
377238104Sdes				}
378238104Sdes#else
379238104Sdes				fprintf(stderr, "TSIG requested, but SSL is not supported\n");
380238104Sdes				result = EXIT_FAILURE;
381238104Sdes				goto exit;
382238104Sdes#endif /* HAVE_SSL */
383238104Sdes				break;
384238104Sdes			case 'z':
385238104Sdes				qrandom = false;
386238104Sdes				break;
387238104Sdes			case 'd':
388238104Sdes				trace_start_name = ldns_dname_new_frm_str(optarg);
389238104Sdes				if (!trace_start_name) {
390238104Sdes					fprintf(stderr, "Unable to parse argument for -%c\n", c);
391238104Sdes					result = EXIT_FAILURE;
392238104Sdes					goto exit;
393238104Sdes				}
394238104Sdes				break;
395238104Sdes			case 'h':
396238104Sdes				version(stdout, progname);
397238104Sdes				usage(stdout, progname);
398238104Sdes				result = EXIT_SUCCESS;
399238104Sdes				goto exit;
400238104Sdes				break;
401238104Sdes			default:
402238104Sdes				fprintf(stderr, "Unknown argument: -%c, use -h to see usage\n", c);
403238104Sdes				result = EXIT_FAILURE;
404238104Sdes				goto exit;
405238104Sdes		}
406238104Sdes	}
407238104Sdes	argc -= optind;
408238104Sdes	argv += optind;
409238104Sdes
410246854Sdes	if ((PURPOSE == DRILL_CHASE || (PURPOSE == DRILL_TRACE && qdnssec)) &&
411246854Sdes			ldns_rr_list_rr_count(key_list) == 0) {
412246854Sdes
413246854Sdes		(void) read_key_file(LDNS_TRUST_ANCHOR_FILE, key_list, true);
414246854Sdes	}
415246854Sdes	if (ldns_rr_list_rr_count(key_list) > 0) {
416246854Sdes		printf(";; Number of trusted keys: %d\n",
417246854Sdes				(int) ldns_rr_list_rr_count(key_list));
418246854Sdes	}
419238104Sdes	/* do a secure trace when requested */
420238104Sdes	if (PURPOSE == DRILL_TRACE && qdnssec) {
421238104Sdes#ifdef HAVE_SSL
422238104Sdes		if (ldns_rr_list_rr_count(key_list) == 0) {
423238104Sdes			warning("%s", "No trusted keys were given. Will not be able to verify authenticity!");
424238104Sdes		}
425238104Sdes		PURPOSE = DRILL_SECTRACE;
426238104Sdes#else
427238104Sdes		fprintf(stderr, "ldns has not been compiled with OpenSSL support. Secure trace not available\n");
428238104Sdes		exit(1);
429238104Sdes#endif /* HAVE_SSL */
430238104Sdes	}
431238104Sdes
432238104Sdes	/* parse the arguments, with multiple arguments, the last argument
433238104Sdes	 * found is used */
434238104Sdes	for(i = 0; i < argc; i++) {
435238104Sdes
436238104Sdes		/* if ^@ then it's a server */
437238104Sdes		if (argv[i][0] == '@') {
438238104Sdes			if (strlen(argv[i]) == 1) {
439238104Sdes				warning("%s", "No nameserver given");
440238104Sdes				exit(EXIT_FAILURE);
441238104Sdes			}
442238104Sdes			serv = argv[i] + 1;
443238104Sdes			continue;
444238104Sdes		}
445238104Sdes		/* if has a dot, it's a name */
446238104Sdes		if (strchr(argv[i], '.')) {
447238104Sdes			name = argv[i];
448238104Sdes			continue;
449238104Sdes		}
450238104Sdes		/* if it matches a type, it's a type */
451238104Sdes		if (int_type == -1) {
452238104Sdes			type = ldns_get_rr_type_by_name(argv[i]);
453238104Sdes			if (type != 0) {
454238104Sdes				int_type = 0;
455238104Sdes				continue;
456238104Sdes			}
457238104Sdes		}
458238104Sdes		/* if it matches a class, it's a class */
459238104Sdes		if (int_clas == -1) {
460238104Sdes			clas = ldns_get_rr_class_by_name(argv[i]);
461238104Sdes			if (clas != 0) {
462238104Sdes				int_clas = 0;
463238104Sdes				continue;
464238104Sdes			}
465238104Sdes		}
466238104Sdes		/* it all fails assume it's a name */
467238104Sdes		name = argv[i];
468238104Sdes	}
469238104Sdes	/* act like dig and use for . NS */
470238104Sdes	if (!name) {
471238104Sdes		name = ".";
472238104Sdes		int_type = 0;
473238104Sdes		type = LDNS_RR_TYPE_NS;
474238104Sdes	}
475238104Sdes
476238104Sdes	/* defaults if not given */
477238104Sdes	if (int_clas == -1) {
478238104Sdes		clas = LDNS_RR_CLASS_IN;
479238104Sdes	}
480238104Sdes	if (int_type == -1) {
481238104Sdes		if (PURPOSE != DRILL_REVERSE) {
482238104Sdes			type = LDNS_RR_TYPE_A;
483238104Sdes		} else {
484238104Sdes			type = LDNS_RR_TYPE_PTR;
485238104Sdes		}
486238104Sdes	}
487238104Sdes
488269257Sdes	if (src) {
489269257Sdes		src_rdf = ldns_rdf_new_addr_frm_str(src);
490269257Sdes		if(!src_rdf) {
491269257Sdes			fprintf(stderr, "-I must be (or resolve) to a valid IP[v6] address.\n");
492269257Sdes			exit(EXIT_FAILURE);
493269257Sdes		}
494269257Sdes	}
495269257Sdes
496238104Sdes	/* set the nameserver to use */
497238104Sdes	if (!serv) {
498238104Sdes		/* no server given make a resolver from /etc/resolv.conf */
499238104Sdes		status = ldns_resolver_new_frm_file(&res, resolv_conf_file);
500238104Sdes		if (status != LDNS_STATUS_OK) {
501238104Sdes			warning("Could not create a resolver structure: %s (%s)\n"
502238104Sdes					"Try drill @localhost if you have a resolver running on your machine.",
503238104Sdes				    ldns_get_errorstr_by_id(status), resolv_conf_file);
504238104Sdes			result = EXIT_FAILURE;
505238104Sdes			goto exit;
506238104Sdes		}
507238104Sdes	} else {
508238104Sdes		res = ldns_resolver_new();
509238104Sdes		if (!res || strlen(serv) <= 0) {
510238104Sdes			warning("Could not create a resolver structure");
511238104Sdes			result = EXIT_FAILURE;
512238104Sdes			goto exit;
513238104Sdes		}
514238104Sdes		/* add the nameserver */
515238104Sdes		serv_rdf = ldns_rdf_new_addr_frm_str(serv);
516238104Sdes		if (!serv_rdf) {
517238104Sdes			/* try to resolv the name if possible */
518238104Sdes			status = ldns_resolver_new_frm_file(&cmdline_res, resolv_conf_file);
519238104Sdes
520238104Sdes			if (status != LDNS_STATUS_OK) {
521238104Sdes				error("%s", "@server ip could not be converted");
522238104Sdes			}
523238104Sdes			ldns_resolver_set_dnssec(cmdline_res, qdnssec);
524238104Sdes			ldns_resolver_set_ip6(cmdline_res, qfamily);
525238104Sdes			ldns_resolver_set_fallback(cmdline_res, qfallback);
526238104Sdes			ldns_resolver_set_usevc(cmdline_res, qusevc);
527269257Sdes			ldns_resolver_set_source(cmdline_res, src_rdf);
528238104Sdes
529238104Sdes			cmdline_dname = ldns_dname_new_frm_str(serv);
530238104Sdes
531238104Sdes			cmdline_rr_list = ldns_get_rr_list_addr_by_name(
532238104Sdes						cmdline_res,
533238104Sdes						cmdline_dname,
534238104Sdes						LDNS_RR_CLASS_IN,
535238104Sdes						qflags);
536238104Sdes			ldns_rdf_deep_free(cmdline_dname);
537238104Sdes			if (!cmdline_rr_list) {
538238104Sdes				/* This error msg is not always accurate */
539238104Sdes				error("%s `%s\'", "could not find any address for the name:", serv);
540238104Sdes			} else {
541238104Sdes				if (ldns_resolver_push_nameserver_rr_list(
542238104Sdes						res,
543238104Sdes						cmdline_rr_list
544238104Sdes					) != LDNS_STATUS_OK) {
545238104Sdes					error("%s", "pushing nameserver");
546238104Sdes				}
547238104Sdes			}
548238104Sdes		} else {
549238104Sdes			if (ldns_resolver_push_nameserver(res, serv_rdf) != LDNS_STATUS_OK) {
550238104Sdes				error("%s", "pushing nameserver");
551238104Sdes			} else {
552238104Sdes				ldns_rdf_deep_free(serv_rdf);
553238104Sdes			}
554238104Sdes		}
555238104Sdes	}
556238104Sdes	/* set the resolver options */
557238104Sdes	ldns_resolver_set_port(res, qport);
558269257Sdes	ldns_resolver_set_source(res, src_rdf);
559238104Sdes	if (verbosity >= 5) {
560238104Sdes		ldns_resolver_set_debug(res, true);
561238104Sdes	} else {
562238104Sdes		ldns_resolver_set_debug(res, false);
563238104Sdes	}
564238104Sdes	ldns_resolver_set_dnssec(res, qdnssec);
565238104Sdes/*	ldns_resolver_set_dnssec_cd(res, qdnssec);*/
566238104Sdes	ldns_resolver_set_ip6(res, qfamily);
567238104Sdes	ldns_resolver_set_fallback(res, qfallback);
568238104Sdes	ldns_resolver_set_usevc(res, qusevc);
569238104Sdes	ldns_resolver_set_random(res, qrandom);
570238104Sdes	if (qbuf != 0) {
571238104Sdes		ldns_resolver_set_edns_udp_size(res, qbuf);
572238104Sdes	}
573238104Sdes
574238104Sdes	if (!name &&
575238104Sdes	    PURPOSE != DRILL_AFROMFILE &&
576238104Sdes	    !query_file
577238104Sdes	   ) {
578238104Sdes		usage(stdout, progname);
579238104Sdes		result = EXIT_FAILURE;
580238104Sdes		goto exit;
581238104Sdes	}
582238104Sdes
583238104Sdes	if (tsig_name && tsig_data) {
584238104Sdes		ldns_resolver_set_tsig_keyname(res, tsig_name);
585238104Sdes		ldns_resolver_set_tsig_keydata(res, tsig_data);
586238104Sdes		ldns_resolver_set_tsig_algorithm(res, tsig_algorithm);
587238104Sdes	}
588238104Sdes
589238104Sdes	/* main switching part of drill */
590238104Sdes	switch(PURPOSE) {
591238104Sdes		case DRILL_TRACE:
592238104Sdes			/* do a trace from the root down */
593238104Sdes			if (!global_dns_root) {
594238104Sdes				init_root();
595238104Sdes			}
596238104Sdes			qname = ldns_dname_new_frm_str(name);
597238104Sdes			if (!qname) {
598238104Sdes				error("%s", "parsing query name");
599238104Sdes			}
600238104Sdes			/* don't care about return packet */
601238104Sdes			(void)do_trace(res, qname, type, clas);
602238104Sdes			clear_root();
603238104Sdes			break;
604238104Sdes		case DRILL_SECTRACE:
605238104Sdes			/* do a secure trace from the root down */
606238104Sdes			if (!global_dns_root) {
607238104Sdes				init_root();
608238104Sdes			}
609238104Sdes			qname = ldns_dname_new_frm_str(name);
610238104Sdes			if (!qname) {
611238104Sdes				error("%s", "making qname");
612238104Sdes			}
613238104Sdes			/* don't care about return packet */
614238104Sdes#ifdef HAVE_SSL
615238104Sdes			result = do_secure_trace(res, qname, type, clas, key_list, trace_start_name);
616238104Sdes#endif /* HAVE_SSL */
617238104Sdes			clear_root();
618238104Sdes			break;
619238104Sdes		case DRILL_CHASE:
620238104Sdes			qname = ldns_dname_new_frm_str(name);
621238104Sdes			if (!qname) {
622238104Sdes				error("%s", "making qname");
623238104Sdes			}
624238104Sdes
625238104Sdes			ldns_resolver_set_dnssec(res, true);
626238104Sdes			ldns_resolver_set_dnssec_cd(res, true);
627238104Sdes			/* set dnssec implies udp_size of 4096 */
628238104Sdes			ldns_resolver_set_edns_udp_size(res, 4096);
629269257Sdes			pkt = NULL;
630269257Sdes			status = ldns_resolver_query_status(
631269257Sdes					&pkt, res, qname, type, clas, qflags);
632269257Sdes			if (status != LDNS_STATUS_OK) {
633269257Sdes				error("error sending query: %s",
634269257Sdes					ldns_get_errorstr_by_id(status));
635269257Sdes			}
636238104Sdes			if (!pkt) {
637269257Sdes				if (status == LDNS_STATUS_OK) {
638269257Sdes					error("%s", "error pkt sending");
639269257Sdes				}
640238104Sdes				result = EXIT_FAILURE;
641238104Sdes			} else {
642238104Sdes				if (verbosity >= 3) {
643238104Sdes					ldns_pkt_print(stdout, pkt);
644238104Sdes				}
645238104Sdes
646238104Sdes				if (!ldns_pkt_answer(pkt)) {
647238104Sdes					mesg("No answer in packet");
648238104Sdes				} else {
649238104Sdes#ifdef HAVE_SSL
650238104Sdes					ldns_resolver_set_dnssec_anchors(res, ldns_rr_list_clone(key_list));
651238104Sdes					result = do_chase(res, qname, type,
652238104Sdes					                  clas, key_list,
653238104Sdes					                  pkt, qflags, NULL,
654238104Sdes								   verbosity);
655238104Sdes					if (result == LDNS_STATUS_OK) {
656238104Sdes						if (verbosity != -1) {
657238104Sdes							mesg("Chase successful");
658238104Sdes						}
659238104Sdes						result = 0;
660238104Sdes					} else {
661238104Sdes						if (verbosity != -1) {
662238104Sdes							mesg("Chase failed.");
663238104Sdes						}
664238104Sdes					}
665238104Sdes#endif /* HAVE_SSL */
666238104Sdes				}
667238104Sdes				ldns_pkt_free(pkt);
668238104Sdes			}
669238104Sdes			break;
670238104Sdes		case DRILL_AFROMFILE:
671238104Sdes			pkt = read_hex_pkt(answer_file);
672238104Sdes			if (pkt) {
673238104Sdes				if (verbosity != -1) {
674238104Sdes					ldns_pkt_print(stdout, pkt);
675238104Sdes				}
676238104Sdes				ldns_pkt_free(pkt);
677238104Sdes			}
678238104Sdes
679238104Sdes			break;
680238104Sdes		case DRILL_QTOFILE:
681238104Sdes			qname = ldns_dname_new_frm_str(name);
682238104Sdes			if (!qname) {
683238104Sdes				error("%s", "making qname");
684238104Sdes			}
685238104Sdes
686238104Sdes			status = ldns_resolver_prepare_query_pkt(&qpkt, res, qname, type, clas, qflags);
687238104Sdes			if(status != LDNS_STATUS_OK) {
688238104Sdes				error("%s", "making query: %s",
689238104Sdes					ldns_get_errorstr_by_id(status));
690238104Sdes			}
691238104Sdes			dump_hex(qpkt, query_file);
692238104Sdes			ldns_pkt_free(qpkt);
693238104Sdes			break;
694238104Sdes		case DRILL_NSEC:
695238104Sdes			break;
696238104Sdes		case DRILL_REVERSE:
697238104Sdes			/* ipv4 or ipv6 addr? */
698238104Sdes			if (strchr(name, ':')) {
699238104Sdes				if (strchr(name, '.')) {
700238104Sdes					error("Syntax error: both '.' and ':' seen in address\n");
701238104Sdes				}
702238104Sdes				name2 = malloc(IP6_ARPA_MAX_LEN + 20);
703238104Sdes				c = 0;
704238104Sdes				for (i=0; i<(int)strlen(name); i++) {
705238104Sdes					if (i >= IP6_ARPA_MAX_LEN) {
706238104Sdes						error("%s", "reverse argument to long");
707238104Sdes					}
708238104Sdes					if (name[i] == ':') {
709238104Sdes						if (i < (int) strlen(name) && name[i + 1] == ':') {
710238104Sdes							error("%s", ":: not supported (yet)");
711238104Sdes						} else {
712238104Sdes							if (i + 2 == (int) strlen(name) || name[i + 2] == ':') {
713238104Sdes								name2[c++] = '0';
714238104Sdes								name2[c++] = '.';
715238104Sdes								name2[c++] = '0';
716238104Sdes								name2[c++] = '.';
717238104Sdes								name2[c++] = '0';
718238104Sdes								name2[c++] = '.';
719238104Sdes							} else if (i + 3 == (int) strlen(name) || name[i + 3] == ':') {
720238104Sdes								name2[c++] = '0';
721238104Sdes								name2[c++] = '.';
722238104Sdes								name2[c++] = '0';
723238104Sdes								name2[c++] = '.';
724238104Sdes							} else if (i + 4 == (int) strlen(name) || name[i + 4] == ':') {
725238104Sdes								name2[c++] = '0';
726238104Sdes								name2[c++] = '.';
727238104Sdes							}
728238104Sdes						}
729238104Sdes					} else {
730238104Sdes						name2[c++] = name[i];
731238104Sdes						name2[c++] = '.';
732238104Sdes					}
733238104Sdes				}
734238104Sdes				name2[c++] = '\0';
735238104Sdes
736238104Sdes				qname = ldns_dname_new_frm_str(name2);
737238104Sdes				qname_tmp = ldns_dname_reverse(qname);
738238104Sdes				ldns_rdf_deep_free(qname);
739238104Sdes				qname = qname_tmp;
740238104Sdes				qname_tmp = ldns_dname_new_frm_str("ip6.arpa.");
741238104Sdes				status = ldns_dname_cat(qname, qname_tmp);
742238104Sdes				if (status != LDNS_STATUS_OK) {
743238104Sdes					error("%s", "could not create reverse address for ip6: %s\n", ldns_get_errorstr_by_id(status));
744238104Sdes				}
745238104Sdes				ldns_rdf_deep_free(qname_tmp);
746238104Sdes
747238104Sdes				free(name2);
748238104Sdes			} else {
749238104Sdes				qname = ldns_dname_new_frm_str(name);
750238104Sdes				qname_tmp = ldns_dname_reverse(qname);
751238104Sdes				ldns_rdf_deep_free(qname);
752238104Sdes				qname = qname_tmp;
753238104Sdes				qname_tmp = ldns_dname_new_frm_str("in-addr.arpa.");
754238104Sdes				status = ldns_dname_cat(qname, qname_tmp);
755238104Sdes				if (status != LDNS_STATUS_OK) {
756238104Sdes					error("%s", "could not create reverse address for ip4: %s\n", ldns_get_errorstr_by_id(status));
757238104Sdes				}
758238104Sdes				ldns_rdf_deep_free(qname_tmp);
759238104Sdes			}
760238104Sdes			if (!qname) {
761238104Sdes				error("%s", "-x implies an ip address");
762238104Sdes			}
763238104Sdes
764238104Sdes			/* create a packet and set the RD flag on it */
765269257Sdes			pkt = NULL;
766269257Sdes			status = ldns_resolver_query_status(
767269257Sdes					&pkt, res, qname, type, clas, qflags);
768269257Sdes			if (status != LDNS_STATUS_OK) {
769269257Sdes				error("error sending query: %s",
770269257Sdes					ldns_get_errorstr_by_id(status));
771269257Sdes			}
772238104Sdes			if (!pkt)  {
773269257Sdes				if (status == LDNS_STATUS_OK) {
774269257Sdes					error("%s", "pkt sending");
775269257Sdes				}
776238104Sdes				result = EXIT_FAILURE;
777238104Sdes			} else {
778238104Sdes				if (verbosity != -1) {
779238104Sdes					ldns_pkt_print(stdout, pkt);
780238104Sdes				}
781238104Sdes				ldns_pkt_free(pkt);
782238104Sdes			}
783238104Sdes			break;
784238104Sdes		case DRILL_QUERY:
785238104Sdes		default:
786238104Sdes			if (query_file) {
787238104Sdes				/* this old way, the query packet needed
788238104Sdes				   to be parseable, but we want to be able
789238104Sdes				   to send mangled packets, so we need
790238104Sdes				   to do it directly */
791238104Sdes				#if 0
792238104Sdes				qpkt = read_hex_pkt(query_file);
793238104Sdes				if (qpkt) {
794238104Sdes					status = ldns_resolver_send_pkt(&pkt, res, qpkt);
795238104Sdes					if (status != LDNS_STATUS_OK) {
796238104Sdes						printf("Error: %s\n", ldns_get_errorstr_by_id(status));
797238104Sdes						exit(1);
798238104Sdes					}
799238104Sdes				} else {
800238104Sdes					/* qpkt was bogus, reset pkt */
801238104Sdes					pkt = NULL;
802238104Sdes				}
803238104Sdes				#endif
804238104Sdes				query_buffer = read_hex_buffer(query_file);
805238104Sdes				if (query_buffer) {
806238104Sdes					status = ldns_send_buffer(&pkt, res, query_buffer, NULL);
807238104Sdes					ldns_buffer_free(query_buffer);
808238104Sdes					if (status != LDNS_STATUS_OK) {
809238104Sdes						printf("Error: %s\n", ldns_get_errorstr_by_id(status));
810238104Sdes						exit(1);
811238104Sdes					}
812238104Sdes				} else {
813238104Sdes					printf("NO BUFFER\n");
814238104Sdes					pkt = NULL;
815238104Sdes				}
816238104Sdes			} else {
817238104Sdes				qname = ldns_dname_new_frm_str(name);
818238104Sdes				if (!qname) {
819238104Sdes					error("%s", "error in making qname");
820238104Sdes				}
821238104Sdes
822238104Sdes				if (type == LDNS_RR_TYPE_AXFR) {
823238104Sdes					status = ldns_axfr_start(res, qname, clas);
824238104Sdes					if(status != LDNS_STATUS_OK) {
825238104Sdes						error("Error starting axfr: %s",
826238104Sdes							ldns_get_errorstr_by_id(status));
827238104Sdes					}
828238104Sdes					axfr_rr = ldns_axfr_next(res);
829238104Sdes					if(!axfr_rr) {
830238104Sdes						fprintf(stderr, "AXFR failed.\n");
831238104Sdes						ldns_pkt_print(stdout,
832238104Sdes							ldns_axfr_last_pkt(res));
833238104Sdes						goto exit;
834238104Sdes					}
835238104Sdes					while (axfr_rr) {
836238104Sdes						if (verbosity != -1) {
837238104Sdes							ldns_rr_print(stdout, axfr_rr);
838238104Sdes						}
839238104Sdes						ldns_rr_free(axfr_rr);
840238104Sdes						axfr_rr = ldns_axfr_next(res);
841238104Sdes					}
842238104Sdes
843238104Sdes					goto exit;
844238104Sdes				} else {
845238104Sdes					/* create a packet and set the RD flag on it */
846269257Sdes					pkt = NULL;
847269257Sdes					status = ldns_resolver_query_status(
848269257Sdes							&pkt, res, qname,
849269257Sdes							type, clas, qflags);
850269257Sdes					if (status != LDNS_STATUS_OK) {
851269257Sdes						error("error sending query: %s"
852269257Sdes						     , ldns_get_errorstr_by_id(
853269257Sdes							     status));
854269257Sdes					}
855238104Sdes				}
856238104Sdes			}
857238104Sdes
858238104Sdes			if (!pkt)  {
859238104Sdes				mesg("No packet received");
860238104Sdes				result = EXIT_FAILURE;
861238104Sdes			} else {
862238104Sdes				if (verbosity != -1) {
863238104Sdes					ldns_pkt_print(stdout, pkt);
864238104Sdes					if (ldns_pkt_tc(pkt)) {
865238104Sdes						fprintf(stdout,
866238104Sdes							"\n;; WARNING: The answer packet was truncated; you might want to\n");
867238104Sdes						fprintf(stdout,
868238104Sdes							";; query again with TCP (-t argument), or EDNS0 (-b for buffer size)\n");
869238104Sdes					}
870238104Sdes				}
871238104Sdes				if (qds) {
872238104Sdes					if (verbosity != -1) {
873238104Sdes						print_ds_of_keys(pkt);
874238104Sdes						printf("\n");
875238104Sdes					}
876238104Sdes				}
877238104Sdes
878238104Sdes				if (ldns_rr_list_rr_count(key_list) > 0) {
879238104Sdes					/* -k's were given on the cmd line */
880238104Sdes					ldns_rr_list *rrset_verified;
881238104Sdes					uint16_t key_count;
882238104Sdes
883238104Sdes					rrset_verified = ldns_pkt_rr_list_by_name_and_type(
884238104Sdes							pkt, qname, type,
885238104Sdes							LDNS_SECTION_ANY_NOQUESTION);
886238104Sdes
887238104Sdes					if (type == LDNS_RR_TYPE_ANY) {
888238104Sdes						/* don't verify this */
889238104Sdes						break;
890238104Sdes					}
891238104Sdes
892238104Sdes					if (verbosity != -1) {
893238104Sdes						printf("; ");
894238104Sdes						ldns_rr_list_print(stdout, rrset_verified);
895238104Sdes					}
896238104Sdes
897238104Sdes					/* verify */
898238104Sdes#ifdef HAVE_SSL
899238104Sdes					key_verified = ldns_rr_list_new();
900238104Sdes					result = ldns_pkt_verify(pkt, type, qname, key_list, NULL, key_verified);
901238104Sdes
902238104Sdes					if (result == LDNS_STATUS_ERR) {
903238104Sdes						/* is the existence denied then? */
904238104Sdes						result = ldns_verify_denial(pkt, qname, type, NULL, NULL);
905238104Sdes						if (result == LDNS_STATUS_OK) {
906238104Sdes							if (verbosity != -1) {
907238104Sdes								printf("Existence denied for ");
908238104Sdes								ldns_rdf_print(stdout, qname);
909238104Sdes								type_str = ldns_rr_type2str(type);
910238104Sdes								printf("\t%s\n", type_str);
911238104Sdes								LDNS_FREE(type_str);
912238104Sdes							}
913238104Sdes						} else {
914238104Sdes							if (verbosity != -1) {
915238104Sdes								printf("Bad data; RR for name and "
916238104Sdes								       "type not found or failed to "
917238104Sdes								       "verify, and denial of "
918238104Sdes								       "existence failed.\n");
919238104Sdes							}
920238104Sdes						}
921238104Sdes					} else if (result == LDNS_STATUS_OK) {
922238104Sdes						for(key_count = 0; key_count < ldns_rr_list_rr_count(key_verified);
923238104Sdes								key_count++) {
924238104Sdes							if (verbosity != -1) {
925238104Sdes								printf("; VALIDATED by id = %u, owner = ",
926238104Sdes										(unsigned int)ldns_calc_keytag(
927238104Sdes												      ldns_rr_list_rr(key_verified, key_count)));
928238104Sdes								ldns_rdf_print(stdout, ldns_rr_owner(
929238104Sdes											ldns_rr_list_rr(key_list, key_count)));
930238104Sdes								printf("\n");
931238104Sdes							}
932238104Sdes						}
933238104Sdes					} else {
934238104Sdes						for(key_count = 0; key_count < ldns_rr_list_rr_count(key_list);
935238104Sdes								key_count++) {
936238104Sdes							if (verbosity != -1) {
937238104Sdes								printf("; %s for id = %u, owner = ",
938238104Sdes								       ldns_get_errorstr_by_id(result),
939238104Sdes								       (unsigned int)ldns_calc_keytag(
940238104Sdes												      ldns_rr_list_rr(key_list, key_count)));
941238104Sdes								ldns_rdf_print(stdout, ldns_rr_owner(
942238104Sdes
943238104Sdes								ldns_rr_list_rr(key_list,
944238104Sdes								key_count)));
945238104Sdes								printf("\n");
946238104Sdes							}
947238104Sdes						}
948238104Sdes					}
949238104Sdes					ldns_rr_list_free(key_verified);
950238104Sdes#else
951238104Sdes					(void) key_count;
952238104Sdes#endif /* HAVE_SSL */
953238104Sdes				}
954238104Sdes				if (answer_file) {
955238104Sdes					dump_hex(pkt, answer_file);
956238104Sdes				}
957238104Sdes				ldns_pkt_free(pkt);
958238104Sdes			}
959238104Sdes
960238104Sdes			break;
961238104Sdes	}
962238104Sdes
963238104Sdes	exit:
964238104Sdes	ldns_rdf_deep_free(qname);
965269257Sdes	ldns_rdf_deep_free(src_rdf);
966238104Sdes	ldns_resolver_deep_free(res);
967238104Sdes	ldns_resolver_deep_free(cmdline_res);
968238104Sdes	ldns_rr_list_deep_free(key_list);
969238104Sdes	ldns_rr_list_deep_free(cmdline_rr_list);
970238104Sdes	ldns_rdf_deep_free(trace_start_name);
971238104Sdes	xfree(progname);
972238104Sdes	xfree(tsig_name);
973238104Sdes	xfree(tsig_data);
974238104Sdes	xfree(tsig_algorithm);
975238104Sdes
976238104Sdes#ifdef HAVE_SSL
977238104Sdes	ERR_remove_state(0);
978238104Sdes	CRYPTO_cleanup_all_ex_data();
979238104Sdes	ERR_free_strings();
980238104Sdes	EVP_cleanup();
981238104Sdes#endif
982238104Sdes#ifdef USE_WINSOCK
983238104Sdes	WSACleanup();
984238104Sdes#endif
985238104Sdes
986238104Sdes	return result;
987238104Sdes}
988