a8f27da3d5b90a25a28f0e307f7967d5e6882c77
[tridge/bind9.git] / bin / dig / dighost.c
1 /*
2  * Copyright (C) 2004-2010  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 2000-2003  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /* $Id: dighost.c,v 1.328.22.4 2010/08/10 08:43:40 marka Exp $ */
19
20 /*! \file
21  *  \note
22  * Notice to programmers:  Do not use this code as an example of how to
23  * use the ISC library to perform DNS lookups.  Dig and Host both operate
24  * on the request level, since they allow fine-tuning of output and are
25  * intended as debugging tools.  As a result, they perform many of the
26  * functions which could be better handled using the dns_resolver
27  * functions in most applications.
28  */
29
30 #include <config.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <string.h>
34 #include <limits.h>
35
36 #ifdef HAVE_LOCALE_H
37 #include <locale.h>
38 #endif
39
40 #ifdef WITH_IDN
41 #include <idn/result.h>
42 #include <idn/log.h>
43 #include <idn/resconf.h>
44 #include <idn/api.h>
45 #endif
46
47 #include <dns/byaddr.h>
48 #ifdef DIG_SIGCHASE
49 #include <dns/dnssec.h>
50 #include <dns/ds.h>
51 #include <dns/nsec.h>
52 #include <isc/random.h>
53 #include <ctype.h>
54 #endif
55 #include <dns/fixedname.h>
56 #include <dns/log.h>
57 #include <dns/message.h>
58 #include <dns/name.h>
59 #include <dns/rdata.h>
60 #include <dns/rdataclass.h>
61 #include <dns/rdatalist.h>
62 #include <dns/rdataset.h>
63 #include <dns/rdatastruct.h>
64 #include <dns/rdatatype.h>
65 #include <dns/result.h>
66 #include <dns/tsig.h>
67
68 #include <dst/dst.h>
69
70 #include <isc/app.h>
71 #include <isc/base64.h>
72 #include <isc/entropy.h>
73 #include <isc/file.h>
74 #include <isc/lang.h>
75 #include <isc/log.h>
76 #include <isc/netaddr.h>
77 #ifdef DIG_SIGCHASE
78 #include <isc/netdb.h>
79 #endif
80 #include <isc/parseint.h>
81 #include <isc/print.h>
82 #include <isc/random.h>
83 #include <isc/result.h>
84 #include <isc/string.h>
85 #include <isc/task.h>
86 #include <isc/timer.h>
87 #include <isc/types.h>
88 #include <isc/util.h>
89
90 #include <isccfg/namedconf.h>
91
92 #include <lwres/lwres.h>
93 #include <lwres/net.h>
94
95 #include <bind9/getaddresses.h>
96
97 #include <dig/dig.h>
98
99 #if ! defined(NS_INADDRSZ)
100 #define NS_INADDRSZ      4
101 #endif
102
103 #if ! defined(NS_IN6ADDRSZ)
104 #define NS_IN6ADDRSZ    16
105 #endif
106
107 static lwres_context_t *lwctx = NULL;
108 static lwres_conf_t *lwconf;
109
110 dig_lookuplist_t lookup_list;
111 dig_serverlist_t server_list;
112 dig_searchlistlist_t search_list;
113
114 isc_boolean_t
115         check_ra = ISC_FALSE,
116         have_ipv4 = ISC_FALSE,
117         have_ipv6 = ISC_FALSE,
118         specified_source = ISC_FALSE,
119         free_now = ISC_FALSE,
120         cancel_now = ISC_FALSE,
121         usesearch = ISC_FALSE,
122         showsearch = ISC_FALSE,
123         qr = ISC_FALSE,
124         is_dst_up = ISC_FALSE;
125 in_port_t port = 53;
126 unsigned int timeout = 0;
127 unsigned int extrabytes;
128 isc_mem_t *mctx = NULL;
129 isc_log_t *lctx = NULL;
130 isc_taskmgr_t *taskmgr = NULL;
131 isc_task_t *global_task = NULL;
132 isc_timermgr_t *timermgr = NULL;
133 isc_socketmgr_t *socketmgr = NULL;
134 isc_sockaddr_t bind_address;
135 isc_sockaddr_t bind_any;
136 int sendcount = 0;
137 int recvcount = 0;
138 int sockcount = 0;
139 int ndots = -1;
140 int tries = 3;
141 int lookup_counter = 0;
142
143 #ifdef WITH_IDN
144 static void             initialize_idn(void);
145 static isc_result_t     output_filter(isc_buffer_t *buffer,
146                                       unsigned int used_org,
147                                       isc_boolean_t absolute);
148 static idn_result_t     append_textname(char *name, const char *origin,
149                                         size_t namesize);
150 static void             idn_check_result(idn_result_t r, const char *msg);
151
152 #define MAXDLEN         256
153 int  idnoptions = 0;
154 #endif
155
156 /*%
157  * Exit Codes:
158  *
159  *\li   0   Everything went well, including things like NXDOMAIN
160  *\li   1   Usage error
161  *\li   7   Got too many RR's or Names
162  *\li   8   Couldn't open batch file
163  *\li   9   No reply from server
164  *\li   10  Internal error
165  */
166 int exitcode = 0;
167 int fatalexit = 0;
168 char keynametext[MXNAME];
169 char keyfile[MXNAME] = "";
170 char keysecret[MXNAME] = "";
171 dns_name_t *hmacname = NULL;
172 unsigned int digestbits = 0;
173 isc_buffer_t *namebuf = NULL;
174 dns_tsigkey_t *key = NULL;
175 isc_boolean_t validated = ISC_TRUE;
176 isc_entropy_t *entp = NULL;
177 isc_mempool_t *commctx = NULL;
178 isc_boolean_t debugging = ISC_FALSE;
179 isc_boolean_t memdebugging = ISC_FALSE;
180 char *progname = NULL;
181 isc_mutex_t lookup_lock;
182 dig_lookup_t *current_lookup = NULL;
183
184 #ifdef DIG_SIGCHASE
185
186 isc_result_t      get_trusted_key(isc_mem_t *mctx);
187 dns_rdataset_t *  sigchase_scanname(dns_rdatatype_t type,
188                                     dns_rdatatype_t covers,
189                                     isc_boolean_t *lookedup,
190                                     dns_name_t *rdata_name);
191 dns_rdataset_t *  chase_scanname_section(dns_message_t *msg,
192                                          dns_name_t *name,
193                                          dns_rdatatype_t type,
194                                          dns_rdatatype_t covers,
195                                          int section);
196 isc_result_t      advanced_rrsearch(dns_rdataset_t **rdataset,
197                                     dns_name_t *name,
198                                     dns_rdatatype_t type,
199                                     dns_rdatatype_t covers,
200                                     isc_boolean_t *lookedup);
201 isc_result_t      sigchase_verify_sig_key(dns_name_t *name,
202                                           dns_rdataset_t *rdataset,
203                                           dst_key_t* dnsseckey,
204                                           dns_rdataset_t *sigrdataset,
205                                           isc_mem_t *mctx);
206 isc_result_t      sigchase_verify_sig(dns_name_t *name,
207                                       dns_rdataset_t *rdataset,
208                                       dns_rdataset_t *keyrdataset,
209                                       dns_rdataset_t *sigrdataset,
210                                       isc_mem_t *mctx);
211 isc_result_t      sigchase_verify_ds(dns_name_t *name,
212                                      dns_rdataset_t *keyrdataset,
213                                      dns_rdataset_t *dsrdataset,
214                                      isc_mem_t *mctx);
215 void              sigchase(dns_message_t *msg);
216 void              print_rdata(dns_rdata_t *rdata, isc_mem_t *mctx);
217 void              print_rdataset(dns_name_t *name,
218                                  dns_rdataset_t *rdataset, isc_mem_t *mctx);
219 void              dup_name(dns_name_t *source, dns_name_t* target,
220                            isc_mem_t *mctx);
221 void              free_name(dns_name_t *name, isc_mem_t *mctx);
222 void              dump_database(void);
223 void              dump_database_section(dns_message_t *msg, int section);
224 dns_rdataset_t *  search_type(dns_name_t *name, dns_rdatatype_t type,
225                               dns_rdatatype_t covers);
226 isc_result_t      contains_trusted_key(dns_name_t *name,
227                                        dns_rdataset_t *rdataset,
228                                        dns_rdataset_t *sigrdataset,
229                                        isc_mem_t *mctx);
230 void              print_type(dns_rdatatype_t type);
231 isc_result_t      prove_nx_domain(dns_message_t * msg,
232                                   dns_name_t * name,
233                                   dns_name_t * rdata_name,
234                                   dns_rdataset_t ** rdataset,
235                                   dns_rdataset_t ** sigrdataset);
236 isc_result_t      prove_nx_type(dns_message_t * msg, dns_name_t *name,
237                                 dns_rdataset_t *nsec,
238                                 dns_rdataclass_t class,
239                                 dns_rdatatype_t type,
240                                 dns_name_t * rdata_name,
241                                 dns_rdataset_t ** rdataset,
242                                 dns_rdataset_t ** sigrdataset);
243 isc_result_t      prove_nx(dns_message_t * msg, dns_name_t * name,
244                            dns_rdataclass_t class,
245                            dns_rdatatype_t type,
246                            dns_name_t * rdata_name,
247                            dns_rdataset_t ** rdataset,
248                            dns_rdataset_t ** sigrdataset);
249 static void       nameFromString(const char *str, dns_name_t *p_ret);
250 int               inf_name(dns_name_t * name1, dns_name_t * name2);
251 isc_result_t      opentmpkey(isc_mem_t *mctx, const char *file,
252                              char **tempp, FILE **fp);
253 isc_result_t      removetmpkey(isc_mem_t *mctx, const char *file);
254 void              clean_trustedkey(void);
255 void              insert_trustedkey(dst_key_t  * key);
256 #if DIG_SIGCHASE_BU
257 isc_result_t      getneededrr(dns_message_t *msg);
258 void              sigchase_bottom_up(dns_message_t *msg);
259 void              sigchase_bu(dns_message_t *msg);
260 #endif
261 #if DIG_SIGCHASE_TD
262 isc_result_t      initialization(dns_name_t *name);
263 isc_result_t      prepare_lookup(dns_name_t *name);
264 isc_result_t      grandfather_pb_test(dns_name_t * zone_name,
265                                       dns_rdataset_t *sigrdataset);
266 isc_result_t      child_of_zone(dns_name_t *name,
267                                 dns_name_t *zone_name,
268                                 dns_name_t *child_name);
269 void              sigchase_td(dns_message_t *msg);
270 #endif
271 char trustedkey[MXNAME] = "";
272
273 dns_rdataset_t *chase_rdataset = NULL;
274 dns_rdataset_t *chase_sigrdataset = NULL;
275 dns_rdataset_t *chase_dsrdataset = NULL;
276 dns_rdataset_t *chase_sigdsrdataset = NULL;
277 dns_rdataset_t *chase_keyrdataset = NULL;
278 dns_rdataset_t *chase_sigkeyrdataset = NULL;
279 dns_rdataset_t *chase_nsrdataset = NULL;
280
281 dns_name_t chase_name; /* the query name */
282 #if DIG_SIGCHASE_TD
283 /*
284  * the current name is the parent name when we follow delegation
285  */
286 dns_name_t chase_current_name;
287 /*
288  * the child name is used for delegation (NS DS responses in AUTHORITY section)
289  */
290 dns_name_t chase_authority_name;
291 #endif
292 #if DIG_SIGCHASE_BU
293 dns_name_t chase_signame;
294 #endif
295
296
297 isc_boolean_t chase_siglookedup = ISC_FALSE;
298 isc_boolean_t chase_keylookedup = ISC_FALSE;
299 isc_boolean_t chase_sigkeylookedup = ISC_FALSE;
300 isc_boolean_t chase_dslookedup = ISC_FALSE;
301 isc_boolean_t chase_sigdslookedup = ISC_FALSE;
302 #if DIG_SIGCHASE_TD
303 isc_boolean_t chase_nslookedup = ISC_FALSE;
304 isc_boolean_t chase_lookedup = ISC_FALSE;
305
306
307 isc_boolean_t delegation_follow = ISC_FALSE;
308 isc_boolean_t grandfather_pb = ISC_FALSE;
309 isc_boolean_t have_response = ISC_FALSE;
310 isc_boolean_t have_delegation_ns = ISC_FALSE;
311 dns_message_t * error_message = NULL;
312 #endif
313
314 isc_boolean_t dsvalidating = ISC_FALSE;
315 isc_boolean_t chase_name_dup = ISC_FALSE;
316
317 ISC_LIST(dig_message_t) chase_message_list;
318 ISC_LIST(dig_message_t) chase_message_list2;
319
320
321 #define MAX_TRUSTED_KEY 5
322 typedef struct struct_trusted_key_list {
323         dst_key_t * key[MAX_TRUSTED_KEY];
324         int nb_tk;
325 } struct_tk_list;
326
327 struct_tk_list tk_list = { {NULL, NULL, NULL, NULL, NULL}, 0};
328
329 #endif
330
331 #define DIG_MAX_ADDRESSES 20
332
333 /*%
334  * Apply and clear locks at the event level in global task.
335  * Can I get rid of these using shutdown events?  XXX
336  */
337 #define LOCK_LOOKUP {\
338         debug("lock_lookup %s:%d", __FILE__, __LINE__);\
339         check_result(isc_mutex_lock((&lookup_lock)), "isc_mutex_lock");\
340         debug("success");\
341 }
342 #define UNLOCK_LOOKUP {\
343         debug("unlock_lookup %s:%d", __FILE__, __LINE__);\
344         check_result(isc_mutex_unlock((&lookup_lock)),\
345                      "isc_mutex_unlock");\
346 }
347
348 static void
349 cancel_lookup(dig_lookup_t *lookup);
350
351 static void
352 recv_done(isc_task_t *task, isc_event_t *event);
353
354 static void
355 send_udp(dig_query_t *query);
356
357 static void
358 connect_timeout(isc_task_t *task, isc_event_t *event);
359
360 static void
361 launch_next_query(dig_query_t *query, isc_boolean_t include_question);
362
363
364 static void *
365 mem_alloc(void *arg, size_t size) {
366         return (isc_mem_get(arg, size));
367 }
368
369 static void
370 mem_free(void *arg, void *mem, size_t size) {
371         isc_mem_put(arg, mem, size);
372 }
373
374 char *
375 next_token(char **stringp, const char *delim) {
376         char *res;
377
378         do {
379                 res = strsep(stringp, delim);
380                 if (res == NULL)
381                         break;
382         } while (*res == '\0');
383         return (res);
384 }
385
386 static int
387 count_dots(char *string) {
388         char *s;
389         int i = 0;
390
391         s = string;
392         while (*s != '\0') {
393                 if (*s == '.')
394                         i++;
395                 s++;
396         }
397         return (i);
398 }
399
400 static void
401 hex_dump(isc_buffer_t *b) {
402         unsigned int len, i;
403         isc_region_t r;
404
405         isc_buffer_usedregion(b, &r);
406
407         printf("%d bytes\n", r.length);
408         for (len = 0; len < r.length; len++) {
409                 printf("%02x ", r.base[len]);
410                 if (len % 16 == 15) {
411                         fputs("         ", stdout);
412                         for (i = len - 15; i <= len; i++) {
413                                 if (r.base[i] >= '!' && r.base[i] <= '}')
414                                         putchar(r.base[i]);
415                                 else
416                                         putchar('.');
417                         }
418                         printf("\n");
419                 }
420         }
421         if (len % 16 != 0) {
422                 for (i = len; (i % 16) != 0; i++)
423                         fputs("   ", stdout);
424                 fputs("         ", stdout);
425                 for (i = ((len>>4)<<4); i < len; i++) {
426                         if (r.base[i] >= '!' && r.base[i] <= '}')
427                                 putchar(r.base[i]);
428                         else
429                                 putchar('.');
430                 }
431                 printf("\n");
432         }
433 }
434
435 /*%
436  * Append 'len' bytes of 'text' at '*p', failing with
437  * ISC_R_NOSPACE if that would advance p past 'end'.
438  */
439 static isc_result_t
440 append(const char *text, int len, char **p, char *end) {
441         if (len > end - *p)
442                 return (ISC_R_NOSPACE);
443         memcpy(*p, text, len);
444         *p += len;
445         return (ISC_R_SUCCESS);
446 }
447
448 static isc_result_t
449 reverse_octets(const char *in, char **p, char *end) {
450         char *dot = strchr(in, '.');
451         int len;
452         if (dot != NULL) {
453                 isc_result_t result;
454                 result = reverse_octets(dot + 1, p, end);
455                 if (result != ISC_R_SUCCESS)
456                         return (result);
457                 result = append(".", 1, p, end);
458                 if (result != ISC_R_SUCCESS)
459                         return (result);
460                 len = dot - in;
461         } else {
462                 len = strlen(in);
463         }
464         return (append(in, len, p, end));
465 }
466
467 isc_result_t
468 get_reverse(char *reverse, size_t len, char *value, isc_boolean_t ip6_int,
469             isc_boolean_t strict)
470 {
471         int r;
472         isc_result_t result;
473         isc_netaddr_t addr;
474
475         addr.family = AF_INET6;
476         r = inet_pton(AF_INET6, value, &addr.type.in6);
477         if (r > 0) {
478                 /* This is a valid IPv6 address. */
479                 dns_fixedname_t fname;
480                 dns_name_t *name;
481                 unsigned int options = 0;
482
483                 if (ip6_int)
484                         options |= DNS_BYADDROPT_IPV6INT;
485                 dns_fixedname_init(&fname);
486                 name = dns_fixedname_name(&fname);
487                 result = dns_byaddr_createptrname2(&addr, options, name);
488                 if (result != ISC_R_SUCCESS)
489                         return (result);
490                 dns_name_format(name, reverse, len);
491                 return (ISC_R_SUCCESS);
492         } else {
493                 /*
494                  * Not a valid IPv6 address.  Assume IPv4.
495                  * If 'strict' is not set, construct the
496                  * in-addr.arpa name by blindly reversing
497                  * octets whether or not they look like integers,
498                  * so that this can be used for RFC2317 names
499                  * and such.
500                  */
501                 char *p = reverse;
502                 char *end = reverse + len;
503                 if (strict && inet_pton(AF_INET, value, &addr.type.in) != 1)
504                         return (DNS_R_BADDOTTEDQUAD);
505                 result = reverse_octets(value, &p, end);
506                 if (result != ISC_R_SUCCESS)
507                         return (result);
508                 /* Append .in-addr.arpa. and a terminating NUL. */
509                 result = append(".in-addr.arpa.", 15, &p, end);
510                 if (result != ISC_R_SUCCESS)
511                         return (result);
512                 return (ISC_R_SUCCESS);
513         }
514 }
515
516 void
517 fatal(const char *format, ...) {
518         va_list args;
519
520         fflush(stdout);
521         fprintf(stderr, "%s: ", progname);
522         va_start(args, format);
523         vfprintf(stderr, format, args);
524         va_end(args);
525         fprintf(stderr, "\n");
526         if (exitcode < 10)
527                 exitcode = 10;
528         if (fatalexit != 0)
529                 exitcode = fatalexit;
530         exit(exitcode);
531 }
532
533 void
534 debug(const char *format, ...) {
535         va_list args;
536
537         if (debugging) {
538                 fflush(stdout);
539                 va_start(args, format);
540                 vfprintf(stderr, format, args);
541                 va_end(args);
542                 fprintf(stderr, "\n");
543         }
544 }
545
546 void
547 check_result(isc_result_t result, const char *msg) {
548         if (result != ISC_R_SUCCESS) {
549                 fatal("%s: %s", msg, isc_result_totext(result));
550         }
551 }
552
553 /*%
554  * Create a server structure, which is part of the lookup structure.
555  * This is little more than a linked list of servers to query in hopes
556  * of finding the answer the user is looking for
557  */
558 dig_server_t *
559 make_server(const char *servname, const char *userarg) {
560         dig_server_t *srv;
561
562         REQUIRE(servname != NULL);
563
564         debug("make_server(%s)", servname);
565         srv = isc_mem_allocate(mctx, sizeof(struct dig_server));
566         if (srv == NULL)
567                 fatal("memory allocation failure in %s:%d",
568                       __FILE__, __LINE__);
569         strncpy(srv->servername, servname, MXNAME);
570         strncpy(srv->userarg, userarg, MXNAME);
571         srv->servername[MXNAME-1] = 0;
572         srv->userarg[MXNAME-1] = 0;
573         ISC_LINK_INIT(srv, link);
574         return (srv);
575 }
576
577 static int
578 addr2af(int lwresaddrtype)
579 {
580         int af = 0;
581
582         switch (lwresaddrtype) {
583         case LWRES_ADDRTYPE_V4:
584                 af = AF_INET;
585                 break;
586
587         case LWRES_ADDRTYPE_V6:
588                 af = AF_INET6;
589                 break;
590         }
591
592         return (af);
593 }
594
595 /*%
596  * Create a copy of the server list from the lwres configuration structure.
597  * The dest list must have already had ISC_LIST_INIT applied.
598  */
599 static void
600 copy_server_list(lwres_conf_t *confdata, dig_serverlist_t *dest) {
601         dig_server_t *newsrv;
602         char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
603         int af;
604         int i;
605
606         debug("copy_server_list()");
607         for (i = 0; i < confdata->nsnext; i++) {
608                 af = addr2af(confdata->nameservers[i].family);
609
610                 if (af == AF_INET && !have_ipv4)
611                         continue;
612                 if (af == AF_INET6 && !have_ipv6)
613                         continue;
614
615                 lwres_net_ntop(af, confdata->nameservers[i].address,
616                                    tmp, sizeof(tmp));
617                 newsrv = make_server(tmp, tmp);
618                 ISC_LINK_INIT(newsrv, link);
619                 ISC_LIST_ENQUEUE(*dest, newsrv, link);
620         }
621 }
622
623 void
624 flush_server_list(void) {
625         dig_server_t *s, *ps;
626
627         debug("flush_server_list()");
628         s = ISC_LIST_HEAD(server_list);
629         while (s != NULL) {
630                 ps = s;
631                 s = ISC_LIST_NEXT(s, link);
632                 ISC_LIST_DEQUEUE(server_list, ps, link);
633                 isc_mem_free(mctx, ps);
634         }
635 }
636
637 void
638 set_nameserver(char *opt) {
639         isc_result_t result;
640         isc_sockaddr_t sockaddrs[DIG_MAX_ADDRESSES];
641         isc_netaddr_t netaddr;
642         int count, i;
643         dig_server_t *srv;
644         char tmp[ISC_NETADDR_FORMATSIZE];
645
646         if (opt == NULL)
647                 return;
648
649         result = bind9_getaddresses(opt, 0, sockaddrs,
650                                     DIG_MAX_ADDRESSES, &count);
651         if (result != ISC_R_SUCCESS)
652                 fatal("couldn't get address for '%s': %s",
653                       opt, isc_result_totext(result));
654
655         flush_server_list();
656
657         for (i = 0; i < count; i++) {
658                 isc_netaddr_fromsockaddr(&netaddr, &sockaddrs[i]);
659                 isc_netaddr_format(&netaddr, tmp, sizeof(tmp));
660                 srv = make_server(tmp, opt);
661                 if (srv == NULL)
662                         fatal("memory allocation failure");
663                 ISC_LIST_APPEND(server_list, srv, link);
664         }
665 }
666
667 static isc_result_t
668 add_nameserver(lwres_conf_t *confdata, const char *addr, int af) {
669
670         int i = confdata->nsnext;
671
672         if (confdata->nsnext >= LWRES_CONFMAXNAMESERVERS)
673                 return (ISC_R_FAILURE);
674
675         switch (af) {
676         case AF_INET:
677                 confdata->nameservers[i].family = LWRES_ADDRTYPE_V4;
678                 confdata->nameservers[i].length = NS_INADDRSZ;
679                 break;
680         case AF_INET6:
681                 confdata->nameservers[i].family = LWRES_ADDRTYPE_V6;
682                 confdata->nameservers[i].length = NS_IN6ADDRSZ;
683                 break;
684         default:
685                 return (ISC_R_FAILURE);
686         }
687
688         if (lwres_net_pton(af, addr, &confdata->nameservers[i].address) == 1) {
689                 confdata->nsnext++;
690                 return (ISC_R_SUCCESS);
691         }
692         return (ISC_R_FAILURE);
693 }
694
695 /*%
696  * Produce a cloned server list.  The dest list must have already had
697  * ISC_LIST_INIT applied.
698  */
699 void
700 clone_server_list(dig_serverlist_t src, dig_serverlist_t *dest) {
701         dig_server_t *srv, *newsrv;
702
703         debug("clone_server_list()");
704         srv = ISC_LIST_HEAD(src);
705         while (srv != NULL) {
706                 newsrv = make_server(srv->servername, srv->userarg);
707                 ISC_LINK_INIT(newsrv, link);
708                 ISC_LIST_ENQUEUE(*dest, newsrv, link);
709                 srv = ISC_LIST_NEXT(srv, link);
710         }
711 }
712
713 /*%
714  * Create an empty lookup structure, which holds all the information needed
715  * to get an answer to a user's question.  This structure contains two
716  * linked lists: the server list (servers to query) and the query list
717  * (outstanding queries which have been made to the listed servers).
718  */
719 dig_lookup_t *
720 make_empty_lookup(void) {
721         dig_lookup_t *looknew;
722
723         debug("make_empty_lookup()");
724
725         INSIST(!free_now);
726
727         looknew = isc_mem_allocate(mctx, sizeof(struct dig_lookup));
728         if (looknew == NULL)
729                 fatal("memory allocation failure in %s:%d",
730                        __FILE__, __LINE__);
731         looknew->pending = ISC_TRUE;
732         looknew->textname[0] = 0;
733         looknew->cmdline[0] = 0;
734         looknew->rdtype = dns_rdatatype_a;
735         looknew->qrdtype = dns_rdatatype_a;
736         looknew->rdclass = dns_rdataclass_in;
737         looknew->rdtypeset = ISC_FALSE;
738         looknew->rdclassset = ISC_FALSE;
739         looknew->sendspace = NULL;
740         looknew->sendmsg = NULL;
741         looknew->name = NULL;
742         looknew->oname = NULL;
743         looknew->timer = NULL;
744         looknew->xfr_q = NULL;
745         looknew->current_query = NULL;
746         looknew->doing_xfr = ISC_FALSE;
747         looknew->ixfr_serial = ISC_FALSE;
748         looknew->trace = ISC_FALSE;
749         looknew->trace_root = ISC_FALSE;
750         looknew->identify = ISC_FALSE;
751         looknew->identify_previous_line = ISC_FALSE;
752         looknew->ignore = ISC_FALSE;
753         looknew->servfail_stops = ISC_TRUE;
754         looknew->besteffort = ISC_TRUE;
755         looknew->dnssec = ISC_FALSE;
756         looknew->nsid = ISC_FALSE;
757 #ifdef DIG_SIGCHASE
758         looknew->sigchase = ISC_FALSE;
759 #if DIG_SIGCHASE_TD
760         looknew->do_topdown = ISC_FALSE;
761         looknew->trace_root_sigchase = ISC_FALSE;
762         looknew->rdtype_sigchaseset = ISC_FALSE;
763         looknew->rdtype_sigchase = dns_rdatatype_any;
764         looknew->qrdtype_sigchase = dns_rdatatype_any;
765         looknew->rdclass_sigchase = dns_rdataclass_in;
766         looknew->rdclass_sigchaseset = ISC_FALSE;
767 #endif
768 #endif
769         looknew->udpsize = 0;
770         looknew->edns = -1;
771         looknew->recurse = ISC_TRUE;
772         looknew->aaonly = ISC_FALSE;
773         looknew->adflag = ISC_FALSE;
774         looknew->cdflag = ISC_FALSE;
775         looknew->ns_search_only = ISC_FALSE;
776         looknew->origin = NULL;
777         looknew->tsigctx = NULL;
778         looknew->querysig = NULL;
779         looknew->retries = tries;
780         looknew->nsfound = 0;
781         looknew->tcp_mode = ISC_FALSE;
782         looknew->ip6_int = ISC_FALSE;
783         looknew->comments = ISC_TRUE;
784         looknew->stats = ISC_TRUE;
785         looknew->section_question = ISC_TRUE;
786         looknew->section_answer = ISC_TRUE;
787         looknew->section_authority = ISC_TRUE;
788         looknew->section_additional = ISC_TRUE;
789         looknew->new_search = ISC_FALSE;
790         looknew->done_as_is = ISC_FALSE;
791         looknew->need_search = ISC_FALSE;
792         ISC_LINK_INIT(looknew, link);
793         ISC_LIST_INIT(looknew->q);
794         ISC_LIST_INIT(looknew->my_server_list);
795         return (looknew);
796 }
797
798 /*%
799  * Clone a lookup, perhaps copying the server list.  This does not clone
800  * the query list, since it will be regenerated by the setup_lookup()
801  * function, nor does it queue up the new lookup for processing.
802  * Caution: If you don't clone the servers, you MUST clone the server
803  * list separately from somewhere else, or construct it by hand.
804  */
805 dig_lookup_t *
806 clone_lookup(dig_lookup_t *lookold, isc_boolean_t servers) {
807         dig_lookup_t *looknew;
808
809         debug("clone_lookup()");
810
811         INSIST(!free_now);
812
813         looknew = make_empty_lookup();
814         INSIST(looknew != NULL);
815         strncpy(looknew->textname, lookold->textname, MXNAME);
816 #if DIG_SIGCHASE_TD
817         strncpy(looknew->textnamesigchase, lookold->textnamesigchase, MXNAME);
818 #endif
819         strncpy(looknew->cmdline, lookold->cmdline, MXNAME);
820         looknew->textname[MXNAME-1] = 0;
821         looknew->rdtype = lookold->rdtype;
822         looknew->qrdtype = lookold->qrdtype;
823         looknew->rdclass = lookold->rdclass;
824         looknew->rdtypeset = lookold->rdtypeset;
825         looknew->rdclassset = lookold->rdclassset;
826         looknew->doing_xfr = lookold->doing_xfr;
827         looknew->ixfr_serial = lookold->ixfr_serial;
828         looknew->trace = lookold->trace;
829         looknew->trace_root = lookold->trace_root;
830         looknew->identify = lookold->identify;
831         looknew->identify_previous_line = lookold->identify_previous_line;
832         looknew->ignore = lookold->ignore;
833         looknew->servfail_stops = lookold->servfail_stops;
834         looknew->besteffort = lookold->besteffort;
835         looknew->dnssec = lookold->dnssec;
836         looknew->nsid = lookold->nsid;
837 #ifdef DIG_SIGCHASE
838         looknew->sigchase = lookold->sigchase;
839 #if DIG_SIGCHASE_TD
840         looknew->do_topdown = lookold->do_topdown;
841         looknew->trace_root_sigchase = lookold->trace_root_sigchase;
842         looknew->rdtype_sigchaseset = lookold->rdtype_sigchaseset;
843         looknew->rdtype_sigchase = lookold->rdtype_sigchase;
844         looknew->qrdtype_sigchase = lookold->qrdtype_sigchase;
845         looknew->rdclass_sigchase = lookold->rdclass_sigchase;
846         looknew->rdclass_sigchaseset = lookold->rdclass_sigchaseset;
847 #endif
848 #endif
849         looknew->udpsize = lookold->udpsize;
850         looknew->edns = lookold->edns;
851         looknew->recurse = lookold->recurse;
852         looknew->aaonly = lookold->aaonly;
853         looknew->adflag = lookold->adflag;
854         looknew->cdflag = lookold->cdflag;
855         looknew->ns_search_only = lookold->ns_search_only;
856         looknew->tcp_mode = lookold->tcp_mode;
857         looknew->comments = lookold->comments;
858         looknew->stats = lookold->stats;
859         looknew->section_question = lookold->section_question;
860         looknew->section_answer = lookold->section_answer;
861         looknew->section_authority = lookold->section_authority;
862         looknew->section_additional = lookold->section_additional;
863         looknew->retries = lookold->retries;
864         looknew->tsigctx = NULL;
865         looknew->need_search = lookold->need_search;
866         looknew->done_as_is = lookold->done_as_is;
867
868         if (servers)
869                 clone_server_list(lookold->my_server_list,
870                                   &looknew->my_server_list);
871         return (looknew);
872 }
873
874 /*%
875  * Requeue a lookup for further processing, perhaps copying the server
876  * list.  The new lookup structure is returned to the caller, and is
877  * queued for processing.  If servers are not cloned in the requeue, they
878  * must be added before allowing the current event to complete, since the
879  * completion of the event may result in the next entry on the lookup
880  * queue getting run.
881  */
882 dig_lookup_t *
883 requeue_lookup(dig_lookup_t *lookold, isc_boolean_t servers) {
884         dig_lookup_t *looknew;
885
886         debug("requeue_lookup()");
887
888         lookup_counter++;
889         if (lookup_counter > LOOKUP_LIMIT)
890                 fatal("too many lookups");
891
892         looknew = clone_lookup(lookold, servers);
893         INSIST(looknew != NULL);
894
895         debug("before insertion, init@%p -> %p, new@%p -> %p",
896               lookold, lookold->link.next, looknew, looknew->link.next);
897         ISC_LIST_PREPEND(lookup_list, looknew, link);
898         debug("after insertion, init -> %p, new = %p, new -> %p",
899               lookold, looknew, looknew->link.next);
900         return (looknew);
901 }
902
903
904 static void
905 setup_text_key(void) {
906         isc_result_t result;
907         dns_name_t keyname;
908         isc_buffer_t secretbuf;
909         int secretsize;
910         unsigned char *secretstore;
911
912         debug("setup_text_key()");
913         result = isc_buffer_allocate(mctx, &namebuf, MXNAME);
914         check_result(result, "isc_buffer_allocate");
915         dns_name_init(&keyname, NULL);
916         check_result(result, "dns_name_init");
917         isc_buffer_putstr(namebuf, keynametext);
918         secretsize = strlen(keysecret) * 3 / 4;
919         secretstore = isc_mem_allocate(mctx, secretsize);
920         if (secretstore == NULL)
921                 fatal("memory allocation failure in %s:%d",
922                       __FILE__, __LINE__);
923         isc_buffer_init(&secretbuf, secretstore, secretsize);
924         result = isc_base64_decodestring(keysecret, &secretbuf);
925         if (result != ISC_R_SUCCESS)
926                 goto failure;
927
928         secretsize = isc_buffer_usedlength(&secretbuf);
929
930         result = dns_name_fromtext(&keyname, namebuf, dns_rootname, 0, namebuf);
931         if (result != ISC_R_SUCCESS)
932                 goto failure;
933
934         result = dns_tsigkey_create(&keyname, hmacname, secretstore,
935                                     secretsize, ISC_FALSE, NULL, 0, 0, mctx,
936                                     NULL, &key);
937  failure:
938         if (result != ISC_R_SUCCESS)
939                 printf(";; Couldn't create key %s: %s\n",
940                        keynametext, isc_result_totext(result));
941         else
942                 dst_key_setbits(key->key, digestbits);
943
944         isc_mem_free(mctx, secretstore);
945         dns_name_invalidate(&keyname);
946         isc_buffer_free(&namebuf);
947 }
948
949 isc_result_t
950 parse_uint(isc_uint32_t *uip, const char *value, isc_uint32_t max,
951            const char *desc) {
952         isc_uint32_t n;
953         isc_result_t result = isc_parse_uint32(&n, value, 10);
954         if (result == ISC_R_SUCCESS && n > max)
955                 result = ISC_R_RANGE;
956         if (result != ISC_R_SUCCESS) {
957                 printf("invalid %s '%s': %s\n", desc,
958                        value, isc_result_totext(result));
959                 return (result);
960         }
961         *uip = n;
962         return (ISC_R_SUCCESS);
963 }
964
965 static isc_uint32_t
966 parse_bits(char *arg, const char *desc, isc_uint32_t max) {
967         isc_result_t result;
968         isc_uint32_t tmp;
969
970         result = parse_uint(&tmp, arg, max, desc);
971         if (result != ISC_R_SUCCESS)
972                 fatal("couldn't parse digest bits");
973         tmp = (tmp + 7) & ~0x7U;
974         return (tmp);
975 }
976
977
978 /*
979  * Parse HMAC algorithm specification
980  */
981 void
982 parse_hmac(const char *hmac) {
983         char buf[20];
984         int len;
985
986         REQUIRE(hmac != NULL);
987
988         len = strlen(hmac);
989         if (len >= (int) sizeof(buf))
990                 fatal("unknown key type '%.*s'", len, hmac);
991         strncpy(buf, hmac, sizeof(buf));
992
993         digestbits = 0;
994
995         if (strcasecmp(buf, "hmac-md5") == 0) {
996                 hmacname = DNS_TSIG_HMACMD5_NAME;
997         } else if (strncasecmp(buf, "hmac-md5-", 9) == 0) {
998                 hmacname = DNS_TSIG_HMACMD5_NAME;
999                 digestbits = parse_bits(&buf[9], "digest-bits [0..128]", 128);
1000         } else if (strcasecmp(buf, "hmac-sha1") == 0) {
1001                 hmacname = DNS_TSIG_HMACSHA1_NAME;
1002                 digestbits = 0;
1003         } else if (strncasecmp(buf, "hmac-sha1-", 10) == 0) {
1004                 hmacname = DNS_TSIG_HMACSHA1_NAME;
1005                 digestbits = parse_bits(&buf[10], "digest-bits [0..160]", 160);
1006         } else if (strcasecmp(buf, "hmac-sha224") == 0) {
1007                 hmacname = DNS_TSIG_HMACSHA224_NAME;
1008         } else if (strncasecmp(buf, "hmac-sha224-", 12) == 0) {
1009                 hmacname = DNS_TSIG_HMACSHA224_NAME;
1010                 digestbits = parse_bits(&buf[12], "digest-bits [0..224]", 224);
1011         } else if (strcasecmp(buf, "hmac-sha256") == 0) {
1012                 hmacname = DNS_TSIG_HMACSHA256_NAME;
1013         } else if (strncasecmp(buf, "hmac-sha256-", 12) == 0) {
1014                 hmacname = DNS_TSIG_HMACSHA256_NAME;
1015                 digestbits = parse_bits(&buf[12], "digest-bits [0..256]", 256);
1016         } else if (strcasecmp(buf, "hmac-sha384") == 0) {
1017                 hmacname = DNS_TSIG_HMACSHA384_NAME;
1018         } else if (strncasecmp(buf, "hmac-sha384-", 12) == 0) {
1019                 hmacname = DNS_TSIG_HMACSHA384_NAME;
1020                 digestbits = parse_bits(&buf[12], "digest-bits [0..384]", 384);
1021         } else if (strcasecmp(buf, "hmac-sha512") == 0) {
1022                 hmacname = DNS_TSIG_HMACSHA512_NAME;
1023         } else if (strncasecmp(buf, "hmac-sha512-", 12) == 0) {
1024                 hmacname = DNS_TSIG_HMACSHA512_NAME;
1025                 digestbits = parse_bits(&buf[12], "digest-bits [0..512]", 512);
1026         } else {
1027                 fprintf(stderr, ";; Warning, ignoring "
1028                         "invalid TSIG algorithm %s\n", buf);
1029         }
1030 }
1031
1032 /*
1033  * Get a key from a named.conf format keyfile
1034  */
1035 static isc_result_t
1036 read_confkey(void) {
1037         isc_log_t *lctx = NULL;
1038         cfg_parser_t *pctx = NULL;
1039         cfg_obj_t *file = NULL;
1040         const cfg_obj_t *key = NULL;
1041         const cfg_obj_t *secretobj = NULL;
1042         const cfg_obj_t *algorithmobj = NULL;
1043         const char *keyname;
1044         const char *secretstr;
1045         const char *algorithm;
1046         isc_result_t result;
1047
1048         if (! isc_file_exists(keyfile))
1049                 return (ISC_R_FILENOTFOUND);
1050
1051         result = cfg_parser_create(mctx, lctx, &pctx);
1052         if (result != ISC_R_SUCCESS)
1053                 goto cleanup;
1054
1055         result = cfg_parse_file(pctx, keyfile, &cfg_type_sessionkey,
1056                                 &file);
1057         if (result != ISC_R_SUCCESS)
1058                 goto cleanup;
1059
1060         result = cfg_map_get(file, "key", &key);
1061         if (result != ISC_R_SUCCESS)
1062                 goto cleanup;
1063
1064         (void) cfg_map_get(key, "secret", &secretobj);
1065         (void) cfg_map_get(key, "algorithm", &algorithmobj);
1066         if (secretobj == NULL || algorithmobj == NULL)
1067                 fatal("key must have algorithm and secret");
1068
1069         keyname = cfg_obj_asstring(cfg_map_getname(key));
1070         secretstr = cfg_obj_asstring(secretobj);
1071         algorithm = cfg_obj_asstring(algorithmobj);
1072
1073         strncpy(keynametext, keyname, sizeof(keynametext));
1074         strncpy(keysecret, secretstr, sizeof(keysecret));
1075         parse_hmac(algorithm);
1076         setup_text_key();
1077
1078  cleanup:
1079         if (pctx != NULL) {
1080                 if (file != NULL)
1081                         cfg_obj_destroy(pctx, &file);
1082                 cfg_parser_destroy(&pctx);
1083         }
1084
1085         return (result);
1086 }
1087
1088 static void
1089 setup_file_key(void) {
1090         isc_result_t result;
1091         dst_key_t *dstkey = NULL;
1092
1093         debug("setup_file_key()");
1094
1095         /* Try reading the key from a K* pair */
1096         result = dst_key_fromnamedfile(keyfile, NULL,
1097                                        DST_TYPE_PRIVATE | DST_TYPE_KEY, mctx,
1098                                        &dstkey);
1099
1100         /* If that didn't work, try reading it as a session.key keyfile */
1101         if (result != ISC_R_SUCCESS) {
1102                 result = read_confkey();
1103                 if (result == ISC_R_SUCCESS)
1104                         return;
1105         }
1106
1107         if (result != ISC_R_SUCCESS) {
1108                 fprintf(stderr, "Couldn't read key from %s: %s\n",
1109                         keyfile, isc_result_totext(result));
1110                 goto failure;
1111         }
1112
1113         switch (dst_key_alg(dstkey)) {
1114         case DST_ALG_HMACMD5:
1115                 hmacname = DNS_TSIG_HMACMD5_NAME;
1116                 break;
1117         case DST_ALG_HMACSHA1:
1118                 hmacname = DNS_TSIG_HMACSHA1_NAME;
1119                 break;
1120         case DST_ALG_HMACSHA224:
1121                 hmacname = DNS_TSIG_HMACSHA224_NAME;
1122                 break;
1123         case DST_ALG_HMACSHA256:
1124                 hmacname = DNS_TSIG_HMACSHA256_NAME;
1125                 break;
1126         case DST_ALG_HMACSHA384:
1127                 hmacname = DNS_TSIG_HMACSHA384_NAME;
1128                 break;
1129         case DST_ALG_HMACSHA512:
1130                 hmacname = DNS_TSIG_HMACSHA512_NAME;
1131                 break;
1132         default:
1133                 printf(";; Couldn't create key %s: bad algorithm\n",
1134                        keynametext);
1135                 goto failure;
1136         }
1137         result = dns_tsigkey_createfromkey(dst_key_name(dstkey), hmacname,
1138                                            dstkey, ISC_FALSE, NULL, 0, 0,
1139                                            mctx, NULL, &key);
1140         if (result != ISC_R_SUCCESS) {
1141                 printf(";; Couldn't create key %s: %s\n",
1142                        keynametext, isc_result_totext(result));
1143                 goto failure;
1144         }
1145         dstkey = NULL;
1146  failure:
1147         if (dstkey != NULL)
1148                 dst_key_free(&dstkey);
1149 }
1150
1151 static dig_searchlist_t *
1152 make_searchlist_entry(char *domain) {
1153         dig_searchlist_t *search;
1154         search = isc_mem_allocate(mctx, sizeof(*search));
1155         if (search == NULL)
1156                 fatal("memory allocation failure in %s:%d",
1157                       __FILE__, __LINE__);
1158         strncpy(search->origin, domain, MXNAME);
1159         search->origin[MXNAME-1] = 0;
1160         ISC_LINK_INIT(search, link);
1161         return (search);
1162 }
1163
1164 static void
1165 clear_searchlist(void) {
1166         dig_searchlist_t *search;
1167         while ((search = ISC_LIST_HEAD(search_list)) != NULL) {
1168                 ISC_LIST_UNLINK(search_list, search, link);
1169                 isc_mem_free(mctx, search);
1170         }
1171 }
1172
1173 static void
1174 create_search_list(lwres_conf_t *confdata) {
1175         int i;
1176         dig_searchlist_t *search;
1177
1178         debug("create_search_list()");
1179         clear_searchlist();
1180
1181         for (i = 0; i < confdata->searchnxt; i++) {
1182                 search = make_searchlist_entry(confdata->search[i]);
1183                 ISC_LIST_APPEND(search_list, search, link);
1184         }
1185 }
1186
1187 /*%
1188  * Setup the system as a whole, reading key information and resolv.conf
1189  * settings.
1190  */
1191 void
1192 setup_system(void) {
1193         dig_searchlist_t *domain = NULL;
1194         lwres_result_t lwresult;
1195         unsigned int lwresflags;
1196
1197         debug("setup_system()");
1198
1199         lwresflags = LWRES_CONTEXT_SERVERMODE;
1200         if (have_ipv4)
1201                 lwresflags |= LWRES_CONTEXT_USEIPV4;
1202         if (have_ipv6)
1203                 lwresflags |= LWRES_CONTEXT_USEIPV6;
1204
1205         lwresult = lwres_context_create(&lwctx, mctx, mem_alloc, mem_free,
1206                                         lwresflags);
1207         if (lwresult != LWRES_R_SUCCESS)
1208                 fatal("lwres_context_create failed");
1209
1210         lwresult = lwres_conf_parse(lwctx, RESOLV_CONF);
1211         if (lwresult != LWRES_R_SUCCESS && lwresult != LWRES_R_NOTFOUND)
1212                 fatal("parse of %s failed", RESOLV_CONF);
1213
1214         lwconf = lwres_conf_get(lwctx);
1215
1216         /* Make the search list */
1217         if (lwconf->searchnxt > 0)
1218                 create_search_list(lwconf);
1219         else { /* No search list. Use the domain name if any */
1220                 if (lwconf->domainname != NULL) {
1221                         domain = make_searchlist_entry(lwconf->domainname);
1222                         ISC_LIST_APPEND(search_list, domain, link);
1223                         domain  = NULL;
1224                 }
1225         }
1226
1227         if (ndots == -1) {
1228                 ndots = lwconf->ndots;
1229                 debug("ndots is %d.", ndots);
1230         }
1231
1232         /* If user doesn't specify server use nameservers from resolv.conf. */
1233         if (ISC_LIST_EMPTY(server_list))
1234                 copy_server_list(lwconf, &server_list);
1235
1236         /* If we don't find a nameserver fall back to localhost */
1237         if (ISC_LIST_EMPTY(server_list)) {
1238                 if (have_ipv4) {
1239                         lwresult = add_nameserver(lwconf, "127.0.0.1", AF_INET);
1240                         if (lwresult != ISC_R_SUCCESS)
1241                                 fatal("add_nameserver failed");
1242                 }
1243                 if (have_ipv6) {
1244                         lwresult = add_nameserver(lwconf, "::1", AF_INET6);
1245                         if (lwresult != ISC_R_SUCCESS)
1246                                 fatal("add_nameserver failed");
1247                 }
1248
1249                 copy_server_list(lwconf, &server_list);
1250         }
1251
1252 #ifdef WITH_IDN
1253         initialize_idn();
1254 #endif
1255
1256         if (keyfile[0] != 0)
1257                 setup_file_key();
1258         else if (keysecret[0] != 0)
1259                 setup_text_key();
1260 #ifdef DIG_SIGCHASE
1261         /* Setup the list of messages for +sigchase */
1262         ISC_LIST_INIT(chase_message_list);
1263         ISC_LIST_INIT(chase_message_list2);
1264         dns_name_init(&chase_name, NULL);
1265 #if DIG_SIGCHASE_TD
1266         dns_name_init(&chase_current_name, NULL);
1267         dns_name_init(&chase_authority_name, NULL);
1268 #endif
1269 #if DIG_SIGCHASE_BU
1270         dns_name_init(&chase_signame, NULL);
1271 #endif
1272
1273 #endif
1274
1275 }
1276
1277 /*%
1278  * Override the search list derived from resolv.conf by 'domain'.
1279  */
1280 void
1281 set_search_domain(char *domain) {
1282         dig_searchlist_t *search;
1283
1284         clear_searchlist();
1285         search = make_searchlist_entry(domain);
1286         ISC_LIST_APPEND(search_list, search, link);
1287 }
1288
1289 /*%
1290  * Setup the ISC and DNS libraries for use by the system.
1291  */
1292 void
1293 setup_libs(void) {
1294         isc_result_t result;
1295         isc_logconfig_t *logconfig = NULL;
1296
1297         debug("setup_libs()");
1298
1299         result = isc_net_probeipv4();
1300         if (result == ISC_R_SUCCESS)
1301                 have_ipv4 = ISC_TRUE;
1302
1303         result = isc_net_probeipv6();
1304         if (result == ISC_R_SUCCESS)
1305                 have_ipv6 = ISC_TRUE;
1306         if (!have_ipv6 && !have_ipv4)
1307                 fatal("can't find either v4 or v6 networking");
1308
1309         result = isc_mem_create(0, 0, &mctx);
1310         check_result(result, "isc_mem_create");
1311
1312         result = isc_log_create(mctx, &lctx, &logconfig);
1313         check_result(result, "isc_log_create");
1314
1315         isc_log_setcontext(lctx);
1316         dns_log_init(lctx);
1317         dns_log_setcontext(lctx);
1318
1319         result = isc_log_usechannel(logconfig, "default_debug", NULL, NULL);
1320         check_result(result, "isc_log_usechannel");
1321
1322         isc_log_setdebuglevel(lctx, 0);
1323
1324         result = isc_taskmgr_create(mctx, 1, 0, &taskmgr);
1325         check_result(result, "isc_taskmgr_create");
1326
1327         result = isc_task_create(taskmgr, 0, &global_task);
1328         check_result(result, "isc_task_create");
1329
1330         result = isc_timermgr_create(mctx, &timermgr);
1331         check_result(result, "isc_timermgr_create");
1332
1333         result = isc_socketmgr_create(mctx, &socketmgr);
1334         check_result(result, "isc_socketmgr_create");
1335
1336         result = isc_entropy_create(mctx, &entp);
1337         check_result(result, "isc_entropy_create");
1338
1339         result = dst_lib_init(mctx, entp, 0);
1340         check_result(result, "dst_lib_init");
1341         is_dst_up = ISC_TRUE;
1342
1343         result = isc_mempool_create(mctx, COMMSIZE, &commctx);
1344         check_result(result, "isc_mempool_create");
1345         isc_mempool_setname(commctx, "COMMPOOL");
1346         /*
1347          * 6 and 2 set as reasonable parameters for 3 or 4 nameserver
1348          * systems.
1349          */
1350         isc_mempool_setfreemax(commctx, 6);
1351         isc_mempool_setfillcount(commctx, 2);
1352
1353         result = isc_mutex_init(&lookup_lock);
1354         check_result(result, "isc_mutex_init");
1355
1356         dns_result_register();
1357 }
1358
1359 /*%
1360  * Add EDNS0 option record to a message.  Currently, the only supported
1361  * options are UDP buffer size, the DO bit, and NSID request.
1362  */
1363 static void
1364 add_opt(dns_message_t *msg, isc_uint16_t udpsize, isc_uint16_t edns,
1365         isc_boolean_t dnssec, isc_boolean_t nsid)
1366 {
1367         dns_rdataset_t *rdataset = NULL;
1368         dns_rdatalist_t *rdatalist = NULL;
1369         dns_rdata_t *rdata = NULL;
1370         isc_result_t result;
1371
1372         debug("add_opt()");
1373         result = dns_message_gettemprdataset(msg, &rdataset);
1374         check_result(result, "dns_message_gettemprdataset");
1375         dns_rdataset_init(rdataset);
1376         result = dns_message_gettemprdatalist(msg, &rdatalist);
1377         check_result(result, "dns_message_gettemprdatalist");
1378         result = dns_message_gettemprdata(msg, &rdata);
1379         check_result(result, "dns_message_gettemprdata");
1380
1381         debug("setting udp size of %d", udpsize);
1382         rdatalist->type = dns_rdatatype_opt;
1383         rdatalist->covers = 0;
1384         rdatalist->rdclass = udpsize;
1385         rdatalist->ttl = edns << 16;
1386         if (dnssec)
1387                 rdatalist->ttl |= DNS_MESSAGEEXTFLAG_DO;
1388         if (nsid) {
1389                 isc_buffer_t *b = NULL;
1390
1391                 result = isc_buffer_allocate(mctx, &b, 4);
1392                 check_result(result, "isc_buffer_allocate");
1393                 isc_buffer_putuint16(b, DNS_OPT_NSID);
1394                 isc_buffer_putuint16(b, 0);
1395                 rdata->data = isc_buffer_base(b);
1396                 rdata->length = isc_buffer_usedlength(b);
1397                 dns_message_takebuffer(msg, &b);
1398         } else {
1399                 rdata->data = NULL;
1400                 rdata->length = 0;
1401         }
1402         ISC_LIST_INIT(rdatalist->rdata);
1403         ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1404         dns_rdatalist_tordataset(rdatalist, rdataset);
1405         result = dns_message_setopt(msg, rdataset);
1406         check_result(result, "dns_message_setopt");
1407 }
1408
1409 /*%
1410  * Add a question section to a message, asking for the specified name,
1411  * type, and class.
1412  */
1413 static void
1414 add_question(dns_message_t *message, dns_name_t *name,
1415              dns_rdataclass_t rdclass, dns_rdatatype_t rdtype)
1416 {
1417         dns_rdataset_t *rdataset;
1418         isc_result_t result;
1419
1420         debug("add_question()");
1421         rdataset = NULL;
1422         result = dns_message_gettemprdataset(message, &rdataset);
1423         check_result(result, "dns_message_gettemprdataset()");
1424         dns_rdataset_init(rdataset);
1425         dns_rdataset_makequestion(rdataset, rdclass, rdtype);
1426         ISC_LIST_APPEND(name->list, rdataset, link);
1427 }
1428
1429 /*%
1430  * Check if we're done with all the queued lookups, which is true iff
1431  * all sockets, sends, and recvs are accounted for (counters == 0),
1432  * and the lookup list is empty.
1433  * If we are done, pass control back out to dighost_shutdown() (which is
1434  * part of dig.c, host.c, or nslookup.c) to either shutdown the system as
1435  * a whole or reseed the lookup list.
1436  */
1437 static void
1438 check_if_done(void) {
1439         debug("check_if_done()");
1440         debug("list %s", ISC_LIST_EMPTY(lookup_list) ? "empty" : "full");
1441         if (ISC_LIST_EMPTY(lookup_list) && current_lookup == NULL &&
1442             sendcount == 0) {
1443                 INSIST(sockcount == 0);
1444                 INSIST(recvcount == 0);
1445                 debug("shutting down");
1446                 dighost_shutdown();
1447         }
1448 }
1449
1450 /*%
1451  * Clear out a query when we're done with it.  WARNING: This routine
1452  * WILL invalidate the query pointer.
1453  */
1454 static void
1455 clear_query(dig_query_t *query) {
1456         dig_lookup_t *lookup;
1457
1458         REQUIRE(query != NULL);
1459
1460         debug("clear_query(%p)", query);
1461
1462         lookup = query->lookup;
1463
1464         if (lookup->current_query == query)
1465                 lookup->current_query = NULL;
1466
1467         ISC_LIST_UNLINK(lookup->q, query, link);
1468         if (ISC_LINK_LINKED(&query->recvbuf, link))
1469                 ISC_LIST_DEQUEUE(query->recvlist, &query->recvbuf,
1470                                  link);
1471         if (ISC_LINK_LINKED(&query->lengthbuf, link))
1472                 ISC_LIST_DEQUEUE(query->lengthlist, &query->lengthbuf,
1473                                  link);
1474         INSIST(query->recvspace != NULL);
1475         if (query->sock != NULL) {
1476                 isc_socket_detach(&query->sock);
1477                 sockcount--;
1478                 debug("sockcount=%d", sockcount);
1479         }
1480         isc_mempool_put(commctx, query->recvspace);
1481         isc_buffer_invalidate(&query->recvbuf);
1482         isc_buffer_invalidate(&query->lengthbuf);
1483         if (query->waiting_senddone)
1484                 query->pending_free = ISC_TRUE;
1485         else
1486                 isc_mem_free(mctx, query);
1487 }
1488
1489 /*%
1490  * Try and clear out a lookup if we're done with it.  Return ISC_TRUE if
1491  * the lookup was successfully cleared.  If ISC_TRUE is returned, the
1492  * lookup pointer has been invalidated.
1493  */
1494 static isc_boolean_t
1495 try_clear_lookup(dig_lookup_t *lookup) {
1496         dig_query_t *q;
1497
1498         REQUIRE(lookup != NULL);
1499
1500         debug("try_clear_lookup(%p)", lookup);
1501
1502         if (ISC_LIST_HEAD(lookup->q) != NULL) {
1503                 if (debugging) {
1504                         q = ISC_LIST_HEAD(lookup->q);
1505                         while (q != NULL) {
1506                                 debug("query to %s still pending", q->servname);
1507                                 q = ISC_LIST_NEXT(q, link);
1508                         }
1509                 }
1510                 return (ISC_FALSE);
1511         }
1512
1513         /*
1514          * At this point, we know there are no queries on the lookup,
1515          * so can make it go away also.
1516          */
1517         destroy_lookup(lookup);
1518         return (ISC_TRUE);
1519 }
1520
1521 void
1522 destroy_lookup(dig_lookup_t *lookup) {
1523         dig_server_t *s;
1524         void *ptr;
1525
1526         debug("destroy");
1527         s = ISC_LIST_HEAD(lookup->my_server_list);
1528         while (s != NULL) {
1529                 debug("freeing server %p belonging to %p", s, lookup);
1530                 ptr = s;
1531                 s = ISC_LIST_NEXT(s, link);
1532                 ISC_LIST_DEQUEUE(lookup->my_server_list,
1533                                  (dig_server_t *)ptr, link);
1534                 isc_mem_free(mctx, ptr);
1535         }
1536         if (lookup->sendmsg != NULL)
1537                 dns_message_destroy(&lookup->sendmsg);
1538         if (lookup->querysig != NULL) {
1539                 debug("freeing buffer %p", lookup->querysig);
1540                 isc_buffer_free(&lookup->querysig);
1541         }
1542         if (lookup->timer != NULL)
1543                 isc_timer_detach(&lookup->timer);
1544         if (lookup->sendspace != NULL)
1545                 isc_mempool_put(commctx, lookup->sendspace);
1546
1547         if (lookup->tsigctx != NULL)
1548                 dst_context_destroy(&lookup->tsigctx);
1549
1550         isc_mem_free(mctx, lookup);
1551 }
1552
1553 /*%
1554  * If we can, start the next lookup in the queue running.
1555  * This assumes that the lookup on the head of the queue hasn't been
1556  * started yet.  It also removes the lookup from the head of the queue,
1557  * setting the current_lookup pointer pointing to it.
1558  */
1559 void
1560 start_lookup(void) {
1561         debug("start_lookup()");
1562         if (cancel_now)
1563                 return;
1564
1565         /*
1566          * If there's a current lookup running, we really shouldn't get
1567          * here.
1568          */
1569         INSIST(current_lookup == NULL);
1570
1571         current_lookup = ISC_LIST_HEAD(lookup_list);
1572         /*
1573          * Put the current lookup somewhere so cancel_all can find it
1574          */
1575         if (current_lookup != NULL) {
1576                 ISC_LIST_DEQUEUE(lookup_list, current_lookup, link);
1577 #if DIG_SIGCHASE_TD
1578                 if (current_lookup->do_topdown &&
1579                     !current_lookup->rdtype_sigchaseset) {
1580                         dst_key_t *trustedkey = NULL;
1581                         isc_buffer_t *b = NULL;
1582                         isc_region_t r;
1583                         isc_result_t result;
1584                         dns_name_t query_name;
1585                         dns_name_t *key_name;
1586                         int i;
1587
1588                         result = get_trusted_key(mctx);
1589                         if (result != ISC_R_SUCCESS) {
1590                                 printf("\n;; No trusted key, "
1591                                        "+sigchase option is disabled\n");
1592                                 current_lookup->sigchase = ISC_FALSE;
1593                                 goto novalidation;
1594                         }
1595                         dns_name_init(&query_name, NULL);
1596                         nameFromString(current_lookup->textname, &query_name);
1597
1598                         for (i = 0; i < tk_list.nb_tk; i++) {
1599                                 key_name = dst_key_name(tk_list.key[i]);
1600
1601                                 if (dns_name_issubdomain(&query_name,
1602                                                          key_name) == ISC_TRUE)
1603                                         trustedkey = tk_list.key[i];
1604                                 /*
1605                                  * Verify temp is really the lowest
1606                                  * WARNING
1607                                  */
1608                         }
1609                         if (trustedkey == NULL) {
1610                                 printf("\n;; The queried zone: ");
1611                                 dns_name_print(&query_name, stdout);
1612                                 printf(" isn't a subdomain of any Trusted Keys"
1613                                        ": +sigchase option is disable\n");
1614                                 current_lookup->sigchase = ISC_FALSE;
1615                                 free_name(&query_name, mctx);
1616                                 goto novalidation;
1617                         }
1618                         free_name(&query_name, mctx);
1619
1620                         current_lookup->rdtype_sigchase
1621                                 = current_lookup->rdtype;
1622                         current_lookup->rdtype_sigchaseset
1623                                 = current_lookup->rdtypeset;
1624                         current_lookup->rdtype = dns_rdatatype_ns;
1625
1626                         current_lookup->qrdtype_sigchase
1627                                 = current_lookup->qrdtype;
1628                         current_lookup->qrdtype = dns_rdatatype_ns;
1629
1630                         current_lookup->rdclass_sigchase
1631                                 = current_lookup->rdclass;
1632                         current_lookup->rdclass_sigchaseset
1633                                 = current_lookup->rdclassset;
1634                         current_lookup->rdclass = dns_rdataclass_in;
1635
1636                         strncpy(current_lookup->textnamesigchase,
1637                                 current_lookup->textname, MXNAME);
1638
1639                         current_lookup->trace_root_sigchase = ISC_TRUE;
1640
1641                         result = isc_buffer_allocate(mctx, &b, BUFSIZE);
1642                         check_result(result, "isc_buffer_allocate");
1643                         result = dns_name_totext(dst_key_name(trustedkey),
1644                                                  ISC_FALSE, b);
1645                         check_result(result, "dns_name_totext");
1646                         isc_buffer_usedregion(b, &r);
1647                         r.base[r.length] = '\0';
1648                         strncpy(current_lookup->textname, (char*)r.base,
1649                                 MXNAME);
1650                         isc_buffer_free(&b);
1651
1652                         nameFromString(current_lookup->textnamesigchase,
1653                                        &chase_name);
1654
1655                         dns_name_init(&chase_authority_name, NULL);
1656                 }
1657         novalidation:
1658 #endif
1659                 setup_lookup(current_lookup);
1660                 do_lookup(current_lookup);
1661         } else {
1662                 check_if_done();
1663         }
1664 }
1665
1666 /*%
1667  * If we can, clear the current lookup and start the next one running.
1668  * This calls try_clear_lookup, so may invalidate the lookup pointer.
1669  */
1670 static void
1671 check_next_lookup(dig_lookup_t *lookup) {
1672
1673         INSIST(!free_now);
1674
1675         debug("check_next_lookup(%p)", lookup);
1676
1677         if (ISC_LIST_HEAD(lookup->q) != NULL) {
1678                 debug("still have a worker");
1679                 return;
1680         }
1681         if (try_clear_lookup(lookup)) {
1682                 current_lookup = NULL;
1683                 start_lookup();
1684         }
1685 }
1686
1687 /*%
1688  * Create and queue a new lookup as a followup to the current lookup,
1689  * based on the supplied message and section.  This is used in trace and
1690  * name server search modes to start a new lookup using servers from
1691  * NS records in a reply. Returns the number of followup lookups made.
1692  */
1693 static int
1694 followup_lookup(dns_message_t *msg, dig_query_t *query, dns_section_t section)
1695 {
1696         dig_lookup_t *lookup = NULL;
1697         dig_server_t *srv = NULL;
1698         dns_rdataset_t *rdataset = NULL;
1699         dns_rdata_t rdata = DNS_RDATA_INIT;
1700         dns_name_t *name = NULL;
1701         isc_result_t result;
1702         isc_boolean_t success = ISC_FALSE;
1703         int numLookups = 0;
1704         dns_name_t *domain;
1705         isc_boolean_t horizontal = ISC_FALSE, bad = ISC_FALSE;
1706
1707         INSIST(!free_now);
1708
1709         debug("following up %s", query->lookup->textname);
1710
1711         for (result = dns_message_firstname(msg, section);
1712              result == ISC_R_SUCCESS;
1713              result = dns_message_nextname(msg, section)) {
1714                 name = NULL;
1715                 dns_message_currentname(msg, section, &name);
1716
1717                 if (section == DNS_SECTION_AUTHORITY) {
1718                         rdataset = NULL;
1719                         result = dns_message_findtype(name, dns_rdatatype_soa,
1720                                                       0, &rdataset);
1721                         if (result == ISC_R_SUCCESS)
1722                                 return (0);
1723                 }
1724                 rdataset = NULL;
1725                 result = dns_message_findtype(name, dns_rdatatype_ns, 0,
1726                                               &rdataset);
1727                 if (result != ISC_R_SUCCESS)
1728                         continue;
1729
1730                 debug("found NS set");
1731
1732                 if (query->lookup->trace && !query->lookup->trace_root) {
1733                         dns_namereln_t namereln;
1734                         unsigned int nlabels;
1735                         int order;
1736
1737                         domain = dns_fixedname_name(&query->lookup->fdomain);
1738                         namereln = dns_name_fullcompare(name, domain,
1739                                                         &order, &nlabels);
1740                         if (namereln == dns_namereln_equal) {
1741                                 if (!horizontal)
1742                                         printf(";; BAD (HORIZONTAL) REFERRAL\n");
1743                                 horizontal = ISC_TRUE;
1744                         } else if (namereln != dns_namereln_subdomain) {
1745                                 if (!bad)
1746                                         printf(";; BAD REFERRAL\n");
1747                                 bad = ISC_TRUE;
1748                                 continue;
1749                         }
1750                 }
1751
1752                 for (result = dns_rdataset_first(rdataset);
1753                      result == ISC_R_SUCCESS;
1754                      result = dns_rdataset_next(rdataset)) {
1755                         char namestr[DNS_NAME_FORMATSIZE];
1756                         dns_rdata_ns_t ns;
1757
1758                         if (query->lookup->trace_root &&
1759                             query->lookup->nsfound >= MXSERV)
1760                                 break;
1761
1762                         dns_rdataset_current(rdataset, &rdata);
1763
1764                         query->lookup->nsfound++;
1765                         result = dns_rdata_tostruct(&rdata, &ns, NULL);
1766                         check_result(result, "dns_rdata_tostruct");
1767                         dns_name_format(&ns.name, namestr, sizeof(namestr));
1768                         dns_rdata_freestruct(&ns);
1769
1770                         /* Initialize lookup if we've not yet */
1771                         debug("found NS %d %s", numLookups, namestr);
1772                         numLookups++;
1773                         if (!success) {
1774                                 success = ISC_TRUE;
1775                                 lookup_counter++;
1776                                 lookup = requeue_lookup(query->lookup,
1777                                                         ISC_FALSE);
1778                                 cancel_lookup(query->lookup);
1779                                 lookup->doing_xfr = ISC_FALSE;
1780                                 if (!lookup->trace_root &&
1781                                     section == DNS_SECTION_ANSWER)
1782                                         lookup->trace = ISC_FALSE;
1783                                 else
1784                                         lookup->trace = query->lookup->trace;
1785                                 lookup->ns_search_only =
1786                                         query->lookup->ns_search_only;
1787                                 lookup->trace_root = ISC_FALSE;
1788                                 if (lookup->ns_search_only)
1789                                         lookup->recurse = ISC_FALSE;
1790                                 dns_fixedname_init(&lookup->fdomain);
1791                                 domain = dns_fixedname_name(&lookup->fdomain);
1792                                 dns_name_copy(name, domain, NULL);
1793                         }
1794                         srv = make_server(namestr, namestr);
1795                         debug("adding server %s", srv->servername);
1796                         ISC_LIST_APPEND(lookup->my_server_list, srv, link);
1797                         dns_rdata_reset(&rdata);
1798                 }
1799         }
1800
1801         if (lookup == NULL &&
1802             section == DNS_SECTION_ANSWER &&
1803             (query->lookup->trace || query->lookup->ns_search_only))
1804                 return (followup_lookup(msg, query, DNS_SECTION_AUTHORITY));
1805
1806         /*
1807          * Randomize the order the nameserver will be tried.
1808          */
1809         if (numLookups > 1) {
1810                 isc_uint32_t i, j;
1811                 dig_serverlist_t my_server_list;
1812
1813                 ISC_LIST_INIT(my_server_list);
1814
1815                 for (i = numLookups; i > 0; i--) {
1816                         isc_random_get(&j);
1817                         j %= i;
1818                         srv = ISC_LIST_HEAD(lookup->my_server_list);
1819                         while (j-- > 0)
1820                                 srv = ISC_LIST_NEXT(srv, link);
1821                         ISC_LIST_DEQUEUE(lookup->my_server_list, srv, link);
1822                         ISC_LIST_APPEND(my_server_list, srv, link);
1823                 }
1824                 ISC_LIST_APPENDLIST(lookup->my_server_list,
1825                                     my_server_list, link);
1826         }
1827
1828         return (numLookups);
1829 }
1830
1831 /*%
1832  * Create and queue a new lookup using the next origin from the search
1833  * list, read in setup_system().
1834  *
1835  * Return ISC_TRUE iff there was another searchlist entry.
1836  */
1837 static isc_boolean_t
1838 next_origin(dns_message_t *msg, dig_query_t *query) {
1839         dig_lookup_t *lookup;
1840         dig_searchlist_t *search;
1841
1842         UNUSED(msg);
1843
1844         INSIST(!free_now);
1845
1846         debug("next_origin()");
1847         debug("following up %s", query->lookup->textname);
1848
1849         if (!usesearch)
1850                 /*
1851                  * We're not using a search list, so don't even think
1852                  * about finding the next entry.
1853                  */
1854                 return (ISC_FALSE);
1855         if (query->lookup->origin == NULL && !query->lookup->need_search)
1856                 /*
1857                  * Then we just did rootorg; there's nothing left.
1858                  */
1859                 return (ISC_FALSE);
1860         if (query->lookup->origin == NULL && query->lookup->need_search) {
1861                 lookup = requeue_lookup(query->lookup, ISC_TRUE);
1862                 lookup->origin = ISC_LIST_HEAD(search_list);
1863                 lookup->need_search = ISC_FALSE;
1864         } else {
1865                 search = ISC_LIST_NEXT(query->lookup->origin, link);
1866                 if (search == NULL && query->lookup->done_as_is)
1867                         return (ISC_FALSE);
1868                 lookup = requeue_lookup(query->lookup, ISC_TRUE);
1869                 lookup->origin = search;
1870         }
1871         cancel_lookup(query->lookup);
1872         return (ISC_TRUE);
1873 }
1874
1875 /*%
1876  * Insert an SOA record into the sendmessage in a lookup.  Used for
1877  * creating IXFR queries.
1878  */
1879 static void
1880 insert_soa(dig_lookup_t *lookup) {
1881         isc_result_t result;
1882         dns_rdata_soa_t soa;
1883         dns_rdata_t *rdata = NULL;
1884         dns_rdatalist_t *rdatalist = NULL;
1885         dns_rdataset_t *rdataset = NULL;
1886         dns_name_t *soaname = NULL;
1887
1888         debug("insert_soa()");
1889         soa.mctx = mctx;
1890         soa.serial = lookup->ixfr_serial;
1891         soa.refresh = 0;
1892         soa.retry = 0;
1893         soa.expire = 0;
1894         soa.minimum = 0;
1895         soa.common.rdclass = lookup->rdclass;
1896         soa.common.rdtype = dns_rdatatype_soa;
1897
1898         dns_name_init(&soa.origin, NULL);
1899         dns_name_init(&soa.contact, NULL);
1900
1901         dns_name_clone(dns_rootname, &soa.origin);
1902         dns_name_clone(dns_rootname, &soa.contact);
1903
1904         isc_buffer_init(&lookup->rdatabuf, lookup->rdatastore,
1905                         sizeof(lookup->rdatastore));
1906
1907         result = dns_message_gettemprdata(lookup->sendmsg, &rdata);
1908         check_result(result, "dns_message_gettemprdata");
1909
1910         result = dns_rdata_fromstruct(rdata, lookup->rdclass,
1911                                       dns_rdatatype_soa, &soa,
1912                                       &lookup->rdatabuf);
1913         check_result(result, "isc_rdata_fromstruct");
1914
1915         result = dns_message_gettemprdatalist(lookup->sendmsg, &rdatalist);
1916         check_result(result, "dns_message_gettemprdatalist");
1917
1918         result = dns_message_gettemprdataset(lookup->sendmsg, &rdataset);
1919         check_result(result, "dns_message_gettemprdataset");
1920
1921         dns_rdatalist_init(rdatalist);
1922         rdatalist->type = dns_rdatatype_soa;
1923         rdatalist->rdclass = lookup->rdclass;
1924         rdatalist->covers = 0;
1925         rdatalist->ttl = 0;
1926         ISC_LIST_INIT(rdatalist->rdata);
1927         ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1928
1929         dns_rdataset_init(rdataset);
1930         dns_rdatalist_tordataset(rdatalist, rdataset);
1931
1932         result = dns_message_gettempname(lookup->sendmsg, &soaname);
1933         check_result(result, "dns_message_gettempname");
1934         dns_name_init(soaname, NULL);
1935         dns_name_clone(lookup->name, soaname);
1936         ISC_LIST_INIT(soaname->list);
1937         ISC_LIST_APPEND(soaname->list, rdataset, link);
1938         dns_message_addname(lookup->sendmsg, soaname, DNS_SECTION_AUTHORITY);
1939 }
1940
1941 /*%
1942  * Setup the supplied lookup structure, making it ready to start sending
1943  * queries to servers.  Create and initialize the message to be sent as
1944  * well as the query structures and buffer space for the replies.  If the
1945  * server list is empty, clone it from the system default list.
1946  */
1947 void
1948 setup_lookup(dig_lookup_t *lookup) {
1949         isc_result_t result;
1950         isc_uint32_t id;
1951         int len;
1952         dig_server_t *serv;
1953         dig_query_t *query;
1954         isc_buffer_t b;
1955         dns_compress_t cctx;
1956         char store[MXNAME];
1957 #ifdef WITH_IDN
1958         idn_result_t mr;
1959         char utf8_textname[MXNAME], utf8_origin[MXNAME], idn_textname[MXNAME];
1960 #endif
1961
1962 #ifdef WITH_IDN
1963         result = dns_name_settotextfilter(output_filter);
1964         check_result(result, "dns_name_settotextfilter");
1965 #endif
1966
1967         REQUIRE(lookup != NULL);
1968         INSIST(!free_now);
1969
1970         debug("setup_lookup(%p)", lookup);
1971
1972         result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER,
1973                                     &lookup->sendmsg);
1974         check_result(result, "dns_message_create");
1975
1976         if (lookup->new_search) {
1977                 debug("resetting lookup counter.");
1978                 lookup_counter = 0;
1979         }
1980
1981         if (ISC_LIST_EMPTY(lookup->my_server_list)) {
1982                 debug("cloning server list");
1983                 clone_server_list(server_list, &lookup->my_server_list);
1984         }
1985         result = dns_message_gettempname(lookup->sendmsg, &lookup->name);
1986         check_result(result, "dns_message_gettempname");
1987         dns_name_init(lookup->name, NULL);
1988
1989         isc_buffer_init(&lookup->namebuf, lookup->namespace,
1990                         sizeof(lookup->namespace));
1991         isc_buffer_init(&lookup->onamebuf, lookup->onamespace,
1992                         sizeof(lookup->onamespace));
1993
1994 #ifdef WITH_IDN
1995         /*
1996          * We cannot convert `textname' and `origin' separately.
1997          * `textname' doesn't contain TLD, but local mapping needs
1998          * TLD.
1999          */
2000         mr = idn_encodename(IDN_LOCALCONV | IDN_DELIMMAP, lookup->textname,
2001                             utf8_textname, sizeof(utf8_textname));
2002         idn_check_result(mr, "convert textname to UTF-8");
2003 #endif
2004
2005         /*
2006          * If the name has too many dots, force the origin to be NULL
2007          * (which produces an absolute lookup).  Otherwise, take the origin
2008          * we have if there's one in the struct already.  If it's NULL,
2009          * take the first entry in the searchlist iff either usesearch
2010          * is TRUE or we got a domain line in the resolv.conf file.
2011          */
2012         if (lookup->new_search) {
2013 #ifdef WITH_IDN
2014                 if ((count_dots(utf8_textname) >= ndots) || !usesearch) {
2015                         lookup->origin = NULL; /* Force abs lookup */
2016                         lookup->done_as_is = ISC_TRUE;
2017                         lookup->need_search = usesearch;
2018                 } else if (lookup->origin == NULL && usesearch) {
2019                         lookup->origin = ISC_LIST_HEAD(search_list);
2020                         lookup->need_search = ISC_FALSE;
2021                 }
2022 #else
2023                 if ((count_dots(lookup->textname) >= ndots) || !usesearch) {
2024                         lookup->origin = NULL; /* Force abs lookup */
2025                         lookup->done_as_is = ISC_TRUE;
2026                         lookup->need_search = usesearch;
2027                 } else if (lookup->origin == NULL && usesearch) {
2028                         lookup->origin = ISC_LIST_HEAD(search_list);
2029                         lookup->need_search = ISC_FALSE;
2030                 }
2031 #endif
2032         }
2033
2034 #ifdef WITH_IDN
2035         if (lookup->origin != NULL) {
2036                 mr = idn_encodename(IDN_LOCALCONV | IDN_DELIMMAP,
2037                                     lookup->origin->origin, utf8_origin,
2038                                     sizeof(utf8_origin));
2039                 idn_check_result(mr, "convert origin to UTF-8");
2040                 mr = append_textname(utf8_textname, utf8_origin,
2041                                      sizeof(utf8_textname));
2042                 idn_check_result(mr, "append origin to textname");
2043         }
2044         mr = idn_encodename(idnoptions | IDN_LOCALMAP | IDN_NAMEPREP |
2045                             IDN_IDNCONV | IDN_LENCHECK, utf8_textname,
2046                             idn_textname, sizeof(idn_textname));
2047         idn_check_result(mr, "convert UTF-8 textname to IDN encoding");
2048 #else
2049         if (lookup->origin != NULL) {
2050                 debug("trying origin %s", lookup->origin->origin);
2051                 result = dns_message_gettempname(lookup->sendmsg,
2052                                                  &lookup->oname);
2053                 check_result(result, "dns_message_gettempname");
2054                 dns_name_init(lookup->oname, NULL);
2055                 /* XXX Helper funct to conv char* to name? */
2056                 len = strlen(lookup->origin->origin);
2057                 isc_buffer_init(&b, lookup->origin->origin, len);
2058                 isc_buffer_add(&b, len);
2059                 result = dns_name_fromtext(lookup->oname, &b, dns_rootname,
2060                                            0, &lookup->onamebuf);
2061                 if (result != ISC_R_SUCCESS) {
2062                         dns_message_puttempname(lookup->sendmsg,
2063                                                 &lookup->name);
2064                         dns_message_puttempname(lookup->sendmsg,
2065                                                 &lookup->oname);
2066                         fatal("'%s' is not in legal name syntax (%s)",
2067                               lookup->origin->origin,
2068                               isc_result_totext(result));
2069                 }
2070                 if (lookup->trace && lookup->trace_root) {
2071                         dns_name_clone(dns_rootname, lookup->name);
2072                 } else {
2073                         len = strlen(lookup->textname);
2074                         isc_buffer_init(&b, lookup->textname, len);
2075                         isc_buffer_add(&b, len);
2076                         result = dns_name_fromtext(lookup->name, &b,
2077                                                    lookup->oname, 0,
2078                                                    &lookup->namebuf);
2079                 }
2080                 if (result != ISC_R_SUCCESS) {
2081                         dns_message_puttempname(lookup->sendmsg,
2082                                                 &lookup->name);
2083                         dns_message_puttempname(lookup->sendmsg,
2084                                                 &lookup->oname);
2085                         fatal("'%s' is not in legal name syntax (%s)",
2086                               lookup->textname, isc_result_totext(result));
2087                 }
2088                 dns_message_puttempname(lookup->sendmsg, &lookup->oname);
2089         } else
2090 #endif
2091         {
2092                 debug("using root origin");
2093                 if (lookup->trace && lookup->trace_root)
2094                         dns_name_clone(dns_rootname, lookup->name);
2095                 else {
2096 #ifdef WITH_IDN
2097                         len = strlen(idn_textname);
2098                         isc_buffer_init(&b, idn_textname, len);
2099                         isc_buffer_add(&b, len);
2100                         result = dns_name_fromtext(lookup->name, &b,
2101                                                    dns_rootname, 0,
2102                                                    &lookup->namebuf);
2103 #else
2104                         len = strlen(lookup->textname);
2105                         isc_buffer_init(&b, lookup->textname, len);
2106                         isc_buffer_add(&b, len);
2107                         result = dns_name_fromtext(lookup->name, &b,
2108                                                    dns_rootname, 0,
2109                                                    &lookup->namebuf);
2110 #endif
2111                 }
2112                 if (result != ISC_R_SUCCESS) {
2113                         dns_message_puttempname(lookup->sendmsg,
2114                                                 &lookup->name);
2115                         isc_buffer_init(&b, store, MXNAME);
2116                         fatal("'%s' is not a legal name "
2117                               "(%s)", lookup->textname,
2118                               isc_result_totext(result));
2119                 }
2120         }
2121         dns_name_format(lookup->name, store, sizeof(store));
2122         trying(store, lookup);
2123         INSIST(dns_name_isabsolute(lookup->name));
2124
2125         isc_random_get(&id);
2126         lookup->sendmsg->id = (unsigned short)id & 0xFFFF;
2127         lookup->sendmsg->opcode = dns_opcode_query;
2128         lookup->msgcounter = 0;
2129         /*
2130          * If this is a trace request, completely disallow recursion, since
2131          * it's meaningless for traces.
2132          */
2133         if (lookup->trace || (lookup->ns_search_only && !lookup->trace_root))
2134                 lookup->recurse = ISC_FALSE;
2135
2136         if (lookup->recurse &&
2137             lookup->rdtype != dns_rdatatype_axfr &&
2138             lookup->rdtype != dns_rdatatype_ixfr) {
2139                 debug("recursive query");
2140                 lookup->sendmsg->flags |= DNS_MESSAGEFLAG_RD;
2141         }
2142
2143         /* XXX aaflag */
2144         if (lookup->aaonly) {
2145                 debug("AA query");
2146                 lookup->sendmsg->flags |= DNS_MESSAGEFLAG_AA;
2147         }
2148
2149         if (lookup->adflag) {
2150                 debug("AD query");
2151                 lookup->sendmsg->flags |= DNS_MESSAGEFLAG_AD;
2152         }
2153
2154         if (lookup->cdflag) {
2155                 debug("CD query");
2156                 lookup->sendmsg->flags |= DNS_MESSAGEFLAG_CD;
2157         }
2158
2159         dns_message_addname(lookup->sendmsg, lookup->name,
2160                             DNS_SECTION_QUESTION);
2161
2162         if (lookup->trace && lookup->trace_root) {
2163                 lookup->qrdtype = lookup->rdtype;
2164                 lookup->rdtype = dns_rdatatype_ns;
2165         }
2166
2167         if ((lookup->rdtype == dns_rdatatype_axfr) ||
2168             (lookup->rdtype == dns_rdatatype_ixfr)) {
2169                 /*
2170                  * Force TCP mode if we're doing an axfr.
2171                  */
2172                 if (lookup->rdtype == dns_rdatatype_axfr) {
2173                         lookup->doing_xfr = ISC_TRUE;
2174                         lookup->tcp_mode = ISC_TRUE;
2175                 } else if (lookup->tcp_mode) {
2176                         lookup->doing_xfr = ISC_TRUE;
2177                 }
2178         }
2179
2180         add_question(lookup->sendmsg, lookup->name, lookup->rdclass,
2181                      lookup->rdtype);
2182
2183         /* add_soa */
2184         if (lookup->rdtype == dns_rdatatype_ixfr)
2185                 insert_soa(lookup);
2186
2187         /* XXX Insist this? */
2188         lookup->tsigctx = NULL;
2189         lookup->querysig = NULL;
2190         if (key != NULL) {
2191                 debug("initializing keys");
2192                 result = dns_message_settsigkey(lookup->sendmsg, key);
2193                 check_result(result, "dns_message_settsigkey");
2194         }
2195
2196         lookup->sendspace = isc_mempool_get(commctx);
2197         if (lookup->sendspace == NULL)
2198                 fatal("memory allocation failure");
2199
2200         result = dns_compress_init(&cctx, -1, mctx);
2201         check_result(result, "dns_compress_init");
2202
2203         debug("starting to render the message");
2204         isc_buffer_init(&lookup->renderbuf, lookup->sendspace, COMMSIZE);
2205         result = dns_message_renderbegin(lookup->sendmsg, &cctx,
2206                                          &lookup->renderbuf);
2207         check_result(result, "dns_message_renderbegin");
2208         if (lookup->udpsize > 0 || lookup->dnssec || lookup->edns > -1) {
2209                 if (lookup->udpsize == 0)
2210                         lookup->udpsize = 4096;
2211                 if (lookup->edns < 0)
2212                         lookup->edns = 0;
2213                 add_opt(lookup->sendmsg, lookup->udpsize,
2214                         lookup->edns, lookup->dnssec, lookup->nsid);
2215         }
2216
2217         result = dns_message_rendersection(lookup->sendmsg,
2218                                            DNS_SECTION_QUESTION, 0);
2219         check_result(result, "dns_message_rendersection");
2220         result = dns_message_rendersection(lookup->sendmsg,
2221                                            DNS_SECTION_AUTHORITY, 0);
2222         check_result(result, "dns_message_rendersection");
2223         result = dns_message_renderend(lookup->sendmsg);
2224         check_result(result, "dns_message_renderend");
2225         debug("done rendering");
2226
2227         dns_compress_invalidate(&cctx);
2228
2229         /*
2230          * Force TCP mode if the request is larger than 512 bytes.
2231          */
2232         if (isc_buffer_usedlength(&lookup->renderbuf) > 512)
2233                 lookup->tcp_mode = ISC_TRUE;
2234
2235         lookup->pending = ISC_FALSE;
2236
2237         for (serv = ISC_LIST_HEAD(lookup->my_server_list);
2238              serv != NULL;
2239              serv = ISC_LIST_NEXT(serv, link)) {
2240                 query = isc_mem_allocate(mctx, sizeof(dig_query_t));
2241                 if (query == NULL)
2242                         fatal("memory allocation failure in %s:%d",
2243                               __FILE__, __LINE__);
2244                 debug("create query %p linked to lookup %p",
2245                        query, lookup);
2246                 query->lookup = lookup;
2247                 query->waiting_connect = ISC_FALSE;
2248                 query->waiting_senddone = ISC_FALSE;
2249                 query->pending_free = ISC_FALSE;
2250                 query->recv_made = ISC_FALSE;
2251                 query->first_pass = ISC_TRUE;
2252                 query->first_soa_rcvd = ISC_FALSE;
2253                 query->second_rr_rcvd = ISC_FALSE;
2254                 query->first_repeat_rcvd = ISC_FALSE;
2255                 query->warn_id = ISC_TRUE;
2256                 query->first_rr_serial = 0;
2257                 query->second_rr_serial = 0;
2258                 query->servname = serv->servername;
2259                 query->userarg = serv->userarg;
2260                 query->rr_count = 0;
2261                 query->msg_count = 0;
2262                 query->byte_count = 0;
2263                 ISC_LINK_INIT(query, link);
2264                 ISC_LIST_INIT(query->recvlist);
2265                 ISC_LIST_INIT(query->lengthlist);
2266                 query->sock = NULL;
2267                 query->recvspace = isc_mempool_get(commctx);
2268                 if (query->recvspace == NULL)
2269                         fatal("memory allocation failure");
2270
2271                 isc_buffer_init(&query->recvbuf, query->recvspace, COMMSIZE);
2272                 isc_buffer_init(&query->lengthbuf, query->lengthspace, 2);
2273                 isc_buffer_init(&query->slbuf, query->slspace, 2);
2274                 query->sendbuf = lookup->renderbuf;
2275
2276                 ISC_LINK_INIT(query, link);
2277                 ISC_LIST_ENQUEUE(lookup->q, query, link);
2278         }
2279         /* XXX qrflag, print_query, etc... */
2280         if (!ISC_LIST_EMPTY(lookup->q) && qr) {
2281                 extrabytes = 0;
2282                 printmessage(ISC_LIST_HEAD(lookup->q), lookup->sendmsg,
2283                              ISC_TRUE);
2284         }
2285 }
2286
2287 /*%
2288  * Event handler for send completion.  Track send counter, and clear out
2289  * the query if the send was canceled.
2290  */
2291 static void
2292 send_done(isc_task_t *_task, isc_event_t *event) {
2293         isc_socketevent_t *sevent = (isc_socketevent_t *)event;
2294         isc_buffer_t *b = NULL;
2295         dig_query_t *query, *next;
2296         dig_lookup_t *l;
2297
2298         REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE);
2299
2300         UNUSED(_task);
2301
2302         LOCK_LOOKUP;
2303
2304         debug("send_done()");
2305         sendcount--;
2306         debug("sendcount=%d", sendcount);
2307         INSIST(sendcount >= 0);
2308
2309         for  (b = ISC_LIST_HEAD(sevent->bufferlist);
2310               b != NULL;
2311               b = ISC_LIST_HEAD(sevent->bufferlist))
2312                 ISC_LIST_DEQUEUE(sevent->bufferlist, b, link);
2313
2314         query = event->ev_arg;
2315         query->waiting_senddone = ISC_FALSE;
2316         l = query->lookup;
2317
2318         if (l->ns_search_only && !l->trace_root) {
2319                 debug("sending next, since searching");
2320                 next = ISC_LIST_NEXT(query, link);
2321                 if (next != NULL)
2322                         send_udp(next);
2323         }
2324
2325         isc_event_free(&event);
2326
2327         if (query->pending_free)
2328                 isc_mem_free(mctx, query);
2329
2330         check_if_done();
2331         UNLOCK_LOOKUP;
2332 }
2333
2334 /*%
2335  * Cancel a lookup, sending isc_socket_cancel() requests to all outstanding
2336  * IO sockets.  The cancel handlers should take care of cleaning up the
2337  * query and lookup structures
2338  */
2339 static void
2340 cancel_lookup(dig_lookup_t *lookup) {
2341         dig_query_t *query, *next;
2342
2343         debug("cancel_lookup()");
2344         query = ISC_LIST_HEAD(lookup->q);
2345         while (query != NULL) {
2346                 next = ISC_LIST_NEXT(query, link);
2347                 if (query->sock != NULL) {
2348                         isc_socket_cancel(query->sock, global_task,
2349                                           ISC_SOCKCANCEL_ALL);
2350                         check_if_done();
2351                 } else {
2352                         clear_query(query);
2353                 }
2354                 query = next;
2355         }
2356         if (lookup->timer != NULL)
2357                 isc_timer_detach(&lookup->timer);
2358         lookup->pending = ISC_FALSE;
2359         lookup->retries = 0;
2360 }
2361
2362 static void
2363 bringup_timer(dig_query_t *query, unsigned int default_timeout) {
2364         dig_lookup_t *l;
2365         unsigned int local_timeout;
2366         isc_result_t result;
2367
2368         debug("bringup_timer()");
2369         /*
2370          * If the timer already exists, that means we're calling this
2371          * a second time (for a retry).  Don't need to recreate it,
2372          * just reset it.
2373          */
2374         l = query->lookup;
2375         if (ISC_LIST_NEXT(query, link) != NULL)
2376                 local_timeout = SERVER_TIMEOUT;
2377         else {
2378                 if (timeout == 0)
2379                         local_timeout = default_timeout;
2380                 else
2381                         local_timeout = timeout;
2382         }
2383         debug("have local timeout of %d", local_timeout);
2384         isc_interval_set(&l->interval, local_timeout, 0);
2385         if (l->timer != NULL)
2386                 isc_timer_detach(&l->timer);
2387         result = isc_timer_create(timermgr, isc_timertype_once, NULL,
2388                                   &l->interval, global_task, connect_timeout,
2389                                   l, &l->timer);
2390         check_result(result, "isc_timer_create");
2391 }
2392
2393 static void
2394 force_timeout(dig_lookup_t *l, dig_query_t *query) {
2395         isc_event_t *event;
2396
2397         event = isc_event_allocate(mctx, query, ISC_TIMEREVENT_IDLE,
2398                                    connect_timeout, l,
2399                                    sizeof(isc_event_t));
2400         if (event == NULL) {
2401                 fatal("isc_event_allocate: %s",
2402                       isc_result_totext(ISC_R_NOMEMORY));
2403         }
2404         isc_task_send(global_task, &event);
2405
2406         /*
2407          * The timer may have expired if, for example, get_address() takes
2408          * long time and the timer was running on a different thread.
2409          * We need to cancel the possible timeout event not to confuse
2410          * ourselves due to the duplicate events.
2411          */
2412         if (l->timer != NULL)
2413                 isc_timer_detach(&l->timer);
2414 }
2415
2416
2417 static void
2418 connect_done(isc_task_t *task, isc_event_t *event);
2419
2420 /*%
2421  * Unlike send_udp, this can't be called multiple times with the same
2422  * query.  When we retry TCP, we requeue the whole lookup, which should
2423  * start anew.
2424  */
2425 static void
2426 send_tcp_connect(dig_query_t *query) {
2427         isc_result_t result;
2428         dig_query_t *next;
2429         dig_lookup_t *l;
2430
2431         debug("send_tcp_connect(%p)", query);
2432
2433         l = query->lookup;
2434         query->waiting_connect = ISC_TRUE;
2435         query->lookup->current_query = query;
2436         result = get_address(query->servname, port, &query->sockaddr);
2437         if (result != ISC_R_SUCCESS) {
2438                 /*
2439                  * This servname doesn't have an address.  Try the next server
2440                  * by triggering an immediate 'timeout' (we lie, but the effect
2441                  * is the same).
2442                  */
2443                 force_timeout(l, query);
2444                 return;
2445         }
2446
2447         if (specified_source &&
2448             (isc_sockaddr_pf(&query->sockaddr) !=
2449              isc_sockaddr_pf(&bind_address))) {
2450                 printf(";; Skipping server %s, incompatible "
2451                        "address family\n", query->servname);
2452                 query->waiting_connect = ISC_FALSE;
2453                 next = ISC_LIST_NEXT(query, link);
2454                 l = query->lookup;
2455                 clear_query(query);
2456                 if (next == NULL) {
2457                         printf(";; No acceptable nameservers\n");
2458                         check_next_lookup(l);
2459                         return;
2460                 }
2461                 send_tcp_connect(next);
2462                 return;
2463         }
2464         INSIST(query->sock == NULL);
2465         result = isc_socket_create(socketmgr,
2466                                    isc_sockaddr_pf(&query->sockaddr),
2467                                    isc_sockettype_tcp, &query->sock);
2468         check_result(result, "isc_socket_create");
2469         sockcount++;
2470         debug("sockcount=%d", sockcount);
2471         if (specified_source)
2472                 result = isc_socket_bind(query->sock, &bind_address,
2473                                          ISC_SOCKET_REUSEADDRESS);
2474         else {
2475                 if ((isc_sockaddr_pf(&query->sockaddr) == AF_INET) &&
2476                     have_ipv4)
2477                         isc_sockaddr_any(&bind_any);
2478                 else
2479                         isc_sockaddr_any6(&bind_any);
2480                 result = isc_socket_bind(query->sock, &bind_any, 0);
2481         }
2482         check_result(result, "isc_socket_bind");
2483         bringup_timer(query, TCP_TIMEOUT);
2484         result = isc_socket_connect(query->sock, &query->sockaddr,
2485                                     global_task, connect_done, query);
2486         check_result(result, "isc_socket_connect");
2487         /*
2488          * If we're at the endgame of a nameserver search, we need to
2489          * immediately bring up all the queries.  Do it here.
2490          */
2491         if (l->ns_search_only && !l->trace_root) {
2492                 debug("sending next, since searching");
2493                 next = ISC_LIST_NEXT(query, link);
2494                 if (next != NULL)
2495                         send_tcp_connect(next);
2496         }
2497 }
2498
2499 /*%
2500  * Send a UDP packet to the remote nameserver, possible starting the
2501  * recv action as well.  Also make sure that the timer is running and
2502  * is properly reset.
2503  */
2504 static void
2505 send_udp(dig_query_t *query) {
2506         dig_lookup_t *l = NULL;
2507         isc_result_t result;
2508
2509         debug("send_udp(%p)", query);
2510
2511         l = query->lookup;
2512         bringup_timer(query, UDP_TIMEOUT);
2513         l->current_query = query;
2514         debug("working on lookup %p, query %p", query->lookup, query);
2515         if (!query->recv_made) {
2516                 /* XXX Check the sense of this, need assertion? */
2517                 query->waiting_connect = ISC_FALSE;
2518                 result = get_address(query->servname, port, &query->sockaddr);
2519                 if (result != ISC_R_SUCCESS) {
2520                         /* This servname doesn't have an address. */
2521                         force_timeout(l, query);
2522                         return;
2523                 }
2524
2525                 result = isc_socket_create(socketmgr,
2526                                            isc_sockaddr_pf(&query->sockaddr),
2527                                            isc_sockettype_udp, &query->sock);
2528                 check_result(result, "isc_socket_create");
2529                 sockcount++;
2530                 debug("sockcount=%d", sockcount);
2531                 if (specified_source) {
2532                         result = isc_socket_bind(query->sock, &bind_address,
2533                                                  ISC_SOCKET_REUSEADDRESS);
2534                 } else {
2535                         isc_sockaddr_anyofpf(&bind_any,
2536                                         isc_sockaddr_pf(&query->sockaddr));
2537                         result = isc_socket_bind(query->sock, &bind_any, 0);
2538                 }
2539                 check_result(result, "isc_socket_bind");
2540
2541                 query->recv_made = ISC_TRUE;
2542                 ISC_LINK_INIT(&query->recvbuf, link);
2543                 ISC_LIST_ENQUEUE(query->recvlist, &query->recvbuf,
2544                                  link);
2545                 debug("recving with lookup=%p, query=%p, sock=%p",
2546                       query->lookup, query, query->sock);
2547                 result = isc_socket_recvv(query->sock, &query->recvlist, 1,
2548                                           global_task, recv_done, query);
2549                 check_result(result, "isc_socket_recvv");
2550                 recvcount++;
2551                 debug("recvcount=%d", recvcount);
2552         }
2553         ISC_LIST_INIT(query->sendlist);
2554         ISC_LIST_ENQUEUE(query->sendlist, &query->sendbuf, link);
2555         debug("sending a request");
2556         TIME_NOW(&query->time_sent);
2557         INSIST(query->sock != NULL);
2558         query->waiting_senddone = ISC_TRUE;
2559         result = isc_socket_sendtov(query->sock, &query->sendlist,
2560                                     global_task, send_done, query,
2561                                     &query->sockaddr, NULL);
2562         check_result(result, "isc_socket_sendtov");
2563         sendcount++;
2564 }
2565
2566 /*%
2567  * IO timeout handler, used for both connect and recv timeouts.  If
2568  * retries are still allowed, either resend the UDP packet or queue a
2569  * new TCP lookup.  Otherwise, cancel the lookup.
2570  */
2571 static void
2572 connect_timeout(isc_task_t *task, isc_event_t *event) {
2573         dig_lookup_t *l = NULL;
2574         dig_query_t *query = NULL, *cq;
2575
2576         UNUSED(task);
2577         REQUIRE(event->ev_type == ISC_TIMEREVENT_IDLE);
2578
2579         debug("connect_timeout()");
2580
2581         LOCK_LOOKUP;
2582         l = event->ev_arg;
2583         query = l->current_query;
2584         isc_event_free(&event);
2585
2586         INSIST(!free_now);
2587
2588         if ((query != NULL) && (query->lookup->current_query != NULL) &&
2589             (ISC_LIST_NEXT(query->lookup->current_query, link) != NULL)) {
2590                 debug("trying next server...");
2591                 cq = query->lookup->current_query;
2592                 if (!l->tcp_mode)
2593                         send_udp(ISC_LIST_NEXT(cq, link));
2594                 else {
2595                         if (query->sock != NULL)
2596                                 isc_socket_cancel(query->sock, NULL,
2597                                                   ISC_SOCKCANCEL_ALL);
2598                         send_tcp_connect(ISC_LIST_NEXT(cq, link));
2599                 }
2600                 UNLOCK_LOOKUP;
2601                 return;
2602         }
2603
2604         if (l->retries > 1) {
2605                 if (!l->tcp_mode) {
2606                         l->retries--;
2607                         debug("resending UDP request to first server");
2608                         send_udp(ISC_LIST_HEAD(l->q));
2609                 } else {
2610                         debug("making new TCP request, %d tries left",
2611                               l->retries);
2612                         l->retries--;
2613                         requeue_lookup(l, ISC_TRUE);
2614                         cancel_lookup(l);
2615                         check_next_lookup(l);
2616                 }
2617         } else {
2618                 fputs(l->cmdline, stdout);
2619                 printf(";; connection timed out; no servers could be "
2620                        "reached\n");
2621                 cancel_lookup(l);
2622                 check_next_lookup(l);
2623                 if (exitcode < 9)
2624                         exitcode = 9;
2625         }
2626         UNLOCK_LOOKUP;
2627 }
2628
2629 /*%
2630  * Event handler for the TCP recv which gets the length header of TCP
2631  * packets.  Start the next recv of length bytes.
2632  */
2633 static void
2634 tcp_length_done(isc_task_t *task, isc_event_t *event) {
2635         isc_socketevent_t *sevent;
2636         isc_buffer_t *b = NULL;
2637         isc_result_t result;
2638         dig_query_t *query = NULL;
2639         dig_lookup_t *l;
2640         isc_uint16_t length;
2641
2642         REQUIRE(event->ev_type == ISC_SOCKEVENT_RECVDONE);
2643         INSIST(!free_now);
2644
2645         UNUSED(task);
2646
2647         debug("tcp_length_done()");
2648
2649         LOCK_LOOKUP;
2650         sevent = (isc_socketevent_t *)event;
2651         query = event->ev_arg;
2652
2653         recvcount--;
2654         INSIST(recvcount >= 0);
2655
2656         b = ISC_LIST_HEAD(sevent->bufferlist);
2657         INSIST(b ==  &query->lengthbuf);
2658         ISC_LIST_DEQUEUE(sevent->bufferlist, b, link);
2659
2660         if (sevent->result == ISC_R_CANCELED) {
2661                 isc_event_free(&event);
2662                 l = query->lookup;
2663                 clear_query(query);
2664                 check_next_lookup(l);
2665                 UNLOCK_LOOKUP;
2666                 return;
2667         }
2668         if (sevent->result != ISC_R_SUCCESS) {
2669                 char sockstr[ISC_SOCKADDR_FORMATSIZE];
2670                 isc_sockaddr_format(&query->sockaddr, sockstr,
2671                                     sizeof(sockstr));
2672                 printf(";; communications error to %s: %s\n",
2673                        sockstr, isc_result_totext(sevent->result));
2674                 l = query->lookup;
2675                 isc_socket_detach(&query->sock);
2676                 sockcount--;
2677                 debug("sockcount=%d", sockcount);
2678                 INSIST(sockcount >= 0);
2679                 isc_event_free(&event);
2680                 clear_query(query);
2681                 check_next_lookup(l);
2682                 UNLOCK_LOOKUP;
2683                 return;
2684         }
2685         length = isc_buffer_getuint16(b);
2686         if (length == 0) {
2687                 isc_event_free(&event);
2688                 launch_next_query(query, ISC_FALSE);
2689                 UNLOCK_LOOKUP;
2690                 return;
2691         }
2692
2693         /*
2694          * Even though the buffer was already init'ed, we need
2695          * to redo it now, to force the length we want.
2696          */
2697         isc_buffer_invalidate(&query->recvbuf);
2698         isc_buffer_init(&query->recvbuf, query->recvspace, length);
2699         ENSURE(ISC_LIST_EMPTY(query->recvlist));
2700         ISC_LINK_INIT(&query->recvbuf, link);
2701         ISC_LIST_ENQUEUE(query->recvlist, &query->recvbuf, link);
2702         debug("recving with lookup=%p, query=%p", query->lookup, query);
2703         result = isc_socket_recvv(query->sock, &query->recvlist, length, task,
2704                                   recv_done, query);
2705         check_result(result, "isc_socket_recvv");
2706         recvcount++;
2707         debug("resubmitted recv request with length %d, recvcount=%d",
2708               length, recvcount);
2709         isc_event_free(&event);
2710         UNLOCK_LOOKUP;
2711 }
2712
2713 /*%
2714  * For transfers that involve multiple recvs (XFR's in particular),
2715  * launch the next recv.
2716  */
2717 static void
2718 launch_next_query(dig_query_t *query, isc_boolean_t include_question) {
2719         isc_result_t result;
2720         dig_lookup_t *l;
2721
2722         INSIST(!free_now);
2723
2724         debug("launch_next_query()");
2725
2726         if (!query->lookup->pending) {
2727                 debug("ignoring launch_next_query because !pending");
2728                 isc_socket_detach(&query->sock);
2729                 sockcount--;
2730                 debug("sockcount=%d", sockcount);
2731                 INSIST(sockcount >= 0);
2732                 query->waiting_connect = ISC_FALSE;
2733                 l = query->lookup;
2734                 clear_query(query);
2735                 check_next_lookup(l);
2736                 return;
2737         }
2738
2739         isc_buffer_clear(&query->slbuf);
2740         isc_buffer_clear(&query->lengthbuf);
2741         isc_buffer_putuint16(&query->slbuf, (isc_uint16_t) query->sendbuf.used);
2742         ISC_LIST_INIT(query->sendlist);
2743         ISC_LINK_INIT(&query->slbuf, link);
2744         ISC_LIST_ENQUEUE(query->sendlist, &query->slbuf, link);
2745         if (include_question)
2746                 ISC_LIST_ENQUEUE(query->sendlist, &query->sendbuf, link);
2747         ISC_LINK_INIT(&query->lengthbuf, link);
2748         ISC_LIST_ENQUEUE(query->lengthlist, &query->lengthbuf, link);
2749
2750         result = isc_socket_recvv(query->sock, &query->lengthlist, 0,
2751                                   global_task, tcp_length_done, query);
2752         check_result(result, "isc_socket_recvv");
2753         recvcount++;
2754         debug("recvcount=%d", recvcount);
2755         if (!query->first_soa_rcvd) {
2756                 debug("sending a request in launch_next_query");
2757                 TIME_NOW(&query->time_sent);
2758                 query->waiting_senddone = ISC_TRUE;
2759                 result = isc_socket_sendv(query->sock, &query->sendlist,
2760                                           global_task, send_done, query);
2761                 check_result(result, "isc_socket_sendv");
2762                 sendcount++;
2763                 debug("sendcount=%d", sendcount);
2764         }
2765         query->waiting_connect = ISC_FALSE;
2766 #if 0
2767         check_next_lookup(query->lookup);
2768 #endif
2769         return;
2770 }
2771
2772 /*%
2773  * Event handler for TCP connect complete.  Make sure the connection was
2774  * successful, then pass into launch_next_query to actually send the
2775  * question.
2776  */
2777 static void
2778 connect_done(isc_task_t *task, isc_event_t *event) {
2779         isc_socketevent_t *sevent = NULL;
2780         dig_query_t *query = NULL, *next;
2781         dig_lookup_t *l;
2782
2783         UNUSED(task);
2784
2785         REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT);
2786         INSIST(!free_now);
2787
2788         debug("connect_done()");
2789
2790         LOCK_LOOKUP;
2791         sevent = (isc_socketevent_t *)event;
2792         query = sevent->ev_arg;
2793
2794         INSIST(query->waiting_connect);
2795
2796         query->waiting_connect = ISC_FALSE;
2797
2798         if (sevent->result == ISC_R_CANCELED) {
2799                 debug("in cancel handler");
2800                 isc_socket_detach(&query->sock);
2801                 INSIST(sockcount > 0);
2802                 sockcount--;
2803                 debug("sockcount=%d", sockcount);
2804                 query->waiting_connect = ISC_FALSE;
2805                 isc_event_free(&event);
2806                 l = query->lookup;
2807                 clear_query(query);
2808                 check_next_lookup(l);
2809                 UNLOCK_LOOKUP;
2810                 return;
2811         }
2812         if (sevent->result != ISC_R_SUCCESS) {
2813                 char sockstr[ISC_SOCKADDR_FORMATSIZE];
2814
2815                 debug("unsuccessful connection: %s",
2816                       isc_result_totext(sevent->result));
2817                 isc_sockaddr_format(&query->sockaddr, sockstr, sizeof(sockstr));
2818                 if (sevent->result != ISC_R_CANCELED)
2819                         printf(";; Connection to %s(%s) for %s failed: "
2820                                "%s.\n", sockstr,
2821                                query->servname, query->lookup->textname,
2822                                isc_result_totext(sevent->result));
2823                 isc_socket_detach(&query->sock);
2824                 sockcount--;
2825                 INSIST(sockcount >= 0);
2826                 /* XXX Clean up exitcodes */
2827                 if (exitcode < 9)
2828                         exitcode = 9;
2829                 debug("sockcount=%d", sockcount);
2830                 query->waiting_connect = ISC_FALSE;
2831                 isc_event_free(&event);
2832                 l = query->lookup;
2833                 if (l->current_query != NULL)
2834                         next = ISC_LIST_NEXT(l->current_query, link);
2835                 else
2836                         next = NULL;
2837                 clear_query(query);
2838                 if (next != NULL) {
2839                         bringup_timer(next, TCP_TIMEOUT);
2840                         send_tcp_connect(next);
2841                 } else {
2842                         check_next_lookup(l);
2843                 }
2844                 UNLOCK_LOOKUP;
2845                 return;
2846         }
2847         launch_next_query(query, ISC_TRUE);
2848         isc_event_free(&event);
2849         UNLOCK_LOOKUP;
2850 }
2851
2852 /*%
2853  * Check if the ongoing XFR needs more data before it's complete, using
2854  * the semantics of IXFR and AXFR protocols.  Much of the complexity of
2855  * this routine comes from determining when an IXFR is complete.
2856  * ISC_FALSE means more data is on the way, and the recv has been issued.
2857  */
2858 static isc_boolean_t
2859 check_for_more_data(dig_query_t *query, dns_message_t *msg,
2860                     isc_socketevent_t *sevent)
2861 {
2862         dns_rdataset_t *rdataset = NULL;
2863         dns_rdata_t rdata = DNS_RDATA_INIT;
2864         dns_rdata_soa_t soa;
2865         isc_uint32_t serial;
2866         isc_result_t result;
2867
2868         debug("check_for_more_data()");
2869
2870         /*
2871          * By the time we're in this routine, we know we're doing
2872          * either an AXFR or IXFR.  If there's no second_rr_type,
2873          * then we don't yet know which kind of answer we got back
2874          * from the server.  Here, we're going to walk through the
2875          * rr's in the message, acting as necessary whenever we hit
2876          * an SOA rr.
2877          */
2878
2879         query->msg_count++;
2880         query->byte_count += sevent->n;
2881         result = dns_message_firstname(msg, DNS_SECTION_ANSWER);
2882         if (result != ISC_R_SUCCESS) {
2883                 puts("; Transfer failed.");
2884                 return (ISC_TRUE);
2885         }
2886         do {
2887                 dns_name_t *name;
2888                 name = NULL;
2889                 dns_message_currentname(msg, DNS_SECTION_ANSWER,
2890                                         &name);
2891                 for (rdataset = ISC_LIST_HEAD(name->list);
2892                      rdataset != NULL;
2893                      rdataset = ISC_LIST_NEXT(rdataset, link)) {
2894                         result = dns_rdataset_first(rdataset);
2895                         if (result != ISC_R_SUCCESS)
2896                                 continue;
2897                         do {
2898                                 query->rr_count++;
2899                                 dns_rdata_reset(&rdata);
2900                                 dns_rdataset_current(rdataset, &rdata);
2901                                 /*
2902                                  * If this is the first rr, make sure
2903                                  * it's an SOA
2904                                  */
2905                                 if ((!query->first_soa_rcvd) &&
2906                                     (rdata.type != dns_rdatatype_soa)) {
2907                                         puts("; Transfer failed.  "
2908                                              "Didn't start with SOA answer.");
2909                                         return (ISC_TRUE);
2910                                 }
2911                                 if ((!query->second_rr_rcvd) &&
2912                                     (rdata.type != dns_rdatatype_soa)) {
2913                                         query->second_rr_rcvd = ISC_TRUE;
2914                                         query->second_rr_serial = 0;
2915                                         debug("got the second rr as nonsoa");
2916                                         goto next_rdata;
2917                                 }
2918
2919                                 /*
2920                                  * If the record is anything except an SOA
2921                                  * now, just continue on...
2922                                  */
2923                                 if (rdata.type != dns_rdatatype_soa)
2924                                         goto next_rdata;
2925                                 /* Now we have an SOA.  Work with it. */
2926                                 debug("got an SOA");
2927                                 result = dns_rdata_tostruct(&rdata, &soa, NULL);
2928                                 check_result(result, "dns_rdata_tostruct");
2929                                 serial = soa.serial;
2930                                 dns_rdata_freestruct(&soa);
2931                                 if (!query->first_soa_rcvd) {
2932                                         query->first_soa_rcvd = ISC_TRUE;
2933                                         query->first_rr_serial = serial;
2934                                         debug("this is the first %d",
2935                                                query->lookup->ixfr_serial);
2936                                         if (query->lookup->ixfr_serial >=
2937                                             serial)
2938                                                 goto doexit;
2939                                         goto next_rdata;
2940                                 }
2941                                 if (query->lookup->rdtype ==
2942                                     dns_rdatatype_axfr) {
2943                                         debug("doing axfr, got second SOA");
2944                                         goto doexit;
2945                                 }
2946                                 if (!query->second_rr_rcvd) {
2947                                         if (query->first_rr_serial == serial) {
2948                                                 debug("doing ixfr, got "
2949                                                       "empty zone");
2950                                                 goto doexit;
2951                                         }
2952                                         debug("this is the second %d",
2953                                                query->lookup->ixfr_serial);
2954                                         query->second_rr_rcvd = ISC_TRUE;
2955                                         query->second_rr_serial = serial;
2956                                         goto next_rdata;
2957                                 }
2958                                 if (query->second_rr_serial == 0) {
2959                                         /*
2960                                          * If the second RR was a non-SOA
2961                                          * record, and we're getting any
2962                                          * other SOA, then this is an
2963                                          * AXFR, and we're done.
2964                                          */
2965                                         debug("done, since axfr");
2966                                         goto doexit;
2967                                 }
2968                                 /*
2969                                  * If we get to this point, we're doing an
2970                                  * IXFR and have to start really looking
2971                                  * at serial numbers.
2972                                  */
2973                                 if (query->first_rr_serial == serial) {
2974                                         debug("got a match for ixfr");
2975                                         if (!query->first_repeat_rcvd) {
2976                                                 query->first_repeat_rcvd =
2977                                                         ISC_TRUE;
2978                                                 goto next_rdata;
2979                                         }
2980                                         debug("done with ixfr");
2981                                         goto doexit;
2982                                 }
2983                                 debug("meaningless soa %d", serial);
2984                         next_rdata:
2985                                 result = dns_rdataset_next(rdataset);
2986                         } while (result == ISC_R_SUCCESS);
2987                 }
2988                 result = dns_message_nextname(msg, DNS_SECTION_ANSWER);
2989         } while (result == ISC_R_SUCCESS);
2990         launch_next_query(query, ISC_FALSE);
2991         return (ISC_FALSE);
2992  doexit:
2993         received(sevent->n, &sevent->address, query);
2994         return (ISC_TRUE);
2995 }
2996
2997 /*%
2998  * Event handler for recv complete.  Perform whatever actions are necessary,
2999  * based on the specifics of the user's request.
3000  */
3001 static void
3002 recv_done(isc_task_t *task, isc_event_t *event) {
3003         isc_socketevent_t *sevent = NULL;
3004         dig_query_t *query = NULL;
3005         isc_buffer_t *b = NULL;
3006         dns_message_t *msg = NULL;
3007 #ifdef DIG_SIGCHASE
3008         dig_message_t *chase_msg = NULL;
3009         dig_message_t *chase_msg2 = NULL;
3010 #endif
3011         isc_result_t result;
3012         dig_lookup_t *n, *l;
3013         isc_boolean_t docancel = ISC_FALSE;
3014         isc_boolean_t match = ISC_TRUE;
3015         unsigned int parseflags;
3016         dns_messageid_t id;
3017         unsigned int msgflags;
3018 #ifdef DIG_SIGCHASE
3019         isc_result_t do_sigchase = ISC_FALSE;
3020
3021         dns_message_t *msg_temp = NULL;
3022         isc_region_t r;
3023         isc_buffer_t *buf = NULL;
3024 #endif
3025
3026         UNUSED(task);
3027         INSIST(!free_now);
3028
3029         debug("recv_done()");
3030
3031         LOCK_LOOKUP;
3032         recvcount--;
3033         debug("recvcount=%d", recvcount);
3034         INSIST(recvcount >= 0);
3035
3036         query = event->ev_arg;
3037         debug("lookup=%p, query=%p", query->lookup, query);
3038
3039         l = query->lookup;
3040
3041         REQUIRE(event->ev_type == ISC_SOCKEVENT_RECVDONE);
3042         sevent = (isc_socketevent_t *)event;
3043
3044         b = ISC_LIST_HEAD(sevent->bufferlist);
3045         INSIST(b == &query->recvbuf);
3046         ISC_LIST_DEQUEUE(sevent->bufferlist, &query->recvbuf, link);
3047
3048         if ((l->tcp_mode) && (l->timer != NULL))
3049                 isc_timer_touch(l->timer);
3050         if ((!l->pending && !l->ns_search_only) || cancel_now) {
3051                 debug("no longer pending.  Got %s",
3052                         isc_result_totext(sevent->result));
3053                 query->waiting_connect = ISC_FALSE;
3054
3055                 isc_event_free(&event);
3056                 clear_query(query);
3057                 check_next_lookup(l);
3058                 UNLOCK_LOOKUP;
3059                 return;
3060         }
3061
3062         if (sevent->result != ISC_R_SUCCESS) {
3063                 if (sevent->result == ISC_R_CANCELED) {
3064                         debug("in recv cancel handler");
3065                         query->waiting_connect = ISC_FALSE;
3066                 } else {
3067                         printf(";; communications error: %s\n",
3068                                isc_result_totext(sevent->result));
3069                         isc_socket_detach(&query->sock);
3070                         sockcount--;
3071                         debug("sockcount=%d", sockcount);
3072                         INSIST(sockcount >= 0);
3073                 }
3074                 isc_event_free(&event);
3075                 clear_query(query);
3076                 check_next_lookup(l);
3077                 UNLOCK_LOOKUP;
3078                 return;
3079         }
3080
3081         if (!l->tcp_mode &&
3082             !isc_sockaddr_compare(&sevent->address, &query->sockaddr,
3083                                   ISC_SOCKADDR_CMPADDR|
3084                                   ISC_SOCKADDR_CMPPORT|
3085                                   ISC_SOCKADDR_CMPSCOPE|
3086                                   ISC_SOCKADDR_CMPSCOPEZERO)) {
3087                 char buf1[ISC_SOCKADDR_FORMATSIZE];
3088                 char buf2[ISC_SOCKADDR_FORMATSIZE];
3089                 isc_sockaddr_t any;
3090
3091                 if (isc_sockaddr_pf(&query->sockaddr) == AF_INET)
3092                         isc_sockaddr_any(&any);
3093                 else
3094                         isc_sockaddr_any6(&any);
3095
3096                 /*
3097                 * We don't expect a match when the packet is
3098                 * sent to 0.0.0.0, :: or to a multicast addresses.
3099                 * XXXMPA broadcast needs to be handled here as well.
3100                 */
3101                 if ((!isc_sockaddr_eqaddr(&query->sockaddr, &any) &&
3102                      !isc_sockaddr_ismulticast(&query->sockaddr)) ||
3103                     isc_sockaddr_getport(&query->sockaddr) !=
3104                     isc_sockaddr_getport(&sevent->address)) {
3105                         isc_sockaddr_format(&sevent->address, buf1,
3106                         sizeof(buf1));
3107                         isc_sockaddr_format(&query->sockaddr, buf2,
3108                         sizeof(buf2));
3109                         printf(";; reply from unexpected source: %s,"
3110                         " expected %s\n", buf1, buf2);
3111                         match = ISC_FALSE;
3112                 }
3113         }
3114
3115         result = dns_message_peekheader(b, &id, &msgflags);
3116         if (result != ISC_R_SUCCESS || l->sendmsg->id != id) {
3117                 match = ISC_FALSE;
3118                 if (l->tcp_mode) {
3119                         isc_boolean_t fail = ISC_TRUE;
3120                         if (result == ISC_R_SUCCESS) {
3121                                 if (!query->first_soa_rcvd ||
3122                                      query->warn_id)
3123                                         printf(";; %s: ID mismatch: "
3124                                                "expected ID %u, got %u\n",
3125                                                query->first_soa_rcvd ?
3126                                                "WARNING" : "ERROR",
3127                                                l->sendmsg->id, id);
3128                                 if (query->first_soa_rcvd)
3129                                         fail = ISC_FALSE;
3130                                 query->warn_id = ISC_FALSE;
3131                         } else
3132                                 printf(";; ERROR: short "
3133                                        "(< header size) message\n");
3134                         if (fail) {
3135                                 isc_event_free(&event);
3136                                 clear_query(query);
3137                                 check_next_lookup(l);
3138                                 UNLOCK_LOOKUP;
3139                                 return;
3140                         }
3141                         match = ISC_TRUE;
3142                 } else if (result == ISC_R_SUCCESS)
3143                         printf(";; Warning: ID mismatch: "
3144                                "expected ID %u, got %u\n", l->sendmsg->id, id);
3145                 else
3146                         printf(";; Warning: short "
3147                                "(< header size) message received\n");
3148         }
3149
3150         if (result == ISC_R_SUCCESS && (msgflags & DNS_MESSAGEFLAG_QR) == 0)
3151                 printf(";; Warning: query response not set\n");
3152
3153         if (!match)
3154                 goto udp_mismatch;
3155
3156         result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &msg);
3157         check_result(result, "dns_message_create");
3158
3159         if (key != NULL) {
3160                 if (l->querysig == NULL) {
3161                         debug("getting initial querysig");
3162                         result = dns_message_getquerytsig(l->sendmsg, mctx,
3163                                                           &l->querysig);
3164                         check_result(result, "dns_message_getquerytsig");
3165                 }
3166                 result = dns_message_setquerytsig(msg, l->querysig);
3167                 check_result(result, "dns_message_setquerytsig");
3168                 result = dns_message_settsigkey(msg, key);
3169                 check_result(result, "dns_message_settsigkey");
3170                 msg->tsigctx = l->tsigctx;
3171                 l->tsigctx = NULL;
3172                 if (l->msgcounter != 0)
3173                         msg->tcp_continuation = 1;
3174                 l->msgcounter++;
3175         }
3176
3177         debug("before parse starts");
3178         parseflags = DNS_MESSAGEPARSE_PRESERVEORDER;
3179 #ifdef DIG_SIGCHASE
3180         if (!l->sigchase) {
3181                 do_sigchase = ISC_FALSE;
3182         } else {
3183                 parseflags = 0;
3184                 do_sigchase = ISC_TRUE;
3185         }
3186 #endif
3187         if (l->besteffort) {
3188                 parseflags |= DNS_MESSAGEPARSE_BESTEFFORT;
3189                 parseflags |= DNS_MESSAGEPARSE_IGNORETRUNCATION;
3190         }
3191         result = dns_message_parse(msg, b, parseflags);
3192         if (result == DNS_R_RECOVERABLE) {
3193                 printf(";; Warning: Message parser reports malformed "
3194                        "message packet.\n");
3195                 result = ISC_R_SUCCESS;
3196         }
3197         if (result != ISC_R_SUCCESS) {
3198                 printf(";; Got bad packet: %s\n", isc_result_totext(result));
3199                 hex_dump(b);
3200                 query->waiting_connect = ISC_FALSE;
3201                 dns_message_destroy(&msg);
3202                 isc_event_free(&event);
3203                 clear_query(query);
3204                 cancel_lookup(l);
3205                 check_next_lookup(l);
3206                 UNLOCK_LOOKUP;
3207                 return;
3208         }
3209         if (msg->counts[DNS_SECTION_QUESTION] != 0) {
3210                 match = ISC_TRUE;
3211                 for (result = dns_message_firstname(msg, DNS_SECTION_QUESTION);
3212                      result == ISC_R_SUCCESS && match;
3213                      result = dns_message_nextname(msg, DNS_SECTION_QUESTION)) {
3214                         dns_name_t *name = NULL;
3215                         dns_rdataset_t *rdataset;
3216
3217                         dns_message_currentname(msg, DNS_SECTION_QUESTION,
3218                                                 &name);
3219                         for (rdataset = ISC_LIST_HEAD(name->list);
3220                              rdataset != NULL;
3221                              rdataset = ISC_LIST_NEXT(rdataset, link)) {
3222                                 if (l->rdtype != rdataset->type ||
3223                                     l->rdclass != rdataset->rdclass ||
3224                                     !dns_name_equal(l->name, name)) {
3225                                         char namestr[DNS_NAME_FORMATSIZE];
3226                                         char typebuf[DNS_RDATATYPE_FORMATSIZE];
3227                                         char classbuf[DNS_RDATACLASS_FORMATSIZE];
3228                                         dns_name_format(name, namestr,
3229                                                         sizeof(namestr));
3230                                         dns_rdatatype_format(rdataset->type,
3231                                                              typebuf,
3232                                                              sizeof(typebuf));
3233                                         dns_rdataclass_format(rdataset->rdclass,
3234                                                               classbuf,
3235                                                               sizeof(classbuf));
3236                                         printf(";; Question section mismatch: "
3237                                                "got %s/%s/%s\n",
3238                                                namestr, typebuf, classbuf);
3239                                         match = ISC_FALSE;
3240                                 }
3241                         }
3242                 }
3243                 if (!match) {
3244                         dns_message_destroy(&msg);
3245                         if (l->tcp_mode) {
3246                                 isc_event_free(&event);
3247                                 clear_query(query);
3248                                 check_next_lookup(l);
3249                                 UNLOCK_LOOKUP;
3250                                 return;
3251                         } else
3252                                 goto udp_mismatch;
3253                 }
3254         }
3255         if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0 &&
3256             !l->ignore && !l->tcp_mode) {
3257                 printf(";; Truncated, retrying in TCP mode.\n");
3258                 n = requeue_lookup(l, ISC_TRUE);
3259                 n->tcp_mode = ISC_TRUE;
3260                 n->origin = query->lookup->origin;
3261                 dns_message_destroy(&msg);
3262                 isc_event_free(&event);
3263                 clear_query(query);
3264                 cancel_lookup(l);
3265                 check_next_lookup(l);
3266                 UNLOCK_LOOKUP;
3267                 return;
3268         }
3269         if ((msg->rcode == dns_rcode_servfail && !l->servfail_stops) ||
3270             (check_ra && (msg->flags & DNS_MESSAGEFLAG_RA) == 0 && l->recurse))
3271         {
3272                 dig_query_t *next = ISC_LIST_NEXT(query, link);
3273                 if (l->current_query == query)
3274                         l->current_query = NULL;
3275                 if (next != NULL) {
3276                         debug("sending query %p\n", next);
3277                         if (l->tcp_mode)
3278                                 send_tcp_connect(next);
3279                         else
3280                                 send_udp(next);
3281                 }
3282                 /*
3283                  * If our query is at the head of the list and there
3284                  * is no next, we're the only one left, so fall
3285                  * through to print the message.
3286                  */
3287                 if ((ISC_LIST_HEAD(l->q) != query) ||
3288                     (ISC_LIST_NEXT(query, link) != NULL)) {
3289                         if( l->comments == ISC_TRUE )
3290                                 printf(";; Got %s from %s, "
3291                                        "trying next server\n",
3292                                        msg->rcode == dns_rcode_servfail ?
3293                                        "SERVFAIL reply" :
3294                                        "recursion not available",
3295                                        query->servname);
3296                         clear_query(query);
3297                         check_next_lookup(l);
3298                         dns_message_destroy(&msg);
3299                         isc_event_free(&event);
3300                         UNLOCK_LOOKUP;
3301                         return;
3302                 }
3303         }
3304
3305         if (key != NULL) {
3306                 result = dns_tsig_verify(&query->recvbuf, msg, NULL, NULL);
3307                 if (result != ISC_R_SUCCESS) {
3308                         printf(";; Couldn't verify signature: %s\n",
3309                                isc_result_totext(result));
3310                         validated = ISC_FALSE;
3311                 }
3312                 l->tsigctx = msg->tsigctx;
3313                 msg->tsigctx = NULL;
3314                 if (l->querysig != NULL) {
3315                         debug("freeing querysig buffer %p", l->querysig);
3316                         isc_buffer_free(&l->querysig);
3317                 }
3318                 result = dns_message_getquerytsig(msg, mctx, &l->querysig);
3319                 check_result(result,"dns_message_getquerytsig");
3320         }
3321
3322         extrabytes = isc_buffer_remaininglength(b);
3323
3324         debug("after parse");
3325         if (l->doing_xfr && l->xfr_q == NULL) {
3326                 l->xfr_q = query;
3327                 /*
3328                  * Once we are in the XFR message, increase
3329                  * the timeout to much longer, so brief network
3330                  * outages won't cause the XFR to abort
3331                  */
3332                 if (timeout != INT_MAX && l->timer != NULL) {
3333                         unsigned int local_timeout;
3334
3335                         if (timeout == 0) {
3336                                 if (l->tcp_mode)
3337                                         local_timeout = TCP_TIMEOUT * 4;
3338                                 else
3339                                         local_timeout = UDP_TIMEOUT * 4;
3340                         } else {
3341                                 if (timeout < (INT_MAX / 4))
3342                                         local_timeout = timeout * 4;
3343                                 else
3344                                         local_timeout = INT_MAX;
3345                         }
3346                         debug("have local timeout of %d", local_timeout);
3347                         isc_interval_set(&l->interval, local_timeout, 0);
3348                         result = isc_timer_reset(l->timer,
3349                                                  isc_timertype_once,
3350                                                  NULL,
3351                                                  &l->interval,
3352                                                  ISC_FALSE);
3353                         check_result(result, "isc_timer_reset");
3354                 }
3355         }
3356
3357         if (!l->doing_xfr || l->xfr_q == query) {
3358                 if (msg->rcode != dns_rcode_noerror &&
3359                     (l->origin != NULL || l->need_search)) {
3360                         if (!next_origin(msg, query) || showsearch) {
3361                                 printmessage(query, msg, ISC_TRUE);
3362                                 received(b->used, &sevent->address, query);
3363                         }
3364                 } else if (!l->trace && !l->ns_search_only) {
3365 #ifdef DIG_SIGCHASE
3366                         if (!do_sigchase)
3367 #endif
3368                                 printmessage(query, msg, ISC_TRUE);
3369                 } else if (l->trace) {
3370                         int n = 0;
3371                         int count = msg->counts[DNS_SECTION_ANSWER];
3372
3373                         debug("in TRACE code");
3374                         if (!l->ns_search_only)
3375                                 printmessage(query, msg, ISC_TRUE);
3376
3377                         l->rdtype = l->qrdtype;
3378                         if (l->trace_root || (l->ns_search_only && count > 0)) {
3379                                 if (!l->trace_root)
3380                                         l->rdtype = dns_rdatatype_soa;
3381                                 n = followup_lookup(msg, query,
3382                                                     DNS_SECTION_ANSWER);
3383                                 l->trace_root = ISC_FALSE;
3384                         } else if (count == 0)
3385                                 n = followup_lookup(msg, query,
3386                                                     DNS_SECTION_AUTHORITY);
3387                         if (n == 0)
3388                                 docancel = ISC_TRUE;
3389                 } else {
3390                         debug("in NSSEARCH code");
3391
3392                         if (l->trace_root) {
3393                                 /*
3394                                  * This is the initial NS query.
3395                                  */
3396                                 int n;
3397
3398                                 l->rdtype = dns_rdatatype_soa;
3399                                 n = followup_lookup(msg, query,
3400                                                     DNS_SECTION_ANSWER);
3401                                 if (n == 0)
3402                                         docancel = ISC_TRUE;
3403                                 l->trace_root = ISC_FALSE;
3404                         } else
3405 #ifdef DIG_SIGCHASE
3406                                 if (!do_sigchase)
3407 #endif
3408                                 printmessage(query, msg, ISC_TRUE);
3409                 }
3410 #ifdef DIG_SIGCHASE
3411                 if (do_sigchase) {
3412                         chase_msg = isc_mem_allocate(mctx,
3413                                                      sizeof(dig_message_t));
3414                         if (chase_msg == NULL) {
3415                                 fatal("Memory allocation failure in %s:%d",
3416                                       __FILE__, __LINE__);
3417                         }
3418                         ISC_LIST_INITANDAPPEND(chase_message_list, chase_msg,
3419                                                link);
3420                         if (dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE,
3421                                                &msg_temp) != ISC_R_SUCCESS) {
3422                                 fatal("dns_message_create in %s:%d",
3423                                       __FILE__, __LINE__);
3424                         }
3425
3426                         isc_buffer_usedregion(b, &r);
3427                         result = isc_buffer_allocate(mctx, &buf, r.length);
3428
3429                         check_result(result, "isc_buffer_allocate");
3430                         result =  isc_buffer_copyregion(buf, &r);
3431                         check_result(result, "isc_buffer_copyregion");
3432
3433                         result =  dns_message_parse(msg_temp, buf, 0);
3434
3435                         isc_buffer_free(&buf);
3436                         chase_msg->msg = msg_temp;
3437
3438                         chase_msg2 = isc_mem_allocate(mctx,
3439                                                       sizeof(dig_message_t));
3440                         if (chase_msg2 == NULL) {
3441                                 fatal("Memory allocation failure in %s:%d",
3442                                       __FILE__, __LINE__);
3443                         }
3444                         ISC_LIST_INITANDAPPEND(chase_message_list2, chase_msg2,
3445                                                link);
3446                         chase_msg2->msg = msg;
3447                 }
3448 #endif
3449         }
3450
3451 #ifdef DIG_SIGCHASE
3452         if (l->sigchase && ISC_LIST_EMPTY(lookup_list)) {
3453                 sigchase(msg_temp);
3454         }
3455 #endif
3456
3457         if (l->pending)
3458                 debug("still pending.");
3459         if (l->doing_xfr) {
3460                 if (query != l->xfr_q) {
3461                         dns_message_destroy(&msg);
3462                         isc_event_free(&event);
3463                         query->waiting_connect = ISC_FALSE;
3464                         UNLOCK_LOOKUP;
3465                         return;
3466                 }
3467                 if (!docancel)
3468                         docancel = check_for_more_data(query, msg, sevent);
3469                 if (docancel) {
3470                         dns_message_destroy(&msg);
3471                         clear_query(query);
3472                         cancel_lookup(l);
3473                         check_next_lookup(l);
3474                 }
3475         } else {
3476
3477                 if (msg->rcode == dns_rcode_noerror || l->origin == NULL) {
3478
3479 #ifdef DIG_SIGCHASE
3480                         if (!l->sigchase)
3481 #endif
3482                                 received(b->used, &sevent->address, query);
3483                 }
3484
3485                 if (!query->lookup->ns_search_only)
3486                         query->lookup->pending = ISC_FALSE;
3487                 if (!query->lookup->ns_search_only ||
3488                     query->lookup->trace_root || docancel) {
3489 #ifdef DIG_SIGCHASE
3490                         if (!do_sigchase)
3491 #endif
3492                                 dns_message_destroy(&msg);
3493
3494                         cancel_lookup(l);
3495                 }
3496                 clear_query(query);
3497                 check_next_lookup(l);
3498         }
3499         if (msg != NULL) {
3500 #ifdef DIG_SIGCHASE
3501                 if (do_sigchase)
3502                         msg = NULL;
3503                 else
3504 #endif
3505                         dns_message_destroy(&msg);
3506         }
3507         isc_event_free(&event);
3508         UNLOCK_LOOKUP;
3509         return;
3510
3511  udp_mismatch:
3512         isc_buffer_invalidate(&query->recvbuf);
3513         isc_buffer_init(&query->recvbuf, query->recvspace, COMMSIZE);
3514         ISC_LIST_ENQUEUE(query->recvlist, &query->recvbuf, link);
3515         result = isc_socket_recvv(query->sock, &query->recvlist, 1,
3516                                   global_task, recv_done, query);
3517         check_result(result, "isc_socket_recvv");
3518         recvcount++;
3519         isc_event_free(&event);
3520         UNLOCK_LOOKUP;
3521         return;
3522 }
3523
3524 /*%
3525  * Turn a name into an address, using system-supplied routines.  This is
3526  * used in looking up server names, etc... and needs to use system-supplied
3527  * routines, since they may be using a non-DNS system for these lookups.
3528  */
3529 isc_result_t
3530 get_address(char *host, in_port_t port, isc_sockaddr_t *sockaddr) {
3531         int count;
3532         isc_result_t result;
3533
3534         isc_app_block();
3535         result = bind9_getaddresses(host, port, sockaddr, 1, &count);
3536         isc_app_unblock();
3537         if (result != ISC_R_SUCCESS)
3538                 return (result);
3539
3540         INSIST(count == 1);
3541
3542         return (ISC_R_SUCCESS);
3543 }
3544
3545 /*%
3546  * Initiate either a TCP or UDP lookup
3547  */
3548 void
3549 do_lookup(dig_lookup_t *lookup) {
3550
3551         REQUIRE(lookup != NULL);
3552
3553         debug("do_lookup()");
3554         lookup->pending = ISC_TRUE;
3555         if (lookup->tcp_mode)
3556                 send_tcp_connect(ISC_LIST_HEAD(lookup->q));
3557         else
3558                 send_udp(ISC_LIST_HEAD(lookup->q));
3559 }
3560
3561 /*%
3562  * Start everything in action upon task startup.
3563  */
3564 void
3565 onrun_callback(isc_task_t *task, isc_event_t *event) {
3566         UNUSED(task);
3567
3568         isc_event_free(&event);
3569         LOCK_LOOKUP;
3570         start_lookup();
3571         UNLOCK_LOOKUP;
3572 }
3573
3574 /*%
3575  * Make everything on the lookup queue go away.  Mainly used by the
3576  * SIGINT handler.
3577  */
3578 void
3579 cancel_all(void) {
3580         dig_lookup_t *l, *n;
3581         dig_query_t *q, *nq;
3582
3583         debug("cancel_all()");
3584
3585         LOCK_LOOKUP;
3586         if (free_now) {
3587                 UNLOCK_LOOKUP;
3588                 return;
3589         }
3590         cancel_now = ISC_TRUE;
3591         if (current_lookup != NULL) {
3592                 if (current_lookup->timer != NULL)
3593                         isc_timer_detach(&current_lookup->timer);
3594                 q = ISC_LIST_HEAD(current_lookup->q);
3595                 while (q != NULL) {
3596                         debug("canceling query %p, belonging to %p",
3597                               q, current_lookup);
3598                         nq = ISC_LIST_NEXT(q, link);
3599                         if (q->sock != NULL) {
3600                                 isc_socket_cancel(q->sock, NULL,
3601                                                   ISC_SOCKCANCEL_ALL);
3602                         } else {
3603                                 clear_query(q);
3604                         }
3605                         q = nq;
3606                 }
3607         }
3608         l = ISC_LIST_HEAD(lookup_list);
3609         while (l != NULL) {
3610                 n = ISC_LIST_NEXT(l, link);
3611                 ISC_LIST_DEQUEUE(lookup_list, l, link);
3612                 try_clear_lookup(l);
3613                 l = n;
3614         }
3615         UNLOCK_LOOKUP;
3616 }
3617
3618 /*%
3619  * Destroy all of the libs we are using, and get everything ready for a
3620  * clean shutdown.
3621  */
3622 void
3623 destroy_libs(void) {
3624 #ifdef DIG_SIGCHASE
3625         void * ptr;
3626         dig_message_t *chase_msg;
3627 #endif
3628 #ifdef WITH_IDN
3629         isc_result_t result;
3630 #endif
3631
3632         debug("destroy_libs()");
3633         if (global_task != NULL) {
3634                 debug("freeing task");
3635                 isc_task_detach(&global_task);
3636         }
3637         /*
3638          * The taskmgr_destroy() call blocks until all events are cleared
3639          * from the task.
3640          */
3641         if (taskmgr != NULL) {
3642                 debug("freeing taskmgr");
3643                 isc_taskmgr_destroy(&taskmgr);
3644         }
3645         LOCK_LOOKUP;
3646         REQUIRE(sockcount == 0);
3647         REQUIRE(recvcount == 0);
3648         REQUIRE(sendcount == 0);
3649
3650         INSIST(ISC_LIST_HEAD(lookup_list) == NULL);
3651         INSIST(current_lookup == NULL);
3652         INSIST(!free_now);
3653
3654         free_now = ISC_TRUE;
3655
3656         lwres_conf_clear(lwctx);
3657         lwres_context_destroy(&lwctx);
3658
3659         flush_server_list();
3660
3661         clear_searchlist();
3662
3663 #ifdef WITH_IDN
3664         result = dns_name_settotextfilter(NULL);
3665         check_result(result, "dns_name_settotextfilter");
3666 #endif
3667         dns_name_destroy();
3668
3669         if (commctx != NULL) {
3670                 debug("freeing commctx");
3671                 isc_mempool_destroy(&commctx);
3672         }
3673         if (socketmgr != NULL) {
3674                 debug("freeing socketmgr");
3675                 isc_socketmgr_destroy(&socketmgr);
3676         }
3677         if (timermgr != NULL) {
3678                 debug("freeing timermgr");
3679                 isc_timermgr_destroy(&timermgr);
3680         }
3681         if (key != NULL) {
3682                 debug("freeing key %p", key);
3683                 dns_tsigkey_detach(&key);
3684         }
3685         if (namebuf != NULL)
3686                 isc_buffer_free(&namebuf);
3687
3688         if (is_dst_up) {
3689                 debug("destroy DST lib");
3690                 dst_lib_destroy();
3691                 is_dst_up = ISC_FALSE;
3692         }
3693         if (entp != NULL) {
3694                 debug("detach from entropy");
3695                 isc_entropy_detach(&entp);
3696         }
3697
3698         UNLOCK_LOOKUP;
3699         DESTROYLOCK(&lookup_lock);
3700 #ifdef DIG_SIGCHASE
3701
3702         debug("Destroy the messages kept for sigchase");
3703         /* Destroy the messages kept for sigchase */
3704         chase_msg = ISC_LIST_HEAD(chase_message_list);
3705
3706         while (chase_msg != NULL) {
3707                 INSIST(chase_msg->msg != NULL);
3708                 dns_message_destroy(&(chase_msg->msg));
3709                 ptr = chase_msg;
3710                 chase_msg = ISC_LIST_NEXT(chase_msg, link);
3711                 isc_mem_free(mctx, ptr);
3712         }
3713
3714         chase_msg = ISC_LIST_HEAD(chase_message_list2);
3715
3716         while (chase_msg != NULL) {
3717                 INSIST(chase_msg->msg != NULL);
3718                 dns_message_destroy(&(chase_msg->msg));
3719                 ptr = chase_msg;
3720                 chase_msg = ISC_LIST_NEXT(chase_msg, link);
3721                 isc_mem_free(mctx, ptr);
3722         }
3723         if (dns_name_dynamic(&chase_name))
3724                 free_name(&chase_name, mctx);
3725 #if DIG_SIGCHASE_TD
3726         if (dns_name_dynamic(&chase_current_name))
3727                 free_name(&chase_current_name, mctx);
3728         if (dns_name_dynamic(&chase_authority_name))
3729                 free_name(&chase_authority_name, mctx);
3730 #endif
3731 #if DIG_SIGCHASE_BU
3732         if (dns_name_dynamic(&chase_signame))
3733                 free_name(&chase_signame, mctx);
3734 #endif
3735
3736 #endif
3737         debug("Removing log context");
3738         isc_log_destroy(&lctx);
3739
3740         debug("Destroy memory");
3741         if (memdebugging != 0)
3742                 isc_mem_stats(mctx, stderr);
3743         if (mctx != NULL)
3744                 isc_mem_destroy(&mctx);
3745 }
3746
3747 #ifdef WITH_IDN
3748 static void
3749 initialize_idn(void) {
3750         idn_result_t r;
3751         isc_result_t result;
3752
3753 #ifdef HAVE_SETLOCALE
3754         /* Set locale */
3755         (void)setlocale(LC_ALL, "");
3756 #endif
3757         /* Create configuration context. */
3758         r = idn_nameinit(1);
3759         if (r != idn_success)
3760                 fatal("idn api initialization failed: %s",
3761                       idn_result_tostring(r));
3762
3763         /* Set domain name -> text post-conversion filter. */
3764         result = dns_name_settotextfilter(output_filter);
3765         check_result(result, "dns_name_settotextfilter");
3766 }
3767
3768 static isc_result_t
3769 output_filter(isc_buffer_t *buffer, unsigned int used_org,
3770               isc_boolean_t absolute)
3771 {
3772         char tmp1[MAXDLEN], tmp2[MAXDLEN];
3773         size_t fromlen, tolen;
3774         isc_boolean_t end_with_dot;
3775
3776         /*
3777          * Copy contents of 'buffer' to 'tmp1', supply trailing dot
3778          * if 'absolute' is true, and terminate with NUL.
3779          */
3780         fromlen = isc_buffer_usedlength(buffer) - used_org;
3781         if (fromlen >= MAXDLEN)
3782                 return (ISC_R_SUCCESS);
3783         memcpy(tmp1, (char *)isc_buffer_base(buffer) + used_org, fromlen);
3784         end_with_dot = (tmp1[fromlen - 1] == '.') ? ISC_TRUE : ISC_FALSE;
3785         if (absolute && !end_with_dot) {
3786                 fromlen++;
3787                 if (fromlen >= MAXDLEN)
3788                         return (ISC_R_SUCCESS);
3789                 tmp1[fromlen - 1] = '.';
3790         }
3791         tmp1[fromlen] = '\0';
3792
3793         /*
3794          * Convert contents of 'tmp1' to local encoding.
3795          */
3796         if (idn_decodename(IDN_DECODE_APP, tmp1, tmp2, MAXDLEN) != idn_success)
3797                 return (ISC_R_SUCCESS);
3798         strcpy(tmp1, tmp2);
3799
3800         /*
3801          * Copy the converted contents in 'tmp1' back to 'buffer'.
3802          * If we have appended trailing dot, remove it.
3803          */
3804         tolen = strlen(tmp1);
3805         if (absolute && !end_with_dot && tmp1[tolen - 1] == '.')
3806                 tolen--;
3807
3808         if (isc_buffer_length(buffer) < used_org + tolen)
3809                 return (ISC_R_NOSPACE);
3810
3811         isc_buffer_subtract(buffer, isc_buffer_usedlength(buffer) - used_org);
3812         memcpy(isc_buffer_used(buffer), tmp1, tolen);
3813         isc_buffer_add(buffer, tolen);
3814
3815         return (ISC_R_SUCCESS);
3816 }
3817
3818 static idn_result_t
3819 append_textname(char *name, const char *origin, size_t namesize) {
3820         size_t namelen = strlen(name);
3821         size_t originlen = strlen(origin);
3822
3823         /* Already absolute? */
3824         if (namelen > 0 && name[namelen - 1] == '.')
3825                 return idn_success;
3826
3827         /* Append dot and origin */
3828
3829         if (namelen + 1 + originlen >= namesize)
3830                 return idn_buffer_overflow;
3831
3832         name[namelen++] = '.';
3833         (void)strcpy(name + namelen, origin);
3834         return idn_success;
3835 }
3836
3837 static void
3838 idn_check_result(idn_result_t r, const char *msg) {
3839         if (r != idn_success) {
3840                 exitcode = 1;
3841                 fatal("%s: %s", msg, idn_result_tostring(r));
3842         }
3843 }
3844 #endif /* WITH_IDN */
3845
3846 #ifdef DIG_SIGCHASE
3847 void
3848 print_type(dns_rdatatype_t type)
3849 {
3850         isc_buffer_t * b = NULL;
3851         isc_result_t result;
3852         isc_region_t r;
3853
3854         result = isc_buffer_allocate(mctx, &b, 4000);
3855         check_result(result, "isc_buffer_allocate");
3856
3857         result = dns_rdatatype_totext(type, b);
3858         check_result(result, "print_type");
3859
3860         isc_buffer_usedregion(b, &r);
3861         r.base[r.length] = '\0';
3862
3863         printf("%s", r.base);
3864
3865         isc_buffer_free(&b);
3866 }
3867
3868 void
3869 dump_database_section(dns_message_t *msg, int section)
3870 {
3871         dns_name_t *msg_name=NULL;
3872
3873         dns_rdataset_t *rdataset;
3874
3875         do {
3876                 dns_message_currentname(msg, section, &msg_name);
3877
3878                 for (rdataset = ISC_LIST_HEAD(msg_name->list); rdataset != NULL;
3879                      rdataset = ISC_LIST_NEXT(rdataset, link)) {
3880                         dns_name_print(msg_name, stdout);
3881                         printf("\n");
3882                         print_rdataset(msg_name, rdataset, mctx);
3883                         printf("end\n");
3884                 }
3885                 msg_name = NULL;
3886         } while (dns_message_nextname(msg, section) == ISC_R_SUCCESS);
3887 }
3888
3889 void
3890 dump_database(void) {
3891         dig_message_t * msg;
3892
3893         for (msg = ISC_LIST_HEAD(chase_message_list);  msg != NULL;
3894              msg = ISC_LIST_NEXT(msg, link)) {
3895                 if (dns_message_firstname(msg->msg, DNS_SECTION_ANSWER)
3896                     == ISC_R_SUCCESS)
3897                         dump_database_section(msg->msg, DNS_SECTION_ANSWER);
3898
3899                 if (dns_message_firstname(msg->msg, DNS_SECTION_AUTHORITY)
3900                     == ISC_R_SUCCESS)
3901                         dump_database_section(msg->msg, DNS_SECTION_AUTHORITY);
3902
3903                 if (dns_message_firstname(msg->msg, DNS_SECTION_ADDITIONAL)
3904                     == ISC_R_SUCCESS)
3905                         dump_database_section(msg->msg, DNS_SECTION_ADDITIONAL);
3906         }
3907 }
3908
3909
3910 dns_rdataset_t *
3911 search_type(dns_name_t *name, dns_rdatatype_t type, dns_rdatatype_t covers) {
3912         dns_rdataset_t *rdataset;
3913         dns_rdata_sig_t siginfo;
3914         dns_rdata_t sigrdata = DNS_RDATA_INIT;
3915         isc_result_t result;
3916
3917         for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL;
3918              rdataset = ISC_LIST_NEXT(rdataset, link)) {
3919                 if (type == dns_rdatatype_any) {
3920                         if (rdataset->type != dns_rdatatype_rrsig)
3921                                 return (rdataset);
3922                 } else if ((type == dns_rdatatype_rrsig) &&
3923                            (rdataset->type == dns_rdatatype_rrsig)) {
3924                         result = dns_rdataset_first(rdataset);
3925                         check_result(result, "empty rdataset");
3926                         dns_rdataset_current(rdataset, &sigrdata);
3927                         result = dns_rdata_tostruct(&sigrdata, &siginfo, NULL);
3928                         check_result(result, "sigrdata tostruct siginfo");
3929
3930                         if ((siginfo.covered == covers) ||
3931                             (covers == dns_rdatatype_any)) {
3932                                 dns_rdata_reset(&sigrdata);
3933                                 dns_rdata_freestruct(&siginfo);
3934                                 return (rdataset);
3935                         }
3936                         dns_rdata_reset(&sigrdata);
3937                         dns_rdata_freestruct(&siginfo);
3938                 } else if (rdataset->type == type)
3939                         return (rdataset);
3940         }
3941         return (NULL);
3942 }
3943
3944 dns_rdataset_t *
3945 chase_scanname_section(dns_message_t *msg, dns_name_t *name,
3946                        dns_rdatatype_t type, dns_rdatatype_t covers,
3947                        int section)
3948 {
3949         dns_rdataset_t *rdataset;
3950         dns_name_t *msg_name = NULL;
3951
3952         do {
3953                 dns_message_currentname(msg, section, &msg_name);
3954                 if (dns_name_compare(msg_name, name) == 0) {
3955                         rdataset = search_type(msg_name, type, covers);
3956                         if (rdataset != NULL)
3957                                 return (rdataset);
3958                 }
3959                 msg_name = NULL;
3960         } while (dns_message_nextname(msg, section) == ISC_R_SUCCESS);
3961
3962         return (NULL);
3963 }
3964
3965
3966 dns_rdataset_t *
3967 chase_scanname(dns_name_t *name, dns_rdatatype_t type, dns_rdatatype_t covers)
3968 {
3969         dns_rdataset_t *rdataset = NULL;
3970         dig_message_t * msg;
3971
3972         for (msg = ISC_LIST_HEAD(chase_message_list2);  msg != NULL;
3973              msg = ISC_LIST_NEXT(msg, link)) {
3974                 if (dns_message_firstname(msg->msg, DNS_SECTION_ANSWER)
3975                     == ISC_R_SUCCESS)
3976                         rdataset = chase_scanname_section(msg->msg, name,
3977                                                           type, covers,
3978                                                           DNS_SECTION_ANSWER);
3979                         if (rdataset != NULL)
3980                                 return (rdataset);
3981                 if (dns_message_firstname(msg->msg, DNS_SECTION_AUTHORITY)
3982                     == ISC_R_SUCCESS)
3983                         rdataset =
3984                                 chase_scanname_section(msg->msg, name,
3985                                                        type, covers,
3986                                                        DNS_SECTION_AUTHORITY);
3987                         if (rdataset != NULL)
3988                                 return (rdataset);
3989                 if (dns_message_firstname(msg->msg, DNS_SECTION_ADDITIONAL)
3990                     == ISC_R_SUCCESS)
3991                         rdataset =
3992                                 chase_scanname_section(msg->msg, name, type,
3993                                                        covers,
3994                                                        DNS_SECTION_ADDITIONAL);
3995                         if (rdataset != NULL)
3996                                 return (rdataset);
3997         }
3998
3999         return (NULL);
4000 }
4001
4002 dns_rdataset_t *
4003 sigchase_scanname(dns_rdatatype_t type, dns_rdatatype_t covers,
4004                   isc_boolean_t * lookedup, dns_name_t *rdata_name)
4005 {
4006         dig_lookup_t *lookup;
4007         isc_buffer_t *b = NULL;
4008         isc_region_t r;
4009         isc_result_t result;
4010         dns_rdataset_t * temp;
4011         dns_rdatatype_t querytype;
4012
4013         temp = chase_scanname(rdata_name, type, covers);
4014         if (temp != NULL)
4015                 return (temp);
4016
4017         if (*lookedup == ISC_TRUE)
4018                 return (NULL);
4019
4020         lookup = clone_lookup(current_lookup, ISC_TRUE);
4021         lookup->trace_root = ISC_FALSE;
4022         lookup->new_search = ISC_TRUE;
4023
4024         result = isc_buffer_allocate(mctx, &b, BUFSIZE);
4025         check_result(result, "isc_buffer_allocate");
4026         result = dns_name_totext(rdata_name, ISC_FALSE, b);
4027         check_result(result, "dns_name_totext");
4028         isc_buffer_usedregion(b, &r);
4029         r.base[r.length] = '\0';
4030         strcpy(lookup->textname, (char*)r.base);
4031         isc_buffer_free(&b);
4032
4033         if (type ==  dns_rdatatype_rrsig)
4034                 querytype = covers;
4035         else
4036                 querytype = type;
4037
4038         if (querytype == 0 || querytype == 255) {
4039                 printf("Error in the queried type: %d\n", querytype);
4040                 return (NULL);
4041         }
4042
4043         lookup->rdtype = querytype;
4044         lookup->rdtypeset = ISC_TRUE;
4045         lookup->qrdtype = querytype;
4046         *lookedup = ISC_TRUE;
4047
4048         ISC_LIST_APPEND(lookup_list, lookup, link);
4049         printf("\n\nLaunch a query to find a RRset of type ");
4050         print_type(type);
4051         printf(" for zone: %s\n", lookup->textname);
4052         return (NULL);
4053 }
4054
4055 void
4056 insert_trustedkey(dst_key_t * key)
4057 {
4058         if (key == NULL)
4059                 return;
4060         if (tk_list.nb_tk >= MAX_TRUSTED_KEY)
4061                 return;
4062
4063         tk_list.key[tk_list.nb_tk++] = key;
4064         return;
4065 }
4066
4067 void
4068 clean_trustedkey()
4069 {
4070         int i = 0;
4071
4072         for (i= 0; i < MAX_TRUSTED_KEY; i++) {
4073                 if (tk_list.key[i] != NULL) {
4074                         dst_key_free(&tk_list.key[i]);
4075                         tk_list.key[i] = NULL;
4076                 } else
4077                         break;
4078         }
4079         tk_list.nb_tk = 0;
4080         return;
4081 }
4082
4083 char alphnum[] =
4084         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
4085
4086 isc_result_t
4087 removetmpkey(isc_mem_t *mctx, const char *file)
4088 {
4089         char *tempnamekey = NULL;
4090         int tempnamekeylen;
4091         isc_result_t result;
4092
4093         tempnamekeylen = strlen(file)+10;
4094
4095         tempnamekey = isc_mem_allocate(mctx, tempnamekeylen);
4096         if (tempnamekey == NULL)
4097                 return (ISC_R_NOMEMORY);
4098
4099         memset(tempnamekey, 0, tempnamekeylen);
4100
4101         strcat(tempnamekey, file);
4102         strcat(tempnamekey,".key");
4103         isc_file_remove(tempnamekey);
4104
4105         result = isc_file_remove(tempnamekey);
4106         isc_mem_free(mctx, tempnamekey);
4107         return (result);
4108 }
4109
4110 isc_result_t
4111 opentmpkey(isc_mem_t *mctx, const char *file, char **tempp, FILE **fp) {
4112         FILE *f = NULL;
4113         isc_result_t result;
4114         char *tempname = NULL;
4115         char *tempnamekey = NULL;
4116         int tempnamelen;
4117         int tempnamekeylen;
4118         char *x;
4119         char *cp;
4120         isc_uint32_t which;
4121
4122         while (1) {
4123                 tempnamelen = strlen(file) + 20;
4124                 tempname = isc_mem_allocate(mctx, tempnamelen);
4125                 if (tempname == NULL)
4126                         return (ISC_R_NOMEMORY);
4127                 memset(tempname, 0, tempnamelen);
4128
4129                 result = isc_file_mktemplate(file, tempname, tempnamelen);
4130                 if (result != ISC_R_SUCCESS)
4131                         goto cleanup;
4132
4133                 cp = tempname;
4134                 while (*cp != '\0')
4135                         cp++;
4136                 if (cp == tempname) {
4137                         isc_mem_free(mctx, tempname);
4138                         return (ISC_R_FAILURE);
4139                 }
4140
4141                 x = cp--;
4142                 while (cp >= tempname && *cp == 'X') {
4143                         isc_random_get(&which);
4144                         *cp = alphnum[which % (sizeof(alphnum) - 1)];
4145                         x = cp--;
4146                 }
4147
4148                 tempnamekeylen = tempnamelen+5;
4149                 tempnamekey = isc_mem_allocate(mctx, tempnamekeylen);
4150                 if (tempnamekey == NULL)
4151                         return (ISC_R_NOMEMORY);
4152
4153                 memset(tempnamekey, 0, tempnamekeylen);
4154                 strncpy(tempnamekey, tempname, tempnamelen);
4155                 strcat(tempnamekey ,".key");
4156
4157
4158                 if (isc_file_exists(tempnamekey)) {
4159                         isc_mem_free(mctx, tempnamekey);
4160                         isc_mem_free(mctx, tempname);
4161                         continue;
4162                 }
4163
4164                 if ((f = fopen(tempnamekey, "w")) == NULL) {
4165                         printf("get_trusted_key(): trusted key not found %s\n",
4166                                tempnamekey);
4167                         return (ISC_R_FAILURE);
4168                 }
4169                 break;
4170         }
4171         isc_mem_free(mctx, tempnamekey);
4172         *tempp = tempname;
4173         *fp = f;
4174         return (ISC_R_SUCCESS);
4175
4176  cleanup:
4177         isc_mem_free(mctx, tempname);
4178
4179         return (result);
4180 }
4181
4182
4183 isc_result_t
4184 get_trusted_key(isc_mem_t *mctx)
4185 {
4186         isc_result_t result;
4187         const char *filename = NULL;
4188         char *filetemp = NULL;
4189         char buf[1500];
4190         FILE *fp, *fptemp;
4191         dst_key_t *key = NULL;
4192
4193         result = isc_file_exists(trustedkey);
4194         if (result !=  ISC_TRUE) {
4195                 result = isc_file_exists("/etc/trusted-key.key");
4196                 if (result !=  ISC_TRUE) {
4197                         result = isc_file_exists("./trusted-key.key");
4198                         if (result !=  ISC_TRUE)
4199                                 return (ISC_R_FAILURE);
4200                         else
4201                                 filename = "./trusted-key.key";
4202                 } else
4203                         filename = "/etc/trusted-key.key";
4204         } else
4205                 filename = trustedkey;
4206
4207         if (filename == NULL) {
4208                 printf("No trusted key\n");
4209                 return (ISC_R_FAILURE);
4210         }
4211
4212         if ((fp = fopen(filename, "r")) == NULL) {
4213                 printf("get_trusted_key(): trusted key not found %s\n",
4214                        filename);
4215                 return (ISC_R_FAILURE);
4216         }
4217         while (fgets(buf, sizeof(buf), fp) != NULL) {
4218                 result = opentmpkey(mctx,"tmp_file", &filetemp, &fptemp);
4219                 if (result != ISC_R_SUCCESS) {
4220                         fclose(fp);
4221                         return (ISC_R_FAILURE);
4222                 }
4223                 if (fputs(buf, fptemp) < 0) {
4224                         fclose(fp);
4225                         fclose(fptemp);
4226                         return (ISC_R_FAILURE);
4227                 }
4228                 fclose(fptemp);
4229                 result = dst_key_fromnamedfile(filetemp, NULL, DST_TYPE_PUBLIC,
4230                                                mctx, &key);
4231                 removetmpkey(mctx, filetemp);
4232                 isc_mem_free(mctx, filetemp);
4233                 if (result !=  ISC_R_SUCCESS) {
4234                         fclose(fp);
4235                         return (ISC_R_FAILURE);
4236                 }
4237                 insert_trustedkey(key);
4238 #if 0
4239                 dst_key_tofile(key, DST_TYPE_PUBLIC,"/tmp");
4240 #endif
4241                 key = NULL;
4242         }
4243         return (ISC_R_SUCCESS);
4244 }
4245
4246
4247 static void
4248 nameFromString(const char *str, dns_name_t *p_ret) {
4249         size_t len = strlen(str);
4250         isc_result_t result;
4251         isc_buffer_t buffer;
4252         dns_fixedname_t fixedname;
4253
4254         REQUIRE(p_ret != NULL);
4255         REQUIRE(str != NULL);
4256
4257         isc_buffer_init(&buffer, str, len);
4258         isc_buffer_add(&buffer, len);
4259
4260         dns_fixedname_init(&fixedname);
4261         result = dns_name_fromtext(dns_fixedname_name(&fixedname), &buffer,
4262                                    dns_rootname, DNS_NAME_DOWNCASE, NULL);
4263         check_result(result, "nameFromString");
4264
4265         if (dns_name_dynamic(p_ret))
4266                 free_name(p_ret, mctx);
4267
4268         result = dns_name_dup(dns_fixedname_name(&fixedname), mctx, p_ret);
4269         check_result(result, "nameFromString");
4270 }
4271
4272
4273 #if DIG_SIGCHASE_TD
4274 isc_result_t
4275 prepare_lookup(dns_name_t *name)
4276 {
4277         isc_result_t result;
4278         dig_lookup_t *lookup = NULL;
4279         dig_server_t *s;
4280         void *ptr;
4281
4282         lookup = clone_lookup(current_lookup, ISC_TRUE);
4283         lookup->trace_root = ISC_FALSE;
4284         lookup->new_search = ISC_TRUE;
4285         lookup->trace_root_sigchase = ISC_FALSE;
4286
4287         strncpy(lookup->textname, lookup->textnamesigchase, MXNAME);
4288
4289         lookup->rdtype = lookup->rdtype_sigchase;
4290         lookup->rdtypeset = ISC_TRUE;
4291         lookup->qrdtype = lookup->qrdtype_sigchase;
4292
4293         s = ISC_LIST_HEAD(lookup->my_server_list);
4294         while (s != NULL) {
4295                 debug("freeing server %p belonging to %p",
4296                       s, lookup);
4297                 ptr = s;
4298                 s = ISC_LIST_NEXT(s, link);
4299                 ISC_LIST_DEQUEUE(lookup->my_server_list,
4300                                  (dig_server_t *)ptr, link);
4301                 isc_mem_free(mctx, ptr);
4302         }
4303
4304
4305         for (result = dns_rdataset_first(chase_nsrdataset);
4306              result == ISC_R_SUCCESS;
4307              result = dns_rdataset_next(chase_nsrdataset)) {
4308                 char namestr[DNS_NAME_FORMATSIZE];
4309                 dns_rdata_ns_t ns;
4310                 dns_rdata_t rdata = DNS_RDATA_INIT;
4311                 dig_server_t * srv = NULL;
4312 #define __FOLLOW_GLUE__
4313 #ifdef __FOLLOW_GLUE__
4314                 isc_buffer_t *b = NULL;
4315                 isc_result_t result;
4316                 isc_region_t r;
4317                 dns_rdataset_t *rdataset = NULL;
4318                 isc_boolean_t true = ISC_TRUE;
4319 #endif
4320
4321                 memset(namestr, 0, DNS_NAME_FORMATSIZE);
4322
4323                 dns_rdataset_current(chase_nsrdataset, &rdata);
4324
4325                 result = dns_rdata_tostruct(&rdata, &ns, NULL);
4326                 check_result(result, "dns_rdata_tostruct");
4327
4328 #ifdef __FOLLOW_GLUE__
4329
4330                 result = advanced_rrsearch(&rdataset, &ns.name,
4331                                            dns_rdatatype_aaaa,
4332                                            dns_rdatatype_any, &true);
4333                 if (result == ISC_R_SUCCESS) {
4334                         for (result = dns_rdataset_first(rdataset);
4335                              result == ISC_R_SUCCESS;
4336                              result = dns_rdataset_next(rdataset)) {
4337                                 dns_rdata_t aaaa = DNS_RDATA_INIT;
4338                                 dns_rdataset_current(rdataset, &aaaa);
4339
4340                                 result = isc_buffer_allocate(mctx, &b, 80);
4341                                 check_result(result, "isc_buffer_allocate");
4342
4343                                 dns_rdata_totext(&aaaa, &ns.name, b);
4344                                 isc_buffer_usedregion(b, &r);
4345                                 r.base[r.length] = '\0';
4346                                 strncpy(namestr, (char*)r.base,
4347                                         DNS_NAME_FORMATSIZE);
4348                                 isc_buffer_free(&b);
4349                                 dns_rdata_reset(&aaaa);
4350
4351
4352                                 srv = make_server(namestr, namestr);
4353
4354                                 ISC_LIST_APPEND(lookup->my_server_list,
4355                                                 srv, link);
4356                         }
4357                 }
4358
4359                 rdataset = NULL;
4360                 result = advanced_rrsearch(&rdataset, &ns.name, dns_rdatatype_a,
4361                                            dns_rdatatype_any, &true);
4362                 if (result == ISC_R_SUCCESS) {
4363                         for (result = dns_rdataset_first(rdataset);
4364                              result == ISC_R_SUCCESS;
4365                              result = dns_rdataset_next(rdataset)) {
4366                                 dns_rdata_t a = DNS_RDATA_INIT;
4367                                 dns_rdataset_current(rdataset, &a);
4368
4369                                 result = isc_buffer_allocate(mctx, &b, 80);
4370                                 check_result(result, "isc_buffer_allocate");
4371
4372                                 dns_rdata_totext(&a, &ns.name, b);
4373                                 isc_buffer_usedregion(b, &r);
4374                                 r.base[r.length] = '\0';
4375                                 strncpy(namestr, (char*)r.base,
4376                                         DNS_NAME_FORMATSIZE);
4377                                 isc_buffer_free(&b);
4378                                 dns_rdata_reset(&a);
4379                                 printf("ns name: %s\n", namestr);
4380
4381
4382                                 srv = make_server(namestr, namestr);
4383
4384                                 ISC_LIST_APPEND(lookup->my_server_list,
4385                                                 srv, link);
4386                         }
4387                 }
4388 #else
4389
4390                 dns_name_format(&ns.name, namestr, sizeof(namestr));
4391                 printf("ns name: ");
4392                 dns_name_print(&ns.name, stdout);
4393                 printf("\n");
4394                 srv = make_server(namestr, namestr);
4395
4396                 ISC_LIST_APPEND(lookup->my_server_list, srv, link);
4397
4398 #endif
4399                 dns_rdata_freestruct(&ns);
4400                 dns_rdata_reset(&rdata);
4401
4402         }
4403
4404         ISC_LIST_APPEND(lookup_list, lookup, link);
4405         printf("\nLaunch a query to find a RRset of type ");
4406         print_type(lookup->rdtype);
4407         printf(" for zone: %s", lookup->textname);
4408         printf(" with nameservers:");
4409         printf("\n");
4410         print_rdataset(name, chase_nsrdataset, mctx);
4411         return (ISC_R_SUCCESS);
4412 }
4413
4414
4415 isc_result_t
4416 child_of_zone(dns_name_t * name, dns_name_t * zone_name,
4417               dns_name_t * child_name)
4418 {
4419         dns_namereln_t name_reln;
4420         int orderp;
4421         unsigned int nlabelsp;
4422
4423         name_reln = dns_name_fullcompare(name, zone_name, &orderp, &nlabelsp);
4424         if (name_reln != dns_namereln_subdomain ||
4425             dns_name_countlabels(name) <= dns_name_countlabels(zone_name) + 1) {
4426                 printf("\n;; ERROR : ");
4427                 dns_name_print(name, stdout);
4428                 printf(" is not a subdomain of: ");
4429                 dns_name_print(zone_name, stdout);
4430                 printf(" FAILED\n\n");
4431                 return (ISC_R_FAILURE);
4432         }
4433
4434         dns_name_getlabelsequence(name,
4435                                   dns_name_countlabels(name) -
4436                                   dns_name_countlabels(zone_name) -1,
4437                                   dns_name_countlabels(zone_name) +1,
4438                                   child_name);
4439         return (ISC_R_SUCCESS);
4440 }
4441
4442 isc_result_t
4443 grandfather_pb_test(dns_name_t *zone_name, dns_rdataset_t  *sigrdataset)
4444 {
4445         isc_result_t result;
4446         dns_rdata_t sigrdata = DNS_RDATA_INIT;
4447         dns_rdata_sig_t siginfo;
4448
4449         result = dns_rdataset_first(sigrdataset);
4450         check_result(result, "empty RRSIG dataset");
4451         dns_rdata_init(&sigrdata);
4452
4453         do {
4454                 dns_rdataset_current(sigrdataset, &sigrdata);
4455
4456                 result = dns_rdata_tostruct(&sigrdata, &siginfo, NULL);
4457                 check_result(result, "sigrdata tostruct siginfo");
4458
4459                 if (dns_name_compare(&siginfo.signer, zone_name) == 0) {
4460                         dns_rdata_freestruct(&siginfo);
4461                         dns_rdata_reset(&sigrdata);
4462                         return (ISC_R_SUCCESS);
4463                 }
4464
4465                 dns_rdata_freestruct(&siginfo);
4466                 dns_rdata_reset(&sigrdata);
4467
4468         } while (dns_rdataset_next(chase_sigkeyrdataset) == ISC_R_SUCCESS);
4469
4470         dns_rdata_reset(&sigrdata);
4471
4472         return (ISC_R_FAILURE);
4473 }
4474
4475
4476 isc_result_t
4477 initialization(dns_name_t *name)
4478 {
4479         isc_result_t   result;
4480         isc_boolean_t  true = ISC_TRUE;
4481
4482         chase_nsrdataset = NULL;
4483         result = advanced_rrsearch(&chase_nsrdataset, name, dns_rdatatype_ns,
4484                                    dns_rdatatype_any, &true);
4485         if (result != ISC_R_SUCCESS) {
4486                 printf("\n;; NS RRset is missing to continue validation:"
4487                        " FAILED\n\n");
4488                 return (ISC_R_FAILURE);
4489         }
4490         INSIST(chase_nsrdataset != NULL);
4491         prepare_lookup(name);
4492
4493         dup_name(name, &chase_current_name, mctx);
4494
4495         return (ISC_R_SUCCESS);
4496 }
4497 #endif
4498
4499 void
4500 print_rdataset(dns_name_t *name, dns_rdataset_t *rdataset, isc_mem_t *mctx)
4501 {
4502         isc_buffer_t *b = NULL;
4503         isc_result_t result;
4504         isc_region_t r;
4505
4506         result = isc_buffer_allocate(mctx, &b, 9000);
4507         check_result(result, "isc_buffer_allocate");
4508
4509         printrdataset(name, rdataset, b);
4510
4511         isc_buffer_usedregion(b, &r);
4512         r.base[r.length] = '\0';
4513
4514
4515         printf("%s\n", r.base);
4516
4517         isc_buffer_free(&b);
4518 }
4519
4520
4521 void
4522 dup_name(dns_name_t *source, dns_name_t *target, isc_mem_t *mctx) {
4523         isc_result_t result;
4524
4525         if (dns_name_dynamic(target))
4526                 free_name(target, mctx);
4527         result = dns_name_dup(source, mctx, target);
4528         check_result(result, "dns_name_dup");
4529 }
4530
4531 void
4532 free_name(dns_name_t *name, isc_mem_t *mctx) {
4533         dns_name_free(name, mctx);
4534         dns_name_init(name, NULL);
4535 }
4536
4537 /*
4538  *
4539  * take a DNSKEY RRset and the RRSIG RRset corresponding in parameter
4540  * return ISC_R_SUCCESS if the DNSKEY RRset contains a trusted_key
4541  *                      and the RRset is valid
4542  * return ISC_R_NOTFOUND if not contains trusted key
4543                         or if the RRset isn't valid
4544  * return ISC_R_FAILURE if problem
4545  *
4546  */
4547 isc_result_t
4548 contains_trusted_key(dns_name_t *name, dns_rdataset_t *rdataset,
4549                      dns_rdataset_t *sigrdataset,
4550                      isc_mem_t *mctx)
4551 {
4552         isc_result_t result;
4553         dns_rdata_t rdata = DNS_RDATA_INIT;
4554         dst_key_t *trustedKey = NULL;
4555         dst_key_t *dnsseckey = NULL;
4556         int i;
4557
4558         if (name == NULL || rdataset == NULL)
4559                 return (ISC_R_FAILURE);
4560
4561         result = dns_rdataset_first(rdataset);
4562         check_result(result, "empty rdataset");
4563
4564         do {
4565                 dns_rdataset_current(rdataset, &rdata);
4566                 INSIST(rdata.type == dns_rdatatype_dnskey);
4567
4568                 result = dns_dnssec_keyfromrdata(name, &rdata,
4569                                                  mctx, &dnsseckey);
4570                 check_result(result, "dns_dnssec_keyfromrdata");
4571
4572
4573                 for (i = 0; i < tk_list.nb_tk; i++) {
4574                         if (dst_key_compare(tk_list.key[i], dnsseckey)
4575                             == ISC_TRUE) {
4576                                 dns_rdata_reset(&rdata);
4577
4578                                 printf(";; Ok, find a Trusted Key in the "
4579                                        "DNSKEY RRset: %d\n",
4580                                        dst_key_id(dnsseckey));
4581                                 if (sigchase_verify_sig_key(name, rdataset,
4582                                                             dnsseckey,
4583                                                             sigrdataset,
4584                                                             mctx)
4585                                     == ISC_R_SUCCESS) {
4586                                         dst_key_free(&dnsseckey);
4587                                         dnsseckey = NULL;
4588                                         return (ISC_R_SUCCESS);
4589                                 }
4590                         }
4591                 }
4592
4593                 dns_rdata_reset(&rdata);
4594                 if (dnsseckey != NULL)
4595                         dst_key_free(&dnsseckey);
4596         } while (dns_rdataset_next(rdataset) == ISC_R_SUCCESS);
4597
4598         if (trustedKey != NULL)
4599                 dst_key_free(&trustedKey);
4600         trustedKey = NULL;
4601
4602         return (ISC_R_NOTFOUND);
4603 }
4604
4605 isc_result_t
4606 sigchase_verify_sig(dns_name_t *name, dns_rdataset_t *rdataset,
4607                     dns_rdataset_t *keyrdataset,
4608                     dns_rdataset_t *sigrdataset,
4609                     isc_mem_t *mctx)
4610 {
4611         isc_result_t result;
4612         dns_rdata_t keyrdata = DNS_RDATA_INIT;
4613         dst_key_t *dnsseckey = NULL;
4614
4615         result = dns_rdataset_first(keyrdataset);
4616         check_result(result, "empty DNSKEY dataset");
4617         dns_rdata_init(&keyrdata);
4618
4619         do {
4620                 dns_rdataset_current(keyrdataset, &keyrdata);
4621                 INSIST(keyrdata.type == dns_rdatatype_dnskey);
4622
4623                 result = dns_dnssec_keyfromrdata(name, &keyrdata,
4624                                                  mctx, &dnsseckey);
4625                 check_result(result, "dns_dnssec_keyfromrdata");
4626
4627                 result = sigchase_verify_sig_key(name, rdataset, dnsseckey,
4628                                                  sigrdataset, mctx);
4629                 if (result == ISC_R_SUCCESS) {
4630                         dns_rdata_reset(&keyrdata);
4631                         dst_key_free(&dnsseckey);
4632                         return (ISC_R_SUCCESS);
4633                 }
4634                 dst_key_free(&dnsseckey);
4635                 dns_rdata_reset(&keyrdata);
4636         } while (dns_rdataset_next(chase_keyrdataset) == ISC_R_SUCCESS);
4637
4638         dns_rdata_reset(&keyrdata);
4639
4640         return (ISC_R_NOTFOUND);
4641 }
4642
4643 isc_result_t
4644 sigchase_verify_sig_key(dns_name_t *name, dns_rdataset_t *rdataset,
4645                         dst_key_t *dnsseckey, dns_rdataset_t *sigrdataset,
4646                         isc_mem_t *mctx)
4647 {
4648         isc_result_t result;
4649         dns_rdata_t sigrdata = DNS_RDATA_INIT;
4650         dns_rdata_sig_t siginfo;
4651
4652         result = dns_rdataset_first(sigrdataset);
4653         check_result(result, "empty RRSIG dataset");
4654         dns_rdata_init(&sigrdata);
4655
4656         do {
4657                 dns_rdataset_current(sigrdataset, &sigrdata);
4658
4659                 result = dns_rdata_tostruct(&sigrdata, &siginfo, NULL);
4660                 check_result(result, "sigrdata tostruct siginfo");
4661
4662                 /*
4663                  * Test if the id of the DNSKEY is
4664                  * the id of the DNSKEY signer's
4665                  */
4666                 if (siginfo.keyid == dst_key_id(dnsseckey)) {
4667
4668                         result = dns_rdataset_first(rdataset);
4669                         check_result(result, "empty DS dataset");
4670
4671                         result = dns_dnssec_verify(name, rdataset, dnsseckey,
4672                                                    ISC_FALSE, mctx, &sigrdata);
4673
4674                         printf(";; VERIFYING ");
4675                         print_type(rdataset->type);
4676                         printf(" RRset for ");
4677                         dns_name_print(name, stdout);
4678                         printf(" with DNSKEY:%d: %s\n", dst_key_id(dnsseckey),
4679                                isc_result_totext(result));
4680
4681                         if (result == ISC_R_SUCCESS) {
4682                                 dns_rdata_reset(&sigrdata);
4683                                 return (result);
4684                         }
4685                 }
4686                 dns_rdata_freestruct(&siginfo);
4687                 dns_rdata_reset(&sigrdata);
4688
4689         } while (dns_rdataset_next(chase_sigkeyrdataset) == ISC_R_SUCCESS);
4690
4691         dns_rdata_reset(&sigrdata);
4692
4693         return (ISC_R_NOTFOUND);
4694 }
4695
4696
4697 isc_result_t
4698 sigchase_verify_ds(dns_name_t *name, dns_rdataset_t *keyrdataset,
4699                    dns_rdataset_t *dsrdataset, isc_mem_t *mctx)
4700 {
4701         isc_result_t result;
4702         dns_rdata_t keyrdata = DNS_RDATA_INIT;
4703         dns_rdata_t newdsrdata = DNS_RDATA_INIT;
4704         dns_rdata_t dsrdata = DNS_RDATA_INIT;
4705         dns_rdata_ds_t dsinfo;
4706         dst_key_t *dnsseckey = NULL;
4707         unsigned char dsbuf[DNS_DS_BUFFERSIZE];
4708
4709         result = dns_rdataset_first(dsrdataset);
4710         check_result(result, "empty DSset dataset");
4711         do {
4712                 dns_rdataset_current(dsrdataset, &dsrdata);
4713
4714                 result = dns_rdata_tostruct(&dsrdata, &dsinfo, NULL);
4715                 check_result(result, "dns_rdata_tostruct for DS");
4716
4717                 result = dns_rdataset_first(keyrdataset);
4718                 check_result(result, "empty KEY dataset");
4719
4720                 do {
4721                         dns_rdataset_current(keyrdataset, &keyrdata);
4722                         INSIST(keyrdata.type == dns_rdatatype_dnskey);
4723
4724                         result = dns_dnssec_keyfromrdata(name, &keyrdata,
4725                                                          mctx, &dnsseckey);
4726                         check_result(result, "dns_dnssec_keyfromrdata");
4727
4728                         /*
4729                          * Test if the id of the DNSKEY is the
4730                          * id of DNSKEY referenced by the DS
4731                          */
4732                         if (dsinfo.key_tag == dst_key_id(dnsseckey)) {
4733
4734                                 result = dns_ds_buildrdata(name, &keyrdata,
4735                                                            dsinfo.digest_type,
4736                                                            dsbuf, &newdsrdata);
4737                                 dns_rdata_freestruct(&dsinfo);
4738
4739                                 if (result != ISC_R_SUCCESS) {
4740                                         dns_rdata_reset(&keyrdata);
4741                                         dns_rdata_reset(&newdsrdata);
4742                                         dns_rdata_reset(&dsrdata);
4743                                         dst_key_free(&dnsseckey);
4744                                         dns_rdata_freestruct(&dsinfo);
4745                                         printf("Oops: impossible to build"
4746                                                " new DS rdata\n");
4747                                         return (result);
4748                                 }
4749
4750
4751                                 if (dns_rdata_compare(&dsrdata,
4752                                                       &newdsrdata) == 0) {
4753                                         printf(";; OK a DS valids a DNSKEY"
4754                                                " in the RRset\n");
4755                                         printf(";; Now verify that this"
4756                                                " DNSKEY validates the "
4757                                                "DNSKEY RRset\n");
4758
4759                                         result = sigchase_verify_sig_key(name,
4760                                                          keyrdataset,
4761                                                          dnsseckey,
4762                                                          chase_sigkeyrdataset,
4763                                                          mctx);
4764                                         if (result ==  ISC_R_SUCCESS) {
4765                                                 dns_rdata_reset(&keyrdata);
4766                                                 dns_rdata_reset(&newdsrdata);
4767                                                 dns_rdata_reset(&dsrdata);
4768                                                 dst_key_free(&dnsseckey);
4769
4770                                                 return (result);
4771                                         }
4772                                 } else {
4773                                         printf(";; This DS is NOT the DS for"
4774                                                " the chasing KEY: FAILED\n");
4775                                 }
4776
4777                                 dns_rdata_reset(&newdsrdata);
4778                         }
4779                         dst_key_free(&dnsseckey);
4780                         dns_rdata_reset(&keyrdata);
4781                         dnsseckey = NULL;
4782                 } while (dns_rdataset_next(chase_keyrdataset) == ISC_R_SUCCESS);
4783                 dns_rdata_reset(&dsrdata);
4784
4785         } while (dns_rdataset_next(chase_dsrdataset) == ISC_R_SUCCESS);
4786
4787         dns_rdata_reset(&keyrdata);
4788         dns_rdata_reset(&newdsrdata);
4789         dns_rdata_reset(&dsrdata);
4790
4791         return (ISC_R_NOTFOUND);
4792 }
4793
4794 /*
4795  *
4796  * take a pointer on a rdataset in parameter and try to resolv it.
4797  * the searched rrset is a rrset on 'name' with type 'type'
4798  * (and if the type is a rrsig the signature cover 'covers').
4799  * the lookedup is to known if you have already done the query on the net.
4800  * ISC_R_SUCCESS: if we found the rrset
4801  * ISC_R_NOTFOUND: we do not found the rrset in cache
4802  * and we do a query on the net
4803  * ISC_R_FAILURE: rrset not found
4804  */
4805 isc_result_t
4806 advanced_rrsearch(dns_rdataset_t **rdataset, dns_name_t *name,
4807                   dns_rdatatype_t type, dns_rdatatype_t covers,
4808                   isc_boolean_t *lookedup)
4809 {
4810         isc_boolean_t  tmplookedup;
4811
4812         INSIST(rdataset != NULL);
4813
4814         if (*rdataset != NULL)
4815                 return (ISC_R_SUCCESS);
4816
4817         tmplookedup = *lookedup;
4818         if ((*rdataset = sigchase_scanname(type, covers,
4819                                            lookedup, name)) == NULL) {
4820                 if (tmplookedup)
4821                         return (ISC_R_FAILURE);
4822                 return (ISC_R_NOTFOUND);
4823         }
4824         *lookedup = ISC_FALSE;
4825         return (ISC_R_SUCCESS);
4826 }
4827
4828
4829
4830 #if DIG_SIGCHASE_TD
4831 void
4832 sigchase_td(dns_message_t *msg)
4833 {
4834         isc_result_t result;
4835         dns_name_t *name = NULL;
4836         isc_boolean_t have_answer = ISC_FALSE;
4837         isc_boolean_t true = ISC_TRUE;
4838
4839         if ((result = dns_message_firstname(msg, DNS_SECTION_ANSWER))
4840             == ISC_R_SUCCESS) {
4841                 dns_message_currentname(msg, DNS_SECTION_ANSWER, &name);
4842                 if (current_lookup->trace_root_sigchase) {
4843                         initialization(name);
4844                         return;
4845                 }
4846                 have_answer = true;
4847         } else {
4848                 if (!current_lookup->trace_root_sigchase) {
4849                         result = dns_message_firstname(msg,
4850                                                        DNS_SECTION_AUTHORITY);
4851                         if (result == ISC_R_SUCCESS)
4852                                 dns_message_currentname(msg,
4853                                                         DNS_SECTION_AUTHORITY,
4854                                                         &name);
4855                         chase_nsrdataset
4856                                 = chase_scanname_section(msg, name,
4857                                                          dns_rdatatype_ns,
4858                                                          dns_rdatatype_any,
4859                                                          DNS_SECTION_AUTHORITY);
4860                         dup_name(name, &chase_authority_name, mctx);
4861                         if (chase_nsrdataset != NULL) {
4862                                 have_delegation_ns = ISC_TRUE;
4863                                 printf("no response but there is a delegation"
4864                                        " in authority section:");
4865                                 dns_name_print(name, stdout);
4866                                 printf("\n");
4867                         } else {
4868                                 printf("no response and no delegation in "
4869                                        "authority section but a reference"
4870                                        " to: ");
4871                                 dns_name_print(name, stdout);
4872                                 printf("\n");
4873                                 error_message = msg;
4874                         }
4875                 } else {
4876                         printf(";; NO ANSWERS: %s\n",
4877                                isc_result_totext(result));
4878                         free_name(&chase_name, mctx);
4879                         clean_trustedkey();
4880                         return;
4881                 }
4882         }
4883
4884
4885         if (have_answer) {
4886                 chase_rdataset
4887                         = chase_scanname_section(msg, &chase_name,
4888                                                  current_lookup
4889                                                  ->rdtype_sigchase,
4890                                                  dns_rdatatype_any,
4891                                                  DNS_SECTION_ANSWER);
4892                 if (chase_rdataset != NULL)
4893                         have_response = ISC_TRUE;
4894         }
4895
4896         result = advanced_rrsearch(&chase_keyrdataset,
4897                                    &chase_current_name,
4898                                    dns_rdatatype_dnskey,
4899                                    dns_rdatatype_any,
4900                                    &chase_keylookedup);
4901         if (result == ISC_R_FAILURE) {
4902                 printf("\n;; DNSKEY is missing to continue validation:"
4903                        " FAILED\n\n");
4904                 goto cleanandgo;
4905         }
4906         if (result == ISC_R_NOTFOUND)
4907                 return;
4908         INSIST(chase_keyrdataset != NULL);
4909         printf("\n;; DNSKEYset:\n");
4910         print_rdataset(&chase_current_name , chase_keyrdataset, mctx);
4911
4912
4913         result = advanced_rrsearch(&chase_sigkeyrdataset,
4914                                    &chase_current_name,
4915                                    dns_rdatatype_rrsig,
4916                                    dns_rdatatype_dnskey,
4917                                    &chase_sigkeylookedup);
4918         if (result == ISC_R_FAILURE) {
4919                 printf("\n;; RRSIG of DNSKEY is missing to continue validation:"
4920                        " FAILED\n\n");
4921                 goto cleanandgo;
4922         }
4923         if (result == ISC_R_NOTFOUND)
4924                 return;
4925         INSIST(chase_sigkeyrdataset != NULL);
4926         printf("\n;; RRSIG of the DNSKEYset:\n");
4927         print_rdataset(&chase_current_name , chase_sigkeyrdataset, mctx);
4928
4929
4930         if (!chase_dslookedup && !chase_nslookedup) {
4931                 if (!delegation_follow) {
4932                         result = contains_trusted_key(&chase_current_name,
4933                                                       chase_keyrdataset,
4934                                                       chase_sigkeyrdataset,
4935                                                       mctx);
4936                 } else {
4937                         INSIST(chase_dsrdataset != NULL);
4938                         INSIST(chase_sigdsrdataset != NULL);
4939                         result = sigchase_verify_ds(&chase_current_name,
4940                                                     chase_keyrdataset,
4941                                                     chase_dsrdataset,
4942                                                     mctx);
4943                 }
4944
4945                 if (result != ISC_R_SUCCESS) {
4946                         printf("\n;; chain of trust can't be validated:"
4947                                " FAILED\n\n");
4948                         goto cleanandgo;
4949                 } else {
4950                         chase_dsrdataset = NULL;
4951                         chase_sigdsrdataset = NULL;
4952                 }
4953         }
4954
4955         if (have_response || (!have_delegation_ns && !have_response)) {
4956                 /* test if it's a grand father case */
4957
4958                 if (have_response) {
4959                         result = advanced_rrsearch(&chase_sigrdataset,
4960                                                    &chase_name,
4961                                                    dns_rdatatype_rrsig,
4962                                                    current_lookup
4963                                                    ->rdtype_sigchase,
4964                                                    &true);
4965                         if (result == ISC_R_FAILURE) {
4966                                 printf("\n;; RRset is missing to continue"
4967                                        " validation SHOULD NOT APPEND:"
4968                                        " FAILED\n\n");
4969                                 goto cleanandgo;
4970                         }
4971
4972                 } else {
4973                         result = advanced_rrsearch(&chase_sigrdataset,
4974                                                    &chase_authority_name,
4975                                                    dns_rdatatype_rrsig,
4976                                                    dns_rdatatype_any,
4977                                                    &true);
4978                         if (result == ISC_R_FAILURE) {
4979                                 printf("\n;; RRSIG is missing  to continue"
4980                                        " validation SHOULD NOT APPEND:"
4981                                        " FAILED\n\n");
4982                                 goto cleanandgo;
4983                         }
4984                 }
4985                 result =  grandfather_pb_test(&chase_current_name,
4986                                               chase_sigrdataset);
4987                 if (result != ISC_R_SUCCESS) {
4988                         dns_name_t tmp_name;
4989
4990                         printf("\n;; We are in a Grand Father Problem:"
4991                                " See 2.2.1 in RFC 3568\n");
4992                         chase_rdataset = NULL;
4993                         chase_sigrdataset = NULL;
4994                         have_response = ISC_FALSE;
4995                         have_delegation_ns = ISC_FALSE;
4996
4997                         dns_name_init(&tmp_name, NULL);
4998                         result = child_of_zone(&chase_name, &chase_current_name,
4999                                                &tmp_name);
5000                         if (dns_name_dynamic(&chase_authority_name))
5001                                 free_name(&chase_authority_name, mctx);
5002                         dup_name(&tmp_name, &chase_authority_name, mctx);
5003                         printf(";; and we try to continue chain of trust"
5004                                " validation of the zone: ");
5005                         dns_name_print(&chase_authority_name, stdout);
5006                         printf("\n");
5007                         have_delegation_ns = ISC_TRUE;
5008                 } else {
5009                         if (have_response)
5010                                 goto finalstep;
5011                         else
5012                                 chase_sigrdataset = NULL;
5013                 }
5014         }
5015
5016         if (have_delegation_ns) {
5017                 chase_nsrdataset = NULL;
5018                 result = advanced_rrsearch(&chase_nsrdataset,
5019                                            &chase_authority_name,
5020                                            dns_rdatatype_ns,
5021                                            dns_rdatatype_any,
5022                                            &chase_nslookedup);
5023                 if (result == ISC_R_FAILURE) {
5024                         printf("\n;;NSset is missing to continue validation:"
5025                                " FAILED\n\n");
5026                         goto cleanandgo;
5027                 }
5028                 if (result == ISC_R_NOTFOUND) {
5029                         return;
5030                 }
5031                 INSIST(chase_nsrdataset != NULL);
5032
5033                 result = advanced_rrsearch(&chase_dsrdataset,
5034                                            &chase_authority_name,
5035                                            dns_rdatatype_ds,
5036                                            dns_rdatatype_any,
5037                                            &chase_dslookedup);
5038                 if (result == ISC_R_FAILURE) {
5039                         printf("\n;; DSset is missing to continue validation:"
5040                                " FAILED\n\n");
5041                         goto cleanandgo;
5042                 }
5043                 if (result == ISC_R_NOTFOUND)
5044                         return;
5045                 INSIST(chase_dsrdataset != NULL);
5046                 printf("\n;; DSset:\n");
5047                 print_rdataset(&chase_authority_name , chase_dsrdataset, mctx);
5048
5049                 result = advanced_rrsearch(&chase_sigdsrdataset,
5050                                            &chase_authority_name,
5051                                            dns_rdatatype_rrsig,
5052                                            dns_rdatatype_ds,
5053                                            &true);
5054                 if (result != ISC_R_SUCCESS) {
5055                         printf("\n;; DSset is missing to continue validation:"
5056                                " FAILED\n\n");
5057                         goto cleanandgo;
5058                 }
5059                 printf("\n;; RRSIGset of DSset\n");
5060                 print_rdataset(&chase_authority_name,
5061                                chase_sigdsrdataset, mctx);
5062                 INSIST(chase_sigdsrdataset != NULL);
5063
5064                 result = sigchase_verify_sig(&chase_authority_name,
5065                                              chase_dsrdataset,
5066                                              chase_keyrdataset,
5067                                              chase_sigdsrdataset, mctx);
5068                 if (result != ISC_R_SUCCESS) {
5069                         printf("\n;; Impossible to verify the DSset:"
5070                                " FAILED\n\n");
5071                         goto cleanandgo;
5072                 }
5073                 chase_keyrdataset = NULL;
5074                 chase_sigkeyrdataset = NULL;
5075
5076
5077                 prepare_lookup(&chase_authority_name);
5078
5079                 have_response = ISC_FALSE;
5080                 have_delegation_ns = ISC_FALSE;
5081                 delegation_follow = ISC_TRUE;
5082                 error_message = NULL;
5083                 dup_name(&chase_authority_name, &chase_current_name, mctx);
5084                 free_name(&chase_authority_name, mctx);
5085                 return;
5086         }
5087
5088
5089         if (error_message != NULL) {
5090                 dns_rdataset_t *rdataset;
5091                 dns_rdataset_t *sigrdataset;
5092                 dns_name_t rdata_name;
5093                 isc_result_t ret = ISC_R_FAILURE;
5094
5095                 dns_name_init(&rdata_name, NULL);
5096                 result = prove_nx(error_message, &chase_name,
5097                                   current_lookup->rdclass_sigchase,
5098                                   current_lookup->rdtype_sigchase, &rdata_name,
5099                                   &rdataset, &sigrdataset);
5100                 if (rdataset == NULL || sigrdataset == NULL ||
5101                     dns_name_countlabels(&rdata_name) == 0) {
5102                         printf("\n;; Impossible to verify the non-existence,"
5103                                " the NSEC RRset can't be validated:"
5104                                " FAILED\n\n");
5105                         goto cleanandgo;
5106                 }
5107                 ret = sigchase_verify_sig(&rdata_name, rdataset,
5108                                           chase_keyrdataset,
5109                                           sigrdataset, mctx);
5110                 if (ret != ISC_R_SUCCESS) {
5111                         free_name(&rdata_name, mctx);
5112                         printf("\n;; Impossible to verify the NSEC RR to prove"
5113                                " the non-existence : FAILED\n\n");
5114                         goto cleanandgo;
5115                 }
5116                 free_name(&rdata_name, mctx);
5117                 if (result != ISC_R_SUCCESS) {
5118                         printf("\n;; Impossible to verify the non-existence:"
5119                                " FAILED\n\n");
5120                         goto cleanandgo;
5121                 } else {
5122                         printf("\n;; OK the query doesn't have response but"
5123                                " we have validate this fact : SUCCESS\n\n");
5124                         goto cleanandgo;
5125                 }
5126         }
5127
5128  cleanandgo:
5129         printf(";; cleanandgo \n");
5130         if (dns_name_dynamic(&chase_current_name))
5131                 free_name(&chase_current_name, mctx);
5132         if (dns_name_dynamic(&chase_authority_name))
5133                 free_name(&chase_authority_name, mctx);
5134         clean_trustedkey();
5135         return;
5136
5137         finalstep :
5138                 result = advanced_rrsearch(&chase_rdataset, &chase_name,
5139                                            current_lookup->rdtype_sigchase,
5140                                            dns_rdatatype_any ,
5141                                            &true);
5142         if (result == ISC_R_FAILURE) {
5143                 printf("\n;; RRsig of RRset is missing to continue validation"
5144                        " SHOULD NOT APPEND: FAILED\n\n");
5145                 goto cleanandgo;
5146         }
5147         result = sigchase_verify_sig(&chase_name, chase_rdataset,
5148                                      chase_keyrdataset,
5149                                      chase_sigrdataset, mctx);
5150         if (result != ISC_R_SUCCESS) {
5151                 printf("\n;; Impossible to verify the RRset : FAILED\n\n");
5152                 /*
5153                   printf("RRset:\n");
5154                   print_rdataset(&chase_name , chase_rdataset, mctx);
5155                   printf("DNSKEYset:\n");
5156                   print_rdataset(&chase_name , chase_keyrdataset, mctx);
5157                   printf("RRSIG of RRset:\n");
5158                   print_rdataset(&chase_name , chase_sigrdataset, mctx);
5159                   printf("\n");
5160                 */
5161                 goto cleanandgo;
5162         } else {
5163                 printf("\n;; The Answer:\n");
5164                 print_rdataset(&chase_name , chase_rdataset, mctx);
5165
5166                 printf("\n;; FINISH : we have validate the DNSSEC chain"
5167                        " of trust: SUCCESS\n\n");
5168                 goto cleanandgo;
5169         }
5170 }
5171
5172 #endif
5173
5174
5175 #if DIG_SIGCHASE_BU
5176
5177 isc_result_t
5178 getneededrr(dns_message_t *msg)
5179 {
5180         isc_result_t result;
5181         dns_name_t *name = NULL;
5182         dns_rdata_t sigrdata = DNS_RDATA_INIT;
5183         dns_rdata_sig_t siginfo;
5184         isc_boolean_t   true = ISC_TRUE;
5185
5186         if ((result = dns_message_firstname(msg, DNS_SECTION_ANSWER))
5187             != ISC_R_SUCCESS) {
5188                 printf(";; NO ANSWERS: %s\n", isc_result_totext(result));
5189
5190                 if (chase_name.ndata == NULL)
5191                         return (ISC_R_ADDRNOTAVAIL);
5192         } else {
5193                 dns_message_currentname(msg, DNS_SECTION_ANSWER, &name);
5194         }
5195
5196         /* What do we chase? */
5197         if (chase_rdataset == NULL) {
5198                 result = advanced_rrsearch(&chase_rdataset, name,
5199                                            dns_rdatatype_any,
5200                                            dns_rdatatype_any, &true);
5201                 if (result != ISC_R_SUCCESS) {
5202                         printf("\n;; No Answers: Validation FAILED\n\n");
5203                         return (ISC_R_NOTFOUND);
5204                 }
5205                 dup_name(name, &chase_name, mctx);
5206                 printf(";; RRset to chase:\n");
5207                 print_rdataset(&chase_name, chase_rdataset, mctx);
5208         }
5209         INSIST(chase_rdataset != NULL);
5210
5211
5212         if (chase_sigrdataset == NULL) {
5213                 result = advanced_rrsearch(&chase_sigrdataset, name,
5214                                            dns_rdatatype_rrsig,
5215                                            chase_rdataset->type,
5216                                            &chase_siglookedup);
5217                 if (result == ISC_R_FAILURE) {
5218                         printf("\n;; RRSIG is missing for continue validation:"
5219                                " FAILED\n\n");
5220                         if (dns_name_dynamic(&chase_name))
5221                                 free_name(&chase_name, mctx);
5222                         return (ISC_R_NOTFOUND);
5223                 }
5224                 if (result == ISC_R_NOTFOUND) {
5225                         return (ISC_R_NOTFOUND);
5226                 }
5227                 printf("\n;; RRSIG of the RRset to chase:\n");
5228                 print_rdataset(&chase_name, chase_sigrdataset, mctx);
5229         }
5230         INSIST(chase_sigrdataset != NULL);
5231
5232
5233         /* first find the DNSKEY name */
5234         result = dns_rdataset_first(chase_sigrdataset);
5235         check_result(result, "empty RRSIG dataset");
5236         dns_rdataset_current(chase_sigrdataset, &sigrdata);
5237         result = dns_rdata_tostruct(&sigrdata, &siginfo, NULL);
5238         check_result(result, "sigrdata tostruct siginfo");
5239         dup_name(&siginfo.signer, &chase_signame, mctx);
5240         dns_rdata_freestruct(&siginfo);
5241         dns_rdata_reset(&sigrdata);
5242
5243         /* Do we have a key?  */
5244         if (chase_keyrdataset == NULL) {
5245                 result = advanced_rrsearch(&chase_keyrdataset,
5246                                            &chase_signame,
5247                                            dns_rdatatype_dnskey,
5248                                            dns_rdatatype_any,
5249                                            &chase_keylookedup);
5250                 if (result == ISC_R_FAILURE) {
5251                         printf("\n;; DNSKEY is missing to continue validation:"
5252                                " FAILED\n\n");
5253                         free_name(&chase_signame, mctx);
5254                         if (dns_name_dynamic(&chase_name))
5255                                 free_name(&chase_name, mctx);
5256                         return (ISC_R_NOTFOUND);
5257                 }
5258                 if (result == ISC_R_NOTFOUND) {
5259                         free_name(&chase_signame, mctx);
5260                         return (ISC_R_NOTFOUND);
5261                 }
5262                 printf("\n;; DNSKEYset that signs the RRset to chase:\n");
5263                 print_rdataset(&chase_signame, chase_keyrdataset, mctx);
5264         }
5265         INSIST(chase_keyrdataset != NULL);
5266
5267         if (chase_sigkeyrdataset == NULL) {
5268                 result = advanced_rrsearch(&chase_sigkeyrdataset,
5269                                            &chase_signame,
5270                                            dns_rdatatype_rrsig,
5271                                            dns_rdatatype_dnskey,
5272                                            &chase_sigkeylookedup);
5273                 if (result == ISC_R_FAILURE) {
5274                         printf("\n;; RRSIG for DNSKEY  is missing  to continue"
5275                                " validation : FAILED\n\n");
5276                         free_name(&chase_signame, mctx);
5277                         if (dns_name_dynamic(&chase_name))
5278                                 free_name(&chase_name, mctx);
5279                         return (ISC_R_NOTFOUND);
5280                 }
5281                 if (result == ISC_R_NOTFOUND) {
5282                         free_name(&chase_signame, mctx);
5283                         return (ISC_R_NOTFOUND);
5284                 }
5285                 printf("\n;; RRSIG of the DNSKEYset that signs the "
5286                        "RRset to chase:\n");
5287                 print_rdataset(&chase_signame, chase_sigkeyrdataset, mctx);
5288         }
5289         INSIST(chase_sigkeyrdataset != NULL);
5290
5291
5292         if (chase_dsrdataset == NULL) {
5293                 result = advanced_rrsearch(&chase_dsrdataset, &chase_signame,
5294                                            dns_rdatatype_ds,
5295                                            dns_rdatatype_any,
5296                 &chase_dslookedup);
5297                 if (result == ISC_R_FAILURE) {
5298                         printf("\n;; WARNING There is no DS for the zone: ");
5299                         dns_name_print(&chase_signame, stdout);
5300                         printf("\n");
5301                 }
5302                 if (result == ISC_R_NOTFOUND) {
5303                         free_name(&chase_signame, mctx);
5304                         return (ISC_R_NOTFOUND);
5305                 }
5306                 if (chase_dsrdataset != NULL) {
5307                         printf("\n;; DSset of the DNSKEYset\n");
5308                         print_rdataset(&chase_signame, chase_dsrdataset, mctx);
5309                 }
5310         }
5311
5312         if (chase_dsrdataset != NULL) {
5313                 /*
5314                  * if there is no RRSIG of DS,
5315                  * we don't want to search on the network
5316                  */
5317                 result = advanced_rrsearch(&chase_sigdsrdataset,
5318                                            &chase_signame,
5319                                            dns_rdatatype_rrsig,
5320                                            dns_rdatatype_ds, &true);
5321                 if (result == ISC_R_FAILURE) {
5322                         printf(";; WARNING : NO RRSIG DS : RRSIG DS"
5323                                " should come with DS\n");
5324                         /*
5325                          * We continue even the DS couldn't be validated,
5326                          * because the DNSKEY could be a Trusted Key.
5327                          */
5328                         chase_dsrdataset = NULL;
5329                 } else {
5330                         printf("\n;; RRSIG of the DSset of the DNSKEYset\n");
5331                         print_rdataset(&chase_signame, chase_sigdsrdataset,
5332                                        mctx);
5333                 }
5334         }
5335         return (1);
5336 }
5337
5338
5339
5340 void
5341 sigchase_bu(dns_message_t *msg)
5342 {
5343         isc_result_t result;
5344         int ret;
5345
5346         if (tk_list.nb_tk == 0) {
5347                 result = get_trusted_key(mctx);
5348                 if (result != ISC_R_SUCCESS) {
5349                         printf("No trusted keys present\n");
5350                         return;
5351                 }
5352         }
5353
5354
5355         ret = getneededrr(msg);
5356         if (ret == ISC_R_NOTFOUND)
5357                 return;
5358
5359         if (ret == ISC_R_ADDRNOTAVAIL) {
5360                 /* We have no response */
5361                 dns_rdataset_t *rdataset;
5362                 dns_rdataset_t *sigrdataset;
5363                 dns_name_t rdata_name;
5364                 dns_name_t query_name;
5365
5366
5367                 dns_name_init(&query_name, NULL);
5368                 dns_name_init(&rdata_name, NULL);
5369                 nameFromString(current_lookup->textname, &query_name);
5370
5371                 result = prove_nx(msg, &query_name, current_lookup->rdclass,
5372                                   current_lookup->rdtype, &rdata_name,
5373                                   &rdataset, &sigrdataset);
5374                 free_name(&query_name, mctx);
5375                 if (rdataset == NULL || sigrdataset == NULL ||
5376                     dns_name_countlabels(&rdata_name) == 0) {
5377                         printf("\n;; Impossible to verify the Non-existence,"
5378                                " the NSEC RRset can't be validated: "
5379                                "FAILED\n\n");
5380                         clean_trustedkey();
5381                         return;
5382                 }
5383
5384                 if (result != ISC_R_SUCCESS) {
5385                         printf("\n No Answers and impossible to prove the"
5386                                " unsecurity : Validation FAILED\n\n");
5387                         clean_trustedkey();
5388                         return;
5389                 }
5390                 printf(";; An NSEC prove the non-existence of a answers,"
5391                        " Now we want validate this NSEC\n");
5392
5393                 dup_name(&rdata_name, &chase_name, mctx);
5394                 free_name(&rdata_name, mctx);
5395                 chase_rdataset =  rdataset;
5396                 chase_sigrdataset = sigrdataset;
5397                 chase_keyrdataset = NULL;
5398                 chase_sigkeyrdataset = NULL;
5399                 chase_dsrdataset = NULL;
5400                 chase_sigdsrdataset = NULL;
5401                 chase_siglookedup = ISC_FALSE;
5402                 chase_keylookedup = ISC_FALSE;
5403                 chase_dslookedup = ISC_FALSE;
5404                 chase_sigdslookedup = ISC_FALSE;
5405                 sigchase(msg);
5406                 clean_trustedkey();
5407                 return;
5408         }
5409
5410
5411         printf("\n\n\n;; WE HAVE MATERIAL, WE NOW DO VALIDATION\n");
5412
5413         result = sigchase_verify_sig(&chase_name, chase_rdataset,
5414                                      chase_keyrdataset,
5415                                      chase_sigrdataset, mctx);
5416         if (result != ISC_R_SUCCESS) {
5417                 free_name(&chase_name, mctx);
5418                 free_name(&chase_signame, mctx);
5419                 printf(";; No DNSKEY is valid to check the RRSIG"
5420                        " of the RRset: FAILED\n");
5421                 clean_trustedkey();
5422                 return;
5423         }
5424         printf(";; OK We found DNSKEY (or more) to validate the RRset\n");
5425
5426         result = contains_trusted_key(&chase_signame, chase_keyrdataset,
5427                                       chase_sigkeyrdataset, mctx);
5428         if (result ==  ISC_R_SUCCESS) {
5429                 free_name(&chase_name, mctx);
5430                 free_name(&chase_signame, mctx);
5431                 printf("\n;; Ok this DNSKEY is a Trusted Key,"
5432                        " DNSSEC validation is ok: SUCCESS\n\n");
5433                 clean_trustedkey();
5434                 return;
5435         }
5436
5437         printf(";; Now, we are going to validate this DNSKEY by the DS\n");
5438
5439         if (chase_dsrdataset == NULL) {
5440                 free_name(&chase_name, mctx);
5441                 free_name(&chase_signame, mctx);
5442                 printf(";; the DNSKEY isn't trusted-key and there isn't"
5443                        " DS to validate the DNSKEY: FAILED\n");
5444                 clean_trustedkey();
5445                 return;
5446         }
5447
5448         result =  sigchase_verify_ds(&chase_signame, chase_keyrdataset,
5449                                      chase_dsrdataset, mctx);
5450         if (result !=  ISC_R_SUCCESS) {
5451                 free_name(&chase_signame, mctx);
5452                 free_name(&chase_name, mctx);
5453                 printf(";; ERROR no DS validates a DNSKEY in the"
5454                        " DNSKEY RRset: FAILED\n");
5455                 clean_trustedkey();
5456                 return;
5457         } else
5458                 printf(";; OK this DNSKEY (validated by the DS) validates"
5459                        " the RRset of the DNSKEYs, thus the DNSKEY validates"
5460                        " the RRset\n");
5461         INSIST(chase_sigdsrdataset != NULL);
5462
5463         dup_name(&chase_signame, &chase_name, mctx);
5464         free_name(&chase_signame, mctx);
5465         chase_rdataset = chase_dsrdataset;
5466         chase_sigrdataset = chase_sigdsrdataset;
5467         chase_keyrdataset = NULL;
5468         chase_sigkeyrdataset = NULL;
5469         chase_dsrdataset = NULL;
5470         chase_sigdsrdataset = NULL;
5471         chase_siglookedup = chase_keylookedup = ISC_FALSE;
5472         chase_dslookedup = chase_sigdslookedup = ISC_FALSE;
5473
5474         printf(";; Now, we want to validate the DS :  recursive call\n");
5475         sigchase(msg);
5476         return;
5477 }
5478 #endif
5479
5480 void
5481 sigchase(dns_message_t *msg) {
5482 #if DIG_SIGCHASE_TD
5483         if (current_lookup->do_topdown) {
5484                 sigchase_td(msg);
5485                 return;
5486         }
5487 #endif
5488 #if DIG_SIGCHASE_BU
5489         sigchase_bu(msg);
5490         return;
5491 #endif
5492 }
5493
5494
5495 /*
5496  * return 1  if name1  <  name2
5497  *        0  if name1  == name2
5498  *        -1 if name1  >  name2
5499  *    and -2 if problem
5500  */
5501 int
5502 inf_name(dns_name_t *name1, dns_name_t *name2)
5503 {
5504         dns_label_t  label1;
5505         dns_label_t  label2;
5506         unsigned int nblabel1;
5507         unsigned int nblabel2;
5508         int min_lum_label;
5509         int i;
5510         int ret = -2;
5511
5512         nblabel1 = dns_name_countlabels(name1);
5513         nblabel2 = dns_name_countlabels(name2);
5514
5515         if (nblabel1 >= nblabel2)
5516                 min_lum_label = nblabel2;
5517         else
5518                 min_lum_label = nblabel1;
5519
5520
5521         for (i=1 ; i < min_lum_label; i++) {
5522                 dns_name_getlabel(name1, nblabel1 -1  - i, &label1);
5523                 dns_name_getlabel(name2, nblabel2 -1  - i, &label2);
5524                 if ((ret = isc_region_compare(&label1, &label2)) != 0) {
5525                         if (ret < 0)
5526                                 return (-1);
5527                         else if (ret > 0)
5528                                 return (1);
5529                 }
5530         }
5531         if (nblabel1 == nblabel2)
5532                 return (0);
5533
5534         if (nblabel1 < nblabel2)
5535                 return (-1);
5536         else
5537                 return (1);
5538 }
5539
5540 /**
5541  *
5542  *
5543  *
5544  */
5545 isc_result_t
5546 prove_nx_domain(dns_message_t *msg,
5547                 dns_name_t *name,
5548                 dns_name_t *rdata_name,
5549                 dns_rdataset_t **rdataset,
5550                 dns_rdataset_t **sigrdataset)
5551 {
5552         isc_result_t ret = ISC_R_FAILURE;
5553         isc_result_t result = ISC_R_NOTFOUND;
5554         dns_rdataset_t *nsecset = NULL;
5555         dns_rdataset_t *signsecset = NULL ;
5556         dns_rdata_t nsec = DNS_RDATA_INIT;
5557         dns_name_t *nsecname;
5558         dns_rdata_nsec_t nsecstruct;
5559
5560         if ((result = dns_message_firstname(msg, DNS_SECTION_AUTHORITY))
5561             != ISC_R_SUCCESS) {
5562                 printf(";; nothing in authority section : impossible to"
5563                        " validate the non-existence : FAILED\n");
5564                 return (ISC_R_FAILURE);
5565         }
5566
5567         do {
5568                 nsecname = NULL;
5569                 dns_message_currentname(msg, DNS_SECTION_AUTHORITY, &nsecname);
5570                 nsecset = search_type(nsecname, dns_rdatatype_nsec,
5571                                       dns_rdatatype_any);
5572                 if (nsecset == NULL)
5573                         continue;
5574
5575                 printf("There is a NSEC for this zone in the"
5576                        " AUTHORITY section:\n");
5577                 print_rdataset(nsecname, nsecset, mctx);
5578
5579                 for (result = dns_rdataset_first(nsecset);
5580                      result == ISC_R_SUCCESS;
5581                      result = dns_rdataset_next(nsecset)) {
5582                         dns_rdataset_current(nsecset, &nsec);
5583
5584
5585                         signsecset
5586                                 = chase_scanname_section(msg, nsecname,
5587                                                  dns_rdatatype_rrsig,
5588                                                  dns_rdatatype_nsec,
5589                                                  DNS_SECTION_AUTHORITY);
5590                         if (signsecset == NULL) {
5591                                 printf(";; no RRSIG NSEC in authority section:"
5592                                        " impossible to validate the "
5593                                        "non-existence: FAILED\n");
5594                                 return (ISC_R_FAILURE);
5595                         }
5596
5597                         ret = dns_rdata_tostruct(&nsec, &nsecstruct, NULL);
5598                         check_result(ret,"dns_rdata_tostruct");
5599
5600                         if ((inf_name(nsecname, &nsecstruct.next) == 1 &&
5601                              inf_name(name, &nsecstruct.next) == 1) ||
5602                             (inf_name(name, nsecname) == 1 &&
5603                              inf_name(&nsecstruct.next, name) == 1)) {
5604                                 dns_rdata_freestruct(&nsecstruct);
5605                                 *rdataset = nsecset;
5606                                 *sigrdataset = signsecset;
5607                                 dup_name(nsecname, rdata_name, mctx);
5608
5609                                 return (ISC_R_SUCCESS);
5610                         }
5611
5612                         dns_rdata_freestruct(&nsecstruct);
5613                         dns_rdata_reset(&nsec);
5614                 }
5615         } while (dns_message_nextname(msg, DNS_SECTION_AUTHORITY)
5616                  == ISC_R_SUCCESS);
5617
5618         *rdataset = NULL;
5619         *sigrdataset =  NULL;
5620         rdata_name = NULL;
5621         return (ISC_R_FAILURE);
5622 }
5623
5624 /**
5625  *
5626  *
5627  *
5628  *
5629  *
5630  */
5631 isc_result_t
5632 prove_nx_type(dns_message_t *msg, dns_name_t *name, dns_rdataset_t *nsecset,
5633               dns_rdataclass_t class, dns_rdatatype_t type,
5634               dns_name_t *rdata_name, dns_rdataset_t **rdataset,
5635               dns_rdataset_t **sigrdataset)
5636 {
5637         isc_result_t ret;
5638         dns_rdataset_t *signsecset;
5639         dns_rdata_t nsec = DNS_RDATA_INIT;
5640
5641         UNUSED(class);
5642
5643         ret = dns_rdataset_first(nsecset);
5644         check_result(ret,"dns_rdataset_first");
5645
5646         dns_rdataset_current(nsecset, &nsec);
5647
5648         ret = dns_nsec_typepresent(&nsec, type);
5649         if (ret == ISC_R_SUCCESS)
5650                 printf("OK the NSEC said that the type doesn't exist \n");
5651
5652         signsecset = chase_scanname_section(msg, name,
5653                                             dns_rdatatype_rrsig,
5654                                             dns_rdatatype_nsec,
5655                                             DNS_SECTION_AUTHORITY);
5656         if (signsecset == NULL) {
5657                 printf("There isn't RRSIG NSEC for the zone \n");
5658                 return (ISC_R_FAILURE);
5659         }
5660         dup_name(name, rdata_name, mctx);
5661         *rdataset = nsecset;
5662         *sigrdataset = signsecset;
5663
5664         return (ret);
5665 }
5666
5667 /**
5668  *
5669  *
5670  *
5671  *
5672  */
5673 isc_result_t
5674 prove_nx(dns_message_t *msg, dns_name_t *name, dns_rdataclass_t class,
5675          dns_rdatatype_t type, dns_name_t *rdata_name,
5676          dns_rdataset_t **rdataset, dns_rdataset_t **sigrdataset)
5677 {
5678         isc_result_t ret;
5679         dns_rdataset_t *nsecset = NULL;
5680
5681         printf("We want to prove the non-existence of a type of rdata %d"
5682                " or of the zone: \n", type);
5683
5684         if ((ret = dns_message_firstname(msg, DNS_SECTION_AUTHORITY))
5685             != ISC_R_SUCCESS) {
5686                 printf(";; nothing in authority section : impossible to"
5687                        " validate the non-existence : FAILED\n");
5688                 return (ISC_R_FAILURE);
5689         }
5690
5691         nsecset = chase_scanname_section(msg, name, dns_rdatatype_nsec,
5692                                          dns_rdatatype_any,
5693                                          DNS_SECTION_AUTHORITY);
5694         if (nsecset != NULL) {
5695                 printf("We have a NSEC for this zone :OK\n");
5696                 ret = prove_nx_type(msg, name, nsecset, class,
5697                                     type, rdata_name, rdataset,
5698                                     sigrdataset);
5699                 if (ret != ISC_R_SUCCESS) {
5700                         printf("prove_nx: ERROR type exist\n");
5701                         return (ret);
5702                 } else {
5703                         printf("prove_nx: OK type does not exist\n");
5704                         return (ISC_R_SUCCESS);
5705                 }
5706         } else {
5707                 printf("there is no NSEC for this zone: validating "
5708                        "that the zone doesn't exist\n");
5709                 ret = prove_nx_domain(msg, name, rdata_name,
5710                                       rdataset, sigrdataset);
5711                 return (ret);
5712         }
5713         /* Never get here */
5714 }
5715 #endif