Remove building with NOCRYPTO option
[minix.git] / external / bsd / bind / dist / bin / dig / dighost.c
blob5fe3cb54abad3cf65f2ac589d79dba1c89c16164
1 /* $NetBSD: dighost.c,v 1.15 2015/07/08 17:28:54 christos Exp $ */
3 /*
4 * Copyright (C) 2004-2015 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2000-2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: dighost.c,v 1.345 2011/12/07 17:23:28 each Exp */
22 /*! \file
23 * \note
24 * Notice to programmers: Do not use this code as an example of how to
25 * use the ISC library to perform DNS lookups. Dig and Host both operate
26 * on the request level, since they allow fine-tuning of output and are
27 * intended as debugging tools. As a result, they perform many of the
28 * functions which could be better handled using the dns_resolver
29 * functions in most applications.
32 #include <config.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <string.h>
36 #include <limits.h>
38 #ifdef HAVE_LOCALE_H
39 #include <locale.h>
40 #endif
42 #ifdef WITH_IDN
43 #include <idn/result.h>
44 #include <idn/log.h>
45 #include <idn/resconf.h>
46 #include <idn/api.h>
47 #endif
49 #include <dns/byaddr.h>
50 #ifdef DIG_SIGCHASE
51 #include <dns/callbacks.h>
52 #include <dns/dnssec.h>
53 #include <dns/ds.h>
54 #include <dns/master.h>
55 #include <dns/nsec.h>
56 #include <isc/random.h>
57 #include <ctype.h>
58 #endif
59 #include <dns/fixedname.h>
60 #include <dns/log.h>
61 #include <dns/message.h>
62 #include <dns/name.h>
63 #include <dns/rcode.h>
64 #include <dns/rdata.h>
65 #include <dns/rdataclass.h>
66 #include <dns/rdatalist.h>
67 #include <dns/rdataset.h>
68 #include <dns/rdatastruct.h>
69 #include <dns/rdatatype.h>
70 #include <dns/result.h>
71 #include <dns/tsig.h>
73 #include <dst/dst.h>
74 #include <dst/result.h>
76 #include <isc/app.h>
77 #include <isc/base64.h>
78 #include <isc/entropy.h>
79 #include <isc/file.h>
80 #include <isc/hex.h>
81 #include <isc/lang.h>
82 #include <isc/log.h>
83 #include <isc/netaddr.h>
84 #include <isc/netdb.h>
85 #include <isc/parseint.h>
86 #include <isc/print.h>
87 #include <isc/random.h>
88 #include <isc/result.h>
89 #include <isc/serial.h>
90 #include <isc/sockaddr.h>
91 #include <isc/string.h>
92 #include <isc/task.h>
93 #include <isc/timer.h>
94 #include <isc/types.h>
95 #include <isc/util.h>
97 #include <isccfg/namedconf.h>
99 #include <lwres/lwres.h>
100 #include <lwres/net.h>
102 #include <bind9/getaddresses.h>
104 #include <dig/dig.h>
106 #ifdef PKCS11CRYPTO
107 #include <pk11/result.h>
108 #endif
110 #if ! defined(NS_INADDRSZ)
111 #define NS_INADDRSZ 4
112 #endif
114 #if ! defined(NS_IN6ADDRSZ)
115 #define NS_IN6ADDRSZ 16
116 #endif
118 static lwres_context_t *lwctx = NULL;
119 static lwres_conf_t *lwconf;
121 dig_lookuplist_t lookup_list;
122 dig_serverlist_t server_list;
123 dig_searchlistlist_t search_list;
125 isc_boolean_t
126 check_ra = ISC_FALSE,
127 have_ipv4 = ISC_FALSE,
128 have_ipv6 = ISC_FALSE,
129 specified_source = ISC_FALSE,
130 free_now = ISC_FALSE,
131 cancel_now = ISC_FALSE,
132 usesearch = ISC_FALSE,
133 showsearch = ISC_FALSE,
134 qr = ISC_FALSE,
135 is_dst_up = ISC_FALSE,
136 keep_open = ISC_FALSE;
137 in_port_t port = 53;
138 unsigned int timeout = 0;
139 unsigned int extrabytes;
140 isc_mem_t *mctx = NULL;
141 isc_log_t *lctx = NULL;
142 isc_taskmgr_t *taskmgr = NULL;
143 isc_task_t *global_task = NULL;
144 isc_timermgr_t *timermgr = NULL;
145 isc_socketmgr_t *socketmgr = NULL;
146 isc_sockaddr_t bind_address;
147 isc_sockaddr_t bind_any;
148 int sendcount = 0;
149 int recvcount = 0;
150 int sockcount = 0;
151 int ndots = -1;
152 int tries = 3;
153 int lookup_counter = 0;
155 #ifdef WITH_IDN
156 static void initialize_idn(void);
157 static isc_result_t output_filter(isc_buffer_t *buffer,
158 unsigned int used_org,
159 isc_boolean_t absolute);
160 static idn_result_t append_textname(char *name, const char *origin,
161 size_t namesize);
162 static void idn_check_result(idn_result_t r, const char *msg);
164 #define MAXDLEN 256
165 int idnoptions = 0;
166 #endif
168 isc_socket_t *keep = NULL;
169 isc_sockaddr_t keepaddr;
172 * Exit Codes:
174 *\li 0 Everything went well, including things like NXDOMAIN
175 *\li 1 Usage error
176 *\li 7 Got too many RR's or Names
177 *\li 8 Couldn't open batch file
178 *\li 9 No reply from server
179 *\li 10 Internal error
181 int exitcode = 0;
182 int fatalexit = 0;
183 char keynametext[MXNAME];
184 char keyfile[MXNAME] = "";
185 char keysecret[MXNAME] = "";
186 unsigned char cookie_secret[33];
187 unsigned char cookie[8];
188 dns_name_t *hmacname = NULL;
189 unsigned int digestbits = 0;
190 isc_buffer_t *namebuf = NULL;
191 dns_tsigkey_t *key = NULL;
192 isc_boolean_t validated = ISC_TRUE;
193 isc_entropy_t *entp = NULL;
194 isc_mempool_t *commctx = NULL;
195 isc_boolean_t debugging = ISC_FALSE;
196 isc_boolean_t debugtiming = ISC_FALSE;
197 isc_boolean_t memdebugging = ISC_FALSE;
198 const char *progname = NULL;
199 isc_mutex_t lookup_lock;
200 dig_lookup_t *current_lookup = NULL;
202 #ifdef DIG_SIGCHASE
204 isc_result_t get_trusted_key(isc_mem_t *mctx);
205 dns_rdataset_t * sigchase_scanname(dns_rdatatype_t type,
206 dns_rdatatype_t covers,
207 isc_boolean_t *lookedup,
208 dns_name_t *rdata_name);
209 dns_rdataset_t * chase_scanname_section(dns_message_t *msg,
210 dns_name_t *name,
211 dns_rdatatype_t type,
212 dns_rdatatype_t covers,
213 int section);
214 isc_result_t advanced_rrsearch(dns_rdataset_t **rdataset,
215 dns_name_t *name,
216 dns_rdatatype_t type,
217 dns_rdatatype_t covers,
218 isc_boolean_t *lookedup);
219 isc_result_t sigchase_verify_sig_key(dns_name_t *name,
220 dns_rdataset_t *rdataset,
221 dst_key_t* dnsseckey,
222 dns_rdataset_t *sigrdataset,
223 isc_mem_t *mctx);
224 isc_result_t sigchase_verify_sig(dns_name_t *name,
225 dns_rdataset_t *rdataset,
226 dns_rdataset_t *keyrdataset,
227 dns_rdataset_t *sigrdataset,
228 isc_mem_t *mctx);
229 isc_result_t sigchase_verify_ds(dns_name_t *name,
230 dns_rdataset_t *keyrdataset,
231 dns_rdataset_t *dsrdataset,
232 isc_mem_t *mctx);
233 void sigchase(dns_message_t *msg);
234 void print_rdata(dns_rdata_t *rdata, isc_mem_t *mctx);
235 void print_rdataset(dns_name_t *name,
236 dns_rdataset_t *rdataset, isc_mem_t *mctx);
237 void dup_name(dns_name_t *source, dns_name_t* target,
238 isc_mem_t *mctx);
239 void free_name(dns_name_t *name, isc_mem_t *mctx);
240 void dump_database(void);
241 void dump_database_section(dns_message_t *msg, int section);
242 dns_rdataset_t * search_type(dns_name_t *name, dns_rdatatype_t type,
243 dns_rdatatype_t covers);
244 isc_result_t contains_trusted_key(dns_name_t *name,
245 dns_rdataset_t *rdataset,
246 dns_rdataset_t *sigrdataset,
247 isc_mem_t *mctx);
248 void print_type(dns_rdatatype_t type);
249 isc_result_t prove_nx_domain(dns_message_t * msg,
250 dns_name_t * name,
251 dns_name_t * rdata_name,
252 dns_rdataset_t ** rdataset,
253 dns_rdataset_t ** sigrdataset);
254 isc_result_t prove_nx_type(dns_message_t * msg, dns_name_t *name,
255 dns_rdataset_t *nsec,
256 dns_rdataclass_t class,
257 dns_rdatatype_t type,
258 dns_name_t * rdata_name,
259 dns_rdataset_t ** rdataset,
260 dns_rdataset_t ** sigrdataset);
261 isc_result_t prove_nx(dns_message_t * msg, dns_name_t * name,
262 dns_rdataclass_t class,
263 dns_rdatatype_t type,
264 dns_name_t * rdata_name,
265 dns_rdataset_t ** rdataset,
266 dns_rdataset_t ** sigrdataset);
267 static void nameFromString(const char *str, dns_name_t *p_ret);
268 int inf_name(dns_name_t * name1, dns_name_t * name2);
269 isc_result_t removetmpkey(isc_mem_t *mctx, const char *file);
270 void clean_trustedkey(void);
271 isc_result_t insert_trustedkey(void *arg, dns_name_t *name,
272 dns_rdataset_t *rdataset);
273 #if DIG_SIGCHASE_BU
274 isc_result_t getneededrr(dns_message_t *msg);
275 void sigchase_bottom_up(dns_message_t *msg);
276 void sigchase_bu(dns_message_t *msg);
277 #endif
278 #if DIG_SIGCHASE_TD
279 isc_result_t initialization(dns_name_t *name);
280 isc_result_t prepare_lookup(dns_name_t *name);
281 isc_result_t grandfather_pb_test(dns_name_t * zone_name,
282 dns_rdataset_t *sigrdataset);
283 isc_result_t child_of_zone(dns_name_t *name,
284 dns_name_t *zone_name,
285 dns_name_t *child_name);
286 void sigchase_td(dns_message_t *msg);
287 #endif
288 char trustedkey[MXNAME] = "";
290 dns_rdataset_t *chase_rdataset = NULL;
291 dns_rdataset_t *chase_sigrdataset = NULL;
292 dns_rdataset_t *chase_dsrdataset = NULL;
293 dns_rdataset_t *chase_sigdsrdataset = NULL;
294 dns_rdataset_t *chase_keyrdataset = NULL;
295 dns_rdataset_t *chase_sigkeyrdataset = NULL;
296 dns_rdataset_t *chase_nsrdataset = NULL;
298 dns_name_t chase_name; /* the query name */
299 #if DIG_SIGCHASE_TD
301 * the current name is the parent name when we follow delegation
303 dns_name_t chase_current_name;
305 * the child name is used for delegation (NS DS responses in AUTHORITY section)
307 dns_name_t chase_authority_name;
308 #endif
309 #if DIG_SIGCHASE_BU
310 dns_name_t chase_signame;
311 #endif
314 isc_boolean_t chase_siglookedup = ISC_FALSE;
315 isc_boolean_t chase_keylookedup = ISC_FALSE;
316 isc_boolean_t chase_sigkeylookedup = ISC_FALSE;
317 isc_boolean_t chase_dslookedup = ISC_FALSE;
318 isc_boolean_t chase_sigdslookedup = ISC_FALSE;
319 #if DIG_SIGCHASE_TD
320 isc_boolean_t chase_nslookedup = ISC_FALSE;
321 isc_boolean_t chase_lookedup = ISC_FALSE;
324 isc_boolean_t delegation_follow = ISC_FALSE;
325 isc_boolean_t grandfather_pb = ISC_FALSE;
326 isc_boolean_t have_response = ISC_FALSE;
327 isc_boolean_t have_delegation_ns = ISC_FALSE;
328 dns_message_t * error_message = NULL;
329 #endif
331 isc_boolean_t dsvalidating = ISC_FALSE;
332 isc_boolean_t chase_name_dup = ISC_FALSE;
334 ISC_LIST(dig_message_t) chase_message_list;
335 ISC_LIST(dig_message_t) chase_message_list2;
338 #define MAX_TRUSTED_KEY 5
339 typedef struct struct_trusted_key_list {
340 dst_key_t * key[MAX_TRUSTED_KEY];
341 int nb_tk;
342 } struct_tk_list;
344 struct_tk_list tk_list = { {NULL, NULL, NULL, NULL, NULL}, 0};
346 #endif
348 #define DIG_MAX_ADDRESSES 20
351 * Apply and clear locks at the event level in global task.
352 * Can I get rid of these using shutdown events? XXX
354 #define LOCK_LOOKUP {\
355 debug("lock_lookup %s:%d", __FILE__, __LINE__);\
356 check_result(isc_mutex_lock((&lookup_lock)), "isc_mutex_lock");\
357 debug("success");\
359 #define UNLOCK_LOOKUP {\
360 debug("unlock_lookup %s:%d", __FILE__, __LINE__);\
361 check_result(isc_mutex_unlock((&lookup_lock)),\
362 "isc_mutex_unlock");\
365 static void
366 cancel_lookup(dig_lookup_t *lookup);
368 static void
369 recv_done(isc_task_t *task, isc_event_t *event);
371 static void
372 send_udp(dig_query_t *query);
374 static void
375 connect_timeout(isc_task_t *task, isc_event_t *event);
377 static void
378 launch_next_query(dig_query_t *query, isc_boolean_t include_question);
380 static void
381 check_next_lookup(dig_lookup_t *lookup);
383 static isc_boolean_t
384 next_origin(dig_lookup_t *oldlookup);
386 static void *
387 mem_alloc(void *arg, size_t size) {
388 return (isc_mem_get(arg, size));
391 static void
392 mem_free(void *arg, void *mem, size_t size) {
393 isc_mem_put(arg, mem, size);
396 char *
397 next_token(char **stringp, const char *delim) {
398 char *res;
400 do {
401 res = strsep(stringp, delim);
402 if (res == NULL)
403 break;
404 } while (*res == '\0');
405 return (res);
408 static int
409 count_dots(char *string) {
410 char *s;
411 int i = 0;
413 s = string;
414 while (*s != '\0') {
415 if (*s == '.')
416 i++;
417 s++;
419 return (i);
422 static void
423 hex_dump(isc_buffer_t *b) {
424 unsigned int len, i;
425 isc_region_t r;
427 isc_buffer_usedregion(b, &r);
429 printf("%d bytes\n", r.length);
430 for (len = 0; len < r.length; len++) {
431 printf("%02x ", r.base[len]);
432 if (len % 16 == 15) {
433 fputs(" ", stdout);
434 for (i = len - 15; i <= len; i++) {
435 if (r.base[i] >= '!' && r.base[i] <= '}')
436 putchar(r.base[i]);
437 else
438 putchar('.');
440 printf("\n");
443 if (len % 16 != 0) {
444 for (i = len; (i % 16) != 0; i++)
445 fputs(" ", stdout);
446 fputs(" ", stdout);
447 for (i = ((len>>4)<<4); i < len; i++) {
448 if (r.base[i] >= '!' && r.base[i] <= '}')
449 putchar(r.base[i]);
450 else
451 putchar('.');
453 printf("\n");
458 * Append 'len' bytes of 'text' at '*p', failing with
459 * ISC_R_NOSPACE if that would advance p past 'end'.
461 static isc_result_t
462 append(const char *text, int len, char **p, char *end) {
463 if (len > end - *p)
464 return (ISC_R_NOSPACE);
465 memmove(*p, text, len);
466 *p += len;
467 return (ISC_R_SUCCESS);
470 static isc_result_t
471 reverse_octets(const char *in, char **p, char *end) {
472 char *dot = strchr(in, '.');
473 int len;
474 if (dot != NULL) {
475 isc_result_t result;
476 result = reverse_octets(dot + 1, p, end);
477 if (result != ISC_R_SUCCESS)
478 return (result);
479 result = append(".", 1, p, end);
480 if (result != ISC_R_SUCCESS)
481 return (result);
482 len = (int)(dot - in);
483 } else {
484 len = strlen(in);
486 return (append(in, len, p, end));
489 isc_result_t
490 get_reverse(char *reverse, size_t len, char *value, isc_boolean_t ip6_int,
491 isc_boolean_t strict)
493 int r;
494 isc_result_t result;
495 isc_netaddr_t addr;
497 addr.family = AF_INET6;
498 r = inet_pton(AF_INET6, value, &addr.type.in6);
499 if (r > 0) {
500 /* This is a valid IPv6 address. */
501 dns_fixedname_t fname;
502 dns_name_t *name;
503 unsigned int options = 0;
505 if (ip6_int)
506 options |= DNS_BYADDROPT_IPV6INT;
507 dns_fixedname_init(&fname);
508 name = dns_fixedname_name(&fname);
509 result = dns_byaddr_createptrname2(&addr, options, name);
510 if (result != ISC_R_SUCCESS)
511 return (result);
512 dns_name_format(name, reverse, (unsigned int)len);
513 return (ISC_R_SUCCESS);
514 } else {
516 * Not a valid IPv6 address. Assume IPv4.
517 * If 'strict' is not set, construct the
518 * in-addr.arpa name by blindly reversing
519 * octets whether or not they look like integers,
520 * so that this can be used for RFC2317 names
521 * and such.
523 char *p = reverse;
524 char *end = reverse + len;
525 if (strict && inet_pton(AF_INET, value, &addr.type.in) != 1)
526 return (DNS_R_BADDOTTEDQUAD);
527 result = reverse_octets(value, &p, end);
528 if (result != ISC_R_SUCCESS)
529 return (result);
530 /* Append .in-addr.arpa. and a terminating NUL. */
531 result = append(".in-addr.arpa.", 15, &p, end);
532 if (result != ISC_R_SUCCESS)
533 return (result);
534 return (ISC_R_SUCCESS);
538 void
539 fatal(const char *format, ...) {
540 va_list args;
542 fflush(stdout);
543 fprintf(stderr, "%s: ", progname);
544 va_start(args, format);
545 vfprintf(stderr, format, args);
546 va_end(args);
547 fprintf(stderr, "\n");
548 if (exitcode < 10)
549 exitcode = 10;
550 if (fatalexit != 0)
551 exitcode = fatalexit;
552 exit(exitcode);
555 void
556 debug(const char *format, ...) {
557 va_list args;
558 isc_time_t t;
560 if (debugging) {
561 fflush(stdout);
562 if (debugtiming) {
563 TIME_NOW(&t);
564 fprintf(stderr, "%d.%06d: ", isc_time_seconds(&t),
565 isc_time_nanoseconds(&t) / 1000);
567 va_start(args, format);
568 vfprintf(stderr, format, args);
569 va_end(args);
570 fprintf(stderr, "\n");
574 void
575 check_result(isc_result_t result, const char *msg) {
576 if (result != ISC_R_SUCCESS) {
577 fatal("%s: %s", msg, isc_result_totext(result));
582 * Create a server structure, which is part of the lookup structure.
583 * This is little more than a linked list of servers to query in hopes
584 * of finding the answer the user is looking for
586 dig_server_t *
587 make_server(const char *servname, const char *userarg) {
588 dig_server_t *srv;
590 REQUIRE(servname != NULL);
592 debug("make_server(%s)", servname);
593 srv = isc_mem_allocate(mctx, sizeof(struct dig_server));
594 if (srv == NULL)
595 fatal("memory allocation failure in %s:%d",
596 __FILE__, __LINE__);
597 strlcpy(srv->servername, servname, MXNAME);
598 strlcpy(srv->userarg, userarg, MXNAME);
599 ISC_LINK_INIT(srv, link);
600 return (srv);
603 static int
604 addr2af(int lwresaddrtype)
606 int af = 0;
608 switch (lwresaddrtype) {
609 case LWRES_ADDRTYPE_V4:
610 af = AF_INET;
611 break;
613 case LWRES_ADDRTYPE_V6:
614 af = AF_INET6;
615 break;
618 return (af);
622 * Create a copy of the server list from the lwres configuration structure.
623 * The dest list must have already had ISC_LIST_INIT applied.
625 static void
626 copy_server_list(lwres_conf_t *confdata, dig_serverlist_t *dest) {
627 dig_server_t *newsrv;
628 char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") +
629 sizeof("%4000000000")];
630 int af;
631 int i;
633 debug("copy_server_list()");
634 for (i = 0; i < confdata->nsnext; i++) {
635 af = addr2af(confdata->nameservers[i].family);
637 if (af == AF_INET && !have_ipv4)
638 continue;
639 if (af == AF_INET6 && !have_ipv6)
640 continue;
642 lwres_net_ntop(af, confdata->nameservers[i].address,
643 tmp, sizeof(tmp));
644 if (af == AF_INET6 && confdata->nameservers[i].zone != 0) {
645 char buf[sizeof("%4000000000")];
646 snprintf(buf, sizeof(buf), "%%%u",
647 confdata->nameservers[i].zone);
648 strlcat(tmp, buf, sizeof(tmp));
650 newsrv = make_server(tmp, tmp);
651 ISC_LINK_INIT(newsrv, link);
652 ISC_LIST_ENQUEUE(*dest, newsrv, link);
656 void
657 flush_server_list(void) {
658 dig_server_t *s, *ps;
660 debug("flush_server_list()");
661 s = ISC_LIST_HEAD(server_list);
662 while (s != NULL) {
663 ps = s;
664 s = ISC_LIST_NEXT(s, link);
665 ISC_LIST_DEQUEUE(server_list, ps, link);
666 isc_mem_free(mctx, ps);
670 void
671 set_nameserver(char *opt) {
672 isc_result_t result;
673 isc_sockaddr_t sockaddrs[DIG_MAX_ADDRESSES];
674 isc_netaddr_t netaddr;
675 int count, i;
676 dig_server_t *srv;
677 char tmp[ISC_NETADDR_FORMATSIZE];
679 if (opt == NULL)
680 return;
682 result = bind9_getaddresses(opt, 0, sockaddrs,
683 DIG_MAX_ADDRESSES, &count);
684 if (result != ISC_R_SUCCESS)
685 fatal("couldn't get address for '%s': %s",
686 opt, isc_result_totext(result));
688 flush_server_list();
690 for (i = 0; i < count; i++) {
691 isc_netaddr_fromsockaddr(&netaddr, &sockaddrs[i]);
692 isc_netaddr_format(&netaddr, tmp, sizeof(tmp));
693 srv = make_server(tmp, opt);
694 if (srv == NULL)
695 fatal("memory allocation failure");
696 ISC_LIST_APPEND(server_list, srv, link);
700 static isc_result_t
701 add_nameserver(lwres_conf_t *confdata, const char *addr, int af) {
703 int i = confdata->nsnext;
705 if (confdata->nsnext >= LWRES_CONFMAXNAMESERVERS)
706 return (ISC_R_FAILURE);
708 switch (af) {
709 case AF_INET:
710 confdata->nameservers[i].family = LWRES_ADDRTYPE_V4;
711 confdata->nameservers[i].length = NS_INADDRSZ;
712 break;
713 case AF_INET6:
714 confdata->nameservers[i].family = LWRES_ADDRTYPE_V6;
715 confdata->nameservers[i].length = NS_IN6ADDRSZ;
716 break;
717 default:
718 return (ISC_R_FAILURE);
721 if (lwres_net_pton(af, addr, &confdata->nameservers[i].address) == 1) {
722 confdata->nsnext++;
723 return (ISC_R_SUCCESS);
725 return (ISC_R_FAILURE);
729 * Produce a cloned server list. The dest list must have already had
730 * ISC_LIST_INIT applied.
732 void
733 clone_server_list(dig_serverlist_t src, dig_serverlist_t *dest) {
734 dig_server_t *srv, *newsrv;
736 debug("clone_server_list()");
737 srv = ISC_LIST_HEAD(src);
738 while (srv != NULL) {
739 newsrv = make_server(srv->servername, srv->userarg);
740 ISC_LINK_INIT(newsrv, link);
741 ISC_LIST_ENQUEUE(*dest, newsrv, link);
742 srv = ISC_LIST_NEXT(srv, link);
747 * Create an empty lookup structure, which holds all the information needed
748 * to get an answer to a user's question. This structure contains two
749 * linked lists: the server list (servers to query) and the query list
750 * (outstanding queries which have been made to the listed servers).
752 dig_lookup_t *
753 make_empty_lookup(void) {
754 dig_lookup_t *looknew;
756 debug("make_empty_lookup()");
758 INSIST(!free_now);
760 looknew = isc_mem_allocate(mctx, sizeof(struct dig_lookup));
761 if (looknew == NULL)
762 fatal("memory allocation failure in %s:%d",
763 __FILE__, __LINE__);
764 looknew->pending = ISC_TRUE;
765 looknew->textname[0] = 0;
766 looknew->cmdline[0] = 0;
767 looknew->rdtype = dns_rdatatype_a;
768 looknew->qrdtype = dns_rdatatype_a;
769 looknew->rdclass = dns_rdataclass_in;
770 looknew->rdtypeset = ISC_FALSE;
771 looknew->rdclassset = ISC_FALSE;
772 looknew->sendspace = NULL;
773 looknew->sendmsg = NULL;
774 looknew->name = NULL;
775 looknew->oname = NULL;
776 looknew->timer = NULL;
777 looknew->xfr_q = NULL;
778 looknew->current_query = NULL;
779 looknew->doing_xfr = ISC_FALSE;
780 looknew->ixfr_serial = 0;
781 looknew->trace = ISC_FALSE;
782 looknew->trace_root = ISC_FALSE;
783 looknew->identify = ISC_FALSE;
784 looknew->identify_previous_line = ISC_FALSE;
785 looknew->ignore = ISC_FALSE;
786 looknew->servfail_stops = ISC_TRUE;
787 looknew->besteffort = ISC_TRUE;
788 looknew->dnssec = ISC_FALSE;
789 looknew->expire = ISC_FALSE;
790 looknew->nsid = ISC_FALSE;
791 #ifdef ISC_PLATFORM_USESIT
792 looknew->sit = ISC_FALSE;
793 #endif
794 #ifdef DIG_SIGCHASE
795 looknew->sigchase = ISC_FALSE;
796 #if DIG_SIGCHASE_TD
797 looknew->do_topdown = ISC_FALSE;
798 looknew->trace_root_sigchase = ISC_FALSE;
799 looknew->rdtype_sigchaseset = ISC_FALSE;
800 looknew->rdtype_sigchase = dns_rdatatype_any;
801 looknew->qrdtype_sigchase = dns_rdatatype_any;
802 looknew->rdclass_sigchase = dns_rdataclass_in;
803 looknew->rdclass_sigchaseset = ISC_FALSE;
804 #endif
805 #endif
806 looknew->udpsize = 0;
807 looknew->edns = -1;
808 looknew->recurse = ISC_TRUE;
809 looknew->aaonly = ISC_FALSE;
810 looknew->adflag = ISC_FALSE;
811 looknew->cdflag = ISC_FALSE;
812 looknew->ns_search_only = ISC_FALSE;
813 looknew->origin = NULL;
814 looknew->tsigctx = NULL;
815 looknew->querysig = NULL;
816 looknew->retries = tries;
817 looknew->nsfound = 0;
818 looknew->tcp_mode = ISC_FALSE;
819 looknew->tcp_mode_set = ISC_FALSE;
820 looknew->ip6_int = ISC_FALSE;
821 looknew->comments = ISC_TRUE;
822 looknew->stats = ISC_TRUE;
823 looknew->section_question = ISC_TRUE;
824 looknew->section_answer = ISC_TRUE;
825 looknew->section_authority = ISC_TRUE;
826 looknew->section_additional = ISC_TRUE;
827 looknew->new_search = ISC_FALSE;
828 looknew->done_as_is = ISC_FALSE;
829 looknew->need_search = ISC_FALSE;
830 looknew->ecs_addr = NULL;
831 #ifdef ISC_PLATFORM_USESIT
832 looknew->sitvalue = NULL;
833 #endif
834 dns_fixedname_init(&looknew->fdomain);
835 ISC_LINK_INIT(looknew, link);
836 ISC_LIST_INIT(looknew->q);
837 ISC_LIST_INIT(looknew->connecting);
838 ISC_LIST_INIT(looknew->my_server_list);
839 return (looknew);
843 * Clone a lookup, perhaps copying the server list. This does not clone
844 * the query list, since it will be regenerated by the setup_lookup()
845 * function, nor does it queue up the new lookup for processing.
846 * Caution: If you don't clone the servers, you MUST clone the server
847 * list separately from somewhere else, or construct it by hand.
849 dig_lookup_t *
850 clone_lookup(dig_lookup_t *lookold, isc_boolean_t servers) {
851 dig_lookup_t *looknew;
853 debug("clone_lookup()");
855 INSIST(!free_now);
857 looknew = make_empty_lookup();
858 INSIST(looknew != NULL);
859 strlcpy(looknew->textname, lookold->textname, MXNAME);
860 #if DIG_SIGCHASE_TD
861 strlcpy(looknew->textnamesigchase, lookold->textnamesigchase, MXNAME);
862 #endif
863 strlcpy(looknew->cmdline, lookold->cmdline, MXNAME);
864 looknew->textname[MXNAME-1] = 0;
865 looknew->rdtype = lookold->rdtype;
866 looknew->qrdtype = lookold->qrdtype;
867 looknew->rdclass = lookold->rdclass;
868 looknew->rdtypeset = lookold->rdtypeset;
869 looknew->rdclassset = lookold->rdclassset;
870 looknew->doing_xfr = lookold->doing_xfr;
871 looknew->ixfr_serial = lookold->ixfr_serial;
872 looknew->trace = lookold->trace;
873 looknew->trace_root = lookold->trace_root;
874 looknew->identify = lookold->identify;
875 looknew->identify_previous_line = lookold->identify_previous_line;
876 looknew->ignore = lookold->ignore;
877 looknew->servfail_stops = lookold->servfail_stops;
878 looknew->besteffort = lookold->besteffort;
879 looknew->dnssec = lookold->dnssec;
880 looknew->expire = lookold->expire;
881 looknew->nsid = lookold->nsid;
882 #ifdef ISC_PLATFORM_USESIT
883 looknew->sit = lookold->sit;
884 looknew->sitvalue = lookold->sitvalue;
885 #endif
886 #ifdef DIG_SIGCHASE
887 looknew->sigchase = lookold->sigchase;
888 #if DIG_SIGCHASE_TD
889 looknew->do_topdown = lookold->do_topdown;
890 looknew->trace_root_sigchase = lookold->trace_root_sigchase;
891 looknew->rdtype_sigchaseset = lookold->rdtype_sigchaseset;
892 looknew->rdtype_sigchase = lookold->rdtype_sigchase;
893 looknew->qrdtype_sigchase = lookold->qrdtype_sigchase;
894 looknew->rdclass_sigchase = lookold->rdclass_sigchase;
895 looknew->rdclass_sigchaseset = lookold->rdclass_sigchaseset;
896 #endif
897 #endif
898 looknew->udpsize = lookold->udpsize;
899 looknew->edns = lookold->edns;
900 looknew->recurse = lookold->recurse;
901 looknew->aaonly = lookold->aaonly;
902 looknew->adflag = lookold->adflag;
903 looknew->cdflag = lookold->cdflag;
904 looknew->ns_search_only = lookold->ns_search_only;
905 looknew->tcp_mode = lookold->tcp_mode;
906 looknew->tcp_mode_set = lookold->tcp_mode_set;
907 looknew->comments = lookold->comments;
908 looknew->stats = lookold->stats;
909 looknew->section_question = lookold->section_question;
910 looknew->section_answer = lookold->section_answer;
911 looknew->section_authority = lookold->section_authority;
912 looknew->section_additional = lookold->section_additional;
913 looknew->retries = lookold->retries;
914 looknew->tsigctx = NULL;
915 looknew->need_search = lookold->need_search;
916 looknew->done_as_is = lookold->done_as_is;
918 if (lookold->ecs_addr != NULL) {
919 size_t len = sizeof(isc_sockaddr_t);
920 looknew->ecs_addr = isc_mem_allocate(mctx, len);
921 memmove(looknew->ecs_addr, lookold->ecs_addr, len);
924 dns_name_copy(dns_fixedname_name(&lookold->fdomain),
925 dns_fixedname_name(&looknew->fdomain), NULL);
927 if (servers)
928 clone_server_list(lookold->my_server_list,
929 &looknew->my_server_list);
930 return (looknew);
934 * Requeue a lookup for further processing, perhaps copying the server
935 * list. The new lookup structure is returned to the caller, and is
936 * queued for processing. If servers are not cloned in the requeue, they
937 * must be added before allowing the current event to complete, since the
938 * completion of the event may result in the next entry on the lookup
939 * queue getting run.
941 dig_lookup_t *
942 requeue_lookup(dig_lookup_t *lookold, isc_boolean_t servers) {
943 dig_lookup_t *looknew;
945 debug("requeue_lookup()");
947 lookup_counter++;
948 if (lookup_counter > LOOKUP_LIMIT)
949 fatal("too many lookups");
951 looknew = clone_lookup(lookold, servers);
952 INSIST(looknew != NULL);
954 debug("before insertion, init@%p -> %p, new@%p -> %p",
955 lookold, lookold->link.next, looknew, looknew->link.next);
956 ISC_LIST_PREPEND(lookup_list, looknew, link);
957 debug("after insertion, init -> %p, new = %p, new -> %p",
958 lookold, looknew, looknew->link.next);
959 return (looknew);
963 static void
964 setup_text_key(void) {
965 isc_result_t result;
966 dns_name_t keyname;
967 isc_buffer_t secretbuf;
968 int secretsize;
969 unsigned char *secretstore;
971 debug("setup_text_key()");
972 result = isc_buffer_allocate(mctx, &namebuf, MXNAME);
973 check_result(result, "isc_buffer_allocate");
974 dns_name_init(&keyname, NULL);
975 check_result(result, "dns_name_init");
976 isc_buffer_putstr(namebuf, keynametext);
977 secretsize = strlen(keysecret) * 3 / 4;
978 secretstore = isc_mem_allocate(mctx, secretsize);
979 if (secretstore == NULL)
980 fatal("memory allocation failure in %s:%d",
981 __FILE__, __LINE__);
982 isc_buffer_init(&secretbuf, secretstore, secretsize);
983 result = isc_base64_decodestring(keysecret, &secretbuf);
984 if (result != ISC_R_SUCCESS)
985 goto failure;
987 secretsize = isc_buffer_usedlength(&secretbuf);
989 if (hmacname == NULL) {
990 result = DST_R_UNSUPPORTEDALG;
991 goto failure;
994 result = dns_name_fromtext(&keyname, namebuf, dns_rootname, 0, namebuf);
995 if (result != ISC_R_SUCCESS)
996 goto failure;
998 result = dns_tsigkey_create(&keyname, hmacname, secretstore,
999 secretsize, ISC_FALSE, NULL, 0, 0, mctx,
1000 NULL, &key);
1001 failure:
1002 if (result != ISC_R_SUCCESS)
1003 printf(";; Couldn't create key %s: %s\n",
1004 keynametext, isc_result_totext(result));
1005 else
1006 dst_key_setbits(key->key, digestbits);
1008 isc_mem_free(mctx, secretstore);
1009 dns_name_invalidate(&keyname);
1010 isc_buffer_free(&namebuf);
1013 isc_result_t
1014 parse_uint(isc_uint32_t *uip, const char *value, isc_uint32_t max,
1015 const char *desc) {
1016 isc_uint32_t n;
1017 isc_result_t result = isc_parse_uint32(&n, value, 10);
1018 if (result == ISC_R_SUCCESS && n > max)
1019 result = ISC_R_RANGE;
1020 if (result != ISC_R_SUCCESS) {
1021 printf("invalid %s '%s': %s\n", desc,
1022 value, isc_result_totext(result));
1023 return (result);
1025 *uip = n;
1026 return (ISC_R_SUCCESS);
1029 static isc_uint32_t
1030 parse_bits(char *arg, const char *desc, isc_uint32_t max) {
1031 isc_result_t result;
1032 isc_uint32_t tmp;
1034 result = parse_uint(&tmp, arg, max, desc);
1035 if (result != ISC_R_SUCCESS)
1036 fatal("couldn't parse digest bits");
1037 tmp = (tmp + 7) & ~0x7U;
1038 return (tmp);
1041 isc_result_t
1042 parse_netprefix(isc_sockaddr_t **sap, const char *value) {
1043 isc_result_t result = ISC_R_SUCCESS;
1044 isc_sockaddr_t *sa = NULL;
1045 struct in_addr in4;
1046 struct in6_addr in6;
1047 isc_uint32_t netmask = 0;
1048 char *slash = NULL;
1049 isc_boolean_t parsed = ISC_FALSE;
1051 if ((slash = strchr(value, '/'))) {
1052 *slash = '\0';
1053 result = isc_parse_uint32(&netmask, slash + 1, 10);
1054 if (result != ISC_R_SUCCESS) {
1055 *slash = '/';
1056 fatal("invalid prefix length '%s': %s\n",
1057 value, isc_result_totext(result));
1061 sa = isc_mem_allocate(mctx, sizeof(*sa));
1062 if (inet_pton(AF_INET6, value, &in6) == 1) {
1063 isc_sockaddr_fromin6(sa, &in6, 0);
1064 parsed = ISC_TRUE;
1065 if (netmask == 0 || netmask > 128)
1066 netmask = 128;
1067 } else if (inet_pton(AF_INET, value, &in4) == 1) {
1068 parsed = ISC_TRUE;
1069 isc_sockaddr_fromin(sa, &in4, 0);
1070 if (netmask == 0 || netmask > 32)
1071 netmask = 32;
1072 } else if (netmask != 0) {
1073 char buf[64];
1074 int i;
1076 strlcpy(buf, value, sizeof(buf));
1077 for (i = 0; i < 3; i++) {
1078 strlcat(buf, ".0", sizeof(buf));
1079 if (inet_pton(AF_INET, buf, &in4) == 1) {
1080 parsed = ISC_TRUE;
1081 isc_sockaddr_fromin(sa, &in4, 0);
1082 break;
1088 if (slash != NULL)
1089 *slash = '/';
1091 if (!parsed)
1092 fatal("invalid address '%s'", value);
1094 sa->length = netmask;
1095 *sap = sa;
1097 return (ISC_R_SUCCESS);
1102 * Parse HMAC algorithm specification
1104 void
1105 parse_hmac(const char *hmac) {
1106 char buf[20];
1107 int len;
1109 REQUIRE(hmac != NULL);
1111 len = strlen(hmac);
1112 if (len >= (int) sizeof(buf))
1113 fatal("unknown key type '%.*s'", len, hmac);
1114 strlcpy(buf, hmac, sizeof(buf));
1116 digestbits = 0;
1118 if (strcasecmp(buf, "hmac-md5") == 0) {
1119 hmacname = DNS_TSIG_HMACMD5_NAME;
1120 } else if (strncasecmp(buf, "hmac-md5-", 9) == 0) {
1121 hmacname = DNS_TSIG_HMACMD5_NAME;
1122 digestbits = parse_bits(&buf[9], "digest-bits [0..128]", 128);
1123 } else if (strcasecmp(buf, "hmac-sha1") == 0) {
1124 hmacname = DNS_TSIG_HMACSHA1_NAME;
1125 digestbits = 0;
1126 } else if (strncasecmp(buf, "hmac-sha1-", 10) == 0) {
1127 hmacname = DNS_TSIG_HMACSHA1_NAME;
1128 digestbits = parse_bits(&buf[10], "digest-bits [0..160]", 160);
1129 } else if (strcasecmp(buf, "hmac-sha224") == 0) {
1130 hmacname = DNS_TSIG_HMACSHA224_NAME;
1131 } else if (strncasecmp(buf, "hmac-sha224-", 12) == 0) {
1132 hmacname = DNS_TSIG_HMACSHA224_NAME;
1133 digestbits = parse_bits(&buf[12], "digest-bits [0..224]", 224);
1134 } else if (strcasecmp(buf, "hmac-sha256") == 0) {
1135 hmacname = DNS_TSIG_HMACSHA256_NAME;
1136 } else if (strncasecmp(buf, "hmac-sha256-", 12) == 0) {
1137 hmacname = DNS_TSIG_HMACSHA256_NAME;
1138 digestbits = parse_bits(&buf[12], "digest-bits [0..256]", 256);
1139 } else if (strcasecmp(buf, "hmac-sha384") == 0) {
1140 hmacname = DNS_TSIG_HMACSHA384_NAME;
1141 } else if (strncasecmp(buf, "hmac-sha384-", 12) == 0) {
1142 hmacname = DNS_TSIG_HMACSHA384_NAME;
1143 digestbits = parse_bits(&buf[12], "digest-bits [0..384]", 384);
1144 } else if (strcasecmp(buf, "hmac-sha512") == 0) {
1145 hmacname = DNS_TSIG_HMACSHA512_NAME;
1146 } else if (strncasecmp(buf, "hmac-sha512-", 12) == 0) {
1147 hmacname = DNS_TSIG_HMACSHA512_NAME;
1148 digestbits = parse_bits(&buf[12], "digest-bits [0..512]", 512);
1149 } else {
1150 fprintf(stderr, ";; Warning, ignoring "
1151 "invalid TSIG algorithm %s\n", buf);
1156 * Get a key from a named.conf format keyfile
1158 static isc_result_t
1159 read_confkey(void) {
1160 cfg_parser_t *pctx = NULL;
1161 cfg_obj_t *file = NULL;
1162 const cfg_obj_t *keyobj = NULL;
1163 const cfg_obj_t *secretobj = NULL;
1164 const cfg_obj_t *algorithmobj = NULL;
1165 const char *keyname;
1166 const char *secretstr;
1167 const char *algorithm;
1168 isc_result_t result;
1170 if (! isc_file_exists(keyfile))
1171 return (ISC_R_FILENOTFOUND);
1173 result = cfg_parser_create(mctx, NULL, &pctx);
1174 if (result != ISC_R_SUCCESS)
1175 goto cleanup;
1177 result = cfg_parse_file(pctx, keyfile, &cfg_type_sessionkey,
1178 &file);
1179 if (result != ISC_R_SUCCESS)
1180 goto cleanup;
1182 result = cfg_map_get(file, "key", &keyobj);
1183 if (result != ISC_R_SUCCESS)
1184 goto cleanup;
1186 (void) cfg_map_get(keyobj, "secret", &secretobj);
1187 (void) cfg_map_get(keyobj, "algorithm", &algorithmobj);
1188 if (secretobj == NULL || algorithmobj == NULL)
1189 fatal("key must have algorithm and secret");
1191 keyname = cfg_obj_asstring(cfg_map_getname(keyobj));
1192 secretstr = cfg_obj_asstring(secretobj);
1193 algorithm = cfg_obj_asstring(algorithmobj);
1195 strlcpy(keynametext, keyname, sizeof(keynametext));
1196 strlcpy(keysecret, secretstr, sizeof(keysecret));
1197 parse_hmac(algorithm);
1198 setup_text_key();
1200 cleanup:
1201 if (pctx != NULL) {
1202 if (file != NULL)
1203 cfg_obj_destroy(pctx, &file);
1204 cfg_parser_destroy(&pctx);
1207 return (result);
1210 static void
1211 setup_file_key(void) {
1212 isc_result_t result;
1213 dst_key_t *dstkey = NULL;
1215 debug("setup_file_key()");
1217 /* Try reading the key from a K* pair */
1218 result = dst_key_fromnamedfile(keyfile, NULL,
1219 DST_TYPE_PRIVATE | DST_TYPE_KEY, mctx,
1220 &dstkey);
1222 /* If that didn't work, try reading it as a session.key keyfile */
1223 if (result != ISC_R_SUCCESS) {
1224 result = read_confkey();
1225 if (result == ISC_R_SUCCESS)
1226 return;
1229 if (result != ISC_R_SUCCESS) {
1230 fprintf(stderr, "Couldn't read key from %s: %s\n",
1231 keyfile, isc_result_totext(result));
1232 goto failure;
1235 switch (dst_key_alg(dstkey)) {
1236 case DST_ALG_HMACMD5:
1237 hmacname = DNS_TSIG_HMACMD5_NAME;
1238 break;
1239 case DST_ALG_HMACSHA1:
1240 hmacname = DNS_TSIG_HMACSHA1_NAME;
1241 break;
1242 case DST_ALG_HMACSHA224:
1243 hmacname = DNS_TSIG_HMACSHA224_NAME;
1244 break;
1245 case DST_ALG_HMACSHA256:
1246 hmacname = DNS_TSIG_HMACSHA256_NAME;
1247 break;
1248 case DST_ALG_HMACSHA384:
1249 hmacname = DNS_TSIG_HMACSHA384_NAME;
1250 break;
1251 case DST_ALG_HMACSHA512:
1252 hmacname = DNS_TSIG_HMACSHA512_NAME;
1253 break;
1254 default:
1255 printf(";; Couldn't create key %s: bad algorithm\n",
1256 keynametext);
1257 goto failure;
1259 result = dns_tsigkey_createfromkey(dst_key_name(dstkey), hmacname,
1260 dstkey, ISC_FALSE, NULL, 0, 0,
1261 mctx, NULL, &key);
1262 if (result != ISC_R_SUCCESS) {
1263 printf(";; Couldn't create key %s: %s\n",
1264 keynametext, isc_result_totext(result));
1265 goto failure;
1267 failure:
1268 if (dstkey != NULL)
1269 dst_key_free(&dstkey);
1272 static dig_searchlist_t *
1273 make_searchlist_entry(char *domain) {
1274 dig_searchlist_t *search;
1275 search = isc_mem_allocate(mctx, sizeof(*search));
1276 if (search == NULL)
1277 fatal("memory allocation failure in %s:%d",
1278 __FILE__, __LINE__);
1279 strlcpy(search->origin, domain, MXNAME);
1280 search->origin[MXNAME-1] = 0;
1281 ISC_LINK_INIT(search, link);
1282 return (search);
1285 static void
1286 clear_searchlist(void) {
1287 dig_searchlist_t *search;
1288 while ((search = ISC_LIST_HEAD(search_list)) != NULL) {
1289 ISC_LIST_UNLINK(search_list, search, link);
1290 isc_mem_free(mctx, search);
1294 static void
1295 create_search_list(lwres_conf_t *confdata) {
1296 int i;
1297 dig_searchlist_t *search;
1299 debug("create_search_list()");
1300 clear_searchlist();
1302 for (i = 0; i < confdata->searchnxt; i++) {
1303 search = make_searchlist_entry(confdata->search[i]);
1304 ISC_LIST_APPEND(search_list, search, link);
1309 * Setup the system as a whole, reading key information and resolv.conf
1310 * settings.
1312 void
1313 setup_system(void) {
1314 dig_searchlist_t *domain = NULL;
1315 lwres_result_t lwresult;
1316 unsigned int lwresflags;
1317 isc_result_t result;
1319 debug("setup_system()");
1321 lwresflags = LWRES_CONTEXT_SERVERMODE;
1322 if (have_ipv4)
1323 lwresflags |= LWRES_CONTEXT_USEIPV4;
1324 if (have_ipv6)
1325 lwresflags |= LWRES_CONTEXT_USEIPV6;
1327 lwresult = lwres_context_create(&lwctx, mctx, mem_alloc, mem_free,
1328 lwresflags);
1329 if (lwresult != LWRES_R_SUCCESS)
1330 fatal("lwres_context_create failed");
1332 lwresult = lwres_conf_parse(lwctx, RESOLV_CONF);
1333 if (lwresult != LWRES_R_SUCCESS && lwresult != LWRES_R_NOTFOUND)
1334 fatal("parse of %s failed", RESOLV_CONF);
1336 lwconf = lwres_conf_get(lwctx);
1338 /* Make the search list */
1339 if (lwconf->searchnxt > 0)
1340 create_search_list(lwconf);
1341 else { /* No search list. Use the domain name if any */
1342 if (lwconf->domainname != NULL) {
1343 domain = make_searchlist_entry(lwconf->domainname);
1344 ISC_LIST_APPEND(search_list, domain, link);
1345 domain = NULL;
1349 if (ndots == -1) {
1350 ndots = lwconf->ndots;
1351 debug("ndots is %d.", ndots);
1354 /* If user doesn't specify server use nameservers from resolv.conf. */
1355 if (ISC_LIST_EMPTY(server_list))
1356 copy_server_list(lwconf, &server_list);
1358 /* If we don't find a nameserver fall back to localhost */
1359 if (ISC_LIST_EMPTY(server_list)) {
1360 if (have_ipv4) {
1361 lwresult = add_nameserver(lwconf, "127.0.0.1", AF_INET);
1362 if (lwresult != ISC_R_SUCCESS)
1363 fatal("add_nameserver failed");
1365 if (have_ipv6) {
1366 lwresult = add_nameserver(lwconf, "::1", AF_INET6);
1367 if (lwresult != ISC_R_SUCCESS)
1368 fatal("add_nameserver failed");
1371 copy_server_list(lwconf, &server_list);
1374 #ifdef WITH_IDN
1375 initialize_idn();
1376 #endif
1378 if (keyfile[0] != 0)
1379 setup_file_key();
1380 else if (keysecret[0] != 0)
1381 setup_text_key();
1382 #ifdef DIG_SIGCHASE
1383 /* Setup the list of messages for +sigchase */
1384 ISC_LIST_INIT(chase_message_list);
1385 ISC_LIST_INIT(chase_message_list2);
1386 dns_name_init(&chase_name, NULL);
1387 #if DIG_SIGCHASE_TD
1388 dns_name_init(&chase_current_name, NULL);
1389 dns_name_init(&chase_authority_name, NULL);
1390 #endif
1391 #if DIG_SIGCHASE_BU
1392 dns_name_init(&chase_signame, NULL);
1393 #endif
1395 #endif
1396 result = isc_entropy_getdata(entp, cookie_secret,
1397 sizeof(cookie_secret), NULL, 0);
1398 if (result != ISC_R_SUCCESS)
1399 fatal("unable to generate cookie secret");
1403 * Override the search list derived from resolv.conf by 'domain'.
1405 void
1406 set_search_domain(char *domain) {
1407 dig_searchlist_t *search;
1409 clear_searchlist();
1410 search = make_searchlist_entry(domain);
1411 ISC_LIST_APPEND(search_list, search, link);
1415 * Setup the ISC and DNS libraries for use by the system.
1417 void
1418 setup_libs(void) {
1419 isc_result_t result;
1420 isc_logconfig_t *logconfig = NULL;
1422 debug("setup_libs()");
1424 #ifdef PKCS11CRYPTO
1425 pk11_result_register();
1426 #endif
1427 dns_result_register();
1429 result = isc_net_probeipv4();
1430 if (result == ISC_R_SUCCESS)
1431 have_ipv4 = ISC_TRUE;
1433 result = isc_net_probeipv6();
1434 if (result == ISC_R_SUCCESS)
1435 have_ipv6 = ISC_TRUE;
1436 if (!have_ipv6 && !have_ipv4)
1437 fatal("can't find either v4 or v6 networking");
1439 result = isc_mem_create(0, 0, &mctx);
1440 check_result(result, "isc_mem_create");
1441 isc_mem_setname(mctx, "dig", NULL);
1443 result = isc_log_create(mctx, &lctx, &logconfig);
1444 check_result(result, "isc_log_create");
1446 isc_log_setcontext(lctx);
1447 dns_log_init(lctx);
1448 dns_log_setcontext(lctx);
1450 result = isc_log_usechannel(logconfig, "default_debug", NULL, NULL);
1451 check_result(result, "isc_log_usechannel");
1453 isc_log_setdebuglevel(lctx, 0);
1455 result = isc_taskmgr_create(mctx, 1, 0, &taskmgr);
1456 check_result(result, "isc_taskmgr_create");
1458 result = isc_task_create(taskmgr, 0, &global_task);
1459 check_result(result, "isc_task_create");
1460 isc_task_setname(global_task, "dig", NULL);
1462 result = isc_timermgr_create(mctx, &timermgr);
1463 check_result(result, "isc_timermgr_create");
1465 result = isc_socketmgr_create(mctx, &socketmgr);
1466 check_result(result, "isc_socketmgr_create");
1468 result = isc_entropy_create(mctx, &entp);
1469 check_result(result, "isc_entropy_create");
1471 result = dst_lib_init(mctx, entp, 0);
1472 check_result(result, "dst_lib_init");
1473 is_dst_up = ISC_TRUE;
1475 result = isc_mempool_create(mctx, COMMSIZE, &commctx);
1476 check_result(result, "isc_mempool_create");
1477 isc_mempool_setname(commctx, "COMMPOOL");
1479 * 6 and 2 set as reasonable parameters for 3 or 4 nameserver
1480 * systems.
1482 isc_mempool_setfreemax(commctx, 6);
1483 isc_mempool_setfillcount(commctx, 2);
1485 result = isc_mutex_init(&lookup_lock);
1486 check_result(result, "isc_mutex_init");
1490 * Add EDNS0 option record to a message. Currently, the only supported
1491 * options are UDP buffer size, the DO bit, and EDNS options
1492 * (e.g., NSID, SIT, client-subnet)
1494 static void
1495 add_opt(dns_message_t *msg, isc_uint16_t udpsize, isc_uint16_t edns,
1496 isc_boolean_t dnssec, dns_ednsopt_t *opts, size_t count)
1498 dns_rdataset_t *rdataset = NULL;
1499 isc_result_t result;
1500 unsigned int flags = 0;
1502 debug("add_opt()");
1503 if (dnssec)
1504 flags |= DNS_MESSAGEEXTFLAG_DO;
1505 result = dns_message_buildopt(msg, &rdataset, edns, udpsize, flags,
1506 opts, count);
1507 check_result(result, "dns_message_buildopt");
1508 result = dns_message_setopt(msg, rdataset);
1509 check_result(result, "dns_message_setopt");
1513 * Add a question section to a message, asking for the specified name,
1514 * type, and class.
1516 static void
1517 add_question(dns_message_t *message, dns_name_t *name,
1518 dns_rdataclass_t rdclass, dns_rdatatype_t rdtype)
1520 dns_rdataset_t *rdataset;
1521 isc_result_t result;
1523 debug("add_question()");
1524 rdataset = NULL;
1525 result = dns_message_gettemprdataset(message, &rdataset);
1526 check_result(result, "dns_message_gettemprdataset()");
1527 dns_rdataset_makequestion(rdataset, rdclass, rdtype);
1528 ISC_LIST_APPEND(name->list, rdataset, link);
1532 * Check if we're done with all the queued lookups, which is true iff
1533 * all sockets, sends, and recvs are accounted for (counters == 0),
1534 * and the lookup list is empty.
1535 * If we are done, pass control back out to dighost_shutdown() (which is
1536 * part of dig.c, host.c, or nslookup.c) to either shutdown the system as
1537 * a whole or reseed the lookup list.
1539 static void
1540 check_if_done(void) {
1541 debug("check_if_done()");
1542 debug("list %s", ISC_LIST_EMPTY(lookup_list) ? "empty" : "full");
1543 if (ISC_LIST_EMPTY(lookup_list) && current_lookup == NULL &&
1544 sendcount == 0) {
1545 INSIST(sockcount == 0);
1546 INSIST(recvcount == 0);
1547 debug("shutting down");
1548 dighost_shutdown();
1553 * Clear out a query when we're done with it. WARNING: This routine
1554 * WILL invalidate the query pointer.
1556 static void
1557 clear_query(dig_query_t *query) {
1558 dig_lookup_t *lookup;
1560 REQUIRE(query != NULL);
1562 debug("clear_query(%p)", query);
1564 lookup = query->lookup;
1566 if (lookup->current_query == query)
1567 lookup->current_query = NULL;
1569 if (ISC_LINK_LINKED(query, link))
1570 ISC_LIST_UNLINK(lookup->q, query, link);
1571 if (ISC_LINK_LINKED(query, clink))
1572 ISC_LIST_UNLINK(lookup->connecting, query, clink);
1573 if (ISC_LINK_LINKED(&query->recvbuf, link))
1574 ISC_LIST_DEQUEUE(query->recvlist, &query->recvbuf,
1575 link);
1576 if (ISC_LINK_LINKED(&query->lengthbuf, link))
1577 ISC_LIST_DEQUEUE(query->lengthlist, &query->lengthbuf,
1578 link);
1579 INSIST(query->recvspace != NULL);
1581 if (query->sock != NULL) {
1582 isc_socket_detach(&query->sock);
1583 sockcount--;
1584 debug("sockcount=%d", sockcount);
1586 isc_mempool_put(commctx, query->recvspace);
1587 isc_buffer_invalidate(&query->recvbuf);
1588 isc_buffer_invalidate(&query->lengthbuf);
1589 if (query->waiting_senddone)
1590 query->pending_free = ISC_TRUE;
1591 else
1592 isc_mem_free(mctx, query);
1596 * Try and clear out a lookup if we're done with it. Return ISC_TRUE if
1597 * the lookup was successfully cleared. If ISC_TRUE is returned, the
1598 * lookup pointer has been invalidated.
1600 static isc_boolean_t
1601 try_clear_lookup(dig_lookup_t *lookup) {
1602 dig_query_t *q;
1604 REQUIRE(lookup != NULL);
1606 debug("try_clear_lookup(%p)", lookup);
1608 if (ISC_LIST_HEAD(lookup->q) != NULL ||
1609 ISC_LIST_HEAD(lookup->connecting) != NULL)
1611 if (debugging) {
1612 q = ISC_LIST_HEAD(lookup->q);
1613 while (q != NULL) {
1614 debug("query to %s still pending", q->servname);
1615 q = ISC_LIST_NEXT(q, link);
1618 q = ISC_LIST_HEAD(lookup->connecting);
1619 while (q != NULL) {
1620 debug("query to %s still connecting",
1621 q->servname);
1622 q = ISC_LIST_NEXT(q, clink);
1625 return (ISC_FALSE);
1629 * At this point, we know there are no queries on the lookup,
1630 * so can make it go away also.
1632 destroy_lookup(lookup);
1633 return (ISC_TRUE);
1636 void
1637 destroy_lookup(dig_lookup_t *lookup) {
1638 dig_server_t *s;
1639 void *ptr;
1641 debug("destroy");
1642 s = ISC_LIST_HEAD(lookup->my_server_list);
1643 while (s != NULL) {
1644 debug("freeing server %p belonging to %p", s, lookup);
1645 ptr = s;
1646 s = ISC_LIST_NEXT(s, link);
1647 ISC_LIST_DEQUEUE(lookup->my_server_list,
1648 (dig_server_t *)ptr, link);
1649 isc_mem_free(mctx, ptr);
1651 if (lookup->sendmsg != NULL)
1652 dns_message_destroy(&lookup->sendmsg);
1653 if (lookup->querysig != NULL) {
1654 debug("freeing buffer %p", lookup->querysig);
1655 isc_buffer_free(&lookup->querysig);
1657 if (lookup->timer != NULL)
1658 isc_timer_detach(&lookup->timer);
1659 if (lookup->sendspace != NULL)
1660 isc_mempool_put(commctx, lookup->sendspace);
1662 if (lookup->tsigctx != NULL)
1663 dst_context_destroy(&lookup->tsigctx);
1665 if (lookup->ecs_addr != NULL)
1666 isc_mem_free(mctx, lookup->ecs_addr);
1668 isc_mem_free(mctx, lookup);
1672 * If we can, start the next lookup in the queue running.
1673 * This assumes that the lookup on the head of the queue hasn't been
1674 * started yet. It also removes the lookup from the head of the queue,
1675 * setting the current_lookup pointer pointing to it.
1677 void
1678 start_lookup(void) {
1679 debug("start_lookup()");
1680 if (cancel_now)
1681 return;
1684 * If there's a current lookup running, we really shouldn't get
1685 * here.
1687 INSIST(current_lookup == NULL);
1689 current_lookup = ISC_LIST_HEAD(lookup_list);
1691 * Put the current lookup somewhere so cancel_all can find it
1693 if (current_lookup != NULL) {
1694 ISC_LIST_DEQUEUE(lookup_list, current_lookup, link);
1695 #if DIG_SIGCHASE_TD
1696 if (current_lookup->do_topdown &&
1697 !current_lookup->rdtype_sigchaseset) {
1698 dst_key_t *trustedkey = NULL;
1699 isc_buffer_t *b = NULL;
1700 isc_region_t r;
1701 isc_result_t result;
1702 dns_name_t query_name;
1703 dns_name_t *key_name;
1704 int i;
1706 result = get_trusted_key(mctx);
1707 if (result != ISC_R_SUCCESS) {
1708 printf("\n;; No trusted key, "
1709 "+sigchase option is disabled\n");
1710 current_lookup->sigchase = ISC_FALSE;
1711 goto novalidation;
1713 dns_name_init(&query_name, NULL);
1714 nameFromString(current_lookup->textname, &query_name);
1716 for (i = 0; i < tk_list.nb_tk; i++) {
1717 key_name = dst_key_name(tk_list.key[i]);
1719 if (dns_name_issubdomain(&query_name,
1720 key_name) == ISC_TRUE)
1721 trustedkey = tk_list.key[i];
1723 * Verify temp is really the lowest
1724 * WARNING
1727 if (trustedkey == NULL) {
1728 printf("\n;; The queried zone: ");
1729 dns_name_print(&query_name, stdout);
1730 printf(" isn't a subdomain of any Trusted Keys"
1731 ": +sigchase option is disable\n");
1732 current_lookup->sigchase = ISC_FALSE;
1733 free_name(&query_name, mctx);
1734 goto novalidation;
1736 free_name(&query_name, mctx);
1738 current_lookup->rdtype_sigchase
1739 = current_lookup->rdtype;
1740 current_lookup->rdtype_sigchaseset
1741 = current_lookup->rdtypeset;
1742 current_lookup->rdtype = dns_rdatatype_ns;
1744 current_lookup->qrdtype_sigchase
1745 = current_lookup->qrdtype;
1746 current_lookup->qrdtype = dns_rdatatype_ns;
1748 current_lookup->rdclass_sigchase
1749 = current_lookup->rdclass;
1750 current_lookup->rdclass_sigchaseset
1751 = current_lookup->rdclassset;
1752 current_lookup->rdclass = dns_rdataclass_in;
1754 strlcpy(current_lookup->textnamesigchase,
1755 current_lookup->textname, MXNAME);
1757 current_lookup->trace_root_sigchase = ISC_TRUE;
1759 result = isc_buffer_allocate(mctx, &b, BUFSIZE);
1760 check_result(result, "isc_buffer_allocate");
1761 result = dns_name_totext(dst_key_name(trustedkey),
1762 ISC_FALSE, b);
1763 check_result(result, "dns_name_totext");
1764 isc_buffer_usedregion(b, &r);
1765 r.base[r.length] = '\0';
1766 strlcpy(current_lookup->textname, (char*)r.base,
1767 MXNAME);
1768 isc_buffer_free(&b);
1770 nameFromString(current_lookup->textnamesigchase,
1771 &chase_name);
1773 dns_name_init(&chase_authority_name, NULL);
1775 novalidation:
1776 #endif
1777 if (setup_lookup(current_lookup))
1778 do_lookup(current_lookup);
1779 else if (next_origin(current_lookup))
1780 check_next_lookup(current_lookup);
1781 } else {
1782 check_if_done();
1787 * If we can, clear the current lookup and start the next one running.
1788 * This calls try_clear_lookup, so may invalidate the lookup pointer.
1790 static void
1791 check_next_lookup(dig_lookup_t *lookup) {
1793 INSIST(!free_now);
1795 debug("check_next_lookup(%p)", lookup);
1797 if (ISC_LIST_HEAD(lookup->q) != NULL) {
1798 debug("still have a worker");
1799 return;
1801 if (try_clear_lookup(lookup)) {
1802 current_lookup = NULL;
1803 start_lookup();
1808 * Create and queue a new lookup as a followup to the current lookup,
1809 * based on the supplied message and section. This is used in trace and
1810 * name server search modes to start a new lookup using servers from
1811 * NS records in a reply. Returns the number of followup lookups made.
1813 static int
1814 followup_lookup(dns_message_t *msg, dig_query_t *query, dns_section_t section)
1816 dig_lookup_t *lookup = NULL;
1817 dig_server_t *srv = NULL;
1818 dns_rdataset_t *rdataset = NULL;
1819 dns_rdata_t rdata = DNS_RDATA_INIT;
1820 dns_name_t *name = NULL;
1821 isc_result_t result;
1822 isc_boolean_t success = ISC_FALSE;
1823 int numLookups = 0;
1824 int num;
1825 isc_result_t lresult, addresses_result;
1826 char bad_namestr[DNS_NAME_FORMATSIZE];
1827 dns_name_t *domain;
1828 isc_boolean_t horizontal = ISC_FALSE, bad = ISC_FALSE;
1830 INSIST(!free_now);
1832 debug("following up %s", query->lookup->textname);
1834 addresses_result = ISC_R_SUCCESS;
1835 bad_namestr[0] = '\0';
1836 for (result = dns_message_firstname(msg, section);
1837 result == ISC_R_SUCCESS;
1838 result = dns_message_nextname(msg, section)) {
1839 name = NULL;
1840 dns_message_currentname(msg, section, &name);
1842 if (section == DNS_SECTION_AUTHORITY) {
1843 rdataset = NULL;
1844 result = dns_message_findtype(name, dns_rdatatype_soa,
1845 0, &rdataset);
1846 if (result == ISC_R_SUCCESS)
1847 return (0);
1849 rdataset = NULL;
1850 result = dns_message_findtype(name, dns_rdatatype_ns, 0,
1851 &rdataset);
1852 if (result != ISC_R_SUCCESS)
1853 continue;
1855 debug("found NS set");
1857 if (query->lookup->trace && !query->lookup->trace_root) {
1858 dns_namereln_t namereln;
1859 unsigned int nlabels;
1860 int order;
1862 domain = dns_fixedname_name(&query->lookup->fdomain);
1863 namereln = dns_name_fullcompare(name, domain,
1864 &order, &nlabels);
1865 if (namereln == dns_namereln_equal) {
1866 if (!horizontal)
1867 printf(";; BAD (HORIZONTAL) REFERRAL\n");
1868 horizontal = ISC_TRUE;
1869 } else if (namereln != dns_namereln_subdomain) {
1870 if (!bad)
1871 printf(";; BAD REFERRAL\n");
1872 bad = ISC_TRUE;
1873 continue;
1877 for (result = dns_rdataset_first(rdataset);
1878 result == ISC_R_SUCCESS;
1879 result = dns_rdataset_next(rdataset)) {
1880 char namestr[DNS_NAME_FORMATSIZE];
1881 dns_rdata_ns_t ns;
1883 if (query->lookup->trace_root &&
1884 query->lookup->nsfound >= MXSERV)
1885 break;
1887 dns_rdataset_current(rdataset, &rdata);
1889 query->lookup->nsfound++;
1890 result = dns_rdata_tostruct(&rdata, &ns, NULL);
1891 check_result(result, "dns_rdata_tostruct");
1892 dns_name_format(&ns.name, namestr, sizeof(namestr));
1893 dns_rdata_freestruct(&ns);
1895 /* Initialize lookup if we've not yet */
1896 debug("found NS %s", namestr);
1897 if (!success) {
1898 success = ISC_TRUE;
1899 lookup_counter++;
1900 lookup = requeue_lookup(query->lookup,
1901 ISC_FALSE);
1902 cancel_lookup(query->lookup);
1903 lookup->doing_xfr = ISC_FALSE;
1904 if (!lookup->trace_root &&
1905 section == DNS_SECTION_ANSWER)
1906 lookup->trace = ISC_FALSE;
1907 else
1908 lookup->trace = query->lookup->trace;
1909 lookup->ns_search_only =
1910 query->lookup->ns_search_only;
1911 lookup->trace_root = ISC_FALSE;
1912 if (lookup->ns_search_only)
1913 lookup->recurse = ISC_FALSE;
1914 domain = dns_fixedname_name(&lookup->fdomain);
1915 dns_name_copy(name, domain, NULL);
1917 debug("adding server %s", namestr);
1918 num = getaddresses(lookup, namestr, &lresult);
1919 if (lresult != ISC_R_SUCCESS) {
1920 printf("couldn't get address for '%s': %s\n",
1921 namestr, isc_result_totext(lresult));
1922 if (addresses_result == ISC_R_SUCCESS) {
1923 addresses_result = lresult;
1924 strcpy(bad_namestr, namestr);
1927 numLookups += num;
1928 dns_rdata_reset(&rdata);
1931 if (numLookups == 0 && addresses_result != ISC_R_SUCCESS) {
1932 fatal("couldn't get address for '%s': %s",
1933 bad_namestr, isc_result_totext(result));
1936 if (lookup == NULL &&
1937 section == DNS_SECTION_ANSWER &&
1938 (query->lookup->trace || query->lookup->ns_search_only))
1939 return (followup_lookup(msg, query, DNS_SECTION_AUTHORITY));
1942 * Randomize the order the nameserver will be tried.
1944 if (numLookups > 1) {
1945 isc_uint32_t i, j;
1946 dig_serverlist_t my_server_list;
1947 dig_server_t *next;
1949 ISC_LIST_INIT(my_server_list);
1951 i = numLookups;
1952 for (srv = ISC_LIST_HEAD(lookup->my_server_list);
1953 srv != NULL;
1954 srv = ISC_LIST_HEAD(lookup->my_server_list)) {
1955 INSIST(i > 0);
1956 isc_random_get(&j);
1957 j %= i;
1958 next = ISC_LIST_NEXT(srv, link);
1959 while (j-- > 0 && next != NULL) {
1960 srv = next;
1961 next = ISC_LIST_NEXT(srv, link);
1963 ISC_LIST_DEQUEUE(lookup->my_server_list, srv, link);
1964 ISC_LIST_APPEND(my_server_list, srv, link);
1965 i--;
1967 ISC_LIST_APPENDLIST(lookup->my_server_list,
1968 my_server_list, link);
1971 return (numLookups);
1975 * Create and queue a new lookup using the next origin from the search
1976 * list, read in setup_system().
1978 * Return ISC_TRUE iff there was another searchlist entry.
1980 static isc_boolean_t
1981 next_origin(dig_lookup_t *oldlookup) {
1982 dig_lookup_t *newlookup;
1983 dig_searchlist_t *search;
1984 dns_fixedname_t fixed;
1985 dns_name_t *name;
1986 isc_result_t result;
1988 INSIST(!free_now);
1990 debug("next_origin()");
1991 debug("following up %s", oldlookup->textname);
1993 if (!usesearch)
1995 * We're not using a search list, so don't even think
1996 * about finding the next entry.
1998 return (ISC_FALSE);
2001 * Check for a absolute name or ndots being met.
2003 dns_fixedname_init(&fixed);
2004 name = dns_fixedname_name(&fixed);
2005 result = dns_name_fromstring2(name, oldlookup->textname, NULL,
2006 0, NULL);
2007 if (result == ISC_R_SUCCESS &&
2008 (dns_name_isabsolute(name) ||
2009 (int)dns_name_countlabels(name) > ndots))
2010 return (ISC_FALSE);
2012 if (oldlookup->origin == NULL && !oldlookup->need_search)
2014 * Then we just did rootorg; there's nothing left.
2016 return (ISC_FALSE);
2017 if (oldlookup->origin == NULL && oldlookup->need_search) {
2018 newlookup = requeue_lookup(oldlookup, ISC_TRUE);
2019 newlookup->origin = ISC_LIST_HEAD(search_list);
2020 newlookup->need_search = ISC_FALSE;
2021 } else {
2022 search = ISC_LIST_NEXT(oldlookup->origin, link);
2023 if (search == NULL && oldlookup->done_as_is)
2024 return (ISC_FALSE);
2025 newlookup = requeue_lookup(oldlookup, ISC_TRUE);
2026 newlookup->origin = search;
2028 cancel_lookup(oldlookup);
2029 return (ISC_TRUE);
2033 * Insert an SOA record into the sendmessage in a lookup. Used for
2034 * creating IXFR queries.
2036 static void
2037 insert_soa(dig_lookup_t *lookup) {
2038 isc_result_t result;
2039 dns_rdata_soa_t soa;
2040 dns_rdata_t *rdata = NULL;
2041 dns_rdatalist_t *rdatalist = NULL;
2042 dns_rdataset_t *rdataset = NULL;
2043 dns_name_t *soaname = NULL;
2045 debug("insert_soa()");
2046 soa.mctx = mctx;
2047 soa.serial = lookup->ixfr_serial;
2048 soa.refresh = 0;
2049 soa.retry = 0;
2050 soa.expire = 0;
2051 soa.minimum = 0;
2052 soa.common.rdclass = lookup->rdclass;
2053 soa.common.rdtype = dns_rdatatype_soa;
2055 dns_name_init(&soa.origin, NULL);
2056 dns_name_init(&soa.contact, NULL);
2058 dns_name_clone(dns_rootname, &soa.origin);
2059 dns_name_clone(dns_rootname, &soa.contact);
2061 isc_buffer_init(&lookup->rdatabuf, lookup->rdatastore,
2062 sizeof(lookup->rdatastore));
2064 result = dns_message_gettemprdata(lookup->sendmsg, &rdata);
2065 check_result(result, "dns_message_gettemprdata");
2067 result = dns_rdata_fromstruct(rdata, lookup->rdclass,
2068 dns_rdatatype_soa, &soa,
2069 &lookup->rdatabuf);
2070 check_result(result, "isc_rdata_fromstruct");
2072 result = dns_message_gettemprdatalist(lookup->sendmsg, &rdatalist);
2073 check_result(result, "dns_message_gettemprdatalist");
2075 result = dns_message_gettemprdataset(lookup->sendmsg, &rdataset);
2076 check_result(result, "dns_message_gettemprdataset");
2078 dns_rdatalist_init(rdatalist);
2079 rdatalist->type = dns_rdatatype_soa;
2080 rdatalist->rdclass = lookup->rdclass;
2081 rdatalist->covers = 0;
2082 rdatalist->ttl = 0;
2083 ISC_LIST_INIT(rdatalist->rdata);
2084 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
2086 dns_rdatalist_tordataset(rdatalist, rdataset);
2088 result = dns_message_gettempname(lookup->sendmsg, &soaname);
2089 check_result(result, "dns_message_gettempname");
2090 dns_name_init(soaname, NULL);
2091 dns_name_clone(lookup->name, soaname);
2092 ISC_LIST_INIT(soaname->list);
2093 ISC_LIST_APPEND(soaname->list, rdataset, link);
2094 dns_message_addname(lookup->sendmsg, soaname, DNS_SECTION_AUTHORITY);
2097 #ifdef ISC_PLATFORM_USESIT
2098 static void
2099 compute_cookie(unsigned char *clientcookie, size_t len) {
2100 /* XXXMPA need to fix, should be per server. */
2101 INSIST(len >= 8U);
2102 memmove(clientcookie, cookie_secret, 8);
2104 #endif
2107 * Setup the supplied lookup structure, making it ready to start sending
2108 * queries to servers. Create and initialize the message to be sent as
2109 * well as the query structures and buffer space for the replies. If the
2110 * server list is empty, clone it from the system default list.
2112 isc_boolean_t
2113 setup_lookup(dig_lookup_t *lookup) {
2114 isc_result_t result;
2115 isc_uint32_t id;
2116 int len;
2117 dig_server_t *serv;
2118 dig_query_t *query;
2119 isc_buffer_t b;
2120 dns_compress_t cctx;
2121 char store[MXNAME];
2122 char ecsbuf[20];
2123 #ifdef ISC_PLATFORM_USESIT
2124 char sitbuf[256];
2125 #endif
2126 #ifdef WITH_IDN
2127 idn_result_t mr;
2128 char utf8_textname[MXNAME], utf8_origin[MXNAME], idn_textname[MXNAME];
2129 #endif
2131 #ifdef WITH_IDN
2132 result = dns_name_settotextfilter(output_filter);
2133 check_result(result, "dns_name_settotextfilter");
2134 #endif
2136 REQUIRE(lookup != NULL);
2137 INSIST(!free_now);
2139 debug("setup_lookup(%p)", lookup);
2141 result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER,
2142 &lookup->sendmsg);
2143 check_result(result, "dns_message_create");
2145 if (lookup->new_search) {
2146 debug("resetting lookup counter.");
2147 lookup_counter = 0;
2150 if (ISC_LIST_EMPTY(lookup->my_server_list)) {
2151 debug("cloning server list");
2152 clone_server_list(server_list, &lookup->my_server_list);
2154 result = dns_message_gettempname(lookup->sendmsg, &lookup->name);
2155 check_result(result, "dns_message_gettempname");
2156 dns_name_init(lookup->name, NULL);
2158 isc_buffer_init(&lookup->namebuf, lookup->namespace,
2159 sizeof(lookup->namespace));
2160 isc_buffer_init(&lookup->onamebuf, lookup->onamespace,
2161 sizeof(lookup->onamespace));
2163 #ifdef WITH_IDN
2165 * We cannot convert `textname' and `origin' separately.
2166 * `textname' doesn't contain TLD, but local mapping needs
2167 * TLD.
2169 mr = idn_encodename(IDN_LOCALCONV | IDN_DELIMMAP, lookup->textname,
2170 utf8_textname, sizeof(utf8_textname));
2171 idn_check_result(mr, "convert textname to UTF-8");
2172 #endif
2175 * If the name has too many dots, force the origin to be NULL
2176 * (which produces an absolute lookup). Otherwise, take the origin
2177 * we have if there's one in the struct already. If it's NULL,
2178 * take the first entry in the searchlist iff either usesearch
2179 * is TRUE or we got a domain line in the resolv.conf file.
2181 if (lookup->new_search) {
2182 #ifdef WITH_IDN
2183 if ((count_dots(utf8_textname) >= ndots) || !usesearch) {
2184 lookup->origin = NULL; /* Force abs lookup */
2185 lookup->done_as_is = ISC_TRUE;
2186 lookup->need_search = usesearch;
2187 } else if (lookup->origin == NULL && usesearch) {
2188 lookup->origin = ISC_LIST_HEAD(search_list);
2189 lookup->need_search = ISC_FALSE;
2191 #else
2192 if ((count_dots(lookup->textname) >= ndots) || !usesearch) {
2193 lookup->origin = NULL; /* Force abs lookup */
2194 lookup->done_as_is = ISC_TRUE;
2195 lookup->need_search = usesearch;
2196 } else if (lookup->origin == NULL && usesearch) {
2197 lookup->origin = ISC_LIST_HEAD(search_list);
2198 lookup->need_search = ISC_FALSE;
2200 #endif
2203 #ifdef WITH_IDN
2204 if (lookup->origin != NULL) {
2205 mr = idn_encodename(IDN_LOCALCONV | IDN_DELIMMAP,
2206 lookup->origin->origin, utf8_origin,
2207 sizeof(utf8_origin));
2208 idn_check_result(mr, "convert origin to UTF-8");
2209 mr = append_textname(utf8_textname, utf8_origin,
2210 sizeof(utf8_textname));
2211 idn_check_result(mr, "append origin to textname");
2213 mr = idn_encodename(idnoptions | IDN_LOCALMAP | IDN_NAMEPREP |
2214 IDN_IDNCONV | IDN_LENCHECK, utf8_textname,
2215 idn_textname, sizeof(idn_textname));
2216 idn_check_result(mr, "convert UTF-8 textname to IDN encoding");
2217 #else
2218 if (lookup->origin != NULL) {
2219 debug("trying origin %s", lookup->origin->origin);
2220 result = dns_message_gettempname(lookup->sendmsg,
2221 &lookup->oname);
2222 check_result(result, "dns_message_gettempname");
2223 dns_name_init(lookup->oname, NULL);
2224 /* XXX Helper funct to conv char* to name? */
2225 len = strlen(lookup->origin->origin);
2226 isc_buffer_init(&b, lookup->origin->origin, len);
2227 isc_buffer_add(&b, len);
2228 result = dns_name_fromtext(lookup->oname, &b, dns_rootname,
2229 0, &lookup->onamebuf);
2230 if (result != ISC_R_SUCCESS) {
2231 dns_message_puttempname(lookup->sendmsg,
2232 &lookup->name);
2233 dns_message_puttempname(lookup->sendmsg,
2234 &lookup->oname);
2235 fatal("'%s' is not in legal name syntax (%s)",
2236 lookup->origin->origin,
2237 isc_result_totext(result));
2239 if (lookup->trace && lookup->trace_root) {
2240 dns_name_clone(dns_rootname, lookup->name);
2241 } else {
2242 dns_fixedname_t fixed;
2243 dns_name_t *name;
2245 dns_fixedname_init(&fixed);
2246 name = dns_fixedname_name(&fixed);
2247 len = strlen(lookup->textname);
2248 isc_buffer_init(&b, lookup->textname, len);
2249 isc_buffer_add(&b, len);
2250 result = dns_name_fromtext(name, &b, NULL, 0, NULL);
2251 if (result == ISC_R_SUCCESS &&
2252 !dns_name_isabsolute(name))
2253 result = dns_name_concatenate(name,
2254 lookup->oname,
2255 lookup->name,
2256 &lookup->namebuf);
2257 else if (result == ISC_R_SUCCESS)
2258 result = dns_name_copy(name, lookup->name,
2259 &lookup->namebuf);
2260 if (result != ISC_R_SUCCESS) {
2261 dns_message_puttempname(lookup->sendmsg,
2262 &lookup->name);
2263 dns_message_puttempname(lookup->sendmsg,
2264 &lookup->oname);
2265 if (result == DNS_R_NAMETOOLONG)
2266 return (ISC_FALSE);
2267 fatal("'%s' is not in legal name syntax (%s)",
2268 lookup->textname,
2269 isc_result_totext(result));
2272 dns_message_puttempname(lookup->sendmsg, &lookup->oname);
2273 } else
2274 #endif
2276 debug("using root origin");
2277 if (lookup->trace && lookup->trace_root)
2278 dns_name_clone(dns_rootname, lookup->name);
2279 else {
2280 #ifdef WITH_IDN
2281 len = strlen(idn_textname);
2282 isc_buffer_init(&b, idn_textname, len);
2283 isc_buffer_add(&b, len);
2284 result = dns_name_fromtext(lookup->name, &b,
2285 dns_rootname, 0,
2286 &lookup->namebuf);
2287 #else
2288 len = strlen(lookup->textname);
2289 isc_buffer_init(&b, lookup->textname, len);
2290 isc_buffer_add(&b, len);
2291 result = dns_name_fromtext(lookup->name, &b,
2292 dns_rootname, 0,
2293 &lookup->namebuf);
2294 #endif
2296 if (result != ISC_R_SUCCESS) {
2297 dns_message_puttempname(lookup->sendmsg,
2298 &lookup->name);
2299 fatal("'%s' is not a legal name "
2300 "(%s)", lookup->textname,
2301 isc_result_totext(result));
2304 dns_name_format(lookup->name, store, sizeof(store));
2305 trying(store, lookup);
2306 INSIST(dns_name_isabsolute(lookup->name));
2308 isc_random_get(&id);
2309 lookup->sendmsg->id = (unsigned short)id & 0xFFFF;
2310 lookup->sendmsg->opcode = dns_opcode_query;
2311 lookup->msgcounter = 0;
2313 * If this is a trace request, completely disallow recursion, since
2314 * it's meaningless for traces.
2316 if (lookup->trace || (lookup->ns_search_only && !lookup->trace_root))
2317 lookup->recurse = ISC_FALSE;
2319 if (lookup->recurse &&
2320 lookup->rdtype != dns_rdatatype_axfr &&
2321 lookup->rdtype != dns_rdatatype_ixfr) {
2322 debug("recursive query");
2323 lookup->sendmsg->flags |= DNS_MESSAGEFLAG_RD;
2326 /* XXX aaflag */
2327 if (lookup->aaonly) {
2328 debug("AA query");
2329 lookup->sendmsg->flags |= DNS_MESSAGEFLAG_AA;
2332 if (lookup->adflag) {
2333 debug("AD query");
2334 lookup->sendmsg->flags |= DNS_MESSAGEFLAG_AD;
2337 if (lookup->cdflag) {
2338 debug("CD query");
2339 lookup->sendmsg->flags |= DNS_MESSAGEFLAG_CD;
2342 dns_message_addname(lookup->sendmsg, lookup->name,
2343 DNS_SECTION_QUESTION);
2345 if (lookup->trace && lookup->trace_root) {
2346 lookup->qrdtype = lookup->rdtype;
2347 lookup->rdtype = dns_rdatatype_ns;
2350 if ((lookup->rdtype == dns_rdatatype_axfr) ||
2351 (lookup->rdtype == dns_rdatatype_ixfr)) {
2353 * Force TCP mode if we're doing an axfr.
2355 if (lookup->rdtype == dns_rdatatype_axfr) {
2356 lookup->doing_xfr = ISC_TRUE;
2357 lookup->tcp_mode = ISC_TRUE;
2358 } else if (lookup->tcp_mode) {
2359 lookup->doing_xfr = ISC_TRUE;
2363 add_question(lookup->sendmsg, lookup->name, lookup->rdclass,
2364 lookup->rdtype);
2366 /* add_soa */
2367 if (lookup->rdtype == dns_rdatatype_ixfr)
2368 insert_soa(lookup);
2370 /* XXX Insist this? */
2371 lookup->tsigctx = NULL;
2372 lookup->querysig = NULL;
2373 if (key != NULL) {
2374 debug("initializing keys");
2375 result = dns_message_settsigkey(lookup->sendmsg, key);
2376 check_result(result, "dns_message_settsigkey");
2379 lookup->sendspace = isc_mempool_get(commctx);
2380 if (lookup->sendspace == NULL)
2381 fatal("memory allocation failure");
2383 result = dns_compress_init(&cctx, -1, mctx);
2384 check_result(result, "dns_compress_init");
2386 debug("starting to render the message");
2387 isc_buffer_init(&lookup->renderbuf, lookup->sendspace, COMMSIZE);
2388 result = dns_message_renderbegin(lookup->sendmsg, &cctx,
2389 &lookup->renderbuf);
2390 check_result(result, "dns_message_renderbegin");
2391 if (lookup->udpsize > 0 || lookup->dnssec ||
2392 lookup->edns > -1 || lookup->ecs_addr != NULL)
2394 dns_ednsopt_t opts[DNS_EDNSOPTIONS];
2395 int i = 0;
2397 if (lookup->udpsize == 0)
2398 lookup->udpsize = 4096;
2399 if (lookup->edns < 0)
2400 lookup->edns = 0;
2402 if (lookup->nsid) {
2403 INSIST(i < DNS_EDNSOPTIONS);
2404 opts[i].code = DNS_OPT_NSID;
2405 opts[i].length = 0;
2406 opts[i].value = NULL;
2407 i++;
2410 if (lookup->ecs_addr != NULL) {
2411 isc_uint32_t prefixlen;
2412 struct sockaddr *sa;
2413 struct sockaddr_in *sin;
2414 struct sockaddr_in6 *sin6;
2415 size_t addrl;
2417 sa = &lookup->ecs_addr->type.sa;
2418 prefixlen = lookup->ecs_addr->length;
2420 /* Round up prefix len to a multiple of 8 */
2421 addrl = (prefixlen + 7) / 8;
2423 INSIST(i < DNS_EDNSOPTIONS);
2424 opts[i].code = DNS_OPT_CLIENT_SUBNET;
2425 opts[i].length = (isc_uint16_t) addrl + 4;
2426 check_result(result, "isc_buffer_allocate");
2427 isc_buffer_init(&b, ecsbuf, sizeof(ecsbuf));
2428 if (sa->sa_family == AF_INET) {
2429 sin = (struct sockaddr_in *) sa;
2430 isc_buffer_putuint16(&b, 1);
2431 isc_buffer_putuint8(&b, prefixlen);
2432 isc_buffer_putuint8(&b, 0);
2433 isc_buffer_putmem(&b,
2434 (isc_uint8_t *) &sin->sin_addr,
2435 (unsigned int) addrl);
2436 } else {
2437 sin6 = (struct sockaddr_in6 *) sa;
2438 isc_buffer_putuint16(&b, 2);
2439 isc_buffer_putuint8(&b, prefixlen);
2440 isc_buffer_putuint8(&b, 0);
2441 isc_buffer_putmem(&b,
2442 (isc_uint8_t *) &sin6->sin6_addr,
2443 (unsigned int) addrl);
2446 opts[i].value = (isc_uint8_t *) ecsbuf;
2447 i++;
2450 #ifdef ISC_PLATFORM_USESIT
2451 if (lookup->sit) {
2452 INSIST(i < DNS_EDNSOPTIONS);
2453 opts[i].code = DNS_OPT_SIT;
2454 if (lookup->sitvalue != NULL) {
2455 isc_buffer_init(&b, sitbuf, sizeof(sitbuf));
2456 result = isc_hex_decodestring(lookup->sitvalue,
2457 &b);
2458 check_result(result, "isc_hex_decodestring");
2459 opts[i].value = isc_buffer_base(&b);
2460 opts[i].length = isc_buffer_usedlength(&b);
2461 } else {
2462 compute_cookie(cookie, sizeof(cookie));
2463 opts[i].length = 8;
2464 opts[i].value = cookie;
2466 i++;
2468 #endif
2470 if (lookup->expire) {
2471 INSIST(i < DNS_EDNSOPTIONS);
2472 opts[i].code = DNS_OPT_EXPIRE;
2473 opts[i].length = 0;
2474 opts[i].value = NULL;
2475 i++;
2478 add_opt(lookup->sendmsg, lookup->udpsize,
2479 lookup->edns, lookup->dnssec, opts, i);
2482 result = dns_message_rendersection(lookup->sendmsg,
2483 DNS_SECTION_QUESTION, 0);
2484 check_result(result, "dns_message_rendersection");
2485 result = dns_message_rendersection(lookup->sendmsg,
2486 DNS_SECTION_AUTHORITY, 0);
2487 check_result(result, "dns_message_rendersection");
2488 result = dns_message_renderend(lookup->sendmsg);
2489 check_result(result, "dns_message_renderend");
2490 debug("done rendering");
2492 dns_compress_invalidate(&cctx);
2495 * Force TCP mode if the request is larger than 512 bytes.
2497 if (isc_buffer_usedlength(&lookup->renderbuf) > 512)
2498 lookup->tcp_mode = ISC_TRUE;
2500 lookup->pending = ISC_FALSE;
2502 for (serv = ISC_LIST_HEAD(lookup->my_server_list);
2503 serv != NULL;
2504 serv = ISC_LIST_NEXT(serv, link)) {
2505 query = isc_mem_allocate(mctx, sizeof(dig_query_t));
2506 if (query == NULL)
2507 fatal("memory allocation failure in %s:%d",
2508 __FILE__, __LINE__);
2509 debug("create query %p linked to lookup %p",
2510 query, lookup);
2511 query->lookup = lookup;
2512 query->waiting_connect = ISC_FALSE;
2513 query->waiting_senddone = ISC_FALSE;
2514 query->pending_free = ISC_FALSE;
2515 query->recv_made = ISC_FALSE;
2516 query->first_pass = ISC_TRUE;
2517 query->first_soa_rcvd = ISC_FALSE;
2518 query->second_rr_rcvd = ISC_FALSE;
2519 query->first_repeat_rcvd = ISC_FALSE;
2520 query->warn_id = ISC_TRUE;
2521 query->first_rr_serial = 0;
2522 query->second_rr_serial = 0;
2523 query->servname = serv->servername;
2524 query->userarg = serv->userarg;
2525 query->rr_count = 0;
2526 query->msg_count = 0;
2527 query->byte_count = 0;
2528 query->ixfr_axfr = ISC_FALSE;
2529 ISC_LIST_INIT(query->recvlist);
2530 ISC_LIST_INIT(query->lengthlist);
2531 query->sock = NULL;
2532 query->recvspace = isc_mempool_get(commctx);
2533 if (query->recvspace == NULL)
2534 fatal("memory allocation failure");
2536 isc_buffer_init(&query->recvbuf, query->recvspace, COMMSIZE);
2537 isc_buffer_init(&query->lengthbuf, query->lengthspace, 2);
2538 isc_buffer_init(&query->slbuf, query->slspace, 2);
2539 query->sendbuf = lookup->renderbuf;
2541 ISC_LINK_INIT(query, clink);
2542 ISC_LINK_INIT(query, link);
2543 ISC_LIST_ENQUEUE(lookup->q, query, link);
2546 /* XXX qrflag, print_query, etc... */
2547 if (!ISC_LIST_EMPTY(lookup->q) && qr) {
2548 extrabytes = 0;
2549 printmessage(ISC_LIST_HEAD(lookup->q), lookup->sendmsg,
2550 ISC_TRUE);
2552 return (ISC_TRUE);
2556 * Event handler for send completion. Track send counter, and clear out
2557 * the query if the send was canceled.
2559 static void
2560 send_done(isc_task_t *_task, isc_event_t *event) {
2561 isc_socketevent_t *sevent = (isc_socketevent_t *)event;
2562 isc_buffer_t *b = NULL;
2563 dig_query_t *query, *next;
2564 dig_lookup_t *l;
2566 REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE);
2568 UNUSED(_task);
2570 LOCK_LOOKUP;
2572 debug("send_done()");
2573 sendcount--;
2574 debug("sendcount=%d", sendcount);
2575 INSIST(sendcount >= 0);
2577 for (b = ISC_LIST_HEAD(sevent->bufferlist);
2578 b != NULL;
2579 b = ISC_LIST_HEAD(sevent->bufferlist)) {
2580 ISC_LIST_DEQUEUE(sevent->bufferlist, b, link);
2581 isc_mem_free(mctx, b);
2584 query = event->ev_arg;
2585 query->waiting_senddone = ISC_FALSE;
2586 l = query->lookup;
2588 if (l->ns_search_only && !l->trace_root && !l->tcp_mode) {
2589 debug("sending next, since searching");
2590 next = ISC_LIST_NEXT(query, link);
2591 if (next != NULL)
2592 send_udp(next);
2595 isc_event_free(&event);
2597 if (query->pending_free)
2598 isc_mem_free(mctx, query);
2600 check_if_done();
2601 UNLOCK_LOOKUP;
2605 * Cancel a lookup, sending isc_socket_cancel() requests to all outstanding
2606 * IO sockets. The cancel handlers should take care of cleaning up the
2607 * query and lookup structures
2609 static void
2610 cancel_lookup(dig_lookup_t *lookup) {
2611 dig_query_t *query, *next;
2613 debug("cancel_lookup()");
2614 query = ISC_LIST_HEAD(lookup->q);
2615 while (query != NULL) {
2616 next = ISC_LIST_NEXT(query, link);
2617 if (query->sock != NULL) {
2618 isc_socket_cancel(query->sock, global_task,
2619 ISC_SOCKCANCEL_ALL);
2620 check_if_done();
2621 } else {
2622 clear_query(query);
2624 query = next;
2626 if (lookup->timer != NULL)
2627 isc_timer_detach(&lookup->timer);
2628 lookup->pending = ISC_FALSE;
2629 lookup->retries = 0;
2632 static void
2633 bringup_timer(dig_query_t *query, unsigned int default_timeout) {
2634 dig_lookup_t *l;
2635 unsigned int local_timeout;
2636 isc_result_t result;
2638 debug("bringup_timer()");
2640 * If the timer already exists, that means we're calling this
2641 * a second time (for a retry). Don't need to recreate it,
2642 * just reset it.
2644 l = query->lookup;
2645 if (ISC_LIST_NEXT(query, link) != NULL)
2646 local_timeout = SERVER_TIMEOUT;
2647 else {
2648 if (timeout == 0)
2649 local_timeout = default_timeout;
2650 else
2651 local_timeout = timeout;
2653 debug("have local timeout of %d", local_timeout);
2654 isc_interval_set(&l->interval, local_timeout, 0);
2655 if (l->timer != NULL)
2656 isc_timer_detach(&l->timer);
2657 result = isc_timer_create(timermgr, isc_timertype_once, NULL,
2658 &l->interval, global_task, connect_timeout,
2659 l, &l->timer);
2660 check_result(result, "isc_timer_create");
2663 static void
2664 force_timeout(dig_lookup_t *l, dig_query_t *query) {
2665 isc_event_t *event;
2667 debug("force_timeout ()");
2668 event = isc_event_allocate(mctx, query, ISC_TIMEREVENT_IDLE,
2669 connect_timeout, l,
2670 sizeof(isc_event_t));
2671 if (event == NULL) {
2672 fatal("isc_event_allocate: %s",
2673 isc_result_totext(ISC_R_NOMEMORY));
2675 isc_task_send(global_task, &event);
2678 * The timer may have expired if, for example, get_address() takes
2679 * long time and the timer was running on a different thread.
2680 * We need to cancel the possible timeout event not to confuse
2681 * ourselves due to the duplicate events.
2683 if (l->timer != NULL)
2684 isc_timer_detach(&l->timer);
2688 static void
2689 connect_done(isc_task_t *task, isc_event_t *event);
2692 * Unlike send_udp, this can't be called multiple times with the same
2693 * query. When we retry TCP, we requeue the whole lookup, which should
2694 * start anew.
2696 static void
2697 send_tcp_connect(dig_query_t *query) {
2698 isc_result_t result;
2699 dig_query_t *next;
2700 dig_lookup_t *l;
2702 debug("send_tcp_connect(%p)", query);
2704 l = query->lookup;
2705 query->waiting_connect = ISC_TRUE;
2706 query->lookup->current_query = query;
2707 result = get_address(query->servname, port, &query->sockaddr);
2708 if (result != ISC_R_SUCCESS) {
2710 * This servname doesn't have an address. Try the next server
2711 * by triggering an immediate 'timeout' (we lie, but the effect
2712 * is the same).
2714 force_timeout(l, query);
2715 return;
2718 if (specified_source &&
2719 (isc_sockaddr_pf(&query->sockaddr) !=
2720 isc_sockaddr_pf(&bind_address))) {
2721 printf(";; Skipping server %s, incompatible "
2722 "address family\n", query->servname);
2723 query->waiting_connect = ISC_FALSE;
2724 next = ISC_LIST_NEXT(query, link);
2725 l = query->lookup;
2726 clear_query(query);
2727 if (next == NULL) {
2728 printf(";; No acceptable nameservers\n");
2729 check_next_lookup(l);
2730 return;
2732 send_tcp_connect(next);
2733 return;
2736 INSIST(query->sock == NULL);
2738 if (keep != NULL && isc_sockaddr_equal(&keepaddr, &query->sockaddr)) {
2739 sockcount++;
2740 isc_socket_attach(keep, &query->sock);
2741 query->waiting_connect = ISC_FALSE;
2742 launch_next_query(query, ISC_TRUE);
2743 goto search;
2746 result = isc_socket_create(socketmgr,
2747 isc_sockaddr_pf(&query->sockaddr),
2748 isc_sockettype_tcp, &query->sock);
2749 check_result(result, "isc_socket_create");
2750 sockcount++;
2751 debug("sockcount=%d", sockcount);
2752 if (specified_source)
2753 result = isc_socket_bind(query->sock, &bind_address,
2754 ISC_SOCKET_REUSEADDRESS);
2755 else {
2756 if ((isc_sockaddr_pf(&query->sockaddr) == AF_INET) &&
2757 have_ipv4)
2758 isc_sockaddr_any(&bind_any);
2759 else
2760 isc_sockaddr_any6(&bind_any);
2761 result = isc_socket_bind(query->sock, &bind_any, 0);
2763 check_result(result, "isc_socket_bind");
2764 bringup_timer(query, TCP_TIMEOUT);
2765 result = isc_socket_connect(query->sock, &query->sockaddr,
2766 global_task, connect_done, query);
2767 check_result(result, "isc_socket_connect");
2768 search:
2770 * If we're at the endgame of a nameserver search, we need to
2771 * immediately bring up all the queries. Do it here.
2773 if (l->ns_search_only && !l->trace_root) {
2774 debug("sending next, since searching");
2775 next = ISC_LIST_NEXT(query, link);
2776 if (ISC_LINK_LINKED(query, link))
2777 ISC_LIST_DEQUEUE(l->q, query, link);
2778 ISC_LIST_ENQUEUE(l->connecting, query, clink);
2779 if (next != NULL)
2780 send_tcp_connect(next);
2784 static isc_buffer_t *
2785 clone_buffer(isc_buffer_t *source) {
2786 isc_buffer_t *buffer;
2787 buffer = isc_mem_allocate(mctx, sizeof(*buffer));
2788 if (buffer == NULL)
2789 fatal("memory allocation failure in %s:%d",
2790 __FILE__, __LINE__);
2791 *buffer = *source;
2792 return (buffer);
2796 * Send a UDP packet to the remote nameserver, possible starting the
2797 * recv action as well. Also make sure that the timer is running and
2798 * is properly reset.
2800 static void
2801 send_udp(dig_query_t *query) {
2802 dig_lookup_t *l = NULL;
2803 isc_result_t result;
2804 isc_buffer_t *sendbuf;
2806 debug("send_udp(%p)", query);
2808 l = query->lookup;
2809 bringup_timer(query, UDP_TIMEOUT);
2810 l->current_query = query;
2811 debug("working on lookup %p, query %p", query->lookup, query);
2812 if (!query->recv_made) {
2813 /* XXX Check the sense of this, need assertion? */
2814 query->waiting_connect = ISC_FALSE;
2815 result = get_address(query->servname, port, &query->sockaddr);
2816 if (result != ISC_R_SUCCESS) {
2817 /* This servname doesn't have an address. */
2818 force_timeout(l, query);
2819 return;
2822 result = isc_socket_create(socketmgr,
2823 isc_sockaddr_pf(&query->sockaddr),
2824 isc_sockettype_udp, &query->sock);
2825 check_result(result, "isc_socket_create");
2826 sockcount++;
2827 debug("sockcount=%d", sockcount);
2828 if (specified_source) {
2829 result = isc_socket_bind(query->sock, &bind_address,
2830 ISC_SOCKET_REUSEADDRESS);
2831 } else {
2832 isc_sockaddr_anyofpf(&bind_any,
2833 isc_sockaddr_pf(&query->sockaddr));
2834 result = isc_socket_bind(query->sock, &bind_any, 0);
2836 check_result(result, "isc_socket_bind");
2838 query->recv_made = ISC_TRUE;
2839 ISC_LINK_INIT(&query->recvbuf, link);
2840 ISC_LIST_ENQUEUE(query->recvlist, &query->recvbuf,
2841 link);
2842 debug("recving with lookup=%p, query=%p, sock=%p",
2843 query->lookup, query, query->sock);
2844 result = isc_socket_recvv(query->sock, &query->recvlist, 1,
2845 global_task, recv_done, query);
2846 check_result(result, "isc_socket_recvv");
2847 recvcount++;
2848 debug("recvcount=%d", recvcount);
2850 ISC_LIST_INIT(query->sendlist);
2851 sendbuf = clone_buffer(&query->sendbuf);
2852 ISC_LIST_ENQUEUE(query->sendlist, sendbuf, link);
2853 debug("sending a request");
2854 TIME_NOW(&query->time_sent);
2855 INSIST(query->sock != NULL);
2856 query->waiting_senddone = ISC_TRUE;
2857 result = isc_socket_sendtov2(query->sock, &query->sendlist,
2858 global_task, send_done, query,
2859 &query->sockaddr, NULL,
2860 ISC_SOCKFLAG_NORETRY);
2861 check_result(result, "isc_socket_sendtov");
2862 sendcount++;
2866 * IO timeout handler, used for both connect and recv timeouts. If
2867 * retries are still allowed, either resend the UDP packet or queue a
2868 * new TCP lookup. Otherwise, cancel the lookup.
2870 static void
2871 connect_timeout(isc_task_t *task, isc_event_t *event) {
2872 dig_lookup_t *l = NULL;
2873 dig_query_t *query = NULL, *next, *cq;
2875 UNUSED(task);
2876 REQUIRE(event->ev_type == ISC_TIMEREVENT_IDLE);
2878 debug("connect_timeout()");
2880 LOCK_LOOKUP;
2881 l = event->ev_arg;
2882 query = l->current_query;
2883 isc_event_free(&event);
2885 INSIST(!free_now);
2887 if ((query != NULL) && (query->lookup->current_query != NULL) &&
2888 (ISC_LIST_NEXT(query->lookup->current_query, link) != NULL)) {
2889 debug("trying next server...");
2890 cq = query->lookup->current_query;
2891 if (!l->tcp_mode)
2892 send_udp(ISC_LIST_NEXT(cq, link));
2893 else {
2894 if (query->sock != NULL)
2895 isc_socket_cancel(query->sock, NULL,
2896 ISC_SOCKCANCEL_ALL);
2897 next = ISC_LIST_NEXT(cq, link);
2898 if (next != NULL)
2899 send_tcp_connect(next);
2901 UNLOCK_LOOKUP;
2902 return;
2905 if (l->retries > 1) {
2906 if (!l->tcp_mode) {
2907 l->retries--;
2908 debug("resending UDP request to first server");
2909 send_udp(ISC_LIST_HEAD(l->q));
2910 } else {
2911 debug("making new TCP request, %d tries left",
2912 l->retries);
2913 l->retries--;
2914 requeue_lookup(l, ISC_TRUE);
2915 cancel_lookup(l);
2916 check_next_lookup(l);
2918 } else {
2919 fputs(l->cmdline, stdout);
2920 printf(";; connection timed out; no servers could be "
2921 "reached\n");
2922 cancel_lookup(l);
2923 check_next_lookup(l);
2924 if (exitcode < 9)
2925 exitcode = 9;
2927 UNLOCK_LOOKUP;
2931 * Event handler for the TCP recv which gets the length header of TCP
2932 * packets. Start the next recv of length bytes.
2934 static void
2935 tcp_length_done(isc_task_t *task, isc_event_t *event) {
2936 isc_socketevent_t *sevent;
2937 isc_buffer_t *b = NULL;
2938 isc_result_t result;
2939 dig_query_t *query = NULL;
2940 dig_lookup_t *l;
2941 isc_uint16_t length;
2943 REQUIRE(event->ev_type == ISC_SOCKEVENT_RECVDONE);
2944 INSIST(!free_now);
2946 UNUSED(task);
2948 debug("tcp_length_done()");
2950 LOCK_LOOKUP;
2951 sevent = (isc_socketevent_t *)event;
2952 query = event->ev_arg;
2954 recvcount--;
2955 INSIST(recvcount >= 0);
2957 b = ISC_LIST_HEAD(sevent->bufferlist);
2958 INSIST(b == &query->lengthbuf);
2959 ISC_LIST_DEQUEUE(sevent->bufferlist, b, link);
2961 if (sevent->result == ISC_R_CANCELED) {
2962 isc_event_free(&event);
2963 l = query->lookup;
2964 clear_query(query);
2965 check_next_lookup(l);
2966 UNLOCK_LOOKUP;
2967 return;
2969 if (sevent->result != ISC_R_SUCCESS) {
2970 char sockstr[ISC_SOCKADDR_FORMATSIZE];
2971 isc_sockaddr_format(&query->sockaddr, sockstr,
2972 sizeof(sockstr));
2973 printf(";; communications error to %s: %s\n",
2974 sockstr, isc_result_totext(sevent->result));
2975 l = query->lookup;
2976 isc_socket_detach(&query->sock);
2977 sockcount--;
2978 debug("sockcount=%d", sockcount);
2979 INSIST(sockcount >= 0);
2980 isc_event_free(&event);
2981 clear_query(query);
2982 check_next_lookup(l);
2983 UNLOCK_LOOKUP;
2984 return;
2986 length = isc_buffer_getuint16(b);
2987 if (length == 0) {
2988 isc_event_free(&event);
2989 launch_next_query(query, ISC_FALSE);
2990 UNLOCK_LOOKUP;
2991 return;
2995 * Even though the buffer was already init'ed, we need
2996 * to redo it now, to force the length we want.
2998 isc_buffer_invalidate(&query->recvbuf);
2999 isc_buffer_init(&query->recvbuf, query->recvspace, length);
3000 ENSURE(ISC_LIST_EMPTY(query->recvlist));
3001 ISC_LINK_INIT(&query->recvbuf, link);
3002 ISC_LIST_ENQUEUE(query->recvlist, &query->recvbuf, link);
3003 debug("recving with lookup=%p, query=%p", query->lookup, query);
3004 result = isc_socket_recvv(query->sock, &query->recvlist, length, task,
3005 recv_done, query);
3006 check_result(result, "isc_socket_recvv");
3007 recvcount++;
3008 debug("resubmitted recv request with length %d, recvcount=%d",
3009 length, recvcount);
3010 isc_event_free(&event);
3011 UNLOCK_LOOKUP;
3015 * For transfers that involve multiple recvs (XFR's in particular),
3016 * launch the next recv.
3018 static void
3019 launch_next_query(dig_query_t *query, isc_boolean_t include_question) {
3020 isc_result_t result;
3021 dig_lookup_t *l;
3022 isc_buffer_t *buffer;
3024 INSIST(!free_now);
3026 debug("launch_next_query()");
3028 if (!query->lookup->pending) {
3029 debug("ignoring launch_next_query because !pending");
3030 isc_socket_detach(&query->sock);
3031 sockcount--;
3032 debug("sockcount=%d", sockcount);
3033 INSIST(sockcount >= 0);
3034 query->waiting_connect = ISC_FALSE;
3035 l = query->lookup;
3036 clear_query(query);
3037 check_next_lookup(l);
3038 return;
3041 isc_buffer_clear(&query->slbuf);
3042 isc_buffer_clear(&query->lengthbuf);
3043 isc_buffer_putuint16(&query->slbuf, (isc_uint16_t) query->sendbuf.used);
3044 ISC_LIST_INIT(query->sendlist);
3045 ISC_LINK_INIT(&query->slbuf, link);
3046 if (!query->first_soa_rcvd) {
3047 buffer = clone_buffer(&query->slbuf);
3048 ISC_LIST_ENQUEUE(query->sendlist, buffer, link);
3049 if (include_question) {
3050 buffer = clone_buffer(&query->sendbuf);
3051 ISC_LIST_ENQUEUE(query->sendlist, buffer, link);
3055 ISC_LINK_INIT(&query->lengthbuf, link);
3056 ISC_LIST_ENQUEUE(query->lengthlist, &query->lengthbuf, link);
3058 result = isc_socket_recvv(query->sock, &query->lengthlist, 0,
3059 global_task, tcp_length_done, query);
3060 check_result(result, "isc_socket_recvv");
3061 recvcount++;
3062 debug("recvcount=%d", recvcount);
3063 if (!query->first_soa_rcvd) {
3064 debug("sending a request in launch_next_query");
3065 TIME_NOW(&query->time_sent);
3066 query->waiting_senddone = ISC_TRUE;
3067 result = isc_socket_sendv(query->sock, &query->sendlist,
3068 global_task, send_done, query);
3069 check_result(result, "isc_socket_sendv");
3070 sendcount++;
3071 debug("sendcount=%d", sendcount);
3073 query->waiting_connect = ISC_FALSE;
3074 #if 0
3075 check_next_lookup(query->lookup);
3076 #endif
3077 return;
3081 * Event handler for TCP connect complete. Make sure the connection was
3082 * successful, then pass into launch_next_query to actually send the
3083 * question.
3085 static void
3086 connect_done(isc_task_t *task, isc_event_t *event) {
3087 isc_socketevent_t *sevent = NULL;
3088 dig_query_t *query = NULL, *next;
3089 dig_lookup_t *l;
3091 UNUSED(task);
3093 REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT);
3094 INSIST(!free_now);
3096 debug("connect_done()");
3098 LOCK_LOOKUP;
3099 sevent = (isc_socketevent_t *)event;
3100 query = sevent->ev_arg;
3102 INSIST(query->waiting_connect);
3104 query->waiting_connect = ISC_FALSE;
3106 if (sevent->result == ISC_R_CANCELED) {
3107 debug("in cancel handler");
3108 isc_socket_detach(&query->sock);
3109 INSIST(sockcount > 0);
3110 sockcount--;
3111 debug("sockcount=%d", sockcount);
3112 query->waiting_connect = ISC_FALSE;
3113 isc_event_free(&event);
3114 l = query->lookup;
3115 clear_query(query);
3116 check_next_lookup(l);
3117 UNLOCK_LOOKUP;
3118 return;
3120 if (sevent->result != ISC_R_SUCCESS) {
3121 char sockstr[ISC_SOCKADDR_FORMATSIZE];
3123 debug("unsuccessful connection: %s",
3124 isc_result_totext(sevent->result));
3125 isc_sockaddr_format(&query->sockaddr, sockstr, sizeof(sockstr));
3126 if (sevent->result != ISC_R_CANCELED)
3127 printf(";; Connection to %s(%s) for %s failed: "
3128 "%s.\n", sockstr,
3129 query->servname, query->lookup->textname,
3130 isc_result_totext(sevent->result));
3131 isc_socket_detach(&query->sock);
3132 sockcount--;
3133 INSIST(sockcount >= 0);
3134 /* XXX Clean up exitcodes */
3135 if (exitcode < 9)
3136 exitcode = 9;
3137 debug("sockcount=%d", sockcount);
3138 query->waiting_connect = ISC_FALSE;
3139 isc_event_free(&event);
3140 l = query->lookup;
3141 if ((l->current_query != NULL) &&
3142 (ISC_LINK_LINKED(l->current_query, link)))
3143 next = ISC_LIST_NEXT(l->current_query, link);
3144 else
3145 next = NULL;
3146 clear_query(query);
3147 if (next != NULL) {
3148 bringup_timer(next, TCP_TIMEOUT);
3149 send_tcp_connect(next);
3150 } else
3151 check_next_lookup(l);
3152 UNLOCK_LOOKUP;
3153 return;
3155 if (keep_open) {
3156 if (keep != NULL)
3157 isc_socket_detach(&keep);
3158 isc_socket_attach(query->sock, &keep);
3159 keepaddr = query->sockaddr;
3161 launch_next_query(query, ISC_TRUE);
3162 isc_event_free(&event);
3163 UNLOCK_LOOKUP;
3167 * Check if the ongoing XFR needs more data before it's complete, using
3168 * the semantics of IXFR and AXFR protocols. Much of the complexity of
3169 * this routine comes from determining when an IXFR is complete.
3170 * ISC_FALSE means more data is on the way, and the recv has been issued.
3172 static isc_boolean_t
3173 check_for_more_data(dig_query_t *query, dns_message_t *msg,
3174 isc_socketevent_t *sevent)
3176 dns_rdataset_t *rdataset = NULL;
3177 dns_rdata_t rdata = DNS_RDATA_INIT;
3178 dns_rdata_soa_t soa;
3179 isc_uint32_t ixfr_serial = query->lookup->ixfr_serial, serial;
3180 isc_result_t result;
3181 isc_boolean_t ixfr = query->lookup->rdtype == dns_rdatatype_ixfr;
3182 isc_boolean_t axfr = query->lookup->rdtype == dns_rdatatype_axfr;
3184 if (ixfr)
3185 axfr = query->ixfr_axfr;
3187 debug("check_for_more_data()");
3190 * By the time we're in this routine, we know we're doing
3191 * either an AXFR or IXFR. If there's no second_rr_type,
3192 * then we don't yet know which kind of answer we got back
3193 * from the server. Here, we're going to walk through the
3194 * rr's in the message, acting as necessary whenever we hit
3195 * an SOA rr.
3198 query->msg_count++;
3199 query->byte_count += sevent->n;
3200 result = dns_message_firstname(msg, DNS_SECTION_ANSWER);
3201 if (result != ISC_R_SUCCESS) {
3202 puts("; Transfer failed.");
3203 return (ISC_TRUE);
3205 do {
3206 dns_name_t *name;
3207 name = NULL;
3208 dns_message_currentname(msg, DNS_SECTION_ANSWER,
3209 &name);
3210 for (rdataset = ISC_LIST_HEAD(name->list);
3211 rdataset != NULL;
3212 rdataset = ISC_LIST_NEXT(rdataset, link)) {
3213 result = dns_rdataset_first(rdataset);
3214 if (result != ISC_R_SUCCESS)
3215 continue;
3216 do {
3217 query->rr_count++;
3218 dns_rdata_reset(&rdata);
3219 dns_rdataset_current(rdataset, &rdata);
3221 * If this is the first rr, make sure
3222 * it's an SOA
3224 if ((!query->first_soa_rcvd) &&
3225 (rdata.type != dns_rdatatype_soa)) {
3226 puts("; Transfer failed. "
3227 "Didn't start with SOA answer.");
3228 return (ISC_TRUE);
3230 if ((!query->second_rr_rcvd) &&
3231 (rdata.type != dns_rdatatype_soa)) {
3232 query->second_rr_rcvd = ISC_TRUE;
3233 query->second_rr_serial = 0;
3234 debug("got the second rr as nonsoa");
3235 axfr = query->ixfr_axfr = ISC_TRUE;
3236 goto next_rdata;
3240 * If the record is anything except an SOA
3241 * now, just continue on...
3243 if (rdata.type != dns_rdatatype_soa)
3244 goto next_rdata;
3246 /* Now we have an SOA. Work with it. */
3247 debug("got an SOA");
3248 result = dns_rdata_tostruct(&rdata, &soa, NULL);
3249 check_result(result, "dns_rdata_tostruct");
3250 serial = soa.serial;
3251 dns_rdata_freestruct(&soa);
3252 if (!query->first_soa_rcvd) {
3253 query->first_soa_rcvd = ISC_TRUE;
3254 query->first_rr_serial = serial;
3255 debug("this is the first serial %u",
3256 serial);
3257 if (ixfr && isc_serial_ge(ixfr_serial,
3258 serial)) {
3259 debug("got up to date "
3260 "response");
3261 goto doexit;
3263 goto next_rdata;
3265 if (axfr) {
3266 debug("doing axfr, got second SOA");
3267 goto doexit;
3269 if (!query->second_rr_rcvd) {
3270 if (query->first_rr_serial == serial) {
3271 debug("doing ixfr, got "
3272 "empty zone");
3273 goto doexit;
3275 debug("this is the second serial %u",
3276 serial);
3277 query->second_rr_rcvd = ISC_TRUE;
3278 query->second_rr_serial = serial;
3279 goto next_rdata;
3282 * If we get to this point, we're doing an
3283 * IXFR and have to start really looking
3284 * at serial numbers.
3286 if (query->first_rr_serial == serial) {
3287 debug("got a match for ixfr");
3288 if (!query->first_repeat_rcvd) {
3289 query->first_repeat_rcvd =
3290 ISC_TRUE;
3291 goto next_rdata;
3293 debug("done with ixfr");
3294 goto doexit;
3296 debug("meaningless soa %u", serial);
3297 next_rdata:
3298 result = dns_rdataset_next(rdataset);
3299 } while (result == ISC_R_SUCCESS);
3301 result = dns_message_nextname(msg, DNS_SECTION_ANSWER);
3302 } while (result == ISC_R_SUCCESS);
3303 launch_next_query(query, ISC_FALSE);
3304 return (ISC_FALSE);
3305 doexit:
3306 received(sevent->n, &sevent->address, query);
3307 return (ISC_TRUE);
3310 #ifdef ISC_PLATFORM_USESIT
3311 static void
3312 process_sit(dig_lookup_t *l, dns_message_t *msg,
3313 isc_buffer_t *optbuf, size_t optlen)
3315 char bb[256];
3316 isc_buffer_t hexbuf;
3317 size_t len;
3318 const unsigned char *sit;
3319 isc_result_t result;
3321 if (l->sitvalue != NULL) {
3322 isc_buffer_init(&hexbuf, bb, sizeof(bb));
3323 result = isc_hex_decodestring(l->sitvalue, &hexbuf);
3324 check_result(result, "isc_hex_decodestring");
3325 sit = isc_buffer_base(&hexbuf);
3326 len = isc_buffer_usedlength(&hexbuf);
3327 } else {
3328 sit = cookie;
3329 len = sizeof(cookie);
3332 INSIST(msg->sitok == 0 && msg->sitbad == 0);
3333 if (optlen >= len && optlen >= 8U) {
3334 if (memcmp(isc_buffer_current(optbuf), sit, 8) == 0) {
3335 msg->sitok = 1;
3336 } else {
3337 printf(";; Warning: SIT client cookie mismatch\n");
3338 msg->sitbad = 1;
3340 } else {
3341 printf(";; Warning: SIT bad token (too short)\n");
3342 msg->sitbad = 1;
3344 isc_buffer_forward(optbuf, (unsigned int)optlen);
3347 static void
3348 process_opt(dig_lookup_t *l, dns_message_t *msg) {
3349 dns_rdata_t rdata;
3350 isc_result_t result;
3351 isc_buffer_t optbuf;
3352 isc_uint16_t optcode, optlen;
3353 dns_rdataset_t *opt = msg->opt;
3355 result = dns_rdataset_first(opt);
3356 if (result == ISC_R_SUCCESS) {
3357 dns_rdata_init(&rdata);
3358 dns_rdataset_current(opt, &rdata);
3359 isc_buffer_init(&optbuf, rdata.data, rdata.length);
3360 isc_buffer_add(&optbuf, rdata.length);
3361 while (isc_buffer_remaininglength(&optbuf) >= 4) {
3362 optcode = isc_buffer_getuint16(&optbuf);
3363 optlen = isc_buffer_getuint16(&optbuf);
3364 switch (optcode) {
3365 case DNS_OPT_SIT:
3366 process_sit(l, msg, &optbuf, optlen);
3367 break;
3368 default:
3369 isc_buffer_forward(&optbuf, optlen);
3370 break;
3375 #endif
3379 * Event handler for recv complete. Perform whatever actions are necessary,
3380 * based on the specifics of the user's request.
3382 static void
3383 recv_done(isc_task_t *task, isc_event_t *event) {
3384 isc_socketevent_t *sevent = NULL;
3385 dig_query_t *query = NULL;
3386 isc_buffer_t *b = NULL;
3387 dns_message_t *msg = NULL;
3388 #ifdef DIG_SIGCHASE
3389 dig_message_t *chase_msg = NULL;
3390 dig_message_t *chase_msg2 = NULL;
3391 #endif
3392 isc_result_t result;
3393 dig_lookup_t *n, *l;
3394 isc_boolean_t docancel = ISC_FALSE;
3395 isc_boolean_t match = ISC_TRUE;
3396 unsigned int parseflags;
3397 dns_messageid_t id;
3398 unsigned int msgflags;
3399 #ifdef DIG_SIGCHASE
3400 isc_result_t do_sigchase = ISC_FALSE;
3402 dns_message_t *msg_temp = NULL;
3403 isc_region_t r;
3404 isc_buffer_t *buf = NULL;
3405 #endif
3407 UNUSED(task);
3408 INSIST(!free_now);
3410 debug("recv_done()");
3412 LOCK_LOOKUP;
3413 recvcount--;
3414 debug("recvcount=%d", recvcount);
3415 INSIST(recvcount >= 0);
3417 query = event->ev_arg;
3418 TIME_NOW(&query->time_recv);
3419 debug("lookup=%p, query=%p", query->lookup, query);
3421 l = query->lookup;
3423 REQUIRE(event->ev_type == ISC_SOCKEVENT_RECVDONE);
3424 sevent = (isc_socketevent_t *)event;
3426 b = ISC_LIST_HEAD(sevent->bufferlist);
3427 INSIST(b == &query->recvbuf);
3428 ISC_LIST_DEQUEUE(sevent->bufferlist, &query->recvbuf, link);
3430 if ((l->tcp_mode) && (l->timer != NULL))
3431 isc_timer_touch(l->timer);
3432 if ((!l->pending && !l->ns_search_only) || cancel_now) {
3433 debug("no longer pending. Got %s",
3434 isc_result_totext(sevent->result));
3435 query->waiting_connect = ISC_FALSE;
3437 isc_event_free(&event);
3438 clear_query(query);
3439 check_next_lookup(l);
3440 UNLOCK_LOOKUP;
3441 return;
3444 if (sevent->result != ISC_R_SUCCESS) {
3445 if (sevent->result == ISC_R_CANCELED) {
3446 debug("in recv cancel handler");
3447 query->waiting_connect = ISC_FALSE;
3448 } else {
3449 printf(";; communications error: %s\n",
3450 isc_result_totext(sevent->result));
3451 isc_socket_detach(&query->sock);
3452 sockcount--;
3453 debug("sockcount=%d", sockcount);
3454 INSIST(sockcount >= 0);
3456 isc_event_free(&event);
3457 clear_query(query);
3458 check_next_lookup(l);
3459 UNLOCK_LOOKUP;
3460 return;
3463 if (!l->tcp_mode &&
3464 !isc_sockaddr_compare(&sevent->address, &query->sockaddr,
3465 ISC_SOCKADDR_CMPADDR|
3466 ISC_SOCKADDR_CMPPORT|
3467 ISC_SOCKADDR_CMPSCOPE|
3468 ISC_SOCKADDR_CMPSCOPEZERO)) {
3469 char buf1[ISC_SOCKADDR_FORMATSIZE];
3470 char buf2[ISC_SOCKADDR_FORMATSIZE];
3471 isc_sockaddr_t any;
3473 if (isc_sockaddr_pf(&query->sockaddr) == AF_INET)
3474 isc_sockaddr_any(&any);
3475 else
3476 isc_sockaddr_any6(&any);
3479 * We don't expect a match when the packet is
3480 * sent to 0.0.0.0, :: or to a multicast addresses.
3481 * XXXMPA broadcast needs to be handled here as well.
3483 if ((!isc_sockaddr_eqaddr(&query->sockaddr, &any) &&
3484 !isc_sockaddr_ismulticast(&query->sockaddr)) ||
3485 isc_sockaddr_getport(&query->sockaddr) !=
3486 isc_sockaddr_getport(&sevent->address)) {
3487 isc_sockaddr_format(&sevent->address, buf1,
3488 sizeof(buf1));
3489 isc_sockaddr_format(&query->sockaddr, buf2,
3490 sizeof(buf2));
3491 printf(";; reply from unexpected source: %s,"
3492 " expected %s\n", buf1, buf2);
3493 match = ISC_FALSE;
3497 result = dns_message_peekheader(b, &id, &msgflags);
3498 if (result != ISC_R_SUCCESS || l->sendmsg->id != id) {
3499 match = ISC_FALSE;
3500 if (l->tcp_mode) {
3501 isc_boolean_t fail = ISC_TRUE;
3502 if (result == ISC_R_SUCCESS) {
3503 if (!query->first_soa_rcvd ||
3504 query->warn_id)
3505 printf(";; %s: ID mismatch: "
3506 "expected ID %u, got %u\n",
3507 query->first_soa_rcvd ?
3508 "WARNING" : "ERROR",
3509 l->sendmsg->id, id);
3510 if (query->first_soa_rcvd)
3511 fail = ISC_FALSE;
3512 query->warn_id = ISC_FALSE;
3513 } else
3514 printf(";; ERROR: short "
3515 "(< header size) message\n");
3516 if (fail) {
3517 isc_event_free(&event);
3518 clear_query(query);
3519 check_next_lookup(l);
3520 UNLOCK_LOOKUP;
3521 return;
3523 match = ISC_TRUE;
3524 } else if (result == ISC_R_SUCCESS)
3525 printf(";; Warning: ID mismatch: "
3526 "expected ID %u, got %u\n", l->sendmsg->id, id);
3527 else
3528 printf(";; Warning: short "
3529 "(< header size) message received\n");
3532 if (result == ISC_R_SUCCESS && (msgflags & DNS_MESSAGEFLAG_QR) == 0)
3533 printf(";; Warning: query response not set\n");
3535 if (!match)
3536 goto udp_mismatch;
3538 result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &msg);
3539 check_result(result, "dns_message_create");
3541 if (key != NULL) {
3542 if (l->querysig == NULL) {
3543 debug("getting initial querysig");
3544 result = dns_message_getquerytsig(l->sendmsg, mctx,
3545 &l->querysig);
3546 check_result(result, "dns_message_getquerytsig");
3548 result = dns_message_setquerytsig(msg, l->querysig);
3549 check_result(result, "dns_message_setquerytsig");
3550 result = dns_message_settsigkey(msg, key);
3551 check_result(result, "dns_message_settsigkey");
3552 msg->tsigctx = l->tsigctx;
3553 l->tsigctx = NULL;
3554 if (l->msgcounter != 0)
3555 msg->tcp_continuation = 1;
3556 l->msgcounter++;
3559 debug("before parse starts");
3560 parseflags = DNS_MESSAGEPARSE_PRESERVEORDER;
3561 #ifdef DIG_SIGCHASE
3562 if (!l->sigchase) {
3563 do_sigchase = ISC_FALSE;
3564 } else {
3565 parseflags = 0;
3566 do_sigchase = ISC_TRUE;
3568 #endif
3569 if (l->besteffort) {
3570 parseflags |= DNS_MESSAGEPARSE_BESTEFFORT;
3571 parseflags |= DNS_MESSAGEPARSE_IGNORETRUNCATION;
3573 result = dns_message_parse(msg, b, parseflags);
3574 if (result == DNS_R_RECOVERABLE) {
3575 printf(";; Warning: Message parser reports malformed "
3576 "message packet.\n");
3577 result = ISC_R_SUCCESS;
3579 if (result != ISC_R_SUCCESS) {
3580 printf(";; Got bad packet: %s\n", isc_result_totext(result));
3581 hex_dump(b);
3582 query->waiting_connect = ISC_FALSE;
3583 dns_message_destroy(&msg);
3584 isc_event_free(&event);
3585 clear_query(query);
3586 cancel_lookup(l);
3587 check_next_lookup(l);
3588 UNLOCK_LOOKUP;
3589 return;
3591 if (msg->counts[DNS_SECTION_QUESTION] != 0) {
3592 match = ISC_TRUE;
3593 for (result = dns_message_firstname(msg, DNS_SECTION_QUESTION);
3594 result == ISC_R_SUCCESS && match;
3595 result = dns_message_nextname(msg, DNS_SECTION_QUESTION)) {
3596 dns_name_t *name = NULL;
3597 dns_rdataset_t *rdataset;
3599 dns_message_currentname(msg, DNS_SECTION_QUESTION,
3600 &name);
3601 for (rdataset = ISC_LIST_HEAD(name->list);
3602 rdataset != NULL;
3603 rdataset = ISC_LIST_NEXT(rdataset, link)) {
3604 if (l->rdtype != rdataset->type ||
3605 l->rdclass != rdataset->rdclass ||
3606 !dns_name_equal(l->name, name)) {
3607 char namestr[DNS_NAME_FORMATSIZE];
3608 char typebuf[DNS_RDATATYPE_FORMATSIZE];
3609 char classbuf[DNS_RDATACLASS_FORMATSIZE];
3610 dns_name_format(name, namestr,
3611 sizeof(namestr));
3612 dns_rdatatype_format(rdataset->type,
3613 typebuf,
3614 sizeof(typebuf));
3615 dns_rdataclass_format(rdataset->rdclass,
3616 classbuf,
3617 sizeof(classbuf));
3618 printf(";; Question section mismatch: "
3619 "got %s/%s/%s\n",
3620 namestr, typebuf, classbuf);
3621 match = ISC_FALSE;
3625 if (!match) {
3626 dns_message_destroy(&msg);
3627 if (l->tcp_mode) {
3628 isc_event_free(&event);
3629 clear_query(query);
3630 check_next_lookup(l);
3631 UNLOCK_LOOKUP;
3632 return;
3633 } else
3634 goto udp_mismatch;
3637 if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0 &&
3638 !l->ignore && !l->tcp_mode) {
3639 if (l->comments)
3640 printf(";; Truncated, retrying in TCP mode.\n");
3641 n = requeue_lookup(l, ISC_TRUE);
3642 n->tcp_mode = ISC_TRUE;
3643 n->origin = query->lookup->origin;
3644 dns_message_destroy(&msg);
3645 isc_event_free(&event);
3646 clear_query(query);
3647 cancel_lookup(l);
3648 check_next_lookup(l);
3649 UNLOCK_LOOKUP;
3650 return;
3652 if ((msg->rcode == dns_rcode_servfail && !l->servfail_stops) ||
3653 (check_ra && (msg->flags & DNS_MESSAGEFLAG_RA) == 0 && l->recurse))
3655 dig_query_t *next = ISC_LIST_NEXT(query, link);
3656 if (l->current_query == query)
3657 l->current_query = NULL;
3658 if (next != NULL) {
3659 debug("sending query %p\n", next);
3660 if (l->tcp_mode)
3661 send_tcp_connect(next);
3662 else
3663 send_udp(next);
3666 * If our query is at the head of the list and there
3667 * is no next, we're the only one left, so fall
3668 * through to print the message.
3670 if ((ISC_LIST_HEAD(l->q) != query) ||
3671 (ISC_LIST_NEXT(query, link) != NULL)) {
3672 if (l->comments)
3673 printf(";; Got %s from %s, "
3674 "trying next server\n",
3675 msg->rcode == dns_rcode_servfail ?
3676 "SERVFAIL reply" :
3677 "recursion not available",
3678 query->servname);
3679 clear_query(query);
3680 check_next_lookup(l);
3681 dns_message_destroy(&msg);
3682 isc_event_free(&event);
3683 UNLOCK_LOOKUP;
3684 return;
3688 if (key != NULL) {
3689 result = dns_tsig_verify(&query->recvbuf, msg, NULL, NULL);
3690 if (result != ISC_R_SUCCESS) {
3691 printf(";; Couldn't verify signature: %s\n",
3692 isc_result_totext(result));
3693 validated = ISC_FALSE;
3695 l->tsigctx = msg->tsigctx;
3696 msg->tsigctx = NULL;
3697 if (l->querysig != NULL) {
3698 debug("freeing querysig buffer %p", l->querysig);
3699 isc_buffer_free(&l->querysig);
3701 result = dns_message_getquerytsig(msg, mctx, &l->querysig);
3702 check_result(result,"dns_message_getquerytsig");
3705 extrabytes = isc_buffer_remaininglength(b);
3707 debug("after parse");
3708 if (l->doing_xfr && l->xfr_q == NULL) {
3709 l->xfr_q = query;
3711 * Once we are in the XFR message, increase
3712 * the timeout to much longer, so brief network
3713 * outages won't cause the XFR to abort
3715 if (timeout != INT_MAX && l->timer != NULL) {
3716 unsigned int local_timeout;
3718 if (timeout == 0) {
3719 if (l->tcp_mode)
3720 local_timeout = TCP_TIMEOUT * 4;
3721 else
3722 local_timeout = UDP_TIMEOUT * 4;
3723 } else {
3724 if (timeout < (INT_MAX / 4))
3725 local_timeout = timeout * 4;
3726 else
3727 local_timeout = INT_MAX;
3729 debug("have local timeout of %d", local_timeout);
3730 isc_interval_set(&l->interval, local_timeout, 0);
3731 result = isc_timer_reset(l->timer,
3732 isc_timertype_once,
3733 NULL,
3734 &l->interval,
3735 ISC_FALSE);
3736 check_result(result, "isc_timer_reset");
3740 #ifdef ISC_PLATFORM_USESIT
3741 if (l->sitvalue != NULL) {
3742 if (msg->opt == NULL)
3743 printf(";; expected opt record in response\n");
3744 else
3745 process_opt(l, msg);
3746 } else if (l->sit && msg->opt != NULL)
3747 process_opt(l, msg);
3748 #endif
3750 if (!l->doing_xfr || l->xfr_q == query) {
3751 if (msg->rcode == dns_rcode_nxdomain &&
3752 (l->origin != NULL || l->need_search)) {
3753 if (!next_origin(query->lookup) || showsearch) {
3754 printmessage(query, msg, ISC_TRUE);
3755 received(b->used, &sevent->address, query);
3757 } else if (!l->trace && !l->ns_search_only) {
3758 #ifdef DIG_SIGCHASE
3759 if (!do_sigchase)
3760 #endif
3761 printmessage(query, msg, ISC_TRUE);
3762 } else if (l->trace) {
3763 int nl = 0;
3764 int count = msg->counts[DNS_SECTION_ANSWER];
3766 debug("in TRACE code");
3767 if (!l->ns_search_only)
3768 printmessage(query, msg, ISC_TRUE);
3770 l->rdtype = l->qrdtype;
3771 if (l->trace_root || (l->ns_search_only && count > 0)) {
3772 if (!l->trace_root)
3773 l->rdtype = dns_rdatatype_soa;
3774 nl = followup_lookup(msg, query,
3775 DNS_SECTION_ANSWER);
3776 l->trace_root = ISC_FALSE;
3777 } else if (count == 0)
3778 nl = followup_lookup(msg, query,
3779 DNS_SECTION_AUTHORITY);
3780 if (nl == 0)
3781 docancel = ISC_TRUE;
3782 } else {
3783 debug("in NSSEARCH code");
3785 if (l->trace_root) {
3787 * This is the initial NS query.
3789 int nl;
3791 l->rdtype = dns_rdatatype_soa;
3792 nl = followup_lookup(msg, query,
3793 DNS_SECTION_ANSWER);
3794 if (nl == 0)
3795 docancel = ISC_TRUE;
3796 l->trace_root = ISC_FALSE;
3797 usesearch = ISC_FALSE;
3798 } else
3799 #ifdef DIG_SIGCHASE
3800 if (!do_sigchase)
3801 #endif
3802 printmessage(query, msg, ISC_TRUE);
3804 #ifdef DIG_SIGCHASE
3805 if (do_sigchase) {
3806 chase_msg = isc_mem_allocate(mctx,
3807 sizeof(dig_message_t));
3808 if (chase_msg == NULL) {
3809 fatal("Memory allocation failure in %s:%d",
3810 __FILE__, __LINE__);
3812 ISC_LIST_INITANDAPPEND(chase_message_list, chase_msg,
3813 link);
3814 if (dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE,
3815 &msg_temp) != ISC_R_SUCCESS) {
3816 fatal("dns_message_create in %s:%d",
3817 __FILE__, __LINE__);
3820 isc_buffer_usedregion(b, &r);
3821 result = isc_buffer_allocate(mctx, &buf, r.length);
3823 check_result(result, "isc_buffer_allocate");
3824 result = isc_buffer_copyregion(buf, &r);
3825 check_result(result, "isc_buffer_copyregion");
3827 result = dns_message_parse(msg_temp, buf, 0);
3829 isc_buffer_free(&buf);
3830 chase_msg->msg = msg_temp;
3832 chase_msg2 = isc_mem_allocate(mctx,
3833 sizeof(dig_message_t));
3834 if (chase_msg2 == NULL) {
3835 fatal("Memory allocation failure in %s:%d",
3836 __FILE__, __LINE__);
3838 ISC_LIST_INITANDAPPEND(chase_message_list2, chase_msg2,
3839 link);
3840 chase_msg2->msg = msg;
3842 #endif
3845 #ifdef DIG_SIGCHASE
3846 if (l->sigchase && ISC_LIST_EMPTY(lookup_list)) {
3847 sigchase(msg_temp);
3849 #endif
3851 if (l->pending)
3852 debug("still pending.");
3853 if (l->doing_xfr) {
3854 if (query != l->xfr_q) {
3855 dns_message_destroy(&msg);
3856 isc_event_free(&event);
3857 query->waiting_connect = ISC_FALSE;
3858 UNLOCK_LOOKUP;
3859 return;
3861 if (!docancel)
3862 docancel = check_for_more_data(query, msg, sevent);
3863 if (docancel) {
3864 dns_message_destroy(&msg);
3865 clear_query(query);
3866 cancel_lookup(l);
3867 check_next_lookup(l);
3869 } else {
3871 if (msg->rcode == dns_rcode_noerror || l->origin == NULL) {
3873 #ifdef DIG_SIGCHASE
3874 if (!l->sigchase)
3875 #endif
3876 received(b->used, &sevent->address, query);
3879 if (!query->lookup->ns_search_only)
3880 query->lookup->pending = ISC_FALSE;
3881 if (!query->lookup->ns_search_only ||
3882 query->lookup->trace_root || docancel) {
3883 #ifdef DIG_SIGCHASE
3884 if (!do_sigchase)
3885 #endif
3886 dns_message_destroy(&msg);
3888 cancel_lookup(l);
3890 clear_query(query);
3891 check_next_lookup(l);
3893 if (msg != NULL) {
3894 #ifdef DIG_SIGCHASE
3895 if (do_sigchase)
3896 msg = NULL;
3897 else
3898 #endif
3899 dns_message_destroy(&msg);
3901 isc_event_free(&event);
3902 UNLOCK_LOOKUP;
3903 return;
3905 udp_mismatch:
3906 isc_buffer_invalidate(&query->recvbuf);
3907 isc_buffer_init(&query->recvbuf, query->recvspace, COMMSIZE);
3908 ISC_LIST_ENQUEUE(query->recvlist, &query->recvbuf, link);
3909 result = isc_socket_recvv(query->sock, &query->recvlist, 1,
3910 global_task, recv_done, query);
3911 check_result(result, "isc_socket_recvv");
3912 recvcount++;
3913 isc_event_free(&event);
3914 UNLOCK_LOOKUP;
3915 return;
3919 * Turn a name into an address, using system-supplied routines. This is
3920 * used in looking up server names, etc... and needs to use system-supplied
3921 * routines, since they may be using a non-DNS system for these lookups.
3923 isc_result_t
3924 get_address(char *host, in_port_t myport, isc_sockaddr_t *sockaddr) {
3925 int count;
3926 isc_result_t result;
3928 isc_app_block();
3929 result = bind9_getaddresses(host, myport, sockaddr, 1, &count);
3930 isc_app_unblock();
3931 if (result != ISC_R_SUCCESS)
3932 return (result);
3934 INSIST(count == 1);
3936 return (ISC_R_SUCCESS);
3940 getaddresses(dig_lookup_t *lookup, const char *host, isc_result_t *resultp) {
3941 isc_result_t result;
3942 isc_sockaddr_t sockaddrs[DIG_MAX_ADDRESSES];
3943 isc_netaddr_t netaddr;
3944 int count, i;
3945 dig_server_t *srv;
3946 char tmp[ISC_NETADDR_FORMATSIZE];
3948 result = bind9_getaddresses(host, 0, sockaddrs,
3949 DIG_MAX_ADDRESSES, &count);
3950 if (resultp != NULL)
3951 *resultp = result;
3952 if (result != ISC_R_SUCCESS) {
3953 if (resultp == NULL)
3954 fatal("couldn't get address for '%s': %s",
3955 host, isc_result_totext(result));
3956 return 0;
3959 for (i = 0; i < count; i++) {
3960 isc_netaddr_fromsockaddr(&netaddr, &sockaddrs[i]);
3961 isc_netaddr_format(&netaddr, tmp, sizeof(tmp));
3962 srv = make_server(tmp, host);
3963 ISC_LIST_APPEND(lookup->my_server_list, srv, link);
3966 return count;
3970 * Initiate either a TCP or UDP lookup
3972 void
3973 do_lookup(dig_lookup_t *lookup) {
3974 dig_query_t *query;
3976 REQUIRE(lookup != NULL);
3978 debug("do_lookup()");
3979 lookup->pending = ISC_TRUE;
3980 query = ISC_LIST_HEAD(lookup->q);
3981 if (query != NULL) {
3982 if (lookup->tcp_mode)
3983 send_tcp_connect(query);
3984 else
3985 send_udp(query);
3990 * Start everything in action upon task startup.
3992 void
3993 onrun_callback(isc_task_t *task, isc_event_t *event) {
3994 UNUSED(task);
3996 isc_event_free(&event);
3997 LOCK_LOOKUP;
3998 start_lookup();
3999 UNLOCK_LOOKUP;
4003 * Make everything on the lookup queue go away. Mainly used by the
4004 * SIGINT handler.
4006 void
4007 cancel_all(void) {
4008 dig_lookup_t *l, *n;
4009 dig_query_t *q, *nq;
4011 debug("cancel_all()");
4013 LOCK_LOOKUP;
4014 if (free_now) {
4015 UNLOCK_LOOKUP;
4016 return;
4018 cancel_now = ISC_TRUE;
4019 if (current_lookup != NULL) {
4020 if (current_lookup->timer != NULL)
4021 isc_timer_detach(&current_lookup->timer);
4022 for (q = ISC_LIST_HEAD(current_lookup->q);
4023 q != NULL;
4024 q = nq)
4026 nq = ISC_LIST_NEXT(q, link);
4027 debug("canceling pending query %p, belonging to %p",
4028 q, current_lookup);
4029 if (q->sock != NULL)
4030 isc_socket_cancel(q->sock, NULL,
4031 ISC_SOCKCANCEL_ALL);
4032 else
4033 clear_query(q);
4035 for (q = ISC_LIST_HEAD(current_lookup->connecting);
4036 q != NULL;
4037 q = nq)
4039 nq = ISC_LIST_NEXT(q, clink);
4040 debug("canceling connecting query %p, belonging to %p",
4041 q, current_lookup);
4042 if (q->sock != NULL)
4043 isc_socket_cancel(q->sock, NULL,
4044 ISC_SOCKCANCEL_ALL);
4045 else
4046 clear_query(q);
4049 l = ISC_LIST_HEAD(lookup_list);
4050 while (l != NULL) {
4051 n = ISC_LIST_NEXT(l, link);
4052 ISC_LIST_DEQUEUE(lookup_list, l, link);
4053 try_clear_lookup(l);
4054 l = n;
4056 UNLOCK_LOOKUP;
4060 * Destroy all of the libs we are using, and get everything ready for a
4061 * clean shutdown.
4063 void
4064 destroy_libs(void) {
4065 #ifdef DIG_SIGCHASE
4066 void * ptr;
4067 dig_message_t *chase_msg;
4068 #endif
4069 #ifdef WITH_IDN
4070 isc_result_t result;
4071 #endif
4073 if (keep != NULL)
4074 isc_socket_detach(&keep);
4075 debug("destroy_libs()");
4076 if (global_task != NULL) {
4077 debug("freeing task");
4078 isc_task_detach(&global_task);
4081 * The taskmgr_destroy() call blocks until all events are cleared
4082 * from the task.
4084 if (taskmgr != NULL) {
4085 debug("freeing taskmgr");
4086 isc_taskmgr_destroy(&taskmgr);
4088 LOCK_LOOKUP;
4089 REQUIRE(sockcount == 0);
4090 REQUIRE(recvcount == 0);
4091 REQUIRE(sendcount == 0);
4093 INSIST(ISC_LIST_HEAD(lookup_list) == NULL);
4094 INSIST(current_lookup == NULL);
4095 INSIST(!free_now);
4097 free_now = ISC_TRUE;
4099 lwres_conf_clear(lwctx);
4100 lwres_context_destroy(&lwctx);
4102 flush_server_list();
4104 clear_searchlist();
4106 #ifdef WITH_IDN
4107 result = dns_name_settotextfilter(NULL);
4108 check_result(result, "dns_name_settotextfilter");
4109 #endif
4110 dns_name_destroy();
4112 if (commctx != NULL) {
4113 debug("freeing commctx");
4114 isc_mempool_destroy(&commctx);
4116 if (socketmgr != NULL) {
4117 debug("freeing socketmgr");
4118 isc_socketmgr_destroy(&socketmgr);
4120 if (timermgr != NULL) {
4121 debug("freeing timermgr");
4122 isc_timermgr_destroy(&timermgr);
4124 if (key != NULL) {
4125 debug("freeing key %p", key);
4126 dns_tsigkey_detach(&key);
4128 if (namebuf != NULL)
4129 isc_buffer_free(&namebuf);
4131 if (is_dst_up) {
4132 debug("destroy DST lib");
4133 dst_lib_destroy();
4134 is_dst_up = ISC_FALSE;
4136 if (entp != NULL) {
4137 debug("detach from entropy");
4138 isc_entropy_detach(&entp);
4141 UNLOCK_LOOKUP;
4142 DESTROYLOCK(&lookup_lock);
4143 #ifdef DIG_SIGCHASE
4145 debug("Destroy the messages kept for sigchase");
4146 /* Destroy the messages kept for sigchase */
4147 chase_msg = ISC_LIST_HEAD(chase_message_list);
4149 while (chase_msg != NULL) {
4150 INSIST(chase_msg->msg != NULL);
4151 dns_message_destroy(&(chase_msg->msg));
4152 ptr = chase_msg;
4153 chase_msg = ISC_LIST_NEXT(chase_msg, link);
4154 isc_mem_free(mctx, ptr);
4157 chase_msg = ISC_LIST_HEAD(chase_message_list2);
4159 while (chase_msg != NULL) {
4160 INSIST(chase_msg->msg != NULL);
4161 dns_message_destroy(&(chase_msg->msg));
4162 ptr = chase_msg;
4163 chase_msg = ISC_LIST_NEXT(chase_msg, link);
4164 isc_mem_free(mctx, ptr);
4166 if (dns_name_dynamic(&chase_name))
4167 free_name(&chase_name, mctx);
4168 #if DIG_SIGCHASE_TD
4169 if (dns_name_dynamic(&chase_current_name))
4170 free_name(&chase_current_name, mctx);
4171 if (dns_name_dynamic(&chase_authority_name))
4172 free_name(&chase_authority_name, mctx);
4173 #endif
4174 #if DIG_SIGCHASE_BU
4175 if (dns_name_dynamic(&chase_signame))
4176 free_name(&chase_signame, mctx);
4177 #endif
4179 #endif
4180 debug("Removing log context");
4181 isc_log_destroy(&lctx);
4183 debug("Destroy memory");
4184 if (memdebugging != 0)
4185 isc_mem_stats(mctx, stderr);
4186 if (mctx != NULL)
4187 isc_mem_destroy(&mctx);
4190 #ifdef WITH_IDN
4191 static void
4192 initialize_idn(void) {
4193 idn_result_t r;
4194 isc_result_t result;
4196 #ifdef HAVE_SETLOCALE
4197 /* Set locale */
4198 (void)setlocale(LC_ALL, "");
4199 #endif
4200 /* Create configuration context. */
4201 r = idn_nameinit(1);
4202 if (r != idn_success)
4203 fatal("idn api initialization failed: %s",
4204 idn_result_tostring(r));
4206 /* Set domain name -> text post-conversion filter. */
4207 result = dns_name_settotextfilter(output_filter);
4208 check_result(result, "dns_name_settotextfilter");
4211 static isc_result_t
4212 output_filter(isc_buffer_t *buffer, unsigned int used_org,
4213 isc_boolean_t absolute)
4215 char tmp1[MAXDLEN], tmp2[MAXDLEN];
4216 size_t fromlen, tolen;
4217 isc_boolean_t end_with_dot;
4220 * Copy contents of 'buffer' to 'tmp1', supply trailing dot
4221 * if 'absolute' is true, and terminate with NUL.
4223 fromlen = isc_buffer_usedlength(buffer) - used_org;
4224 if (fromlen >= MAXDLEN)
4225 return (ISC_R_SUCCESS);
4226 memmove(tmp1, (char *)isc_buffer_base(buffer) + used_org, fromlen);
4227 end_with_dot = (tmp1[fromlen - 1] == '.') ? ISC_TRUE : ISC_FALSE;
4228 if (absolute && !end_with_dot) {
4229 fromlen++;
4230 if (fromlen >= MAXDLEN)
4231 return (ISC_R_SUCCESS);
4232 tmp1[fromlen - 1] = '.';
4234 tmp1[fromlen] = '\0';
4237 * Convert contents of 'tmp1' to local encoding.
4239 if (idn_decodename(IDN_DECODE_APP, tmp1, tmp2, MAXDLEN) != idn_success)
4240 return (ISC_R_SUCCESS);
4241 strcpy(tmp1, tmp2);
4244 * Copy the converted contents in 'tmp1' back to 'buffer'.
4245 * If we have appended trailing dot, remove it.
4247 tolen = strlen(tmp1);
4248 if (absolute && !end_with_dot && tmp1[tolen - 1] == '.')
4249 tolen--;
4251 if (isc_buffer_length(buffer) < used_org + tolen)
4252 return (ISC_R_NOSPACE);
4254 isc_buffer_subtract(buffer, isc_buffer_usedlength(buffer) - used_org);
4255 memmove(isc_buffer_used(buffer), tmp1, tolen);
4256 isc_buffer_add(buffer, (unsigned int)tolen);
4258 return (ISC_R_SUCCESS);
4261 static idn_result_t
4262 append_textname(char *name, const char *origin, size_t namesize) {
4263 size_t namelen = strlen(name);
4264 size_t originlen = strlen(origin);
4266 /* Already absolute? */
4267 if (namelen > 0 && name[namelen - 1] == '.')
4268 return idn_success;
4270 /* Append dot and origin */
4272 if (namelen + 1 + originlen >= namesize)
4273 return idn_buffer_overflow;
4275 if (*origin != '.')
4276 name[namelen++] = '.';
4277 (void)strcpy(name + namelen, origin);
4278 return idn_success;
4281 static void
4282 idn_check_result(idn_result_t r, const char *msg) {
4283 if (r != idn_success) {
4284 exitcode = 1;
4285 fatal("%s: %s", msg, idn_result_tostring(r));
4288 #endif /* WITH_IDN */
4290 #ifdef DIG_SIGCHASE
4291 void
4292 print_type(dns_rdatatype_t type)
4294 isc_buffer_t * b = NULL;
4295 isc_result_t result;
4296 isc_region_t r;
4298 result = isc_buffer_allocate(mctx, &b, 4000);
4299 check_result(result, "isc_buffer_allocate");
4301 result = dns_rdatatype_totext(type, b);
4302 check_result(result, "print_type");
4304 isc_buffer_usedregion(b, &r);
4305 r.base[r.length] = '\0';
4307 printf("%s", r.base);
4309 isc_buffer_free(&b);
4312 void
4313 dump_database_section(dns_message_t *msg, int section)
4315 dns_name_t *msg_name=NULL;
4317 dns_rdataset_t *rdataset;
4319 do {
4320 dns_message_currentname(msg, section, &msg_name);
4322 for (rdataset = ISC_LIST_HEAD(msg_name->list); rdataset != NULL;
4323 rdataset = ISC_LIST_NEXT(rdataset, link)) {
4324 dns_name_print(msg_name, stdout);
4325 printf("\n");
4326 print_rdataset(msg_name, rdataset, mctx);
4327 printf("end\n");
4329 msg_name = NULL;
4330 } while (dns_message_nextname(msg, section) == ISC_R_SUCCESS);
4333 void
4334 dump_database(void) {
4335 dig_message_t * msg;
4337 for (msg = ISC_LIST_HEAD(chase_message_list); msg != NULL;
4338 msg = ISC_LIST_NEXT(msg, link)) {
4339 if (dns_message_firstname(msg->msg, DNS_SECTION_ANSWER)
4340 == ISC_R_SUCCESS)
4341 dump_database_section(msg->msg, DNS_SECTION_ANSWER);
4343 if (dns_message_firstname(msg->msg, DNS_SECTION_AUTHORITY)
4344 == ISC_R_SUCCESS)
4345 dump_database_section(msg->msg, DNS_SECTION_AUTHORITY);
4347 if (dns_message_firstname(msg->msg, DNS_SECTION_ADDITIONAL)
4348 == ISC_R_SUCCESS)
4349 dump_database_section(msg->msg, DNS_SECTION_ADDITIONAL);
4354 dns_rdataset_t *
4355 search_type(dns_name_t *name, dns_rdatatype_t type, dns_rdatatype_t covers) {
4356 dns_rdataset_t *rdataset;
4357 dns_rdata_sig_t siginfo;
4358 dns_rdata_t sigrdata = DNS_RDATA_INIT;
4359 isc_result_t result;
4361 for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL;
4362 rdataset = ISC_LIST_NEXT(rdataset, link)) {
4363 if (type == dns_rdatatype_any) {
4364 if (rdataset->type != dns_rdatatype_rrsig)
4365 return (rdataset);
4366 } else if ((type == dns_rdatatype_rrsig) &&
4367 (rdataset->type == dns_rdatatype_rrsig)) {
4368 result = dns_rdataset_first(rdataset);
4369 check_result(result, "empty rdataset");
4370 dns_rdataset_current(rdataset, &sigrdata);
4371 result = dns_rdata_tostruct(&sigrdata, &siginfo, NULL);
4372 check_result(result, "sigrdata tostruct siginfo");
4374 if ((siginfo.covered == covers) ||
4375 (covers == dns_rdatatype_any)) {
4376 dns_rdata_reset(&sigrdata);
4377 dns_rdata_freestruct(&siginfo);
4378 return (rdataset);
4380 dns_rdata_reset(&sigrdata);
4381 dns_rdata_freestruct(&siginfo);
4382 } else if (rdataset->type == type)
4383 return (rdataset);
4385 return (NULL);
4388 dns_rdataset_t *
4389 chase_scanname_section(dns_message_t *msg, dns_name_t *name,
4390 dns_rdatatype_t type, dns_rdatatype_t covers,
4391 int section)
4393 dns_rdataset_t *rdataset;
4394 dns_name_t *msg_name = NULL;
4396 if (msg->counts[section] == 0)
4397 return (NULL);
4399 do {
4400 dns_message_currentname(msg, section, &msg_name);
4401 if (dns_name_compare(msg_name, name) == 0) {
4402 rdataset = search_type(msg_name, type, covers);
4403 if (rdataset != NULL)
4404 return (rdataset);
4406 msg_name = NULL;
4407 } while (dns_message_nextname(msg, section) == ISC_R_SUCCESS);
4409 return (NULL);
4413 dns_rdataset_t *
4414 chase_scanname(dns_name_t *name, dns_rdatatype_t type, dns_rdatatype_t covers)
4416 dns_rdataset_t *rdataset = NULL;
4417 dig_message_t * msg;
4419 for (msg = ISC_LIST_HEAD(chase_message_list2); msg != NULL;
4420 msg = ISC_LIST_NEXT(msg, link)) {
4421 if (dns_message_firstname(msg->msg, DNS_SECTION_ANSWER)
4422 == ISC_R_SUCCESS)
4423 rdataset = chase_scanname_section(msg->msg, name,
4424 type, covers,
4425 DNS_SECTION_ANSWER);
4426 if (rdataset != NULL)
4427 return (rdataset);
4428 if (dns_message_firstname(msg->msg, DNS_SECTION_AUTHORITY)
4429 == ISC_R_SUCCESS)
4430 rdataset =
4431 chase_scanname_section(msg->msg, name,
4432 type, covers,
4433 DNS_SECTION_AUTHORITY);
4434 if (rdataset != NULL)
4435 return (rdataset);
4436 if (dns_message_firstname(msg->msg, DNS_SECTION_ADDITIONAL)
4437 == ISC_R_SUCCESS)
4438 rdataset =
4439 chase_scanname_section(msg->msg, name, type,
4440 covers,
4441 DNS_SECTION_ADDITIONAL);
4442 if (rdataset != NULL)
4443 return (rdataset);
4446 return (NULL);
4449 dns_rdataset_t *
4450 sigchase_scanname(dns_rdatatype_t type, dns_rdatatype_t covers,
4451 isc_boolean_t * lookedup, dns_name_t *rdata_name)
4453 dig_lookup_t *lookup;
4454 isc_buffer_t *b = NULL;
4455 isc_region_t r;
4456 isc_result_t result;
4457 dns_rdataset_t * temp;
4458 dns_rdatatype_t querytype;
4460 temp = chase_scanname(rdata_name, type, covers);
4461 if (temp != NULL)
4462 return (temp);
4464 if (*lookedup == ISC_TRUE)
4465 return (NULL);
4467 lookup = clone_lookup(current_lookup, ISC_TRUE);
4468 lookup->trace_root = ISC_FALSE;
4469 lookup->new_search = ISC_TRUE;
4471 result = isc_buffer_allocate(mctx, &b, BUFSIZE);
4472 check_result(result, "isc_buffer_allocate");
4473 result = dns_name_totext(rdata_name, ISC_FALSE, b);
4474 check_result(result, "dns_name_totext");
4475 isc_buffer_usedregion(b, &r);
4476 r.base[r.length] = '\0';
4477 strlcpy(lookup->textname, (char*)r.base, sizeof(lookup->textname));
4478 isc_buffer_free(&b);
4480 if (type == dns_rdatatype_rrsig)
4481 querytype = covers;
4482 else
4483 querytype = type;
4485 if (querytype == 0 || querytype == 255) {
4486 printf("Error in the queried type: %d\n", querytype);
4487 return (NULL);
4490 lookup->rdtype = querytype;
4491 lookup->rdtypeset = ISC_TRUE;
4492 lookup->qrdtype = querytype;
4493 *lookedup = ISC_TRUE;
4495 ISC_LIST_APPEND(lookup_list, lookup, link);
4496 printf("\n\nLaunch a query to find a RRset of type ");
4497 print_type(type);
4498 printf(" for zone: %s\n", lookup->textname);
4499 return (NULL);
4502 isc_result_t
4503 insert_trustedkey(void *arg, dns_name_t *name, dns_rdataset_t *rdataset)
4505 isc_result_t result;
4506 dst_key_t *key;
4508 UNUSED(arg);
4510 if (rdataset == NULL || rdataset->type != dns_rdatatype_dnskey)
4511 return (ISC_R_SUCCESS);
4513 for (result = dns_rdataset_first(rdataset);
4514 result == ISC_R_SUCCESS;
4515 result = dns_rdataset_next(rdataset)) {
4516 dns_rdata_t rdata = DNS_RDATA_INIT;
4517 isc_buffer_t b;
4519 dns_rdataset_current(rdataset, &rdata);
4520 isc_buffer_init(&b, rdata.data, rdata.length);
4521 isc_buffer_add(&b, rdata.length);
4522 if (tk_list.nb_tk >= MAX_TRUSTED_KEY)
4523 return (ISC_R_SUCCESS);
4524 key = NULL;
4525 result = dst_key_fromdns(name, rdata.rdclass, &b, mctx, &key);
4526 if (result != ISC_R_SUCCESS)
4527 continue;
4528 tk_list.key[tk_list.nb_tk++] = key;
4530 return (ISC_R_SUCCESS);
4533 void
4534 clean_trustedkey()
4536 int i = 0;
4538 for (i= 0; i < MAX_TRUSTED_KEY; i++) {
4539 if (tk_list.key[i] != NULL) {
4540 dst_key_free(&tk_list.key[i]);
4541 tk_list.key[i] = NULL;
4542 } else
4543 break;
4545 tk_list.nb_tk = 0;
4546 return;
4549 char alphnum[] =
4550 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
4552 isc_result_t
4553 removetmpkey(isc_mem_t *mctx, const char *file)
4555 char *tempnamekey = NULL;
4556 int tempnamekeylen;
4557 isc_result_t result;
4559 tempnamekeylen = strlen(file)+10;
4561 tempnamekey = isc_mem_allocate(mctx, tempnamekeylen);
4562 if (tempnamekey == NULL)
4563 return (ISC_R_NOMEMORY);
4565 memset(tempnamekey, 0, tempnamekeylen);
4567 strcat(tempnamekey, file);
4568 strcat(tempnamekey,".key");
4569 isc_file_remove(tempnamekey);
4571 result = isc_file_remove(tempnamekey);
4572 isc_mem_free(mctx, tempnamekey);
4573 return (result);
4576 isc_result_t
4577 get_trusted_key(isc_mem_t *mctx)
4579 isc_result_t result;
4580 const char *filename = NULL;
4581 dns_rdatacallbacks_t callbacks;
4583 result = isc_file_exists(trustedkey);
4584 if (result != ISC_TRUE) {
4585 result = isc_file_exists("/etc/trusted-key.key");
4586 if (result != ISC_TRUE) {
4587 result = isc_file_exists("./trusted-key.key");
4588 if (result != ISC_TRUE)
4589 return (ISC_R_FAILURE);
4590 else
4591 filename = "./trusted-key.key";
4592 } else
4593 filename = "/etc/trusted-key.key";
4594 } else
4595 filename = trustedkey;
4597 if (filename == NULL) {
4598 printf("No trusted key\n");
4599 return (ISC_R_FAILURE);
4602 dns_rdatacallbacks_init_stdio(&callbacks);
4603 callbacks.add = insert_trustedkey;
4604 return (dns_master_loadfile(filename, dns_rootname, dns_rootname,
4605 current_lookup->rdclass, DNS_MASTER_NOTTL,
4606 &callbacks, mctx));
4610 static void
4611 nameFromString(const char *str, dns_name_t *p_ret) {
4612 size_t len = strlen(str);
4613 isc_result_t result;
4614 isc_buffer_t buffer;
4615 dns_fixedname_t fixedname;
4617 REQUIRE(p_ret != NULL);
4618 REQUIRE(str != NULL);
4620 isc_buffer_constinit(&buffer, str, len);
4621 isc_buffer_add(&buffer, len);
4623 dns_fixedname_init(&fixedname);
4624 result = dns_name_fromtext(dns_fixedname_name(&fixedname), &buffer,
4625 dns_rootname, DNS_NAME_DOWNCASE, NULL);
4626 check_result(result, "nameFromString");
4628 if (dns_name_dynamic(p_ret))
4629 free_name(p_ret, mctx);
4631 result = dns_name_dup(dns_fixedname_name(&fixedname), mctx, p_ret);
4632 check_result(result, "nameFromString");
4636 #if DIG_SIGCHASE_TD
4637 isc_result_t
4638 prepare_lookup(dns_name_t *name)
4640 isc_result_t result;
4641 dig_lookup_t *lookup = NULL;
4642 dig_server_t *s;
4643 void *ptr;
4645 lookup = clone_lookup(current_lookup, ISC_TRUE);
4646 lookup->trace_root = ISC_FALSE;
4647 lookup->new_search = ISC_TRUE;
4648 lookup->trace_root_sigchase = ISC_FALSE;
4650 strlcpy(lookup->textname, lookup->textnamesigchase, MXNAME);
4652 lookup->rdtype = lookup->rdtype_sigchase;
4653 lookup->rdtypeset = ISC_TRUE;
4654 lookup->qrdtype = lookup->qrdtype_sigchase;
4656 s = ISC_LIST_HEAD(lookup->my_server_list);
4657 while (s != NULL) {
4658 debug("freeing server %p belonging to %p",
4659 s, lookup);
4660 ptr = s;
4661 s = ISC_LIST_NEXT(s, link);
4662 ISC_LIST_DEQUEUE(lookup->my_server_list,
4663 (dig_server_t *)ptr, link);
4664 isc_mem_free(mctx, ptr);
4668 for (result = dns_rdataset_first(chase_nsrdataset);
4669 result == ISC_R_SUCCESS;
4670 result = dns_rdataset_next(chase_nsrdataset)) {
4671 char namestr[DNS_NAME_FORMATSIZE];
4672 dns_rdata_ns_t ns;
4673 dns_rdata_t rdata = DNS_RDATA_INIT;
4674 dig_server_t * srv = NULL;
4675 #define __FOLLOW_GLUE__
4676 #ifdef __FOLLOW_GLUE__
4677 isc_buffer_t *b = NULL;
4678 isc_result_t result;
4679 isc_region_t r;
4680 dns_rdataset_t *rdataset = NULL;
4681 isc_boolean_t true = ISC_TRUE;
4682 #endif
4684 memset(namestr, 0, DNS_NAME_FORMATSIZE);
4686 dns_rdataset_current(chase_nsrdataset, &rdata);
4688 result = dns_rdata_tostruct(&rdata, &ns, NULL);
4689 check_result(result, "dns_rdata_tostruct");
4691 #ifdef __FOLLOW_GLUE__
4693 result = advanced_rrsearch(&rdataset, &ns.name,
4694 dns_rdatatype_aaaa,
4695 dns_rdatatype_any, &true);
4696 if (result == ISC_R_SUCCESS) {
4697 for (result = dns_rdataset_first(rdataset);
4698 result == ISC_R_SUCCESS;
4699 result = dns_rdataset_next(rdataset)) {
4700 dns_rdata_t aaaa = DNS_RDATA_INIT;
4701 dns_rdataset_current(rdataset, &aaaa);
4703 result = isc_buffer_allocate(mctx, &b, 80);
4704 check_result(result, "isc_buffer_allocate");
4706 dns_rdata_totext(&aaaa, &ns.name, b);
4707 isc_buffer_usedregion(b, &r);
4708 r.base[r.length] = '\0';
4709 strlcpy(namestr, (char*)r.base,
4710 DNS_NAME_FORMATSIZE);
4711 isc_buffer_free(&b);
4712 dns_rdata_reset(&aaaa);
4715 srv = make_server(namestr, namestr);
4717 ISC_LIST_APPEND(lookup->my_server_list,
4718 srv, link);
4722 rdataset = NULL;
4723 result = advanced_rrsearch(&rdataset, &ns.name, dns_rdatatype_a,
4724 dns_rdatatype_any, &true);
4725 if (result == ISC_R_SUCCESS) {
4726 for (result = dns_rdataset_first(rdataset);
4727 result == ISC_R_SUCCESS;
4728 result = dns_rdataset_next(rdataset)) {
4729 dns_rdata_t a = DNS_RDATA_INIT;
4730 dns_rdataset_current(rdataset, &a);
4732 result = isc_buffer_allocate(mctx, &b, 80);
4733 check_result(result, "isc_buffer_allocate");
4735 dns_rdata_totext(&a, &ns.name, b);
4736 isc_buffer_usedregion(b, &r);
4737 r.base[r.length] = '\0';
4738 strlcpy(namestr, (char*)r.base,
4739 DNS_NAME_FORMATSIZE);
4740 isc_buffer_free(&b);
4741 dns_rdata_reset(&a);
4742 printf("ns name: %s\n", namestr);
4745 srv = make_server(namestr, namestr);
4747 ISC_LIST_APPEND(lookup->my_server_list,
4748 srv, link);
4751 #else
4753 dns_name_format(&ns.name, namestr, sizeof(namestr));
4754 printf("ns name: ");
4755 dns_name_print(&ns.name, stdout);
4756 printf("\n");
4757 srv = make_server(namestr, namestr);
4759 ISC_LIST_APPEND(lookup->my_server_list, srv, link);
4761 #endif
4762 dns_rdata_freestruct(&ns);
4763 dns_rdata_reset(&rdata);
4767 ISC_LIST_APPEND(lookup_list, lookup, link);
4768 printf("\nLaunch a query to find a RRset of type ");
4769 print_type(lookup->rdtype);
4770 printf(" for zone: %s", lookup->textname);
4771 printf(" with nameservers:");
4772 printf("\n");
4773 print_rdataset(name, chase_nsrdataset, mctx);
4774 return (ISC_R_SUCCESS);
4778 isc_result_t
4779 child_of_zone(dns_name_t * name, dns_name_t * zone_name,
4780 dns_name_t * child_name)
4782 dns_namereln_t name_reln;
4783 int orderp;
4784 unsigned int nlabelsp;
4786 name_reln = dns_name_fullcompare(name, zone_name, &orderp, &nlabelsp);
4787 if (name_reln != dns_namereln_subdomain ||
4788 dns_name_countlabels(name) <= dns_name_countlabels(zone_name) + 1) {
4789 printf("\n;; ERROR : ");
4790 dns_name_print(name, stdout);
4791 printf(" is not a subdomain of: ");
4792 dns_name_print(zone_name, stdout);
4793 printf(" FAILED\n\n");
4794 return (ISC_R_FAILURE);
4797 dns_name_getlabelsequence(name,
4798 dns_name_countlabels(name) -
4799 dns_name_countlabels(zone_name) -1,
4800 dns_name_countlabels(zone_name) +1,
4801 child_name);
4802 return (ISC_R_SUCCESS);
4805 isc_result_t
4806 grandfather_pb_test(dns_name_t *zone_name, dns_rdataset_t *sigrdataset) {
4807 dns_rdata_sig_t siginfo;
4808 dns_rdataset_t mysigrdataset;
4809 isc_result_t result;
4811 dns_rdataset_init(&mysigrdataset);
4812 dns_rdataset_clone(sigrdataset, &mysigrdataset);
4814 result = dns_rdataset_first(&mysigrdataset);
4815 check_result(result, "empty RRSIG dataset");
4817 do {
4818 dns_rdata_t sigrdata = DNS_RDATA_INIT;
4820 dns_rdataset_current(&mysigrdataset, &sigrdata);
4822 result = dns_rdata_tostruct(&sigrdata, &siginfo, NULL);
4823 check_result(result, "sigrdata tostruct siginfo");
4825 if (dns_name_compare(&siginfo.signer, zone_name) == 0) {
4826 result = ISC_R_SUCCESS;
4827 goto cleanup;
4829 } while (dns_rdataset_next(&mysigrdataset) == ISC_R_SUCCESS);
4831 result = ISC_R_FAILURE;
4832 cleanup:
4833 dns_rdataset_disassociate(&mysigrdataset);
4835 return (result);
4839 isc_result_t
4840 initialization(dns_name_t *name)
4842 isc_result_t result;
4843 isc_boolean_t true = ISC_TRUE;
4845 chase_nsrdataset = NULL;
4846 result = advanced_rrsearch(&chase_nsrdataset, name, dns_rdatatype_ns,
4847 dns_rdatatype_any, &true);
4848 if (result != ISC_R_SUCCESS) {
4849 printf("\n;; NS RRset is missing to continue validation:"
4850 " FAILED\n\n");
4851 return (ISC_R_FAILURE);
4853 INSIST(chase_nsrdataset != NULL);
4854 prepare_lookup(name);
4856 dup_name(name, &chase_current_name, mctx);
4858 return (ISC_R_SUCCESS);
4860 #endif
4862 void
4863 print_rdataset(dns_name_t *name, dns_rdataset_t *rdataset, isc_mem_t *mctx)
4865 isc_buffer_t *b = NULL;
4866 isc_result_t result;
4867 isc_region_t r;
4869 result = isc_buffer_allocate(mctx, &b, 9000);
4870 check_result(result, "isc_buffer_allocate");
4872 printrdataset(name, rdataset, b);
4874 isc_buffer_usedregion(b, &r);
4875 r.base[r.length] = '\0';
4878 printf("%s\n", r.base);
4880 isc_buffer_free(&b);
4884 void
4885 dup_name(dns_name_t *source, dns_name_t *target, isc_mem_t *mctx) {
4886 isc_result_t result;
4888 if (dns_name_dynamic(target))
4889 free_name(target, mctx);
4890 result = dns_name_dup(source, mctx, target);
4891 check_result(result, "dns_name_dup");
4894 void
4895 free_name(dns_name_t *name, isc_mem_t *mctx) {
4896 dns_name_free(name, mctx);
4897 dns_name_init(name, NULL);
4902 * take a DNSKEY RRset and the RRSIG RRset corresponding in parameter
4903 * return ISC_R_SUCCESS if the DNSKEY RRset contains a trusted_key
4904 * and the RRset is valid
4905 * return ISC_R_NOTFOUND if not contains trusted key
4906 or if the RRset isn't valid
4907 * return ISC_R_FAILURE if problem
4910 isc_result_t
4911 contains_trusted_key(dns_name_t *name, dns_rdataset_t *rdataset,
4912 dns_rdataset_t *sigrdataset,
4913 isc_mem_t *mctx)
4915 dns_rdataset_t myrdataset;
4916 dst_key_t *dnsseckey = NULL;
4917 int i;
4918 isc_result_t result;
4920 if (name == NULL || rdataset == NULL)
4921 return (ISC_R_FAILURE);
4923 dns_rdataset_init(&myrdataset);
4924 dns_rdataset_clone(rdataset, &myrdataset);
4926 result = dns_rdataset_first(&myrdataset);
4927 check_result(result, "empty rdataset");
4929 do {
4930 dns_rdata_t rdata = DNS_RDATA_INIT;
4932 dns_rdataset_current(&myrdataset, &rdata);
4933 INSIST(rdata.type == dns_rdatatype_dnskey);
4935 result = dns_dnssec_keyfromrdata(name, &rdata,
4936 mctx, &dnsseckey);
4937 check_result(result, "dns_dnssec_keyfromrdata");
4939 for (i = 0; i < tk_list.nb_tk; i++) {
4940 if (dst_key_compare(tk_list.key[i], dnsseckey)
4941 == ISC_TRUE) {
4942 dns_rdata_reset(&rdata);
4944 printf(";; Ok, find a Trusted Key in the "
4945 "DNSKEY RRset: %d\n",
4946 dst_key_id(dnsseckey));
4947 result = sigchase_verify_sig_key(name, rdataset,
4948 dnsseckey,
4949 sigrdataset,
4950 mctx);
4951 if (result == ISC_R_SUCCESS)
4952 goto cleanup;
4955 dst_key_free(&dnsseckey);
4956 } while (dns_rdataset_next(&myrdataset) == ISC_R_SUCCESS);
4958 cleanup:
4959 if (dnsseckey != NULL)
4960 dst_key_free(&dnsseckey);
4961 dns_rdataset_disassociate(&myrdataset);
4963 return (ISC_R_NOTFOUND);
4966 isc_result_t
4967 sigchase_verify_sig(dns_name_t *name, dns_rdataset_t *rdataset,
4968 dns_rdataset_t *keyrdataset,
4969 dns_rdataset_t *sigrdataset,
4970 isc_mem_t *mctx)
4972 dns_rdataset_t mykeyrdataset;
4973 dst_key_t *dnsseckey = NULL;
4974 isc_result_t result;
4976 dns_rdataset_init(&mykeyrdataset);
4977 dns_rdataset_clone(keyrdataset, &mykeyrdataset);
4979 result = dns_rdataset_first(&mykeyrdataset);
4980 check_result(result, "empty DNSKEY dataset");
4982 do {
4983 dns_rdata_t keyrdata = DNS_RDATA_INIT;
4985 dns_rdataset_current(&mykeyrdataset, &keyrdata);
4986 INSIST(keyrdata.type == dns_rdatatype_dnskey);
4988 result = dns_dnssec_keyfromrdata(name, &keyrdata,
4989 mctx, &dnsseckey);
4990 check_result(result, "dns_dnssec_keyfromrdata");
4992 result = sigchase_verify_sig_key(name, rdataset, dnsseckey,
4993 sigrdataset, mctx);
4994 if (result == ISC_R_SUCCESS)
4995 goto cleanup;
4996 dst_key_free(&dnsseckey);
4997 } while (dns_rdataset_next(&mykeyrdataset) == ISC_R_SUCCESS);
4999 result = ISC_R_NOTFOUND;
5001 cleanup:
5002 if (dnsseckey != NULL)
5003 dst_key_free(&dnsseckey);
5004 dns_rdataset_disassociate(&mykeyrdataset);
5006 return (result);
5009 isc_result_t
5010 sigchase_verify_sig_key(dns_name_t *name, dns_rdataset_t *rdataset,
5011 dst_key_t *dnsseckey, dns_rdataset_t *sigrdataset,
5012 isc_mem_t *mctx)
5014 dns_rdata_sig_t siginfo;
5015 dns_rdataset_t myrdataset;
5016 dns_rdataset_t mysigrdataset;
5017 isc_result_t result;
5019 dns_rdataset_init(&myrdataset);
5020 dns_rdataset_clone(rdataset, &myrdataset);
5021 dns_rdataset_init(&mysigrdataset);
5022 dns_rdataset_clone(sigrdataset, &mysigrdataset);
5024 result = dns_rdataset_first(&mysigrdataset);
5025 check_result(result, "empty RRSIG dataset");
5027 do {
5028 dns_rdata_t sigrdata = DNS_RDATA_INIT;
5030 dns_rdataset_current(&mysigrdataset, &sigrdata);
5032 result = dns_rdata_tostruct(&sigrdata, &siginfo, NULL);
5033 check_result(result, "sigrdata tostruct siginfo");
5036 * Test if the id of the DNSKEY is
5037 * the id of the DNSKEY signer's
5039 if (siginfo.keyid == dst_key_id(dnsseckey)) {
5041 result = dns_rdataset_first(&myrdataset);
5042 check_result(result, "empty DS dataset");
5044 result = dns_dnssec_verify(name, &myrdataset, dnsseckey,
5045 ISC_FALSE, mctx, &sigrdata);
5047 printf(";; VERIFYING ");
5048 print_type(rdataset->type);
5049 printf(" RRset for ");
5050 dns_name_print(name, stdout);
5051 printf(" with DNSKEY:%d: %s\n", dst_key_id(dnsseckey),
5052 isc_result_totext(result));
5054 if (result == ISC_R_SUCCESS)
5055 goto cleanup;
5057 } while (dns_rdataset_next(&mysigrdataset) == ISC_R_SUCCESS);
5059 result = ISC_R_NOTFOUND;
5061 cleanup:
5062 dns_rdataset_disassociate(&myrdataset);
5063 dns_rdataset_disassociate(&mysigrdataset);
5065 return (result);
5069 isc_result_t
5070 sigchase_verify_ds(dns_name_t *name, dns_rdataset_t *keyrdataset,
5071 dns_rdataset_t *dsrdataset, isc_mem_t *mctx)
5073 dns_rdata_ds_t dsinfo;
5074 dns_rdataset_t mydsrdataset;
5075 dns_rdataset_t mykeyrdataset;
5076 dst_key_t *dnsseckey = NULL;
5077 isc_result_t result;
5078 unsigned char dsbuf[DNS_DS_BUFFERSIZE];
5080 dns_rdataset_init(&mydsrdataset);
5081 dns_rdataset_clone(dsrdataset, &mydsrdataset);
5082 dns_rdataset_init(&mykeyrdataset);
5083 dns_rdataset_clone(keyrdataset, &mykeyrdataset);
5085 result = dns_rdataset_first(&mydsrdataset);
5086 check_result(result, "empty DSset dataset");
5087 do {
5088 dns_rdata_t dsrdata = DNS_RDATA_INIT;
5090 dns_rdataset_current(&mydsrdataset, &dsrdata);
5092 result = dns_rdata_tostruct(&dsrdata, &dsinfo, NULL);
5093 check_result(result, "dns_rdata_tostruct for DS");
5095 result = dns_rdataset_first(&mykeyrdataset);
5096 check_result(result, "empty KEY dataset");
5098 do {
5099 dns_rdata_t keyrdata = DNS_RDATA_INIT;
5101 dns_rdataset_current(&mykeyrdataset, &keyrdata);
5102 INSIST(keyrdata.type == dns_rdatatype_dnskey);
5104 result = dns_dnssec_keyfromrdata(name, &keyrdata,
5105 mctx, &dnsseckey);
5106 check_result(result, "dns_dnssec_keyfromrdata");
5109 * Test if the id of the DNSKEY is the
5110 * id of DNSKEY referenced by the DS
5112 if (dsinfo.key_tag == dst_key_id(dnsseckey)) {
5113 dns_rdata_t newdsrdata = DNS_RDATA_INIT;
5115 result = dns_ds_buildrdata(name, &keyrdata,
5116 dsinfo.digest_type,
5117 dsbuf, &newdsrdata);
5118 dns_rdata_freestruct(&dsinfo);
5120 if (result != ISC_R_SUCCESS) {
5121 printf("Oops: impossible to build"
5122 " new DS rdata\n");
5123 goto cleanup;
5127 if (dns_rdata_compare(&dsrdata,
5128 &newdsrdata) == 0) {
5129 printf(";; OK a DS valids a DNSKEY"
5130 " in the RRset\n");
5131 printf(";; Now verify that this"
5132 " DNSKEY validates the "
5133 "DNSKEY RRset\n");
5135 result = sigchase_verify_sig_key(name,
5136 keyrdataset,
5137 dnsseckey,
5138 chase_sigkeyrdataset,
5139 mctx);
5140 if (result == ISC_R_SUCCESS)
5141 goto cleanup;
5142 } else {
5143 printf(";; This DS is NOT the DS for"
5144 " the chasing KEY: FAILED\n");
5147 dst_key_free(&dnsseckey);
5148 } while (dns_rdataset_next(&mykeyrdataset) == ISC_R_SUCCESS);
5149 } while (dns_rdataset_next(&mydsrdataset) == ISC_R_SUCCESS);
5151 result = ISC_R_NOTFOUND;
5153 cleanup:
5154 if (dnsseckey != NULL)
5155 dst_key_free(&dnsseckey);
5156 dns_rdataset_disassociate(&mydsrdataset);
5157 dns_rdataset_disassociate(&mykeyrdataset);
5159 return (result);
5164 * take a pointer on a rdataset in parameter and try to resolv it.
5165 * the searched rrset is a rrset on 'name' with type 'type'
5166 * (and if the type is a rrsig the signature cover 'covers').
5167 * the lookedup is to known if you have already done the query on the net.
5168 * ISC_R_SUCCESS: if we found the rrset
5169 * ISC_R_NOTFOUND: we do not found the rrset in cache
5170 * and we do a query on the net
5171 * ISC_R_FAILURE: rrset not found
5173 isc_result_t
5174 advanced_rrsearch(dns_rdataset_t **rdataset, dns_name_t *name,
5175 dns_rdatatype_t type, dns_rdatatype_t covers,
5176 isc_boolean_t *lookedup)
5178 isc_boolean_t tmplookedup;
5180 INSIST(rdataset != NULL);
5182 if (*rdataset != NULL)
5183 return (ISC_R_SUCCESS);
5185 tmplookedup = *lookedup;
5186 if ((*rdataset = sigchase_scanname(type, covers,
5187 lookedup, name)) == NULL) {
5188 if (tmplookedup)
5189 return (ISC_R_FAILURE);
5190 return (ISC_R_NOTFOUND);
5192 *lookedup = ISC_FALSE;
5193 return (ISC_R_SUCCESS);
5198 #if DIG_SIGCHASE_TD
5199 void
5200 sigchase_td(dns_message_t *msg)
5202 isc_result_t result;
5203 dns_name_t *name = NULL;
5204 isc_boolean_t have_answer = ISC_FALSE;
5205 isc_boolean_t true = ISC_TRUE;
5207 if (msg->rcode != dns_rcode_noerror &&
5208 msg->rcode != dns_rcode_nxdomain) {
5209 char buf[20];
5210 isc_buffer_t b;
5212 isc_buffer_init(&b, buf, sizeof(buf));
5213 result = dns_rcode_totext(msg->rcode, &b);
5214 check_result(result, "dns_rcode_totext failed");
5215 printf("error response code %.*s\n",
5216 (int)isc_buffer_usedlength(&b), buf);
5217 error_message = msg;
5218 return;
5221 if ((result = dns_message_firstname(msg, DNS_SECTION_ANSWER))
5222 == ISC_R_SUCCESS) {
5223 dns_message_currentname(msg, DNS_SECTION_ANSWER, &name);
5224 if (current_lookup->trace_root_sigchase) {
5225 initialization(name);
5226 return;
5228 have_answer = true;
5229 } else {
5230 if (!current_lookup->trace_root_sigchase) {
5231 result = dns_message_firstname(msg,
5232 DNS_SECTION_AUTHORITY);
5233 if (result != ISC_R_SUCCESS) {
5234 printf("no answer or authority section\n");
5235 error_message = msg;
5236 return;
5238 dns_message_currentname(msg, DNS_SECTION_AUTHORITY,
5239 &name);
5240 chase_nsrdataset
5241 = chase_scanname_section(msg, name,
5242 dns_rdatatype_ns,
5243 dns_rdatatype_any,
5244 DNS_SECTION_AUTHORITY);
5245 dup_name(name, &chase_authority_name, mctx);
5246 if (chase_nsrdataset != NULL) {
5247 have_delegation_ns = ISC_TRUE;
5248 printf("no response but there is a delegation"
5249 " in authority section: ");
5250 dns_name_print(name, stdout);
5251 printf("\n");
5252 } else {
5253 printf("no response and no delegation in "
5254 "authority section but a reference"
5255 " to: ");
5256 dns_name_print(name, stdout);
5257 printf("\n");
5258 error_message = msg;
5260 } else {
5261 printf(";; NO ANSWERS: %s\n",
5262 isc_result_totext(result));
5263 free_name(&chase_name, mctx);
5264 clean_trustedkey();
5265 return;
5270 if (have_answer) {
5271 chase_rdataset
5272 = chase_scanname_section(msg, &chase_name,
5273 current_lookup
5274 ->rdtype_sigchase,
5275 dns_rdatatype_any,
5276 DNS_SECTION_ANSWER);
5277 if (chase_rdataset != NULL)
5278 have_response = ISC_TRUE;
5281 result = advanced_rrsearch(&chase_keyrdataset,
5282 &chase_current_name,
5283 dns_rdatatype_dnskey,
5284 dns_rdatatype_any,
5285 &chase_keylookedup);
5286 if (result == ISC_R_FAILURE) {
5287 printf("\n;; DNSKEY is missing to continue validation:"
5288 " FAILED\n\n");
5289 goto cleanandgo;
5291 if (result == ISC_R_NOTFOUND)
5292 return;
5293 INSIST(chase_keyrdataset != NULL);
5294 printf("\n;; DNSKEYset:\n");
5295 print_rdataset(&chase_current_name , chase_keyrdataset, mctx);
5298 result = advanced_rrsearch(&chase_sigkeyrdataset,
5299 &chase_current_name,
5300 dns_rdatatype_rrsig,
5301 dns_rdatatype_dnskey,
5302 &chase_sigkeylookedup);
5303 if (result == ISC_R_FAILURE) {
5304 printf("\n;; RRSIG of DNSKEY is missing to continue validation:"
5305 " FAILED\n\n");
5306 goto cleanandgo;
5308 if (result == ISC_R_NOTFOUND)
5309 return;
5310 INSIST(chase_sigkeyrdataset != NULL);
5311 printf("\n;; RRSIG of the DNSKEYset:\n");
5312 print_rdataset(&chase_current_name , chase_sigkeyrdataset, mctx);
5315 if (!chase_dslookedup && !chase_nslookedup) {
5316 if (!delegation_follow) {
5317 result = contains_trusted_key(&chase_current_name,
5318 chase_keyrdataset,
5319 chase_sigkeyrdataset,
5320 mctx);
5321 } else {
5322 INSIST(chase_dsrdataset != NULL);
5323 INSIST(chase_sigdsrdataset != NULL);
5324 result = sigchase_verify_ds(&chase_current_name,
5325 chase_keyrdataset,
5326 chase_dsrdataset,
5327 mctx);
5330 if (result != ISC_R_SUCCESS) {
5331 printf("\n;; chain of trust can't be validated:"
5332 " FAILED\n\n");
5333 goto cleanandgo;
5334 } else {
5335 chase_dsrdataset = NULL;
5336 chase_sigdsrdataset = NULL;
5340 if (have_response || (!have_delegation_ns && !have_response)) {
5341 /* test if it's a grand father case */
5343 if (have_response) {
5344 result = advanced_rrsearch(&chase_sigrdataset,
5345 &chase_name,
5346 dns_rdatatype_rrsig,
5347 current_lookup
5348 ->rdtype_sigchase,
5349 &true);
5350 if (result == ISC_R_FAILURE) {
5351 printf("\n;; RRset is missing to continue"
5352 " validation SHOULD NOT APPEND:"
5353 " FAILED\n\n");
5354 goto cleanandgo;
5357 } else {
5358 result = advanced_rrsearch(&chase_sigrdataset,
5359 &chase_authority_name,
5360 dns_rdatatype_rrsig,
5361 dns_rdatatype_any,
5362 &true);
5363 if (result == ISC_R_FAILURE) {
5364 printf("\n;; RRSIG is missing to continue"
5365 " validation SHOULD NOT APPEND:"
5366 " FAILED\n\n");
5367 goto cleanandgo;
5370 result = grandfather_pb_test(&chase_current_name,
5371 chase_sigrdataset);
5372 if (result != ISC_R_SUCCESS) {
5373 dns_name_t tmp_name;
5375 printf("\n;; We are in a Grand Father Problem:"
5376 " See 2.2.1 in RFC 3658\n");
5377 chase_rdataset = NULL;
5378 chase_sigrdataset = NULL;
5379 have_response = ISC_FALSE;
5380 have_delegation_ns = ISC_FALSE;
5382 dns_name_init(&tmp_name, NULL);
5383 result = child_of_zone(&chase_name, &chase_current_name,
5384 &tmp_name);
5385 if (dns_name_dynamic(&chase_authority_name))
5386 free_name(&chase_authority_name, mctx);
5387 dup_name(&tmp_name, &chase_authority_name, mctx);
5388 printf(";; and we try to continue chain of trust"
5389 " validation of the zone: ");
5390 dns_name_print(&chase_authority_name, stdout);
5391 printf("\n");
5392 have_delegation_ns = ISC_TRUE;
5393 } else {
5394 if (have_response)
5395 goto finalstep;
5396 else
5397 chase_sigrdataset = NULL;
5401 if (have_delegation_ns) {
5402 chase_nsrdataset = NULL;
5403 result = advanced_rrsearch(&chase_nsrdataset,
5404 &chase_authority_name,
5405 dns_rdatatype_ns,
5406 dns_rdatatype_any,
5407 &chase_nslookedup);
5408 if (result == ISC_R_FAILURE) {
5409 printf("\n;;NSset is missing to continue validation:"
5410 " FAILED\n\n");
5411 goto cleanandgo;
5413 if (result == ISC_R_NOTFOUND) {
5414 return;
5416 INSIST(chase_nsrdataset != NULL);
5418 result = advanced_rrsearch(&chase_dsrdataset,
5419 &chase_authority_name,
5420 dns_rdatatype_ds,
5421 dns_rdatatype_any,
5422 &chase_dslookedup);
5423 if (result == ISC_R_FAILURE) {
5424 printf("\n;; DSset is missing to continue validation:"
5425 " FAILED\n\n");
5426 goto cleanandgo;
5428 if (result == ISC_R_NOTFOUND)
5429 return;
5430 INSIST(chase_dsrdataset != NULL);
5431 printf("\n;; DSset:\n");
5432 print_rdataset(&chase_authority_name , chase_dsrdataset, mctx);
5434 result = advanced_rrsearch(&chase_sigdsrdataset,
5435 &chase_authority_name,
5436 dns_rdatatype_rrsig,
5437 dns_rdatatype_ds,
5438 &true);
5439 if (result != ISC_R_SUCCESS) {
5440 printf("\n;; DSset is missing to continue validation:"
5441 " FAILED\n\n");
5442 goto cleanandgo;
5444 printf("\n;; RRSIGset of DSset\n");
5445 print_rdataset(&chase_authority_name,
5446 chase_sigdsrdataset, mctx);
5447 INSIST(chase_sigdsrdataset != NULL);
5449 result = sigchase_verify_sig(&chase_authority_name,
5450 chase_dsrdataset,
5451 chase_keyrdataset,
5452 chase_sigdsrdataset, mctx);
5453 if (result != ISC_R_SUCCESS) {
5454 printf("\n;; Impossible to verify the DSset:"
5455 " FAILED\n\n");
5456 goto cleanandgo;
5458 chase_keyrdataset = NULL;
5459 chase_sigkeyrdataset = NULL;
5462 prepare_lookup(&chase_authority_name);
5464 have_response = ISC_FALSE;
5465 have_delegation_ns = ISC_FALSE;
5466 delegation_follow = ISC_TRUE;
5467 error_message = NULL;
5468 dup_name(&chase_authority_name, &chase_current_name, mctx);
5469 free_name(&chase_authority_name, mctx);
5470 return;
5474 if (error_message != NULL) {
5475 dns_rdataset_t *rdataset;
5476 dns_rdataset_t *sigrdataset;
5477 dns_name_t rdata_name;
5478 isc_result_t ret = ISC_R_FAILURE;
5480 dns_name_init(&rdata_name, NULL);
5481 result = prove_nx(error_message, &chase_name,
5482 current_lookup->rdclass_sigchase,
5483 current_lookup->rdtype_sigchase, &rdata_name,
5484 &rdataset, &sigrdataset);
5485 if (rdataset == NULL || sigrdataset == NULL ||
5486 dns_name_countlabels(&rdata_name) == 0) {
5487 printf("\n;; Impossible to verify the non-existence,"
5488 " the NSEC RRset can't be validated:"
5489 " FAILED\n\n");
5490 goto cleanandgo;
5492 ret = sigchase_verify_sig(&rdata_name, rdataset,
5493 chase_keyrdataset,
5494 sigrdataset, mctx);
5495 if (ret != ISC_R_SUCCESS) {
5496 free_name(&rdata_name, mctx);
5497 printf("\n;; Impossible to verify the NSEC RR to prove"
5498 " the non-existence : FAILED\n\n");
5499 goto cleanandgo;
5501 free_name(&rdata_name, mctx);
5502 if (result != ISC_R_SUCCESS) {
5503 printf("\n;; Impossible to verify the non-existence:"
5504 " FAILED\n\n");
5505 goto cleanandgo;
5506 } else {
5507 printf("\n;; OK the query doesn't have response but"
5508 " we have validate this fact : SUCCESS\n\n");
5509 goto cleanandgo;
5513 cleanandgo:
5514 printf(";; cleanandgo \n");
5515 if (dns_name_dynamic(&chase_current_name))
5516 free_name(&chase_current_name, mctx);
5517 if (dns_name_dynamic(&chase_authority_name))
5518 free_name(&chase_authority_name, mctx);
5519 clean_trustedkey();
5520 return;
5522 finalstep :
5523 result = advanced_rrsearch(&chase_rdataset, &chase_name,
5524 current_lookup->rdtype_sigchase,
5525 dns_rdatatype_any ,
5526 &true);
5527 if (result == ISC_R_FAILURE) {
5528 printf("\n;; RRsig of RRset is missing to continue validation"
5529 " SHOULD NOT APPEND: FAILED\n\n");
5530 goto cleanandgo;
5532 result = sigchase_verify_sig(&chase_name, chase_rdataset,
5533 chase_keyrdataset,
5534 chase_sigrdataset, mctx);
5535 if (result != ISC_R_SUCCESS) {
5536 printf("\n;; Impossible to verify the RRset : FAILED\n\n");
5538 printf("RRset:\n");
5539 print_rdataset(&chase_name , chase_rdataset, mctx);
5540 printf("DNSKEYset:\n");
5541 print_rdataset(&chase_name , chase_keyrdataset, mctx);
5542 printf("RRSIG of RRset:\n");
5543 print_rdataset(&chase_name , chase_sigrdataset, mctx);
5544 printf("\n");
5546 goto cleanandgo;
5547 } else {
5548 printf("\n;; The Answer:\n");
5549 print_rdataset(&chase_name , chase_rdataset, mctx);
5551 printf("\n;; FINISH : we have validate the DNSSEC chain"
5552 " of trust: SUCCESS\n\n");
5553 goto cleanandgo;
5557 #endif
5560 #if DIG_SIGCHASE_BU
5562 isc_result_t
5563 getneededrr(dns_message_t *msg)
5565 isc_result_t result;
5566 dns_name_t *name = NULL;
5567 dns_rdata_t sigrdata = DNS_RDATA_INIT;
5568 dns_rdata_sig_t siginfo;
5569 isc_boolean_t true = ISC_TRUE;
5571 if ((result = dns_message_firstname(msg, DNS_SECTION_ANSWER))
5572 != ISC_R_SUCCESS) {
5573 printf(";; NO ANSWERS: %s\n", isc_result_totext(result));
5575 if (chase_name.ndata == NULL)
5576 return (ISC_R_ADDRNOTAVAIL);
5577 } else {
5578 dns_message_currentname(msg, DNS_SECTION_ANSWER, &name);
5581 /* What do we chase? */
5582 if (chase_rdataset == NULL) {
5583 result = advanced_rrsearch(&chase_rdataset, name,
5584 dns_rdatatype_any,
5585 dns_rdatatype_any, &true);
5586 if (result != ISC_R_SUCCESS) {
5587 printf("\n;; No Answers: Validation FAILED\n\n");
5588 return (ISC_R_NOTFOUND);
5590 dup_name(name, &chase_name, mctx);
5591 printf(";; RRset to chase:\n");
5592 print_rdataset(&chase_name, chase_rdataset, mctx);
5594 INSIST(chase_rdataset != NULL);
5597 if (chase_sigrdataset == NULL) {
5598 result = advanced_rrsearch(&chase_sigrdataset, name,
5599 dns_rdatatype_rrsig,
5600 chase_rdataset->type,
5601 &chase_siglookedup);
5602 if (result == ISC_R_FAILURE) {
5603 printf("\n;; RRSIG is missing for continue validation:"
5604 " FAILED\n\n");
5605 if (dns_name_dynamic(&chase_name))
5606 free_name(&chase_name, mctx);
5607 return (ISC_R_NOTFOUND);
5609 if (result == ISC_R_NOTFOUND) {
5610 return (ISC_R_NOTFOUND);
5612 printf("\n;; RRSIG of the RRset to chase:\n");
5613 print_rdataset(&chase_name, chase_sigrdataset, mctx);
5615 INSIST(chase_sigrdataset != NULL);
5618 /* first find the DNSKEY name */
5619 result = dns_rdataset_first(chase_sigrdataset);
5620 check_result(result, "empty RRSIG dataset");
5621 dns_rdataset_current(chase_sigrdataset, &sigrdata);
5622 result = dns_rdata_tostruct(&sigrdata, &siginfo, NULL);
5623 check_result(result, "sigrdata tostruct siginfo");
5624 dup_name(&siginfo.signer, &chase_signame, mctx);
5625 dns_rdata_freestruct(&siginfo);
5626 dns_rdata_reset(&sigrdata);
5628 /* Do we have a key? */
5629 if (chase_keyrdataset == NULL) {
5630 result = advanced_rrsearch(&chase_keyrdataset,
5631 &chase_signame,
5632 dns_rdatatype_dnskey,
5633 dns_rdatatype_any,
5634 &chase_keylookedup);
5635 if (result == ISC_R_FAILURE) {
5636 printf("\n;; DNSKEY is missing to continue validation:"
5637 " FAILED\n\n");
5638 free_name(&chase_signame, mctx);
5639 if (dns_name_dynamic(&chase_name))
5640 free_name(&chase_name, mctx);
5641 return (ISC_R_NOTFOUND);
5643 if (result == ISC_R_NOTFOUND) {
5644 free_name(&chase_signame, mctx);
5645 return (ISC_R_NOTFOUND);
5647 printf("\n;; DNSKEYset that signs the RRset to chase:\n");
5648 print_rdataset(&chase_signame, chase_keyrdataset, mctx);
5650 INSIST(chase_keyrdataset != NULL);
5652 if (chase_sigkeyrdataset == NULL) {
5653 result = advanced_rrsearch(&chase_sigkeyrdataset,
5654 &chase_signame,
5655 dns_rdatatype_rrsig,
5656 dns_rdatatype_dnskey,
5657 &chase_sigkeylookedup);
5658 if (result == ISC_R_FAILURE) {
5659 printf("\n;; RRSIG for DNSKEY is missing to continue"
5660 " validation : FAILED\n\n");
5661 free_name(&chase_signame, mctx);
5662 if (dns_name_dynamic(&chase_name))
5663 free_name(&chase_name, mctx);
5664 return (ISC_R_NOTFOUND);
5666 if (result == ISC_R_NOTFOUND) {
5667 free_name(&chase_signame, mctx);
5668 return (ISC_R_NOTFOUND);
5670 printf("\n;; RRSIG of the DNSKEYset that signs the "
5671 "RRset to chase:\n");
5672 print_rdataset(&chase_signame, chase_sigkeyrdataset, mctx);
5674 INSIST(chase_sigkeyrdataset != NULL);
5677 if (chase_dsrdataset == NULL) {
5678 result = advanced_rrsearch(&chase_dsrdataset, &chase_signame,
5679 dns_rdatatype_ds, dns_rdatatype_any,
5680 &chase_dslookedup);
5681 if (result == ISC_R_FAILURE) {
5682 printf("\n;; WARNING There is no DS for the zone: ");
5683 dns_name_print(&chase_signame, stdout);
5684 printf("\n");
5686 if (result == ISC_R_NOTFOUND) {
5687 free_name(&chase_signame, mctx);
5688 return (ISC_R_NOTFOUND);
5690 if (chase_dsrdataset != NULL) {
5691 printf("\n;; DSset of the DNSKEYset\n");
5692 print_rdataset(&chase_signame, chase_dsrdataset, mctx);
5696 if (chase_dsrdataset != NULL) {
5698 * if there is no RRSIG of DS,
5699 * we don't want to search on the network
5701 result = advanced_rrsearch(&chase_sigdsrdataset,
5702 &chase_signame,
5703 dns_rdatatype_rrsig,
5704 dns_rdatatype_ds, &true);
5705 if (result == ISC_R_FAILURE) {
5706 printf(";; WARNING : NO RRSIG DS : RRSIG DS"
5707 " should come with DS\n");
5709 * We continue even the DS couldn't be validated,
5710 * because the DNSKEY could be a Trusted Key.
5712 chase_dsrdataset = NULL;
5713 } else {
5714 printf("\n;; RRSIG of the DSset of the DNSKEYset\n");
5715 print_rdataset(&chase_signame, chase_sigdsrdataset,
5716 mctx);
5719 return (1);
5724 void
5725 sigchase_bu(dns_message_t *msg)
5727 isc_result_t result;
5728 int ret;
5730 if (tk_list.nb_tk == 0) {
5731 result = get_trusted_key(mctx);
5732 if (result != ISC_R_SUCCESS) {
5733 printf("No trusted keys present\n");
5734 return;
5739 ret = getneededrr(msg);
5740 if (ret == ISC_R_NOTFOUND)
5741 return;
5743 if (ret == ISC_R_ADDRNOTAVAIL) {
5744 /* We have no response */
5745 dns_rdataset_t *rdataset;
5746 dns_rdataset_t *sigrdataset;
5747 dns_name_t rdata_name;
5748 dns_name_t query_name;
5751 dns_name_init(&query_name, NULL);
5752 dns_name_init(&rdata_name, NULL);
5753 nameFromString(current_lookup->textname, &query_name);
5755 result = prove_nx(msg, &query_name, current_lookup->rdclass,
5756 current_lookup->rdtype, &rdata_name,
5757 &rdataset, &sigrdataset);
5758 free_name(&query_name, mctx);
5759 if (rdataset == NULL || sigrdataset == NULL ||
5760 dns_name_countlabels(&rdata_name) == 0) {
5761 printf("\n;; Impossible to verify the Non-existence,"
5762 " the NSEC RRset can't be validated: "
5763 "FAILED\n\n");
5764 clean_trustedkey();
5765 return;
5768 if (result != ISC_R_SUCCESS) {
5769 printf("\n No Answers and impossible to prove the"
5770 " unsecurity : Validation FAILED\n\n");
5771 clean_trustedkey();
5772 return;
5774 printf(";; An NSEC prove the non-existence of a answers,"
5775 " Now we want validate this NSEC\n");
5777 dup_name(&rdata_name, &chase_name, mctx);
5778 free_name(&rdata_name, mctx);
5779 chase_rdataset = rdataset;
5780 chase_sigrdataset = sigrdataset;
5781 chase_keyrdataset = NULL;
5782 chase_sigkeyrdataset = NULL;
5783 chase_dsrdataset = NULL;
5784 chase_sigdsrdataset = NULL;
5785 chase_siglookedup = ISC_FALSE;
5786 chase_keylookedup = ISC_FALSE;
5787 chase_dslookedup = ISC_FALSE;
5788 chase_sigdslookedup = ISC_FALSE;
5789 sigchase(msg);
5790 clean_trustedkey();
5791 return;
5795 printf("\n\n\n;; WE HAVE MATERIAL, WE NOW DO VALIDATION\n");
5797 result = sigchase_verify_sig(&chase_name, chase_rdataset,
5798 chase_keyrdataset,
5799 chase_sigrdataset, mctx);
5800 if (result != ISC_R_SUCCESS) {
5801 free_name(&chase_name, mctx);
5802 free_name(&chase_signame, mctx);
5803 printf(";; No DNSKEY is valid to check the RRSIG"
5804 " of the RRset: FAILED\n");
5805 clean_trustedkey();
5806 return;
5808 printf(";; OK We found DNSKEY (or more) to validate the RRset\n");
5810 result = contains_trusted_key(&chase_signame, chase_keyrdataset,
5811 chase_sigkeyrdataset, mctx);
5812 if (result == ISC_R_SUCCESS) {
5813 free_name(&chase_name, mctx);
5814 free_name(&chase_signame, mctx);
5815 printf("\n;; Ok this DNSKEY is a Trusted Key,"
5816 " DNSSEC validation is ok: SUCCESS\n\n");
5817 clean_trustedkey();
5818 return;
5821 printf(";; Now, we are going to validate this DNSKEY by the DS\n");
5823 if (chase_dsrdataset == NULL) {
5824 free_name(&chase_name, mctx);
5825 free_name(&chase_signame, mctx);
5826 printf(";; the DNSKEY isn't trusted-key and there isn't"
5827 " DS to validate the DNSKEY: FAILED\n");
5828 clean_trustedkey();
5829 return;
5832 result = sigchase_verify_ds(&chase_signame, chase_keyrdataset,
5833 chase_dsrdataset, mctx);
5834 if (result != ISC_R_SUCCESS) {
5835 free_name(&chase_signame, mctx);
5836 free_name(&chase_name, mctx);
5837 printf(";; ERROR no DS validates a DNSKEY in the"
5838 " DNSKEY RRset: FAILED\n");
5839 clean_trustedkey();
5840 return;
5841 } else
5842 printf(";; OK this DNSKEY (validated by the DS) validates"
5843 " the RRset of the DNSKEYs, thus the DNSKEY validates"
5844 " the RRset\n");
5845 INSIST(chase_sigdsrdataset != NULL);
5847 dup_name(&chase_signame, &chase_name, mctx);
5848 free_name(&chase_signame, mctx);
5849 chase_rdataset = chase_dsrdataset;
5850 chase_sigrdataset = chase_sigdsrdataset;
5851 chase_keyrdataset = NULL;
5852 chase_sigkeyrdataset = NULL;
5853 chase_dsrdataset = NULL;
5854 chase_sigdsrdataset = NULL;
5855 chase_siglookedup = chase_keylookedup = ISC_FALSE;
5856 chase_dslookedup = chase_sigdslookedup = ISC_FALSE;
5858 printf(";; Now, we want to validate the DS : recursive call\n");
5859 sigchase(msg);
5860 return;
5862 #endif
5864 void
5865 sigchase(dns_message_t *msg) {
5866 #if DIG_SIGCHASE_TD
5867 if (current_lookup->do_topdown) {
5868 sigchase_td(msg);
5869 return;
5871 #endif
5872 #if DIG_SIGCHASE_BU
5873 sigchase_bu(msg);
5874 return;
5875 #endif
5880 * return 1 if name1 < name2
5881 * 0 if name1 == name2
5882 * -1 if name1 > name2
5883 * and -2 if problem
5886 inf_name(dns_name_t *name1, dns_name_t *name2)
5888 dns_label_t label1;
5889 dns_label_t label2;
5890 unsigned int nblabel1;
5891 unsigned int nblabel2;
5892 int min_lum_label;
5893 int i;
5894 int ret = -2;
5896 nblabel1 = dns_name_countlabels(name1);
5897 nblabel2 = dns_name_countlabels(name2);
5899 if (nblabel1 >= nblabel2)
5900 min_lum_label = nblabel2;
5901 else
5902 min_lum_label = nblabel1;
5905 for (i=1 ; i < min_lum_label; i++) {
5906 dns_name_getlabel(name1, nblabel1 -1 - i, &label1);
5907 dns_name_getlabel(name2, nblabel2 -1 - i, &label2);
5908 if ((ret = isc_region_compare(&label1, &label2)) != 0) {
5909 if (ret < 0)
5910 return (-1);
5911 else if (ret > 0)
5912 return (1);
5915 if (nblabel1 == nblabel2)
5916 return (0);
5918 if (nblabel1 < nblabel2)
5919 return (-1);
5920 else
5921 return (1);
5929 isc_result_t
5930 prove_nx_domain(dns_message_t *msg,
5931 dns_name_t *name,
5932 dns_name_t *rdata_name,
5933 dns_rdataset_t **rdataset,
5934 dns_rdataset_t **sigrdataset)
5936 isc_result_t ret = ISC_R_FAILURE;
5937 isc_result_t result = ISC_R_NOTFOUND;
5938 dns_rdataset_t *nsecset = NULL;
5939 dns_rdataset_t *signsecset = NULL ;
5940 dns_rdata_t nsec = DNS_RDATA_INIT;
5941 dns_name_t *nsecname;
5942 dns_rdata_nsec_t nsecstruct;
5944 if ((result = dns_message_firstname(msg, DNS_SECTION_AUTHORITY))
5945 != ISC_R_SUCCESS) {
5946 printf(";; nothing in authority section : impossible to"
5947 " validate the non-existence : FAILED\n");
5948 return (ISC_R_FAILURE);
5951 do {
5952 nsecname = NULL;
5953 dns_message_currentname(msg, DNS_SECTION_AUTHORITY, &nsecname);
5954 nsecset = search_type(nsecname, dns_rdatatype_nsec,
5955 dns_rdatatype_any);
5956 if (nsecset == NULL)
5957 continue;
5959 printf("There is a NSEC for this zone in the"
5960 " AUTHORITY section:\n");
5961 print_rdataset(nsecname, nsecset, mctx);
5963 for (result = dns_rdataset_first(nsecset);
5964 result == ISC_R_SUCCESS;
5965 result = dns_rdataset_next(nsecset)) {
5966 dns_rdataset_current(nsecset, &nsec);
5968 signsecset
5969 = chase_scanname_section(msg, nsecname,
5970 dns_rdatatype_rrsig,
5971 dns_rdatatype_nsec,
5972 DNS_SECTION_AUTHORITY);
5973 if (signsecset == NULL) {
5974 printf(";; no RRSIG NSEC in authority section:"
5975 " impossible to validate the "
5976 "non-existence: FAILED\n");
5977 return (ISC_R_FAILURE);
5980 ret = dns_rdata_tostruct(&nsec, &nsecstruct, NULL);
5981 check_result(ret,"dns_rdata_tostruct");
5983 if ((inf_name(nsecname, &nsecstruct.next) == 1 &&
5984 inf_name(name, &nsecstruct.next) == 1) ||
5985 (inf_name(name, nsecname) == 1 &&
5986 inf_name(&nsecstruct.next, name) == 1)) {
5987 dns_rdata_freestruct(&nsecstruct);
5988 *rdataset = nsecset;
5989 *sigrdataset = signsecset;
5990 dup_name(nsecname, rdata_name, mctx);
5992 return (ISC_R_SUCCESS);
5995 dns_rdata_freestruct(&nsecstruct);
5996 dns_rdata_reset(&nsec);
5998 } while (dns_message_nextname(msg, DNS_SECTION_AUTHORITY)
5999 == ISC_R_SUCCESS);
6001 *rdataset = NULL;
6002 *sigrdataset = NULL;
6003 rdata_name = NULL;
6004 return (ISC_R_FAILURE);
6014 isc_result_t
6015 prove_nx_type(dns_message_t *msg, dns_name_t *name, dns_rdataset_t *nsecset,
6016 dns_rdataclass_t class, dns_rdatatype_t type,
6017 dns_name_t *rdata_name, dns_rdataset_t **rdataset,
6018 dns_rdataset_t **sigrdataset)
6020 isc_result_t ret;
6021 dns_rdataset_t *signsecset;
6022 dns_rdata_t nsec = DNS_RDATA_INIT;
6024 UNUSED(class);
6026 ret = dns_rdataset_first(nsecset);
6027 check_result(ret,"dns_rdataset_first");
6029 dns_rdataset_current(nsecset, &nsec);
6031 ret = dns_nsec_typepresent(&nsec, type);
6032 if (ret == ISC_R_SUCCESS)
6033 printf("OK the NSEC said that the type doesn't exist \n");
6035 signsecset = chase_scanname_section(msg, name,
6036 dns_rdatatype_rrsig,
6037 dns_rdatatype_nsec,
6038 DNS_SECTION_AUTHORITY);
6039 if (signsecset == NULL) {
6040 printf("There isn't RRSIG NSEC for the zone \n");
6041 return (ISC_R_FAILURE);
6043 dup_name(name, rdata_name, mctx);
6044 *rdataset = nsecset;
6045 *sigrdataset = signsecset;
6047 return (ret);
6056 isc_result_t
6057 prove_nx(dns_message_t *msg, dns_name_t *name, dns_rdataclass_t class,
6058 dns_rdatatype_t type, dns_name_t *rdata_name,
6059 dns_rdataset_t **rdataset, dns_rdataset_t **sigrdataset)
6061 isc_result_t ret;
6062 dns_rdataset_t *nsecset = NULL;
6064 printf("We want to prove the non-existence of a type of rdata %d"
6065 " or of the zone: \n", type);
6067 if ((ret = dns_message_firstname(msg, DNS_SECTION_AUTHORITY))
6068 != ISC_R_SUCCESS) {
6069 printf(";; nothing in authority section : impossible to"
6070 " validate the non-existence : FAILED\n");
6071 return (ISC_R_FAILURE);
6074 nsecset = chase_scanname_section(msg, name, dns_rdatatype_nsec,
6075 dns_rdatatype_any,
6076 DNS_SECTION_AUTHORITY);
6077 if (nsecset != NULL) {
6078 printf("We have a NSEC for this zone :OK\n");
6079 ret = prove_nx_type(msg, name, nsecset, class,
6080 type, rdata_name, rdataset,
6081 sigrdataset);
6082 if (ret != ISC_R_SUCCESS) {
6083 printf("prove_nx: ERROR type exist\n");
6084 return (ret);
6085 } else {
6086 printf("prove_nx: OK type does not exist\n");
6087 return (ISC_R_SUCCESS);
6089 } else {
6090 printf("there is no NSEC for this zone: validating "
6091 "that the zone doesn't exist\n");
6092 ret = prove_nx_domain(msg, name, rdata_name,
6093 rdataset, sigrdataset);
6094 return (ret);
6096 /* Never get here */
6098 #endif