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