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