1/*
2 * chasetrace.c
3 * Where all the hard work concerning chasing
4 * and tracing is done
5 * (c) 2005, 2006 NLnet Labs
6 *
7 * See the file LICENSE for the license
8 *
9 */
10
11#include "drill.h"
12#include <ldns/ldns.h>
13
14/* Cache all RRs from rr_list "rr_list" to "referrals" database for lookup
15 * later on.  Print the NS RRs that were not already present.
16 */
17static void add_rr_list_to_referrals(
18    ldns_dnssec_zone *referrals, ldns_rr_list *rr_list)
19{
20	size_t i;
21	ldns_rr *rr;
22	ldns_dnssec_rrsets *rrset;
23	ldns_dnssec_rrs *rrs;
24
25	for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
26		rr = ldns_rr_list_rr(rr_list, i);
27		/* Check if a RR equal to "rr" is present in "referrals" */
28		rrset = ldns_dnssec_zone_find_rrset(
29		    referrals, ldns_rr_owner(rr), ldns_rr_get_type(rr));
30		if (rrset) {
31			for (rrs = rrset->rrs; rrs; rrs = rrs->next)
32				if (ldns_rr_compare(rr, rrs->rr) == 0)
33					break;
34			if (rrs) continue; /* "rr" is present, next! */
35		}
36		if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_NS && verbosity != -1)
37			ldns_rr_print(stdout, rr);
38		(void) ldns_dnssec_zone_add_rr(referrals, rr);
39	}
40}
41
42/* Cache all RRs from packet "p" to "referrals" database for lookup later on.
43 * Print the NS RRs that were not already present.
44 */
45static void add_referrals(ldns_dnssec_zone *referrals, ldns_pkt *p)
46{
47	ldns_rr_list *l = ldns_pkt_all_noquestion(p);
48	if (l) {
49		add_rr_list_to_referrals(referrals, l);
50		ldns_rr_list_free(l);
51	}
52}
53
54/* Equip name-server "res" with the name-servers authoritative for as much
55 * of "name" as possible.  Lookup addresses if needed.
56 */
57static bool set_nss_for_name(
58    ldns_resolver *res, ldns_dnssec_zone *referrals, ldns_rdf *name,
59    ldns_resolver *local_res, ldns_rr_class c)
60{
61	ldns_dnssec_rrsets *nss = NULL;
62	ldns_dnssec_rrs *nss_rrs;
63	ldns_dnssec_rrsets *as = NULL;
64	ldns_dnssec_rrs *as_rrs;
65	ldns_rdf *lookup = ldns_rdf_clone(name);
66	ldns_rdf *new_lookup;
67	ldns_rdf *addr;
68	ldns_rr_list *addrs;
69
70	/* nss will become the rrset of as much of "name" as possible */
71	for (;;) {
72		nss = ldns_dnssec_zone_find_rrset(
73		    referrals, lookup, LDNS_RR_TYPE_NS);
74		if (nss != NULL) {
75			ldns_rdf_deep_free(lookup);
76			break;
77		}
78		new_lookup = ldns_dname_left_chop(lookup);
79		ldns_rdf_deep_free(lookup);
80		lookup = new_lookup;
81		if (!lookup) {
82			error("No referrals for name found");
83			return false;
84		}
85	}
86
87	/* remove the old nameserver from the resolver */
88	while ((addr = ldns_resolver_pop_nameserver(res)))
89		ldns_rdf_deep_free(addr);
90
91	/* Find and add the address records for the rrset as name-servers */
92	for (nss_rrs = nss->rrs; nss_rrs; nss_rrs = nss_rrs->next) {
93
94		if ((as = ldns_dnssec_zone_find_rrset(
95		    referrals, ldns_rr_rdf(nss_rrs->rr, 0), LDNS_RR_TYPE_A)))
96			for (as_rrs = as->rrs; as_rrs; as_rrs = as_rrs->next)
97				(void) ldns_resolver_push_nameserver(
98				    res, ldns_rr_rdf(as_rrs->rr, 0));
99
100		if ((as = ldns_dnssec_zone_find_rrset(
101		    referrals, ldns_rr_rdf(nss_rrs->rr, 0), LDNS_RR_TYPE_AAAA)))
102			for (as_rrs = as->rrs; as_rrs; as_rrs = as_rrs->next)
103				(void) ldns_resolver_push_nameserver(
104				    res, ldns_rr_rdf(as_rrs->rr, 0));
105	}
106	/* Is our resolver equipped with name-servers? Good! We're done */
107	if (ldns_resolver_nameserver_count(res) > 0)
108		return true;
109
110	/* Lookup addresses with local resolver add add to "referrals" database */
111	addrs = ldns_rr_list_new();
112	for (nss_rrs = nss->rrs; nss_rrs; nss_rrs = nss_rrs->next) {
113		ldns_rr_list *addrs_by_name =
114		    ldns_get_rr_list_addr_by_name(
115			local_res, ldns_rr_rdf(nss_rrs->rr, 0), c, 0);
116		ldns_rr_list_cat(addrs, addrs_by_name);
117		ldns_rr_list_free(addrs_by_name);
118	}
119
120	if (ldns_rr_list_rr_count(addrs) == 0)
121		error("Could not find the nameserver ip addr; abort");
122
123	else if (ldns_resolver_push_nameserver_rr_list(res, addrs) !=
124	    LDNS_STATUS_OK)
125
126		error("Error adding new nameservers");
127	else {
128		ldns_rr_list_deep_free(addrs);
129		return true;
130	}
131	add_rr_list_to_referrals(referrals, addrs);
132	ldns_rr_list_deep_free(addrs);
133	return false;
134}
135
136/**
137 * trace down from the root to name
138 */
139
140/* same naive method as in drill0.9
141 * We resolve _ALL_ the names, which is of course not needed.
142 * We _do_ use the local resolver to do that, so it still is
143 * fast, but it can be made to run much faster.
144 */
145void
146do_trace(ldns_resolver *local_res, ldns_rdf *name, ldns_rr_type t,
147		ldns_rr_class c)
148{
149
150	static uint8_t zero[1] = { 0 };
151	static const ldns_rdf root_dname = { 1, LDNS_RDF_TYPE_DNAME, &zero };
152
153	ldns_resolver *res = NULL;
154	ldns_pkt *p = NULL;
155	ldns_rr_list *final_answer;
156	ldns_rr_list *new_nss;
157	ldns_rr_list *cname = NULL;
158	ldns_rr_list *answers = NULL;
159	uint16_t loop_count;
160	ldns_status status;
161	ldns_dnssec_zone* referrals = NULL;
162	ldns_rdf *addr;
163
164	loop_count = 0;
165	final_answer = NULL;
166	res = ldns_resolver_new();
167
168	if (!res) {
169                error("Memory allocation failed");
170		goto cleanup;
171        }
172
173	/* transfer some properties of local_res to res,
174	 * because they were given on the command line */
175	ldns_resolver_set_ip6(res,
176			ldns_resolver_ip6(local_res));
177	ldns_resolver_set_port(res,
178			ldns_resolver_port(local_res));
179	ldns_resolver_set_debug(res,
180			ldns_resolver_debug(local_res));
181	ldns_resolver_set_dnssec(res,
182			ldns_resolver_dnssec(local_res));
183	ldns_resolver_set_fail(res,
184			ldns_resolver_fail(local_res));
185	ldns_resolver_set_usevc(res,
186			ldns_resolver_usevc(local_res));
187	ldns_resolver_set_random(res,
188			ldns_resolver_random(local_res));
189	ldns_resolver_set_source(res,
190			ldns_resolver_source(local_res));
191	ldns_resolver_set_recursive(res, false);
192
193	/* setup the root nameserver in the new resolver */
194	status = ldns_resolver_push_nameserver_rr_list(res, global_dns_root);
195	if (status != LDNS_STATUS_OK) {
196		fprintf(stderr, "Error adding root servers to resolver: %s\n", ldns_get_errorstr_by_id(status));
197		ldns_rr_list_print(stdout, global_dns_root);
198		goto cleanup;
199	}
200
201	/* this must be a real query to local_res */
202	status = ldns_resolver_send(&p, res, &root_dname, LDNS_RR_TYPE_NS, c, 0);
203	/* p can still be NULL */
204
205	if (ldns_pkt_empty(p)) {
206		warning("No root server information received");
207	}
208
209	if (status == LDNS_STATUS_OK) {
210		if (!ldns_pkt_empty(p)) {
211			drill_pkt_print(stdout, local_res, p);
212		}
213		referrals = ldns_dnssec_zone_new();
214		add_referrals(referrals, p);
215	} else {
216		error("cannot use local resolver");
217		goto cleanup;
218	}
219	if (! set_nss_for_name(res, referrals, name, local_res, c)) {
220		goto cleanup;
221	}
222	ldns_pkt_free(p);
223	p = NULL;
224	status = ldns_resolver_send(&p, res, name, t, c, 0);
225	while(status == LDNS_STATUS_OK &&
226	      ldns_pkt_reply_type(p) == LDNS_PACKET_REFERRAL) {
227
228		if (!p) {
229			/* some error occurred -- bail out */
230			goto cleanup;
231		}
232		add_referrals(referrals, p);
233
234		/* checks itself for verbosity */
235		drill_pkt_print_footer(stdout, local_res, p);
236
237		if (! set_nss_for_name(res, referrals, name, local_res, c)) {
238			goto cleanup;
239		}
240		if (loop_count++ > 20) {
241			/* unlikely that we are doing anything useful */
242			error("Looks like we are looping");
243			goto cleanup;
244		}
245		ldns_pkt_free(p);
246		p = NULL;
247		status = ldns_resolver_send(&p, res, name, t, c, 0);
248
249		/* Exit trace on error */
250		if (status != LDNS_STATUS_OK)
251			break;
252
253		/* An answer might be the desired answer (and no referral) */
254		if (ldns_pkt_reply_type(p) != LDNS_PACKET_ANSWER)
255			continue;
256
257		/* Exit trace when the requested type is found */
258		answers = ldns_pkt_rr_list_by_type(p, t, LDNS_SECTION_ANSWER);
259		if (answers && ldns_rr_list_rr_count(answers) > 0) {
260			ldns_rr_list_free(answers);
261			answers = NULL;
262			break;
263		}
264		ldns_rr_list_free(answers);
265		answers = NULL;
266
267		/* Get the CNAMEs from the answer */
268		cname = ldns_pkt_rr_list_by_type(
269		    p, LDNS_RR_TYPE_CNAME, LDNS_SECTION_ANSWER);
270
271		/* No CNAME either: exit trace */
272		if (ldns_rr_list_rr_count(cname) == 0)
273			break;
274
275		/* Print CNAME referral */
276		ldns_rr_list_print(stdout, cname);
277
278		/* restart with the CNAME */
279		name = ldns_rr_rdf(ldns_rr_list_rr(cname, 0), 0);
280		ldns_rr_list_free(cname);
281		cname = NULL;
282
283		/* remove the old nameserver from the resolver */
284		while((addr = ldns_resolver_pop_nameserver(res)))
285			ldns_rdf_deep_free(addr);
286
287		/* Restart trace from the root up */
288		(void) ldns_resolver_push_nameserver_rr_list(
289		    res, global_dns_root);
290
291		ldns_pkt_free(p);
292		p = NULL;
293		status = ldns_resolver_send(&p, res, name, t, c, 0);
294	}
295
296	ldns_pkt_free(p);
297	p = NULL;
298	(void) ldns_resolver_send(&p, res, name, t, c, 0);
299	if (!p) {
300		goto cleanup;
301	}
302	new_nss = ldns_pkt_authority(p);
303	final_answer = ldns_pkt_answer(p);
304
305	if (verbosity != -1) {
306		ldns_rr_list_print(stdout, final_answer);
307		ldns_rr_list_print(stdout, new_nss);
308
309	}
310	drill_pkt_print_footer(stdout, local_res, p);
311cleanup:
312	if (res) {
313		while((addr = ldns_resolver_pop_nameserver(res)))
314			ldns_rdf_deep_free(addr);
315		ldns_resolver_free(res);
316	}
317	if (referrals)
318		ldns_dnssec_zone_deep_free(referrals);
319	if (p)
320		ldns_pkt_free(p);
321}
322
323
324/**
325 * Chase the given rr to a known and trusted key
326 *
327 * Based on drill 0.9
328 *
329 * the last argument prev_key_list, if not null, and type == DS, then the ds
330 * rr list we have must all be a ds for the keys in this list
331 */
332#ifdef HAVE_SSL
333ldns_status
334do_chase(ldns_resolver *res,
335	    ldns_rdf *name,
336	    ldns_rr_type type,
337	    ldns_rr_class c,
338	    ldns_rr_list *trusted_keys,
339	    ldns_pkt *pkt_o,
340	    uint16_t qflags,
341	    ldns_rr_list * ATTR_UNUSED(prev_key_list))
342{
343	ldns_rr_list *rrset = NULL;
344	ldns_status result;
345	ldns_rr *orig_rr = NULL;
346
347/*
348	ldns_rr_list *sigs;
349	ldns_rr *cur_sig;
350	uint16_t sig_i;
351	ldns_rr_list *keys;
352*/
353	ldns_pkt *pkt;
354	ldns_status tree_result;
355	ldns_dnssec_data_chain *chain;
356	ldns_dnssec_trust_tree *tree;
357
358	const ldns_rr_descriptor *descriptor;
359	descriptor = ldns_rr_descript(type);
360
361	ldns_dname2canonical(name);
362
363	pkt = ldns_pkt_clone(pkt_o);
364	if (!name) {
365		mesg("No name to chase");
366		ldns_pkt_free(pkt);
367		return LDNS_STATUS_EMPTY_LABEL;
368	}
369	if (verbosity != -1) {
370		printf(";; Chasing: ");
371			ldns_rdf_print(stdout, name);
372			if (descriptor && descriptor->_name) {
373				printf(" %s\n", descriptor->_name);
374			} else {
375				printf(" type %d\n", type);
376			}
377	}
378
379	if (!trusted_keys || ldns_rr_list_rr_count(trusted_keys) < 1) {
380		warning("No trusted keys specified");
381	}
382
383	if (pkt) {
384		rrset = ldns_pkt_rr_list_by_name_and_type(pkt,
385				name,
386				type,
387				LDNS_SECTION_ANSWER
388				);
389		if (!rrset) {
390			/* nothing in answer, try authority */
391			rrset = ldns_pkt_rr_list_by_name_and_type(pkt,
392					name,
393					type,
394					LDNS_SECTION_AUTHORITY
395					);
396		}
397		/* answer might be a cname, chase that first, then chase
398		   cname target? (TODO) */
399		if (!rrset) {
400			rrset = ldns_pkt_rr_list_by_name_and_type(pkt,
401					name,
402					LDNS_RR_TYPE_CNAME,
403					LDNS_SECTION_ANSWER
404					);
405			if (!rrset) {
406				/* nothing in answer, try authority */
407				rrset = ldns_pkt_rr_list_by_name_and_type(pkt,
408						name,
409						LDNS_RR_TYPE_CNAME,
410						LDNS_SECTION_AUTHORITY
411						);
412			}
413		}
414	} else {
415		/* no packet? */
416		if (verbosity >= 0) {
417			fprintf(stderr, "%s", ldns_get_errorstr_by_id(LDNS_STATUS_MEM_ERR));
418			fprintf(stderr, "\n");
419		}
420		return LDNS_STATUS_MEM_ERR;
421	}
422
423	if (!rrset) {
424		/* not found in original packet, try again */
425		ldns_pkt_free(pkt);
426		pkt = NULL;
427		pkt = ldns_resolver_query(res, name, type, c, qflags);
428
429		if (!pkt) {
430			if (verbosity >= 0) {
431				fprintf(stderr, "%s", ldns_get_errorstr_by_id(LDNS_STATUS_NETWORK_ERR));
432				fprintf(stderr, "\n");
433			}
434			return LDNS_STATUS_NETWORK_ERR;
435		}
436		if (verbosity >= 5) {
437			ldns_pkt_print(stdout, pkt);
438		}
439
440		rrset =	ldns_pkt_rr_list_by_name_and_type(pkt,
441				name,
442				type,
443				LDNS_SECTION_ANSWER
444				);
445	}
446
447	orig_rr = ldns_rr_new();
448
449/* if the answer had no answer section, we need to construct our own rr (for instance if
450 * the rr qe asked for doesn't exist. This rr will be destroyed when the chain is freed */
451	if (ldns_pkt_ancount(pkt) < 1) {
452		ldns_rr_set_type(orig_rr, type);
453		ldns_rr_set_owner(orig_rr, ldns_rdf_clone(name));
454
455		chain = ldns_dnssec_build_data_chain(res, qflags, rrset, pkt, ldns_rr_clone(orig_rr));
456	} else {
457		/* chase the first answer */
458		chain = ldns_dnssec_build_data_chain(res, qflags, rrset, pkt, NULL);
459	}
460
461	if (verbosity >= 4) {
462		printf("\n\nDNSSEC Data Chain:\n");
463		ldns_dnssec_data_chain_print(stdout, chain);
464	}
465
466	result = LDNS_STATUS_OK;
467
468	tree = ldns_dnssec_derive_trust_tree(chain, NULL);
469
470	if (verbosity >= 2) {
471		printf("\n\nDNSSEC Trust tree:\n");
472		ldns_dnssec_trust_tree_print(stdout, tree, 0, true);
473	}
474
475	if (ldns_rr_list_rr_count(trusted_keys) > 0) {
476		tree_result = ldns_dnssec_trust_tree_contains_keys(tree, trusted_keys);
477
478		if (tree_result == LDNS_STATUS_DNSSEC_EXISTENCE_DENIED) {
479			if (verbosity >= 1) {
480				printf("Existence denied or verifiably insecure\n");
481			}
482			result = LDNS_STATUS_OK;
483		} else if (tree_result != LDNS_STATUS_OK) {
484			if (verbosity >= 1) {
485				printf("No trusted keys found in tree: first error was: %s\n", ldns_get_errorstr_by_id(tree_result));
486			}
487			result = tree_result;
488		}
489
490	} else {
491		if (verbosity >= 0) {
492			printf("You have not provided any trusted keys.\n");
493		}
494	}
495
496	ldns_rr_free(orig_rr);
497	ldns_dnssec_trust_tree_free(tree);
498	ldns_dnssec_data_chain_deep_free(chain);
499
500	ldns_rr_list_deep_free(rrset);
501	ldns_pkt_free(pkt);
502	/*	ldns_rr_free(orig_rr);*/
503
504	return result;
505}
506#endif /* HAVE_SSL */
507
508