Ignore machine-check MSRs
[freebsd-src/fkvm-freebsd.git] / contrib / bind9 / bin / dig / dighost.c
blob9e7e79659a69cc81c0a4639bd3e35aa6ae0a7b5d
1 /*
2 * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: dighost.c,v 1.259.18.43.10.3 2008/07/23 23:16:43 marka Exp $ */
20 /*! \file
21 * \note
22 * Notice to programmers: Do not use this code as an example of how to
23 * use the ISC library to perform DNS lookups. Dig and Host both operate
24 * on the request level, since they allow fine-tuning of output and are
25 * intended as debugging tools. As a result, they perform many of the
26 * functions which could be better handled using the dns_resolver
27 * functions in most applications.
30 #include <config.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <string.h>
34 #include <limits.h>
36 #ifdef HAVE_LOCALE_H
37 #include <locale.h>
38 #endif
40 #ifdef WITH_IDN
41 #include <idn/result.h>
42 #include <idn/log.h>
43 #include <idn/resconf.h>
44 #include <idn/api.h>
45 #endif
47 #include <dns/byaddr.h>
48 #ifdef DIG_SIGCHASE
49 #include <dns/dnssec.h>
50 #include <dns/ds.h>
51 #include <dns/nsec.h>
52 #include <isc/random.h>
53 #include <ctype.h>
54 #endif
55 #include <dns/fixedname.h>
56 #include <dns/message.h>
57 #include <dns/name.h>
58 #include <dns/rdata.h>
59 #include <dns/rdataclass.h>
60 #include <dns/rdatalist.h>
61 #include <dns/rdataset.h>
62 #include <dns/rdatastruct.h>
63 #include <dns/rdatatype.h>
64 #include <dns/result.h>
65 #include <dns/tsig.h>
67 #include <dst/dst.h>
69 #include <isc/app.h>
70 #include <isc/base64.h>
71 #include <isc/entropy.h>
72 #include <isc/file.h>
73 #include <isc/lang.h>
74 #include <isc/netaddr.h>
75 #ifdef DIG_SIGCHASE
76 #include <isc/netdb.h>
77 #endif
78 #include <isc/print.h>
79 #include <isc/random.h>
80 #include <isc/result.h>
81 #include <isc/string.h>
82 #include <isc/task.h>
83 #include <isc/timer.h>
84 #include <isc/types.h>
85 #include <isc/util.h>
87 #include <lwres/lwres.h>
88 #include <lwres/net.h>
90 #include <bind9/getaddresses.h>
92 #include <dig/dig.h>
94 #if ! defined(NS_INADDRSZ)
95 #define NS_INADDRSZ 4
96 #endif
98 #if ! defined(NS_IN6ADDRSZ)
99 #define NS_IN6ADDRSZ 16
100 #endif
102 static lwres_context_t *lwctx = NULL;
103 static lwres_conf_t *lwconf;
105 dig_lookuplist_t lookup_list;
106 dig_serverlist_t server_list;
107 dig_searchlistlist_t search_list;
109 isc_boolean_t
110 check_ra = ISC_FALSE,
111 have_ipv4 = ISC_FALSE,
112 have_ipv6 = ISC_FALSE,
113 specified_source = ISC_FALSE,
114 free_now = ISC_FALSE,
115 cancel_now = ISC_FALSE,
116 usesearch = ISC_FALSE,
117 showsearch = ISC_FALSE,
118 qr = ISC_FALSE,
119 is_dst_up = ISC_FALSE;
120 in_port_t port = 53;
121 unsigned int timeout = 0;
122 unsigned int extrabytes;
123 isc_mem_t *mctx = NULL;
124 isc_taskmgr_t *taskmgr = NULL;
125 isc_task_t *global_task = NULL;
126 isc_timermgr_t *timermgr = NULL;
127 isc_socketmgr_t *socketmgr = NULL;
128 isc_sockaddr_t bind_address;
129 isc_sockaddr_t bind_any;
130 int sendcount = 0;
131 int recvcount = 0;
132 int sockcount = 0;
133 int ndots = -1;
134 int tries = 3;
135 int lookup_counter = 0;
137 #ifdef WITH_IDN
138 static void initialize_idn(void);
139 static isc_result_t output_filter(isc_buffer_t *buffer,
140 unsigned int used_org,
141 isc_boolean_t absolute);
142 static idn_result_t append_textname(char *name, const char *origin,
143 size_t namesize);
144 static void idn_check_result(idn_result_t r, const char *msg);
146 #define MAXDLEN 256
147 int idnoptions = 0;
148 #endif
151 * Exit Codes:
153 *\li 0 Everything went well, including things like NXDOMAIN
154 *\li 1 Usage error
155 *\li 7 Got too many RR's or Names
156 *\li 8 Couldn't open batch file
157 *\li 9 No reply from server
158 *\li 10 Internal error
160 int exitcode = 0;
161 int fatalexit = 0;
162 char keynametext[MXNAME];
163 char keyfile[MXNAME] = "";
164 char keysecret[MXNAME] = "";
165 dns_name_t *hmacname = NULL;
166 unsigned int digestbits = 0;
167 isc_buffer_t *namebuf = NULL;
168 dns_tsigkey_t *key = NULL;
169 isc_boolean_t validated = ISC_TRUE;
170 isc_entropy_t *entp = NULL;
171 isc_mempool_t *commctx = NULL;
172 isc_boolean_t debugging = ISC_FALSE;
173 isc_boolean_t memdebugging = ISC_FALSE;
174 char *progname = NULL;
175 isc_mutex_t lookup_lock;
176 dig_lookup_t *current_lookup = NULL;
178 #ifdef DIG_SIGCHASE
180 isc_result_t get_trusted_key(isc_mem_t *mctx);
181 dns_rdataset_t * sigchase_scanname(dns_rdatatype_t type,
182 dns_rdatatype_t covers,
183 isc_boolean_t *lookedup,
184 dns_name_t *rdata_name);
185 dns_rdataset_t * chase_scanname_section(dns_message_t *msg,
186 dns_name_t *name,
187 dns_rdatatype_t type,
188 dns_rdatatype_t covers,
189 int section);
190 isc_result_t advanced_rrsearch(dns_rdataset_t **rdataset,
191 dns_name_t *name,
192 dns_rdatatype_t type,
193 dns_rdatatype_t covers,
194 isc_boolean_t *lookedup);
195 isc_result_t sigchase_verify_sig_key(dns_name_t *name,
196 dns_rdataset_t *rdataset,
197 dst_key_t* dnsseckey,
198 dns_rdataset_t *sigrdataset,
199 isc_mem_t *mctx);
200 isc_result_t sigchase_verify_sig(dns_name_t *name,
201 dns_rdataset_t *rdataset,
202 dns_rdataset_t *keyrdataset,
203 dns_rdataset_t *sigrdataset,
204 isc_mem_t *mctx);
205 isc_result_t sigchase_verify_ds(dns_name_t *name,
206 dns_rdataset_t *keyrdataset,
207 dns_rdataset_t *dsrdataset,
208 isc_mem_t *mctx);
209 void sigchase(dns_message_t *msg);
210 void print_rdata(dns_rdata_t *rdata, isc_mem_t *mctx);
211 void print_rdataset(dns_name_t *name,
212 dns_rdataset_t *rdataset, isc_mem_t *mctx);
213 void dup_name(dns_name_t *source, dns_name_t* target,
214 isc_mem_t *mctx);
215 void free_name(dns_name_t *name, isc_mem_t *mctx);
216 void dump_database(void);
217 void dump_database_section(dns_message_t *msg, int section);
218 dns_rdataset_t * search_type(dns_name_t *name, dns_rdatatype_t type,
219 dns_rdatatype_t covers);
220 isc_result_t contains_trusted_key(dns_name_t *name,
221 dns_rdataset_t *rdataset,
222 dns_rdataset_t *sigrdataset,
223 isc_mem_t *mctx);
224 void print_type(dns_rdatatype_t type);
225 isc_result_t prove_nx_domain(dns_message_t * msg,
226 dns_name_t * name,
227 dns_name_t * rdata_name,
228 dns_rdataset_t ** rdataset,
229 dns_rdataset_t ** sigrdataset);
230 isc_result_t prove_nx_type(dns_message_t * msg, dns_name_t *name,
231 dns_rdataset_t *nsec,
232 dns_rdataclass_t class,
233 dns_rdatatype_t type,
234 dns_name_t * rdata_name,
235 dns_rdataset_t ** rdataset,
236 dns_rdataset_t ** sigrdataset);
237 isc_result_t prove_nx(dns_message_t * msg, dns_name_t * name,
238 dns_rdataclass_t class,
239 dns_rdatatype_t type,
240 dns_name_t * rdata_name,
241 dns_rdataset_t ** rdataset,
242 dns_rdataset_t ** sigrdataset);
243 static void nameFromString(const char *str, dns_name_t *p_ret);
244 int inf_name(dns_name_t * name1, dns_name_t * name2);
245 isc_result_t opentmpkey(isc_mem_t *mctx, const char *file,
246 char **tempp, FILE **fp);
247 isc_result_t removetmpkey(isc_mem_t *mctx, const char *file);
248 void clean_trustedkey(void);
249 void insert_trustedkey(dst_key_t * key);
250 #if DIG_SIGCHASE_BU
251 isc_result_t getneededrr(dns_message_t *msg);
252 void sigchase_bottom_up(dns_message_t *msg);
253 void sigchase_bu(dns_message_t *msg);
254 #endif
255 #if DIG_SIGCHASE_TD
256 isc_result_t initialization(dns_name_t *name);
257 isc_result_t prepare_lookup(dns_name_t *name);
258 isc_result_t grandfather_pb_test(dns_name_t * zone_name,
259 dns_rdataset_t *sigrdataset);
260 isc_result_t child_of_zone(dns_name_t *name,
261 dns_name_t *zone_name,
262 dns_name_t *child_name);
263 void sigchase_td(dns_message_t *msg);
264 #endif
265 char trustedkey[MXNAME] = "";
267 dns_rdataset_t *chase_rdataset = NULL;
268 dns_rdataset_t *chase_sigrdataset = NULL;
269 dns_rdataset_t *chase_dsrdataset = NULL;
270 dns_rdataset_t *chase_sigdsrdataset = NULL;
271 dns_rdataset_t *chase_keyrdataset = NULL;
272 dns_rdataset_t *chase_sigkeyrdataset = NULL;
273 dns_rdataset_t *chase_nsrdataset = NULL;
275 dns_name_t chase_name; /* the query name */
276 #if DIG_SIGCHASE_TD
278 * the current name is the parent name when we follow delegation
280 dns_name_t chase_current_name;
282 * the child name is used for delegation (NS DS responses in AUTHORITY section)
284 dns_name_t chase_authority_name;
285 #endif
286 #if DIG_SIGCHASE_BU
287 dns_name_t chase_signame;
288 #endif
291 isc_boolean_t chase_siglookedup = ISC_FALSE;
292 isc_boolean_t chase_keylookedup = ISC_FALSE;
293 isc_boolean_t chase_sigkeylookedup = ISC_FALSE;
294 isc_boolean_t chase_dslookedup = ISC_FALSE;
295 isc_boolean_t chase_sigdslookedup = ISC_FALSE;
296 #if DIG_SIGCHASE_TD
297 isc_boolean_t chase_nslookedup = ISC_FALSE;
298 isc_boolean_t chase_lookedup = ISC_FALSE;
301 isc_boolean_t delegation_follow = ISC_FALSE;
302 isc_boolean_t grandfather_pb = ISC_FALSE;
303 isc_boolean_t have_response = ISC_FALSE;
304 isc_boolean_t have_delegation_ns = ISC_FALSE;
305 dns_message_t * error_message = NULL;
306 #endif
308 isc_boolean_t dsvalidating = ISC_FALSE;
309 isc_boolean_t chase_name_dup = ISC_FALSE;
311 ISC_LIST(dig_message_t) chase_message_list;
312 ISC_LIST(dig_message_t) chase_message_list2;
315 #define MAX_TRUSTED_KEY 5
316 typedef struct struct_trusted_key_list {
317 dst_key_t * key[MAX_TRUSTED_KEY];
318 int nb_tk;
319 } struct_tk_list;
321 struct_tk_list tk_list = { {NULL, NULL, NULL, NULL, NULL}, 0};
323 #endif
325 #define DIG_MAX_ADDRESSES 20
328 * Apply and clear locks at the event level in global task.
329 * Can I get rid of these using shutdown events? XXX
331 #define LOCK_LOOKUP {\
332 debug("lock_lookup %s:%d", __FILE__, __LINE__);\
333 check_result(isc_mutex_lock((&lookup_lock)), "isc_mutex_lock");\
334 debug("success");\
336 #define UNLOCK_LOOKUP {\
337 debug("unlock_lookup %s:%d", __FILE__, __LINE__);\
338 check_result(isc_mutex_unlock((&lookup_lock)),\
339 "isc_mutex_unlock");\
342 static void
343 cancel_lookup(dig_lookup_t *lookup);
345 static void
346 recv_done(isc_task_t *task, isc_event_t *event);
348 static void
349 send_udp(dig_query_t *query);
351 static void
352 connect_timeout(isc_task_t *task, isc_event_t *event);
354 static void
355 launch_next_query(dig_query_t *query, isc_boolean_t include_question);
358 static void *
359 mem_alloc(void *arg, size_t size) {
360 return (isc_mem_get(arg, size));
363 static void
364 mem_free(void *arg, void *mem, size_t size) {
365 isc_mem_put(arg, mem, size);
368 char *
369 next_token(char **stringp, const char *delim) {
370 char *res;
372 do {
373 res = strsep(stringp, delim);
374 if (res == NULL)
375 break;
376 } while (*res == '\0');
377 return (res);
380 static int
381 count_dots(char *string) {
382 char *s;
383 int i = 0;
385 s = string;
386 while (*s != '\0') {
387 if (*s == '.')
388 i++;
389 s++;
391 return (i);
394 static void
395 hex_dump(isc_buffer_t *b) {
396 unsigned int len;
397 isc_region_t r;
399 isc_buffer_usedregion(b, &r);
401 printf("%d bytes\n", r.length);
402 for (len = 0; len < r.length; len++) {
403 printf("%02x ", r.base[len]);
404 if (len % 16 == 15)
405 printf("\n");
407 if (len % 16 != 0)
408 printf("\n");
412 * Append 'len' bytes of 'text' at '*p', failing with
413 * ISC_R_NOSPACE if that would advance p past 'end'.
415 static isc_result_t
416 append(const char *text, int len, char **p, char *end) {
417 if (len > end - *p)
418 return (ISC_R_NOSPACE);
419 memcpy(*p, text, len);
420 *p += len;
421 return (ISC_R_SUCCESS);
424 static isc_result_t
425 reverse_octets(const char *in, char **p, char *end) {
426 char *dot = strchr(in, '.');
427 int len;
428 if (dot != NULL) {
429 isc_result_t result;
430 result = reverse_octets(dot + 1, p, end);
431 if (result != ISC_R_SUCCESS)
432 return (result);
433 result = append(".", 1, p, end);
434 if (result != ISC_R_SUCCESS)
435 return (result);
436 len = dot - in;
437 } else {
438 len = strlen(in);
440 return (append(in, len, p, end));
443 isc_result_t
444 get_reverse(char *reverse, size_t len, char *value, isc_boolean_t ip6_int,
445 isc_boolean_t strict)
447 int r;
448 isc_result_t result;
449 isc_netaddr_t addr;
451 addr.family = AF_INET6;
452 r = inet_pton(AF_INET6, value, &addr.type.in6);
453 if (r > 0) {
454 /* This is a valid IPv6 address. */
455 dns_fixedname_t fname;
456 dns_name_t *name;
457 unsigned int options = 0;
459 if (ip6_int)
460 options |= DNS_BYADDROPT_IPV6INT;
461 dns_fixedname_init(&fname);
462 name = dns_fixedname_name(&fname);
463 result = dns_byaddr_createptrname2(&addr, options, name);
464 if (result != ISC_R_SUCCESS)
465 return (result);
466 dns_name_format(name, reverse, len);
467 return (ISC_R_SUCCESS);
468 } else {
470 * Not a valid IPv6 address. Assume IPv4.
471 * If 'strict' is not set, construct the
472 * in-addr.arpa name by blindly reversing
473 * octets whether or not they look like integers,
474 * so that this can be used for RFC2317 names
475 * and such.
477 char *p = reverse;
478 char *end = reverse + len;
479 if (strict && inet_pton(AF_INET, value, &addr.type.in) != 1)
480 return (DNS_R_BADDOTTEDQUAD);
481 result = reverse_octets(value, &p, end);
482 if (result != ISC_R_SUCCESS)
483 return (result);
484 /* Append .in-addr.arpa. and a terminating NUL. */
485 result = append(".in-addr.arpa.", 15, &p, end);
486 if (result != ISC_R_SUCCESS)
487 return (result);
488 return (ISC_R_SUCCESS);
492 void
493 fatal(const char *format, ...) {
494 va_list args;
496 fprintf(stderr, "%s: ", progname);
497 va_start(args, format);
498 vfprintf(stderr, format, args);
499 va_end(args);
500 fprintf(stderr, "\n");
501 if (exitcode < 10)
502 exitcode = 10;
503 if (fatalexit != 0)
504 exitcode = fatalexit;
505 exit(exitcode);
508 void
509 debug(const char *format, ...) {
510 va_list args;
512 if (debugging) {
513 va_start(args, format);
514 vfprintf(stderr, format, args);
515 va_end(args);
516 fprintf(stderr, "\n");
520 void
521 check_result(isc_result_t result, const char *msg) {
522 if (result != ISC_R_SUCCESS) {
523 fatal("%s: %s", msg, isc_result_totext(result));
528 * Create a server structure, which is part of the lookup structure.
529 * This is little more than a linked list of servers to query in hopes
530 * of finding the answer the user is looking for
532 dig_server_t *
533 make_server(const char *servname, const char *userarg) {
534 dig_server_t *srv;
536 REQUIRE(servname != NULL);
538 debug("make_server(%s)", servname);
539 srv = isc_mem_allocate(mctx, sizeof(struct dig_server));
540 if (srv == NULL)
541 fatal("memory allocation failure in %s:%d",
542 __FILE__, __LINE__);
543 strncpy(srv->servername, servname, MXNAME);
544 strncpy(srv->userarg, userarg, MXNAME);
545 srv->servername[MXNAME-1] = 0;
546 srv->userarg[MXNAME-1] = 0;
547 ISC_LINK_INIT(srv, link);
548 return (srv);
551 static int
552 addr2af(int lwresaddrtype)
554 int af = 0;
556 switch (lwresaddrtype) {
557 case LWRES_ADDRTYPE_V4:
558 af = AF_INET;
559 break;
561 case LWRES_ADDRTYPE_V6:
562 af = AF_INET6;
563 break;
566 return (af);
570 * Create a copy of the server list from the lwres configuration structure.
571 * The dest list must have already had ISC_LIST_INIT applied.
573 static void
574 copy_server_list(lwres_conf_t *confdata, dig_serverlist_t *dest) {
575 dig_server_t *newsrv;
576 char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
577 int af;
578 int i;
580 debug("copy_server_list()");
581 for (i = 0; i < confdata->nsnext; i++) {
582 af = addr2af(confdata->nameservers[i].family);
584 lwres_net_ntop(af, confdata->nameservers[i].address,
585 tmp, sizeof(tmp));
586 newsrv = make_server(tmp, tmp);
587 ISC_LINK_INIT(newsrv, link);
588 ISC_LIST_ENQUEUE(*dest, newsrv, link);
592 void
593 flush_server_list(void) {
594 dig_server_t *s, *ps;
596 debug("flush_server_list()");
597 s = ISC_LIST_HEAD(server_list);
598 while (s != NULL) {
599 ps = s;
600 s = ISC_LIST_NEXT(s, link);
601 ISC_LIST_DEQUEUE(server_list, ps, link);
602 isc_mem_free(mctx, ps);
606 void
607 set_nameserver(char *opt) {
608 isc_result_t result;
609 isc_sockaddr_t sockaddrs[DIG_MAX_ADDRESSES];
610 isc_netaddr_t netaddr;
611 int count, i;
612 dig_server_t *srv;
613 char tmp[ISC_NETADDR_FORMATSIZE];
615 if (opt == NULL)
616 return;
618 result = bind9_getaddresses(opt, 0, sockaddrs,
619 DIG_MAX_ADDRESSES, &count);
620 if (result != ISC_R_SUCCESS)
621 fatal("couldn't get address for '%s': %s",
622 opt, isc_result_totext(result));
624 flush_server_list();
626 for (i = 0; i < count; i++) {
627 isc_netaddr_fromsockaddr(&netaddr, &sockaddrs[i]);
628 isc_netaddr_format(&netaddr, tmp, sizeof(tmp));
629 srv = make_server(tmp, opt);
630 if (srv == NULL)
631 fatal("memory allocation failure");
632 ISC_LIST_APPEND(server_list, srv, link);
636 static isc_result_t
637 add_nameserver(lwres_conf_t *confdata, const char *addr, int af) {
639 int i = confdata->nsnext;
641 if (confdata->nsnext >= LWRES_CONFMAXNAMESERVERS)
642 return (ISC_R_FAILURE);
644 switch (af) {
645 case AF_INET:
646 confdata->nameservers[i].family = LWRES_ADDRTYPE_V4;
647 confdata->nameservers[i].length = NS_INADDRSZ;
648 break;
649 case AF_INET6:
650 confdata->nameservers[i].family = LWRES_ADDRTYPE_V6;
651 confdata->nameservers[i].length = NS_IN6ADDRSZ;
652 break;
653 default:
654 return (ISC_R_FAILURE);
657 if (lwres_net_pton(af, addr, &confdata->nameservers[i].address) == 1) {
658 confdata->nsnext++;
659 return (ISC_R_SUCCESS);
661 return (ISC_R_FAILURE);
665 * Produce a cloned server list. The dest list must have already had
666 * ISC_LIST_INIT applied.
668 void
669 clone_server_list(dig_serverlist_t src, dig_serverlist_t *dest) {
670 dig_server_t *srv, *newsrv;
672 debug("clone_server_list()");
673 srv = ISC_LIST_HEAD(src);
674 while (srv != NULL) {
675 newsrv = make_server(srv->servername, srv->userarg);
676 ISC_LINK_INIT(newsrv, link);
677 ISC_LIST_ENQUEUE(*dest, newsrv, link);
678 srv = ISC_LIST_NEXT(srv, link);
683 * Create an empty lookup structure, which holds all the information needed
684 * to get an answer to a user's question. This structure contains two
685 * linked lists: the server list (servers to query) and the query list
686 * (outstanding queries which have been made to the listed servers).
688 dig_lookup_t *
689 make_empty_lookup(void) {
690 dig_lookup_t *looknew;
692 debug("make_empty_lookup()");
694 INSIST(!free_now);
696 looknew = isc_mem_allocate(mctx, sizeof(struct dig_lookup));
697 if (looknew == NULL)
698 fatal("memory allocation failure in %s:%d",
699 __FILE__, __LINE__);
700 looknew->pending = ISC_TRUE;
701 looknew->textname[0] = 0;
702 looknew->cmdline[0] = 0;
703 looknew->rdtype = dns_rdatatype_a;
704 looknew->qrdtype = dns_rdatatype_a;
705 looknew->rdclass = dns_rdataclass_in;
706 looknew->rdtypeset = ISC_FALSE;
707 looknew->rdclassset = ISC_FALSE;
708 looknew->sendspace = NULL;
709 looknew->sendmsg = NULL;
710 looknew->name = NULL;
711 looknew->oname = NULL;
712 looknew->timer = NULL;
713 looknew->xfr_q = NULL;
714 looknew->current_query = NULL;
715 looknew->doing_xfr = ISC_FALSE;
716 looknew->ixfr_serial = ISC_FALSE;
717 looknew->trace = ISC_FALSE;
718 looknew->trace_root = ISC_FALSE;
719 looknew->identify = ISC_FALSE;
720 looknew->identify_previous_line = ISC_FALSE;
721 looknew->ignore = ISC_FALSE;
722 looknew->servfail_stops = ISC_TRUE;
723 looknew->besteffort = ISC_TRUE;
724 looknew->dnssec = ISC_FALSE;
725 #ifdef DIG_SIGCHASE
726 looknew->sigchase = ISC_FALSE;
727 #if DIG_SIGCHASE_TD
728 looknew->do_topdown = ISC_FALSE;
729 looknew->trace_root_sigchase = ISC_FALSE;
730 looknew->rdtype_sigchaseset = ISC_FALSE;
731 looknew->rdtype_sigchase = dns_rdatatype_any;
732 looknew->qrdtype_sigchase = dns_rdatatype_any;
733 looknew->rdclass_sigchase = dns_rdataclass_in;
734 looknew->rdclass_sigchaseset = ISC_FALSE;
735 #endif
736 #endif
737 looknew->udpsize = 0;
738 looknew->edns = -1;
739 looknew->recurse = ISC_TRUE;
740 looknew->aaonly = ISC_FALSE;
741 looknew->adflag = ISC_FALSE;
742 looknew->cdflag = ISC_FALSE;
743 looknew->ns_search_only = ISC_FALSE;
744 looknew->origin = NULL;
745 looknew->tsigctx = NULL;
746 looknew->querysig = NULL;
747 looknew->retries = tries;
748 looknew->nsfound = 0;
749 looknew->tcp_mode = ISC_FALSE;
750 looknew->ip6_int = ISC_FALSE;
751 looknew->comments = ISC_TRUE;
752 looknew->stats = ISC_TRUE;
753 looknew->section_question = ISC_TRUE;
754 looknew->section_answer = ISC_TRUE;
755 looknew->section_authority = ISC_TRUE;
756 looknew->section_additional = ISC_TRUE;
757 looknew->new_search = ISC_FALSE;
758 looknew->done_as_is = ISC_FALSE;
759 looknew->need_search = ISC_FALSE;
760 ISC_LINK_INIT(looknew, link);
761 ISC_LIST_INIT(looknew->q);
762 ISC_LIST_INIT(looknew->my_server_list);
763 return (looknew);
767 * Clone a lookup, perhaps copying the server list. This does not clone
768 * the query list, since it will be regenerated by the setup_lookup()
769 * function, nor does it queue up the new lookup for processing.
770 * Caution: If you don't clone the servers, you MUST clone the server
771 * list seperately from somewhere else, or construct it by hand.
773 dig_lookup_t *
774 clone_lookup(dig_lookup_t *lookold, isc_boolean_t servers) {
775 dig_lookup_t *looknew;
777 debug("clone_lookup()");
779 INSIST(!free_now);
781 looknew = make_empty_lookup();
782 INSIST(looknew != NULL);
783 strncpy(looknew->textname, lookold->textname, MXNAME);
784 #if DIG_SIGCHASE_TD
785 strncpy(looknew->textnamesigchase, lookold->textnamesigchase, MXNAME);
786 #endif
787 strncpy(looknew->cmdline, lookold->cmdline, MXNAME);
788 looknew->textname[MXNAME-1] = 0;
789 looknew->rdtype = lookold->rdtype;
790 looknew->qrdtype = lookold->qrdtype;
791 looknew->rdclass = lookold->rdclass;
792 looknew->rdtypeset = lookold->rdtypeset;
793 looknew->rdclassset = lookold->rdclassset;
794 looknew->doing_xfr = lookold->doing_xfr;
795 looknew->ixfr_serial = lookold->ixfr_serial;
796 looknew->trace = lookold->trace;
797 looknew->trace_root = lookold->trace_root;
798 looknew->identify = lookold->identify;
799 looknew->identify_previous_line = lookold->identify_previous_line;
800 looknew->ignore = lookold->ignore;
801 looknew->servfail_stops = lookold->servfail_stops;
802 looknew->besteffort = lookold->besteffort;
803 looknew->dnssec = lookold->dnssec;
804 #ifdef DIG_SIGCHASE
805 looknew->sigchase = lookold->sigchase;
806 #if DIG_SIGCHASE_TD
807 looknew->do_topdown = lookold->do_topdown;
808 looknew->trace_root_sigchase = lookold->trace_root_sigchase;
809 looknew->rdtype_sigchaseset = lookold->rdtype_sigchaseset;
810 looknew->rdtype_sigchase = lookold->rdtype_sigchase;
811 looknew->qrdtype_sigchase = lookold->qrdtype_sigchase;
812 looknew->rdclass_sigchase = lookold->rdclass_sigchase;
813 looknew->rdclass_sigchaseset = lookold->rdclass_sigchaseset;
814 #endif
815 #endif
816 looknew->udpsize = lookold->udpsize;
817 looknew->edns = lookold->edns;
818 looknew->recurse = lookold->recurse;
819 looknew->aaonly = lookold->aaonly;
820 looknew->adflag = lookold->adflag;
821 looknew->cdflag = lookold->cdflag;
822 looknew->ns_search_only = lookold->ns_search_only;
823 looknew->tcp_mode = lookold->tcp_mode;
824 looknew->comments = lookold->comments;
825 looknew->stats = lookold->stats;
826 looknew->section_question = lookold->section_question;
827 looknew->section_answer = lookold->section_answer;
828 looknew->section_authority = lookold->section_authority;
829 looknew->section_additional = lookold->section_additional;
830 looknew->retries = lookold->retries;
831 looknew->tsigctx = NULL;
832 looknew->need_search = lookold->need_search;
833 looknew->done_as_is = lookold->done_as_is;
835 if (servers)
836 clone_server_list(lookold->my_server_list,
837 &looknew->my_server_list);
838 return (looknew);
842 * Requeue a lookup for further processing, perhaps copying the server
843 * list. The new lookup structure is returned to the caller, and is
844 * queued for processing. If servers are not cloned in the requeue, they
845 * must be added before allowing the current event to complete, since the
846 * completion of the event may result in the next entry on the lookup
847 * queue getting run.
849 dig_lookup_t *
850 requeue_lookup(dig_lookup_t *lookold, isc_boolean_t servers) {
851 dig_lookup_t *looknew;
853 debug("requeue_lookup()");
855 lookup_counter++;
856 if (lookup_counter > LOOKUP_LIMIT)
857 fatal("too many lookups");
859 looknew = clone_lookup(lookold, servers);
860 INSIST(looknew != NULL);
862 debug("before insertion, init@%p -> %p, new@%p -> %p",
863 lookold, lookold->link.next, looknew, looknew->link.next);
864 ISC_LIST_PREPEND(lookup_list, looknew, link);
865 debug("after insertion, init -> %p, new = %p, new -> %p",
866 lookold, looknew, looknew->link.next);
867 return (looknew);
871 static void
872 setup_text_key(void) {
873 isc_result_t result;
874 dns_name_t keyname;
875 isc_buffer_t secretbuf;
876 int secretsize;
877 unsigned char *secretstore;
879 debug("setup_text_key()");
880 result = isc_buffer_allocate(mctx, &namebuf, MXNAME);
881 check_result(result, "isc_buffer_allocate");
882 dns_name_init(&keyname, NULL);
883 check_result(result, "dns_name_init");
884 isc_buffer_putstr(namebuf, keynametext);
885 secretsize = strlen(keysecret) * 3 / 4;
886 secretstore = isc_mem_allocate(mctx, secretsize);
887 if (secretstore == NULL)
888 fatal("memory allocation failure in %s:%d",
889 __FILE__, __LINE__);
890 isc_buffer_init(&secretbuf, secretstore, secretsize);
891 result = isc_base64_decodestring(keysecret, &secretbuf);
892 if (result != ISC_R_SUCCESS)
893 goto failure;
895 secretsize = isc_buffer_usedlength(&secretbuf);
897 result = dns_name_fromtext(&keyname, namebuf,
898 dns_rootname, ISC_FALSE,
899 namebuf);
900 if (result != ISC_R_SUCCESS)
901 goto failure;
903 result = dns_tsigkey_create(&keyname, hmacname, secretstore,
904 secretsize, ISC_FALSE, NULL, 0, 0, mctx,
905 NULL, &key);
906 failure:
907 if (result != ISC_R_SUCCESS)
908 printf(";; Couldn't create key %s: %s\n",
909 keynametext, isc_result_totext(result));
910 else
911 dst_key_setbits(key->key, digestbits);
913 isc_mem_free(mctx, secretstore);
914 dns_name_invalidate(&keyname);
915 isc_buffer_free(&namebuf);
918 static void
919 setup_file_key(void) {
920 isc_result_t result;
921 dst_key_t *dstkey = NULL;
923 debug("setup_file_key()");
924 result = dst_key_fromnamedfile(keyfile, DST_TYPE_PRIVATE | DST_TYPE_KEY,
925 mctx, &dstkey);
926 if (result != ISC_R_SUCCESS) {
927 fprintf(stderr, "Couldn't read key from %s: %s\n",
928 keyfile, isc_result_totext(result));
929 goto failure;
932 switch (dst_key_alg(dstkey)) {
933 case DST_ALG_HMACMD5:
934 hmacname = DNS_TSIG_HMACMD5_NAME;
935 break;
936 case DST_ALG_HMACSHA1:
937 hmacname = DNS_TSIG_HMACSHA1_NAME;
938 break;
939 case DST_ALG_HMACSHA224:
940 hmacname = DNS_TSIG_HMACSHA224_NAME;
941 break;
942 case DST_ALG_HMACSHA256:
943 hmacname = DNS_TSIG_HMACSHA256_NAME;
944 break;
945 case DST_ALG_HMACSHA384:
946 hmacname = DNS_TSIG_HMACSHA384_NAME;
947 break;
948 case DST_ALG_HMACSHA512:
949 hmacname = DNS_TSIG_HMACSHA512_NAME;
950 break;
951 default:
952 printf(";; Couldn't create key %s: bad algorithm\n",
953 keynametext);
954 goto failure;
956 result = dns_tsigkey_createfromkey(dst_key_name(dstkey), hmacname,
957 dstkey, ISC_FALSE, NULL, 0, 0,
958 mctx, NULL, &key);
959 if (result != ISC_R_SUCCESS) {
960 printf(";; Couldn't create key %s: %s\n",
961 keynametext, isc_result_totext(result));
962 goto failure;
964 dstkey = NULL;
965 failure:
966 if (dstkey != NULL)
967 dst_key_free(&dstkey);
970 static dig_searchlist_t *
971 make_searchlist_entry(char *domain) {
972 dig_searchlist_t *search;
973 search = isc_mem_allocate(mctx, sizeof(*search));
974 if (search == NULL)
975 fatal("memory allocation failure in %s:%d",
976 __FILE__, __LINE__);
977 strncpy(search->origin, domain, MXNAME);
978 search->origin[MXNAME-1] = 0;
979 ISC_LINK_INIT(search, link);
980 return (search);
983 static void
984 create_search_list(lwres_conf_t *confdata) {
985 int i;
986 dig_searchlist_t *search;
988 debug("create_search_list()");
989 ISC_LIST_INIT(search_list);
991 for (i = 0; i < confdata->searchnxt; i++) {
992 search = make_searchlist_entry(confdata->search[i]);
993 ISC_LIST_APPEND(search_list, search, link);
998 * Setup the system as a whole, reading key information and resolv.conf
999 * settings.
1001 void
1002 setup_system(void) {
1003 dig_searchlist_t *domain = NULL;
1004 lwres_result_t lwresult;
1006 debug("setup_system()");
1008 lwresult = lwres_context_create(&lwctx, mctx, mem_alloc, mem_free, 1);
1009 if (lwresult != LWRES_R_SUCCESS)
1010 fatal("lwres_context_create failed");
1012 lwresult = lwres_conf_parse(lwctx, RESOLV_CONF);
1013 if (lwresult != LWRES_R_SUCCESS && lwresult != LWRES_R_NOTFOUND)
1014 fatal("parse of %s failed", RESOLV_CONF);
1016 lwconf = lwres_conf_get(lwctx);
1018 /* Make the search list */
1019 if (lwconf->searchnxt > 0)
1020 create_search_list(lwconf);
1021 else { /* No search list. Use the domain name if any */
1022 if (lwconf->domainname != NULL) {
1023 domain = make_searchlist_entry(lwconf->domainname);
1024 ISC_LIST_INITANDAPPEND(search_list, domain, link);
1025 domain = NULL;
1029 if (ndots == -1) {
1030 ndots = lwconf->ndots;
1031 debug("ndots is %d.", ndots);
1034 /* If we don't find a nameserver fall back to localhost */
1035 if (lwconf->nsnext == 0) {
1036 if (have_ipv4) {
1037 lwresult = add_nameserver(lwconf, "127.0.0.1", AF_INET);
1038 if (lwresult != ISC_R_SUCCESS)
1039 fatal("add_nameserver failed");
1041 if (have_ipv6) {
1042 lwresult = add_nameserver(lwconf, "::1", AF_INET6);
1043 if (lwresult != ISC_R_SUCCESS)
1044 fatal("add_nameserver failed");
1048 if (ISC_LIST_EMPTY(server_list))
1049 copy_server_list(lwconf, &server_list);
1051 #ifdef WITH_IDN
1052 initialize_idn();
1053 #endif
1055 if (keyfile[0] != 0)
1056 setup_file_key();
1057 else if (keysecret[0] != 0)
1058 setup_text_key();
1059 #ifdef DIG_SIGCHASE
1060 /* Setup the list of messages for +sigchase */
1061 ISC_LIST_INIT(chase_message_list);
1062 ISC_LIST_INIT(chase_message_list2);
1063 dns_name_init(&chase_name, NULL);
1064 #if DIG_SIGCHASE_TD
1065 dns_name_init(&chase_current_name, NULL);
1066 dns_name_init(&chase_authority_name, NULL);
1067 #endif
1068 #if DIG_SIGCHASE_BU
1069 dns_name_init(&chase_signame, NULL);
1070 #endif
1072 #endif
1076 static void
1077 clear_searchlist(void) {
1078 dig_searchlist_t *search;
1079 while ((search = ISC_LIST_HEAD(search_list)) != NULL) {
1080 ISC_LIST_UNLINK(search_list, search, link);
1081 isc_mem_free(mctx, search);
1086 * Override the search list derived from resolv.conf by 'domain'.
1088 void
1089 set_search_domain(char *domain) {
1090 dig_searchlist_t *search;
1092 clear_searchlist();
1093 search = make_searchlist_entry(domain);
1094 ISC_LIST_APPEND(search_list, search, link);
1098 * Setup the ISC and DNS libraries for use by the system.
1100 void
1101 setup_libs(void) {
1102 isc_result_t result;
1104 debug("setup_libs()");
1106 result = isc_net_probeipv4();
1107 if (result == ISC_R_SUCCESS)
1108 have_ipv4 = ISC_TRUE;
1110 result = isc_net_probeipv6();
1111 if (result == ISC_R_SUCCESS)
1112 have_ipv6 = ISC_TRUE;
1113 if (!have_ipv6 && !have_ipv4)
1114 fatal("can't find either v4 or v6 networking");
1116 result = isc_mem_create(0, 0, &mctx);
1117 check_result(result, "isc_mem_create");
1119 result = isc_taskmgr_create(mctx, 1, 0, &taskmgr);
1120 check_result(result, "isc_taskmgr_create");
1122 result = isc_task_create(taskmgr, 0, &global_task);
1123 check_result(result, "isc_task_create");
1125 result = isc_timermgr_create(mctx, &timermgr);
1126 check_result(result, "isc_timermgr_create");
1128 result = isc_socketmgr_create(mctx, &socketmgr);
1129 check_result(result, "isc_socketmgr_create");
1131 result = isc_entropy_create(mctx, &entp);
1132 check_result(result, "isc_entropy_create");
1134 result = dst_lib_init(mctx, entp, 0);
1135 check_result(result, "dst_lib_init");
1136 is_dst_up = ISC_TRUE;
1138 result = isc_mempool_create(mctx, COMMSIZE, &commctx);
1139 check_result(result, "isc_mempool_create");
1140 isc_mempool_setname(commctx, "COMMPOOL");
1142 * 6 and 2 set as reasonable parameters for 3 or 4 nameserver
1143 * systems.
1145 isc_mempool_setfreemax(commctx, 6);
1146 isc_mempool_setfillcount(commctx, 2);
1148 result = isc_mutex_init(&lookup_lock);
1149 check_result(result, "isc_mutex_init");
1151 dns_result_register();
1155 * Add EDNS0 option record to a message. Currently, the only supported
1156 * options are UDP buffer size and the DO bit.
1158 static void
1159 add_opt(dns_message_t *msg, isc_uint16_t udpsize, isc_uint16_t edns,
1160 isc_boolean_t dnssec)
1162 dns_rdataset_t *rdataset = NULL;
1163 dns_rdatalist_t *rdatalist = NULL;
1164 dns_rdata_t *rdata = NULL;
1165 isc_result_t result;
1167 debug("add_opt()");
1168 result = dns_message_gettemprdataset(msg, &rdataset);
1169 check_result(result, "dns_message_gettemprdataset");
1170 dns_rdataset_init(rdataset);
1171 result = dns_message_gettemprdatalist(msg, &rdatalist);
1172 check_result(result, "dns_message_gettemprdatalist");
1173 result = dns_message_gettemprdata(msg, &rdata);
1174 check_result(result, "dns_message_gettemprdata");
1176 debug("setting udp size of %d", udpsize);
1177 rdatalist->type = dns_rdatatype_opt;
1178 rdatalist->covers = 0;
1179 rdatalist->rdclass = udpsize;
1180 rdatalist->ttl = edns << 16;
1181 if (dnssec)
1182 rdatalist->ttl |= DNS_MESSAGEEXTFLAG_DO;
1183 rdata->data = NULL;
1184 rdata->length = 0;
1185 ISC_LIST_INIT(rdatalist->rdata);
1186 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1187 dns_rdatalist_tordataset(rdatalist, rdataset);
1188 result = dns_message_setopt(msg, rdataset);
1189 check_result(result, "dns_message_setopt");
1193 * Add a question section to a message, asking for the specified name,
1194 * type, and class.
1196 static void
1197 add_question(dns_message_t *message, dns_name_t *name,
1198 dns_rdataclass_t rdclass, dns_rdatatype_t rdtype)
1200 dns_rdataset_t *rdataset;
1201 isc_result_t result;
1203 debug("add_question()");
1204 rdataset = NULL;
1205 result = dns_message_gettemprdataset(message, &rdataset);
1206 check_result(result, "dns_message_gettemprdataset()");
1207 dns_rdataset_init(rdataset);
1208 dns_rdataset_makequestion(rdataset, rdclass, rdtype);
1209 ISC_LIST_APPEND(name->list, rdataset, link);
1213 * Check if we're done with all the queued lookups, which is true iff
1214 * all sockets, sends, and recvs are accounted for (counters == 0),
1215 * and the lookup list is empty.
1216 * If we are done, pass control back out to dighost_shutdown() (which is
1217 * part of dig.c, host.c, or nslookup.c) to either shutdown the system as
1218 * a whole or reseed the lookup list.
1220 static void
1221 check_if_done(void) {
1222 debug("check_if_done()");
1223 debug("list %s", ISC_LIST_EMPTY(lookup_list) ? "empty" : "full");
1224 if (ISC_LIST_EMPTY(lookup_list) && current_lookup == NULL &&
1225 sendcount == 0) {
1226 INSIST(sockcount == 0);
1227 INSIST(recvcount == 0);
1228 debug("shutting down");
1229 dighost_shutdown();
1234 * Clear out a query when we're done with it. WARNING: This routine
1235 * WILL invalidate the query pointer.
1237 static void
1238 clear_query(dig_query_t *query) {
1239 dig_lookup_t *lookup;
1241 REQUIRE(query != NULL);
1243 debug("clear_query(%p)", query);
1245 lookup = query->lookup;
1247 if (lookup->current_query == query)
1248 lookup->current_query = NULL;
1250 ISC_LIST_UNLINK(lookup->q, query, link);
1251 if (ISC_LINK_LINKED(&query->recvbuf, link))
1252 ISC_LIST_DEQUEUE(query->recvlist, &query->recvbuf,
1253 link);
1254 if (ISC_LINK_LINKED(&query->lengthbuf, link))
1255 ISC_LIST_DEQUEUE(query->lengthlist, &query->lengthbuf,
1256 link);
1257 INSIST(query->recvspace != NULL);
1258 if (query->sock != NULL) {
1259 isc_socket_detach(&query->sock);
1260 sockcount--;
1261 debug("sockcount=%d", sockcount);
1263 isc_mempool_put(commctx, query->recvspace);
1264 isc_buffer_invalidate(&query->recvbuf);
1265 isc_buffer_invalidate(&query->lengthbuf);
1266 if (query->waiting_senddone)
1267 query->pending_free = ISC_TRUE;
1268 else
1269 isc_mem_free(mctx, query);
1273 * Try and clear out a lookup if we're done with it. Return ISC_TRUE if
1274 * the lookup was successfully cleared. If ISC_TRUE is returned, the
1275 * lookup pointer has been invalidated.
1277 static isc_boolean_t
1278 try_clear_lookup(dig_lookup_t *lookup) {
1279 dig_query_t *q;
1281 REQUIRE(lookup != NULL);
1283 debug("try_clear_lookup(%p)", lookup);
1285 if (ISC_LIST_HEAD(lookup->q) != NULL) {
1286 if (debugging) {
1287 q = ISC_LIST_HEAD(lookup->q);
1288 while (q != NULL) {
1289 debug("query to %s still pending", q->servname);
1290 q = ISC_LIST_NEXT(q, link);
1293 return (ISC_FALSE);
1297 * At this point, we know there are no queries on the lookup,
1298 * so can make it go away also.
1300 destroy_lookup(lookup);
1301 return (ISC_TRUE);
1304 void
1305 destroy_lookup(dig_lookup_t *lookup) {
1306 dig_server_t *s;
1307 void *ptr;
1309 debug("destroy");
1310 s = ISC_LIST_HEAD(lookup->my_server_list);
1311 while (s != NULL) {
1312 debug("freeing server %p belonging to %p", s, lookup);
1313 ptr = s;
1314 s = ISC_LIST_NEXT(s, link);
1315 ISC_LIST_DEQUEUE(lookup->my_server_list,
1316 (dig_server_t *)ptr, link);
1317 isc_mem_free(mctx, ptr);
1319 if (lookup->sendmsg != NULL)
1320 dns_message_destroy(&lookup->sendmsg);
1321 if (lookup->querysig != NULL) {
1322 debug("freeing buffer %p", lookup->querysig);
1323 isc_buffer_free(&lookup->querysig);
1325 if (lookup->timer != NULL)
1326 isc_timer_detach(&lookup->timer);
1327 if (lookup->sendspace != NULL)
1328 isc_mempool_put(commctx, lookup->sendspace);
1330 if (lookup->tsigctx != NULL)
1331 dst_context_destroy(&lookup->tsigctx);
1333 isc_mem_free(mctx, lookup);
1337 * If we can, start the next lookup in the queue running.
1338 * This assumes that the lookup on the head of the queue hasn't been
1339 * started yet. It also removes the lookup from the head of the queue,
1340 * setting the current_lookup pointer pointing to it.
1342 void
1343 start_lookup(void) {
1344 debug("start_lookup()");
1345 if (cancel_now)
1346 return;
1349 * If there's a current lookup running, we really shouldn't get
1350 * here.
1352 INSIST(current_lookup == NULL);
1354 current_lookup = ISC_LIST_HEAD(lookup_list);
1356 * Put the current lookup somewhere so cancel_all can find it
1358 if (current_lookup != NULL) {
1359 ISC_LIST_DEQUEUE(lookup_list, current_lookup, link);
1360 #if DIG_SIGCHASE_TD
1361 if (current_lookup->do_topdown &&
1362 !current_lookup->rdtype_sigchaseset) {
1363 dst_key_t *trustedkey = NULL;
1364 isc_buffer_t *b = NULL;
1365 isc_region_t r;
1366 isc_result_t result;
1367 dns_name_t query_name;
1368 dns_name_t *key_name;
1369 int i;
1371 result = get_trusted_key(mctx);
1372 if (result != ISC_R_SUCCESS) {
1373 printf("\n;; No trusted key, "
1374 "+sigchase option is disabled\n");
1375 current_lookup->sigchase = ISC_FALSE;
1376 goto novalidation;
1378 dns_name_init(&query_name, NULL);
1379 nameFromString(current_lookup->textname, &query_name);
1381 for (i = 0; i < tk_list.nb_tk; i++) {
1382 key_name = dst_key_name(tk_list.key[i]);
1384 if (dns_name_issubdomain(&query_name,
1385 key_name) == ISC_TRUE)
1386 trustedkey = tk_list.key[i];
1388 * Verifier que la temp est bien la plus basse
1389 * WARNING
1392 if (trustedkey == NULL) {
1393 printf("\n;; The queried zone: ");
1394 dns_name_print(&query_name, stdout);
1395 printf(" isn't a subdomain of any Trusted Keys"
1396 ": +sigchase option is disable\n");
1397 current_lookup->sigchase = ISC_FALSE;
1398 free_name(&query_name, mctx);
1399 goto novalidation;
1401 free_name(&query_name, mctx);
1403 current_lookup->rdtype_sigchase
1404 = current_lookup->rdtype;
1405 current_lookup->rdtype_sigchaseset
1406 = current_lookup->rdtypeset;
1407 current_lookup->rdtype = dns_rdatatype_ns;
1409 current_lookup->qrdtype_sigchase
1410 = current_lookup->qrdtype;
1411 current_lookup->qrdtype = dns_rdatatype_ns;
1413 current_lookup->rdclass_sigchase
1414 = current_lookup->rdclass;
1415 current_lookup->rdclass_sigchaseset
1416 = current_lookup->rdclassset;
1417 current_lookup->rdclass = dns_rdataclass_in;
1419 strncpy(current_lookup->textnamesigchase,
1420 current_lookup->textname, MXNAME);
1422 current_lookup->trace_root_sigchase = ISC_TRUE;
1424 result = isc_buffer_allocate(mctx, &b, BUFSIZE);
1425 check_result(result, "isc_buffer_allocate");
1426 result = dns_name_totext(dst_key_name(trustedkey),
1427 ISC_FALSE, b);
1428 check_result(result, "dns_name_totext");
1429 isc_buffer_usedregion(b, &r);
1430 r.base[r.length] = '\0';
1431 strncpy(current_lookup->textname, (char*)r.base,
1432 MXNAME);
1433 isc_buffer_free(&b);
1435 nameFromString(current_lookup->textnamesigchase,
1436 &chase_name);
1438 dns_name_init(&chase_authority_name, NULL);
1440 novalidation:
1441 #endif
1442 setup_lookup(current_lookup);
1443 do_lookup(current_lookup);
1444 } else {
1445 check_if_done();
1450 * If we can, clear the current lookup and start the next one running.
1451 * This calls try_clear_lookup, so may invalidate the lookup pointer.
1453 static void
1454 check_next_lookup(dig_lookup_t *lookup) {
1456 INSIST(!free_now);
1458 debug("check_next_lookup(%p)", lookup);
1460 if (ISC_LIST_HEAD(lookup->q) != NULL) {
1461 debug("still have a worker");
1462 return;
1464 if (try_clear_lookup(lookup)) {
1465 current_lookup = NULL;
1466 start_lookup();
1471 * Create and queue a new lookup as a followup to the current lookup,
1472 * based on the supplied message and section. This is used in trace and
1473 * name server search modes to start a new lookup using servers from
1474 * NS records in a reply. Returns the number of followup lookups made.
1476 static int
1477 followup_lookup(dns_message_t *msg, dig_query_t *query, dns_section_t section)
1479 dig_lookup_t *lookup = NULL;
1480 dig_server_t *srv = NULL;
1481 dns_rdataset_t *rdataset = NULL;
1482 dns_rdata_t rdata = DNS_RDATA_INIT;
1483 dns_name_t *name = NULL;
1484 isc_result_t result;
1485 isc_boolean_t success = ISC_FALSE;
1486 int numLookups = 0;
1487 dns_name_t *domain;
1488 isc_boolean_t horizontal = ISC_FALSE, bad = ISC_FALSE;
1490 INSIST(!free_now);
1492 debug("following up %s", query->lookup->textname);
1494 for (result = dns_message_firstname(msg, section);
1495 result == ISC_R_SUCCESS;
1496 result = dns_message_nextname(msg, section)) {
1497 name = NULL;
1498 dns_message_currentname(msg, section, &name);
1500 if (section == DNS_SECTION_AUTHORITY) {
1501 rdataset = NULL;
1502 result = dns_message_findtype(name, dns_rdatatype_soa,
1503 0, &rdataset);
1504 if (result == ISC_R_SUCCESS)
1505 return (0);
1507 rdataset = NULL;
1508 result = dns_message_findtype(name, dns_rdatatype_ns, 0,
1509 &rdataset);
1510 if (result != ISC_R_SUCCESS)
1511 continue;
1513 debug("found NS set");
1515 if (query->lookup->trace && !query->lookup->trace_root) {
1516 dns_namereln_t namereln;
1517 unsigned int nlabels;
1518 int order;
1520 domain = dns_fixedname_name(&query->lookup->fdomain);
1521 namereln = dns_name_fullcompare(name, domain,
1522 &order, &nlabels);
1523 if (namereln == dns_namereln_equal) {
1524 if (!horizontal)
1525 printf(";; BAD (HORIZONTAL) REFERRAL\n");
1526 horizontal = ISC_TRUE;
1527 } else if (namereln != dns_namereln_subdomain) {
1528 if (!bad)
1529 printf(";; BAD REFERRAL\n");
1530 bad = ISC_TRUE;
1531 continue;
1535 for (result = dns_rdataset_first(rdataset);
1536 result == ISC_R_SUCCESS;
1537 result = dns_rdataset_next(rdataset)) {
1538 char namestr[DNS_NAME_FORMATSIZE];
1539 dns_rdata_ns_t ns;
1541 if (query->lookup->trace_root &&
1542 query->lookup->nsfound >= MXSERV)
1543 break;
1545 dns_rdataset_current(rdataset, &rdata);
1547 query->lookup->nsfound++;
1548 (void)dns_rdata_tostruct(&rdata, &ns, NULL);
1549 dns_name_format(&ns.name, namestr, sizeof(namestr));
1550 dns_rdata_freestruct(&ns);
1552 /* Initialize lookup if we've not yet */
1553 debug("found NS %d %s", numLookups, namestr);
1554 numLookups++;
1555 if (!success) {
1556 success = ISC_TRUE;
1557 lookup_counter++;
1558 lookup = requeue_lookup(query->lookup,
1559 ISC_FALSE);
1560 cancel_lookup(query->lookup);
1561 lookup->doing_xfr = ISC_FALSE;
1562 if (!lookup->trace_root &&
1563 section == DNS_SECTION_ANSWER)
1564 lookup->trace = ISC_FALSE;
1565 else
1566 lookup->trace = query->lookup->trace;
1567 lookup->ns_search_only =
1568 query->lookup->ns_search_only;
1569 lookup->trace_root = ISC_FALSE;
1570 if (lookup->ns_search_only)
1571 lookup->recurse = ISC_FALSE;
1572 dns_fixedname_init(&lookup->fdomain);
1573 domain = dns_fixedname_name(&lookup->fdomain);
1574 dns_name_copy(name, domain, NULL);
1576 srv = make_server(namestr, namestr);
1577 debug("adding server %s", srv->servername);
1578 ISC_LIST_APPEND(lookup->my_server_list, srv, link);
1579 dns_rdata_reset(&rdata);
1583 if (lookup == NULL &&
1584 section == DNS_SECTION_ANSWER &&
1585 (query->lookup->trace || query->lookup->ns_search_only))
1586 return (followup_lookup(msg, query, DNS_SECTION_AUTHORITY));
1589 * Randomize the order the nameserver will be tried.
1591 if (numLookups > 1) {
1592 isc_uint32_t i, j;
1593 dig_serverlist_t my_server_list;
1595 ISC_LIST_INIT(my_server_list);
1597 for (i = numLookups; i > 0; i--) {
1598 isc_random_get(&j);
1599 j %= i;
1600 srv = ISC_LIST_HEAD(lookup->my_server_list);
1601 while (j-- > 0)
1602 srv = ISC_LIST_NEXT(srv, link);
1603 ISC_LIST_DEQUEUE(lookup->my_server_list, srv, link);
1604 ISC_LIST_APPEND(my_server_list, srv, link);
1606 ISC_LIST_APPENDLIST(lookup->my_server_list,
1607 my_server_list, link);
1610 return (numLookups);
1614 * Create and queue a new lookup using the next origin from the search
1615 * list, read in setup_system().
1617 * Return ISC_TRUE iff there was another searchlist entry.
1619 static isc_boolean_t
1620 next_origin(dns_message_t *msg, dig_query_t *query) {
1621 dig_lookup_t *lookup;
1622 dig_searchlist_t *search;
1624 UNUSED(msg);
1626 INSIST(!free_now);
1628 debug("next_origin()");
1629 debug("following up %s", query->lookup->textname);
1631 if (!usesearch)
1633 * We're not using a search list, so don't even think
1634 * about finding the next entry.
1636 return (ISC_FALSE);
1637 if (query->lookup->origin == NULL && !query->lookup->need_search)
1639 * Then we just did rootorg; there's nothing left.
1641 return (ISC_FALSE);
1642 if (query->lookup->origin == NULL && query->lookup->need_search) {
1643 lookup = requeue_lookup(query->lookup, ISC_TRUE);
1644 lookup->origin = ISC_LIST_HEAD(search_list);
1645 lookup->need_search = ISC_FALSE;
1646 } else {
1647 search = ISC_LIST_NEXT(query->lookup->origin, link);
1648 if (search == NULL && query->lookup->done_as_is)
1649 return (ISC_FALSE);
1650 lookup = requeue_lookup(query->lookup, ISC_TRUE);
1651 lookup->origin = search;
1653 cancel_lookup(query->lookup);
1654 return (ISC_TRUE);
1658 * Insert an SOA record into the sendmessage in a lookup. Used for
1659 * creating IXFR queries.
1661 static void
1662 insert_soa(dig_lookup_t *lookup) {
1663 isc_result_t result;
1664 dns_rdata_soa_t soa;
1665 dns_rdata_t *rdata = NULL;
1666 dns_rdatalist_t *rdatalist = NULL;
1667 dns_rdataset_t *rdataset = NULL;
1668 dns_name_t *soaname = NULL;
1670 debug("insert_soa()");
1671 soa.mctx = mctx;
1672 soa.serial = lookup->ixfr_serial;
1673 soa.refresh = 0;
1674 soa.retry = 0;
1675 soa.expire = 0;
1676 soa.minimum = 0;
1677 soa.common.rdclass = lookup->rdclass;
1678 soa.common.rdtype = dns_rdatatype_soa;
1680 dns_name_init(&soa.origin, NULL);
1681 dns_name_init(&soa.contact, NULL);
1683 dns_name_clone(dns_rootname, &soa.origin);
1684 dns_name_clone(dns_rootname, &soa.contact);
1686 isc_buffer_init(&lookup->rdatabuf, lookup->rdatastore,
1687 sizeof(lookup->rdatastore));
1689 result = dns_message_gettemprdata(lookup->sendmsg, &rdata);
1690 check_result(result, "dns_message_gettemprdata");
1692 result = dns_rdata_fromstruct(rdata, lookup->rdclass,
1693 dns_rdatatype_soa, &soa,
1694 &lookup->rdatabuf);
1695 check_result(result, "isc_rdata_fromstruct");
1697 result = dns_message_gettemprdatalist(lookup->sendmsg, &rdatalist);
1698 check_result(result, "dns_message_gettemprdatalist");
1700 result = dns_message_gettemprdataset(lookup->sendmsg, &rdataset);
1701 check_result(result, "dns_message_gettemprdataset");
1703 dns_rdatalist_init(rdatalist);
1704 rdatalist->type = dns_rdatatype_soa;
1705 rdatalist->rdclass = lookup->rdclass;
1706 rdatalist->covers = 0;
1707 rdatalist->ttl = 0;
1708 ISC_LIST_INIT(rdatalist->rdata);
1709 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1711 dns_rdataset_init(rdataset);
1712 dns_rdatalist_tordataset(rdatalist, rdataset);
1714 result = dns_message_gettempname(lookup->sendmsg, &soaname);
1715 check_result(result, "dns_message_gettempname");
1716 dns_name_init(soaname, NULL);
1717 dns_name_clone(lookup->name, soaname);
1718 ISC_LIST_INIT(soaname->list);
1719 ISC_LIST_APPEND(soaname->list, rdataset, link);
1720 dns_message_addname(lookup->sendmsg, soaname, DNS_SECTION_AUTHORITY);
1724 * Setup the supplied lookup structure, making it ready to start sending
1725 * queries to servers. Create and initialize the message to be sent as
1726 * well as the query structures and buffer space for the replies. If the
1727 * server list is empty, clone it from the system default list.
1729 void
1730 setup_lookup(dig_lookup_t *lookup) {
1731 isc_result_t result;
1732 isc_uint32_t id;
1733 int len;
1734 dig_server_t *serv;
1735 dig_query_t *query;
1736 isc_buffer_t b;
1737 dns_compress_t cctx;
1738 char store[MXNAME];
1739 #ifdef WITH_IDN
1740 idn_result_t mr;
1741 char utf8_textname[MXNAME], utf8_origin[MXNAME], idn_textname[MXNAME];
1742 #endif
1744 #ifdef WITH_IDN
1745 result = dns_name_settotextfilter(output_filter);
1746 check_result(result, "dns_name_settotextfilter");
1747 #endif
1749 REQUIRE(lookup != NULL);
1750 INSIST(!free_now);
1752 debug("setup_lookup(%p)", lookup);
1754 result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER,
1755 &lookup->sendmsg);
1756 check_result(result, "dns_message_create");
1758 if (lookup->new_search) {
1759 debug("resetting lookup counter.");
1760 lookup_counter = 0;
1763 if (ISC_LIST_EMPTY(lookup->my_server_list)) {
1764 debug("cloning server list");
1765 clone_server_list(server_list, &lookup->my_server_list);
1767 result = dns_message_gettempname(lookup->sendmsg, &lookup->name);
1768 check_result(result, "dns_message_gettempname");
1769 dns_name_init(lookup->name, NULL);
1771 isc_buffer_init(&lookup->namebuf, lookup->namespace,
1772 sizeof(lookup->namespace));
1773 isc_buffer_init(&lookup->onamebuf, lookup->onamespace,
1774 sizeof(lookup->onamespace));
1776 #ifdef WITH_IDN
1778 * We cannot convert `textname' and `origin' separately.
1779 * `textname' doesn't contain TLD, but local mapping needs
1780 * TLD.
1782 mr = idn_encodename(IDN_LOCALCONV | IDN_DELIMMAP, lookup->textname,
1783 utf8_textname, sizeof(utf8_textname));
1784 idn_check_result(mr, "convert textname to UTF-8");
1785 #endif
1788 * If the name has too many dots, force the origin to be NULL
1789 * (which produces an absolute lookup). Otherwise, take the origin
1790 * we have if there's one in the struct already. If it's NULL,
1791 * take the first entry in the searchlist iff either usesearch
1792 * is TRUE or we got a domain line in the resolv.conf file.
1794 if (lookup->new_search) {
1795 #ifdef WITH_IDN
1796 if ((count_dots(utf8_textname) >= ndots) || !usesearch) {
1797 lookup->origin = NULL; /* Force abs lookup */
1798 lookup->done_as_is = ISC_TRUE;
1799 lookup->need_search = usesearch;
1800 } else if (lookup->origin == NULL && usesearch) {
1801 lookup->origin = ISC_LIST_HEAD(search_list);
1802 lookup->need_search = ISC_FALSE;
1804 #else
1805 if ((count_dots(lookup->textname) >= ndots) || !usesearch) {
1806 lookup->origin = NULL; /* Force abs lookup */
1807 lookup->done_as_is = ISC_TRUE;
1808 lookup->need_search = usesearch;
1809 } else if (lookup->origin == NULL && usesearch) {
1810 lookup->origin = ISC_LIST_HEAD(search_list);
1811 lookup->need_search = ISC_FALSE;
1813 #endif
1816 #ifdef WITH_IDN
1817 if (lookup->origin != NULL) {
1818 mr = idn_encodename(IDN_LOCALCONV | IDN_DELIMMAP,
1819 lookup->origin->origin, utf8_origin,
1820 sizeof(utf8_origin));
1821 idn_check_result(mr, "convert origin to UTF-8");
1822 mr = append_textname(utf8_textname, utf8_origin,
1823 sizeof(utf8_textname));
1824 idn_check_result(mr, "append origin to textname");
1826 mr = idn_encodename(idnoptions | IDN_LOCALMAP | IDN_NAMEPREP |
1827 IDN_IDNCONV | IDN_LENCHECK, utf8_textname,
1828 idn_textname, sizeof(idn_textname));
1829 idn_check_result(mr, "convert UTF-8 textname to IDN encoding");
1830 #else
1831 if (lookup->origin != NULL) {
1832 debug("trying origin %s", lookup->origin->origin);
1833 result = dns_message_gettempname(lookup->sendmsg,
1834 &lookup->oname);
1835 check_result(result, "dns_message_gettempname");
1836 dns_name_init(lookup->oname, NULL);
1837 /* XXX Helper funct to conv char* to name? */
1838 len = strlen(lookup->origin->origin);
1839 isc_buffer_init(&b, lookup->origin->origin, len);
1840 isc_buffer_add(&b, len);
1841 result = dns_name_fromtext(lookup->oname, &b, dns_rootname,
1842 ISC_FALSE, &lookup->onamebuf);
1843 if (result != ISC_R_SUCCESS) {
1844 dns_message_puttempname(lookup->sendmsg,
1845 &lookup->name);
1846 dns_message_puttempname(lookup->sendmsg,
1847 &lookup->oname);
1848 fatal("'%s' is not in legal name syntax (%s)",
1849 lookup->origin->origin,
1850 isc_result_totext(result));
1852 if (lookup->trace && lookup->trace_root) {
1853 dns_name_clone(dns_rootname, lookup->name);
1854 } else {
1855 len = strlen(lookup->textname);
1856 isc_buffer_init(&b, lookup->textname, len);
1857 isc_buffer_add(&b, len);
1858 result = dns_name_fromtext(lookup->name, &b,
1859 lookup->oname, ISC_FALSE,
1860 &lookup->namebuf);
1862 if (result != ISC_R_SUCCESS) {
1863 dns_message_puttempname(lookup->sendmsg,
1864 &lookup->name);
1865 dns_message_puttempname(lookup->sendmsg,
1866 &lookup->oname);
1867 fatal("'%s' is not in legal name syntax (%s)",
1868 lookup->textname, isc_result_totext(result));
1870 dns_message_puttempname(lookup->sendmsg, &lookup->oname);
1871 } else
1872 #endif
1874 debug("using root origin");
1875 if (lookup->trace && lookup->trace_root)
1876 dns_name_clone(dns_rootname, lookup->name);
1877 else {
1878 #ifdef WITH_IDN
1879 len = strlen(idn_textname);
1880 isc_buffer_init(&b, idn_textname, len);
1881 isc_buffer_add(&b, len);
1882 result = dns_name_fromtext(lookup->name, &b,
1883 dns_rootname,
1884 ISC_FALSE,
1885 &lookup->namebuf);
1886 #else
1887 len = strlen(lookup->textname);
1888 isc_buffer_init(&b, lookup->textname, len);
1889 isc_buffer_add(&b, len);
1890 result = dns_name_fromtext(lookup->name, &b,
1891 dns_rootname,
1892 ISC_FALSE,
1893 &lookup->namebuf);
1894 #endif
1896 if (result != ISC_R_SUCCESS) {
1897 dns_message_puttempname(lookup->sendmsg,
1898 &lookup->name);
1899 isc_buffer_init(&b, store, MXNAME);
1900 fatal("'%s' is not a legal name "
1901 "(%s)", lookup->textname,
1902 isc_result_totext(result));
1905 dns_name_format(lookup->name, store, sizeof(store));
1906 trying(store, lookup);
1907 INSIST(dns_name_isabsolute(lookup->name));
1909 isc_random_get(&id);
1910 lookup->sendmsg->id = (unsigned short)id & 0xFFFF;
1911 lookup->sendmsg->opcode = dns_opcode_query;
1912 lookup->msgcounter = 0;
1914 * If this is a trace request, completely disallow recursion, since
1915 * it's meaningless for traces.
1917 if (lookup->trace || (lookup->ns_search_only && !lookup->trace_root))
1918 lookup->recurse = ISC_FALSE;
1920 if (lookup->recurse &&
1921 lookup->rdtype != dns_rdatatype_axfr &&
1922 lookup->rdtype != dns_rdatatype_ixfr) {
1923 debug("recursive query");
1924 lookup->sendmsg->flags |= DNS_MESSAGEFLAG_RD;
1927 /* XXX aaflag */
1928 if (lookup->aaonly) {
1929 debug("AA query");
1930 lookup->sendmsg->flags |= DNS_MESSAGEFLAG_AA;
1933 if (lookup->adflag) {
1934 debug("AD query");
1935 lookup->sendmsg->flags |= DNS_MESSAGEFLAG_AD;
1938 if (lookup->cdflag) {
1939 debug("CD query");
1940 lookup->sendmsg->flags |= DNS_MESSAGEFLAG_CD;
1943 dns_message_addname(lookup->sendmsg, lookup->name,
1944 DNS_SECTION_QUESTION);
1946 if (lookup->trace && lookup->trace_root) {
1947 lookup->qrdtype = lookup->rdtype;
1948 lookup->rdtype = dns_rdatatype_ns;
1951 if ((lookup->rdtype == dns_rdatatype_axfr) ||
1952 (lookup->rdtype == dns_rdatatype_ixfr)) {
1953 lookup->doing_xfr = ISC_TRUE;
1955 * Force TCP mode if we're doing an xfr.
1956 * XXX UDP ixfr's would be useful
1958 lookup->tcp_mode = ISC_TRUE;
1961 add_question(lookup->sendmsg, lookup->name, lookup->rdclass,
1962 lookup->rdtype);
1964 /* add_soa */
1965 if (lookup->rdtype == dns_rdatatype_ixfr)
1966 insert_soa(lookup);
1968 /* XXX Insist this? */
1969 lookup->tsigctx = NULL;
1970 lookup->querysig = NULL;
1971 if (key != NULL) {
1972 debug("initializing keys");
1973 result = dns_message_settsigkey(lookup->sendmsg, key);
1974 check_result(result, "dns_message_settsigkey");
1977 lookup->sendspace = isc_mempool_get(commctx);
1978 if (lookup->sendspace == NULL)
1979 fatal("memory allocation failure");
1981 result = dns_compress_init(&cctx, -1, mctx);
1982 check_result(result, "dns_compress_init");
1984 debug("starting to render the message");
1985 isc_buffer_init(&lookup->renderbuf, lookup->sendspace, COMMSIZE);
1986 result = dns_message_renderbegin(lookup->sendmsg, &cctx,
1987 &lookup->renderbuf);
1988 check_result(result, "dns_message_renderbegin");
1989 if (lookup->udpsize > 0 || lookup->dnssec || lookup->edns > -1) {
1990 if (lookup->udpsize == 0)
1991 lookup->udpsize = 4096;
1992 if (lookup->edns < 0)
1993 lookup->edns = 0;
1994 add_opt(lookup->sendmsg, lookup->udpsize,
1995 lookup->edns, lookup->dnssec);
1998 result = dns_message_rendersection(lookup->sendmsg,
1999 DNS_SECTION_QUESTION, 0);
2000 check_result(result, "dns_message_rendersection");
2001 result = dns_message_rendersection(lookup->sendmsg,
2002 DNS_SECTION_AUTHORITY, 0);
2003 check_result(result, "dns_message_rendersection");
2004 result = dns_message_renderend(lookup->sendmsg);
2005 check_result(result, "dns_message_renderend");
2006 debug("done rendering");
2008 dns_compress_invalidate(&cctx);
2011 * Force TCP mode if the request is larger than 512 bytes.
2013 if (isc_buffer_usedlength(&lookup->renderbuf) > 512)
2014 lookup->tcp_mode = ISC_TRUE;
2016 lookup->pending = ISC_FALSE;
2018 for (serv = ISC_LIST_HEAD(lookup->my_server_list);
2019 serv != NULL;
2020 serv = ISC_LIST_NEXT(serv, link)) {
2021 query = isc_mem_allocate(mctx, sizeof(dig_query_t));
2022 if (query == NULL)
2023 fatal("memory allocation failure in %s:%d",
2024 __FILE__, __LINE__);
2025 debug("create query %p linked to lookup %p",
2026 query, lookup);
2027 query->lookup = lookup;
2028 query->waiting_connect = ISC_FALSE;
2029 query->waiting_senddone = ISC_FALSE;
2030 query->pending_free = ISC_FALSE;
2031 query->recv_made = ISC_FALSE;
2032 query->first_pass = ISC_TRUE;
2033 query->first_soa_rcvd = ISC_FALSE;
2034 query->second_rr_rcvd = ISC_FALSE;
2035 query->first_repeat_rcvd = ISC_FALSE;
2036 query->warn_id = ISC_TRUE;
2037 query->first_rr_serial = 0;
2038 query->second_rr_serial = 0;
2039 query->servname = serv->servername;
2040 query->userarg = serv->userarg;
2041 query->rr_count = 0;
2042 query->msg_count = 0;
2043 query->byte_count = 0;
2044 ISC_LINK_INIT(query, link);
2045 ISC_LIST_INIT(query->recvlist);
2046 ISC_LIST_INIT(query->lengthlist);
2047 query->sock = NULL;
2048 query->recvspace = isc_mempool_get(commctx);
2049 if (query->recvspace == NULL)
2050 fatal("memory allocation failure");
2052 isc_buffer_init(&query->recvbuf, query->recvspace, COMMSIZE);
2053 isc_buffer_init(&query->lengthbuf, query->lengthspace, 2);
2054 isc_buffer_init(&query->slbuf, query->slspace, 2);
2055 query->sendbuf = lookup->renderbuf;
2057 ISC_LINK_INIT(query, link);
2058 ISC_LIST_ENQUEUE(lookup->q, query, link);
2060 /* XXX qrflag, print_query, etc... */
2061 if (!ISC_LIST_EMPTY(lookup->q) && qr) {
2062 extrabytes = 0;
2063 printmessage(ISC_LIST_HEAD(lookup->q), lookup->sendmsg,
2064 ISC_TRUE);
2069 * Event handler for send completion. Track send counter, and clear out
2070 * the query if the send was canceled.
2072 static void
2073 send_done(isc_task_t *_task, isc_event_t *event) {
2074 isc_socketevent_t *sevent = (isc_socketevent_t *)event;
2075 isc_buffer_t *b = NULL;
2076 dig_query_t *query, *next;
2077 dig_lookup_t *l;
2079 REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE);
2081 UNUSED(_task);
2083 LOCK_LOOKUP;
2085 debug("send_done()");
2086 sendcount--;
2087 debug("sendcount=%d", sendcount);
2088 INSIST(sendcount >= 0);
2090 for (b = ISC_LIST_HEAD(sevent->bufferlist);
2091 b != NULL;
2092 b = ISC_LIST_HEAD(sevent->bufferlist))
2093 ISC_LIST_DEQUEUE(sevent->bufferlist, b, link);
2095 query = event->ev_arg;
2096 query->waiting_senddone = ISC_FALSE;
2097 l = query->lookup;
2099 if (l->ns_search_only && !l->trace_root) {
2100 debug("sending next, since searching");
2101 next = ISC_LIST_NEXT(query, link);
2102 if (next != NULL)
2103 send_udp(next);
2106 isc_event_free(&event);
2108 if (query->pending_free)
2109 isc_mem_free(mctx, query);
2111 check_if_done();
2112 UNLOCK_LOOKUP;
2116 * Cancel a lookup, sending isc_socket_cancel() requests to all outstanding
2117 * IO sockets. The cancel handlers should take care of cleaning up the
2118 * query and lookup structures
2120 static void
2121 cancel_lookup(dig_lookup_t *lookup) {
2122 dig_query_t *query, *next;
2124 debug("cancel_lookup()");
2125 query = ISC_LIST_HEAD(lookup->q);
2126 while (query != NULL) {
2127 next = ISC_LIST_NEXT(query, link);
2128 if (query->sock != NULL) {
2129 isc_socket_cancel(query->sock, global_task,
2130 ISC_SOCKCANCEL_ALL);
2131 check_if_done();
2132 } else {
2133 clear_query(query);
2135 query = next;
2137 if (lookup->timer != NULL)
2138 isc_timer_detach(&lookup->timer);
2139 lookup->pending = ISC_FALSE;
2140 lookup->retries = 0;
2143 static void
2144 bringup_timer(dig_query_t *query, unsigned int default_timeout) {
2145 dig_lookup_t *l;
2146 unsigned int local_timeout;
2147 isc_result_t result;
2149 debug("bringup_timer()");
2151 * If the timer already exists, that means we're calling this
2152 * a second time (for a retry). Don't need to recreate it,
2153 * just reset it.
2155 l = query->lookup;
2156 if (ISC_LIST_NEXT(query, link) != NULL)
2157 local_timeout = SERVER_TIMEOUT;
2158 else {
2159 if (timeout == 0)
2160 local_timeout = default_timeout;
2161 else
2162 local_timeout = timeout;
2164 debug("have local timeout of %d", local_timeout);
2165 isc_interval_set(&l->interval, local_timeout, 0);
2166 if (l->timer != NULL)
2167 isc_timer_detach(&l->timer);
2168 result = isc_timer_create(timermgr, isc_timertype_once, NULL,
2169 &l->interval, global_task, connect_timeout,
2170 l, &l->timer);
2171 check_result(result, "isc_timer_create");
2174 static void
2175 connect_done(isc_task_t *task, isc_event_t *event);
2178 * Unlike send_udp, this can't be called multiple times with the same
2179 * query. When we retry TCP, we requeue the whole lookup, which should
2180 * start anew.
2182 static void
2183 send_tcp_connect(dig_query_t *query) {
2184 isc_result_t result;
2185 dig_query_t *next;
2186 dig_lookup_t *l;
2188 debug("send_tcp_connect(%p)", query);
2190 l = query->lookup;
2191 query->waiting_connect = ISC_TRUE;
2192 query->lookup->current_query = query;
2193 get_address(query->servname, port, &query->sockaddr);
2195 if (specified_source &&
2196 (isc_sockaddr_pf(&query->sockaddr) !=
2197 isc_sockaddr_pf(&bind_address))) {
2198 printf(";; Skipping server %s, incompatible "
2199 "address family\n", query->servname);
2200 query->waiting_connect = ISC_FALSE;
2201 next = ISC_LIST_NEXT(query, link);
2202 l = query->lookup;
2203 clear_query(query);
2204 if (next == NULL) {
2205 printf(";; No acceptable nameservers\n");
2206 check_next_lookup(l);
2207 return;
2209 send_tcp_connect(next);
2210 return;
2212 INSIST(query->sock == NULL);
2213 result = isc_socket_create(socketmgr,
2214 isc_sockaddr_pf(&query->sockaddr),
2215 isc_sockettype_tcp, &query->sock);
2216 check_result(result, "isc_socket_create");
2217 sockcount++;
2218 debug("sockcount=%d", sockcount);
2219 if (specified_source)
2220 result = isc_socket_bind(query->sock, &bind_address,
2221 ISC_SOCKET_REUSEADDRESS);
2222 else {
2223 if ((isc_sockaddr_pf(&query->sockaddr) == AF_INET) &&
2224 have_ipv4)
2225 isc_sockaddr_any(&bind_any);
2226 else
2227 isc_sockaddr_any6(&bind_any);
2228 result = isc_socket_bind(query->sock, &bind_any, 0);
2230 check_result(result, "isc_socket_bind");
2231 bringup_timer(query, TCP_TIMEOUT);
2232 result = isc_socket_connect(query->sock, &query->sockaddr,
2233 global_task, connect_done, query);
2234 check_result(result, "isc_socket_connect");
2236 * If we're at the endgame of a nameserver search, we need to
2237 * immediately bring up all the queries. Do it here.
2239 if (l->ns_search_only && !l->trace_root) {
2240 debug("sending next, since searching");
2241 next = ISC_LIST_NEXT(query, link);
2242 if (next != NULL)
2243 send_tcp_connect(next);
2248 * Send a UDP packet to the remote nameserver, possible starting the
2249 * recv action as well. Also make sure that the timer is running and
2250 * is properly reset.
2252 static void
2253 send_udp(dig_query_t *query) {
2254 dig_lookup_t *l = NULL;
2255 isc_result_t result;
2257 debug("send_udp(%p)", query);
2259 l = query->lookup;
2260 bringup_timer(query, UDP_TIMEOUT);
2261 l->current_query = query;
2262 debug("working on lookup %p, query %p", query->lookup, query);
2263 if (!query->recv_made) {
2264 /* XXX Check the sense of this, need assertion? */
2265 query->waiting_connect = ISC_FALSE;
2266 get_address(query->servname, port, &query->sockaddr);
2268 result = isc_socket_create(socketmgr,
2269 isc_sockaddr_pf(&query->sockaddr),
2270 isc_sockettype_udp, &query->sock);
2271 check_result(result, "isc_socket_create");
2272 sockcount++;
2273 debug("sockcount=%d", sockcount);
2274 if (specified_source) {
2275 result = isc_socket_bind(query->sock, &bind_address,
2276 ISC_SOCKET_REUSEADDRESS);
2277 } else {
2278 isc_sockaddr_anyofpf(&bind_any,
2279 isc_sockaddr_pf(&query->sockaddr));
2280 result = isc_socket_bind(query->sock, &bind_any, 0);
2282 check_result(result, "isc_socket_bind");
2284 query->recv_made = ISC_TRUE;
2285 ISC_LINK_INIT(&query->recvbuf, link);
2286 ISC_LIST_ENQUEUE(query->recvlist, &query->recvbuf,
2287 link);
2288 debug("recving with lookup=%p, query=%p, sock=%p",
2289 query->lookup, query, query->sock);
2290 result = isc_socket_recvv(query->sock, &query->recvlist, 1,
2291 global_task, recv_done, query);
2292 check_result(result, "isc_socket_recvv");
2293 recvcount++;
2294 debug("recvcount=%d", recvcount);
2296 ISC_LIST_INIT(query->sendlist);
2297 ISC_LIST_ENQUEUE(query->sendlist, &query->sendbuf, link);
2298 debug("sending a request");
2299 TIME_NOW(&query->time_sent);
2300 INSIST(query->sock != NULL);
2301 query->waiting_senddone = ISC_TRUE;
2302 result = isc_socket_sendtov(query->sock, &query->sendlist,
2303 global_task, send_done, query,
2304 &query->sockaddr, NULL);
2305 check_result(result, "isc_socket_sendtov");
2306 sendcount++;
2310 * IO timeout handler, used for both connect and recv timeouts. If
2311 * retries are still allowed, either resend the UDP packet or queue a
2312 * new TCP lookup. Otherwise, cancel the lookup.
2314 static void
2315 connect_timeout(isc_task_t *task, isc_event_t *event) {
2316 dig_lookup_t *l = NULL;
2317 dig_query_t *query = NULL, *cq;
2319 UNUSED(task);
2320 REQUIRE(event->ev_type == ISC_TIMEREVENT_IDLE);
2322 debug("connect_timeout()");
2324 LOCK_LOOKUP;
2325 l = event->ev_arg;
2326 query = l->current_query;
2327 isc_event_free(&event);
2329 INSIST(!free_now);
2331 if ((query != NULL) && (query->lookup->current_query != NULL) &&
2332 (ISC_LIST_NEXT(query->lookup->current_query, link) != NULL)) {
2333 debug("trying next server...");
2334 cq = query->lookup->current_query;
2335 if (!l->tcp_mode)
2336 send_udp(ISC_LIST_NEXT(cq, link));
2337 else
2338 send_tcp_connect(ISC_LIST_NEXT(cq, link));
2339 UNLOCK_LOOKUP;
2340 return;
2343 if (l->retries > 1) {
2344 if (!l->tcp_mode) {
2345 l->retries--;
2346 debug("resending UDP request to first server");
2347 send_udp(ISC_LIST_HEAD(l->q));
2348 } else {
2349 debug("making new TCP request, %d tries left",
2350 l->retries);
2351 l->retries--;
2352 requeue_lookup(l, ISC_TRUE);
2353 cancel_lookup(l);
2354 check_next_lookup(l);
2356 } else {
2357 fputs(l->cmdline, stdout);
2358 printf(";; connection timed out; no servers could be "
2359 "reached\n");
2360 cancel_lookup(l);
2361 check_next_lookup(l);
2362 if (exitcode < 9)
2363 exitcode = 9;
2365 UNLOCK_LOOKUP;
2369 * Event handler for the TCP recv which gets the length header of TCP
2370 * packets. Start the next recv of length bytes.
2372 static void
2373 tcp_length_done(isc_task_t *task, isc_event_t *event) {
2374 isc_socketevent_t *sevent;
2375 isc_buffer_t *b = NULL;
2376 isc_result_t result;
2377 dig_query_t *query = NULL;
2378 dig_lookup_t *l;
2379 isc_uint16_t length;
2381 REQUIRE(event->ev_type == ISC_SOCKEVENT_RECVDONE);
2382 INSIST(!free_now);
2384 UNUSED(task);
2386 debug("tcp_length_done()");
2388 LOCK_LOOKUP;
2389 sevent = (isc_socketevent_t *)event;
2390 query = event->ev_arg;
2392 recvcount--;
2393 INSIST(recvcount >= 0);
2395 b = ISC_LIST_HEAD(sevent->bufferlist);
2396 INSIST(b == &query->lengthbuf);
2397 ISC_LIST_DEQUEUE(sevent->bufferlist, b, link);
2399 if (sevent->result == ISC_R_CANCELED) {
2400 isc_event_free(&event);
2401 l = query->lookup;
2402 clear_query(query);
2403 check_next_lookup(l);
2404 UNLOCK_LOOKUP;
2405 return;
2407 if (sevent->result != ISC_R_SUCCESS) {
2408 char sockstr[ISC_SOCKADDR_FORMATSIZE];
2409 isc_sockaddr_format(&query->sockaddr, sockstr,
2410 sizeof(sockstr));
2411 printf(";; communications error to %s: %s\n",
2412 sockstr, isc_result_totext(sevent->result));
2413 l = query->lookup;
2414 isc_socket_detach(&query->sock);
2415 sockcount--;
2416 debug("sockcount=%d", sockcount);
2417 INSIST(sockcount >= 0);
2418 isc_event_free(&event);
2419 clear_query(query);
2420 check_next_lookup(l);
2421 UNLOCK_LOOKUP;
2422 return;
2424 length = isc_buffer_getuint16(b);
2425 if (length == 0) {
2426 isc_event_free(&event);
2427 launch_next_query(query, ISC_FALSE);
2428 UNLOCK_LOOKUP;
2429 return;
2433 * Even though the buffer was already init'ed, we need
2434 * to redo it now, to force the length we want.
2436 isc_buffer_invalidate(&query->recvbuf);
2437 isc_buffer_init(&query->recvbuf, query->recvspace, length);
2438 ENSURE(ISC_LIST_EMPTY(query->recvlist));
2439 ISC_LINK_INIT(&query->recvbuf, link);
2440 ISC_LIST_ENQUEUE(query->recvlist, &query->recvbuf, link);
2441 debug("recving with lookup=%p, query=%p", query->lookup, query);
2442 result = isc_socket_recvv(query->sock, &query->recvlist, length, task,
2443 recv_done, query);
2444 check_result(result, "isc_socket_recvv");
2445 recvcount++;
2446 debug("resubmitted recv request with length %d, recvcount=%d",
2447 length, recvcount);
2448 isc_event_free(&event);
2449 UNLOCK_LOOKUP;
2453 * For transfers that involve multiple recvs (XFR's in particular),
2454 * launch the next recv.
2456 static void
2457 launch_next_query(dig_query_t *query, isc_boolean_t include_question) {
2458 isc_result_t result;
2459 dig_lookup_t *l;
2461 INSIST(!free_now);
2463 debug("launch_next_query()");
2465 if (!query->lookup->pending) {
2466 debug("ignoring launch_next_query because !pending");
2467 isc_socket_detach(&query->sock);
2468 sockcount--;
2469 debug("sockcount=%d", sockcount);
2470 INSIST(sockcount >= 0);
2471 query->waiting_connect = ISC_FALSE;
2472 l = query->lookup;
2473 clear_query(query);
2474 check_next_lookup(l);
2475 return;
2478 isc_buffer_clear(&query->slbuf);
2479 isc_buffer_clear(&query->lengthbuf);
2480 isc_buffer_putuint16(&query->slbuf, (isc_uint16_t) query->sendbuf.used);
2481 ISC_LIST_INIT(query->sendlist);
2482 ISC_LINK_INIT(&query->slbuf, link);
2483 ISC_LIST_ENQUEUE(query->sendlist, &query->slbuf, link);
2484 if (include_question)
2485 ISC_LIST_ENQUEUE(query->sendlist, &query->sendbuf, link);
2486 ISC_LINK_INIT(&query->lengthbuf, link);
2487 ISC_LIST_ENQUEUE(query->lengthlist, &query->lengthbuf, link);
2489 result = isc_socket_recvv(query->sock, &query->lengthlist, 0,
2490 global_task, tcp_length_done, query);
2491 check_result(result, "isc_socket_recvv");
2492 recvcount++;
2493 debug("recvcount=%d", recvcount);
2494 if (!query->first_soa_rcvd) {
2495 debug("sending a request in launch_next_query");
2496 TIME_NOW(&query->time_sent);
2497 query->waiting_senddone = ISC_TRUE;
2498 result = isc_socket_sendv(query->sock, &query->sendlist,
2499 global_task, send_done, query);
2500 check_result(result, "isc_socket_sendv");
2501 sendcount++;
2502 debug("sendcount=%d", sendcount);
2504 query->waiting_connect = ISC_FALSE;
2505 #if 0
2506 check_next_lookup(query->lookup);
2507 #endif
2508 return;
2512 * Event handler for TCP connect complete. Make sure the connection was
2513 * successful, then pass into launch_next_query to actually send the
2514 * question.
2516 static void
2517 connect_done(isc_task_t *task, isc_event_t *event) {
2518 isc_socketevent_t *sevent = NULL;
2519 dig_query_t *query = NULL, *next;
2520 dig_lookup_t *l;
2522 UNUSED(task);
2524 REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT);
2525 INSIST(!free_now);
2527 debug("connect_done()");
2529 LOCK_LOOKUP;
2530 sevent = (isc_socketevent_t *)event;
2531 query = sevent->ev_arg;
2533 INSIST(query->waiting_connect);
2535 query->waiting_connect = ISC_FALSE;
2537 if (sevent->result == ISC_R_CANCELED) {
2538 debug("in cancel handler");
2539 isc_socket_detach(&query->sock);
2540 sockcount--;
2541 INSIST(sockcount >= 0);
2542 debug("sockcount=%d", sockcount);
2543 query->waiting_connect = ISC_FALSE;
2544 isc_event_free(&event);
2545 l = query->lookup;
2546 clear_query(query);
2547 check_next_lookup(l);
2548 UNLOCK_LOOKUP;
2549 return;
2551 if (sevent->result != ISC_R_SUCCESS) {
2552 char sockstr[ISC_SOCKADDR_FORMATSIZE];
2554 debug("unsuccessful connection: %s",
2555 isc_result_totext(sevent->result));
2556 isc_sockaddr_format(&query->sockaddr, sockstr, sizeof(sockstr));
2557 if (sevent->result != ISC_R_CANCELED)
2558 printf(";; Connection to %s(%s) for %s failed: "
2559 "%s.\n", sockstr,
2560 query->servname, query->lookup->textname,
2561 isc_result_totext(sevent->result));
2562 isc_socket_detach(&query->sock);
2563 sockcount--;
2564 INSIST(sockcount >= 0);
2565 /* XXX Clean up exitcodes */
2566 if (exitcode < 9)
2567 exitcode = 9;
2568 debug("sockcount=%d", sockcount);
2569 query->waiting_connect = ISC_FALSE;
2570 isc_event_free(&event);
2571 l = query->lookup;
2572 if (l->current_query != NULL)
2573 next = ISC_LIST_NEXT(l->current_query, link);
2574 else
2575 next = NULL;
2576 clear_query(query);
2577 if (next != NULL) {
2578 bringup_timer(next, TCP_TIMEOUT);
2579 send_tcp_connect(next);
2580 } else {
2581 check_next_lookup(l);
2583 UNLOCK_LOOKUP;
2584 return;
2586 launch_next_query(query, ISC_TRUE);
2587 isc_event_free(&event);
2588 UNLOCK_LOOKUP;
2592 * Check if the ongoing XFR needs more data before it's complete, using
2593 * the semantics of IXFR and AXFR protocols. Much of the complexity of
2594 * this routine comes from determining when an IXFR is complete.
2595 * ISC_FALSE means more data is on the way, and the recv has been issued.
2597 static isc_boolean_t
2598 check_for_more_data(dig_query_t *query, dns_message_t *msg,
2599 isc_socketevent_t *sevent)
2601 dns_rdataset_t *rdataset = NULL;
2602 dns_rdata_t rdata = DNS_RDATA_INIT;
2603 dns_rdata_soa_t soa;
2604 isc_uint32_t serial;
2605 isc_result_t result;
2607 debug("check_for_more_data()");
2610 * By the time we're in this routine, we know we're doing
2611 * either an AXFR or IXFR. If there's no second_rr_type,
2612 * then we don't yet know which kind of answer we got back
2613 * from the server. Here, we're going to walk through the
2614 * rr's in the message, acting as necessary whenever we hit
2615 * an SOA rr.
2618 query->msg_count++;
2619 query->byte_count += sevent->n;
2620 result = dns_message_firstname(msg, DNS_SECTION_ANSWER);
2621 if (result != ISC_R_SUCCESS) {
2622 puts("; Transfer failed.");
2623 return (ISC_TRUE);
2625 do {
2626 dns_name_t *name;
2627 name = NULL;
2628 dns_message_currentname(msg, DNS_SECTION_ANSWER,
2629 &name);
2630 for (rdataset = ISC_LIST_HEAD(name->list);
2631 rdataset != NULL;
2632 rdataset = ISC_LIST_NEXT(rdataset, link)) {
2633 result = dns_rdataset_first(rdataset);
2634 if (result != ISC_R_SUCCESS)
2635 continue;
2636 do {
2637 query->rr_count++;
2638 dns_rdata_reset(&rdata);
2639 dns_rdataset_current(rdataset, &rdata);
2641 * If this is the first rr, make sure
2642 * it's an SOA
2644 if ((!query->first_soa_rcvd) &&
2645 (rdata.type != dns_rdatatype_soa)) {
2646 puts("; Transfer failed. "
2647 "Didn't start with SOA answer.");
2648 return (ISC_TRUE);
2650 if ((!query->second_rr_rcvd) &&
2651 (rdata.type != dns_rdatatype_soa)) {
2652 query->second_rr_rcvd = ISC_TRUE;
2653 query->second_rr_serial = 0;
2654 debug("got the second rr as nonsoa");
2655 goto next_rdata;
2659 * If the record is anything except an SOA
2660 * now, just continue on...
2662 if (rdata.type != dns_rdatatype_soa)
2663 goto next_rdata;
2664 /* Now we have an SOA. Work with it. */
2665 debug("got an SOA");
2666 (void)dns_rdata_tostruct(&rdata, &soa, NULL);
2667 serial = soa.serial;
2668 dns_rdata_freestruct(&soa);
2669 if (!query->first_soa_rcvd) {
2670 query->first_soa_rcvd = ISC_TRUE;
2671 query->first_rr_serial = serial;
2672 debug("this is the first %d",
2673 query->lookup->ixfr_serial);
2674 if (query->lookup->ixfr_serial >=
2675 serial)
2676 goto doexit;
2677 goto next_rdata;
2679 if (query->lookup->rdtype ==
2680 dns_rdatatype_axfr) {
2681 debug("doing axfr, got second SOA");
2682 goto doexit;
2684 if (!query->second_rr_rcvd) {
2685 if (query->first_rr_serial == serial) {
2686 debug("doing ixfr, got "
2687 "empty zone");
2688 goto doexit;
2690 debug("this is the second %d",
2691 query->lookup->ixfr_serial);
2692 query->second_rr_rcvd = ISC_TRUE;
2693 query->second_rr_serial = serial;
2694 goto next_rdata;
2696 if (query->second_rr_serial == 0) {
2698 * If the second RR was a non-SOA
2699 * record, and we're getting any
2700 * other SOA, then this is an
2701 * AXFR, and we're done.
2703 debug("done, since axfr");
2704 goto doexit;
2707 * If we get to this point, we're doing an
2708 * IXFR and have to start really looking
2709 * at serial numbers.
2711 if (query->first_rr_serial == serial) {
2712 debug("got a match for ixfr");
2713 if (!query->first_repeat_rcvd) {
2714 query->first_repeat_rcvd =
2715 ISC_TRUE;
2716 goto next_rdata;
2718 debug("done with ixfr");
2719 goto doexit;
2721 debug("meaningless soa %d", serial);
2722 next_rdata:
2723 result = dns_rdataset_next(rdataset);
2724 } while (result == ISC_R_SUCCESS);
2726 result = dns_message_nextname(msg, DNS_SECTION_ANSWER);
2727 } while (result == ISC_R_SUCCESS);
2728 launch_next_query(query, ISC_FALSE);
2729 return (ISC_FALSE);
2730 doexit:
2731 received(sevent->n, &sevent->address, query);
2732 return (ISC_TRUE);
2736 * Event handler for recv complete. Perform whatever actions are necessary,
2737 * based on the specifics of the user's request.
2739 static void
2740 recv_done(isc_task_t *task, isc_event_t *event) {
2741 isc_socketevent_t *sevent = NULL;
2742 dig_query_t *query = NULL;
2743 isc_buffer_t *b = NULL;
2744 dns_message_t *msg = NULL;
2745 #ifdef DIG_SIGCHASE
2746 dig_message_t *chase_msg = NULL;
2747 dig_message_t *chase_msg2 = NULL;
2748 #endif
2749 isc_result_t result;
2750 dig_lookup_t *n, *l;
2751 isc_boolean_t docancel = ISC_FALSE;
2752 isc_boolean_t match = ISC_TRUE;
2753 unsigned int parseflags;
2754 dns_messageid_t id;
2755 unsigned int msgflags;
2756 #ifdef DIG_SIGCHASE
2757 isc_result_t do_sigchase = ISC_FALSE;
2759 dns_message_t *msg_temp = NULL;
2760 isc_region_t r;
2761 isc_buffer_t *buf = NULL;
2762 #endif
2764 UNUSED(task);
2765 INSIST(!free_now);
2767 debug("recv_done()");
2769 LOCK_LOOKUP;
2770 recvcount--;
2771 debug("recvcount=%d", recvcount);
2772 INSIST(recvcount >= 0);
2774 query = event->ev_arg;
2775 debug("lookup=%p, query=%p", query->lookup, query);
2777 l = query->lookup;
2779 REQUIRE(event->ev_type == ISC_SOCKEVENT_RECVDONE);
2780 sevent = (isc_socketevent_t *)event;
2782 b = ISC_LIST_HEAD(sevent->bufferlist);
2783 INSIST(b == &query->recvbuf);
2784 ISC_LIST_DEQUEUE(sevent->bufferlist, &query->recvbuf, link);
2786 if ((l->tcp_mode) && (l->timer != NULL))
2787 isc_timer_touch(l->timer);
2788 if ((!l->pending && !l->ns_search_only) || cancel_now) {
2789 debug("no longer pending. Got %s",
2790 isc_result_totext(sevent->result));
2791 query->waiting_connect = ISC_FALSE;
2793 isc_event_free(&event);
2794 clear_query(query);
2795 check_next_lookup(l);
2796 UNLOCK_LOOKUP;
2797 return;
2800 if (sevent->result != ISC_R_SUCCESS) {
2801 if (sevent->result == ISC_R_CANCELED) {
2802 debug("in recv cancel handler");
2803 query->waiting_connect = ISC_FALSE;
2804 } else {
2805 printf(";; communications error: %s\n",
2806 isc_result_totext(sevent->result));
2807 isc_socket_detach(&query->sock);
2808 sockcount--;
2809 debug("sockcount=%d", sockcount);
2810 INSIST(sockcount >= 0);
2812 isc_event_free(&event);
2813 clear_query(query);
2814 check_next_lookup(l);
2815 UNLOCK_LOOKUP;
2816 return;
2819 if (!l->tcp_mode &&
2820 !isc_sockaddr_compare(&sevent->address, &query->sockaddr,
2821 ISC_SOCKADDR_CMPADDR|
2822 ISC_SOCKADDR_CMPPORT|
2823 ISC_SOCKADDR_CMPSCOPE|
2824 ISC_SOCKADDR_CMPSCOPEZERO)) {
2825 char buf1[ISC_SOCKADDR_FORMATSIZE];
2826 char buf2[ISC_SOCKADDR_FORMATSIZE];
2827 isc_sockaddr_t any;
2829 if (isc_sockaddr_pf(&query->sockaddr) == AF_INET)
2830 isc_sockaddr_any(&any);
2831 else
2832 isc_sockaddr_any6(&any);
2835 * We don't expect a match when the packet is
2836 * sent to 0.0.0.0, :: or to a multicast addresses.
2837 * XXXMPA broadcast needs to be handled here as well.
2839 if ((!isc_sockaddr_eqaddr(&query->sockaddr, &any) &&
2840 !isc_sockaddr_ismulticast(&query->sockaddr)) ||
2841 isc_sockaddr_getport(&query->sockaddr) !=
2842 isc_sockaddr_getport(&sevent->address)) {
2843 isc_sockaddr_format(&sevent->address, buf1,
2844 sizeof(buf1));
2845 isc_sockaddr_format(&query->sockaddr, buf2,
2846 sizeof(buf2));
2847 printf(";; reply from unexpected source: %s,"
2848 " expected %s\n", buf1, buf2);
2849 match = ISC_FALSE;
2853 result = dns_message_peekheader(b, &id, &msgflags);
2854 if (result != ISC_R_SUCCESS || l->sendmsg->id != id) {
2855 match = ISC_FALSE;
2856 if (l->tcp_mode) {
2857 isc_boolean_t fail = ISC_TRUE;
2858 if (result == ISC_R_SUCCESS) {
2859 if (!query->first_soa_rcvd ||
2860 query->warn_id)
2861 printf(";; %s: ID mismatch: "
2862 "expected ID %u, got %u\n",
2863 query->first_soa_rcvd ?
2864 "WARNING" : "ERROR",
2865 l->sendmsg->id, id);
2866 if (query->first_soa_rcvd)
2867 fail = ISC_FALSE;
2868 query->warn_id = ISC_FALSE;
2869 } else
2870 printf(";; ERROR: short "
2871 "(< header size) message\n");
2872 if (fail) {
2873 isc_event_free(&event);
2874 clear_query(query);
2875 check_next_lookup(l);
2876 UNLOCK_LOOKUP;
2877 return;
2879 match = ISC_TRUE;
2880 } else if (result == ISC_R_SUCCESS)
2881 printf(";; Warning: ID mismatch: "
2882 "expected ID %u, got %u\n", l->sendmsg->id, id);
2883 else
2884 printf(";; Warning: short "
2885 "(< header size) message received\n");
2888 if (result == ISC_R_SUCCESS && (msgflags & DNS_MESSAGEFLAG_QR) == 0)
2889 printf(";; Warning: query response not set\n");
2891 if (!match) {
2892 isc_buffer_invalidate(&query->recvbuf);
2893 isc_buffer_init(&query->recvbuf, query->recvspace, COMMSIZE);
2894 ISC_LIST_ENQUEUE(query->recvlist, &query->recvbuf, link);
2895 result = isc_socket_recvv(query->sock, &query->recvlist, 1,
2896 global_task, recv_done, query);
2897 check_result(result, "isc_socket_recvv");
2898 recvcount++;
2899 isc_event_free(&event);
2900 UNLOCK_LOOKUP;
2901 return;
2904 result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &msg);
2905 check_result(result, "dns_message_create");
2907 if (key != NULL) {
2908 if (l->querysig == NULL) {
2909 debug("getting initial querysig");
2910 result = dns_message_getquerytsig(l->sendmsg, mctx,
2911 &l->querysig);
2912 check_result(result, "dns_message_getquerytsig");
2914 result = dns_message_setquerytsig(msg, l->querysig);
2915 check_result(result, "dns_message_setquerytsig");
2916 result = dns_message_settsigkey(msg, key);
2917 check_result(result, "dns_message_settsigkey");
2918 msg->tsigctx = l->tsigctx;
2919 l->tsigctx = NULL;
2920 if (l->msgcounter != 0)
2921 msg->tcp_continuation = 1;
2922 l->msgcounter++;
2925 debug("before parse starts");
2926 parseflags = DNS_MESSAGEPARSE_PRESERVEORDER;
2927 #ifdef DIG_SIGCHASE
2928 if (!l->sigchase) {
2929 do_sigchase = ISC_FALSE;
2930 } else {
2931 parseflags = 0;
2932 do_sigchase = ISC_TRUE;
2934 #endif
2935 if (l->besteffort) {
2936 parseflags |= DNS_MESSAGEPARSE_BESTEFFORT;
2937 parseflags |= DNS_MESSAGEPARSE_IGNORETRUNCATION;
2939 result = dns_message_parse(msg, b, parseflags);
2940 if (result == DNS_R_RECOVERABLE) {
2941 printf(";; Warning: Message parser reports malformed "
2942 "message packet.\n");
2943 result = ISC_R_SUCCESS;
2945 if (result != ISC_R_SUCCESS) {
2946 printf(";; Got bad packet: %s\n", isc_result_totext(result));
2947 hex_dump(b);
2948 query->waiting_connect = ISC_FALSE;
2949 dns_message_destroy(&msg);
2950 isc_event_free(&event);
2951 clear_query(query);
2952 cancel_lookup(l);
2953 check_next_lookup(l);
2954 UNLOCK_LOOKUP;
2955 return;
2957 if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0 &&
2958 !l->ignore && !l->tcp_mode) {
2959 printf(";; Truncated, retrying in TCP mode.\n");
2960 n = requeue_lookup(l, ISC_TRUE);
2961 n->tcp_mode = ISC_TRUE;
2962 n->origin = query->lookup->origin;
2963 dns_message_destroy(&msg);
2964 isc_event_free(&event);
2965 clear_query(query);
2966 cancel_lookup(l);
2967 check_next_lookup(l);
2968 UNLOCK_LOOKUP;
2969 return;
2971 if ((msg->rcode == dns_rcode_servfail && !l->servfail_stops) ||
2972 (check_ra && (msg->flags & DNS_MESSAGEFLAG_RA) == 0 && l->recurse))
2974 dig_query_t *next = ISC_LIST_NEXT(query, link);
2975 if (l->current_query == query)
2976 l->current_query = NULL;
2977 if (next != NULL) {
2978 debug("sending query %p\n", next);
2979 if (l->tcp_mode)
2980 send_tcp_connect(next);
2981 else
2982 send_udp(next);
2985 * If our query is at the head of the list and there
2986 * is no next, we're the only one left, so fall
2987 * through to print the message.
2989 if ((ISC_LIST_HEAD(l->q) != query) ||
2990 (ISC_LIST_NEXT(query, link) != NULL)) {
2991 if( l->comments == ISC_TRUE )
2992 printf(";; Got %s from %s, "
2993 "trying next server\n",
2994 msg->rcode == dns_rcode_servfail ?
2995 "SERVFAIL reply" :
2996 "recursion not available",
2997 query->servname);
2998 clear_query(query);
2999 check_next_lookup(l);
3000 dns_message_destroy(&msg);
3001 isc_event_free(&event);
3002 UNLOCK_LOOKUP;
3003 return;
3007 if (key != NULL) {
3008 result = dns_tsig_verify(&query->recvbuf, msg, NULL, NULL);
3009 if (result != ISC_R_SUCCESS) {
3010 printf(";; Couldn't verify signature: %s\n",
3011 isc_result_totext(result));
3012 validated = ISC_FALSE;
3014 l->tsigctx = msg->tsigctx;
3015 msg->tsigctx = NULL;
3016 if (l->querysig != NULL) {
3017 debug("freeing querysig buffer %p", l->querysig);
3018 isc_buffer_free(&l->querysig);
3020 result = dns_message_getquerytsig(msg, mctx, &l->querysig);
3021 check_result(result,"dns_message_getquerytsig");
3024 extrabytes = isc_buffer_remaininglength(b);
3026 debug("after parse");
3027 if (l->doing_xfr && l->xfr_q == NULL) {
3028 l->xfr_q = query;
3030 * Once we are in the XFR message, increase
3031 * the timeout to much longer, so brief network
3032 * outages won't cause the XFR to abort
3034 if (timeout != INT_MAX && l->timer != NULL) {
3035 unsigned int local_timeout;
3037 if (timeout == 0) {
3038 if (l->tcp_mode)
3039 local_timeout = TCP_TIMEOUT * 4;
3040 else
3041 local_timeout = UDP_TIMEOUT * 4;
3042 } else {
3043 if (timeout < (INT_MAX / 4))
3044 local_timeout = timeout * 4;
3045 else
3046 local_timeout = INT_MAX;
3048 debug("have local timeout of %d", local_timeout);
3049 isc_interval_set(&l->interval, local_timeout, 0);
3050 result = isc_timer_reset(l->timer,
3051 isc_timertype_once,
3052 NULL,
3053 &l->interval,
3054 ISC_FALSE);
3055 check_result(result, "isc_timer_reset");
3059 if (!l->doing_xfr || l->xfr_q == query) {
3060 if (msg->rcode != dns_rcode_noerror &&
3061 (l->origin != NULL || l->need_search)) {
3062 if (!next_origin(msg, query) || showsearch) {
3063 printmessage(query, msg, ISC_TRUE);
3064 received(b->used, &sevent->address, query);
3066 } else if (!l->trace && !l->ns_search_only) {
3067 #ifdef DIG_SIGCHASE
3068 if (!do_sigchase)
3069 #endif
3070 printmessage(query, msg, ISC_TRUE);
3071 } else if (l->trace) {
3072 int n = 0;
3073 int count = msg->counts[DNS_SECTION_ANSWER];
3075 debug("in TRACE code");
3076 if (!l->ns_search_only)
3077 printmessage(query, msg, ISC_TRUE);
3079 l->rdtype = l->qrdtype;
3080 if (l->trace_root || (l->ns_search_only && count > 0)) {
3081 if (!l->trace_root)
3082 l->rdtype = dns_rdatatype_soa;
3083 n = followup_lookup(msg, query,
3084 DNS_SECTION_ANSWER);
3085 l->trace_root = ISC_FALSE;
3086 } else if (count == 0)
3087 n = followup_lookup(msg, query,
3088 DNS_SECTION_AUTHORITY);
3089 if (n == 0)
3090 docancel = ISC_TRUE;
3091 } else {
3092 debug("in NSSEARCH code");
3094 if (l->trace_root) {
3096 * This is the initial NS query.
3098 int n;
3100 l->rdtype = dns_rdatatype_soa;
3101 n = followup_lookup(msg, query,
3102 DNS_SECTION_ANSWER);
3103 if (n == 0)
3104 docancel = ISC_TRUE;
3105 l->trace_root = ISC_FALSE;
3106 } else
3107 #ifdef DIG_SIGCHASE
3108 if (!do_sigchase)
3109 #endif
3110 printmessage(query, msg, ISC_TRUE);
3112 #ifdef DIG_SIGCHASE
3113 if (do_sigchase) {
3114 chase_msg = isc_mem_allocate(mctx,
3115 sizeof(dig_message_t));
3116 if (chase_msg == NULL) {
3117 fatal("Memory allocation failure in %s:%d",
3118 __FILE__, __LINE__);
3120 ISC_LIST_INITANDAPPEND(chase_message_list, chase_msg,
3121 link);
3122 if (dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE,
3123 &msg_temp) != ISC_R_SUCCESS) {
3124 fatal("dns_message_create in %s:%d",
3125 __FILE__, __LINE__);
3128 isc_buffer_usedregion(b, &r);
3129 result = isc_buffer_allocate(mctx, &buf, r.length);
3131 check_result(result, "isc_buffer_allocate");
3132 result = isc_buffer_copyregion(buf, &r);
3133 check_result(result, "isc_buffer_copyregion");
3135 result = dns_message_parse(msg_temp, buf, 0);
3137 isc_buffer_free(&buf);
3138 chase_msg->msg = msg_temp;
3140 chase_msg2 = isc_mem_allocate(mctx,
3141 sizeof(dig_message_t));
3142 if (chase_msg2 == NULL) {
3143 fatal("Memory allocation failure in %s:%d",
3144 __FILE__, __LINE__);
3146 ISC_LIST_INITANDAPPEND(chase_message_list2, chase_msg2,
3147 link);
3148 chase_msg2->msg = msg;
3150 #endif
3153 #ifdef DIG_SIGCHASE
3154 if (l->sigchase && ISC_LIST_EMPTY(lookup_list)) {
3155 sigchase(msg_temp);
3157 #endif
3159 if (l->pending)
3160 debug("still pending.");
3161 if (l->doing_xfr) {
3162 if (query != l->xfr_q) {
3163 dns_message_destroy(&msg);
3164 isc_event_free(&event);
3165 query->waiting_connect = ISC_FALSE;
3166 UNLOCK_LOOKUP;
3167 return;
3169 if (!docancel)
3170 docancel = check_for_more_data(query, msg, sevent);
3171 if (docancel) {
3172 dns_message_destroy(&msg);
3173 clear_query(query);
3174 cancel_lookup(l);
3175 check_next_lookup(l);
3177 } else {
3179 if (msg->rcode == dns_rcode_noerror || l->origin == NULL) {
3181 #ifdef DIG_SIGCHASE
3182 if (!l->sigchase)
3183 #endif
3184 received(b->used, &sevent->address, query);
3187 if (!query->lookup->ns_search_only)
3188 query->lookup->pending = ISC_FALSE;
3189 if (!query->lookup->ns_search_only ||
3190 query->lookup->trace_root || docancel) {
3191 #ifdef DIG_SIGCHASE
3192 if (!do_sigchase)
3193 #endif
3194 dns_message_destroy(&msg);
3196 cancel_lookup(l);
3198 clear_query(query);
3199 check_next_lookup(l);
3201 if (msg != NULL) {
3202 #ifdef DIG_SIGCHASE
3203 if (do_sigchase)
3204 msg = NULL;
3205 else
3206 #endif
3207 dns_message_destroy(&msg);
3209 isc_event_free(&event);
3210 UNLOCK_LOOKUP;
3214 * Turn a name into an address, using system-supplied routines. This is
3215 * used in looking up server names, etc... and needs to use system-supplied
3216 * routines, since they may be using a non-DNS system for these lookups.
3218 void
3219 get_address(char *host, in_port_t port, isc_sockaddr_t *sockaddr) {
3220 int count;
3221 isc_result_t result;
3223 isc_app_block();
3224 result = bind9_getaddresses(host, port, sockaddr, 1, &count);
3225 isc_app_unblock();
3226 if (result != ISC_R_SUCCESS)
3227 fatal("couldn't get address for '%s': %s",
3228 host, isc_result_totext(result));
3229 INSIST(count == 1);
3233 * Initiate either a TCP or UDP lookup
3235 void
3236 do_lookup(dig_lookup_t *lookup) {
3238 REQUIRE(lookup != NULL);
3240 debug("do_lookup()");
3241 lookup->pending = ISC_TRUE;
3242 if (lookup->tcp_mode)
3243 send_tcp_connect(ISC_LIST_HEAD(lookup->q));
3244 else
3245 send_udp(ISC_LIST_HEAD(lookup->q));
3249 * Start everything in action upon task startup.
3251 void
3252 onrun_callback(isc_task_t *task, isc_event_t *event) {
3253 UNUSED(task);
3255 isc_event_free(&event);
3256 LOCK_LOOKUP;
3257 start_lookup();
3258 UNLOCK_LOOKUP;
3262 * Make everything on the lookup queue go away. Mainly used by the
3263 * SIGINT handler.
3265 void
3266 cancel_all(void) {
3267 dig_lookup_t *l, *n;
3268 dig_query_t *q, *nq;
3270 debug("cancel_all()");
3272 LOCK_LOOKUP;
3273 if (free_now) {
3274 UNLOCK_LOOKUP;
3275 return;
3277 cancel_now = ISC_TRUE;
3278 if (current_lookup != NULL) {
3279 if (current_lookup->timer != NULL)
3280 isc_timer_detach(&current_lookup->timer);
3281 q = ISC_LIST_HEAD(current_lookup->q);
3282 while (q != NULL) {
3283 debug("cancelling query %p, belonging to %p",
3284 q, current_lookup);
3285 nq = ISC_LIST_NEXT(q, link);
3286 if (q->sock != NULL) {
3287 isc_socket_cancel(q->sock, NULL,
3288 ISC_SOCKCANCEL_ALL);
3289 } else {
3290 clear_query(q);
3292 q = nq;
3295 l = ISC_LIST_HEAD(lookup_list);
3296 while (l != NULL) {
3297 n = ISC_LIST_NEXT(l, link);
3298 ISC_LIST_DEQUEUE(lookup_list, l, link);
3299 try_clear_lookup(l);
3300 l = n;
3302 UNLOCK_LOOKUP;
3306 * Destroy all of the libs we are using, and get everything ready for a
3307 * clean shutdown.
3309 void
3310 destroy_libs(void) {
3311 #ifdef DIG_SIGCHASE
3312 void * ptr;
3313 dig_message_t *chase_msg;
3314 #endif
3315 #ifdef WITH_IDN
3316 isc_result_t result;
3317 #endif
3319 debug("destroy_libs()");
3320 if (global_task != NULL) {
3321 debug("freeing task");
3322 isc_task_detach(&global_task);
3325 * The taskmgr_destroy() call blocks until all events are cleared
3326 * from the task.
3328 if (taskmgr != NULL) {
3329 debug("freeing taskmgr");
3330 isc_taskmgr_destroy(&taskmgr);
3332 LOCK_LOOKUP;
3333 REQUIRE(sockcount == 0);
3334 REQUIRE(recvcount == 0);
3335 REQUIRE(sendcount == 0);
3337 INSIST(ISC_LIST_HEAD(lookup_list) == NULL);
3338 INSIST(current_lookup == NULL);
3339 INSIST(!free_now);
3341 free_now = ISC_TRUE;
3343 lwres_conf_clear(lwctx);
3344 lwres_context_destroy(&lwctx);
3346 flush_server_list();
3348 clear_searchlist();
3350 #ifdef WITH_IDN
3351 result = dns_name_settotextfilter(NULL);
3352 check_result(result, "dns_name_settotextfilter");
3353 #endif
3354 dns_name_destroy();
3356 if (commctx != NULL) {
3357 debug("freeing commctx");
3358 isc_mempool_destroy(&commctx);
3360 if (socketmgr != NULL) {
3361 debug("freeing socketmgr");
3362 isc_socketmgr_destroy(&socketmgr);
3364 if (timermgr != NULL) {
3365 debug("freeing timermgr");
3366 isc_timermgr_destroy(&timermgr);
3368 if (key != NULL) {
3369 debug("freeing key %p", key);
3370 dns_tsigkey_detach(&key);
3372 if (namebuf != NULL)
3373 isc_buffer_free(&namebuf);
3375 if (is_dst_up) {
3376 debug("destroy DST lib");
3377 dst_lib_destroy();
3378 is_dst_up = ISC_FALSE;
3380 if (entp != NULL) {
3381 debug("detach from entropy");
3382 isc_entropy_detach(&entp);
3385 UNLOCK_LOOKUP;
3386 DESTROYLOCK(&lookup_lock);
3387 #ifdef DIG_SIGCHASE
3389 debug("Destroy the messages kept for sigchase");
3390 /* Destroy the messages kept for sigchase */
3391 chase_msg = ISC_LIST_HEAD(chase_message_list);
3393 while (chase_msg != NULL) {
3394 INSIST(chase_msg->msg != NULL);
3395 dns_message_destroy(&(chase_msg->msg));
3396 ptr = chase_msg;
3397 chase_msg = ISC_LIST_NEXT(chase_msg, link);
3398 isc_mem_free(mctx, ptr);
3401 chase_msg = ISC_LIST_HEAD(chase_message_list2);
3403 while (chase_msg != NULL) {
3404 INSIST(chase_msg->msg != NULL);
3405 dns_message_destroy(&(chase_msg->msg));
3406 ptr = chase_msg;
3407 chase_msg = ISC_LIST_NEXT(chase_msg, link);
3408 isc_mem_free(mctx, ptr);
3410 if (dns_name_dynamic(&chase_name))
3411 free_name(&chase_name, mctx);
3412 #if DIG_SIGCHASE_TD
3413 if (dns_name_dynamic(&chase_current_name))
3414 free_name(&chase_current_name, mctx);
3415 if (dns_name_dynamic(&chase_authority_name))
3416 free_name(&chase_authority_name, mctx);
3417 #endif
3418 #if DIG_SIGCHASE_BU
3419 if (dns_name_dynamic(&chase_signame))
3420 free_name(&chase_signame, mctx);
3421 #endif
3423 debug("Destroy memory");
3425 #endif
3426 if (memdebugging != 0)
3427 isc_mem_stats(mctx, stderr);
3428 if (mctx != NULL)
3429 isc_mem_destroy(&mctx);
3432 #ifdef WITH_IDN
3433 static void
3434 initialize_idn(void) {
3435 idn_result_t r;
3436 isc_result_t result;
3438 #ifdef HAVE_SETLOCALE
3439 /* Set locale */
3440 (void)setlocale(LC_ALL, "");
3441 #endif
3442 /* Create configuration context. */
3443 r = idn_nameinit(1);
3444 if (r != idn_success)
3445 fatal("idn api initialization failed: %s",
3446 idn_result_tostring(r));
3448 /* Set domain name -> text post-conversion filter. */
3449 result = dns_name_settotextfilter(output_filter);
3450 check_result(result, "dns_name_settotextfilter");
3453 static isc_result_t
3454 output_filter(isc_buffer_t *buffer, unsigned int used_org,
3455 isc_boolean_t absolute)
3457 char tmp1[MAXDLEN], tmp2[MAXDLEN];
3458 size_t fromlen, tolen;
3459 isc_boolean_t end_with_dot;
3462 * Copy contents of 'buffer' to 'tmp1', supply trailing dot
3463 * if 'absolute' is true, and terminate with NUL.
3465 fromlen = isc_buffer_usedlength(buffer) - used_org;
3466 if (fromlen >= MAXDLEN)
3467 return (ISC_R_SUCCESS);
3468 memcpy(tmp1, (char *)isc_buffer_base(buffer) + used_org, fromlen);
3469 end_with_dot = (tmp1[fromlen - 1] == '.') ? ISC_TRUE : ISC_FALSE;
3470 if (absolute && !end_with_dot) {
3471 fromlen++;
3472 if (fromlen >= MAXDLEN)
3473 return (ISC_R_SUCCESS);
3474 tmp1[fromlen - 1] = '.';
3476 tmp1[fromlen] = '\0';
3479 * Convert contents of 'tmp1' to local encoding.
3481 if (idn_decodename(IDN_DECODE_APP, tmp1, tmp2, MAXDLEN) != idn_success)
3482 return (ISC_R_SUCCESS);
3483 strcpy(tmp1, tmp2);
3486 * Copy the converted contents in 'tmp1' back to 'buffer'.
3487 * If we have appended trailing dot, remove it.
3489 tolen = strlen(tmp1);
3490 if (absolute && !end_with_dot && tmp1[tolen - 1] == '.')
3491 tolen--;
3493 if (isc_buffer_length(buffer) < used_org + tolen)
3494 return (ISC_R_NOSPACE);
3496 isc_buffer_subtract(buffer, isc_buffer_usedlength(buffer) - used_org);
3497 memcpy(isc_buffer_used(buffer), tmp1, tolen);
3498 isc_buffer_add(buffer, tolen);
3500 return (ISC_R_SUCCESS);
3503 static idn_result_t
3504 append_textname(char *name, const char *origin, size_t namesize) {
3505 size_t namelen = strlen(name);
3506 size_t originlen = strlen(origin);
3508 /* Already absolute? */
3509 if (namelen > 0 && name[namelen - 1] == '.')
3510 return idn_success;
3512 /* Append dot and origin */
3514 if (namelen + 1 + originlen >= namesize)
3515 return idn_buffer_overflow;
3517 name[namelen++] = '.';
3518 (void)strcpy(name + namelen, origin);
3519 return idn_success;
3522 static void
3523 idn_check_result(idn_result_t r, const char *msg) {
3524 if (r != idn_success) {
3525 exitcode = 1;
3526 fatal("%s: %s", msg, idn_result_tostring(r));
3529 #endif /* WITH_IDN */
3531 #ifdef DIG_SIGCHASE
3532 void
3533 print_type(dns_rdatatype_t type)
3535 isc_buffer_t * b = NULL;
3536 isc_result_t result;
3537 isc_region_t r;
3539 result = isc_buffer_allocate(mctx, &b, 4000);
3540 check_result(result, "isc_buffer_allocate");
3542 result = dns_rdatatype_totext(type, b);
3543 check_result(result, "print_type");
3545 isc_buffer_usedregion(b, &r);
3546 r.base[r.length] = '\0';
3548 printf("%s", r.base);
3550 isc_buffer_free(&b);
3553 void
3554 dump_database_section(dns_message_t *msg, int section)
3556 dns_name_t *msg_name=NULL;
3558 dns_rdataset_t *rdataset;
3560 do {
3561 dns_message_currentname(msg, section, &msg_name);
3563 for (rdataset = ISC_LIST_HEAD(msg_name->list); rdataset != NULL;
3564 rdataset = ISC_LIST_NEXT(rdataset, link)) {
3565 dns_name_print(msg_name, stdout);
3566 printf("\n");
3567 print_rdataset(msg_name, rdataset, mctx);
3568 printf("end\n");
3570 msg_name = NULL;
3571 } while (dns_message_nextname(msg, section) == ISC_R_SUCCESS);
3574 void
3575 dump_database(void) {
3576 dig_message_t * msg;
3578 for (msg = ISC_LIST_HEAD(chase_message_list); msg != NULL;
3579 msg = ISC_LIST_NEXT(msg, link)) {
3580 if (dns_message_firstname(msg->msg, DNS_SECTION_ANSWER)
3581 == ISC_R_SUCCESS)
3582 dump_database_section(msg->msg, DNS_SECTION_ANSWER);
3584 if (dns_message_firstname(msg->msg, DNS_SECTION_AUTHORITY)
3585 == ISC_R_SUCCESS)
3586 dump_database_section(msg->msg, DNS_SECTION_AUTHORITY);
3588 if (dns_message_firstname(msg->msg, DNS_SECTION_ADDITIONAL)
3589 == ISC_R_SUCCESS)
3590 dump_database_section(msg->msg, DNS_SECTION_ADDITIONAL);
3595 dns_rdataset_t *
3596 search_type(dns_name_t *name, dns_rdatatype_t type, dns_rdatatype_t covers) {
3597 dns_rdataset_t *rdataset;
3598 dns_rdata_sig_t siginfo;
3599 dns_rdata_t sigrdata;
3600 isc_result_t result;
3602 for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL;
3603 rdataset = ISC_LIST_NEXT(rdataset, link)) {
3604 if (type == dns_rdatatype_any) {
3605 if (rdataset->type != dns_rdatatype_rrsig)
3606 return (rdataset);
3607 } else if ((type == dns_rdatatype_rrsig) &&
3608 (rdataset->type == dns_rdatatype_rrsig)) {
3609 dns_rdata_init(&sigrdata);
3610 result = dns_rdataset_first(rdataset);
3611 check_result(result, "empty rdataset");
3612 dns_rdataset_current(rdataset, &sigrdata);
3613 result = dns_rdata_tostruct(&sigrdata, &siginfo, NULL);
3614 check_result(result, "sigrdata tostruct siginfo");
3616 if ((siginfo.covered == covers) ||
3617 (covers == dns_rdatatype_any)) {
3618 dns_rdata_reset(&sigrdata);
3619 dns_rdata_freestruct(&siginfo);
3620 return (rdataset);
3622 dns_rdata_reset(&sigrdata);
3623 dns_rdata_freestruct(&siginfo);
3624 } else if (rdataset->type == type)
3625 return (rdataset);
3627 return (NULL);
3630 dns_rdataset_t *
3631 chase_scanname_section(dns_message_t *msg, dns_name_t *name,
3632 dns_rdatatype_t type, dns_rdatatype_t covers,
3633 int section)
3635 dns_rdataset_t *rdataset;
3636 dns_name_t *msg_name = NULL;
3638 do {
3639 dns_message_currentname(msg, section, &msg_name);
3640 if (dns_name_compare(msg_name, name) == 0) {
3641 rdataset = search_type(msg_name, type, covers);
3642 if (rdataset != NULL)
3643 return (rdataset);
3645 msg_name = NULL;
3646 } while (dns_message_nextname(msg, section) == ISC_R_SUCCESS);
3648 return (NULL);
3652 dns_rdataset_t *
3653 chase_scanname(dns_name_t *name, dns_rdatatype_t type, dns_rdatatype_t covers)
3655 dns_rdataset_t *rdataset = NULL;
3656 dig_message_t * msg;
3658 for (msg = ISC_LIST_HEAD(chase_message_list2); msg != NULL;
3659 msg = ISC_LIST_NEXT(msg, link)) {
3660 if (dns_message_firstname(msg->msg, DNS_SECTION_ANSWER)
3661 == ISC_R_SUCCESS)
3662 rdataset = chase_scanname_section(msg->msg, name,
3663 type, covers,
3664 DNS_SECTION_ANSWER);
3665 if (rdataset != NULL)
3666 return (rdataset);
3667 if (dns_message_firstname(msg->msg, DNS_SECTION_AUTHORITY)
3668 == ISC_R_SUCCESS)
3669 rdataset =
3670 chase_scanname_section(msg->msg, name,
3671 type, covers,
3672 DNS_SECTION_AUTHORITY);
3673 if (rdataset != NULL)
3674 return (rdataset);
3675 if (dns_message_firstname(msg->msg, DNS_SECTION_ADDITIONAL)
3676 == ISC_R_SUCCESS)
3677 rdataset =
3678 chase_scanname_section(msg->msg, name, type,
3679 covers,
3680 DNS_SECTION_ADDITIONAL);
3681 if (rdataset != NULL)
3682 return (rdataset);
3685 return (NULL);
3688 dns_rdataset_t *
3689 sigchase_scanname(dns_rdatatype_t type, dns_rdatatype_t covers,
3690 isc_boolean_t * lookedup, dns_name_t *rdata_name)
3692 dig_lookup_t *lookup;
3693 isc_buffer_t *b = NULL;
3694 isc_region_t r;
3695 isc_result_t result;
3696 dns_rdataset_t * temp;
3697 dns_rdatatype_t querytype;
3699 temp = chase_scanname(rdata_name, type, covers);
3700 if (temp != NULL)
3701 return (temp);
3703 if (*lookedup == ISC_TRUE)
3704 return (NULL);
3706 lookup = clone_lookup(current_lookup, ISC_TRUE);
3707 lookup->trace_root = ISC_FALSE;
3708 lookup->new_search = ISC_TRUE;
3710 result = isc_buffer_allocate(mctx, &b, BUFSIZE);
3711 check_result(result, "isc_buffer_allocate");
3712 result = dns_name_totext(rdata_name, ISC_FALSE, b);
3713 check_result(result, "dns_name_totext");
3714 isc_buffer_usedregion(b, &r);
3715 r.base[r.length] = '\0';
3716 strcpy(lookup->textname, (char*)r.base);
3717 isc_buffer_free(&b);
3719 if (type == dns_rdatatype_rrsig)
3720 querytype = covers;
3721 else
3722 querytype = type;
3724 if (querytype == 0 || querytype == 255) {
3725 printf("Error in the queried type: %d\n", querytype);
3726 return (NULL);
3729 lookup->rdtype = querytype;
3730 lookup->rdtypeset = ISC_TRUE;
3731 lookup->qrdtype = querytype;
3732 *lookedup = ISC_TRUE;
3734 ISC_LIST_APPEND(lookup_list, lookup, link);
3735 printf("\n\nLaunch a query to find a RRset of type ");
3736 print_type(type);
3737 printf(" for zone: %s\n", lookup->textname);
3738 return (NULL);
3741 void
3742 insert_trustedkey(dst_key_t * key)
3744 if (key == NULL)
3745 return;
3746 if (tk_list.nb_tk >= MAX_TRUSTED_KEY)
3747 return;
3749 tk_list.key[tk_list.nb_tk++] = key;
3750 return;
3753 void
3754 clean_trustedkey()
3756 int i = 0;
3758 for (i= 0; i < MAX_TRUSTED_KEY; i++) {
3759 if (tk_list.key[i] != NULL) {
3760 dst_key_free(&tk_list.key[i]);
3761 tk_list.key[i] = NULL;
3762 } else
3763 break;
3765 tk_list.nb_tk = 0;
3766 return;
3769 char alphnum[] =
3770 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
3772 isc_result_t
3773 removetmpkey(isc_mem_t *mctx, const char *file)
3775 char *tempnamekey = NULL;
3776 int tempnamekeylen;
3777 isc_result_t result;
3779 tempnamekeylen = strlen(file)+10;
3781 tempnamekey = isc_mem_allocate(mctx, tempnamekeylen);
3782 if (tempnamekey == NULL)
3783 return (ISC_R_NOMEMORY);
3785 memset(tempnamekey, 0, tempnamekeylen);
3787 strcat(tempnamekey, file);
3788 strcat(tempnamekey,".key");
3789 isc_file_remove(tempnamekey);
3791 result = isc_file_remove(tempnamekey);
3792 isc_mem_free(mctx, tempnamekey);
3793 return (result);
3796 isc_result_t
3797 opentmpkey(isc_mem_t *mctx, const char *file, char **tempp, FILE **fp) {
3798 FILE *f = NULL;
3799 isc_result_t result;
3800 char *tempname = NULL;
3801 char *tempnamekey = NULL;
3802 int tempnamelen;
3803 int tempnamekeylen;
3804 char *x;
3805 char *cp;
3806 isc_uint32_t which;
3808 while (1) {
3809 tempnamelen = strlen(file) + 20;
3810 tempname = isc_mem_allocate(mctx, tempnamelen);
3811 if (tempname == NULL)
3812 return (ISC_R_NOMEMORY);
3813 memset(tempname, 0, tempnamelen);
3815 result = isc_file_mktemplate(file, tempname, tempnamelen);
3816 if (result != ISC_R_SUCCESS)
3817 goto cleanup;
3819 cp = tempname;
3820 while (*cp != '\0')
3821 cp++;
3822 if (cp == tempname) {
3823 isc_mem_free(mctx, tempname);
3824 return (ISC_R_FAILURE);
3827 x = cp--;
3828 while (cp >= tempname && *cp == 'X') {
3829 isc_random_get(&which);
3830 *cp = alphnum[which % (sizeof(alphnum) - 1)];
3831 x = cp--;
3834 tempnamekeylen = tempnamelen+5;
3835 tempnamekey = isc_mem_allocate(mctx, tempnamekeylen);
3836 if (tempnamekey == NULL)
3837 return (ISC_R_NOMEMORY);
3839 memset(tempnamekey, 0, tempnamekeylen);
3840 strncpy(tempnamekey, tempname, tempnamelen);
3841 strcat(tempnamekey ,".key");
3844 if (isc_file_exists(tempnamekey)) {
3845 isc_mem_free(mctx, tempnamekey);
3846 isc_mem_free(mctx, tempname);
3847 continue;
3850 if ((f = fopen(tempnamekey, "w")) == NULL) {
3851 printf("get_trusted_key(): trusted key not found %s\n",
3852 tempnamekey);
3853 return (ISC_R_FAILURE);
3855 break;
3857 isc_mem_free(mctx, tempnamekey);
3858 *tempp = tempname;
3859 *fp = f;
3860 return (ISC_R_SUCCESS);
3862 cleanup:
3863 isc_mem_free(mctx, tempname);
3865 return (result);
3869 isc_result_t
3870 get_trusted_key(isc_mem_t *mctx)
3872 isc_result_t result;
3873 const char *filename = NULL;
3874 char *filetemp = NULL;
3875 char buf[1500];
3876 FILE *fp, *fptemp;
3877 dst_key_t *key = NULL;
3879 result = isc_file_exists(trustedkey);
3880 if (result != ISC_TRUE) {
3881 result = isc_file_exists("/etc/trusted-key.key");
3882 if (result != ISC_TRUE) {
3883 result = isc_file_exists("./trusted-key.key");
3884 if (result != ISC_TRUE)
3885 return (ISC_R_FAILURE);
3886 else
3887 filename = "./trusted-key.key";
3888 } else
3889 filename = "/etc/trusted-key.key";
3890 } else
3891 filename = trustedkey;
3893 if (filename == NULL) {
3894 printf("No trusted key\n");
3895 return (ISC_R_FAILURE);
3898 if ((fp = fopen(filename, "r")) == NULL) {
3899 printf("get_trusted_key(): trusted key not found %s\n",
3900 filename);
3901 return (ISC_R_FAILURE);
3903 while (fgets(buf, sizeof(buf), fp) != NULL) {
3904 result = opentmpkey(mctx,"tmp_file", &filetemp, &fptemp);
3905 if (result != ISC_R_SUCCESS) {
3906 fclose(fp);
3907 return (ISC_R_FAILURE);
3909 if (fputs(buf, fptemp) < 0) {
3910 fclose(fp);
3911 fclose(fptemp);
3912 return (ISC_R_FAILURE);
3914 fclose(fptemp);
3915 result = dst_key_fromnamedfile(filetemp, DST_TYPE_PUBLIC,
3916 mctx, &key);
3917 removetmpkey(mctx, filetemp);
3918 isc_mem_free(mctx, filetemp);
3919 if (result != ISC_R_SUCCESS) {
3920 fclose(fp);
3921 return (ISC_R_FAILURE);
3923 insert_trustedkey(key);
3924 #if 0
3925 dst_key_tofile(key, DST_TYPE_PUBLIC,"/tmp");
3926 #endif
3927 key = NULL;
3929 return (ISC_R_SUCCESS);
3933 static void
3934 nameFromString(const char *str, dns_name_t *p_ret) {
3935 size_t len = strlen(str);
3936 isc_result_t result;
3937 isc_buffer_t buffer;
3938 dns_fixedname_t fixedname;
3940 REQUIRE(p_ret != NULL);
3941 REQUIRE(str != NULL);
3943 isc_buffer_init(&buffer, str, len);
3944 isc_buffer_add(&buffer, len);
3946 dns_fixedname_init(&fixedname);
3947 result = dns_name_fromtext(dns_fixedname_name(&fixedname), &buffer,
3948 dns_rootname, ISC_TRUE, NULL);
3949 check_result(result, "nameFromString");
3951 if (dns_name_dynamic(p_ret))
3952 free_name(p_ret, mctx);
3954 result = dns_name_dup(dns_fixedname_name(&fixedname), mctx, p_ret);
3955 check_result(result, "nameFromString");
3959 #if DIG_SIGCHASE_TD
3960 isc_result_t
3961 prepare_lookup(dns_name_t *name)
3963 isc_result_t result;
3964 dig_lookup_t *lookup = NULL;
3965 dig_server_t *s;
3966 void *ptr;
3968 lookup = clone_lookup(current_lookup, ISC_TRUE);
3969 lookup->trace_root = ISC_FALSE;
3970 lookup->new_search = ISC_TRUE;
3971 lookup->trace_root_sigchase = ISC_FALSE;
3973 strncpy(lookup->textname, lookup->textnamesigchase, MXNAME);
3975 lookup->rdtype = lookup->rdtype_sigchase;
3976 lookup->rdtypeset = ISC_TRUE;
3977 lookup->qrdtype = lookup->qrdtype_sigchase;
3979 s = ISC_LIST_HEAD(lookup->my_server_list);
3980 while (s != NULL) {
3981 debug("freeing server %p belonging to %p",
3982 s, lookup);
3983 ptr = s;
3984 s = ISC_LIST_NEXT(s, link);
3985 ISC_LIST_DEQUEUE(lookup->my_server_list,
3986 (dig_server_t *)ptr, link);
3987 isc_mem_free(mctx, ptr);
3991 for (result = dns_rdataset_first(chase_nsrdataset);
3992 result == ISC_R_SUCCESS;
3993 result = dns_rdataset_next(chase_nsrdataset)) {
3994 char namestr[DNS_NAME_FORMATSIZE];
3995 dns_rdata_ns_t ns;
3996 dns_rdata_t rdata = DNS_RDATA_INIT;
3997 dig_server_t * srv = NULL;
3998 #define __FOLLOW_GLUE__
3999 #ifdef __FOLLOW_GLUE__
4000 isc_buffer_t *b = NULL;
4001 isc_result_t result;
4002 isc_region_t r;
4003 dns_rdataset_t *rdataset = NULL;
4004 isc_boolean_t true = ISC_TRUE;
4005 #endif
4007 memset(namestr, 0, DNS_NAME_FORMATSIZE);
4009 dns_rdataset_current(chase_nsrdataset, &rdata);
4011 (void)dns_rdata_tostruct(&rdata, &ns, NULL);
4015 #ifdef __FOLLOW_GLUE__
4017 result = advanced_rrsearch(&rdataset, &ns.name,
4018 dns_rdatatype_aaaa,
4019 dns_rdatatype_any, &true);
4020 if (result == ISC_R_SUCCESS) {
4021 for (result = dns_rdataset_first(rdataset);
4022 result == ISC_R_SUCCESS;
4023 result = dns_rdataset_next(rdataset)) {
4024 dns_rdata_t aaaa = DNS_RDATA_INIT;
4025 dns_rdataset_current(rdataset, &aaaa);
4027 result = isc_buffer_allocate(mctx, &b, 80);
4028 check_result(result, "isc_buffer_allocate");
4030 dns_rdata_totext(&aaaa, &ns.name, b);
4031 isc_buffer_usedregion(b, &r);
4032 r.base[r.length] = '\0';
4033 strncpy(namestr, (char*)r.base,
4034 DNS_NAME_FORMATSIZE);
4035 isc_buffer_free(&b);
4036 dns_rdata_reset(&aaaa);
4039 srv = make_server(namestr, namestr);
4041 ISC_LIST_APPEND(lookup->my_server_list,
4042 srv, link);
4046 rdataset = NULL;
4047 result = advanced_rrsearch(&rdataset, &ns.name, dns_rdatatype_a,
4048 dns_rdatatype_any, &true);
4049 if (result == ISC_R_SUCCESS) {
4050 for (result = dns_rdataset_first(rdataset);
4051 result == ISC_R_SUCCESS;
4052 result = dns_rdataset_next(rdataset)) {
4053 dns_rdata_t a = DNS_RDATA_INIT;
4054 dns_rdataset_current(rdataset, &a);
4056 result = isc_buffer_allocate(mctx, &b, 80);
4057 check_result(result, "isc_buffer_allocate");
4059 dns_rdata_totext(&a, &ns.name, b);
4060 isc_buffer_usedregion(b, &r);
4061 r.base[r.length] = '\0';
4062 strncpy(namestr, (char*)r.base,
4063 DNS_NAME_FORMATSIZE);
4064 isc_buffer_free(&b);
4065 dns_rdata_reset(&a);
4066 printf("ns name: %s\n", namestr);
4069 srv = make_server(namestr, namestr);
4071 ISC_LIST_APPEND(lookup->my_server_list,
4072 srv, link);
4075 #else
4077 dns_name_format(&ns.name, namestr, sizeof(namestr));
4078 printf("ns name: ");
4079 dns_name_print(&ns.name, stdout);
4080 printf("\n");
4081 srv = make_server(namestr, namestr);
4083 ISC_LIST_APPEND(lookup->my_server_list, srv, link);
4085 #endif
4086 dns_rdata_freestruct(&ns);
4087 dns_rdata_reset(&rdata);
4091 ISC_LIST_APPEND(lookup_list, lookup, link);
4092 printf("\nLaunch a query to find a RRset of type ");
4093 print_type(lookup->rdtype);
4094 printf(" for zone: %s", lookup->textname);
4095 printf(" with nameservers:");
4096 printf("\n");
4097 print_rdataset(name, chase_nsrdataset, mctx);
4098 return (ISC_R_SUCCESS);
4102 isc_result_t
4103 child_of_zone(dns_name_t * name, dns_name_t * zone_name,
4104 dns_name_t * child_name)
4106 dns_namereln_t name_reln;
4107 int orderp;
4108 unsigned int nlabelsp;
4110 name_reln = dns_name_fullcompare(name, zone_name, &orderp, &nlabelsp);
4111 if (name_reln != dns_namereln_subdomain ||
4112 dns_name_countlabels(name) <= dns_name_countlabels(zone_name) + 1) {
4113 printf("\n;; ERROR : ");
4114 dns_name_print(name, stdout);
4115 printf(" is not a subdomain of: ");
4116 dns_name_print(zone_name, stdout);
4117 printf(" FAILED\n\n");
4118 return (ISC_R_FAILURE);
4121 dns_name_getlabelsequence(name,
4122 dns_name_countlabels(name) -
4123 dns_name_countlabels(zone_name) -1,
4124 dns_name_countlabels(zone_name) +1,
4125 child_name);
4126 return (ISC_R_SUCCESS);
4129 isc_result_t
4130 grandfather_pb_test(dns_name_t *zone_name, dns_rdataset_t *sigrdataset)
4132 isc_result_t result;
4133 dns_rdata_t sigrdata;
4134 dns_rdata_sig_t siginfo;
4136 result = dns_rdataset_first(sigrdataset);
4137 check_result(result, "empty RRSIG dataset");
4138 dns_rdata_init(&sigrdata);
4140 do {
4141 dns_rdataset_current(sigrdataset, &sigrdata);
4143 result = dns_rdata_tostruct(&sigrdata, &siginfo, NULL);
4144 check_result(result, "sigrdata tostruct siginfo");
4146 if (dns_name_compare(&siginfo.signer, zone_name) == 0) {
4147 dns_rdata_freestruct(&siginfo);
4148 dns_rdata_reset(&sigrdata);
4149 return (ISC_R_SUCCESS);
4152 dns_rdata_freestruct(&siginfo);
4154 } while (dns_rdataset_next(chase_sigkeyrdataset) == ISC_R_SUCCESS);
4156 dns_rdata_reset(&sigrdata);
4158 return (ISC_R_FAILURE);
4162 isc_result_t
4163 initialization(dns_name_t *name)
4165 isc_result_t result;
4166 isc_boolean_t true = ISC_TRUE;
4168 chase_nsrdataset = NULL;
4169 result = advanced_rrsearch(&chase_nsrdataset, name, dns_rdatatype_ns,
4170 dns_rdatatype_any, &true);
4171 if (result != ISC_R_SUCCESS) {
4172 printf("\n;; NS RRset is missing to continue validation:"
4173 " FAILED\n\n");
4174 return (ISC_R_FAILURE);
4176 INSIST(chase_nsrdataset != NULL);
4177 prepare_lookup(name);
4179 dup_name(name, &chase_current_name, mctx);
4181 return (ISC_R_SUCCESS);
4183 #endif
4185 void
4186 print_rdataset(dns_name_t *name, dns_rdataset_t *rdataset, isc_mem_t *mctx)
4188 isc_buffer_t *b = NULL;
4189 isc_result_t result;
4190 isc_region_t r;
4192 result = isc_buffer_allocate(mctx, &b, 9000);
4193 check_result(result, "isc_buffer_allocate");
4195 printrdataset(name, rdataset, b);
4197 isc_buffer_usedregion(b, &r);
4198 r.base[r.length] = '\0';
4201 printf("%s\n", r.base);
4203 isc_buffer_free(&b);
4207 void
4208 dup_name(dns_name_t *source, dns_name_t *target, isc_mem_t *mctx) {
4209 isc_result_t result;
4211 if (dns_name_dynamic(target))
4212 free_name(target, mctx);
4213 result = dns_name_dup(source, mctx, target);
4214 check_result(result, "dns_name_dup");
4217 void
4218 free_name(dns_name_t *name, isc_mem_t *mctx) {
4219 dns_name_free(name, mctx);
4220 dns_name_init(name, NULL);
4225 * take a DNSKEY RRset and the RRSIG RRset corresponding in parameter
4226 * return ISC_R_SUCCESS if the DNSKEY RRset contains a trusted_key
4227 * and the RRset is valid
4228 * return ISC_R_NOTFOUND if not contains trusted key
4229 or if the RRset isn't valid
4230 * return ISC_R_FAILURE if problem
4233 isc_result_t
4234 contains_trusted_key(dns_name_t *name, dns_rdataset_t *rdataset,
4235 dns_rdataset_t *sigrdataset,
4236 isc_mem_t *mctx)
4238 isc_result_t result;
4239 dns_rdata_t rdata;
4240 dst_key_t *trustedKey = NULL;
4241 dst_key_t *dnsseckey = NULL;
4242 int i;
4244 if (name == NULL || rdataset == NULL)
4245 return (ISC_R_FAILURE);
4247 result = dns_rdataset_first(rdataset);
4248 check_result(result, "empty rdataset");
4249 dns_rdata_init(&rdata);
4251 do {
4252 dns_rdataset_current(rdataset, &rdata);
4253 INSIST(rdata.type == dns_rdatatype_dnskey);
4255 result = dns_dnssec_keyfromrdata(name, &rdata,
4256 mctx, &dnsseckey);
4257 check_result(result, "dns_dnssec_keyfromrdata");
4260 for (i = 0; i < tk_list.nb_tk; i++) {
4261 if (dst_key_compare(tk_list.key[i], dnsseckey)
4262 == ISC_TRUE) {
4263 dns_rdata_reset(&rdata);
4265 printf(";; Ok, find a Trusted Key in the "
4266 "DNSKEY RRset: %d\n",
4267 dst_key_id(dnsseckey));
4268 if (sigchase_verify_sig_key(name, rdataset,
4269 dnsseckey,
4270 sigrdataset,
4271 mctx)
4272 == ISC_R_SUCCESS) {
4273 dst_key_free(&dnsseckey);
4274 dnsseckey = NULL;
4275 return (ISC_R_SUCCESS);
4280 dns_rdata_reset(&rdata);
4281 if (dnsseckey != NULL)
4282 dst_key_free(&dnsseckey);
4283 } while (dns_rdataset_next(rdataset) == ISC_R_SUCCESS);
4285 if (trustedKey != NULL)
4286 dst_key_free(&trustedKey);
4287 trustedKey = NULL;
4289 return (ISC_R_NOTFOUND);
4292 isc_result_t
4293 sigchase_verify_sig(dns_name_t *name, dns_rdataset_t *rdataset,
4294 dns_rdataset_t *keyrdataset,
4295 dns_rdataset_t *sigrdataset,
4296 isc_mem_t *mctx)
4298 isc_result_t result;
4299 dns_rdata_t keyrdata;
4300 dst_key_t *dnsseckey = NULL;
4302 result = dns_rdataset_first(keyrdataset);
4303 check_result(result, "empty DNSKEY dataset");
4304 dns_rdata_init(&keyrdata);
4306 do {
4307 dns_rdataset_current(keyrdataset, &keyrdata);
4308 INSIST(keyrdata.type == dns_rdatatype_dnskey);
4310 result = dns_dnssec_keyfromrdata(name, &keyrdata,
4311 mctx, &dnsseckey);
4312 check_result(result, "dns_dnssec_keyfromrdata");
4314 result = sigchase_verify_sig_key(name, rdataset, dnsseckey,
4315 sigrdataset, mctx);
4316 if (result == ISC_R_SUCCESS) {
4317 dns_rdata_reset(&keyrdata);
4318 dst_key_free(&dnsseckey);
4319 return (ISC_R_SUCCESS);
4321 dst_key_free(&dnsseckey);
4322 } while (dns_rdataset_next(chase_keyrdataset) == ISC_R_SUCCESS);
4324 dns_rdata_reset(&keyrdata);
4326 return (ISC_R_NOTFOUND);
4329 isc_result_t
4330 sigchase_verify_sig_key(dns_name_t *name, dns_rdataset_t *rdataset,
4331 dst_key_t *dnsseckey, dns_rdataset_t *sigrdataset,
4332 isc_mem_t *mctx)
4334 isc_result_t result;
4335 dns_rdata_t sigrdata;
4336 dns_rdata_sig_t siginfo;
4338 result = dns_rdataset_first(sigrdataset);
4339 check_result(result, "empty RRSIG dataset");
4340 dns_rdata_init(&sigrdata);
4342 do {
4343 dns_rdataset_current(sigrdataset, &sigrdata);
4345 result = dns_rdata_tostruct(&sigrdata, &siginfo, NULL);
4346 check_result(result, "sigrdata tostruct siginfo");
4349 * Test if the id of the DNSKEY is
4350 * the id of the DNSKEY signer's
4352 if (siginfo.keyid == dst_key_id(dnsseckey)) {
4354 result = dns_rdataset_first(rdataset);
4355 check_result(result, "empty DS dataset");
4357 result = dns_dnssec_verify(name, rdataset, dnsseckey,
4358 ISC_FALSE, mctx, &sigrdata);
4360 printf(";; VERIFYING ");
4361 print_type(rdataset->type);
4362 printf(" RRset for ");
4363 dns_name_print(name, stdout);
4364 printf(" with DNSKEY:%d: %s\n", dst_key_id(dnsseckey),
4365 isc_result_totext(result));
4367 if (result == ISC_R_SUCCESS) {
4368 dns_rdata_reset(&sigrdata);
4369 return (result);
4372 dns_rdata_freestruct(&siginfo);
4374 } while (dns_rdataset_next(chase_sigkeyrdataset) == ISC_R_SUCCESS);
4376 dns_rdata_reset(&sigrdata);
4378 return (ISC_R_NOTFOUND);
4382 isc_result_t
4383 sigchase_verify_ds(dns_name_t *name, dns_rdataset_t *keyrdataset,
4384 dns_rdataset_t *dsrdataset, isc_mem_t *mctx)
4386 isc_result_t result;
4387 dns_rdata_t keyrdata;
4388 dns_rdata_t newdsrdata;
4389 dns_rdata_t dsrdata;
4390 dns_rdata_ds_t dsinfo;
4391 dst_key_t *dnsseckey = NULL;
4392 unsigned char dsbuf[DNS_DS_BUFFERSIZE];
4394 result = dns_rdataset_first(dsrdataset);
4395 check_result(result, "empty DSset dataset");
4396 dns_rdata_init(&dsrdata);
4397 do {
4398 dns_rdataset_current(dsrdataset, &dsrdata);
4400 result = dns_rdata_tostruct(&dsrdata, &dsinfo, NULL);
4401 check_result(result, "dns_rdata_tostruct for DS");
4403 result = dns_rdataset_first(keyrdataset);
4404 check_result(result, "empty KEY dataset");
4405 dns_rdata_init(&keyrdata);
4407 do {
4408 dns_rdataset_current(keyrdataset, &keyrdata);
4409 INSIST(keyrdata.type == dns_rdatatype_dnskey);
4411 result = dns_dnssec_keyfromrdata(name, &keyrdata,
4412 mctx, &dnsseckey);
4413 check_result(result, "dns_dnssec_keyfromrdata");
4416 * Test if the id of the DNSKEY is the
4417 * id of DNSKEY referenced by the DS
4419 if (dsinfo.key_tag == dst_key_id(dnsseckey)) {
4420 dns_rdata_init(&newdsrdata);
4422 result = dns_ds_buildrdata(name, &keyrdata,
4423 dsinfo.digest_type,
4424 dsbuf, &newdsrdata);
4425 dns_rdata_freestruct(&dsinfo);
4427 if (result != ISC_R_SUCCESS) {
4428 dns_rdata_reset(&keyrdata);
4429 dns_rdata_reset(&newdsrdata);
4430 dns_rdata_reset(&dsrdata);
4431 dst_key_free(&dnsseckey);
4432 dns_rdata_freestruct(&dsinfo);
4433 printf("Oops: impossible to build"
4434 " new DS rdata\n");
4435 return (result);
4439 if (dns_rdata_compare(&dsrdata,
4440 &newdsrdata) == 0) {
4441 printf(";; OK a DS valids a DNSKEY"
4442 " in the RRset\n");
4443 printf(";; Now verify that this"
4444 " DNSKEY validates the "
4445 "DNSKEY RRset\n");
4447 result = sigchase_verify_sig_key(name,
4448 keyrdataset,
4449 dnsseckey,
4450 chase_sigkeyrdataset,
4451 mctx);
4452 if (result == ISC_R_SUCCESS) {
4453 dns_rdata_reset(&keyrdata);
4454 dns_rdata_reset(&newdsrdata);
4455 dns_rdata_reset(&dsrdata);
4456 dst_key_free(&dnsseckey);
4458 return (result);
4460 } else {
4461 printf(";; This DS is NOT the DS for"
4462 " the chasing KEY: FAILED\n");
4465 dns_rdata_reset(&newdsrdata);
4467 dst_key_free(&dnsseckey);
4468 dnsseckey = NULL;
4469 } while (dns_rdataset_next(chase_keyrdataset) == ISC_R_SUCCESS);
4470 dns_rdata_reset(&keyrdata);
4472 } while (dns_rdataset_next(chase_dsrdataset) == ISC_R_SUCCESS);
4473 #if 0
4474 dns_rdata_reset(&dsrdata); WARNING
4475 #endif
4477 return (ISC_R_NOTFOUND);
4482 * take a pointer on a rdataset in parameter and try to resolv it.
4483 * the searched rrset is a rrset on 'name' with type 'type'
4484 * (and if the type is a rrsig the signature cover 'covers').
4485 * the lookedup is to known if you have already done the query on the net.
4486 * ISC_R_SUCCESS: if we found the rrset
4487 * ISC_R_NOTFOUND: we do not found the rrset in cache
4488 * and we do a query on the net
4489 * ISC_R_FAILURE: rrset not found
4491 isc_result_t
4492 advanced_rrsearch(dns_rdataset_t **rdataset, dns_name_t *name,
4493 dns_rdatatype_t type, dns_rdatatype_t covers,
4494 isc_boolean_t *lookedup)
4496 isc_boolean_t tmplookedup;
4498 INSIST(rdataset != NULL);
4500 if (*rdataset != NULL)
4501 return (ISC_R_SUCCESS);
4503 tmplookedup = *lookedup;
4504 if ((*rdataset = sigchase_scanname(type, covers,
4505 lookedup, name)) == NULL) {
4506 if (tmplookedup)
4507 return (ISC_R_FAILURE);
4508 return (ISC_R_NOTFOUND);
4510 *lookedup = ISC_FALSE;
4511 return (ISC_R_SUCCESS);
4516 #if DIG_SIGCHASE_TD
4517 void
4518 sigchase_td(dns_message_t *msg)
4520 isc_result_t result;
4521 dns_name_t *name = NULL;
4522 isc_boolean_t have_answer = ISC_FALSE;
4523 isc_boolean_t true = ISC_TRUE;
4525 if ((result = dns_message_firstname(msg, DNS_SECTION_ANSWER))
4526 == ISC_R_SUCCESS) {
4527 dns_message_currentname(msg, DNS_SECTION_ANSWER, &name);
4528 if (current_lookup->trace_root_sigchase) {
4529 initialization(name);
4530 return;
4532 have_answer = true;
4533 } else {
4534 if (!current_lookup->trace_root_sigchase) {
4535 result = dns_message_firstname(msg,
4536 DNS_SECTION_AUTHORITY);
4537 if (result == ISC_R_SUCCESS)
4538 dns_message_currentname(msg,
4539 DNS_SECTION_AUTHORITY,
4540 &name);
4541 chase_nsrdataset
4542 = chase_scanname_section(msg, name,
4543 dns_rdatatype_ns,
4544 dns_rdatatype_any,
4545 DNS_SECTION_AUTHORITY);
4546 dup_name(name, &chase_authority_name, mctx);
4547 if (chase_nsrdataset != NULL) {
4548 have_delegation_ns = ISC_TRUE;
4549 printf("no response but there is a delegation"
4550 " in authority section:");
4551 dns_name_print(name, stdout);
4552 printf("\n");
4553 } else {
4554 printf("no response and no delegation in "
4555 "authority section but a reference"
4556 " to: ");
4557 dns_name_print(name, stdout);
4558 printf("\n");
4559 error_message = msg;
4561 } else {
4562 printf(";; NO ANSWERS: %s\n",
4563 isc_result_totext(result));
4564 free_name(&chase_name, mctx);
4565 clean_trustedkey();
4566 return;
4571 if (have_answer) {
4572 chase_rdataset
4573 = chase_scanname_section(msg, &chase_name,
4574 current_lookup
4575 ->rdtype_sigchase,
4576 dns_rdatatype_any,
4577 DNS_SECTION_ANSWER);
4578 if (chase_rdataset != NULL)
4579 have_response = ISC_TRUE;
4582 result = advanced_rrsearch(&chase_keyrdataset,
4583 &chase_current_name,
4584 dns_rdatatype_dnskey,
4585 dns_rdatatype_any,
4586 &chase_keylookedup);
4587 if (result == ISC_R_FAILURE) {
4588 printf("\n;; DNSKEY is missing to continue validation:"
4589 " FAILED\n\n");
4590 goto cleanandgo;
4592 if (result == ISC_R_NOTFOUND)
4593 return;
4594 INSIST(chase_keyrdataset != NULL);
4595 printf("\n;; DNSKEYset:\n");
4596 print_rdataset(&chase_current_name , chase_keyrdataset, mctx);
4599 result = advanced_rrsearch(&chase_sigkeyrdataset,
4600 &chase_current_name,
4601 dns_rdatatype_rrsig,
4602 dns_rdatatype_dnskey,
4603 &chase_sigkeylookedup);
4604 if (result == ISC_R_FAILURE) {
4605 printf("\n;; RRSIG of DNSKEY is missing to continue validation:"
4606 " FAILED\n\n");
4607 goto cleanandgo;
4609 if (result == ISC_R_NOTFOUND)
4610 return;
4611 INSIST(chase_sigkeyrdataset != NULL);
4612 printf("\n;; RRSIG of the DNSKEYset:\n");
4613 print_rdataset(&chase_current_name , chase_sigkeyrdataset, mctx);
4616 if (!chase_dslookedup && !chase_nslookedup) {
4617 if (!delegation_follow) {
4618 result = contains_trusted_key(&chase_current_name,
4619 chase_keyrdataset,
4620 chase_sigkeyrdataset,
4621 mctx);
4622 } else {
4623 INSIST(chase_dsrdataset != NULL);
4624 INSIST(chase_sigdsrdataset != NULL);
4625 result = sigchase_verify_ds(&chase_current_name,
4626 chase_keyrdataset,
4627 chase_dsrdataset,
4628 mctx);
4631 if (result != ISC_R_SUCCESS) {
4632 printf("\n;; chain of trust can't be validated:"
4633 " FAILED\n\n");
4634 goto cleanandgo;
4635 } else {
4636 chase_dsrdataset = NULL;
4637 chase_sigdsrdataset = NULL;
4641 if (have_response || (!have_delegation_ns && !have_response)) {
4642 /* test if it's a grand father case */
4644 if (have_response) {
4645 result = advanced_rrsearch(&chase_sigrdataset,
4646 &chase_name,
4647 dns_rdatatype_rrsig,
4648 current_lookup
4649 ->rdtype_sigchase,
4650 &true);
4651 if (result == ISC_R_FAILURE) {
4652 printf("\n;; RRset is missing to continue"
4653 " validation SHOULD NOT APPEND:"
4654 " FAILED\n\n");
4655 goto cleanandgo;
4658 } else {
4659 result = advanced_rrsearch(&chase_sigrdataset,
4660 &chase_authority_name,
4661 dns_rdatatype_rrsig,
4662 dns_rdatatype_any,
4663 &true);
4664 if (result == ISC_R_FAILURE) {
4665 printf("\n;; RRSIG is missing to continue"
4666 " validation SHOULD NOT APPEND:"
4667 " FAILED\n\n");
4668 goto cleanandgo;
4671 result = grandfather_pb_test(&chase_current_name,
4672 chase_sigrdataset);
4673 if (result != ISC_R_SUCCESS) {
4674 dns_name_t tmp_name;
4676 printf("\n;; We are in a Grand Father Problem:"
4677 " See 2.2.1 in RFC 3568\n");
4678 chase_rdataset = NULL;
4679 chase_sigrdataset = NULL;
4680 have_response = ISC_FALSE;
4681 have_delegation_ns = ISC_FALSE;
4683 dns_name_init(&tmp_name, NULL);
4684 result = child_of_zone(&chase_name, &chase_current_name,
4685 &tmp_name);
4686 if (dns_name_dynamic(&chase_authority_name))
4687 free_name(&chase_authority_name, mctx);
4688 dup_name(&tmp_name, &chase_authority_name, mctx);
4689 printf(";; and we try to continue chain of trust"
4690 " validation of the zone: ");
4691 dns_name_print(&chase_authority_name, stdout);
4692 printf("\n");
4693 have_delegation_ns = ISC_TRUE;
4694 } else {
4695 if (have_response)
4696 goto finalstep;
4697 else
4698 chase_sigrdataset = NULL;
4702 if (have_delegation_ns) {
4703 chase_nsrdataset = NULL;
4704 result = advanced_rrsearch(&chase_nsrdataset,
4705 &chase_authority_name,
4706 dns_rdatatype_ns,
4707 dns_rdatatype_any,
4708 &chase_nslookedup);
4709 if (result == ISC_R_FAILURE) {
4710 printf("\n;;NSset is missing to continue validation:"
4711 " FAILED\n\n");
4712 goto cleanandgo;
4714 if (result == ISC_R_NOTFOUND) {
4715 return;
4717 INSIST(chase_nsrdataset != NULL);
4719 result = advanced_rrsearch(&chase_dsrdataset,
4720 &chase_authority_name,
4721 dns_rdatatype_ds,
4722 dns_rdatatype_any,
4723 &chase_dslookedup);
4724 if (result == ISC_R_FAILURE) {
4725 printf("\n;; DSset is missing to continue validation:"
4726 " FAILED\n\n");
4727 goto cleanandgo;
4729 if (result == ISC_R_NOTFOUND)
4730 return;
4731 INSIST(chase_dsrdataset != NULL);
4732 printf("\n;; DSset:\n");
4733 print_rdataset(&chase_authority_name , chase_dsrdataset, mctx);
4735 result = advanced_rrsearch(&chase_sigdsrdataset,
4736 &chase_authority_name,
4737 dns_rdatatype_rrsig,
4738 dns_rdatatype_ds,
4739 &true);
4740 if (result != ISC_R_SUCCESS) {
4741 printf("\n;; DSset is missing to continue validation:"
4742 " FAILED\n\n");
4743 goto cleanandgo;
4745 printf("\n;; RRSIGset of DSset\n");
4746 print_rdataset(&chase_authority_name,
4747 chase_sigdsrdataset, mctx);
4748 INSIST(chase_sigdsrdataset != NULL);
4750 result = sigchase_verify_sig(&chase_authority_name,
4751 chase_dsrdataset,
4752 chase_keyrdataset,
4753 chase_sigdsrdataset, mctx);
4754 if (result != ISC_R_SUCCESS) {
4755 printf("\n;; Impossible to verify the DSset:"
4756 " FAILED\n\n");
4757 goto cleanandgo;
4759 chase_keyrdataset = NULL;
4760 chase_sigkeyrdataset = NULL;
4763 prepare_lookup(&chase_authority_name);
4765 have_response = ISC_FALSE;
4766 have_delegation_ns = ISC_FALSE;
4767 delegation_follow = ISC_TRUE;
4768 error_message = NULL;
4769 dup_name(&chase_authority_name, &chase_current_name, mctx);
4770 free_name(&chase_authority_name, mctx);
4771 return;
4775 if (error_message != NULL) {
4776 dns_rdataset_t *rdataset;
4777 dns_rdataset_t *sigrdataset;
4778 dns_name_t rdata_name;
4779 isc_result_t ret = ISC_R_FAILURE;
4781 dns_name_init(&rdata_name, NULL);
4782 result = prove_nx(error_message, &chase_name,
4783 current_lookup->rdclass_sigchase,
4784 current_lookup->rdtype_sigchase, &rdata_name,
4785 &rdataset, &sigrdataset);
4786 if (rdataset == NULL || sigrdataset == NULL ||
4787 dns_name_countlabels(&rdata_name) == 0) {
4788 printf("\n;; Impossible to verify the non-existence,"
4789 " the NSEC RRset can't be validated:"
4790 " FAILED\n\n");
4791 goto cleanandgo;
4793 ret = sigchase_verify_sig(&rdata_name, rdataset,
4794 chase_keyrdataset,
4795 sigrdataset, mctx);
4796 if (ret != ISC_R_SUCCESS) {
4797 free_name(&rdata_name, mctx);
4798 printf("\n;; Impossible to verify the NSEC RR to prove"
4799 " the non-existence : FAILED\n\n");
4800 goto cleanandgo;
4802 free_name(&rdata_name, mctx);
4803 if (result != ISC_R_SUCCESS) {
4804 printf("\n;; Impossible to verify the non-existence:"
4805 " FAILED\n\n");
4806 goto cleanandgo;
4807 } else {
4808 printf("\n;; OK the query doesn't have response but"
4809 " we have validate this fact : SUCCESS\n\n");
4810 goto cleanandgo;
4814 cleanandgo:
4815 printf(";; cleanandgo \n");
4816 if (dns_name_dynamic(&chase_current_name))
4817 free_name(&chase_current_name, mctx);
4818 if (dns_name_dynamic(&chase_authority_name))
4819 free_name(&chase_authority_name, mctx);
4820 clean_trustedkey();
4821 return;
4823 finalstep :
4824 result = advanced_rrsearch(&chase_rdataset, &chase_name,
4825 current_lookup->rdtype_sigchase,
4826 dns_rdatatype_any ,
4827 &true);
4828 if (result == ISC_R_FAILURE) {
4829 printf("\n;; RRsig of RRset is missing to continue validation"
4830 " SHOULD NOT APPEND: FAILED\n\n");
4831 goto cleanandgo;
4833 result = sigchase_verify_sig(&chase_name, chase_rdataset,
4834 chase_keyrdataset,
4835 chase_sigrdataset, mctx);
4836 if (result != ISC_R_SUCCESS) {
4837 printf("\n;; Impossible to verify the RRset : FAILED\n\n");
4839 printf("RRset:\n");
4840 print_rdataset(&chase_name , chase_rdataset, mctx);
4841 printf("DNSKEYset:\n");
4842 print_rdataset(&chase_name , chase_keyrdataset, mctx);
4843 printf("RRSIG of RRset:\n");
4844 print_rdataset(&chase_name , chase_sigrdataset, mctx);
4845 printf("\n");
4847 goto cleanandgo;
4848 } else {
4849 printf("\n;; The Answer:\n");
4850 print_rdataset(&chase_name , chase_rdataset, mctx);
4852 printf("\n;; FINISH : we have validate the DNSSEC chain"
4853 " of trust: SUCCESS\n\n");
4854 goto cleanandgo;
4858 #endif
4861 #if DIG_SIGCHASE_BU
4863 isc_result_t
4864 getneededrr(dns_message_t *msg)
4866 isc_result_t result;
4867 dns_name_t *name = NULL;
4868 dns_rdata_t sigrdata;
4869 dns_rdata_sig_t siginfo;
4870 isc_boolean_t true = ISC_TRUE;
4872 if ((result = dns_message_firstname(msg, DNS_SECTION_ANSWER))
4873 != ISC_R_SUCCESS) {
4874 printf(";; NO ANSWERS: %s\n", isc_result_totext(result));
4876 if (chase_name.ndata == NULL)
4877 return (ISC_R_ADDRNOTAVAIL);
4878 } else {
4879 dns_message_currentname(msg, DNS_SECTION_ANSWER, &name);
4882 /* What do we chase? */
4883 if (chase_rdataset == NULL) {
4884 result = advanced_rrsearch(&chase_rdataset, name,
4885 dns_rdatatype_any,
4886 dns_rdatatype_any, &true);
4887 if (result != ISC_R_SUCCESS) {
4888 printf("\n;; No Answers: Validation FAILED\n\n");
4889 return (ISC_R_NOTFOUND);
4891 dup_name(name, &chase_name, mctx);
4892 printf(";; RRset to chase:\n");
4893 print_rdataset(&chase_name, chase_rdataset, mctx);
4895 INSIST(chase_rdataset != NULL);
4898 if (chase_sigrdataset == NULL) {
4899 result = advanced_rrsearch(&chase_sigrdataset, name,
4900 dns_rdatatype_rrsig,
4901 chase_rdataset->type,
4902 &chase_siglookedup);
4903 if (result == ISC_R_FAILURE) {
4904 printf("\n;; RRSIG is missing for continue validation:"
4905 " FAILED\n\n");
4906 if (dns_name_dynamic(&chase_name))
4907 free_name(&chase_name, mctx);
4908 return (ISC_R_NOTFOUND);
4910 if (result == ISC_R_NOTFOUND) {
4911 return (ISC_R_NOTFOUND);
4913 printf("\n;; RRSIG of the RRset to chase:\n");
4914 print_rdataset(&chase_name, chase_sigrdataset, mctx);
4916 INSIST(chase_sigrdataset != NULL);
4919 /* first find the DNSKEY name */
4920 result = dns_rdataset_first(chase_sigrdataset);
4921 check_result(result, "empty RRSIG dataset");
4922 dns_rdata_init(&sigrdata);
4923 dns_rdataset_current(chase_sigrdataset, &sigrdata);
4924 result = dns_rdata_tostruct(&sigrdata, &siginfo, NULL);
4925 check_result(result, "sigrdata tostruct siginfo");
4926 dup_name(&siginfo.signer, &chase_signame, mctx);
4927 dns_rdata_freestruct(&siginfo);
4928 dns_rdata_reset(&sigrdata);
4930 /* Do we have a key? */
4931 if (chase_keyrdataset == NULL) {
4932 result = advanced_rrsearch(&chase_keyrdataset,
4933 &chase_signame,
4934 dns_rdatatype_dnskey,
4935 dns_rdatatype_any,
4936 &chase_keylookedup);
4937 if (result == ISC_R_FAILURE) {
4938 printf("\n;; DNSKEY is missing to continue validation:"
4939 " FAILED\n\n");
4940 free_name(&chase_signame, mctx);
4941 if (dns_name_dynamic(&chase_name))
4942 free_name(&chase_name, mctx);
4943 return (ISC_R_NOTFOUND);
4945 if (result == ISC_R_NOTFOUND) {
4946 free_name(&chase_signame, mctx);
4947 return (ISC_R_NOTFOUND);
4949 printf("\n;; DNSKEYset that signs the RRset to chase:\n");
4950 print_rdataset(&chase_signame, chase_keyrdataset, mctx);
4952 INSIST(chase_keyrdataset != NULL);
4954 if (chase_sigkeyrdataset == NULL) {
4955 result = advanced_rrsearch(&chase_sigkeyrdataset,
4956 &chase_signame,
4957 dns_rdatatype_rrsig,
4958 dns_rdatatype_dnskey,
4959 &chase_sigkeylookedup);
4960 if (result == ISC_R_FAILURE) {
4961 printf("\n;; RRSIG for DNSKEY is missing to continue"
4962 " validation : FAILED\n\n");
4963 free_name(&chase_signame, mctx);
4964 if (dns_name_dynamic(&chase_name))
4965 free_name(&chase_name, mctx);
4966 return (ISC_R_NOTFOUND);
4968 if (result == ISC_R_NOTFOUND) {
4969 free_name(&chase_signame, mctx);
4970 return (ISC_R_NOTFOUND);
4972 printf("\n;; RRSIG of the DNSKEYset that signs the "
4973 "RRset to chase:\n");
4974 print_rdataset(&chase_signame, chase_sigkeyrdataset, mctx);
4976 INSIST(chase_sigkeyrdataset != NULL);
4979 if (chase_dsrdataset == NULL) {
4980 result = advanced_rrsearch(&chase_dsrdataset, &chase_signame,
4981 dns_rdatatype_ds,
4982 dns_rdatatype_any,
4983 &chase_dslookedup);
4984 if (result == ISC_R_FAILURE) {
4985 printf("\n;; WARNING There is no DS for the zone: ");
4986 dns_name_print(&chase_signame, stdout);
4987 printf("\n");
4989 if (result == ISC_R_NOTFOUND) {
4990 free_name(&chase_signame, mctx);
4991 return (ISC_R_NOTFOUND);
4993 if (chase_dsrdataset != NULL) {
4994 printf("\n;; DSset of the DNSKEYset\n");
4995 print_rdataset(&chase_signame, chase_dsrdataset, mctx);
4999 if (chase_dsrdataset != NULL) {
5001 * if there is no RRSIG of DS,
5002 * we don't want to search on the network
5004 result = advanced_rrsearch(&chase_sigdsrdataset,
5005 &chase_signame,
5006 dns_rdatatype_rrsig,
5007 dns_rdatatype_ds, &true);
5008 if (result == ISC_R_FAILURE) {
5009 printf(";; WARNING : NO RRSIG DS : RRSIG DS"
5010 " should come with DS\n");
5012 * We continue even the DS couldn't be validated,
5013 * because the DNSKEY could be a Trusted Key.
5015 chase_dsrdataset = NULL;
5016 } else {
5017 printf("\n;; RRSIG of the DSset of the DNSKEYset\n");
5018 print_rdataset(&chase_signame, chase_sigdsrdataset,
5019 mctx);
5022 return (1);
5027 void
5028 sigchase_bu(dns_message_t *msg)
5030 isc_result_t result;
5031 int ret;
5033 if (tk_list.nb_tk == 0) {
5034 result = get_trusted_key(mctx);
5035 if (result != ISC_R_SUCCESS) {
5036 printf("No trusted keys present\n");
5037 return;
5042 ret = getneededrr(msg);
5043 if (ret == ISC_R_NOTFOUND)
5044 return;
5046 if (ret == ISC_R_ADDRNOTAVAIL) {
5047 /* We have no response */
5048 dns_rdataset_t *rdataset;
5049 dns_rdataset_t *sigrdataset;
5050 dns_name_t rdata_name;
5051 dns_name_t query_name;
5054 dns_name_init(&query_name, NULL);
5055 dns_name_init(&rdata_name, NULL);
5056 nameFromString(current_lookup->textname, &query_name);
5058 result = prove_nx(msg, &query_name, current_lookup->rdclass,
5059 current_lookup->rdtype, &rdata_name,
5060 &rdataset, &sigrdataset);
5061 free_name(&query_name, mctx);
5062 if (rdataset == NULL || sigrdataset == NULL ||
5063 dns_name_countlabels(&rdata_name) == 0) {
5064 printf("\n;; Impossible to verify the Non-existence,"
5065 " the NSEC RRset can't be validated: "
5066 "FAILED\n\n");
5067 clean_trustedkey();
5068 return;
5071 if (result != ISC_R_SUCCESS) {
5072 printf("\n No Answers and impossible to prove the"
5073 " unsecurity : Validation FAILED\n\n");
5074 clean_trustedkey();
5075 return;
5077 printf(";; An NSEC prove the non-existence of a answers,"
5078 " Now we want validate this NSEC\n");
5080 dup_name(&rdata_name, &chase_name, mctx);
5081 free_name(&rdata_name, mctx);
5082 chase_rdataset = rdataset;
5083 chase_sigrdataset = sigrdataset;
5084 chase_keyrdataset = NULL;
5085 chase_sigkeyrdataset = NULL;
5086 chase_dsrdataset = NULL;
5087 chase_sigdsrdataset = NULL;
5088 chase_siglookedup = ISC_FALSE;
5089 chase_keylookedup = ISC_FALSE;
5090 chase_dslookedup = ISC_FALSE;
5091 chase_sigdslookedup = ISC_FALSE;
5092 sigchase(msg);
5093 clean_trustedkey();
5094 return;
5098 printf("\n\n\n;; WE HAVE MATERIAL, WE NOW DO VALIDATION\n");
5100 result = sigchase_verify_sig(&chase_name, chase_rdataset,
5101 chase_keyrdataset,
5102 chase_sigrdataset, mctx);
5103 if (result != ISC_R_SUCCESS) {
5104 free_name(&chase_name, mctx);
5105 free_name(&chase_signame, mctx);
5106 printf(";; No DNSKEY is valid to check the RRSIG"
5107 " of the RRset: FAILED\n");
5108 clean_trustedkey();
5109 return;
5111 printf(";; OK We found DNSKEY (or more) to validate the RRset\n");
5113 result = contains_trusted_key(&chase_signame, chase_keyrdataset,
5114 chase_sigkeyrdataset, mctx);
5115 if (result == ISC_R_SUCCESS) {
5116 free_name(&chase_name, mctx);
5117 free_name(&chase_signame, mctx);
5118 printf("\n;; Ok this DNSKEY is a Trusted Key,"
5119 " DNSSEC validation is ok: SUCCESS\n\n");
5120 clean_trustedkey();
5121 return;
5124 printf(";; Now, we are going to validate this DNSKEY by the DS\n");
5126 if (chase_dsrdataset == NULL) {
5127 free_name(&chase_name, mctx);
5128 free_name(&chase_signame, mctx);
5129 printf(";; the DNSKEY isn't trusted-key and there isn't"
5130 " DS to validate the DNSKEY: FAILED\n");
5131 clean_trustedkey();
5132 return;
5135 result = sigchase_verify_ds(&chase_signame, chase_keyrdataset,
5136 chase_dsrdataset, mctx);
5137 if (result != ISC_R_SUCCESS) {
5138 free_name(&chase_signame, mctx);
5139 free_name(&chase_name, mctx);
5140 printf(";; ERROR no DS validates a DNSKEY in the"
5141 " DNSKEY RRset: FAILED\n");
5142 clean_trustedkey();
5143 return;
5144 } else
5145 printf(";; OK this DNSKEY (validated by the DS) validates"
5146 " the RRset of the DNSKEYs, thus the DNSKEY validates"
5147 " the RRset\n");
5148 INSIST(chase_sigdsrdataset != NULL);
5150 dup_name(&chase_signame, &chase_name, mctx);
5151 free_name(&chase_signame, mctx);
5152 chase_rdataset = chase_dsrdataset;
5153 chase_sigrdataset = chase_sigdsrdataset;
5154 chase_keyrdataset = NULL;
5155 chase_sigkeyrdataset = NULL;
5156 chase_dsrdataset = NULL;
5157 chase_sigdsrdataset = NULL;
5158 chase_siglookedup = chase_keylookedup = ISC_FALSE;
5159 chase_dslookedup = chase_sigdslookedup = ISC_FALSE;
5161 printf(";; Now, we want to validate the DS : recursive call\n");
5162 sigchase(msg);
5163 return;
5165 #endif
5167 void
5168 sigchase(dns_message_t *msg) {
5169 #if DIG_SIGCHASE_TD
5170 if (current_lookup->do_topdown) {
5171 sigchase_td(msg);
5172 return;
5174 #endif
5175 #if DIG_SIGCHASE_BU
5176 sigchase_bu(msg);
5177 return;
5178 #endif
5183 * return 1 if name1 < name2
5184 * 0 if name1 == name2
5185 * -1 if name1 > name2
5186 * and -2 if problem
5189 inf_name(dns_name_t *name1, dns_name_t *name2)
5191 dns_label_t label1;
5192 dns_label_t label2;
5193 unsigned int nblabel1;
5194 unsigned int nblabel2;
5195 int min_lum_label;
5196 int i;
5197 int ret = -2;
5199 nblabel1 = dns_name_countlabels(name1);
5200 nblabel2 = dns_name_countlabels(name2);
5202 if (nblabel1 >= nblabel2)
5203 min_lum_label = nblabel2;
5204 else
5205 min_lum_label = nblabel1;
5208 for (i=1 ; i < min_lum_label; i++) {
5209 dns_name_getlabel(name1, nblabel1 -1 - i, &label1);
5210 dns_name_getlabel(name2, nblabel2 -1 - i, &label2);
5211 if ((ret = isc_region_compare(&label1, &label2)) != 0) {
5212 if (ret < 0)
5213 return (-1);
5214 else if (ret > 0)
5215 return (1);
5218 if (nblabel1 == nblabel2)
5219 return (0);
5221 if (nblabel1 < nblabel2)
5222 return (-1);
5223 else
5224 return (1);
5232 isc_result_t
5233 prove_nx_domain(dns_message_t *msg,
5234 dns_name_t *name,
5235 dns_name_t *rdata_name,
5236 dns_rdataset_t **rdataset,
5237 dns_rdataset_t **sigrdataset)
5239 isc_result_t ret = ISC_R_FAILURE;
5240 isc_result_t result = ISC_R_NOTFOUND;
5241 dns_rdataset_t *nsecset = NULL;
5242 dns_rdataset_t *signsecset = NULL ;
5243 dns_rdata_t nsec = DNS_RDATA_INIT;
5244 dns_name_t *nsecname;
5245 dns_rdata_nsec_t nsecstruct;
5247 if ((result = dns_message_firstname(msg, DNS_SECTION_AUTHORITY))
5248 != ISC_R_SUCCESS) {
5249 printf(";; nothing in authority section : impossible to"
5250 " validate the non-existence : FAILED\n");
5251 return (ISC_R_FAILURE);
5254 do {
5255 nsecname = NULL;
5256 dns_message_currentname(msg, DNS_SECTION_AUTHORITY, &nsecname);
5257 nsecset = search_type(nsecname, dns_rdatatype_nsec,
5258 dns_rdatatype_any);
5259 if (nsecset == NULL)
5260 continue;
5262 printf("There is a NSEC for this zone in the"
5263 " AUTHORITY section:\n");
5264 print_rdataset(nsecname, nsecset, mctx);
5266 for (result = dns_rdataset_first(nsecset);
5267 result == ISC_R_SUCCESS;
5268 result = dns_rdataset_next(nsecset)) {
5269 dns_rdataset_current(nsecset, &nsec);
5272 signsecset
5273 = chase_scanname_section(msg, nsecname,
5274 dns_rdatatype_rrsig,
5275 dns_rdatatype_nsec,
5276 DNS_SECTION_AUTHORITY);
5277 if (signsecset == NULL) {
5278 printf(";; no RRSIG NSEC in authority section:"
5279 " impossible to validate the "
5280 "non-existence: FAILED\n");
5281 return (ISC_R_FAILURE);
5284 ret = dns_rdata_tostruct(&nsec, &nsecstruct, NULL);
5285 check_result(ret,"dns_rdata_tostruct");
5287 if ((inf_name(nsecname, &nsecstruct.next) == 1 &&
5288 inf_name(name, &nsecstruct.next) == 1) ||
5289 (inf_name(name, nsecname) == 1 &&
5290 inf_name(&nsecstruct.next, name) == 1)) {
5291 dns_rdata_freestruct(&nsecstruct);
5292 *rdataset = nsecset;
5293 *sigrdataset = signsecset;
5294 dup_name(nsecname, rdata_name, mctx);
5296 return (ISC_R_SUCCESS);
5299 dns_rdata_freestruct(&nsecstruct);
5301 } while (dns_message_nextname(msg, DNS_SECTION_AUTHORITY)
5302 == ISC_R_SUCCESS);
5304 *rdataset = NULL;
5305 *sigrdataset = NULL;
5306 rdata_name = NULL;
5307 return (ISC_R_FAILURE);
5317 isc_result_t
5318 prove_nx_type(dns_message_t *msg, dns_name_t *name, dns_rdataset_t *nsecset,
5319 dns_rdataclass_t class, dns_rdatatype_t type,
5320 dns_name_t *rdata_name, dns_rdataset_t **rdataset,
5321 dns_rdataset_t **sigrdataset)
5323 isc_result_t ret;
5324 dns_rdataset_t *signsecset;
5325 dns_rdata_t nsec = DNS_RDATA_INIT;
5327 UNUSED(class);
5329 ret = dns_rdataset_first(nsecset);
5330 check_result(ret,"dns_rdataset_first");
5332 dns_rdataset_current(nsecset, &nsec);
5334 ret = dns_nsec_typepresent(&nsec, type);
5335 if (ret == ISC_R_SUCCESS)
5336 printf("OK the NSEC said that the type doesn't exist \n");
5338 signsecset = chase_scanname_section(msg, name,
5339 dns_rdatatype_rrsig,
5340 dns_rdatatype_nsec,
5341 DNS_SECTION_AUTHORITY);
5342 if (signsecset == NULL) {
5343 printf("There isn't RRSIG NSEC for the zone \n");
5344 return (ISC_R_FAILURE);
5346 dup_name(name, rdata_name, mctx);
5347 *rdataset = nsecset;
5348 *sigrdataset = signsecset;
5350 return (ret);
5359 isc_result_t
5360 prove_nx(dns_message_t *msg, dns_name_t *name, dns_rdataclass_t class,
5361 dns_rdatatype_t type, dns_name_t *rdata_name,
5362 dns_rdataset_t **rdataset, dns_rdataset_t **sigrdataset)
5364 isc_result_t ret;
5365 dns_rdataset_t *nsecset = NULL;
5367 printf("We want to prove the non-existance of a type of rdata %d"
5368 " or of the zone: \n", type);
5370 if ((ret = dns_message_firstname(msg, DNS_SECTION_AUTHORITY))
5371 != ISC_R_SUCCESS) {
5372 printf(";; nothing in authority section : impossible to"
5373 " validate the non-existence : FAILED\n");
5374 return (ISC_R_FAILURE);
5377 nsecset = chase_scanname_section(msg, name, dns_rdatatype_nsec,
5378 dns_rdatatype_any,
5379 DNS_SECTION_AUTHORITY);
5380 if (nsecset != NULL) {
5381 printf("We have a NSEC for this zone :OK\n");
5382 ret = prove_nx_type(msg, name, nsecset, class,
5383 type, rdata_name, rdataset,
5384 sigrdataset);
5385 if (ret != ISC_R_SUCCESS) {
5386 printf("prove_nx: ERROR type exist\n");
5387 return (ret);
5388 } else {
5389 printf("prove_nx: OK type does not exist\n");
5390 return (ISC_R_SUCCESS);
5392 } else {
5393 printf("there is no NSEC for this zone: validating "
5394 "that the zone doesn't exist\n");
5395 ret = prove_nx_domain(msg, name, rdata_name,
5396 rdataset, sigrdataset);
5397 return (ret);
5399 /* Never get here */
5401 #endif