/contrib/bind9/bin/named/query.c
C | 7242 lines | 5285 code | 595 blank | 1362 comment | 1873 complexity | 884d102af774a65093406c7039f80ba4 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
1/* 2 * Copyright (C) 2004-2012 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 1999-2003 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 * PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/* $Id: query.c,v 1.353.8.24 2012/02/07 01:14:39 marka Exp $ */ 19 20/*! \file */ 21 22#include <config.h> 23 24#include <string.h> 25 26#include <isc/hex.h> 27#include <isc/mem.h> 28#include <isc/stats.h> 29#include <isc/util.h> 30 31#include <dns/adb.h> 32#include <dns/byaddr.h> 33#include <dns/db.h> 34#include <dns/dlz.h> 35#include <dns/dns64.h> 36#include <dns/dnssec.h> 37#include <dns/events.h> 38#include <dns/message.h> 39#include <dns/ncache.h> 40#include <dns/nsec3.h> 41#include <dns/order.h> 42#include <dns/rdata.h> 43#include <dns/rdataclass.h> 44#include <dns/rdatalist.h> 45#include <dns/rdataset.h> 46#include <dns/rdatasetiter.h> 47#include <dns/rdatastruct.h> 48#include <dns/rdatatype.h> 49#include <dns/resolver.h> 50#include <dns/result.h> 51#include <dns/stats.h> 52#include <dns/tkey.h> 53#include <dns/view.h> 54#include <dns/zone.h> 55#include <dns/zt.h> 56 57#include <named/client.h> 58#include <named/globals.h> 59#include <named/log.h> 60#include <named/server.h> 61#include <named/sortlist.h> 62#include <named/xfrout.h> 63 64#if 0 65/* 66 * It has been recommended that DNS64 be changed to return excluded 67 * AAAA addresses if DNS64 synthesis does not occur. This minimises 68 * the impact on the lookup results. While most DNS AAAA lookups are 69 * done to send IP packets to a host, not all of them are and filtering 70 * excluded addresses has a negative impact on those uses. 71 */ 72#define dns64_bis_return_excluded_addresses 1 73#endif 74 75/*% Partial answer? */ 76#define PARTIALANSWER(c) (((c)->query.attributes & \ 77 NS_QUERYATTR_PARTIALANSWER) != 0) 78/*% Use Cache? */ 79#define USECACHE(c) (((c)->query.attributes & \ 80 NS_QUERYATTR_CACHEOK) != 0) 81/*% Recursion OK? */ 82#define RECURSIONOK(c) (((c)->query.attributes & \ 83 NS_QUERYATTR_RECURSIONOK) != 0) 84/*% Recursing? */ 85#define RECURSING(c) (((c)->query.attributes & \ 86 NS_QUERYATTR_RECURSING) != 0) 87/*% Cache glue ok? */ 88#define CACHEGLUEOK(c) (((c)->query.attributes & \ 89 NS_QUERYATTR_CACHEGLUEOK) != 0) 90/*% Want Recursion? */ 91#define WANTRECURSION(c) (((c)->query.attributes & \ 92 NS_QUERYATTR_WANTRECURSION) != 0) 93/*% Want DNSSEC? */ 94#define WANTDNSSEC(c) (((c)->attributes & \ 95 NS_CLIENTATTR_WANTDNSSEC) != 0) 96/*% No authority? */ 97#define NOAUTHORITY(c) (((c)->query.attributes & \ 98 NS_QUERYATTR_NOAUTHORITY) != 0) 99/*% No additional? */ 100#define NOADDITIONAL(c) (((c)->query.attributes & \ 101 NS_QUERYATTR_NOADDITIONAL) != 0) 102/*% Secure? */ 103#define SECURE(c) (((c)->query.attributes & \ 104 NS_QUERYATTR_SECURE) != 0) 105/*% DNS64 A lookup? */ 106#define DNS64(c) (((c)->query.attributes & \ 107 NS_QUERYATTR_DNS64) != 0) 108 109#define DNS64EXCLUDE(c) (((c)->query.attributes & \ 110 NS_QUERYATTR_DNS64EXCLUDE) != 0) 111 112/*% No QNAME Proof? */ 113#define NOQNAME(r) (((r)->attributes & \ 114 DNS_RDATASETATTR_NOQNAME) != 0) 115 116#if 0 117#define CTRACE(m) isc_log_write(ns_g_lctx, \ 118 NS_LOGCATEGORY_CLIENT, \ 119 NS_LOGMODULE_QUERY, \ 120 ISC_LOG_DEBUG(3), \ 121 "client %p: %s", client, (m)) 122#define QTRACE(m) isc_log_write(ns_g_lctx, \ 123 NS_LOGCATEGORY_GENERAL, \ 124 NS_LOGMODULE_QUERY, \ 125 ISC_LOG_DEBUG(3), \ 126 "query %p: %s", query, (m)) 127#else 128#define CTRACE(m) ((void)m) 129#define QTRACE(m) ((void)m) 130#endif 131 132#define DNS_GETDB_NOEXACT 0x01U 133#define DNS_GETDB_NOLOG 0x02U 134#define DNS_GETDB_PARTIAL 0x04U 135#define DNS_GETDB_IGNOREACL 0x08U 136 137#define PENDINGOK(x) (((x) & DNS_DBFIND_PENDINGOK) != 0) 138 139typedef struct client_additionalctx { 140 ns_client_t *client; 141 dns_rdataset_t *rdataset; 142} client_additionalctx_t; 143 144static isc_result_t 145query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype); 146 147static isc_boolean_t 148validate(ns_client_t *client, dns_db_t *db, dns_name_t *name, 149 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset); 150 151static void 152query_findclosestnsec3(dns_name_t *qname, dns_db_t *db, 153 dns_dbversion_t *version, ns_client_t *client, 154 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, 155 dns_name_t *fname, isc_boolean_t exact, 156 dns_name_t *found); 157 158static inline void 159log_queryerror(ns_client_t *client, isc_result_t result, int line, int level); 160 161static void 162rpz_st_clear(ns_client_t *client); 163 164/*% 165 * Increment query statistics counters. 166 */ 167static inline void 168inc_stats(ns_client_t *client, isc_statscounter_t counter) { 169 dns_zone_t *zone = client->query.authzone; 170 171 isc_stats_increment(ns_g_server->nsstats, counter); 172 173 if (zone != NULL) { 174 isc_stats_t *zonestats = dns_zone_getrequeststats(zone); 175 if (zonestats != NULL) 176 isc_stats_increment(zonestats, counter); 177 } 178} 179 180static void 181query_send(ns_client_t *client) { 182 isc_statscounter_t counter; 183 if ((client->message->flags & DNS_MESSAGEFLAG_AA) == 0) 184 inc_stats(client, dns_nsstatscounter_nonauthans); 185 else 186 inc_stats(client, dns_nsstatscounter_authans); 187 if (client->message->rcode == dns_rcode_noerror) { 188 if (ISC_LIST_EMPTY(client->message->sections[DNS_SECTION_ANSWER])) { 189 if (client->query.isreferral) { 190 counter = dns_nsstatscounter_referral; 191 } else { 192 counter = dns_nsstatscounter_nxrrset; 193 } 194 } else { 195 counter = dns_nsstatscounter_success; 196 } 197 } else if (client->message->rcode == dns_rcode_nxdomain) { 198 counter = dns_nsstatscounter_nxdomain; 199 } else { 200 /* We end up here in case of YXDOMAIN, and maybe others */ 201 counter = dns_nsstatscounter_failure; 202 } 203 inc_stats(client, counter); 204 ns_client_send(client); 205} 206 207static void 208query_error(ns_client_t *client, isc_result_t result, int line) { 209 int loglevel = ISC_LOG_DEBUG(3); 210 211 switch (result) { 212 case DNS_R_SERVFAIL: 213 loglevel = ISC_LOG_DEBUG(1); 214 inc_stats(client, dns_nsstatscounter_servfail); 215 break; 216 case DNS_R_FORMERR: 217 inc_stats(client, dns_nsstatscounter_formerr); 218 break; 219 default: 220 inc_stats(client, dns_nsstatscounter_failure); 221 break; 222 } 223 224 log_queryerror(client, result, line, loglevel); 225 226 ns_client_error(client, result); 227} 228 229static void 230query_next(ns_client_t *client, isc_result_t result) { 231 if (result == DNS_R_DUPLICATE) 232 inc_stats(client, dns_nsstatscounter_duplicate); 233 else if (result == DNS_R_DROP) 234 inc_stats(client, dns_nsstatscounter_dropped); 235 else 236 inc_stats(client, dns_nsstatscounter_failure); 237 ns_client_next(client, result); 238} 239 240static inline void 241query_freefreeversions(ns_client_t *client, isc_boolean_t everything) { 242 ns_dbversion_t *dbversion, *dbversion_next; 243 unsigned int i; 244 245 for (dbversion = ISC_LIST_HEAD(client->query.freeversions), i = 0; 246 dbversion != NULL; 247 dbversion = dbversion_next, i++) 248 { 249 dbversion_next = ISC_LIST_NEXT(dbversion, link); 250 /* 251 * If we're not freeing everything, we keep the first three 252 * dbversions structures around. 253 */ 254 if (i > 3 || everything) { 255 ISC_LIST_UNLINK(client->query.freeversions, dbversion, 256 link); 257 isc_mem_put(client->mctx, dbversion, 258 sizeof(*dbversion)); 259 } 260 } 261} 262 263void 264ns_query_cancel(ns_client_t *client) { 265 LOCK(&client->query.fetchlock); 266 if (client->query.fetch != NULL) { 267 dns_resolver_cancelfetch(client->query.fetch); 268 269 client->query.fetch = NULL; 270 } 271 UNLOCK(&client->query.fetchlock); 272} 273 274static inline void 275query_putrdataset(ns_client_t *client, dns_rdataset_t **rdatasetp) { 276 dns_rdataset_t *rdataset = *rdatasetp; 277 278 CTRACE("query_putrdataset"); 279 if (rdataset != NULL) { 280 if (dns_rdataset_isassociated(rdataset)) 281 dns_rdataset_disassociate(rdataset); 282 dns_message_puttemprdataset(client->message, rdatasetp); 283 } 284 CTRACE("query_putrdataset: done"); 285} 286 287static inline void 288query_reset(ns_client_t *client, isc_boolean_t everything) { 289 isc_buffer_t *dbuf, *dbuf_next; 290 ns_dbversion_t *dbversion, *dbversion_next; 291 292 /*% 293 * Reset the query state of a client to its default state. 294 */ 295 296 /* 297 * Cancel the fetch if it's running. 298 */ 299 ns_query_cancel(client); 300 301 /* 302 * Cleanup any active versions. 303 */ 304 for (dbversion = ISC_LIST_HEAD(client->query.activeversions); 305 dbversion != NULL; 306 dbversion = dbversion_next) { 307 dbversion_next = ISC_LIST_NEXT(dbversion, link); 308 dns_db_closeversion(dbversion->db, &dbversion->version, 309 ISC_FALSE); 310 dns_db_detach(&dbversion->db); 311 ISC_LIST_INITANDAPPEND(client->query.freeversions, 312 dbversion, link); 313 } 314 ISC_LIST_INIT(client->query.activeversions); 315 316 if (client->query.authdb != NULL) 317 dns_db_detach(&client->query.authdb); 318 if (client->query.authzone != NULL) 319 dns_zone_detach(&client->query.authzone); 320 321 if (client->query.dns64_aaaa != NULL) 322 query_putrdataset(client, &client->query.dns64_aaaa); 323 if (client->query.dns64_sigaaaa != NULL) 324 query_putrdataset(client, &client->query.dns64_sigaaaa); 325 if (client->query.dns64_aaaaok != NULL) { 326 isc_mem_put(client->mctx, client->query.dns64_aaaaok, 327 client->query.dns64_aaaaoklen * 328 sizeof(isc_boolean_t)); 329 client->query.dns64_aaaaok = NULL; 330 client->query.dns64_aaaaoklen = 0; 331 } 332 333 query_freefreeversions(client, everything); 334 335 for (dbuf = ISC_LIST_HEAD(client->query.namebufs); 336 dbuf != NULL; 337 dbuf = dbuf_next) { 338 dbuf_next = ISC_LIST_NEXT(dbuf, link); 339 if (dbuf_next != NULL || everything) { 340 ISC_LIST_UNLINK(client->query.namebufs, dbuf, link); 341 isc_buffer_free(&dbuf); 342 } 343 } 344 345 if (client->query.restarts > 0) { 346 /* 347 * client->query.qname was dynamically allocated. 348 */ 349 dns_message_puttempname(client->message, 350 &client->query.qname); 351 } 352 client->query.qname = NULL; 353 client->query.attributes = (NS_QUERYATTR_RECURSIONOK | 354 NS_QUERYATTR_CACHEOK | 355 NS_QUERYATTR_SECURE); 356 client->query.restarts = 0; 357 client->query.timerset = ISC_FALSE; 358 if (client->query.rpz_st != NULL) { 359 rpz_st_clear(client); 360 if (everything) { 361 isc_mem_put(client->mctx, client->query.rpz_st, 362 sizeof(*client->query.rpz_st)); 363 client->query.rpz_st = NULL; 364 } 365 } 366 client->query.origqname = NULL; 367 client->query.dboptions = 0; 368 client->query.fetchoptions = 0; 369 client->query.gluedb = NULL; 370 client->query.authdbset = ISC_FALSE; 371 client->query.isreferral = ISC_FALSE; 372 client->query.dns64_options = 0; 373 client->query.dns64_ttl = ISC_UINT32_MAX; 374} 375 376static void 377query_next_callback(ns_client_t *client) { 378 query_reset(client, ISC_FALSE); 379} 380 381void 382ns_query_free(ns_client_t *client) { 383 query_reset(client, ISC_TRUE); 384} 385 386static inline isc_result_t 387query_newnamebuf(ns_client_t *client) { 388 isc_buffer_t *dbuf; 389 isc_result_t result; 390 391 CTRACE("query_newnamebuf"); 392 /*% 393 * Allocate a name buffer. 394 */ 395 396 dbuf = NULL; 397 result = isc_buffer_allocate(client->mctx, &dbuf, 1024); 398 if (result != ISC_R_SUCCESS) { 399 CTRACE("query_newnamebuf: isc_buffer_allocate failed: done"); 400 return (result); 401 } 402 ISC_LIST_APPEND(client->query.namebufs, dbuf, link); 403 404 CTRACE("query_newnamebuf: done"); 405 return (ISC_R_SUCCESS); 406} 407 408static inline isc_buffer_t * 409query_getnamebuf(ns_client_t *client) { 410 isc_buffer_t *dbuf; 411 isc_result_t result; 412 isc_region_t r; 413 414 CTRACE("query_getnamebuf"); 415 /*% 416 * Return a name buffer with space for a maximal name, allocating 417 * a new one if necessary. 418 */ 419 420 if (ISC_LIST_EMPTY(client->query.namebufs)) { 421 result = query_newnamebuf(client); 422 if (result != ISC_R_SUCCESS) { 423 CTRACE("query_getnamebuf: query_newnamebuf failed: done"); 424 return (NULL); 425 } 426 } 427 428 dbuf = ISC_LIST_TAIL(client->query.namebufs); 429 INSIST(dbuf != NULL); 430 isc_buffer_availableregion(dbuf, &r); 431 if (r.length < 255) { 432 result = query_newnamebuf(client); 433 if (result != ISC_R_SUCCESS) { 434 CTRACE("query_getnamebuf: query_newnamebuf failed: done"); 435 return (NULL); 436 437 } 438 dbuf = ISC_LIST_TAIL(client->query.namebufs); 439 isc_buffer_availableregion(dbuf, &r); 440 INSIST(r.length >= 255); 441 } 442 CTRACE("query_getnamebuf: done"); 443 return (dbuf); 444} 445 446static inline void 447query_keepname(ns_client_t *client, dns_name_t *name, isc_buffer_t *dbuf) { 448 isc_region_t r; 449 450 CTRACE("query_keepname"); 451 /*% 452 * 'name' is using space in 'dbuf', but 'dbuf' has not yet been 453 * adjusted to take account of that. We do the adjustment. 454 */ 455 456 REQUIRE((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED) != 0); 457 458 dns_name_toregion(name, &r); 459 isc_buffer_add(dbuf, r.length); 460 dns_name_setbuffer(name, NULL); 461 client->query.attributes &= ~NS_QUERYATTR_NAMEBUFUSED; 462} 463 464static inline void 465query_releasename(ns_client_t *client, dns_name_t **namep) { 466 dns_name_t *name = *namep; 467 468 /*% 469 * 'name' is no longer needed. Return it to our pool of temporary 470 * names. If it is using a name buffer, relinquish its exclusive 471 * rights on the buffer. 472 */ 473 474 CTRACE("query_releasename"); 475 if (dns_name_hasbuffer(name)) { 476 INSIST((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED) 477 != 0); 478 client->query.attributes &= ~NS_QUERYATTR_NAMEBUFUSED; 479 } 480 dns_message_puttempname(client->message, namep); 481 CTRACE("query_releasename: done"); 482} 483 484static inline dns_name_t * 485query_newname(ns_client_t *client, isc_buffer_t *dbuf, 486 isc_buffer_t *nbuf) 487{ 488 dns_name_t *name; 489 isc_region_t r; 490 isc_result_t result; 491 492 REQUIRE((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED) == 0); 493 494 CTRACE("query_newname"); 495 name = NULL; 496 result = dns_message_gettempname(client->message, &name); 497 if (result != ISC_R_SUCCESS) { 498 CTRACE("query_newname: dns_message_gettempname failed: done"); 499 return (NULL); 500 } 501 isc_buffer_availableregion(dbuf, &r); 502 isc_buffer_init(nbuf, r.base, r.length); 503 dns_name_init(name, NULL); 504 dns_name_setbuffer(name, nbuf); 505 client->query.attributes |= NS_QUERYATTR_NAMEBUFUSED; 506 507 CTRACE("query_newname: done"); 508 return (name); 509} 510 511static inline dns_rdataset_t * 512query_newrdataset(ns_client_t *client) { 513 dns_rdataset_t *rdataset; 514 isc_result_t result; 515 516 CTRACE("query_newrdataset"); 517 rdataset = NULL; 518 result = dns_message_gettemprdataset(client->message, &rdataset); 519 if (result != ISC_R_SUCCESS) { 520 CTRACE("query_newrdataset: " 521 "dns_message_gettemprdataset failed: done"); 522 return (NULL); 523 } 524 dns_rdataset_init(rdataset); 525 526 CTRACE("query_newrdataset: done"); 527 return (rdataset); 528} 529 530static inline isc_result_t 531query_newdbversion(ns_client_t *client, unsigned int n) { 532 unsigned int i; 533 ns_dbversion_t *dbversion; 534 535 for (i = 0; i < n; i++) { 536 dbversion = isc_mem_get(client->mctx, sizeof(*dbversion)); 537 if (dbversion != NULL) { 538 dbversion->db = NULL; 539 dbversion->version = NULL; 540 ISC_LIST_INITANDAPPEND(client->query.freeversions, 541 dbversion, link); 542 } else { 543 /* 544 * We only return ISC_R_NOMEMORY if we couldn't 545 * allocate anything. 546 */ 547 if (i == 0) 548 return (ISC_R_NOMEMORY); 549 else 550 return (ISC_R_SUCCESS); 551 } 552 } 553 554 return (ISC_R_SUCCESS); 555} 556 557static inline ns_dbversion_t * 558query_getdbversion(ns_client_t *client) { 559 isc_result_t result; 560 ns_dbversion_t *dbversion; 561 562 if (ISC_LIST_EMPTY(client->query.freeversions)) { 563 result = query_newdbversion(client, 1); 564 if (result != ISC_R_SUCCESS) 565 return (NULL); 566 } 567 dbversion = ISC_LIST_HEAD(client->query.freeversions); 568 INSIST(dbversion != NULL); 569 ISC_LIST_UNLINK(client->query.freeversions, dbversion, link); 570 571 return (dbversion); 572} 573 574isc_result_t 575ns_query_init(ns_client_t *client) { 576 isc_result_t result; 577 578 ISC_LIST_INIT(client->query.namebufs); 579 ISC_LIST_INIT(client->query.activeversions); 580 ISC_LIST_INIT(client->query.freeversions); 581 client->query.restarts = 0; 582 client->query.timerset = ISC_FALSE; 583 client->query.rpz_st = NULL; 584 client->query.qname = NULL; 585 result = isc_mutex_init(&client->query.fetchlock); 586 if (result != ISC_R_SUCCESS) 587 return (result); 588 client->query.fetch = NULL; 589 client->query.authdb = NULL; 590 client->query.authzone = NULL; 591 client->query.authdbset = ISC_FALSE; 592 client->query.isreferral = ISC_FALSE; 593 client->query.dns64_aaaa = NULL; 594 client->query.dns64_sigaaaa = NULL; 595 client->query.dns64_aaaaok = NULL; 596 client->query.dns64_aaaaoklen = 0; 597 query_reset(client, ISC_FALSE); 598 result = query_newdbversion(client, 3); 599 if (result != ISC_R_SUCCESS) { 600 DESTROYLOCK(&client->query.fetchlock); 601 return (result); 602 } 603 result = query_newnamebuf(client); 604 if (result != ISC_R_SUCCESS) 605 query_freefreeversions(client, ISC_TRUE); 606 607 return (result); 608} 609 610static inline ns_dbversion_t * 611query_findversion(ns_client_t *client, dns_db_t *db) 612{ 613 ns_dbversion_t *dbversion; 614 615 /*% 616 * We may already have done a query related to this 617 * database. If so, we must be sure to make subsequent 618 * queries from the same version. 619 */ 620 for (dbversion = ISC_LIST_HEAD(client->query.activeversions); 621 dbversion != NULL; 622 dbversion = ISC_LIST_NEXT(dbversion, link)) { 623 if (dbversion->db == db) 624 break; 625 } 626 627 if (dbversion == NULL) { 628 /* 629 * This is a new zone for this query. Add it to 630 * the active list. 631 */ 632 dbversion = query_getdbversion(client); 633 if (dbversion == NULL) 634 return (NULL); 635 dns_db_attach(db, &dbversion->db); 636 dns_db_currentversion(db, &dbversion->version); 637 dbversion->acl_checked = ISC_FALSE; 638 dbversion->queryok = ISC_FALSE; 639 ISC_LIST_APPEND(client->query.activeversions, 640 dbversion, link); 641 } 642 643 return (dbversion); 644} 645 646static inline isc_result_t 647query_validatezonedb(ns_client_t *client, dns_name_t *name, 648 dns_rdatatype_t qtype, unsigned int options, 649 dns_zone_t *zone, dns_db_t *db, 650 dns_dbversion_t **versionp) 651{ 652 isc_result_t result; 653 dns_acl_t *queryacl; 654 ns_dbversion_t *dbversion; 655 656 REQUIRE(zone != NULL); 657 REQUIRE(db != NULL); 658 659 /* 660 * This limits our searching to the zone where the first name 661 * (the query target) was looked for. This prevents following 662 * CNAMES or DNAMES into other zones and prevents returning 663 * additional data from other zones. 664 */ 665 if (!client->view->additionalfromauth && 666 client->query.authdbset && 667 db != client->query.authdb) 668 return (DNS_R_REFUSED); 669 670 /* 671 * Non recursive query to a static-stub zone is prohibited; its 672 * zone content is not public data, but a part of local configuration 673 * and should not be disclosed. 674 */ 675 if (dns_zone_gettype(zone) == dns_zone_staticstub && 676 !RECURSIONOK(client)) { 677 return (DNS_R_REFUSED); 678 } 679 680 /* 681 * If the zone has an ACL, we'll check it, otherwise 682 * we use the view's "allow-query" ACL. Each ACL is only checked 683 * once per query. 684 * 685 * Also, get the database version to use. 686 */ 687 688 /* 689 * Get the current version of this database. 690 */ 691 dbversion = query_findversion(client, db); 692 if (dbversion == NULL) 693 return (DNS_R_SERVFAIL); 694 695 if ((options & DNS_GETDB_IGNOREACL) != 0) 696 goto approved; 697 if (dbversion->acl_checked) { 698 if (!dbversion->queryok) 699 return (DNS_R_REFUSED); 700 goto approved; 701 } 702 703 queryacl = dns_zone_getqueryacl(zone); 704 if (queryacl == NULL) { 705 queryacl = client->view->queryacl; 706 if ((client->query.attributes & 707 NS_QUERYATTR_QUERYOKVALID) != 0) { 708 /* 709 * We've evaluated the view's queryacl already. If 710 * NS_QUERYATTR_QUERYOK is set, then the client is 711 * allowed to make queries, otherwise the query should 712 * be refused. 713 */ 714 dbversion->acl_checked = ISC_TRUE; 715 if ((client->query.attributes & 716 NS_QUERYATTR_QUERYOK) == 0) { 717 dbversion->queryok = ISC_FALSE; 718 return (DNS_R_REFUSED); 719 } 720 dbversion->queryok = ISC_TRUE; 721 goto approved; 722 } 723 } 724 725 result = ns_client_checkaclsilent(client, NULL, queryacl, ISC_TRUE); 726 if ((options & DNS_GETDB_NOLOG) == 0) { 727 char msg[NS_CLIENT_ACLMSGSIZE("query")]; 728 if (result == ISC_R_SUCCESS) { 729 if (isc_log_wouldlog(ns_g_lctx, ISC_LOG_DEBUG(3))) { 730 ns_client_aclmsg("query", name, qtype, 731 client->view->rdclass, 732 msg, sizeof(msg)); 733 ns_client_log(client, 734 DNS_LOGCATEGORY_SECURITY, 735 NS_LOGMODULE_QUERY, 736 ISC_LOG_DEBUG(3), 737 "%s approved", msg); 738 } 739 } else { 740 ns_client_aclmsg("query", name, qtype, 741 client->view->rdclass, 742 msg, sizeof(msg)); 743 ns_client_log(client, DNS_LOGCATEGORY_SECURITY, 744 NS_LOGMODULE_QUERY, ISC_LOG_INFO, 745 "%s denied", msg); 746 } 747 } 748 749 if (queryacl == client->view->queryacl) { 750 if (result == ISC_R_SUCCESS) { 751 /* 752 * We were allowed by the default 753 * "allow-query" ACL. Remember this so we 754 * don't have to check again. 755 */ 756 client->query.attributes |= NS_QUERYATTR_QUERYOK; 757 } 758 /* 759 * We've now evaluated the view's query ACL, and 760 * the NS_QUERYATTR_QUERYOK attribute is now valid. 761 */ 762 client->query.attributes |= NS_QUERYATTR_QUERYOKVALID; 763 } 764 765 dbversion->acl_checked = ISC_TRUE; 766 if (result != ISC_R_SUCCESS) { 767 dbversion->queryok = ISC_FALSE; 768 return (DNS_R_REFUSED); 769 } 770 dbversion->queryok = ISC_TRUE; 771 772 approved: 773 /* Transfer ownership, if necessary. */ 774 if (versionp != NULL) 775 *versionp = dbversion->version; 776 return (ISC_R_SUCCESS); 777} 778 779static inline isc_result_t 780query_getzonedb(ns_client_t *client, dns_name_t *name, dns_rdatatype_t qtype, 781 unsigned int options, dns_zone_t **zonep, dns_db_t **dbp, 782 dns_dbversion_t **versionp) 783{ 784 isc_result_t result; 785 unsigned int ztoptions; 786 dns_zone_t *zone = NULL; 787 dns_db_t *db = NULL; 788 isc_boolean_t partial = ISC_FALSE; 789 790 REQUIRE(zonep != NULL && *zonep == NULL); 791 REQUIRE(dbp != NULL && *dbp == NULL); 792 793 /*% 794 * Find a zone database to answer the query. 795 */ 796 ztoptions = ((options & DNS_GETDB_NOEXACT) != 0) ? 797 DNS_ZTFIND_NOEXACT : 0; 798 799 result = dns_zt_find(client->view->zonetable, name, ztoptions, NULL, 800 &zone); 801 if (result == DNS_R_PARTIALMATCH) 802 partial = ISC_TRUE; 803 if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) 804 result = dns_zone_getdb(zone, &db); 805 806 if (result != ISC_R_SUCCESS) 807 goto fail; 808 809 result = query_validatezonedb(client, name, qtype, options, zone, db, 810 versionp); 811 812 if (result != ISC_R_SUCCESS) 813 goto fail; 814 815 /* Transfer ownership. */ 816 *zonep = zone; 817 *dbp = db; 818 819 if (partial && (options & DNS_GETDB_PARTIAL) != 0) 820 return (DNS_R_PARTIALMATCH); 821 return (ISC_R_SUCCESS); 822 823 fail: 824 if (zone != NULL) 825 dns_zone_detach(&zone); 826 if (db != NULL) 827 dns_db_detach(&db); 828 829 return (result); 830} 831 832static void 833rpz_log_rewrite(ns_client_t *client, const char *disabled, 834 dns_rpz_policy_t policy, dns_rpz_type_t type, 835 dns_name_t *rpz_qname) { 836 char qname_buf[DNS_NAME_FORMATSIZE]; 837 char rpz_qname_buf[DNS_NAME_FORMATSIZE]; 838 839 if (!isc_log_wouldlog(ns_g_lctx, DNS_RPZ_INFO_LEVEL)) 840 return; 841 842 dns_name_format(client->query.qname, qname_buf, sizeof(qname_buf)); 843 dns_name_format(rpz_qname, rpz_qname_buf, sizeof(rpz_qname_buf)); 844 845 ns_client_log(client, DNS_LOGCATEGORY_RPZ, NS_LOGMODULE_QUERY, 846 DNS_RPZ_INFO_LEVEL, "%srpz %s %s rewrite %s via %s", 847 disabled, 848 dns_rpz_type2str(type), dns_rpz_policy2str(policy), 849 qname_buf, rpz_qname_buf); 850} 851 852static void 853rpz_log_fail(ns_client_t *client, int level, 854 dns_rpz_type_t rpz_type, dns_name_t *name, 855 const char *str, isc_result_t result) 856{ 857 char namebuf1[DNS_NAME_FORMATSIZE]; 858 char namebuf2[DNS_NAME_FORMATSIZE]; 859 860 if (!isc_log_wouldlog(ns_g_lctx, level)) 861 return; 862 863 dns_name_format(client->query.qname, namebuf1, sizeof(namebuf1)); 864 dns_name_format(name, namebuf2, sizeof(namebuf2)); 865 ns_client_log(client, NS_LOGCATEGORY_QUERY_EERRORS, 866 NS_LOGMODULE_QUERY, level, 867 "rpz %s rewrite %s via %s %sfailed: %s", 868 dns_rpz_type2str(rpz_type), 869 namebuf1, namebuf2, str, isc_result_totext(result)); 870} 871 872/* 873 * Get a policy rewrite zone database. 874 */ 875static isc_result_t 876rpz_getdb(ns_client_t *client, dns_rpz_type_t rpz_type, dns_name_t *rpz_qname, 877 dns_zone_t **zonep, dns_db_t **dbp, dns_dbversion_t **versionp) 878{ 879 char namebuf1[DNS_NAME_FORMATSIZE]; 880 char namebuf2[DNS_NAME_FORMATSIZE]; 881 dns_dbversion_t *rpz_version = NULL; 882 isc_result_t result; 883 884 result = query_getzonedb(client, rpz_qname, dns_rdatatype_any, 885 DNS_GETDB_IGNOREACL, zonep, dbp, &rpz_version); 886 if (result == ISC_R_SUCCESS) { 887 if (isc_log_wouldlog(ns_g_lctx, DNS_RPZ_DEBUG_LEVEL2)) { 888 dns_name_format(client->query.qname, namebuf1, 889 sizeof(namebuf1)); 890 dns_name_format(rpz_qname, namebuf2, sizeof(namebuf2)); 891 ns_client_log(client, DNS_LOGCATEGORY_RPZ, 892 NS_LOGMODULE_QUERY, DNS_RPZ_DEBUG_LEVEL2, 893 "try rpz %s rewrite %s via %s", 894 dns_rpz_type2str(rpz_type), 895 namebuf1, namebuf2); 896 } 897 *versionp = rpz_version; 898 return (ISC_R_SUCCESS); 899 } 900 rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, rpz_type, rpz_qname, 901 "query_getzonedb() ", result); 902 return (result); 903} 904 905static inline isc_result_t 906query_getcachedb(ns_client_t *client, dns_name_t *name, dns_rdatatype_t qtype, 907 dns_db_t **dbp, unsigned int options) 908{ 909 isc_result_t result; 910 isc_boolean_t check_acl; 911 dns_db_t *db = NULL; 912 913 REQUIRE(dbp != NULL && *dbp == NULL); 914 915 /*% 916 * Find a cache database to answer the query. 917 * This may fail with DNS_R_REFUSED if the client 918 * is not allowed to use the cache. 919 */ 920 921 if (!USECACHE(client)) 922 return (DNS_R_REFUSED); 923 dns_db_attach(client->view->cachedb, &db); 924 925 if ((client->query.attributes & NS_QUERYATTR_CACHEACLOKVALID) != 0) { 926 /* 927 * We've evaluated the view's cacheacl already. If 928 * NS_QUERYATTR_CACHEACLOK is set, then the client is 929 * allowed to make queries, otherwise the query should 930 * be refused. 931 */ 932 check_acl = ISC_FALSE; 933 if ((client->query.attributes & NS_QUERYATTR_CACHEACLOK) == 0) 934 goto refuse; 935 } else { 936 /* 937 * We haven't evaluated the view's queryacl yet. 938 */ 939 check_acl = ISC_TRUE; 940 } 941 942 if (check_acl) { 943 isc_boolean_t log = ISC_TF((options & DNS_GETDB_NOLOG) == 0); 944 char msg[NS_CLIENT_ACLMSGSIZE("query (cache)")]; 945 946 result = ns_client_checkaclsilent(client, NULL, 947 client->view->cacheacl, 948 ISC_TRUE); 949 if (result == ISC_R_SUCCESS) { 950 /* 951 * We were allowed by the "allow-query-cache" ACL. 952 * Remember this so we don't have to check again. 953 */ 954 client->query.attributes |= 955 NS_QUERYATTR_CACHEACLOK; 956 if (log && isc_log_wouldlog(ns_g_lctx, 957 ISC_LOG_DEBUG(3))) 958 { 959 ns_client_aclmsg("query (cache)", name, qtype, 960 client->view->rdclass, 961 msg, sizeof(msg)); 962 ns_client_log(client, 963 DNS_LOGCATEGORY_SECURITY, 964 NS_LOGMODULE_QUERY, 965 ISC_LOG_DEBUG(3), 966 "%s approved", msg); 967 } 968 } else if (log) { 969 ns_client_aclmsg("query (cache)", name, qtype, 970 client->view->rdclass, msg, 971 sizeof(msg)); 972 ns_client_log(client, DNS_LOGCATEGORY_SECURITY, 973 NS_LOGMODULE_QUERY, ISC_LOG_INFO, 974 "%s denied", msg); 975 } 976 /* 977 * We've now evaluated the view's query ACL, and 978 * the NS_QUERYATTR_CACHEACLOKVALID attribute is now valid. 979 */ 980 client->query.attributes |= NS_QUERYATTR_CACHEACLOKVALID; 981 982 if (result != ISC_R_SUCCESS) 983 goto refuse; 984 } 985 986 /* Approved. */ 987 988 /* Transfer ownership. */ 989 *dbp = db; 990 991 return (ISC_R_SUCCESS); 992 993 refuse: 994 result = DNS_R_REFUSED; 995 996 if (db != NULL) 997 dns_db_detach(&db); 998 999 return (result); 1000} 1001 1002 1003static inline isc_result_t 1004query_getdb(ns_client_t *client, dns_name_t *name, dns_rdatatype_t qtype, 1005 unsigned int options, dns_zone_t **zonep, dns_db_t **dbp, 1006 dns_dbversion_t **versionp, isc_boolean_t *is_zonep) 1007{ 1008 isc_result_t result; 1009 1010 isc_result_t tresult; 1011 unsigned int namelabels; 1012 unsigned int zonelabels; 1013 dns_zone_t *zone = NULL; 1014 dns_db_t *tdbp; 1015 1016 REQUIRE(zonep != NULL && *zonep == NULL); 1017 1018 tdbp = NULL; 1019 1020 /* Calculate how many labels are in name. */ 1021 namelabels = dns_name_countlabels(name); 1022 zonelabels = 0; 1023 1024 /* Try to find name in bind's standard database. */ 1025 result = query_getzonedb(client, name, qtype, options, &zone, 1026 dbp, versionp); 1027 1028 /* See how many labels are in the zone's name. */ 1029 if (result == ISC_R_SUCCESS && zone != NULL) 1030 zonelabels = dns_name_countlabels(dns_zone_getorigin(zone)); 1031 /* 1032 * If # zone labels < # name labels, try to find an even better match 1033 * Only try if a DLZ driver is loaded for this view 1034 */ 1035 if (zonelabels < namelabels && client->view->dlzdatabase != NULL) { 1036 tresult = dns_dlzfindzone(client->view, name, 1037 zonelabels, &tdbp); 1038 /* If we successful, we found a better match. */ 1039 if (tresult == ISC_R_SUCCESS) { 1040 /* 1041 * If the previous search returned a zone, detach it. 1042 */ 1043 if (zone != NULL) 1044 dns_zone_detach(&zone); 1045 1046 /* 1047 * If the previous search returned a database, 1048 * detach it. 1049 */ 1050 if (*dbp != NULL) 1051 dns_db_detach(dbp); 1052 1053 /* 1054 * If the previous search returned a version, clear it. 1055 */ 1056 *versionp = NULL; 1057 1058 /* 1059 * Get our database version. 1060 */ 1061 dns_db_currentversion(tdbp, versionp); 1062 1063 /* 1064 * Be sure to return our database. 1065 */ 1066 *dbp = tdbp; 1067 1068 /* 1069 * We return a null zone, No stats for DLZ zones. 1070 */ 1071 zone = NULL; 1072 result = tresult; 1073 } 1074 } 1075 1076 /* If successful, Transfer ownership of zone. */ 1077 if (result == ISC_R_SUCCESS) { 1078 *zonep = zone; 1079 /* 1080 * If neither attempt above succeeded, return the cache instead 1081 */ 1082 *is_zonep = ISC_TRUE; 1083 } else if (result == ISC_R_NOTFOUND) { 1084 result = query_getcachedb(client, name, qtype, dbp, options); 1085 *is_zonep = ISC_FALSE; 1086 } 1087 return (result); 1088} 1089 1090static inline isc_boolean_t 1091query_isduplicate(ns_client_t *client, dns_name_t *name, 1092 dns_rdatatype_t type, dns_name_t **mnamep) 1093{ 1094 dns_section_t section; 1095 dns_name_t *mname = NULL; 1096 isc_result_t result; 1097 1098 CTRACE("query_isduplicate"); 1099 1100 for (section = DNS_SECTION_ANSWER; 1101 section <= DNS_SECTION_ADDITIONAL; 1102 section++) { 1103 result = dns_message_findname(client->message, section, 1104 name, type, 0, &mname, NULL); 1105 if (result == ISC_R_SUCCESS) { 1106 /* 1107 * We've already got this RRset in the response. 1108 */ 1109 CTRACE("query_isduplicate: true: done"); 1110 return (ISC_TRUE); 1111 } else if (result == DNS_R_NXRRSET) { 1112 /* 1113 * The name exists, but the rdataset does not. 1114 */ 1115 if (section == DNS_SECTION_ADDITIONAL) 1116 break; 1117 } else 1118 RUNTIME_CHECK(result == DNS_R_NXDOMAIN); 1119 mname = NULL; 1120 } 1121 1122 if (mnamep != NULL) 1123 *mnamep = mname; 1124 1125 CTRACE("query_isduplicate: false: done"); 1126 return (ISC_FALSE); 1127} 1128 1129static isc_result_t 1130query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) { 1131 ns_client_t *client = arg; 1132 isc_result_t result, eresult; 1133 dns_dbnode_t *node; 1134 dns_db_t *db; 1135 dns_name_t *fname, *mname; 1136 dns_rdataset_t *rdataset, *sigrdataset, *trdataset; 1137 isc_buffer_t *dbuf; 1138 isc_buffer_t b; 1139 dns_dbversion_t *version; 1140 isc_boolean_t added_something, need_addname; 1141 dns_zone_t *zone; 1142 dns_rdatatype_t type; 1143 1144 REQUIRE(NS_CLIENT_VALID(client)); 1145 REQUIRE(qtype != dns_rdatatype_any); 1146 1147 if (!WANTDNSSEC(client) && dns_rdatatype_isdnssec(qtype)) 1148 return (ISC_R_SUCCESS); 1149 1150 CTRACE("query_addadditional"); 1151 1152 /* 1153 * Initialization. 1154 */ 1155 eresult = ISC_R_SUCCESS; 1156 fname = NULL; 1157 rdataset = NULL; 1158 sigrdataset = NULL; 1159 trdataset = NULL; 1160 db = NULL; 1161 version = NULL; 1162 node = NULL; 1163 added_something = ISC_FALSE; 1164 need_addname = ISC_FALSE; 1165 zone = NULL; 1166 1167 /* 1168 * We treat type A additional section processing as if it 1169 * were "any address type" additional section processing. 1170 * To avoid multiple lookups, we do an 'any' database 1171 * lookup and iterate over the node. 1172 */ 1173 if (qtype == dns_rdatatype_a) 1174 type = dns_rdatatype_any; 1175 else 1176 type = qtype; 1177 1178 /* 1179 * Get some resources. 1180 */ 1181 dbuf = query_getnamebuf(client); 1182 if (dbuf == NULL) 1183 goto cleanup; 1184 fname = query_newname(client, dbuf, &b); 1185 rdataset = query_newrdataset(client); 1186 if (fname == NULL || rdataset == NULL) 1187 goto cleanup; 1188 if (WANTDNSSEC(client)) { 1189 sigrdataset = query_newrdataset(client); 1190 if (sigrdataset == NULL) 1191 goto cleanup; 1192 } 1193 1194 /* 1195 * Look for a zone database that might contain authoritative 1196 * additional data. 1197 */ 1198 result = query_getzonedb(client, name, qtype, DNS_GETDB_NOLOG, 1199 &zone, &db, &version); 1200 if (result != ISC_R_SUCCESS) 1201 goto try_cache; 1202 1203 CTRACE("query_addadditional: db_find"); 1204 1205 /* 1206 * Since we are looking for authoritative data, we do not set 1207 * the GLUEOK flag. Glue will be looked for later, but not 1208 * necessarily in the same database. 1209 */ 1210 node = NULL; 1211 result = dns_db_find(db, name, version, type, client->query.dboptions, 1212 client->now, &node, fname, rdataset, 1213 sigrdataset); 1214 if (result == ISC_R_SUCCESS) { 1215 if (sigrdataset != NULL && !dns_db_issecure(db) && 1216 dns_rdataset_isassociated(sigrdataset)) 1217 dns_rdataset_disassociate(sigrdataset); 1218 goto found; 1219 } 1220 1221 if (dns_rdataset_isassociated(rdataset)) 1222 dns_rdataset_disassociate(rdataset); 1223 if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) 1224 dns_rdataset_disassociate(sigrdataset); 1225 if (node != NULL) 1226 dns_db_detachnode(db, &node); 1227 version = NULL; 1228 dns_db_detach(&db); 1229 1230 /* 1231 * No authoritative data was found. The cache is our next best bet. 1232 */ 1233 1234 try_cache: 1235 result = query_getcachedb(client, name, qtype, &db, DNS_GETDB_NOLOG); 1236 if (result != ISC_R_SUCCESS) 1237 /* 1238 * Most likely the client isn't allowed to query the cache. 1239 */ 1240 goto try_glue; 1241 /* 1242 * Attempt to validate glue. 1243 */ 1244 if (sigrdataset == NULL) { 1245 sigrdataset = query_newrdataset(client); 1246 if (sigrdataset == NULL) 1247 goto cleanup; 1248 } 1249 result = dns_db_find(db, name, version, type, 1250 client->query.dboptions | 1251 DNS_DBFIND_GLUEOK | DNS_DBFIND_ADDITIONALOK, 1252 client->now, &node, fname, rdataset, 1253 sigrdataset); 1254 if (result == DNS_R_GLUE && 1255 validate(client, db, fname, rdataset, sigrdataset)) 1256 result = ISC_R_SUCCESS; 1257 if (!WANTDNSSEC(client)) 1258 query_putrdataset(client, &sigrdataset); 1259 if (result == ISC_R_SUCCESS) 1260 goto found; 1261 1262 if (dns_rdataset_isassociated(rdataset)) 1263 dns_rdataset_disassociate(rdataset); 1264 if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) 1265 dns_rdataset_disassociate(sigrdataset); 1266 if (node != NULL) 1267 dns_db_detachnode(db, &node); 1268 dns_db_detach(&db); 1269 1270 try_glue: 1271 /* 1272 * No cached data was found. Glue is our last chance. 1273 * RFC1035 sayeth: 1274 * 1275 * NS records cause both the usual additional section 1276 * processing to locate a type A record, and, when used 1277 * in a referral, a special search of the zone in which 1278 * they reside for glue information. 1279 * 1280 * This is the "special search". Note that we must search 1281 * the zone where the NS record resides, not the zone it 1282 * points to, and that we only do the search in the delegation 1283 * case (identified by client->query.gluedb being set). 1284 */ 1285 1286 if (client->query.gluedb == NULL) 1287 goto cleanup; 1288 1289 /* 1290 * Don't poison caches using the bailiwick protection model. 1291 */ 1292 if (!dns_name_issubdomain(name, dns_db_origin(client->query.gluedb))) 1293 goto cleanup; 1294 1295 dns_db_attach(client->query.gluedb, &db); 1296 result = dns_db_find(db, name, version, type, 1297 client->query.dboptions | DNS_DBFIND_GLUEOK, 1298 client->now, &node, fname, rdataset, 1299 sigrdataset); 1300 if (!(result == ISC_R_SUCCESS || 1301 result == DNS_R_ZONECUT || 1302 result == DNS_R_GLUE)) 1303 goto cleanup; 1304 1305 found: 1306 /* 1307 * We have found a potential additional data rdataset, or 1308 * at least a node to iterate over. 1309 */ 1310 query_keepname(client, fname, dbuf); 1311 1312 /* 1313 * If we have an rdataset, add it to the additional data 1314 * section. 1315 */ 1316 mname = NULL; 1317 if (dns_rdataset_isassociated(rdataset) && 1318 !query_isduplicate(client, fname, type, &mname)) { 1319 if (mname != NULL) { 1320 INSIST(mname != fname); 1321 query_releasename(client, &fname); 1322 fname = mname; 1323 } else 1324 need_addname = ISC_TRUE; 1325 ISC_LIST_APPEND(fname->list, rdataset, link); 1326 trdataset = rdataset; 1327 rdataset = NULL; 1328 added_something = ISC_TRUE; 1329 /* 1330 * Note: we only add SIGs if we've added the type they cover, 1331 * so we do not need to check if the SIG rdataset is already 1332 * in the response. 1333 */ 1334 if (sigrdataset != NULL && 1335 dns_rdataset_isassociated(sigrdataset)) 1336 { 1337 ISC_LIST_APPEND(fname->list, sigrdataset, link); 1338 sigrdataset = NULL; 1339 } 1340 } 1341 1342 if (qtype == dns_rdatatype_a) { 1343#ifdef ALLOW_FILTER_AAAA_ON_V4 1344 isc_boolean_t have_a = ISC_FALSE; 1345#endif 1346 1347 /* 1348 * We now go looking for A and AAAA records, along with 1349 * their signatures. 1350 * 1351 * XXXRTH This code could be more efficient. 1352 */ 1353 if (rdataset != NULL) { 1354 if (dns_rdataset_isassociated(rdataset)) 1355 dns_rdataset_disassociate(rdataset); 1356 } else { 1357 rdataset = query_newrdataset(client); 1358 if (rdataset == NULL) 1359 goto addname; 1360 } 1361 if (sigrdataset != NULL) { 1362 if (dns_rdataset_isassociated(sigrdataset)) 1363 dns_rdataset_disassociate(sigrdataset); 1364 } else if (WANTDNSSEC(client)) { 1365 sigrdataset = query_newrdataset(client); 1366 if (sigrdataset == NULL) 1367 goto addname; 1368 } 1369 if (query_isduplicate(client, fname, dns_rdatatype_a, NULL)) 1370 goto aaaa_lookup; 1371 result = dns_db_findrdataset(db, node, version, 1372 dns_rdatatype_a, 0, 1373 client->now, rdataset, 1374 sigrdataset); 1375 if (result == DNS_R_NCACHENXDOMAIN) 1376 goto addname; 1377 if (result == DNS_R_NCACHENXRRSET) { 1378 dns_rdataset_disassociate(rdataset); 1379 if (sigrdataset != NULL && 1380 dns_rdataset_isassociated(sigrdataset)) 1381 dns_rdataset_disassociate(sigrdataset); 1382 } 1383 if (result == ISC_R_SUCCESS) { 1384 mname = NULL; 1385#ifdef ALLOW_FILTER_AAAA_ON_V4 1386 have_a = ISC_TRUE; 1387#endif 1388 if (!query_isduplicate(client, fname, 1389 dns_rdatatype_a, &mname)) { 1390 if (mname != fname) { 1391 if (mname != NULL) { 1392 query_releasename(client, &fname); 1393 fname = mname; 1394 } else 1395 need_addname = ISC_TRUE; 1396 } 1397 ISC_LIST_APPEND(fname->list, rdataset, link); 1398 added_something = ISC_TRUE; 1399 if (sigrdataset != NULL && 1400 dns_rdataset_isassociated(sigrdataset)) 1401 { 1402 ISC_LIST_APPEND(fname->list, 1403 sigrdataset, link); 1404 sigrdataset = 1405 query_newrdataset(client); 1406 } 1407 rdataset = query_newrdataset(client); 1408 if (rdataset == NULL) 1409 goto addname; 1410 if (WANTDNSSEC(client) && sigrdataset == NULL) 1411 goto addname; 1412 } else { 1413 dns_rdataset_disassociate(rdataset); 1414 if (sigrdataset != NULL && 1415 dns_rdataset_isassociated(sigrdataset)) 1416 dns_rdataset_disassociate(sigrdataset); 1417 } 1418 } 1419 aaaa_lookup: 1420 if (query_isduplicate(client, fname, dns_rdatatype_aaaa, NULL)) 1421 goto addname; 1422 result = dns_db_findrdataset(db, node, version, 1423 dns_rdatatype_aaaa, 0, 1424 client->now, rdataset, 1425 sigrdataset); 1426 if (result == DNS_R_NCACHENXDOMAIN) 1427 goto addname; 1428 if (result == DNS_R_NCACHENXRRSET) { 1429 dns_rdataset_disassociate(rdataset); 1430 if (sigrdataset != NULL && 1431 dns_rdataset_isassociated(sigrdataset)) 1432 dns_rdataset_disassociate(sigrdataset); 1433 } 1434 if (result == ISC_R_SUCCESS) { 1435 mname = NULL; 1436 /* 1437 * There's an A; check whether we're filtering AAAA 1438 */ 1439#ifdef ALLOW_FILTER_AAAA_ON_V4 1440 if (have_a && 1441 (client->filter_aaaa == dns_v4_aaaa_break_dnssec || 1442 (client->filter_aaaa == dns_v4_aaaa_filter && 1443 (!WANTDNSSEC(client) || sigrdataset == NULL || 1444 !dns_rdataset_isassociated(sigrdataset))))) 1445 goto addname; 1446#endif 1447 if (!query_isduplicate(client, fname, 1448 dns_rdatatype_aaaa, &mname)) { 1449 if (mname != fname) { 1450 if (mname != NULL) { 1451 query_releasename(client, &fname); 1452 fname = mname; 1453 } else 1454 need_addname = ISC_TRUE; 1455 } 1456 ISC_LIST_APPEND(fname->list, rdataset, link); 1457 added_something = ISC_TRUE; 1458 if (sigrdataset != NULL && 1459 dns_rdataset_isassociated(sigrdataset)) 1460 { 1461 ISC_LIST_APPEND(fname->list, 1462 sigrdataset, link); 1463 sigrdataset = NULL; 1464 } 1465 rdataset = NULL; 1466 } 1467 } 1468 } 1469 1470 addname: 1471 CTRACE("query_addadditional: addname"); 1472 /* 1473 * If we haven't added anything, then we're done. 1474 */ 1475 if (!added_something) 1476 goto cleanup; 1477 1478 /* 1479 * We may have added our rdatasets to an existing name, if so, then 1480 * need_addname will be ISC_FALSE. Whether we used an existing name 1481 * or a new one, we must set fname to NULL to prevent cleanup. 1482 */ 1483 if (need_addname) 1484 dns_message_addname(client->message, fname, 1485 DNS_SECTION_ADDITIONAL); 1486 fname = NULL; 1487 1488 /* 1489 * In a few cases, we want to add additional data for additional 1490 * data. It's simpler to just deal with special cases here than 1491 * to try to create a general purpose mechanism and allow the 1492 * rdata implementations to do it themselves. 1493 * 1494 * This involves recursion, but the depth is limited. The 1495 * most complex case is adding a SRV rdataset, which involves 1496 * recursing to add address records, which in turn can cause 1497 * recursion to add KEYs. 1498 */ 1499 if (type == dns_rdatatype_srv && trdataset != NULL) { 1500 /* 1501 * If we're adding SRV records to the additional data 1502 * section, it's helpful if we add the SRV additional data 1503 * as well. 1504 */ 1505 eresult = dns_rdataset_additionaldata(trdataset, 1506 query_addadditional, 1507 client); 1508 } 1509 1510 cleanup: 1511 CTRACE("query_addadditional: cleanup"); 1512 query_putrdataset(client, &rdataset); 1513 if (sigrdataset != NULL) 1514 query_putrdataset(client, &sigrdataset); 1515 if (fname != NULL) 1516 query_releasename(client, &fname); 1517 if (node != NULL) 1518 dns_db_detachnode(db, &node); 1519 if (db != NULL) 1520 dns_db_detach(&db); 1521 if (zone != NULL) 1522 dns_zone_detach(&zone); 1523 1524 CTRACE("query_addadditional: done"); 1525 return (eresult); 1526} 1527 1528static inline void 1529query_discardcache(ns_client_t *client, dns_rdataset_t *rdataset_base, 1530 dns_rdatasetadditional_t additionaltype, 1531 dns_rdatatype_t type, dns_zone_t **zonep, dns_db_t **dbp, 1532 dns_dbversion_t **versionp, dns_dbnode_t **nodep, 1533 dns_name_t *fname) 1534{ 1535 dns_rdataset_t *rdataset; 1536 1537 while ((rdataset = ISC_LIST_HEAD(fname->list)) != NULL) { 1538 ISC_LIST_UNLINK(fname->list, rdataset, link); 1539 query_putrdataset(client, &rdataset); 1540 } 1541 if (*versionp != NULL) 1542 dns_db_closeversion(*dbp, versionp, ISC_FALSE); 1543 if (*nodep != NULL) 1544 dns_db_detachnode(*dbp, nodep); 1545 if (*dbp != NULL) 1546 dns_db_detach(dbp); 1547 if (*zonep != NULL) 1548 dns_zone_detach(zonep); 1549 (void)dns_rdataset_putadditional(client->view->acache, rdataset_base, 1550 additionaltype, type); 1551} 1552 1553static inline isc_result_t 1554query_iscachevalid(dns_zone_t *zone, dns_db_t *db, dns_db_t *db0, 1555 dns_dbversion_t *version) 1556{ 1557 isc_result_t result = ISC_R_SUCCESS; 1558 dns_dbversion_t *version_current = NULL; 1559 dns_db_t *db_current = db0; 1560 1561 if (db_current == NULL) { 1562 result = dns_zone_getdb(zone, &db_current); 1563 if (result != ISC_R_SUCCESS) 1564 return (result); 1565 } 1566 dns_db_currentversion(db_current, &version_current); 1567 if (db_current != db || version_current != version) { 1568 result = ISC_R_FAILURE; 1569 goto cleanup; 1570 } 1571 1572 cleanup: 1573 dns_db_closeversion(db_current, &version_current, ISC_FALSE); 1574 if (db0 == NULL && db_current != NULL) 1575 dns_db_detach(&db_current); 1576 1577 return (result); 1578} 1579 1580static isc_result_t 1581query_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) { 1582 client_additionalctx_t *additionalctx = arg; 1583 dns_rdataset_t *rdataset_base; 1584 ns_client_t *client; 1585 isc_result_t result, eresult; 1586 dns_dbnode_t *node, *cnode; 1587 dns_db_t *db, *cdb; 1588 dns_name_t *fname, *mname0, cfname; 1589 dns_rdataset_t *rdataset, *sigrdataset; 1590 dns_rdataset_t *crdataset, *crdataset_next; 1591 isc_buffer_t *dbuf; 1592 isc_buffer_t b; 1593 dns_dbversion_t *version, *cversion; 1594 isc_boolean_t added_something, need_addname, needadditionalcache; 1595 isc_boolean_t need_sigrrset; 1596 dns_zone_t *zone; 1597 dns_rdatatype_t type; 1598 dns_rdatasetadditional_t additionaltype; 1599 1600 /* 1601 * If we don't have an additional cache call query_addadditional. 1602 */ 1603 client = additionalctx->client; 1604 REQUIRE(NS_CLIENT_VALID(client)); 1605 1606 if (qtype != dns_rdatatype_a || client->view->acache == NULL) { 1607 /* 1608 * This function is optimized for "address" types. For other 1609 * types, use a generic routine. 1610 * XXX: ideally, this function should be generic enough. 1611 */ 1612 return (query_addadditional(additionalctx->client, 1613 name, qtype)); 1614 } 1615 1616 /* 1617 * Initialization. 1618 */ 1619 rdataset_base = additionalctx->rdataset; 1620 eresult = ISC_R_SUCCESS; 1621 fname = NULL; 1622 rdataset = NULL; 1623 sigrdataset = NULL; 1624 db = NULL; 1625 cdb = NULL; 1626 version = NULL; 1627 cversion = NULL; 1628 node = NULL; 1629 cnode = NULL; 1630 added_something = ISC_FALSE; 1631 need_addname = ISC_FALSE; 1632 zone = NULL; 1633 needadditionalcache = ISC_FALSE; 1634 POST(needadditionalcache); 1635 additionaltype = dns_rdatasetadditional_fromauth; 1636 dns_name_init(&cfname, NULL); 1637 1638 CTRACE("query_addadditional2"); 1639 1640 /* 1641 * We treat type A additional section processing as if it 1642 * were "any address type" additional section processing. 1643 * To avoid multiple lookups, we do an 'any' database 1644 * lookup and iterate over the node. 1645 * XXXJT: this approach can cause a suboptimal result when the cache 1646 * DB only has partial address types and the glue DB has remaining 1647 * ones. 1648 */ 1649 type = dns_rdatatype_any; 1650 1651 /* 1652 * Get some resources. 1653 */ 1654 dbuf = query_getnamebuf(client); 1655 if (dbuf == NULL) 1656 goto cleanup; 1657 fname = query_newname(client, dbuf, &b); 1658 if (fname == NULL) 1659 goto cleanup; 1660 dns_name_setbuffer(&cfname, &b); /* share the buffer */ 1661 1662 /* Check additional cache */ 1663 result = dns_rdataset_getadditional(rdataset_base, additionaltype, 1664 type, client->view->acache, &zone, 1665 &cdb, &cversion, &cnode, &cfname, 1666 client->message, client->now); 1667 if (result != ISC_R_SUCCESS) 1668 goto findauthdb; 1669 if (zone == NULL) { 1670 CTRACE("query_addadditional2: auth zone not found"); 1671 goto try_cache; 1672 } 1673 1674 /* Is the cached DB up-to-date? */ 1675 result = query_iscachevalid(zone, cdb, NULL, cversion); 1676 if (result != ISC_R_SUCCESS) { 1677 CTRACE("query_addadditional2: old auth additional cache"); 1678 query_discardcache(client, rdataset_base, additionaltype, 1679 type, &zone, &cdb, &cversion, &cnode, 1680 &cfname); 1681 goto findauthdb; 1682 } 1683 1684 if (cnode == NULL) { 1685 /* 1686 * We have a negative cache. We don't have to check the zone 1687 * ACL, since the result (not using this zone) would be same 1688 * regardless of the result. 1689 */ 1690 CTRACE("query_addadditional2: negative auth additional cache"); 1691 dns_db_closeversion(cdb, &cversion, ISC_FALSE); 1692 dns_db_detach(&cdb); 1693 dns_zone_detach(&zone); 1694 goto try_cache; 1695 } 1696 1697 result = query_validatezonedb(client, name, qtype, DNS_GETDB_NOLOG, 1698 zone, cdb, NULL); 1699 if (result != ISC_R_SUCCESS) { 1700 query_discardcache(client, rdataset_base, additionaltype, 1701 type, &zone, &cdb, &cversion, &cnode, 1702 &cfname); 1703 goto try_cache; 1704 } 1705 1706 /* We've got an active cache. */ 1707 CTRACE("query_addadditional2: auth additional cache"); 1708 dns_db_closeversion(cdb, &cversion, ISC_FALSE); 1709 db = cdb; 1710 node = cnode; 1711 dns_name_clone(&cfname, fname); 1712 query_keepname(client, fname, dbuf); 1713 goto foundcache; 1714 1715 /* 1716 * Look for a zone database that might contain authoritative 1717 * additional data. 1718 */ 1719 findauthdb: 1720 result = query_getzonedb(client, name, qtype, DNS_GETDB_NOLOG, 1721 &zone, &db, &version); 1722 if (result != ISC_R_SUCCESS) { 1723 /* Cache the negative result */ 1724 (void)dns_rdataset_setadditional(rdataset_base, additionaltype, 1725 type, client->view->acache, 1726 NULL, NULL, NULL, NULL, 1727 NULL); 1728 goto try_cache; 1729 } 1730 1731 CTRACE("query_addadditional2: db_find"); 1732 1733 /* 1734 * Since we are looking for authoritative data, we do not set 1735 * the GLUEOK flag. Glue will be looked for later, but not 1736 * necessarily in the same database. 1737 */ 1738 node = NULL; 1739 result = dns_db_find(db, name, version, type, client->query.dboptions, 1740 client->now, &node, fname, NULL, NULL); 1741 if (result == ISC_R_SUCCESS) 1742 goto found; 1743 1744 /* Cache the negative result */ 1745 (void)dns_rdataset_setadditional(rdataset_base, additionaltype, 1746 type, client->view->acache, zone, db, 1747 version, NULL, fname); 1748 1749 if (node != NULL) 1750 dns_db_detachnode(db, &node); 1751 version = NULL; 1752 dns_db_detach(&db); 1753 1754 /* 1755 * No authoritative data was found. The cache is our next best bet. 1756 */ 1757 1758 try_cache: 1759 additionaltype = dns_rdatasetadditional_fromcache; 1760 result = query_getcachedb(client, name, qtype, &db, DNS_GETDB_NOLOG); 1761 if (result != ISC_R_SUCCESS) 1762 /* 1763 * Most likely the client isn't allowed to query the cache. 1764 */ 1765 goto try_glue; 1766 1767 result = dns_db_find(db, name, version, type, 1768 client->query.dboptions | 1769 DNS_DBFIND_GLUEOK | DNS_DBFIND_ADDITIONALOK, 1770 client->now, &node, fname, NULL, NULL); 1771 if (result == ISC_R_SUCCESS) 1772 goto found; 1773 1774 if (node != NULL) 1775 dns_db_detachnode(db, &node); 1776 dns_db_detach(&db); 1777 1778 try_glue: 1779 /* 1780 * No cached data was found. Glue is our last chance. 1781 * RFC1035 sayeth: 1782 * 1783 * NS records cause both the usual additional section 1784 * processing to locate a type A record, and, when used 1785 * in a referral, a special search of the zone in which 1786 * they reside for glue information. 1787 * 1788 * This is the "special search". Note that we must search 1789 * the zone where the NS record resides, not the zone it 1790 * points to, and that we only do the search in the delegation 1791 * case (identified by client->query.gluedb being set). 1792 */ 1793 if (client->query.gluedb == NULL) 1794 goto cleanup; 1795 1796 /* 1797 * Don't poison caches using the bailiwick protection model. 1798 */ 1799 if (!dns_name_issubdomain(name, dns_db_origin(client->query.gluedb))) 1800 goto cleanup; 1801 1802 /* Check additional cache */ 1803 additionaltype = dns_rdatasetadditional_fromglue; 1804 result = dns_rdataset_getadditional(rdataset_base, additionaltype, 1805 type, client->view->acache, NULL, 1806 &cdb, &cversion, &cnode, &cfname, 1807 client->message, client->now); 1808 if (result != ISC_R_SUCCESS) 1809 goto findglue; 1810 1811 result = query_iscachevalid(zone, cdb, client->query.gluedb, cversion); 1812 if (result != ISC_R_SUCCESS) { 1813 CTRACE("query_addadditional2: old glue additional cache"); 1814 query_discardcache(client, rdataset_base, additionaltype, 1815 type, &zone, &cdb, &cversion, &cnode, 1816 &cfname); 1817 goto findglue; 1818 } 1819 1820 if (cnode == NULL) { 1821 /* We have a negative cache. */ 1822 CTRACE("query_addadditional2: negative glue additional cache"); 1823 dns_db_closeversi…
Large files files are truncated, but you can click here to view the full file