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