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