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