Fix UTIME_OMIT handling
[dragonfly.git] / contrib / ldns / drill / chasetrace.c
blob3bd59563c5c05687c71cc6dc0975142379fa32ff
1 /*
2 * chasetrace.c
3 * Where all the hard work concerning chasing
4 * and tracing is done
5 * (c) 2005, 2006 NLnet Labs
7 * See the file LICENSE for the license
9 */
11 #include "drill.h"
12 #include <ldns/ldns.h>
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.
17 static void add_rr_list_to_referrals(
18 ldns_dnssec_zone *referrals, ldns_rr_list *rr_list)
20 size_t i;
21 ldns_rr *rr;
22 ldns_dnssec_rrsets *rrset;
23 ldns_dnssec_rrs *rrs;
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! */
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);
42 /* Cache all RRs from packet "p" to "referrals" database for lookup later on.
43 * Print the NS RRs that were not already present.
45 static void add_referrals(ldns_dnssec_zone *referrals, ldns_pkt *p)
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);
54 /* Equip name-server "res" with the name-servers authoritative for as much
55 * of "name" as possible. Lookup addresses if needed.
57 static 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)
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;
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;
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;
87 /* remove the old nameserver from the resolver */
88 while ((addr = ldns_resolver_pop_nameserver(res)))
89 ldns_rdf_deep_free(addr);
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) {
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));
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));
106 /* Is our resolver equipped with name-servers? Good! We're done */
107 if (ldns_resolver_nameserver_count(res) > 0)
108 return true;
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);
120 if (ldns_rr_list_rr_count(addrs) == 0)
121 error("Could not find the nameserver ip addr; abort");
123 else if (ldns_resolver_push_nameserver_rr_list(res, addrs) !=
124 LDNS_STATUS_OK)
126 error("Error adding new nameservers");
127 else {
128 ldns_rr_list_deep_free(addrs);
129 return true;
131 add_rr_list_to_referrals(referrals, addrs);
132 ldns_rr_list_deep_free(addrs);
133 return false;
137 * trace down from the root to name
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.
145 void
146 do_trace(ldns_resolver *local_res, ldns_rdf *name, ldns_rr_type t,
147 ldns_rr_class c)
150 static uint8_t zero[1] = { 0 };
151 static const ldns_rdf root_dname = { 1, LDNS_RDF_TYPE_DNAME, &zero };
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;
164 loop_count = 0;
165 final_answer = NULL;
166 res = ldns_resolver_new();
168 if (!res) {
169 error("Memory allocation failed");
170 goto cleanup;
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);
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;
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 */
205 if (ldns_pkt_empty(p)) {
206 warning("No root server information received");
209 if (status == LDNS_STATUS_OK) {
210 if (!ldns_pkt_empty(p)) {
211 drill_pkt_print(stdout, local_res, p);
213 referrals = ldns_dnssec_zone_new();
214 add_referrals(referrals, p);
215 } else {
216 error("cannot use local resolver");
217 goto cleanup;
219 if (! set_nss_for_name(res, referrals, name, local_res, c)) {
220 goto cleanup;
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) {
228 if (!p) {
229 /* some error occurred -- bail out */
230 goto cleanup;
232 add_referrals(referrals, p);
234 /* checks itself for verbosity */
235 drill_pkt_print_footer(stdout, local_res, p);
237 if (! set_nss_for_name(res, referrals, name, local_res, c)) {
238 goto cleanup;
240 if (loop_count++ > 20) {
241 /* unlikely that we are doing anything useful */
242 error("Looks like we are looping");
243 goto cleanup;
245 ldns_pkt_free(p);
246 p = NULL;
247 status = ldns_resolver_send(&p, res, name, t, c, 0);
249 /* Exit trace on error */
250 if (status != LDNS_STATUS_OK)
251 break;
253 /* An answer might be the desired answer (and no referral) */
254 if (ldns_pkt_reply_type(p) != LDNS_PACKET_ANSWER)
255 continue;
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;
264 ldns_rr_list_free(answers);
265 answers = NULL;
267 /* Get the CNAMEs from the answer */
268 cname = ldns_pkt_rr_list_by_type(
269 p, LDNS_RR_TYPE_CNAME, LDNS_SECTION_ANSWER);
271 /* No CNAME either: exit trace */
272 if (ldns_rr_list_rr_count(cname) == 0)
273 break;
275 /* Print CNAME referral */
276 ldns_rr_list_print(stdout, cname);
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;
283 /* remove the old nameserver from the resolver */
284 while((addr = ldns_resolver_pop_nameserver(res)))
285 ldns_rdf_deep_free(addr);
287 /* Restart trace from the root up */
288 (void) ldns_resolver_push_nameserver_rr_list(
289 res, global_dns_root);
291 ldns_pkt_free(p);
292 p = NULL;
293 status = ldns_resolver_send(&p, res, name, t, c, 0);
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;
302 new_nss = ldns_pkt_authority(p);
303 final_answer = ldns_pkt_answer(p);
305 if (verbosity != -1) {
306 ldns_rr_list_print(stdout, final_answer);
307 ldns_rr_list_print(stdout, new_nss);
310 drill_pkt_print_footer(stdout, local_res, p);
311 cleanup:
312 if (res) {
313 while((addr = ldns_resolver_pop_nameserver(res)))
314 ldns_rdf_deep_free(addr);
315 ldns_resolver_free(res);
317 if (referrals)
318 ldns_dnssec_zone_deep_free(referrals);
319 if (p)
320 ldns_pkt_free(p);
325 * Chase the given rr to a known and trusted key
327 * Based on drill 0.9
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
332 #ifdef HAVE_SSL
333 ldns_status
334 do_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))
343 ldns_rr_list *rrset = NULL;
344 ldns_status result;
345 ldns_rr *orig_rr = NULL;
348 ldns_rr_list *sigs;
349 ldns_rr *cur_sig;
350 uint16_t sig_i;
351 ldns_rr_list *keys;
353 ldns_pkt *pkt;
354 ldns_status tree_result;
355 ldns_dnssec_data_chain *chain;
356 ldns_dnssec_trust_tree *tree;
358 const ldns_rr_descriptor *descriptor;
359 descriptor = ldns_rr_descript(type);
361 ldns_dname2canonical(name);
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;
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);
379 if (!trusted_keys || ldns_rr_list_rr_count(trusted_keys) < 1) {
380 warning("No trusted keys specified");
383 if (pkt) {
384 rrset = ldns_pkt_rr_list_by_name_and_type(pkt,
385 name,
386 type,
387 LDNS_SECTION_ANSWER
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
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
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
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");
420 return LDNS_STATUS_MEM_ERR;
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);
429 if (!pkt) {
430 if (verbosity >= 0) {
431 fprintf(stderr, "%s", ldns_get_errorstr_by_id(LDNS_STATUS_NETWORK_ERR));
432 fprintf(stderr, "\n");
434 return LDNS_STATUS_NETWORK_ERR;
436 if (verbosity >= 5) {
437 ldns_pkt_print(stdout, pkt);
440 rrset = ldns_pkt_rr_list_by_name_and_type(pkt,
441 name,
442 type,
443 LDNS_SECTION_ANSWER
447 orig_rr = ldns_rr_new();
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));
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);
461 if (verbosity >= 4) {
462 printf("\n\nDNSSEC Data Chain:\n");
463 ldns_dnssec_data_chain_print(stdout, chain);
466 result = LDNS_STATUS_OK;
468 tree = ldns_dnssec_derive_trust_tree(chain, NULL);
470 if (verbosity >= 2) {
471 printf("\n\nDNSSEC Trust tree:\n");
472 ldns_dnssec_trust_tree_print(stdout, tree, 0, true);
475 if (ldns_rr_list_rr_count(trusted_keys) > 0) {
476 tree_result = ldns_dnssec_trust_tree_contains_keys(tree, trusted_keys);
478 if (tree_result == LDNS_STATUS_DNSSEC_EXISTENCE_DENIED) {
479 if (verbosity >= 1) {
480 printf("Existence denied or verifiably insecure\n");
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));
487 result = tree_result;
490 } else {
491 if (verbosity >= 0) {
492 printf("You have not provided any trusted keys.\n");
496 ldns_rr_free(orig_rr);
497 ldns_dnssec_trust_tree_free(tree);
498 ldns_dnssec_data_chain_deep_free(chain);
500 ldns_rr_list_deep_free(rrset);
501 ldns_pkt_free(pkt);
502 /* ldns_rr_free(orig_rr);*/
504 return result;
506 #endif /* HAVE_SSL */