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