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