1238104Sdes/* 2238104Sdes * resolver.c 3238104Sdes * 4238104Sdes * resolver implementation 5238104Sdes * 6238104Sdes * a Net::DNS like library for C 7238104Sdes * 8238104Sdes * (c) NLnet Labs, 2004-2006 9238104Sdes * 10238104Sdes * See the file LICENSE for the license 11238104Sdes */ 12238104Sdes 13238104Sdes#include <ldns/config.h> 14238104Sdes 15238104Sdes#include <ldns/ldns.h> 16238104Sdes#include <strings.h> 17238104Sdes 18238104Sdes/* Access function for reading 19238104Sdes * and setting the different Resolver 20238104Sdes * options */ 21238104Sdes 22238104Sdes/* read */ 23238104Sdesuint16_t 24238104Sdesldns_resolver_port(const ldns_resolver *r) 25238104Sdes{ 26238104Sdes return r->_port; 27238104Sdes} 28238104Sdes 29266114Sdesldns_rdf * 30266114Sdesldns_resolver_source(const ldns_resolver *r) 31266114Sdes{ 32266114Sdes return r->_source; 33266114Sdes} 34266114Sdes 35238104Sdesuint16_t 36238104Sdesldns_resolver_edns_udp_size(const ldns_resolver *r) 37238104Sdes{ 38238104Sdes return r->_edns_udp_size; 39238104Sdes} 40238104Sdes 41238104Sdesuint8_t 42238104Sdesldns_resolver_retry(const ldns_resolver *r) 43238104Sdes{ 44238104Sdes return r->_retry; 45238104Sdes} 46238104Sdes 47238104Sdesuint8_t 48238104Sdesldns_resolver_retrans(const ldns_resolver *r) 49238104Sdes{ 50238104Sdes return r->_retrans; 51238104Sdes} 52238104Sdes 53238104Sdesbool 54238104Sdesldns_resolver_fallback(const ldns_resolver *r) 55238104Sdes{ 56238104Sdes return r->_fallback; 57238104Sdes} 58238104Sdes 59238104Sdesuint8_t 60238104Sdesldns_resolver_ip6(const ldns_resolver *r) 61238104Sdes{ 62238104Sdes return r->_ip6; 63238104Sdes} 64238104Sdes 65238104Sdesbool 66238104Sdesldns_resolver_recursive(const ldns_resolver *r) 67238104Sdes{ 68238104Sdes return r->_recursive; 69238104Sdes} 70238104Sdes 71238104Sdesbool 72238104Sdesldns_resolver_debug(const ldns_resolver *r) 73238104Sdes{ 74238104Sdes return r->_debug; 75238104Sdes} 76238104Sdes 77238104Sdesbool 78238104Sdesldns_resolver_dnsrch(const ldns_resolver *r) 79238104Sdes{ 80238104Sdes return r->_dnsrch; 81238104Sdes} 82238104Sdes 83238104Sdesbool 84238104Sdesldns_resolver_fail(const ldns_resolver *r) 85238104Sdes{ 86238104Sdes return r->_fail; 87238104Sdes} 88238104Sdes 89238104Sdesbool 90238104Sdesldns_resolver_defnames(const ldns_resolver *r) 91238104Sdes{ 92238104Sdes return r->_defnames; 93238104Sdes} 94238104Sdes 95238104Sdesldns_rdf * 96238104Sdesldns_resolver_domain(const ldns_resolver *r) 97238104Sdes{ 98238104Sdes return r->_domain; 99238104Sdes} 100238104Sdes 101238104Sdesldns_rdf ** 102238104Sdesldns_resolver_searchlist(const ldns_resolver *r) 103238104Sdes{ 104238104Sdes return r->_searchlist; 105238104Sdes} 106238104Sdes 107238104Sdesldns_rdf ** 108238104Sdesldns_resolver_nameservers(const ldns_resolver *r) 109238104Sdes{ 110238104Sdes return r->_nameservers; 111238104Sdes} 112238104Sdes 113238104Sdessize_t 114238104Sdesldns_resolver_nameserver_count(const ldns_resolver *r) 115238104Sdes{ 116238104Sdes return r->_nameserver_count; 117238104Sdes} 118238104Sdes 119238104Sdesbool 120238104Sdesldns_resolver_dnssec(const ldns_resolver *r) 121238104Sdes{ 122238104Sdes return r->_dnssec; 123238104Sdes} 124238104Sdes 125238104Sdesbool 126238104Sdesldns_resolver_dnssec_cd(const ldns_resolver *r) 127238104Sdes{ 128238104Sdes return r->_dnssec_cd; 129238104Sdes} 130238104Sdes 131238104Sdesldns_rr_list * 132238104Sdesldns_resolver_dnssec_anchors(const ldns_resolver *r) 133238104Sdes{ 134238104Sdes return r->_dnssec_anchors; 135238104Sdes} 136238104Sdes 137238104Sdesbool 138238104Sdesldns_resolver_trusted_key(const ldns_resolver *r, ldns_rr_list * keys, ldns_rr_list * trusted_keys) 139238104Sdes{ 140238104Sdes size_t i; 141238104Sdes bool result = false; 142238104Sdes 143238104Sdes ldns_rr_list * trust_anchors; 144238104Sdes ldns_rr * cur_rr; 145238104Sdes 146238104Sdes if (!r || !keys) { return false; } 147238104Sdes 148238104Sdes trust_anchors = ldns_resolver_dnssec_anchors(r); 149238104Sdes 150238104Sdes if (!trust_anchors) { return false; } 151238104Sdes 152238104Sdes for (i = 0; i < ldns_rr_list_rr_count(keys); i++) { 153238104Sdes 154238104Sdes cur_rr = ldns_rr_list_rr(keys, i); 155238104Sdes if (ldns_rr_list_contains_rr(trust_anchors, cur_rr)) { 156238104Sdes if (trusted_keys) { ldns_rr_list_push_rr(trusted_keys, cur_rr); } 157238104Sdes result = true; 158238104Sdes } 159238104Sdes } 160238104Sdes 161238104Sdes return result; 162238104Sdes} 163238104Sdes 164238104Sdesbool 165238104Sdesldns_resolver_igntc(const ldns_resolver *r) 166238104Sdes{ 167238104Sdes return r->_igntc; 168238104Sdes} 169238104Sdes 170238104Sdesbool 171238104Sdesldns_resolver_usevc(const ldns_resolver *r) 172238104Sdes{ 173238104Sdes return r->_usevc; 174238104Sdes} 175238104Sdes 176238104Sdessize_t * 177238104Sdesldns_resolver_rtt(const ldns_resolver *r) 178238104Sdes{ 179238104Sdes return r->_rtt; 180238104Sdes} 181238104Sdes 182238104Sdessize_t 183238104Sdesldns_resolver_nameserver_rtt(const ldns_resolver *r, size_t pos) 184238104Sdes{ 185238104Sdes size_t *rtt; 186238104Sdes 187238104Sdes assert(r != NULL); 188238104Sdes 189238104Sdes rtt = ldns_resolver_rtt(r); 190238104Sdes 191238104Sdes if (pos >= ldns_resolver_nameserver_count(r)) { 192238104Sdes /* error ?*/ 193238104Sdes return 0; 194238104Sdes } else { 195238104Sdes return rtt[pos]; 196238104Sdes } 197238104Sdes 198238104Sdes} 199238104Sdes 200238104Sdesstruct timeval 201238104Sdesldns_resolver_timeout(const ldns_resolver *r) 202238104Sdes{ 203238104Sdes return r->_timeout; 204238104Sdes} 205238104Sdes 206238104Sdeschar * 207238104Sdesldns_resolver_tsig_keyname(const ldns_resolver *r) 208238104Sdes{ 209238104Sdes return r->_tsig_keyname; 210238104Sdes} 211238104Sdes 212238104Sdeschar * 213238104Sdesldns_resolver_tsig_algorithm(const ldns_resolver *r) 214238104Sdes{ 215238104Sdes return r->_tsig_algorithm; 216238104Sdes} 217238104Sdes 218238104Sdeschar * 219238104Sdesldns_resolver_tsig_keydata(const ldns_resolver *r) 220238104Sdes{ 221238104Sdes return r->_tsig_keydata; 222238104Sdes} 223238104Sdes 224238104Sdesbool 225238104Sdesldns_resolver_random(const ldns_resolver *r) 226238104Sdes{ 227238104Sdes return r->_random; 228238104Sdes} 229238104Sdes 230238104Sdessize_t 231238104Sdesldns_resolver_searchlist_count(const ldns_resolver *r) 232238104Sdes{ 233238104Sdes return r->_searchlist_count; 234238104Sdes} 235238104Sdes 236238104Sdes/* write */ 237238104Sdesvoid 238238104Sdesldns_resolver_set_port(ldns_resolver *r, uint16_t p) 239238104Sdes{ 240238104Sdes r->_port = p; 241238104Sdes} 242238104Sdes 243266114Sdesvoid 244266114Sdesldns_resolver_set_source(ldns_resolver *r, ldns_rdf *s) 245266114Sdes{ 246266114Sdes r->_source = s; 247266114Sdes} 248266114Sdes 249238104Sdesldns_rdf * 250238104Sdesldns_resolver_pop_nameserver(ldns_resolver *r) 251238104Sdes{ 252238104Sdes ldns_rdf **nameservers; 253238104Sdes ldns_rdf *pop; 254238104Sdes size_t ns_count; 255238104Sdes size_t *rtt; 256238104Sdes 257238104Sdes assert(r != NULL); 258238104Sdes 259238104Sdes ns_count = ldns_resolver_nameserver_count(r); 260238104Sdes nameservers = ldns_resolver_nameservers(r); 261238104Sdes rtt = ldns_resolver_rtt(r); 262238104Sdes if (ns_count == 0 || !nameservers) { 263238104Sdes return NULL; 264238104Sdes } 265238104Sdes 266238104Sdes pop = nameservers[ns_count - 1]; 267238104Sdes 268246854Sdes if (ns_count == 1) { 269246854Sdes LDNS_FREE(nameservers); 270246854Sdes LDNS_FREE(rtt); 271238104Sdes 272246854Sdes ldns_resolver_set_nameservers(r, NULL); 273246854Sdes ldns_resolver_set_rtt(r, NULL); 274246854Sdes } else { 275246854Sdes nameservers = LDNS_XREALLOC(nameservers, ldns_rdf *, 276246854Sdes (ns_count - 1)); 277246854Sdes rtt = LDNS_XREALLOC(rtt, size_t, (ns_count - 1)); 278246854Sdes 279238104Sdes ldns_resolver_set_nameservers(r, nameservers); 280238104Sdes ldns_resolver_set_rtt(r, rtt); 281246854Sdes } 282238104Sdes /* decr the count */ 283238104Sdes ldns_resolver_dec_nameserver_count(r); 284238104Sdes return pop; 285238104Sdes} 286238104Sdes 287238104Sdesldns_status 288238104Sdesldns_resolver_push_nameserver(ldns_resolver *r, ldns_rdf *n) 289238104Sdes{ 290238104Sdes ldns_rdf **nameservers; 291238104Sdes size_t ns_count; 292238104Sdes size_t *rtt; 293238104Sdes 294238104Sdes if (ldns_rdf_get_type(n) != LDNS_RDF_TYPE_A && 295238104Sdes ldns_rdf_get_type(n) != LDNS_RDF_TYPE_AAAA) { 296238104Sdes return LDNS_STATUS_ERR; 297238104Sdes } 298238104Sdes 299238104Sdes ns_count = ldns_resolver_nameserver_count(r); 300238104Sdes nameservers = ldns_resolver_nameservers(r); 301238104Sdes rtt = ldns_resolver_rtt(r); 302238104Sdes 303238104Sdes /* make room for the next one */ 304238104Sdes if (ns_count == 0) { 305238104Sdes nameservers = LDNS_XMALLOC(ldns_rdf *, 1); 306238104Sdes } else { 307238104Sdes nameservers = LDNS_XREALLOC(nameservers, ldns_rdf *, (ns_count + 1)); 308238104Sdes } 309238104Sdes if(!nameservers) 310238104Sdes return LDNS_STATUS_MEM_ERR; 311238104Sdes 312238104Sdes /* set the new value in the resolver */ 313238104Sdes ldns_resolver_set_nameservers(r, nameservers); 314238104Sdes 315238104Sdes /* don't forget the rtt */ 316238104Sdes if (ns_count == 0) { 317238104Sdes rtt = LDNS_XMALLOC(size_t, 1); 318238104Sdes } else { 319238104Sdes rtt = LDNS_XREALLOC(rtt, size_t, (ns_count + 1)); 320238104Sdes } 321238104Sdes if(!rtt) 322238104Sdes return LDNS_STATUS_MEM_ERR; 323238104Sdes 324238104Sdes /* slide n in its slot. */ 325238104Sdes /* we clone it here, because then we can free the original 326238104Sdes * rr's where it stood */ 327238104Sdes nameservers[ns_count] = ldns_rdf_clone(n); 328238104Sdes rtt[ns_count] = LDNS_RESOLV_RTT_MIN; 329238104Sdes ldns_resolver_incr_nameserver_count(r); 330238104Sdes ldns_resolver_set_rtt(r, rtt); 331238104Sdes return LDNS_STATUS_OK; 332238104Sdes} 333238104Sdes 334238104Sdesldns_status 335238104Sdesldns_resolver_push_nameserver_rr(ldns_resolver *r, ldns_rr *rr) 336238104Sdes{ 337238104Sdes ldns_rdf *address; 338238104Sdes if ((!rr) || (ldns_rr_get_type(rr) != LDNS_RR_TYPE_A && 339238104Sdes ldns_rr_get_type(rr) != LDNS_RR_TYPE_AAAA)) { 340238104Sdes return LDNS_STATUS_ERR; 341238104Sdes } 342238104Sdes address = ldns_rr_rdf(rr, 0); /* extract the ip number */ 343238104Sdes if (address) { 344238104Sdes return ldns_resolver_push_nameserver(r, address); 345238104Sdes } else { 346238104Sdes return LDNS_STATUS_ERR; 347238104Sdes } 348238104Sdes} 349238104Sdes 350238104Sdesldns_status 351238104Sdesldns_resolver_push_nameserver_rr_list(ldns_resolver *r, ldns_rr_list *rrlist) 352238104Sdes{ 353238104Sdes ldns_rr *rr; 354238104Sdes ldns_status stat; 355238104Sdes size_t i; 356238104Sdes 357238104Sdes stat = LDNS_STATUS_OK; 358238104Sdes if (rrlist) { 359238104Sdes for(i = 0; i < ldns_rr_list_rr_count(rrlist); i++) { 360238104Sdes rr = ldns_rr_list_rr(rrlist, i); 361238104Sdes if (ldns_resolver_push_nameserver_rr(r, rr) != LDNS_STATUS_OK) { 362238104Sdes stat = LDNS_STATUS_ERR; 363238104Sdes break; 364238104Sdes } 365238104Sdes } 366238104Sdes return stat; 367238104Sdes } else { 368238104Sdes return LDNS_STATUS_ERR; 369238104Sdes } 370238104Sdes} 371238104Sdes 372238104Sdesvoid 373238104Sdesldns_resolver_set_edns_udp_size(ldns_resolver *r, uint16_t s) 374238104Sdes{ 375238104Sdes r->_edns_udp_size = s; 376238104Sdes} 377238104Sdes 378238104Sdesvoid 379238104Sdesldns_resolver_set_recursive(ldns_resolver *r, bool re) 380238104Sdes{ 381238104Sdes r->_recursive = re; 382238104Sdes} 383238104Sdes 384238104Sdesvoid 385238104Sdesldns_resolver_set_dnssec(ldns_resolver *r, bool d) 386238104Sdes{ 387238104Sdes r->_dnssec = d; 388238104Sdes} 389238104Sdes 390238104Sdesvoid 391238104Sdesldns_resolver_set_dnssec_cd(ldns_resolver *r, bool d) 392238104Sdes{ 393238104Sdes r->_dnssec_cd = d; 394238104Sdes} 395238104Sdes 396238104Sdesvoid 397238104Sdesldns_resolver_set_dnssec_anchors(ldns_resolver *r, ldns_rr_list * l) 398238104Sdes{ 399238104Sdes r->_dnssec_anchors = l; 400238104Sdes} 401238104Sdes 402238104Sdesldns_status 403238104Sdesldns_resolver_push_dnssec_anchor(ldns_resolver *r, ldns_rr *rr) 404238104Sdes{ 405238104Sdes ldns_rr_list * trust_anchors; 406238104Sdes 407246854Sdes if ((!rr) || (ldns_rr_get_type(rr) != LDNS_RR_TYPE_DNSKEY && 408246854Sdes ldns_rr_get_type(rr) != LDNS_RR_TYPE_DS)) { 409246854Sdes 410238104Sdes return LDNS_STATUS_ERR; 411238104Sdes } 412238104Sdes 413238104Sdes if (!(trust_anchors = ldns_resolver_dnssec_anchors(r))) { /* Initialize */ 414238104Sdes trust_anchors = ldns_rr_list_new(); 415238104Sdes ldns_resolver_set_dnssec_anchors(r, trust_anchors); 416238104Sdes } 417238104Sdes 418238104Sdes return (ldns_rr_list_push_rr(trust_anchors, ldns_rr_clone(rr))) ? LDNS_STATUS_OK : LDNS_STATUS_ERR; 419238104Sdes} 420238104Sdes 421238104Sdesvoid 422238104Sdesldns_resolver_set_igntc(ldns_resolver *r, bool i) 423238104Sdes{ 424238104Sdes r->_igntc = i; 425238104Sdes} 426238104Sdes 427238104Sdesvoid 428238104Sdesldns_resolver_set_usevc(ldns_resolver *r, bool vc) 429238104Sdes{ 430238104Sdes r->_usevc = vc; 431238104Sdes} 432238104Sdes 433238104Sdesvoid 434238104Sdesldns_resolver_set_debug(ldns_resolver *r, bool d) 435238104Sdes{ 436238104Sdes r->_debug = d; 437238104Sdes} 438238104Sdes 439238104Sdesvoid 440238104Sdesldns_resolver_set_ip6(ldns_resolver *r, uint8_t ip6) 441238104Sdes{ 442238104Sdes r->_ip6 = ip6; 443238104Sdes} 444238104Sdes 445238104Sdesvoid 446238104Sdesldns_resolver_set_fail(ldns_resolver *r, bool f) 447238104Sdes{ 448238104Sdes r->_fail =f; 449238104Sdes} 450238104Sdes 451246827Sdesstatic void 452238104Sdesldns_resolver_set_searchlist_count(ldns_resolver *r, size_t c) 453238104Sdes{ 454238104Sdes r->_searchlist_count = c; 455238104Sdes} 456238104Sdes 457238104Sdesvoid 458238104Sdesldns_resolver_set_nameserver_count(ldns_resolver *r, size_t c) 459238104Sdes{ 460238104Sdes r->_nameserver_count = c; 461238104Sdes} 462238104Sdes 463238104Sdesvoid 464238104Sdesldns_resolver_set_dnsrch(ldns_resolver *r, bool d) 465238104Sdes{ 466238104Sdes r->_dnsrch = d; 467238104Sdes} 468238104Sdes 469238104Sdesvoid 470238104Sdesldns_resolver_set_retry(ldns_resolver *r, uint8_t retry) 471238104Sdes{ 472238104Sdes r->_retry = retry; 473238104Sdes} 474238104Sdes 475238104Sdesvoid 476238104Sdesldns_resolver_set_retrans(ldns_resolver *r, uint8_t retrans) 477238104Sdes{ 478238104Sdes r->_retrans = retrans; 479238104Sdes} 480238104Sdes 481238104Sdesvoid 482238104Sdesldns_resolver_set_fallback(ldns_resolver *r, bool fallback) 483238104Sdes{ 484238104Sdes r->_fallback = fallback; 485238104Sdes} 486238104Sdes 487238104Sdesvoid 488238104Sdesldns_resolver_set_nameservers(ldns_resolver *r, ldns_rdf **n) 489238104Sdes{ 490238104Sdes r->_nameservers = n; 491238104Sdes} 492238104Sdes 493238104Sdesvoid 494238104Sdesldns_resolver_set_defnames(ldns_resolver *r, bool d) 495238104Sdes{ 496238104Sdes r->_defnames = d; 497238104Sdes} 498238104Sdes 499238104Sdesvoid 500238104Sdesldns_resolver_set_rtt(ldns_resolver *r, size_t *rtt) 501238104Sdes{ 502238104Sdes r->_rtt = rtt; 503238104Sdes} 504238104Sdes 505238104Sdesvoid 506238104Sdesldns_resolver_set_nameserver_rtt(ldns_resolver *r, size_t pos, size_t value) 507238104Sdes{ 508238104Sdes size_t *rtt; 509238104Sdes 510238104Sdes assert(r != NULL); 511238104Sdes 512238104Sdes rtt = ldns_resolver_rtt(r); 513238104Sdes 514238104Sdes if (pos >= ldns_resolver_nameserver_count(r)) { 515238104Sdes /* error ?*/ 516238104Sdes } else { 517238104Sdes rtt[pos] = value; 518238104Sdes } 519238104Sdes 520238104Sdes} 521238104Sdes 522238104Sdesvoid 523238104Sdesldns_resolver_incr_nameserver_count(ldns_resolver *r) 524238104Sdes{ 525238104Sdes size_t c; 526238104Sdes 527238104Sdes c = ldns_resolver_nameserver_count(r); 528238104Sdes ldns_resolver_set_nameserver_count(r, ++c); 529238104Sdes} 530238104Sdes 531238104Sdesvoid 532238104Sdesldns_resolver_dec_nameserver_count(ldns_resolver *r) 533238104Sdes{ 534238104Sdes size_t c; 535238104Sdes 536238104Sdes c = ldns_resolver_nameserver_count(r); 537238104Sdes if (c == 0) { 538238104Sdes return; 539238104Sdes } else { 540238104Sdes ldns_resolver_set_nameserver_count(r, --c); 541238104Sdes } 542238104Sdes} 543238104Sdes 544238104Sdesvoid 545238104Sdesldns_resolver_set_domain(ldns_resolver *r, ldns_rdf *d) 546238104Sdes{ 547238104Sdes r->_domain = d; 548238104Sdes} 549238104Sdes 550238104Sdesvoid 551238104Sdesldns_resolver_set_timeout(ldns_resolver *r, struct timeval timeout) 552238104Sdes{ 553238104Sdes r->_timeout.tv_sec = timeout.tv_sec; 554238104Sdes r->_timeout.tv_usec = timeout.tv_usec; 555238104Sdes} 556238104Sdes 557238104Sdesvoid 558238104Sdesldns_resolver_push_searchlist(ldns_resolver *r, ldns_rdf *d) 559238104Sdes{ 560238104Sdes ldns_rdf **searchlist; 561238104Sdes size_t list_count; 562238104Sdes 563238104Sdes if (ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME) { 564238104Sdes return; 565238104Sdes } 566238104Sdes 567238104Sdes list_count = ldns_resolver_searchlist_count(r); 568238104Sdes searchlist = ldns_resolver_searchlist(r); 569238104Sdes 570238104Sdes searchlist = LDNS_XREALLOC(searchlist, ldns_rdf *, (list_count + 1)); 571238104Sdes if (searchlist) { 572238104Sdes r->_searchlist = searchlist; 573238104Sdes 574238104Sdes searchlist[list_count] = ldns_rdf_clone(d); 575238104Sdes ldns_resolver_set_searchlist_count(r, list_count + 1); 576238104Sdes } /* no way to report mem err */ 577238104Sdes} 578238104Sdes 579238104Sdesvoid 580238104Sdesldns_resolver_set_tsig_keyname(ldns_resolver *r, char *tsig_keyname) 581238104Sdes{ 582238104Sdes LDNS_FREE(r->_tsig_keyname); 583238104Sdes r->_tsig_keyname = strdup(tsig_keyname); 584238104Sdes} 585238104Sdes 586238104Sdesvoid 587238104Sdesldns_resolver_set_tsig_algorithm(ldns_resolver *r, char *tsig_algorithm) 588238104Sdes{ 589238104Sdes LDNS_FREE(r->_tsig_algorithm); 590238104Sdes r->_tsig_algorithm = strdup(tsig_algorithm); 591238104Sdes} 592238104Sdes 593238104Sdesvoid 594238104Sdesldns_resolver_set_tsig_keydata(ldns_resolver *r, char *tsig_keydata) 595238104Sdes{ 596238104Sdes LDNS_FREE(r->_tsig_keydata); 597238104Sdes r->_tsig_keydata = strdup(tsig_keydata); 598238104Sdes} 599238104Sdes 600238104Sdesvoid 601238104Sdesldns_resolver_set_random(ldns_resolver *r, bool b) 602238104Sdes{ 603238104Sdes r->_random = b; 604238104Sdes} 605238104Sdes 606238104Sdes/* more sophisticated functions */ 607238104Sdesldns_resolver * 608238104Sdesldns_resolver_new(void) 609238104Sdes{ 610238104Sdes ldns_resolver *r; 611238104Sdes 612238104Sdes r = LDNS_MALLOC(ldns_resolver); 613238104Sdes if (!r) { 614238104Sdes return NULL; 615238104Sdes } 616238104Sdes 617238104Sdes r->_searchlist = NULL; 618238104Sdes r->_nameservers = NULL; 619238104Sdes r->_rtt = NULL; 620238104Sdes 621238104Sdes /* defaults are filled out */ 622238104Sdes ldns_resolver_set_searchlist_count(r, 0); 623238104Sdes ldns_resolver_set_nameserver_count(r, 0); 624238104Sdes ldns_resolver_set_usevc(r, 0); 625238104Sdes ldns_resolver_set_port(r, LDNS_PORT); 626238104Sdes ldns_resolver_set_domain(r, NULL); 627238104Sdes ldns_resolver_set_defnames(r, false); 628238104Sdes ldns_resolver_set_retry(r, 3); 629238104Sdes ldns_resolver_set_retrans(r, 2); 630238104Sdes ldns_resolver_set_fallback(r, true); 631238104Sdes ldns_resolver_set_fail(r, false); 632238104Sdes ldns_resolver_set_edns_udp_size(r, 0); 633238104Sdes ldns_resolver_set_dnssec(r, false); 634238104Sdes ldns_resolver_set_dnssec_cd(r, false); 635238104Sdes ldns_resolver_set_dnssec_anchors(r, NULL); 636238104Sdes ldns_resolver_set_ip6(r, LDNS_RESOLV_INETANY); 637238104Sdes ldns_resolver_set_igntc(r, false); 638238104Sdes ldns_resolver_set_recursive(r, false); 639238104Sdes ldns_resolver_set_dnsrch(r, true); 640266114Sdes ldns_resolver_set_source(r, NULL); 641238104Sdes 642238104Sdes /* randomize the nameserver to be queried 643238104Sdes * when there are multiple 644238104Sdes */ 645238104Sdes ldns_resolver_set_random(r, true); 646238104Sdes 647238104Sdes ldns_resolver_set_debug(r, 0); 648238104Sdes 649238104Sdes r->_timeout.tv_sec = LDNS_DEFAULT_TIMEOUT_SEC; 650238104Sdes r->_timeout.tv_usec = LDNS_DEFAULT_TIMEOUT_USEC; 651238104Sdes 652238104Sdes /* TODO: fd=0 is actually a valid socket (stdin), 653238104Sdes replace with -1 */ 654238104Sdes r->_socket = 0; 655238104Sdes r->_axfr_soa_count = 0; 656238104Sdes r->_axfr_i = 0; 657238104Sdes r->_cur_axfr_pkt = NULL; 658238104Sdes 659238104Sdes r->_tsig_keyname = NULL; 660238104Sdes r->_tsig_keydata = NULL; 661238104Sdes r->_tsig_algorithm = NULL; 662238104Sdes return r; 663238104Sdes} 664238104Sdes 665238104Sdesldns_status 666238104Sdesldns_resolver_new_frm_fp(ldns_resolver **res, FILE *fp) 667238104Sdes{ 668238104Sdes return ldns_resolver_new_frm_fp_l(res, fp, NULL); 669238104Sdes} 670238104Sdes 671238104Sdesldns_status 672238104Sdesldns_resolver_new_frm_fp_l(ldns_resolver **res, FILE *fp, int *line_nr) 673238104Sdes{ 674238104Sdes ldns_resolver *r; 675238104Sdes const char *keyword[LDNS_RESOLV_KEYWORDS]; 676238104Sdes char word[LDNS_MAX_LINELEN + 1]; 677238104Sdes int8_t expect; 678238104Sdes uint8_t i; 679238104Sdes ldns_rdf *tmp; 680238104Sdes#ifdef HAVE_SSL 681238104Sdes ldns_rr *tmp_rr; 682238104Sdes#endif 683238104Sdes ssize_t gtr, bgtr; 684238104Sdes ldns_buffer *b; 685238104Sdes int lnr = 0, oldline; 686266114Sdes FILE* myfp = fp; 687238104Sdes if(!line_nr) line_nr = &lnr; 688238104Sdes 689266114Sdes if(!fp) { 690266114Sdes myfp = fopen("/etc/resolv.conf", "r"); 691266114Sdes if(!myfp) 692266114Sdes return LDNS_STATUS_FILE_ERR; 693266114Sdes } 694266114Sdes 695238104Sdes /* do this better 696238104Sdes * expect = 697238104Sdes * 0: keyword 698238104Sdes * 1: default domain dname 699238104Sdes * 2: NS aaaa or a record 700238104Sdes */ 701238104Sdes 702238104Sdes /* recognized keywords */ 703238104Sdes keyword[LDNS_RESOLV_NAMESERVER] = "nameserver"; 704238104Sdes keyword[LDNS_RESOLV_DEFDOMAIN] = "domain"; 705238104Sdes keyword[LDNS_RESOLV_SEARCH] = "search"; 706238104Sdes /* these two are read but not used atm TODO */ 707238104Sdes keyword[LDNS_RESOLV_SORTLIST] = "sortlist"; 708238104Sdes keyword[LDNS_RESOLV_OPTIONS] = "options"; 709238104Sdes keyword[LDNS_RESOLV_ANCHOR] = "anchor"; 710238104Sdes expect = LDNS_RESOLV_KEYWORD; 711238104Sdes 712238104Sdes r = ldns_resolver_new(); 713238104Sdes if (!r) { 714266114Sdes if(!fp) fclose(myfp); 715238104Sdes return LDNS_STATUS_MEM_ERR; 716238104Sdes } 717238104Sdes 718238104Sdes gtr = 1; 719238104Sdes word[0] = 0; 720238104Sdes oldline = *line_nr; 721238104Sdes expect = LDNS_RESOLV_KEYWORD; 722238104Sdes while (gtr > 0) { 723238104Sdes /* check comments */ 724238104Sdes if (word[0] == '#') { 725238104Sdes word[0]='x'; 726238104Sdes if(oldline == *line_nr) { 727238104Sdes /* skip until end of line */ 728238104Sdes int c; 729238104Sdes do { 730266114Sdes c = fgetc(myfp); 731238104Sdes } while(c != EOF && c != '\n'); 732266114Sdes if(c=='\n') (*line_nr)++; 733238104Sdes } 734238104Sdes /* and read next to prepare for further parsing */ 735238104Sdes oldline = *line_nr; 736238104Sdes continue; 737238104Sdes } 738238104Sdes oldline = *line_nr; 739238104Sdes switch(expect) { 740238104Sdes case LDNS_RESOLV_KEYWORD: 741238104Sdes /* keyword */ 742266114Sdes gtr = ldns_fget_token_l(myfp, word, LDNS_PARSE_NORMAL, 0, line_nr); 743238104Sdes if (gtr != 0) { 744238104Sdes if(word[0] == '#') continue; 745238104Sdes for(i = 0; i < LDNS_RESOLV_KEYWORDS; i++) { 746238104Sdes if (strcasecmp(keyword[i], word) == 0) { 747238104Sdes /* chosen the keyword and 748238104Sdes * expect values carefully 749238104Sdes */ 750238104Sdes expect = i; 751238104Sdes break; 752238104Sdes } 753238104Sdes } 754238104Sdes /* no keyword recognized */ 755238104Sdes if (expect == LDNS_RESOLV_KEYWORD) { 756238104Sdes /* skip line */ 757238104Sdes /* 758238104Sdes ldns_resolver_deep_free(r); 759266114Sdes if(!fp) fclose(myfp); 760238104Sdes return LDNS_STATUS_SYNTAX_KEYWORD_ERR; 761238104Sdes */ 762238104Sdes } 763238104Sdes } 764238104Sdes break; 765238104Sdes case LDNS_RESOLV_DEFDOMAIN: 766238104Sdes /* default domain dname */ 767266114Sdes gtr = ldns_fget_token_l(myfp, word, LDNS_PARSE_NORMAL, 0, line_nr); 768238104Sdes if (gtr == 0) { 769266114Sdes if(!fp) fclose(myfp); 770238104Sdes return LDNS_STATUS_SYNTAX_MISSING_VALUE_ERR; 771238104Sdes } 772238104Sdes if(word[0] == '#') { 773238104Sdes expect = LDNS_RESOLV_KEYWORD; 774238104Sdes continue; 775238104Sdes } 776238104Sdes tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, word); 777238104Sdes if (!tmp) { 778238104Sdes ldns_resolver_deep_free(r); 779266114Sdes if(!fp) fclose(myfp); 780238104Sdes return LDNS_STATUS_SYNTAX_DNAME_ERR; 781238104Sdes } 782238104Sdes 783238104Sdes /* DOn't free, because we copy the pointer */ 784238104Sdes ldns_resolver_set_domain(r, tmp); 785238104Sdes expect = LDNS_RESOLV_KEYWORD; 786238104Sdes break; 787238104Sdes case LDNS_RESOLV_NAMESERVER: 788238104Sdes /* NS aaaa or a record */ 789266114Sdes gtr = ldns_fget_token_l(myfp, word, LDNS_PARSE_NORMAL, 0, line_nr); 790238104Sdes if (gtr == 0) { 791266114Sdes if(!fp) fclose(myfp); 792238104Sdes return LDNS_STATUS_SYNTAX_MISSING_VALUE_ERR; 793238104Sdes } 794238104Sdes if(word[0] == '#') { 795238104Sdes expect = LDNS_RESOLV_KEYWORD; 796238104Sdes continue; 797238104Sdes } 798238104Sdes if(strchr(word, '%')) { 799238104Sdes /* snip off interface labels, 800238104Sdes * fe80::222:19ff:fe31:4222%eth0 */ 801238104Sdes strchr(word, '%')[0]=0; 802238104Sdes } 803238104Sdes tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_AAAA, word); 804238104Sdes if (!tmp) { 805238104Sdes /* try ip4 */ 806238104Sdes tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_A, word); 807238104Sdes } 808238104Sdes /* could not parse it, exit */ 809238104Sdes if (!tmp) { 810238104Sdes ldns_resolver_deep_free(r); 811266114Sdes if(!fp) fclose(myfp); 812238104Sdes return LDNS_STATUS_SYNTAX_ERR; 813238104Sdes } 814238104Sdes (void)ldns_resolver_push_nameserver(r, tmp); 815238104Sdes ldns_rdf_deep_free(tmp); 816238104Sdes expect = LDNS_RESOLV_KEYWORD; 817238104Sdes break; 818238104Sdes case LDNS_RESOLV_SEARCH: 819238104Sdes /* search list domain dname */ 820266114Sdes gtr = ldns_fget_token_l(myfp, word, LDNS_PARSE_SKIP_SPACE, 0, line_nr); 821238104Sdes b = LDNS_MALLOC(ldns_buffer); 822238104Sdes if(!b) { 823238104Sdes ldns_resolver_deep_free(r); 824266114Sdes if(!fp) fclose(myfp); 825238104Sdes return LDNS_STATUS_MEM_ERR; 826238104Sdes } 827238104Sdes 828238104Sdes ldns_buffer_new_frm_data(b, word, (size_t) gtr); 829238104Sdes if(ldns_buffer_status(b) != LDNS_STATUS_OK) { 830238104Sdes LDNS_FREE(b); 831238104Sdes ldns_resolver_deep_free(r); 832266114Sdes if(!fp) fclose(myfp); 833238104Sdes return LDNS_STATUS_MEM_ERR; 834238104Sdes } 835238104Sdes bgtr = ldns_bget_token(b, word, LDNS_PARSE_NORMAL, (size_t) gtr + 1); 836238104Sdes while (bgtr > 0) { 837238104Sdes gtr -= bgtr; 838238104Sdes if(word[0] == '#') { 839238104Sdes expect = LDNS_RESOLV_KEYWORD; 840246854Sdes break; 841238104Sdes } 842238104Sdes tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, word); 843238104Sdes if (!tmp) { 844238104Sdes ldns_resolver_deep_free(r); 845238104Sdes ldns_buffer_free(b); 846266114Sdes if(!fp) fclose(myfp); 847238104Sdes return LDNS_STATUS_SYNTAX_DNAME_ERR; 848238104Sdes } 849238104Sdes 850238104Sdes ldns_resolver_push_searchlist(r, tmp); 851238104Sdes 852238104Sdes ldns_rdf_deep_free(tmp); 853238104Sdes bgtr = ldns_bget_token(b, word, LDNS_PARSE_NORMAL, 854238104Sdes (size_t) gtr + 1); 855238104Sdes } 856238104Sdes ldns_buffer_free(b); 857246854Sdes if (expect != LDNS_RESOLV_KEYWORD) { 858246854Sdes gtr = 1; 859246854Sdes expect = LDNS_RESOLV_KEYWORD; 860246854Sdes } 861238104Sdes break; 862238104Sdes case LDNS_RESOLV_SORTLIST: 863266114Sdes gtr = ldns_fget_token_l(myfp, word, LDNS_PARSE_SKIP_SPACE, 0, line_nr); 864238104Sdes /* sortlist not implemented atm */ 865238104Sdes expect = LDNS_RESOLV_KEYWORD; 866238104Sdes break; 867238104Sdes case LDNS_RESOLV_OPTIONS: 868266114Sdes gtr = ldns_fget_token_l(myfp, word, LDNS_PARSE_SKIP_SPACE, 0, line_nr); 869238104Sdes /* options not implemented atm */ 870238104Sdes expect = LDNS_RESOLV_KEYWORD; 871238104Sdes break; 872238104Sdes case LDNS_RESOLV_ANCHOR: 873238104Sdes /* a file containing a DNSSEC trust anchor */ 874266114Sdes gtr = ldns_fget_token_l(myfp, word, LDNS_PARSE_NORMAL, 0, line_nr); 875238104Sdes if (gtr == 0) { 876238104Sdes ldns_resolver_deep_free(r); 877266114Sdes if(!fp) fclose(myfp); 878238104Sdes return LDNS_STATUS_SYNTAX_MISSING_VALUE_ERR; 879238104Sdes } 880238104Sdes if(word[0] == '#') { 881238104Sdes expect = LDNS_RESOLV_KEYWORD; 882238104Sdes continue; 883238104Sdes } 884238104Sdes 885238104Sdes#ifdef HAVE_SSL 886238104Sdes tmp_rr = ldns_read_anchor_file(word); 887238104Sdes (void) ldns_resolver_push_dnssec_anchor(r, tmp_rr); 888238104Sdes ldns_rr_free(tmp_rr); 889238104Sdes#endif 890238104Sdes expect = LDNS_RESOLV_KEYWORD; 891238104Sdes break; 892238104Sdes } 893238104Sdes } 894238104Sdes 895266114Sdes if(!fp) 896266114Sdes fclose(myfp); 897266114Sdes 898238104Sdes if (res) { 899238104Sdes *res = r; 900238104Sdes return LDNS_STATUS_OK; 901238104Sdes } else { 902238104Sdes ldns_resolver_deep_free(r); 903238104Sdes return LDNS_STATUS_NULL; 904238104Sdes } 905238104Sdes} 906238104Sdes 907238104Sdesldns_status 908238104Sdesldns_resolver_new_frm_file(ldns_resolver **res, const char *filename) 909238104Sdes{ 910238104Sdes ldns_resolver *r; 911238104Sdes FILE *fp; 912238104Sdes ldns_status s; 913238104Sdes 914238104Sdes if (!filename) { 915238104Sdes fp = fopen(LDNS_RESOLV_CONF, "r"); 916238104Sdes 917238104Sdes } else { 918238104Sdes fp = fopen(filename, "r"); 919238104Sdes } 920238104Sdes if (!fp) { 921238104Sdes return LDNS_STATUS_FILE_ERR; 922238104Sdes } 923238104Sdes 924238104Sdes s = ldns_resolver_new_frm_fp(&r, fp); 925238104Sdes fclose(fp); 926238104Sdes if (s == LDNS_STATUS_OK) { 927238104Sdes if (res) { 928238104Sdes *res = r; 929238104Sdes return LDNS_STATUS_OK; 930238104Sdes } else { 931246854Sdes ldns_resolver_free(r); 932238104Sdes return LDNS_STATUS_NULL; 933238104Sdes } 934238104Sdes } 935238104Sdes return s; 936238104Sdes} 937238104Sdes 938238104Sdesvoid 939238104Sdesldns_resolver_free(ldns_resolver *res) 940238104Sdes{ 941238104Sdes LDNS_FREE(res); 942238104Sdes} 943238104Sdes 944238104Sdesvoid 945238104Sdesldns_resolver_deep_free(ldns_resolver *res) 946238104Sdes{ 947238104Sdes size_t i; 948238104Sdes 949238104Sdes if (res) { 950238104Sdes if (res->_searchlist) { 951238104Sdes for (i = 0; i < ldns_resolver_searchlist_count(res); i++) { 952238104Sdes ldns_rdf_deep_free(res->_searchlist[i]); 953238104Sdes } 954238104Sdes LDNS_FREE(res->_searchlist); 955238104Sdes } 956238104Sdes if (res->_nameservers) { 957238104Sdes for (i = 0; i < res->_nameserver_count; i++) { 958238104Sdes ldns_rdf_deep_free(res->_nameservers[i]); 959238104Sdes } 960238104Sdes LDNS_FREE(res->_nameservers); 961238104Sdes } 962238104Sdes if (ldns_resolver_domain(res)) { 963238104Sdes ldns_rdf_deep_free(ldns_resolver_domain(res)); 964238104Sdes } 965238104Sdes if (res->_tsig_keyname) { 966238104Sdes LDNS_FREE(res->_tsig_keyname); 967238104Sdes } 968238104Sdes if (res->_tsig_keydata) { 969238104Sdes LDNS_FREE(res->_tsig_keydata); 970238104Sdes } 971238104Sdes if (res->_tsig_algorithm) { 972238104Sdes LDNS_FREE(res->_tsig_algorithm); 973238104Sdes } 974238104Sdes 975238104Sdes if (res->_cur_axfr_pkt) { 976238104Sdes ldns_pkt_free(res->_cur_axfr_pkt); 977238104Sdes } 978238104Sdes 979238104Sdes if (res->_rtt) { 980238104Sdes LDNS_FREE(res->_rtt); 981238104Sdes } 982238104Sdes if (res->_dnssec_anchors) { 983238104Sdes ldns_rr_list_deep_free(res->_dnssec_anchors); 984238104Sdes } 985238104Sdes LDNS_FREE(res); 986238104Sdes } 987238104Sdes} 988238104Sdes 989266114Sdesldns_status 990266114Sdesldns_resolver_search_status(ldns_pkt** pkt, 991266114Sdes ldns_resolver *r, const ldns_rdf *name, 992266114Sdes ldns_rr_type t, ldns_rr_class c, uint16_t flags) 993238104Sdes{ 994238104Sdes ldns_rdf *new_name; 995238104Sdes ldns_rdf **search_list; 996238104Sdes size_t i; 997266114Sdes ldns_status s = LDNS_STATUS_OK; 998238104Sdes 999246854Sdes if (ldns_dname_absolute(name)) { 1000238104Sdes /* query as-is */ 1001266114Sdes return ldns_resolver_query_status(pkt, r, name, t, c, flags); 1002238104Sdes } else if (ldns_resolver_dnsrch(r)) { 1003238104Sdes search_list = ldns_resolver_searchlist(r); 1004238104Sdes for (i = 0; i < ldns_resolver_searchlist_count(r); i++) { 1005238104Sdes new_name = ldns_dname_cat_clone(name, search_list[i]); 1006238104Sdes 1007266114Sdes s = ldns_resolver_query_status(pkt, r, 1008266114Sdes new_name, t, c, flags); 1009238104Sdes ldns_rdf_free(new_name); 1010266114Sdes if (pkt) { 1011266114Sdes if (s == LDNS_STATUS_OK && *pkt && 1012266114Sdes ldns_pkt_get_rcode(*pkt) == 1013266114Sdes LDNS_RCODE_NOERROR) { 1014266114Sdes return LDNS_STATUS_OK; 1015238104Sdes } 1016266114Sdes ldns_pkt_free(*pkt); 1017238104Sdes } 1018238104Sdes } 1019238104Sdes } 1020266114Sdes return s; 1021238104Sdes} 1022238104Sdes 1023238104Sdesldns_pkt * 1024266114Sdesldns_resolver_search(const ldns_resolver *r,const ldns_rdf *name, 1025238104Sdes ldns_rr_type t, ldns_rr_class c, uint16_t flags) 1026238104Sdes{ 1027266114Sdes ldns_pkt* pkt = NULL; 1028266114Sdes if (ldns_resolver_search_status(&pkt, (ldns_resolver *)r, 1029266114Sdes name, t, c, flags) != LDNS_STATUS_OK) { 1030266114Sdes ldns_pkt_free(pkt); 1031266114Sdes } 1032266114Sdes return pkt; 1033266114Sdes} 1034266114Sdes 1035266114Sdesldns_status 1036266114Sdesldns_resolver_query_status(ldns_pkt** pkt, 1037266114Sdes ldns_resolver *r, const ldns_rdf *name, 1038266114Sdes ldns_rr_type t, ldns_rr_class c, uint16_t flags) 1039266114Sdes{ 1040238104Sdes ldns_rdf *newname; 1041238104Sdes ldns_status status; 1042238104Sdes 1043266114Sdes if (!ldns_resolver_defnames(r) || !ldns_resolver_domain(r)) { 1044266114Sdes return ldns_resolver_send(pkt, r, name, t, c, flags); 1045238104Sdes } 1046238104Sdes 1047266114Sdes newname = ldns_dname_cat_clone(name, ldns_resolver_domain(r)); 1048238104Sdes if (!newname) { 1049266114Sdes return LDNS_STATUS_MEM_ERR; 1050238104Sdes } 1051266114Sdes status = ldns_resolver_send(pkt, r, newname, t, c, flags); 1052238104Sdes ldns_rdf_free(newname); 1053266114Sdes return status; 1054266114Sdes} 1055238104Sdes 1056266114Sdesldns_pkt * 1057266114Sdesldns_resolver_query(const ldns_resolver *r, const ldns_rdf *name, 1058266114Sdes ldns_rr_type t, ldns_rr_class c, uint16_t flags) 1059266114Sdes{ 1060266114Sdes ldns_pkt* pkt = NULL; 1061266114Sdes if (ldns_resolver_query_status(&pkt, (ldns_resolver *)r, 1062266114Sdes name, t, c, flags) != LDNS_STATUS_OK) { 1063266114Sdes ldns_pkt_free(pkt); 1064266114Sdes } 1065238104Sdes return pkt; 1066238104Sdes} 1067238104Sdes 1068238104Sdesstatic size_t * 1069238104Sdesldns_resolver_backup_rtt(ldns_resolver *r) 1070238104Sdes{ 1071238104Sdes size_t *new_rtt; 1072238104Sdes size_t *old_rtt = ldns_resolver_rtt(r); 1073238104Sdes 1074238104Sdes if (old_rtt && ldns_resolver_nameserver_count(r)) { 1075238104Sdes new_rtt = LDNS_XMALLOC(size_t 1076238104Sdes , ldns_resolver_nameserver_count(r)); 1077238104Sdes memcpy(new_rtt, old_rtt, sizeof(size_t) 1078238104Sdes * ldns_resolver_nameserver_count(r)); 1079238104Sdes ldns_resolver_set_rtt(r, new_rtt); 1080238104Sdes return old_rtt; 1081238104Sdes } 1082238104Sdes return NULL; 1083238104Sdes} 1084238104Sdes 1085238104Sdesstatic void 1086238104Sdesldns_resolver_restore_rtt(ldns_resolver *r, size_t *old_rtt) 1087238104Sdes{ 1088238104Sdes size_t *cur_rtt = ldns_resolver_rtt(r); 1089238104Sdes 1090238104Sdes if (cur_rtt) { 1091238104Sdes LDNS_FREE(cur_rtt); 1092238104Sdes } 1093238104Sdes ldns_resolver_set_rtt(r, old_rtt); 1094238104Sdes} 1095238104Sdes 1096238104Sdesldns_status 1097238104Sdesldns_resolver_send_pkt(ldns_pkt **answer, ldns_resolver *r, 1098238104Sdes ldns_pkt *query_pkt) 1099238104Sdes{ 1100238104Sdes ldns_pkt *answer_pkt = NULL; 1101238104Sdes ldns_status stat = LDNS_STATUS_OK; 1102238104Sdes size_t *rtt; 1103238104Sdes 1104238104Sdes stat = ldns_send(&answer_pkt, (ldns_resolver *)r, query_pkt); 1105238104Sdes if (stat != LDNS_STATUS_OK) { 1106238104Sdes if(answer_pkt) { 1107238104Sdes ldns_pkt_free(answer_pkt); 1108238104Sdes answer_pkt = NULL; 1109238104Sdes } 1110238104Sdes } else { 1111238104Sdes /* if tc=1 fall back to EDNS and/or TCP */ 1112238104Sdes /* check for tcp first (otherwise we don't care about tc=1) */ 1113238104Sdes if (!ldns_resolver_usevc(r) && ldns_resolver_fallback(r)) { 1114238104Sdes if (ldns_pkt_tc(answer_pkt)) { 1115238104Sdes /* was EDNS0 set? */ 1116238104Sdes if (ldns_pkt_edns_udp_size(query_pkt) == 0) { 1117238104Sdes ldns_pkt_set_edns_udp_size(query_pkt 1118238104Sdes , 4096); 1119238104Sdes ldns_pkt_free(answer_pkt); 1120238104Sdes /* Nameservers should not become 1121238104Sdes * unreachable because fragments are 1122238104Sdes * dropped (network error). We might 1123238104Sdes * still have success with TCP. 1124238104Sdes * Therefore maintain reachability 1125238104Sdes * statuses of the nameservers by 1126238104Sdes * backup and restore the rtt list. 1127238104Sdes */ 1128238104Sdes rtt = ldns_resolver_backup_rtt(r); 1129238104Sdes stat = ldns_send(&answer_pkt, r 1130238104Sdes , query_pkt); 1131238104Sdes ldns_resolver_restore_rtt(r, rtt); 1132238104Sdes } 1133238104Sdes /* either way, if it is still truncated, use TCP */ 1134238104Sdes if (stat != LDNS_STATUS_OK || 1135238104Sdes ldns_pkt_tc(answer_pkt)) { 1136238104Sdes ldns_resolver_set_usevc(r, true); 1137238104Sdes ldns_pkt_free(answer_pkt); 1138238104Sdes stat = ldns_send(&answer_pkt, r, query_pkt); 1139238104Sdes ldns_resolver_set_usevc(r, false); 1140238104Sdes } 1141238104Sdes } 1142238104Sdes } 1143238104Sdes } 1144238104Sdes 1145238104Sdes if (answer) { 1146238104Sdes *answer = answer_pkt; 1147238104Sdes } 1148238104Sdes 1149238104Sdes return stat; 1150238104Sdes} 1151238104Sdes 1152238104Sdesldns_status 1153238104Sdesldns_resolver_prepare_query_pkt(ldns_pkt **query_pkt, ldns_resolver *r, 1154238104Sdes const ldns_rdf *name, ldns_rr_type t, 1155238104Sdes ldns_rr_class c, uint16_t flags) 1156238104Sdes{ 1157238104Sdes struct timeval now; 1158238104Sdes 1159238104Sdes /* prepare a question pkt from the parameters 1160238104Sdes * and then send this */ 1161266114Sdes if (t == LDNS_RR_TYPE_IXFR) { 1162266114Sdes *query_pkt = ldns_pkt_ixfr_request_new(ldns_rdf_clone(name), 1163266114Sdes c, flags, NULL); 1164266114Sdes } else { 1165266114Sdes *query_pkt = ldns_pkt_query_new(ldns_rdf_clone(name), t, c, flags); 1166266114Sdes } 1167238104Sdes if (!*query_pkt) { 1168238104Sdes return LDNS_STATUS_ERR; 1169238104Sdes } 1170238104Sdes 1171238104Sdes /* set DO bit if necessary */ 1172238104Sdes if (ldns_resolver_dnssec(r)) { 1173238104Sdes if (ldns_resolver_edns_udp_size(r) == 0) { 1174238104Sdes ldns_resolver_set_edns_udp_size(r, 4096); 1175238104Sdes } 1176238104Sdes ldns_pkt_set_edns_do(*query_pkt, true); 1177238104Sdes if (ldns_resolver_dnssec_cd(r) || (flags & LDNS_CD)) { 1178238104Sdes ldns_pkt_set_cd(*query_pkt, true); 1179238104Sdes } 1180238104Sdes } 1181238104Sdes 1182238104Sdes /* transfer the udp_edns_size from the resolver to the packet */ 1183238104Sdes if (ldns_resolver_edns_udp_size(r) != 0) { 1184238104Sdes ldns_pkt_set_edns_udp_size(*query_pkt, ldns_resolver_edns_udp_size(r)); 1185238104Sdes } 1186238104Sdes 1187238104Sdes /* set the timestamp */ 1188238104Sdes now.tv_sec = time(NULL); 1189238104Sdes now.tv_usec = 0; 1190238104Sdes ldns_pkt_set_timestamp(*query_pkt, now); 1191238104Sdes 1192238104Sdes 1193238104Sdes if (ldns_resolver_debug(r)) { 1194238104Sdes ldns_pkt_print(stdout, *query_pkt); 1195238104Sdes } 1196238104Sdes 1197238104Sdes /* only set the id if it is not set yet */ 1198238104Sdes if (ldns_pkt_id(*query_pkt) == 0) { 1199238104Sdes ldns_pkt_set_random_id(*query_pkt); 1200238104Sdes } 1201238104Sdes 1202238104Sdes return LDNS_STATUS_OK; 1203238104Sdes} 1204238104Sdes 1205238104Sdes 1206238104Sdesldns_status 1207238104Sdesldns_resolver_send(ldns_pkt **answer, ldns_resolver *r, const ldns_rdf *name, 1208238104Sdes ldns_rr_type t, ldns_rr_class c, uint16_t flags) 1209238104Sdes{ 1210238104Sdes ldns_pkt *query_pkt; 1211238104Sdes ldns_pkt *answer_pkt; 1212238104Sdes ldns_status status; 1213238104Sdes 1214238104Sdes assert(r != NULL); 1215238104Sdes assert(name != NULL); 1216238104Sdes 1217238104Sdes answer_pkt = NULL; 1218238104Sdes 1219238104Sdes /* do all the preprocessing here, then fire of an query to 1220238104Sdes * the network */ 1221238104Sdes 1222238104Sdes if (0 == t) { 1223238104Sdes t= LDNS_RR_TYPE_A; 1224238104Sdes } 1225238104Sdes if (0 == c) { 1226238104Sdes c= LDNS_RR_CLASS_IN; 1227238104Sdes } 1228238104Sdes if (0 == ldns_resolver_nameserver_count(r)) { 1229238104Sdes return LDNS_STATUS_RES_NO_NS; 1230238104Sdes } 1231238104Sdes if (ldns_rdf_get_type(name) != LDNS_RDF_TYPE_DNAME) { 1232238104Sdes return LDNS_STATUS_RES_QUERY; 1233238104Sdes } 1234238104Sdes 1235238104Sdes status = ldns_resolver_prepare_query_pkt(&query_pkt, r, name, 1236238104Sdes t, c, flags); 1237238104Sdes if (status != LDNS_STATUS_OK) { 1238238104Sdes return status; 1239238104Sdes } 1240238104Sdes 1241238104Sdes /* if tsig values are set, tsign it */ 1242238104Sdes /* TODO: make last 3 arguments optional too? maybe make complete 1243266114Sdes rr instead of separate values in resolver (and packet) 1244238104Sdes Jelte 1245238104Sdes should this go in pkt_prepare? 1246238104Sdes */ 1247238104Sdes if (ldns_resolver_tsig_keyname(r) && ldns_resolver_tsig_keydata(r)) { 1248238104Sdes#ifdef HAVE_SSL 1249238104Sdes status = ldns_pkt_tsig_sign(query_pkt, 1250238104Sdes ldns_resolver_tsig_keyname(r), 1251238104Sdes ldns_resolver_tsig_keydata(r), 1252238104Sdes 300, ldns_resolver_tsig_algorithm(r), NULL); 1253238104Sdes if (status != LDNS_STATUS_OK) { 1254246854Sdes ldns_pkt_free(query_pkt); 1255238104Sdes return LDNS_STATUS_CRYPTO_TSIG_ERR; 1256238104Sdes } 1257238104Sdes#else 1258246854Sdes ldns_pkt_free(query_pkt); 1259238104Sdes return LDNS_STATUS_CRYPTO_TSIG_ERR; 1260238104Sdes#endif /* HAVE_SSL */ 1261238104Sdes } 1262238104Sdes 1263238104Sdes status = ldns_resolver_send_pkt(&answer_pkt, r, query_pkt); 1264238104Sdes ldns_pkt_free(query_pkt); 1265238104Sdes 1266238104Sdes /* allows answer to be NULL when not interested in return value */ 1267238104Sdes if (answer) { 1268238104Sdes *answer = answer_pkt; 1269238104Sdes } 1270238104Sdes return status; 1271238104Sdes} 1272238104Sdes 1273238104Sdesldns_rr * 1274238104Sdesldns_axfr_next(ldns_resolver *resolver) 1275238104Sdes{ 1276238104Sdes ldns_rr *cur_rr; 1277238104Sdes uint8_t *packet_wire; 1278238104Sdes size_t packet_wire_size; 1279238104Sdes ldns_lookup_table *rcode; 1280238104Sdes ldns_status status; 1281238104Sdes 1282238104Sdes /* check if start() has been called */ 1283238104Sdes if (!resolver || resolver->_socket == 0) { 1284238104Sdes return NULL; 1285238104Sdes } 1286238104Sdes 1287238104Sdes if (resolver->_cur_axfr_pkt) { 1288238104Sdes if (resolver->_axfr_i == ldns_pkt_ancount(resolver->_cur_axfr_pkt)) { 1289238104Sdes ldns_pkt_free(resolver->_cur_axfr_pkt); 1290238104Sdes resolver->_cur_axfr_pkt = NULL; 1291238104Sdes return ldns_axfr_next(resolver); 1292238104Sdes } 1293238104Sdes cur_rr = ldns_rr_clone(ldns_rr_list_rr( 1294238104Sdes ldns_pkt_answer(resolver->_cur_axfr_pkt), 1295238104Sdes resolver->_axfr_i)); 1296238104Sdes resolver->_axfr_i++; 1297238104Sdes if (ldns_rr_get_type(cur_rr) == LDNS_RR_TYPE_SOA) { 1298238104Sdes resolver->_axfr_soa_count++; 1299238104Sdes if (resolver->_axfr_soa_count >= 2) { 1300238104Sdes#ifndef USE_WINSOCK 1301238104Sdes close(resolver->_socket); 1302238104Sdes#else 1303238104Sdes closesocket(resolver->_socket); 1304238104Sdes#endif 1305238104Sdes resolver->_socket = 0; 1306238104Sdes ldns_pkt_free(resolver->_cur_axfr_pkt); 1307238104Sdes resolver->_cur_axfr_pkt = NULL; 1308238104Sdes } 1309238104Sdes } 1310238104Sdes return cur_rr; 1311238104Sdes } else { 1312238104Sdes packet_wire = ldns_tcp_read_wire(resolver->_socket, &packet_wire_size); 1313238104Sdes if(!packet_wire) 1314238104Sdes return NULL; 1315238104Sdes 1316238104Sdes status = ldns_wire2pkt(&resolver->_cur_axfr_pkt, packet_wire, 1317238104Sdes packet_wire_size); 1318238104Sdes LDNS_FREE(packet_wire); 1319238104Sdes 1320238104Sdes resolver->_axfr_i = 0; 1321238104Sdes if (status != LDNS_STATUS_OK) { 1322238104Sdes /* TODO: make status return type of this function (...api change) */ 1323266114Sdes#ifdef STDERR_MSGS 1324238104Sdes fprintf(stderr, "Error parsing rr during AXFR: %s\n", ldns_get_errorstr_by_id(status)); 1325266114Sdes#endif 1326238104Sdes 1327266114Sdes /* we must now also close the socket, otherwise subsequent uses of the 1328238104Sdes same resolver structure will fail because the link is still open or 1329238104Sdes in an undefined state */ 1330238104Sdes#ifndef USE_WINSOCK 1331238104Sdes close(resolver->_socket); 1332238104Sdes#else 1333238104Sdes closesocket(resolver->_socket); 1334238104Sdes#endif 1335238104Sdes resolver->_socket = 0; 1336238104Sdes 1337238104Sdes return NULL; 1338238104Sdes } else if (ldns_pkt_get_rcode(resolver->_cur_axfr_pkt) != 0) { 1339238104Sdes rcode = ldns_lookup_by_id(ldns_rcodes, (int) ldns_pkt_get_rcode(resolver->_cur_axfr_pkt)); 1340266114Sdes#ifdef STDERR_MSGS 1341246854Sdes if (rcode) { 1342246854Sdes fprintf(stderr, "Error in AXFR: %s\n", 1343246854Sdes rcode->name); 1344246854Sdes } else { 1345246854Sdes fprintf(stderr, "Error in AXFR: %d\n", 1346246854Sdes (int) ldns_pkt_get_rcode( 1347246854Sdes resolver->_cur_axfr_pkt)); 1348246854Sdes } 1349266114Sdes#endif 1350238104Sdes 1351266114Sdes /* we must now also close the socket, otherwise subsequent uses of the 1352238104Sdes same resolver structure will fail because the link is still open or 1353238104Sdes in an undefined state */ 1354238104Sdes#ifndef USE_WINSOCK 1355238104Sdes close(resolver->_socket); 1356238104Sdes#else 1357238104Sdes closesocket(resolver->_socket); 1358238104Sdes#endif 1359238104Sdes resolver->_socket = 0; 1360238104Sdes 1361238104Sdes return NULL; 1362238104Sdes } else { 1363238104Sdes return ldns_axfr_next(resolver); 1364238104Sdes } 1365238104Sdes 1366238104Sdes } 1367238104Sdes 1368238104Sdes} 1369238104Sdes 1370266114Sdes/* this function is needed to abort a transfer that is in progress; 1371266114Sdes * without it an aborted transfer will lead to the AXFR code in the 1372266114Sdes * library staying in an indetermined state because the socket for the 1373266114Sdes * AXFR is never closed 1374266114Sdes */ 1375266193Sdesvoid 1376266114Sdesldns_axfr_abort(ldns_resolver *resolver) 1377266114Sdes{ 1378266114Sdes /* Only abort if an actual AXFR is in progress */ 1379266114Sdes if (resolver->_socket != 0) 1380266114Sdes { 1381266114Sdes#ifndef USE_WINSOCK 1382266114Sdes close(resolver->_socket); 1383266114Sdes#else 1384266114Sdes closesocket(resolver->_socket); 1385266114Sdes#endif 1386266114Sdes resolver->_socket = 0; 1387266114Sdes } 1388266114Sdes} 1389266114Sdes 1390238104Sdesbool 1391238104Sdesldns_axfr_complete(const ldns_resolver *res) 1392238104Sdes{ 1393238104Sdes /* complete when soa count is 2? */ 1394238104Sdes return res->_axfr_soa_count == 2; 1395238104Sdes} 1396238104Sdes 1397238104Sdesldns_pkt * 1398238104Sdesldns_axfr_last_pkt(const ldns_resolver *res) 1399238104Sdes{ 1400238104Sdes return res->_cur_axfr_pkt; 1401238104Sdes} 1402238104Sdes 1403238104Sdes/* random isn't really that good */ 1404238104Sdesvoid 1405238104Sdesldns_resolver_nameservers_randomize(ldns_resolver *r) 1406238104Sdes{ 1407238104Sdes uint16_t i, j; 1408246854Sdes ldns_rdf **ns, *tmpns; 1409246854Sdes size_t *rtt, tmprtt; 1410238104Sdes 1411238104Sdes /* should I check for ldns_resolver_random?? */ 1412238104Sdes assert(r != NULL); 1413238104Sdes 1414238104Sdes ns = ldns_resolver_nameservers(r); 1415246854Sdes rtt = ldns_resolver_rtt(r); 1416238104Sdes for (i = 0; i < ldns_resolver_nameserver_count(r); i++) { 1417238104Sdes j = ldns_get_random() % ldns_resolver_nameserver_count(r); 1418246854Sdes tmpns = ns[i]; 1419238104Sdes ns[i] = ns[j]; 1420246854Sdes ns[j] = tmpns; 1421246854Sdes tmprtt = rtt[i]; 1422246854Sdes rtt[i] = rtt[j]; 1423246854Sdes rtt[j] = tmprtt; 1424238104Sdes } 1425238104Sdes ldns_resolver_set_nameservers(r, ns); 1426238104Sdes} 1427238104Sdes 1428