aboutsummaryrefslogtreecommitdiffstats
path: root/drill/chasetrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'drill/chasetrace.c')
-rw-r--r--drill/chasetrace.c328
1 files changed, 214 insertions, 114 deletions
diff --git a/drill/chasetrace.c b/drill/chasetrace.c
index 370f627673e2..1f8a2901ab26 100644
--- a/drill/chasetrace.c
+++ b/drill/chasetrace.c
@@ -11,51 +11,163 @@
#include "drill.h"
#include <ldns/ldns.h>
+/* Cache all RRs from rr_list "rr_list" to "referrals" database for lookup
+ * later on. Print the NS RRs that were not already present.
+ */
+static void add_rr_list_to_referrals(
+ ldns_dnssec_zone *referrals, ldns_rr_list *rr_list)
+{
+ size_t i;
+ ldns_rr *rr;
+ ldns_dnssec_rrsets *rrset;
+ ldns_dnssec_rrs *rrs;
+
+ for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
+ rr = ldns_rr_list_rr(rr_list, i);
+ /* Check if a RR equal to "rr" is present in "referrals" */
+ rrset = ldns_dnssec_zone_find_rrset(
+ referrals, ldns_rr_owner(rr), ldns_rr_get_type(rr));
+ if (rrset) {
+ for (rrs = rrset->rrs; rrs; rrs = rrs->next)
+ if (ldns_rr_compare(rr, rrs->rr) == 0)
+ break;
+ if (rrs) continue; /* "rr" is present, next! */
+ }
+ if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_NS && verbosity != -1)
+ ldns_rr_print(stdout, rr);
+ (void) ldns_dnssec_zone_add_rr(referrals, rr);
+ }
+}
+
+/* Cache all RRs from packet "p" to "referrals" database for lookup later on.
+ * Print the NS RRs that were not already present.
+ */
+static void add_referrals(ldns_dnssec_zone *referrals, ldns_pkt *p)
+{
+ ldns_rr_list *l = ldns_pkt_all_noquestion(p);
+ if (l) {
+ add_rr_list_to_referrals(referrals, l);
+ ldns_rr_list_free(l);
+ }
+}
+
+/* Equip name-server "res" with the name-servers authoritative for as much
+ * of "name" as possible. Lookup addresses if needed.
+ */
+static bool set_nss_for_name(
+ ldns_resolver *res, ldns_dnssec_zone *referrals, ldns_rdf *name,
+ ldns_resolver *local_res, ldns_rr_class c)
+{
+ ldns_dnssec_rrsets *nss = NULL;
+ ldns_dnssec_rrs *nss_rrs;
+ ldns_dnssec_rrsets *as = NULL;
+ ldns_dnssec_rrs *as_rrs;
+ ldns_rdf *lookup = ldns_rdf_clone(name);
+ ldns_rdf *new_lookup;
+ ldns_rdf *addr;
+ ldns_rr_list *addrs;
+
+ /* nss will become the rrset of as much of "name" as possible */
+ for (;;) {
+ nss = ldns_dnssec_zone_find_rrset(
+ referrals, lookup, LDNS_RR_TYPE_NS);
+ if (nss != NULL) {
+ ldns_rdf_deep_free(lookup);
+ break;
+ }
+ new_lookup = ldns_dname_left_chop(lookup);
+ ldns_rdf_deep_free(lookup);
+ lookup = new_lookup;
+ if (!lookup) {
+ error("No referrals for name found");
+ return false;
+ }
+ }
+
+ /* remove the old nameserver from the resolver */
+ while ((addr = ldns_resolver_pop_nameserver(res)))
+ ldns_rdf_deep_free(addr);
+
+ /* Find and add the address records for the rrset as name-servers */
+ for (nss_rrs = nss->rrs; nss_rrs; nss_rrs = nss_rrs->next) {
+
+ if ((as = ldns_dnssec_zone_find_rrset(
+ referrals, ldns_rr_rdf(nss_rrs->rr, 0), LDNS_RR_TYPE_A)))
+ for (as_rrs = as->rrs; as_rrs; as_rrs = as_rrs->next)
+ (void) ldns_resolver_push_nameserver(
+ res, ldns_rr_rdf(as_rrs->rr, 0));
+
+ if ((as = ldns_dnssec_zone_find_rrset(
+ referrals, ldns_rr_rdf(nss_rrs->rr, 0), LDNS_RR_TYPE_AAAA)))
+ for (as_rrs = as->rrs; as_rrs; as_rrs = as_rrs->next)
+ (void) ldns_resolver_push_nameserver(
+ res, ldns_rr_rdf(as_rrs->rr, 0));
+ }
+ /* Is our resolver equipped with name-servers? Good! We're done */
+ if (ldns_resolver_nameserver_count(res) > 0)
+ return true;
+
+ /* Lookup addresses with local resolver add add to "referrals" database */
+ addrs = ldns_rr_list_new();
+ for (nss_rrs = nss->rrs; nss_rrs; nss_rrs = nss_rrs->next) {
+ ldns_rr_list *addrs_by_name =
+ ldns_get_rr_list_addr_by_name(
+ local_res, ldns_rr_rdf(nss_rrs->rr, 0), c, 0);
+ ldns_rr_list_cat(addrs, addrs_by_name);
+ ldns_rr_list_free(addrs_by_name);
+ }
+
+ if (ldns_rr_list_rr_count(addrs) == 0)
+ error("Could not find the nameserver ip addr; abort");
+
+ else if (ldns_resolver_push_nameserver_rr_list(res, addrs) !=
+ LDNS_STATUS_OK)
+
+ error("Error adding new nameservers");
+ else {
+ ldns_rr_list_deep_free(addrs);
+ return true;
+ }
+ add_rr_list_to_referrals(referrals, addrs);
+ ldns_rr_list_deep_free(addrs);
+ return false;
+}
+
/**
* trace down from the root to name
*/
/* same naive method as in drill0.9
- * We resolver _ALL_ the names, which is ofcourse not needed
+ * We resolve _ALL_ the names, which is of course not needed.
* We _do_ use the local resolver to do that, so it still is
- * fast, but it can be made to run much faster
+ * fast, but it can be made to run much faster.
*/
-ldns_pkt *
+void
do_trace(ldns_resolver *local_res, ldns_rdf *name, ldns_rr_type t,
ldns_rr_class c)
{
- ldns_resolver *res;
- ldns_pkt *p;
- ldns_rr_list *new_nss_a;
- ldns_rr_list *new_nss_aaaa;
+
+ static uint8_t zero[1] = { 0 };
+ static const ldns_rdf root_dname = { 1, LDNS_RDF_TYPE_DNAME, &zero };
+
+ ldns_resolver *res = NULL;
+ ldns_pkt *p = NULL;
ldns_rr_list *final_answer;
ldns_rr_list *new_nss;
- ldns_rr_list *ns_addr;
+ ldns_rr_list *cname = NULL;
+ ldns_rr_list *answers = NULL;
uint16_t loop_count;
- ldns_rdf *pop;
ldns_status status;
- size_t i;
+ ldns_dnssec_zone* referrals = NULL;
+ ldns_rdf *addr;
loop_count = 0;
- new_nss_a = NULL;
- new_nss_aaaa = NULL;
- new_nss = NULL;
- ns_addr = NULL;
final_answer = NULL;
- p = ldns_pkt_new();
res = ldns_resolver_new();
- if (!p) {
- if (res) {
- ldns_resolver_free(res);
- }
- error("Memory allocation failed");
- return NULL;
- }
if (!res) {
- ldns_pkt_free(p);
error("Memory allocation failed");
- return NULL;
+ goto cleanup;
}
/* transfer some properties of local_res to res,
@@ -83,16 +195,13 @@ do_trace(ldns_resolver *local_res, ldns_rdf *name, ldns_rr_type t,
if (status != LDNS_STATUS_OK) {
fprintf(stderr, "Error adding root servers to resolver: %s\n", ldns_get_errorstr_by_id(status));
ldns_rr_list_print(stdout, global_dns_root);
- ldns_resolver_free(res);
- ldns_pkt_free(p);
- return NULL;
+ goto cleanup;
}
/* this must be a real query to local_res */
- status = ldns_resolver_send(&p, res, ldns_dname_new_frm_str("."), LDNS_RR_TYPE_NS, c, 0);
+ status = ldns_resolver_send(&p, res, &root_dname, LDNS_RR_TYPE_NS, c, 0);
/* p can still be NULL */
-
if (ldns_pkt_empty(p)) {
warning("No root server information received");
}
@@ -101,111 +210,95 @@ do_trace(ldns_resolver *local_res, ldns_rdf *name, ldns_rr_type t,
if (!ldns_pkt_empty(p)) {
drill_pkt_print(stdout, local_res, p);
}
+ referrals = ldns_dnssec_zone_new();
+ add_referrals(referrals, p);
} else {
error("cannot use local resolver");
- return NULL;
+ goto cleanup;
}
-
+ if (! set_nss_for_name(res, referrals, name, local_res, c)) {
+ goto cleanup;
+ }
+ ldns_pkt_free(p);
+ p = NULL;
status = ldns_resolver_send(&p, res, name, t, c, 0);
-
while(status == LDNS_STATUS_OK &&
ldns_pkt_reply_type(p) == LDNS_PACKET_REFERRAL) {
if (!p) {
- /* some error occurred, bail out */
- return NULL;
+ /* some error occurred -- bail out */
+ goto cleanup;
}
+ add_referrals(referrals, p);
- new_nss_a = ldns_pkt_rr_list_by_type(p,
- LDNS_RR_TYPE_A, LDNS_SECTION_ADDITIONAL);
- new_nss_aaaa = ldns_pkt_rr_list_by_type(p,
- LDNS_RR_TYPE_AAAA, LDNS_SECTION_ADDITIONAL);
- new_nss = ldns_pkt_rr_list_by_type(p,
- LDNS_RR_TYPE_NS, LDNS_SECTION_AUTHORITY);
-
- if (verbosity != -1) {
- ldns_rr_list_print(stdout, new_nss);
- }
/* checks itself for verbosity */
drill_pkt_print_footer(stdout, local_res, p);
- /* remove the old nameserver from the resolver */
- while(ldns_resolver_pop_nameserver(res)) { /* do it */ }
-
- /* also check for new_nss emptyness */
-
- if (!new_nss_aaaa && !new_nss_a) {
- /*
- * no nameserver found!!!
- * try to resolve the names we do got
- */
- for(i = 0; i < ldns_rr_list_rr_count(new_nss); i++) {
- /* get the name of the nameserver */
- pop = ldns_rr_rdf(ldns_rr_list_rr(new_nss, i), 0);
- if (!pop) {
- break;
- }
+ if (! set_nss_for_name(res, referrals, name, local_res, c)) {
+ goto cleanup;
+ }
+ if (loop_count++ > 20) {
+ /* unlikely that we are doing anything useful */
+ error("Looks like we are looping");
+ goto cleanup;
+ }
+ ldns_pkt_free(p);
+ p = NULL;
+ status = ldns_resolver_send(&p, res, name, t, c, 0);
- ldns_rr_list_print(stdout, new_nss);
- ldns_rdf_print(stdout, pop);
- /* retrieve it's addresses */
- ns_addr = ldns_rr_list_cat_clone(ns_addr,
- ldns_get_rr_list_addr_by_name(local_res, pop, c, 0));
- }
+ /* Exit trace on error */
+ if (status != LDNS_STATUS_OK)
+ break;
- if (ns_addr) {
- if (ldns_resolver_push_nameserver_rr_list(res, ns_addr) !=
- LDNS_STATUS_OK) {
- error("Error adding new nameservers");
- ldns_pkt_free(p);
- return NULL;
- }
- ldns_rr_list_free(ns_addr);
- } else {
- ldns_rr_list_print(stdout, ns_addr);
- error("Could not find the nameserver ip addr; abort");
- ldns_pkt_free(p);
- return NULL;
- }
- }
+ /* An answer might be the desired answer (and no referral) */
+ if (ldns_pkt_reply_type(p) != LDNS_PACKET_ANSWER)
+ continue;
- /* add the new ones */
- if (new_nss_aaaa) {
- if (ldns_resolver_push_nameserver_rr_list(res, new_nss_aaaa) !=
- LDNS_STATUS_OK) {
- error("adding new nameservers");
- ldns_pkt_free(p);
- return NULL;
- }
- }
- if (new_nss_a) {
- if (ldns_resolver_push_nameserver_rr_list(res, new_nss_a) !=
- LDNS_STATUS_OK) {
- error("adding new nameservers");
- ldns_pkt_free(p);
- return NULL;
- }
+ /* Exit trace when the requested type is found */
+ answers = ldns_pkt_rr_list_by_type(p, t, LDNS_SECTION_ANSWER);
+ if (answers && ldns_rr_list_rr_count(answers) > 0) {
+ ldns_rr_list_free(answers);
+ answers = NULL;
+ break;
}
+ ldns_rr_list_free(answers);
+ answers = NULL;
- if (loop_count++ > 20) {
- /* unlikely that we are doing something usefull */
- error("Looks like we are looping");
- ldns_pkt_free(p);
- return NULL;
- }
-
+ /* Get the CNAMEs from the answer */
+ cname = ldns_pkt_rr_list_by_type(
+ p, LDNS_RR_TYPE_CNAME, LDNS_SECTION_ANSWER);
+
+ /* No CNAME either: exit trace */
+ if (ldns_rr_list_rr_count(cname) == 0)
+ break;
+
+ /* Print CNAME referral */
+ ldns_rr_list_print(stdout, cname);
+
+ /* restart with the CNAME */
+ name = ldns_rr_rdf(ldns_rr_list_rr(cname, 0), 0);
+ ldns_rr_list_free(cname);
+ cname = NULL;
+
+ /* remove the old nameserver from the resolver */
+ while((addr = ldns_resolver_pop_nameserver(res)))
+ ldns_rdf_deep_free(addr);
+
+ /* Restart trace from the root up */
+ (void) ldns_resolver_push_nameserver_rr_list(
+ res, global_dns_root);
+
+ ldns_pkt_free(p);
+ p = NULL;
status = ldns_resolver_send(&p, res, name, t, c, 0);
- new_nss_aaaa = NULL;
- new_nss_a = NULL;
- ns_addr = NULL;
}
+ ldns_pkt_free(p);
+ p = NULL;
status = ldns_resolver_send(&p, res, name, t, c, 0);
-
if (!p) {
- return NULL;
+ goto cleanup;
}
-
new_nss = ldns_pkt_authority(p);
final_answer = ldns_pkt_answer(p);
@@ -215,8 +308,16 @@ do_trace(ldns_resolver *local_res, ldns_rdf *name, ldns_rr_type t,
}
drill_pkt_print_footer(stdout, local_res, p);
- ldns_pkt_free(p);
- return NULL;
+cleanup:
+ if (res) {
+ while((addr = ldns_resolver_pop_nameserver(res)))
+ ldns_rdf_deep_free(addr);
+ ldns_resolver_free(res);
+ }
+ if (referrals)
+ ldns_dnssec_zone_deep_free(referrals);
+ if (p)
+ ldns_pkt_free(p);
}
@@ -237,8 +338,7 @@ do_chase(ldns_resolver *res,
ldns_rr_list *trusted_keys,
ldns_pkt *pkt_o,
uint16_t qflags,
- ldns_rr_list * ATTR_UNUSED(prev_key_list),
- int verbosity)
+ ldns_rr_list * ATTR_UNUSED(prev_key_list))
{
ldns_rr_list *rrset = NULL;
ldns_status result;