1238104Sdes/*
2238104Sdes * chasetrace.c
3238104Sdes * Where all the hard work concerning chasing
4238104Sdes * and tracing is done
5238104Sdes * (c) 2005, 2006 NLnet Labs
6238104Sdes *
7238104Sdes * See the file LICENSE for the license
8238104Sdes *
9238104Sdes */
10238104Sdes
11238104Sdes#include "drill.h"
12238104Sdes#include <ldns/ldns.h>
13238104Sdes
14238104Sdes/**
15238104Sdes * trace down from the root to name
16238104Sdes */
17238104Sdes
18238104Sdes/* same naive method as in drill0.9
19238104Sdes * We resolver _ALL_ the names, which is ofcourse not needed
20238104Sdes * We _do_ use the local resolver to do that, so it still is
21238104Sdes * fast, but it can be made to run much faster
22238104Sdes */
23238104Sdesldns_pkt *
24238104Sdesdo_trace(ldns_resolver *local_res, ldns_rdf *name, ldns_rr_type t,
25238104Sdes		ldns_rr_class c)
26238104Sdes{
27238104Sdes	ldns_resolver *res;
28238104Sdes	ldns_pkt *p;
29238104Sdes	ldns_rr_list *new_nss_a;
30238104Sdes	ldns_rr_list *new_nss_aaaa;
31238104Sdes	ldns_rr_list *final_answer;
32238104Sdes	ldns_rr_list *new_nss;
33238104Sdes	ldns_rr_list *ns_addr;
34238104Sdes	uint16_t loop_count;
35238104Sdes	ldns_rdf *pop;
36238104Sdes	ldns_status status;
37238104Sdes	size_t i;
38238104Sdes
39238104Sdes	loop_count = 0;
40238104Sdes	new_nss_a = NULL;
41238104Sdes	new_nss_aaaa = NULL;
42238104Sdes	new_nss = NULL;
43238104Sdes	ns_addr = NULL;
44238104Sdes	final_answer = NULL;
45238104Sdes	p = ldns_pkt_new();
46238104Sdes	res = ldns_resolver_new();
47238104Sdes
48246854Sdes	if (!p) {
49246854Sdes		if (res) {
50246854Sdes			ldns_resolver_free(res);
51246854Sdes		}
52238104Sdes                error("Memory allocation failed");
53238104Sdes                return NULL;
54246854Sdes	}
55246854Sdes	if (!res) {
56246854Sdes		ldns_pkt_free(p);
57246854Sdes                error("Memory allocation failed");
58246854Sdes                return NULL;
59238104Sdes        }
60238104Sdes
61238104Sdes	/* transfer some properties of local_res to res,
62238104Sdes	 * because they were given on the commandline */
63238104Sdes	ldns_resolver_set_ip6(res,
64238104Sdes			ldns_resolver_ip6(local_res));
65238104Sdes	ldns_resolver_set_port(res,
66238104Sdes			ldns_resolver_port(local_res));
67238104Sdes	ldns_resolver_set_debug(res,
68238104Sdes			ldns_resolver_debug(local_res));
69238104Sdes	ldns_resolver_set_dnssec(res,
70238104Sdes			ldns_resolver_dnssec(local_res));
71238104Sdes	ldns_resolver_set_fail(res,
72238104Sdes			ldns_resolver_fail(local_res));
73238104Sdes	ldns_resolver_set_usevc(res,
74238104Sdes			ldns_resolver_usevc(local_res));
75238104Sdes	ldns_resolver_set_random(res,
76238104Sdes			ldns_resolver_random(local_res));
77269257Sdes	ldns_resolver_set_source(res,
78269257Sdes			ldns_resolver_source(local_res));
79238104Sdes	ldns_resolver_set_recursive(res, false);
80238104Sdes
81238104Sdes	/* setup the root nameserver in the new resolver */
82238104Sdes	status = ldns_resolver_push_nameserver_rr_list(res, global_dns_root);
83238104Sdes	if (status != LDNS_STATUS_OK) {
84238104Sdes		fprintf(stderr, "Error adding root servers to resolver: %s\n", ldns_get_errorstr_by_id(status));
85238104Sdes		ldns_rr_list_print(stdout, global_dns_root);
86246854Sdes		ldns_resolver_free(res);
87246854Sdes		ldns_pkt_free(p);
88238104Sdes		return NULL;
89238104Sdes	}
90238104Sdes
91238104Sdes	/* this must be a real query to local_res */
92238104Sdes	status = ldns_resolver_send(&p, res, ldns_dname_new_frm_str("."), LDNS_RR_TYPE_NS, c, 0);
93238104Sdes	/* p can still be NULL */
94238104Sdes
95238104Sdes
96238104Sdes	if (ldns_pkt_empty(p)) {
97238104Sdes		warning("No root server information received");
98238104Sdes	}
99238104Sdes
100238104Sdes	if (status == LDNS_STATUS_OK) {
101238104Sdes		if (!ldns_pkt_empty(p)) {
102238104Sdes			drill_pkt_print(stdout, local_res, p);
103238104Sdes		}
104238104Sdes	} else {
105238104Sdes		error("cannot use local resolver");
106238104Sdes		return NULL;
107238104Sdes	}
108238104Sdes
109238104Sdes	status = ldns_resolver_send(&p, res, name, t, c, 0);
110238104Sdes
111238104Sdes	while(status == LDNS_STATUS_OK &&
112238104Sdes	      ldns_pkt_reply_type(p) == LDNS_PACKET_REFERRAL) {
113238104Sdes
114238104Sdes		if (!p) {
115238104Sdes			/* some error occurred, bail out */
116238104Sdes			return NULL;
117238104Sdes		}
118238104Sdes
119238104Sdes		new_nss_a = ldns_pkt_rr_list_by_type(p,
120238104Sdes				LDNS_RR_TYPE_A, LDNS_SECTION_ADDITIONAL);
121238104Sdes		new_nss_aaaa = ldns_pkt_rr_list_by_type(p,
122238104Sdes				LDNS_RR_TYPE_AAAA, LDNS_SECTION_ADDITIONAL);
123238104Sdes		new_nss = ldns_pkt_rr_list_by_type(p,
124238104Sdes				LDNS_RR_TYPE_NS, LDNS_SECTION_AUTHORITY);
125238104Sdes
126238104Sdes		if (verbosity != -1) {
127238104Sdes			ldns_rr_list_print(stdout, new_nss);
128238104Sdes		}
129238104Sdes		/* checks itself for verbosity */
130238104Sdes		drill_pkt_print_footer(stdout, local_res, p);
131238104Sdes
132238104Sdes		/* remove the old nameserver from the resolver */
133246854Sdes		while(ldns_resolver_pop_nameserver(res)) { /* do it */ }
134238104Sdes
135238104Sdes		/* also check for new_nss emptyness */
136238104Sdes
137238104Sdes		if (!new_nss_aaaa && !new_nss_a) {
138238104Sdes			/*
139238104Sdes			 * no nameserver found!!!
140238104Sdes			 * try to resolve the names we do got
141238104Sdes			 */
142238104Sdes			for(i = 0; i < ldns_rr_list_rr_count(new_nss); i++) {
143238104Sdes				/* get the name of the nameserver */
144238104Sdes				pop = ldns_rr_rdf(ldns_rr_list_rr(new_nss, i), 0);
145238104Sdes				if (!pop) {
146238104Sdes					break;
147238104Sdes				}
148238104Sdes
149238104Sdes				ldns_rr_list_print(stdout, new_nss);
150238104Sdes				ldns_rdf_print(stdout, pop);
151238104Sdes				/* retrieve it's addresses */
152238104Sdes				ns_addr = ldns_rr_list_cat_clone(ns_addr,
153238104Sdes					ldns_get_rr_list_addr_by_name(local_res, pop, c, 0));
154238104Sdes			}
155238104Sdes
156238104Sdes			if (ns_addr) {
157238104Sdes				if (ldns_resolver_push_nameserver_rr_list(res, ns_addr) !=
158238104Sdes						LDNS_STATUS_OK) {
159238104Sdes					error("Error adding new nameservers");
160238104Sdes					ldns_pkt_free(p);
161238104Sdes					return NULL;
162238104Sdes				}
163238104Sdes				ldns_rr_list_free(ns_addr);
164238104Sdes			} else {
165238104Sdes				ldns_rr_list_print(stdout, ns_addr);
166238104Sdes				error("Could not find the nameserver ip addr; abort");
167238104Sdes				ldns_pkt_free(p);
168238104Sdes				return NULL;
169238104Sdes			}
170238104Sdes		}
171238104Sdes
172238104Sdes		/* add the new ones */
173238104Sdes		if (new_nss_aaaa) {
174238104Sdes			if (ldns_resolver_push_nameserver_rr_list(res, new_nss_aaaa) !=
175238104Sdes					LDNS_STATUS_OK) {
176238104Sdes				error("adding new nameservers");
177238104Sdes				ldns_pkt_free(p);
178238104Sdes				return NULL;
179238104Sdes			}
180238104Sdes		}
181238104Sdes		if (new_nss_a) {
182238104Sdes			if (ldns_resolver_push_nameserver_rr_list(res, new_nss_a) !=
183238104Sdes					LDNS_STATUS_OK) {
184238104Sdes				error("adding new nameservers");
185238104Sdes				ldns_pkt_free(p);
186238104Sdes				return NULL;
187238104Sdes			}
188238104Sdes		}
189238104Sdes
190238104Sdes		if (loop_count++ > 20) {
191238104Sdes			/* unlikely that we are doing something usefull */
192238104Sdes			error("Looks like we are looping");
193238104Sdes			ldns_pkt_free(p);
194238104Sdes			return NULL;
195238104Sdes		}
196238104Sdes
197238104Sdes		status = ldns_resolver_send(&p, res, name, t, c, 0);
198238104Sdes		new_nss_aaaa = NULL;
199238104Sdes		new_nss_a = NULL;
200238104Sdes		ns_addr = NULL;
201238104Sdes	}
202238104Sdes
203238104Sdes	status = ldns_resolver_send(&p, res, name, t, c, 0);
204238104Sdes
205238104Sdes	if (!p) {
206238104Sdes		return NULL;
207238104Sdes	}
208238104Sdes
209238104Sdes	new_nss = ldns_pkt_authority(p);
210238104Sdes	final_answer = ldns_pkt_answer(p);
211238104Sdes
212238104Sdes	if (verbosity != -1) {
213238104Sdes		ldns_rr_list_print(stdout, final_answer);
214238104Sdes		ldns_rr_list_print(stdout, new_nss);
215238104Sdes
216238104Sdes	}
217238104Sdes	drill_pkt_print_footer(stdout, local_res, p);
218238104Sdes	ldns_pkt_free(p);
219238104Sdes	return NULL;
220238104Sdes}
221238104Sdes
222238104Sdes
223238104Sdes/**
224238104Sdes * Chase the given rr to a known and trusted key
225238104Sdes *
226238104Sdes * Based on drill 0.9
227238104Sdes *
228238104Sdes * the last argument prev_key_list, if not null, and type == DS, then the ds
229238104Sdes * rr list we have must all be a ds for the keys in this list
230238104Sdes */
231238104Sdes#ifdef HAVE_SSL
232238104Sdesldns_status
233238104Sdesdo_chase(ldns_resolver *res,
234238104Sdes	    ldns_rdf *name,
235238104Sdes	    ldns_rr_type type,
236238104Sdes	    ldns_rr_class c,
237238104Sdes	    ldns_rr_list *trusted_keys,
238238104Sdes	    ldns_pkt *pkt_o,
239238104Sdes	    uint16_t qflags,
240238104Sdes	    ldns_rr_list * ATTR_UNUSED(prev_key_list),
241238104Sdes	    int verbosity)
242238104Sdes{
243238104Sdes	ldns_rr_list *rrset = NULL;
244238104Sdes	ldns_status result;
245238104Sdes	ldns_rr *orig_rr = NULL;
246238104Sdes
247238104Sdes/*
248238104Sdes	ldns_rr_list *sigs;
249238104Sdes	ldns_rr *cur_sig;
250238104Sdes	uint16_t sig_i;
251238104Sdes	ldns_rr_list *keys;
252238104Sdes*/
253238104Sdes	ldns_pkt *pkt;
254238104Sdes	ldns_status tree_result;
255238104Sdes	ldns_dnssec_data_chain *chain;
256238104Sdes	ldns_dnssec_trust_tree *tree;
257238104Sdes
258238104Sdes	const ldns_rr_descriptor *descriptor;
259238104Sdes	descriptor = ldns_rr_descript(type);
260238104Sdes
261238104Sdes	ldns_dname2canonical(name);
262238104Sdes
263238104Sdes	pkt = ldns_pkt_clone(pkt_o);
264238104Sdes	if (!name) {
265238104Sdes		mesg("No name to chase");
266238104Sdes		ldns_pkt_free(pkt);
267238104Sdes		return LDNS_STATUS_EMPTY_LABEL;
268238104Sdes	}
269238104Sdes	if (verbosity != -1) {
270238104Sdes		printf(";; Chasing: ");
271238104Sdes			ldns_rdf_print(stdout, name);
272238104Sdes			if (descriptor && descriptor->_name) {
273238104Sdes				printf(" %s\n", descriptor->_name);
274238104Sdes			} else {
275238104Sdes				printf(" type %d\n", type);
276238104Sdes			}
277238104Sdes	}
278238104Sdes
279238104Sdes	if (!trusted_keys || ldns_rr_list_rr_count(trusted_keys) < 1) {
280238104Sdes		warning("No trusted keys specified");
281238104Sdes	}
282238104Sdes
283238104Sdes	if (pkt) {
284238104Sdes		rrset = ldns_pkt_rr_list_by_name_and_type(pkt,
285238104Sdes				name,
286238104Sdes				type,
287238104Sdes				LDNS_SECTION_ANSWER
288238104Sdes				);
289238104Sdes		if (!rrset) {
290238104Sdes			/* nothing in answer, try authority */
291238104Sdes			rrset = ldns_pkt_rr_list_by_name_and_type(pkt,
292238104Sdes					name,
293238104Sdes					type,
294238104Sdes					LDNS_SECTION_AUTHORITY
295238104Sdes					);
296238104Sdes		}
297238104Sdes		/* answer might be a cname, chase that first, then chase
298238104Sdes		   cname target? (TODO) */
299238104Sdes		if (!rrset) {
300238104Sdes			rrset = ldns_pkt_rr_list_by_name_and_type(pkt,
301238104Sdes					name,
302238104Sdes					LDNS_RR_TYPE_CNAME,
303238104Sdes					LDNS_SECTION_ANSWER
304238104Sdes					);
305238104Sdes			if (!rrset) {
306238104Sdes				/* nothing in answer, try authority */
307238104Sdes				rrset = ldns_pkt_rr_list_by_name_and_type(pkt,
308238104Sdes						name,
309238104Sdes						LDNS_RR_TYPE_CNAME,
310238104Sdes						LDNS_SECTION_AUTHORITY
311238104Sdes						);
312238104Sdes			}
313238104Sdes		}
314238104Sdes	} else {
315238104Sdes		/* no packet? */
316238104Sdes		if (verbosity >= 0) {
317238104Sdes			fprintf(stderr, "%s", ldns_get_errorstr_by_id(LDNS_STATUS_MEM_ERR));
318238104Sdes			fprintf(stderr, "\n");
319238104Sdes		}
320238104Sdes		return LDNS_STATUS_MEM_ERR;
321238104Sdes	}
322238104Sdes
323238104Sdes	if (!rrset) {
324238104Sdes		/* not found in original packet, try again */
325238104Sdes		ldns_pkt_free(pkt);
326238104Sdes		pkt = NULL;
327238104Sdes		pkt = ldns_resolver_query(res, name, type, c, qflags);
328238104Sdes
329238104Sdes		if (!pkt) {
330238104Sdes			if (verbosity >= 0) {
331238104Sdes				fprintf(stderr, "%s", ldns_get_errorstr_by_id(LDNS_STATUS_NETWORK_ERR));
332238104Sdes				fprintf(stderr, "\n");
333238104Sdes			}
334238104Sdes			return LDNS_STATUS_NETWORK_ERR;
335238104Sdes		}
336238104Sdes		if (verbosity >= 5) {
337238104Sdes			ldns_pkt_print(stdout, pkt);
338238104Sdes		}
339238104Sdes
340238104Sdes		rrset =	ldns_pkt_rr_list_by_name_and_type(pkt,
341238104Sdes				name,
342238104Sdes				type,
343238104Sdes				LDNS_SECTION_ANSWER
344238104Sdes				);
345238104Sdes	}
346238104Sdes
347238104Sdes	orig_rr = ldns_rr_new();
348238104Sdes
349238104Sdes/* if the answer had no answer section, we need to construct our own rr (for instance if
350238104Sdes * the rr qe asked for doesn't exist. This rr will be destroyed when the chain is freed */
351238104Sdes	if (ldns_pkt_ancount(pkt) < 1) {
352238104Sdes		ldns_rr_set_type(orig_rr, type);
353238104Sdes		ldns_rr_set_owner(orig_rr, ldns_rdf_clone(name));
354238104Sdes
355238104Sdes		chain = ldns_dnssec_build_data_chain(res, qflags, rrset, pkt, ldns_rr_clone(orig_rr));
356238104Sdes	} else {
357238104Sdes		/* chase the first answer */
358238104Sdes		chain = ldns_dnssec_build_data_chain(res, qflags, rrset, pkt, NULL);
359238104Sdes	}
360238104Sdes
361238104Sdes	if (verbosity >= 4) {
362238104Sdes		printf("\n\nDNSSEC Data Chain:\n");
363238104Sdes		ldns_dnssec_data_chain_print(stdout, chain);
364238104Sdes	}
365238104Sdes
366238104Sdes	result = LDNS_STATUS_OK;
367238104Sdes
368238104Sdes	tree = ldns_dnssec_derive_trust_tree(chain, NULL);
369238104Sdes
370238104Sdes	if (verbosity >= 2) {
371238104Sdes		printf("\n\nDNSSEC Trust tree:\n");
372238104Sdes		ldns_dnssec_trust_tree_print(stdout, tree, 0, true);
373238104Sdes	}
374238104Sdes
375238104Sdes	if (ldns_rr_list_rr_count(trusted_keys) > 0) {
376238104Sdes		tree_result = ldns_dnssec_trust_tree_contains_keys(tree, trusted_keys);
377238104Sdes
378238104Sdes		if (tree_result == LDNS_STATUS_DNSSEC_EXISTENCE_DENIED) {
379238104Sdes			if (verbosity >= 1) {
380238104Sdes				printf("Existence denied or verifiably insecure\n");
381238104Sdes			}
382238104Sdes			result = LDNS_STATUS_OK;
383238104Sdes		} else if (tree_result != LDNS_STATUS_OK) {
384238104Sdes			if (verbosity >= 1) {
385238104Sdes				printf("No trusted keys found in tree: first error was: %s\n", ldns_get_errorstr_by_id(tree_result));
386238104Sdes			}
387238104Sdes			result = tree_result;
388238104Sdes		}
389238104Sdes
390238104Sdes	} else {
391238104Sdes		if (verbosity >= 0) {
392238104Sdes			printf("You have not provided any trusted keys.\n");
393238104Sdes		}
394238104Sdes	}
395238104Sdes
396238104Sdes	ldns_rr_free(orig_rr);
397238104Sdes	ldns_dnssec_trust_tree_free(tree);
398238104Sdes	ldns_dnssec_data_chain_deep_free(chain);
399238104Sdes
400238104Sdes	ldns_rr_list_deep_free(rrset);
401238104Sdes	ldns_pkt_free(pkt);
402238104Sdes	/*	ldns_rr_free(orig_rr);*/
403238104Sdes
404238104Sdes	return result;
405238104Sdes}
406238104Sdes#endif /* HAVE_SSL */
407238104Sdes
408