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