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