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