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