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 /* 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. 16 */ 17 static void add_rr_list_to_referrals( 18 ldns_dnssec_zone *referrals, ldns_rr_list *rr_list) 19 { 20 size_t i; 21 ldns_rr *rr; 22 ldns_dnssec_rrsets *rrset; 23 ldns_dnssec_rrs *rrs; 24 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! */ 35 } 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); 39 } 40 } 41 42 /* Cache all RRs from packet "p" to "referrals" database for lookup later on. 43 * Print the NS RRs that were not already present. 44 */ 45 static void add_referrals(ldns_dnssec_zone *referrals, ldns_pkt *p) 46 { 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); 51 } 52 } 53 54 /* Equip name-server "res" with the name-servers authoritative for as much 55 * of "name" as possible. Lookup addresses if needed. 56 */ 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) 60 { 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; 69 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; 77 } 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; 84 } 85 } 86 87 /* remove the old nameserver from the resolver */ 88 while ((addr = ldns_resolver_pop_nameserver(res))) 89 ldns_rdf_deep_free(addr); 90 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) { 93 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)); 99 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)); 105 } 106 /* Is our resolver equipped with name-servers? Good! We're done */ 107 if (ldns_resolver_nameserver_count(res) > 0) 108 return true; 109 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); 118 } 119 120 if (ldns_rr_list_rr_count(addrs) == 0) 121 error("Could not find the nameserver ip addr; abort"); 122 123 else if (ldns_resolver_push_nameserver_rr_list(res, addrs) != 124 LDNS_STATUS_OK) 125 126 error("Error adding new nameservers"); 127 else { 128 ldns_rr_list_deep_free(addrs); 129 return true; 130 } 131 add_rr_list_to_referrals(referrals, addrs); 132 ldns_rr_list_deep_free(addrs); 133 return false; 134 } 135 136 /** 137 * trace down from the root to name 138 */ 139 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. 144 */ 145 void 146 do_trace(ldns_resolver *local_res, ldns_rdf *name, ldns_rr_type t, 147 ldns_rr_class c) 148 { 149 150 static uint8_t zero[1] = { 0 }; 151 static const ldns_rdf root_dname = { 1, LDNS_RDF_TYPE_DNAME, &zero }; 152 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; 163 164 loop_count = 0; 165 final_answer = NULL; 166 res = ldns_resolver_new(); 167 168 if (!res) { 169 error("Memory allocation failed"); 170 goto cleanup; 171 } 172 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); 192 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; 199 } 200 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 */ 204 205 if (ldns_pkt_empty(p)) { 206 warning("No root server information received"); 207 } 208 209 if (status == LDNS_STATUS_OK) { 210 if (!ldns_pkt_empty(p)) { 211 drill_pkt_print(stdout, local_res, p); 212 } 213 referrals = ldns_dnssec_zone_new(); 214 add_referrals(referrals, p); 215 } else { 216 error("cannot use local resolver"); 217 goto cleanup; 218 } 219 if (! set_nss_for_name(res, referrals, name, local_res, c)) { 220 goto cleanup; 221 } 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) { 227 228 if (!p) { 229 /* some error occurred -- bail out */ 230 goto cleanup; 231 } 232 add_referrals(referrals, p); 233 234 /* checks itself for verbosity */ 235 drill_pkt_print_footer(stdout, local_res, p); 236 237 if (! set_nss_for_name(res, referrals, name, local_res, c)) { 238 goto cleanup; 239 } 240 if (loop_count++ > 20) { 241 /* unlikely that we are doing anything useful */ 242 error("Looks like we are looping"); 243 goto cleanup; 244 } 245 ldns_pkt_free(p); 246 p = NULL; 247 status = ldns_resolver_send(&p, res, name, t, c, 0); 248 249 /* Exit trace on error */ 250 if (status != LDNS_STATUS_OK) 251 break; 252 253 /* An answer might be the desired answer (and no referral) */ 254 if (ldns_pkt_reply_type(p) != LDNS_PACKET_ANSWER) 255 continue; 256 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; 263 } 264 ldns_rr_list_free(answers); 265 answers = NULL; 266 267 /* Get the CNAMEs from the answer */ 268 cname = ldns_pkt_rr_list_by_type( 269 p, LDNS_RR_TYPE_CNAME, LDNS_SECTION_ANSWER); 270 271 /* No CNAME either: exit trace */ 272 if (ldns_rr_list_rr_count(cname) == 0) 273 break; 274 275 /* Print CNAME referral */ 276 ldns_rr_list_print(stdout, cname); 277 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; 282 283 /* remove the old nameserver from the resolver */ 284 while((addr = ldns_resolver_pop_nameserver(res))) 285 ldns_rdf_deep_free(addr); 286 287 /* Restart trace from the root up */ 288 (void) ldns_resolver_push_nameserver_rr_list( 289 res, global_dns_root); 290 291 ldns_pkt_free(p); 292 p = NULL; 293 status = ldns_resolver_send(&p, res, name, t, c, 0); 294 } 295 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; 301 } 302 new_nss = ldns_pkt_authority(p); 303 final_answer = ldns_pkt_answer(p); 304 305 if (verbosity != -1) { 306 ldns_rr_list_print(stdout, final_answer); 307 ldns_rr_list_print(stdout, new_nss); 308 309 } 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); 316 } 317 if (referrals) 318 ldns_dnssec_zone_deep_free(referrals); 319 if (p) 320 ldns_pkt_free(p); 321 } 322 323 324 /** 325 * Chase the given rr to a known and trusted key 326 * 327 * Based on drill 0.9 328 * 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 331 */ 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)) 342 { 343 ldns_rr_list *rrset = NULL; 344 ldns_status result; 345 ldns_rr *orig_rr = NULL; 346 347 /* 348 ldns_rr_list *sigs; 349 ldns_rr *cur_sig; 350 uint16_t sig_i; 351 ldns_rr_list *keys; 352 */ 353 ldns_pkt *pkt; 354 ldns_status tree_result; 355 ldns_dnssec_data_chain *chain; 356 ldns_dnssec_trust_tree *tree; 357 358 const ldns_rr_descriptor *descriptor; 359 descriptor = ldns_rr_descript(type); 360 361 ldns_dname2canonical(name); 362 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; 368 } 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); 376 } 377 } 378 379 if (!trusted_keys || ldns_rr_list_rr_count(trusted_keys) < 1) { 380 warning("No trusted keys specified"); 381 } 382 383 if (pkt) { 384 rrset = ldns_pkt_rr_list_by_name_and_type(pkt, 385 name, 386 type, 387 LDNS_SECTION_ANSWER 388 ); 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 395 ); 396 } 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 404 ); 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 411 ); 412 } 413 } 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"); 419 } 420 return LDNS_STATUS_MEM_ERR; 421 } 422 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); 428 429 if (!pkt) { 430 if (verbosity >= 0) { 431 fprintf(stderr, "%s", ldns_get_errorstr_by_id(LDNS_STATUS_NETWORK_ERR)); 432 fprintf(stderr, "\n"); 433 } 434 return LDNS_STATUS_NETWORK_ERR; 435 } 436 if (verbosity >= 5) { 437 ldns_pkt_print(stdout, pkt); 438 } 439 440 rrset = ldns_pkt_rr_list_by_name_and_type(pkt, 441 name, 442 type, 443 LDNS_SECTION_ANSWER 444 ); 445 } 446 447 orig_rr = ldns_rr_new(); 448 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)); 454 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); 459 } 460 461 if (verbosity >= 4) { 462 printf("\n\nDNSSEC Data Chain:\n"); 463 ldns_dnssec_data_chain_print(stdout, chain); 464 } 465 466 result = LDNS_STATUS_OK; 467 468 tree = ldns_dnssec_derive_trust_tree(chain, NULL); 469 470 if (verbosity >= 2) { 471 printf("\n\nDNSSEC Trust tree:\n"); 472 ldns_dnssec_trust_tree_print(stdout, tree, 0, true); 473 } 474 475 if (ldns_rr_list_rr_count(trusted_keys) > 0) { 476 tree_result = ldns_dnssec_trust_tree_contains_keys(tree, trusted_keys); 477 478 if (tree_result == LDNS_STATUS_DNSSEC_EXISTENCE_DENIED) { 479 if (verbosity >= 1) { 480 printf("Existence denied or verifiably insecure\n"); 481 } 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)); 486 } 487 result = tree_result; 488 } 489 490 } else { 491 if (verbosity >= 0) { 492 printf("You have not provided any trusted keys.\n"); 493 } 494 } 495 496 ldns_rr_free(orig_rr); 497 ldns_dnssec_trust_tree_free(tree); 498 ldns_dnssec_data_chain_deep_free(chain); 499 500 ldns_rr_list_deep_free(rrset); 501 ldns_pkt_free(pkt); 502 /* ldns_rr_free(orig_rr);*/ 503 504 return result; 505 } 506 #endif /* HAVE_SSL */ 507 508