xref: /dragonfly/contrib/ldns/drill/chasetrace.c (revision 0dace59e)
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 /**
15  * trace down from the root to name
16  */
17 
18 /* same naive method as in drill0.9
19  * We resolver _ALL_ the names, which is ofcourse not needed
20  * We _do_ use the local resolver to do that, so it still is
21  * fast, but it can be made to run much faster
22  */
23 ldns_pkt *
24 do_trace(ldns_resolver *local_res, ldns_rdf *name, ldns_rr_type t,
25 		ldns_rr_class c)
26 {
27 	ldns_resolver *res;
28 	ldns_pkt *p;
29 	ldns_rr_list *new_nss_a;
30 	ldns_rr_list *new_nss_aaaa;
31 	ldns_rr_list *final_answer;
32 	ldns_rr_list *new_nss;
33 	ldns_rr_list *hostnames;
34 	ldns_rr_list *ns_addr;
35 	uint16_t loop_count;
36 	ldns_rdf *pop;
37 	ldns_status status;
38 	size_t i;
39 
40 	loop_count = 0;
41 	new_nss_a = NULL;
42 	new_nss_aaaa = NULL;
43 	new_nss = NULL;
44 	ns_addr = NULL;
45 	final_answer = NULL;
46 	p = ldns_pkt_new();
47 	res = ldns_resolver_new();
48 
49 	if (!p || !res) {
50                 error("Memory allocation failed");
51                 return NULL;
52         }
53 
54 	/* transfer some properties of local_res to res,
55 	 * because they were given on the commandline */
56 	ldns_resolver_set_ip6(res,
57 			ldns_resolver_ip6(local_res));
58 	ldns_resolver_set_port(res,
59 			ldns_resolver_port(local_res));
60 	ldns_resolver_set_debug(res,
61 			ldns_resolver_debug(local_res));
62 	ldns_resolver_set_dnssec(res,
63 			ldns_resolver_dnssec(local_res));
64 	ldns_resolver_set_fail(res,
65 			ldns_resolver_fail(local_res));
66 	ldns_resolver_set_usevc(res,
67 			ldns_resolver_usevc(local_res));
68 	ldns_resolver_set_random(res,
69 			ldns_resolver_random(local_res));
70 	ldns_resolver_set_recursive(res, false);
71 
72 	/* setup the root nameserver in the new resolver */
73 	status = ldns_resolver_push_nameserver_rr_list(res, global_dns_root);
74 	if (status != LDNS_STATUS_OK) {
75 		fprintf(stderr, "Error adding root servers to resolver: %s\n", ldns_get_errorstr_by_id(status));
76 		ldns_rr_list_print(stdout, global_dns_root);
77 		return NULL;
78 	}
79 
80 	/* this must be a real query to local_res */
81 	status = ldns_resolver_send(&p, res, ldns_dname_new_frm_str("."), LDNS_RR_TYPE_NS, c, 0);
82 	/* p can still be NULL */
83 
84 
85 	if (ldns_pkt_empty(p)) {
86 		warning("No root server information received");
87 	}
88 
89 	if (status == LDNS_STATUS_OK) {
90 		if (!ldns_pkt_empty(p)) {
91 			drill_pkt_print(stdout, local_res, p);
92 		}
93 	} else {
94 		error("cannot use local resolver");
95 		return NULL;
96 	}
97 
98 	status = ldns_resolver_send(&p, res, name, t, c, 0);
99 
100 	while(status == LDNS_STATUS_OK &&
101 	      ldns_pkt_reply_type(p) == LDNS_PACKET_REFERRAL) {
102 
103 		if (!p) {
104 			/* some error occurred, bail out */
105 			return NULL;
106 		}
107 
108 		new_nss_a = ldns_pkt_rr_list_by_type(p,
109 				LDNS_RR_TYPE_A, LDNS_SECTION_ADDITIONAL);
110 		new_nss_aaaa = ldns_pkt_rr_list_by_type(p,
111 				LDNS_RR_TYPE_AAAA, LDNS_SECTION_ADDITIONAL);
112 		new_nss = ldns_pkt_rr_list_by_type(p,
113 				LDNS_RR_TYPE_NS, LDNS_SECTION_AUTHORITY);
114 
115 		if (verbosity != -1) {
116 			ldns_rr_list_print(stdout, new_nss);
117 		}
118 		/* checks itself for verbosity */
119 		drill_pkt_print_footer(stdout, local_res, p);
120 
121 		/* remove the old nameserver from the resolver */
122 		while((pop = ldns_resolver_pop_nameserver(res))) { /* do it */ }
123 
124 		/* also check for new_nss emptyness */
125 
126 		if (!new_nss_aaaa && !new_nss_a) {
127 			/*
128 			 * no nameserver found!!!
129 			 * try to resolve the names we do got
130 			 */
131 			for(i = 0; i < ldns_rr_list_rr_count(new_nss); i++) {
132 				/* get the name of the nameserver */
133 				pop = ldns_rr_rdf(ldns_rr_list_rr(new_nss, i), 0);
134 				if (!pop) {
135 					break;
136 				}
137 
138 				ldns_rr_list_print(stdout, new_nss);
139 				ldns_rdf_print(stdout, pop);
140 				/* retrieve it's addresses */
141 				ns_addr = ldns_rr_list_cat_clone(ns_addr,
142 					ldns_get_rr_list_addr_by_name(local_res, pop, c, 0));
143 			}
144 
145 			if (ns_addr) {
146 				if (ldns_resolver_push_nameserver_rr_list(res, ns_addr) !=
147 						LDNS_STATUS_OK) {
148 					error("Error adding new nameservers");
149 					ldns_pkt_free(p);
150 					return NULL;
151 				}
152 				ldns_rr_list_free(ns_addr);
153 			} else {
154 				ldns_rr_list_print(stdout, ns_addr);
155 				error("Could not find the nameserver ip addr; abort");
156 				ldns_pkt_free(p);
157 				return NULL;
158 			}
159 		}
160 
161 		/* add the new ones */
162 		if (new_nss_aaaa) {
163 			if (ldns_resolver_push_nameserver_rr_list(res, new_nss_aaaa) !=
164 					LDNS_STATUS_OK) {
165 				error("adding new nameservers");
166 				ldns_pkt_free(p);
167 				return NULL;
168 			}
169 		}
170 		if (new_nss_a) {
171 			if (ldns_resolver_push_nameserver_rr_list(res, new_nss_a) !=
172 					LDNS_STATUS_OK) {
173 				error("adding new nameservers");
174 				ldns_pkt_free(p);
175 				return NULL;
176 			}
177 		}
178 
179 		if (loop_count++ > 20) {
180 			/* unlikely that we are doing something usefull */
181 			error("Looks like we are looping");
182 			ldns_pkt_free(p);
183 			return NULL;
184 		}
185 
186 		status = ldns_resolver_send(&p, res, name, t, c, 0);
187 		new_nss_aaaa = NULL;
188 		new_nss_a = NULL;
189 		ns_addr = NULL;
190 	}
191 
192 	status = ldns_resolver_send(&p, res, name, t, c, 0);
193 
194 	if (!p) {
195 		return NULL;
196 	}
197 
198 	hostnames = ldns_get_rr_list_name_by_addr(local_res,
199 			ldns_pkt_answerfrom(p), 0, 0);
200 
201 	new_nss = ldns_pkt_authority(p);
202 	final_answer = ldns_pkt_answer(p);
203 
204 	if (verbosity != -1) {
205 		ldns_rr_list_print(stdout, final_answer);
206 		ldns_rr_list_print(stdout, new_nss);
207 
208 	}
209 	drill_pkt_print_footer(stdout, local_res, p);
210 	ldns_pkt_free(p);
211 	return NULL;
212 }
213 
214 
215 /**
216  * Chase the given rr to a known and trusted key
217  *
218  * Based on drill 0.9
219  *
220  * the last argument prev_key_list, if not null, and type == DS, then the ds
221  * rr list we have must all be a ds for the keys in this list
222  */
223 #ifdef HAVE_SSL
224 ldns_status
225 do_chase(ldns_resolver *res,
226 	    ldns_rdf *name,
227 	    ldns_rr_type type,
228 	    ldns_rr_class c,
229 	    ldns_rr_list *trusted_keys,
230 	    ldns_pkt *pkt_o,
231 	    uint16_t qflags,
232 	    ldns_rr_list *prev_key_list,
233 	    int verbosity)
234 {
235 	ldns_rr_list *rrset = NULL;
236 	ldns_status result;
237 	ldns_rr *orig_rr = NULL;
238 
239 	bool cname_followed = false;
240 /*
241 	ldns_rr_list *sigs;
242 	ldns_rr *cur_sig;
243 	uint16_t sig_i;
244 	ldns_rr_list *keys;
245 */
246 	ldns_pkt *pkt;
247 	ldns_status tree_result;
248 	ldns_dnssec_data_chain *chain;
249 	ldns_dnssec_trust_tree *tree;
250 
251 	const ldns_rr_descriptor *descriptor;
252 	descriptor = ldns_rr_descript(type);
253 
254 	ldns_dname2canonical(name);
255 
256 	pkt = ldns_pkt_clone(pkt_o);
257 	if (!name) {
258 		mesg("No name to chase");
259 		ldns_pkt_free(pkt);
260 		return LDNS_STATUS_EMPTY_LABEL;
261 	}
262 	if (verbosity != -1) {
263 		printf(";; Chasing: ");
264 			ldns_rdf_print(stdout, name);
265 			if (descriptor && descriptor->_name) {
266 				printf(" %s\n", descriptor->_name);
267 			} else {
268 				printf(" type %d\n", type);
269 			}
270 	}
271 
272 	if (!trusted_keys || ldns_rr_list_rr_count(trusted_keys) < 1) {
273 		warning("No trusted keys specified");
274 	}
275 
276 	if (pkt) {
277 		rrset = ldns_pkt_rr_list_by_name_and_type(pkt,
278 				name,
279 				type,
280 				LDNS_SECTION_ANSWER
281 				);
282 		if (!rrset) {
283 			/* nothing in answer, try authority */
284 			rrset = ldns_pkt_rr_list_by_name_and_type(pkt,
285 					name,
286 					type,
287 					LDNS_SECTION_AUTHORITY
288 					);
289 		}
290 		/* answer might be a cname, chase that first, then chase
291 		   cname target? (TODO) */
292 		if (!rrset) {
293 			cname_followed = true;
294 			rrset = ldns_pkt_rr_list_by_name_and_type(pkt,
295 					name,
296 					LDNS_RR_TYPE_CNAME,
297 					LDNS_SECTION_ANSWER
298 					);
299 			if (!rrset) {
300 				/* nothing in answer, try authority */
301 				rrset = ldns_pkt_rr_list_by_name_and_type(pkt,
302 						name,
303 						LDNS_RR_TYPE_CNAME,
304 						LDNS_SECTION_AUTHORITY
305 						);
306 			}
307 		}
308 	} else {
309 		/* no packet? */
310 		if (verbosity >= 0) {
311 			fprintf(stderr, "%s", ldns_get_errorstr_by_id(LDNS_STATUS_MEM_ERR));
312 			fprintf(stderr, "\n");
313 		}
314 		return LDNS_STATUS_MEM_ERR;
315 	}
316 
317 	if (!rrset) {
318 		/* not found in original packet, try again */
319 		ldns_pkt_free(pkt);
320 		pkt = NULL;
321 		pkt = ldns_resolver_query(res, name, type, c, qflags);
322 
323 		if (!pkt) {
324 			if (verbosity >= 0) {
325 				fprintf(stderr, "%s", ldns_get_errorstr_by_id(LDNS_STATUS_NETWORK_ERR));
326 				fprintf(stderr, "\n");
327 			}
328 			return LDNS_STATUS_NETWORK_ERR;
329 		}
330 		if (verbosity >= 5) {
331 			ldns_pkt_print(stdout, pkt);
332 		}
333 
334 		rrset =	ldns_pkt_rr_list_by_name_and_type(pkt,
335 				name,
336 				type,
337 				LDNS_SECTION_ANSWER
338 				);
339 	}
340 
341 	orig_rr = ldns_rr_new();
342 
343 /* if the answer had no answer section, we need to construct our own rr (for instance if
344  * the rr qe asked for doesn't exist. This rr will be destroyed when the chain is freed */
345 	if (ldns_pkt_ancount(pkt) < 1) {
346 		ldns_rr_set_type(orig_rr, type);
347 		ldns_rr_set_owner(orig_rr, ldns_rdf_clone(name));
348 
349 		chain = ldns_dnssec_build_data_chain(res, qflags, rrset, pkt, ldns_rr_clone(orig_rr));
350 	} else {
351 		/* chase the first answer */
352 		chain = ldns_dnssec_build_data_chain(res, qflags, rrset, pkt, NULL);
353 	}
354 
355 	if (verbosity >= 4) {
356 		printf("\n\nDNSSEC Data Chain:\n");
357 		ldns_dnssec_data_chain_print(stdout, chain);
358 	}
359 
360 	result = LDNS_STATUS_OK;
361 
362 	tree = ldns_dnssec_derive_trust_tree(chain, NULL);
363 
364 	if (verbosity >= 2) {
365 		printf("\n\nDNSSEC Trust tree:\n");
366 		ldns_dnssec_trust_tree_print(stdout, tree, 0, true);
367 	}
368 
369 	if (ldns_rr_list_rr_count(trusted_keys) > 0) {
370 		tree_result = ldns_dnssec_trust_tree_contains_keys(tree, trusted_keys);
371 
372 		if (tree_result == LDNS_STATUS_DNSSEC_EXISTENCE_DENIED) {
373 			if (verbosity >= 1) {
374 				printf("Existence denied or verifiably insecure\n");
375 			}
376 			result = LDNS_STATUS_OK;
377 		} else if (tree_result != LDNS_STATUS_OK) {
378 			if (verbosity >= 1) {
379 				printf("No trusted keys found in tree: first error was: %s\n", ldns_get_errorstr_by_id(tree_result));
380 			}
381 			result = tree_result;
382 		}
383 
384 	} else {
385 		if (verbosity >= 0) {
386 			printf("You have not provided any trusted keys.\n");
387 		}
388 	}
389 
390 	ldns_rr_free(orig_rr);
391 	ldns_dnssec_trust_tree_free(tree);
392 	ldns_dnssec_data_chain_deep_free(chain);
393 
394 	ldns_rr_list_deep_free(rrset);
395 	ldns_pkt_free(pkt);
396 	/*	ldns_rr_free(orig_rr);*/
397 
398 	return result;
399 }
400 #endif /* HAVE_SSL */
401 
402