dnsrps.c revision 1.11
1/* $NetBSD: dnsrps.c,v 1.11 2024/02/21 22:52:06 christos Exp $ */ 2 3/* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16/*! \file */ 17 18#include <inttypes.h> 19#include <stdbool.h> 20 21#ifdef USE_DNSRPS 22 23#include <stdlib.h> 24 25#include <isc/mem.h> 26#include <isc/string.h> 27#include <isc/util.h> 28 29#include <dns/db.h> 30#define LIBRPZ_LIB_OPEN DNSRPS_LIB_OPEN 31#include <isc/result.h> 32 33#include <dns/dnsrps.h> 34#include <dns/rdataset.h> 35#include <dns/rdatasetiter.h> 36#include <dns/rpz.h> 37 38librpz_t *librpz; 39librpz_emsg_t librpz_lib_open_emsg; 40static void *librpz_handle; 41 42#define RPSDB_MAGIC ISC_MAGIC('R', 'P', 'Z', 'F') 43#define VALID_RPSDB(rpsdb) ((rpsdb)->common.impmagic == RPSDB_MAGIC) 44 45#define RD_DB(r) ((r)->private1) 46#define RD_CUR_RR(r) ((r)->private2) 47#define RD_NEXT_RR(r) ((r)->resign) 48#define RD_COUNT(r) ((r)->privateuint4) 49 50typedef struct { 51 dns_rdatasetiter_t common; 52 dns_rdatatype_t type; 53 dns_rdataclass_t class; 54 uint32_t ttl; 55 uint count; 56 librpz_idx_t next_rr; 57} rpsdb_rdatasetiter_t; 58 59static dns_dbmethods_t rpsdb_db_methods; 60static dns_rdatasetmethods_t rpsdb_rdataset_methods; 61static dns_rdatasetitermethods_t rpsdb_rdatasetiter_methods; 62 63static librpz_clist_t *clist; 64 65static isc_mutex_t dnsrps_mutex; 66 67static void 68dnsrps_lock(void *mutex0) { 69 isc_mutex_t *mutex = mutex0; 70 71 LOCK(mutex); 72} 73 74static void 75dnsrps_unlock(void *mutex0) { 76 isc_mutex_t *mutex = mutex0; 77 78 UNLOCK(mutex); 79} 80 81static void 82dnsrps_mutex_destroy(void *mutex0) { 83 isc_mutex_t *mutex = mutex0; 84 85 isc_mutex_destroy(mutex); 86} 87 88static void 89dnsrps_log_fnc(librpz_log_level_t level, void *ctxt, const char *buf) { 90 int isc_level; 91 92 UNUSED(ctxt); 93 94 /* Setting librpz_log_level in the configuration overrides the 95 * BIND9 logging levels. */ 96 if (level > LIBRPZ_LOG_TRACE1 && 97 level <= librpz->log_level_val(LIBRPZ_LOG_INVALID)) 98 { 99 level = LIBRPZ_LOG_TRACE1; 100 } 101 102 switch (level) { 103 case LIBRPZ_LOG_FATAL: 104 case LIBRPZ_LOG_ERROR: /* errors */ 105 default: 106 isc_level = DNS_RPZ_ERROR_LEVEL; 107 break; 108 109 case LIBRPZ_LOG_TRACE1: /* big events such as dnsrpzd starts */ 110 isc_level = DNS_RPZ_INFO_LEVEL; 111 break; 112 113 case LIBRPZ_LOG_TRACE2: /* smaller dnsrpzd zone transfers */ 114 isc_level = DNS_RPZ_DEBUG_LEVEL1; 115 break; 116 117 case LIBRPZ_LOG_TRACE3: /* librpz hits */ 118 isc_level = DNS_RPZ_DEBUG_LEVEL2; 119 break; 120 121 case LIBRPZ_LOG_TRACE4: /* librpz lookups */ 122 isc_level = DNS_RPZ_DEBUG_LEVEL3; 123 break; 124 } 125 isc_log_write(dns_lctx, DNS_LOGCATEGORY_RPZ, DNS_LOGMODULE_RBTDB, 126 isc_level, "dnsrps: %s", buf); 127} 128 129/* 130 * Start dnsrps for the entire server. 131 * This is not thread safe, but it is called by a single thread. 132 */ 133isc_result_t 134dns_dnsrps_server_create(void) { 135 librpz_emsg_t emsg; 136 137 INSIST(clist == NULL); 138 INSIST(librpz == NULL); 139 INSIST(librpz_handle == NULL); 140 141 /* 142 * Notice if librpz is available. 143 */ 144 librpz = librpz_lib_open(&librpz_lib_open_emsg, &librpz_handle, 145 DNSRPS_LIBRPZ_PATH); 146 /* 147 * Stop now without complaining if librpz is not available. 148 * Complain later if and when librpz is needed for a view with 149 * "dnsrps-enable yes" (including the default view). 150 */ 151 if (librpz == NULL) { 152 return (ISC_R_SUCCESS); 153 } 154 155 isc_mutex_init(&dnsrps_mutex); 156 157 librpz->set_log(dnsrps_log_fnc, NULL); 158 159 clist = librpz->clist_create(&emsg, dnsrps_lock, dnsrps_unlock, 160 dnsrps_mutex_destroy, &dnsrps_mutex, 161 dns_lctx); 162 if (clist == NULL) { 163 isc_log_write(dns_lctx, DNS_LOGCATEGORY_RPZ, 164 DNS_LOGMODULE_RBTDB, DNS_RPZ_ERROR_LEVEL, 165 "dnsrps: %s", emsg.c); 166 return (ISC_R_NOMEMORY); 167 } 168 return (ISC_R_SUCCESS); 169} 170 171/* 172 * Stop dnsrps for the entire server. 173 * This is not thread safe. 174 */ 175void 176dns_dnsrps_server_destroy(void) { 177 if (clist != NULL) { 178 librpz->clist_detach(&clist); 179 } 180 181#ifdef LIBRPZ_USE_DLOPEN 182 if (librpz != NULL) { 183 INSIST(librpz_handle != NULL); 184 if (dlclose(librpz_handle) != 0) { 185 isc_log_write(dns_lctx, DNS_LOGCATEGORY_RPZ, 186 DNS_LOGMODULE_RBTDB, DNS_RPZ_ERROR_LEVEL, 187 "dnsrps: dlclose(): %s", dlerror()); 188 } 189 librpz_handle = NULL; 190 } 191#endif /* ifdef LIBRPZ_USE_DLOPEN */ 192} 193 194/* 195 * Ready dnsrps for a view. 196 */ 197isc_result_t 198dns_dnsrps_view_init(dns_rpz_zones_t *new, char *rps_cstr) { 199 librpz_emsg_t emsg; 200 201 isc_log_write(dns_lctx, DNS_LOGCATEGORY_RPZ, DNS_LOGMODULE_RBTDB, 202 DNS_RPZ_DEBUG_LEVEL3, "dnsrps configuration \"%s\"", 203 rps_cstr); 204 205 new->rps_client = librpz->client_create(&emsg, clist, rps_cstr, false); 206 if (new->rps_client == NULL) { 207 isc_log_write(dns_lctx, DNS_LOGCATEGORY_RPZ, 208 DNS_LOGMODULE_RBTDB, DNS_RPZ_ERROR_LEVEL, 209 "librpz->client_create(): %s", emsg.c); 210 new->p.dnsrps_enabled = false; 211 return (ISC_R_FAILURE); 212 } 213 214 new->p.dnsrps_enabled = true; 215 return (ISC_R_SUCCESS); 216} 217 218/* 219 * Connect to and start the dnsrps daemon, dnsrpzd. 220 */ 221isc_result_t 222dns_dnsrps_connect(dns_rpz_zones_t *rpzs) { 223 librpz_emsg_t emsg; 224 225 if (rpzs == NULL || !rpzs->p.dnsrps_enabled) { 226 return (ISC_R_SUCCESS); 227 } 228 229 /* 230 * Fail only if we failed to link to librpz. 231 */ 232 if (librpz == NULL) { 233 isc_log_write(dns_lctx, DNS_LOGCATEGORY_RPZ, 234 DNS_LOGMODULE_RBTDB, DNS_RPZ_ERROR_LEVEL, 235 "librpz->connect(): %s", librpz_lib_open_emsg.c); 236 return (ISC_R_FAILURE); 237 } 238 239 if (!librpz->connect(&emsg, rpzs->rps_client, true)) { 240 isc_log_write(dns_lctx, DNS_LOGCATEGORY_RPZ, 241 DNS_LOGMODULE_RBTDB, DNS_RPZ_ERROR_LEVEL, 242 "librpz->connect(): %s", emsg.c); 243 return (ISC_R_SUCCESS); 244 } 245 246 isc_log_write(dns_lctx, DNS_LOGCATEGORY_RPZ, DNS_LOGMODULE_RBTDB, 247 DNS_RPZ_INFO_LEVEL, "dnsrps: librpz version %s", 248 librpz->version); 249 250 return (ISC_R_SUCCESS); 251} 252 253/* 254 * Get ready to try RPZ rewriting. 255 */ 256isc_result_t 257dns_dnsrps_rewrite_init(librpz_emsg_t *emsg, dns_rpz_st_t *st, 258 dns_rpz_zones_t *rpzs, const dns_name_t *qname, 259 isc_mem_t *mctx, bool have_rd) { 260 rpsdb_t *rpsdb; 261 262 rpsdb = isc_mem_get(mctx, sizeof(*rpsdb)); 263 memset(rpsdb, 0, sizeof(*rpsdb)); 264 265 if (!librpz->rsp_create(emsg, &rpsdb->rsp, NULL, rpzs->rps_client, 266 have_rd, false)) 267 { 268 isc_mem_put(mctx, rpsdb, sizeof(*rpsdb)); 269 return (DNS_R_SERVFAIL); 270 } 271 if (rpsdb->rsp == NULL) { 272 isc_mem_put(mctx, rpsdb, sizeof(*rpsdb)); 273 return (DNS_R_DISALLOWED); 274 } 275 276 rpsdb->common.magic = DNS_DB_MAGIC; 277 rpsdb->common.impmagic = RPSDB_MAGIC; 278 rpsdb->common.methods = &rpsdb_db_methods; 279 rpsdb->common.rdclass = dns_rdataclass_in; 280 dns_name_init(&rpsdb->common.origin, NULL); 281 isc_mem_attach(mctx, &rpsdb->common.mctx); 282 283 rpsdb->ref_cnt = 1; 284 rpsdb->qname = qname; 285 286 st->rpsdb = &rpsdb->common; 287 return (ISC_R_SUCCESS); 288} 289 290/* 291 * Convert a dnsrps policy to a classic BIND9 RPZ policy. 292 */ 293dns_rpz_policy_t 294dns_dnsrps_2policy(librpz_policy_t rps_policy) { 295 switch (rps_policy) { 296 case LIBRPZ_POLICY_UNDEFINED: 297 return (DNS_RPZ_POLICY_MISS); 298 case LIBRPZ_POLICY_PASSTHRU: 299 return (DNS_RPZ_POLICY_PASSTHRU); 300 case LIBRPZ_POLICY_DROP: 301 return (DNS_RPZ_POLICY_DROP); 302 case LIBRPZ_POLICY_TCP_ONLY: 303 return (DNS_RPZ_POLICY_TCP_ONLY); 304 case LIBRPZ_POLICY_NXDOMAIN: 305 return (DNS_RPZ_POLICY_NXDOMAIN); 306 case LIBRPZ_POLICY_NODATA: 307 return (DNS_RPZ_POLICY_NODATA); 308 case LIBRPZ_POLICY_RECORD: 309 case LIBRPZ_POLICY_CNAME: 310 return (DNS_RPZ_POLICY_RECORD); 311 312 case LIBRPZ_POLICY_DELETED: 313 case LIBRPZ_POLICY_GIVEN: 314 case LIBRPZ_POLICY_DISABLED: 315 default: 316 UNREACHABLE(); 317 } 318} 319 320/* 321 * Convert a dnsrps trigger to a classic BIND9 RPZ rewrite or trigger type. 322 */ 323dns_rpz_type_t 324dns_dnsrps_trig2type(librpz_trig_t trig) { 325 switch (trig) { 326 case LIBRPZ_TRIG_BAD: 327 default: 328 return (DNS_RPZ_TYPE_BAD); 329 case LIBRPZ_TRIG_CLIENT_IP: 330 return (DNS_RPZ_TYPE_CLIENT_IP); 331 case LIBRPZ_TRIG_QNAME: 332 return (DNS_RPZ_TYPE_QNAME); 333 case LIBRPZ_TRIG_IP: 334 return (DNS_RPZ_TYPE_IP); 335 case LIBRPZ_TRIG_NSDNAME: 336 return (DNS_RPZ_TYPE_NSDNAME); 337 case LIBRPZ_TRIG_NSIP: 338 return (DNS_RPZ_TYPE_NSIP); 339 } 340} 341 342/* 343 * Convert a classic BIND9 RPZ rewrite or trigger type to a librpz trigger type. 344 */ 345librpz_trig_t 346dns_dnsrps_type2trig(dns_rpz_type_t type) { 347 switch (type) { 348 case DNS_RPZ_TYPE_BAD: 349 default: 350 return (LIBRPZ_TRIG_BAD); 351 case DNS_RPZ_TYPE_CLIENT_IP: 352 return (LIBRPZ_TRIG_CLIENT_IP); 353 case DNS_RPZ_TYPE_QNAME: 354 return (LIBRPZ_TRIG_QNAME); 355 case DNS_RPZ_TYPE_IP: 356 return (LIBRPZ_TRIG_IP); 357 case DNS_RPZ_TYPE_NSDNAME: 358 return (LIBRPZ_TRIG_NSDNAME); 359 case DNS_RPZ_TYPE_NSIP: 360 return (LIBRPZ_TRIG_NSIP); 361 } 362} 363 364static void 365rpsdb_attach(dns_db_t *source, dns_db_t **targetp) { 366 rpsdb_t *rpsdb = (rpsdb_t *)source; 367 368 REQUIRE(VALID_RPSDB(rpsdb)); 369 370 /* 371 * Use a simple count because only one thread uses any single rpsdb_t 372 */ 373 ++rpsdb->ref_cnt; 374 *targetp = source; 375} 376 377static void 378rpsdb_detach(dns_db_t **dbp) { 379 rpsdb_t *rpsdb = (rpsdb_t *)*dbp; 380 381 REQUIRE(VALID_RPSDB(rpsdb)); 382 REQUIRE(rpsdb->ref_cnt > 0); 383 384 *dbp = NULL; 385 386 /* 387 * Simple count because only one thread uses a rpsdb_t. 388 */ 389 if (--rpsdb->ref_cnt != 0) { 390 return; 391 } 392 393 librpz->rsp_detach(&rpsdb->rsp); 394 rpsdb->common.impmagic = 0; 395 isc_mem_putanddetach(&rpsdb->common.mctx, rpsdb, sizeof(*rpsdb)); 396} 397 398static void 399rpsdb_attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) { 400 rpsdb_t *rpsdb = (rpsdb_t *)db; 401 402 REQUIRE(VALID_RPSDB(rpsdb)); 403 REQUIRE(targetp != NULL && *targetp == NULL); 404 REQUIRE(source == &rpsdb->origin_node || source == &rpsdb->data_node); 405 406 /* 407 * Simple count because only one thread uses a rpsdb_t. 408 */ 409 ++rpsdb->ref_cnt; 410 *targetp = source; 411} 412 413static void 414rpsdb_detachnode(dns_db_t *db, dns_dbnode_t **targetp) { 415 rpsdb_t *rpsdb = (rpsdb_t *)db; 416 417 REQUIRE(VALID_RPSDB(rpsdb)); 418 REQUIRE(*targetp == &rpsdb->origin_node || 419 *targetp == &rpsdb->data_node); 420 421 *targetp = NULL; 422 rpsdb_detach(&db); 423} 424 425static isc_result_t 426rpsdb_findnode(dns_db_t *db, const dns_name_t *name, bool create, 427 dns_dbnode_t **nodep) { 428 rpsdb_t *rpsdb = (rpsdb_t *)db; 429 dns_db_t *dbp; 430 431 REQUIRE(VALID_RPSDB(rpsdb)); 432 REQUIRE(nodep != NULL && *nodep == NULL); 433 REQUIRE(!create); 434 435 /* 436 * A fake/shim rpsdb has two nodes. 437 * One is the origin to support query_addsoa() in bin/named/query.c. 438 * The other contains rewritten RRs. 439 */ 440 if (dns_name_equal(name, &db->origin)) { 441 *nodep = &rpsdb->origin_node; 442 } else { 443 *nodep = &rpsdb->data_node; 444 } 445 dbp = NULL; 446 rpsdb_attach(db, &dbp); 447 448 return (ISC_R_SUCCESS); 449} 450 451static void 452rpsdb_bind_rdataset(dns_rdataset_t *rdataset, uint count, librpz_idx_t next_rr, 453 dns_rdatatype_t type, uint16_t class, uint32_t ttl, 454 rpsdb_t *rpsdb) { 455 dns_db_t *dbp; 456 457 INSIST(rdataset->methods == NULL); /* We must be disassociated. */ 458 REQUIRE(type != dns_rdatatype_none); 459 460 rdataset->methods = &rpsdb_rdataset_methods; 461 rdataset->rdclass = class; 462 rdataset->type = type; 463 rdataset->ttl = ttl; 464 dbp = NULL; 465 dns_db_attach(&rpsdb->common, &dbp); 466 RD_DB(rdataset) = dbp; 467 RD_COUNT(rdataset) = count; 468 RD_NEXT_RR(rdataset) = next_rr; 469 RD_CUR_RR(rdataset) = NULL; 470} 471 472static isc_result_t 473rpsdb_bind_soa(dns_rdataset_t *rdataset, rpsdb_t *rpsdb) { 474 uint32_t ttl; 475 librpz_emsg_t emsg; 476 477 if (!librpz->rsp_soa(&emsg, &ttl, NULL, NULL, &rpsdb->result, 478 rpsdb->rsp)) 479 { 480 librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c); 481 return (DNS_R_SERVFAIL); 482 } 483 rpsdb_bind_rdataset(rdataset, 1, LIBRPZ_IDX_BAD, dns_rdatatype_soa, 484 dns_rdataclass_in, ttl, rpsdb); 485 return (ISC_R_SUCCESS); 486} 487 488/* 489 * Forge an rdataset of the desired type from a librpz result. 490 * This is written for simplicity instead of speed, because RPZ rewriting 491 * should be rare compared to normal BIND operations. 492 */ 493static isc_result_t 494rpsdb_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, 495 dns_rdatatype_t type, dns_rdatatype_t covers, 496 isc_stdtime_t now, dns_rdataset_t *rdataset, 497 dns_rdataset_t *sigrdataset) { 498 rpsdb_t *rpsdb = (rpsdb_t *)db; 499 dns_rdatatype_t foundtype; 500 dns_rdataclass_t class; 501 uint32_t ttl; 502 uint count; 503 librpz_emsg_t emsg; 504 505 UNUSED(version); 506 UNUSED(covers); 507 UNUSED(now); 508 UNUSED(sigrdataset); 509 510 REQUIRE(VALID_RPSDB(rpsdb)); 511 512 if (node == &rpsdb->origin_node) { 513 if (type == dns_rdatatype_any) { 514 return (ISC_R_SUCCESS); 515 } 516 if (type == dns_rdatatype_soa) { 517 return (rpsdb_bind_soa(rdataset, rpsdb)); 518 } 519 return (DNS_R_NXRRSET); 520 } 521 522 REQUIRE(node == &rpsdb->data_node); 523 524 switch (rpsdb->result.policy) { 525 case LIBRPZ_POLICY_UNDEFINED: 526 case LIBRPZ_POLICY_DELETED: 527 case LIBRPZ_POLICY_PASSTHRU: 528 case LIBRPZ_POLICY_DROP: 529 case LIBRPZ_POLICY_TCP_ONLY: 530 case LIBRPZ_POLICY_GIVEN: 531 case LIBRPZ_POLICY_DISABLED: 532 default: 533 librpz->log(LIBRPZ_LOG_ERROR, NULL, 534 "impossible dnsrps policy %d at %s:%d", 535 rpsdb->result.policy, __FILE__, __LINE__); 536 return (DNS_R_SERVFAIL); 537 538 case LIBRPZ_POLICY_NXDOMAIN: 539 return (DNS_R_NXDOMAIN); 540 541 case LIBRPZ_POLICY_NODATA: 542 return (DNS_R_NXRRSET); 543 544 case LIBRPZ_POLICY_RECORD: 545 case LIBRPZ_POLICY_CNAME: 546 break; 547 } 548 549 if (type == dns_rdatatype_soa) { 550 return (rpsdb_bind_soa(rdataset, rpsdb)); 551 } 552 553 /* 554 * There is little to do for an ANY query. 555 */ 556 if (type == dns_rdatatype_any) { 557 return (ISC_R_SUCCESS); 558 } 559 560 /* 561 * Reset to the start of the RRs. 562 * This function is only used after a policy has been chosen, 563 * and so without caring whether it is after recursion. 564 */ 565 if (!librpz->rsp_result(&emsg, &rpsdb->result, true, rpsdb->rsp)) { 566 librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c); 567 return (DNS_R_SERVFAIL); 568 } 569 if (!librpz->rsp_rr(&emsg, &foundtype, &class, &ttl, NULL, 570 &rpsdb->result, rpsdb->qname->ndata, 571 rpsdb->qname->length, rpsdb->rsp)) 572 { 573 librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c); 574 return (DNS_R_SERVFAIL); 575 } 576 REQUIRE(foundtype != dns_rdatatype_none); 577 578 /* 579 * Ho many of the target RR type are available? 580 */ 581 count = 0; 582 do { 583 if (type == foundtype || type == dns_rdatatype_any) { 584 ++count; 585 } 586 587 if (!librpz->rsp_rr(&emsg, &foundtype, NULL, NULL, NULL, 588 &rpsdb->result, rpsdb->qname->ndata, 589 rpsdb->qname->length, rpsdb->rsp)) 590 { 591 librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c); 592 return (DNS_R_SERVFAIL); 593 } 594 } while (foundtype != dns_rdatatype_none); 595 if (count == 0) { 596 return (DNS_R_NXRRSET); 597 } 598 rpsdb_bind_rdataset(rdataset, count, rpsdb->result.next_rr, type, class, 599 ttl, rpsdb); 600 return (ISC_R_SUCCESS); 601} 602 603static isc_result_t 604rpsdb_finddb(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, 605 dns_rdatatype_t type, unsigned int options, isc_stdtime_t now, 606 dns_dbnode_t **nodep, dns_name_t *foundname, 607 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) { 608 dns_dbnode_t *node; 609 610 UNUSED(version); 611 UNUSED(options); 612 UNUSED(now); 613 UNUSED(sigrdataset); 614 615 if (nodep == NULL) { 616 node = NULL; 617 nodep = &node; 618 } 619 rpsdb_findnode(db, name, false, nodep); 620 dns_name_copy(name, foundname); 621 return (rpsdb_findrdataset(db, *nodep, NULL, type, 0, 0, rdataset, 622 sigrdataset)); 623} 624 625static isc_result_t 626rpsdb_allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, 627 unsigned int options, isc_stdtime_t now, 628 dns_rdatasetiter_t **iteratorp) { 629 rpsdb_t *rpsdb = (rpsdb_t *)db; 630 rpsdb_rdatasetiter_t *rpsdb_iter; 631 632 UNUSED(version); 633 UNUSED(now); 634 635 REQUIRE(VALID_RPSDB(rpsdb)); 636 REQUIRE(node == &rpsdb->origin_node || node == &rpsdb->data_node); 637 638 rpsdb_iter = isc_mem_get(rpsdb->common.mctx, sizeof(*rpsdb_iter)); 639 640 memset(rpsdb_iter, 0, sizeof(*rpsdb_iter)); 641 rpsdb_iter->common.magic = DNS_RDATASETITER_MAGIC; 642 rpsdb_iter->common.methods = &rpsdb_rdatasetiter_methods; 643 rpsdb_iter->common.db = db; 644 rpsdb_iter->common.options = options; 645 rpsdb_attachnode(db, node, &rpsdb_iter->common.node); 646 647 *iteratorp = &rpsdb_iter->common; 648 649 return (ISC_R_SUCCESS); 650} 651 652static bool 653rpsdb_issecure(dns_db_t *db) { 654 UNUSED(db); 655 656 return (false); 657} 658 659static isc_result_t 660rpsdb_getoriginnode(dns_db_t *db, dns_dbnode_t **nodep) { 661 rpsdb_t *rpsdb = (rpsdb_t *)db; 662 663 REQUIRE(VALID_RPSDB(rpsdb)); 664 REQUIRE(nodep != NULL && *nodep == NULL); 665 666 rpsdb_attachnode(db, &rpsdb->origin_node, nodep); 667 return (ISC_R_SUCCESS); 668} 669 670static void 671rpsdb_rdataset_disassociate(dns_rdataset_t *rdataset) { 672 dns_db_t *db; 673 674 /* 675 * Detach the last RR delivered. 676 */ 677 if (RD_CUR_RR(rdataset) != NULL) { 678 free(RD_CUR_RR(rdataset)); 679 RD_CUR_RR(rdataset) = NULL; 680 } 681 682 db = RD_DB(rdataset); 683 RD_DB(rdataset) = NULL; 684 dns_db_detach(&db); 685} 686 687static isc_result_t 688rpsdb_rdataset_next(dns_rdataset_t *rdataset) { 689 rpsdb_t *rpsdb; 690 uint16_t type; 691 dns_rdataclass_t class; 692 librpz_rr_t *rr; 693 librpz_emsg_t emsg; 694 695 rpsdb = RD_DB(rdataset); 696 697 /* 698 * Detach the previous RR. 699 */ 700 if (RD_CUR_RR(rdataset) != NULL) { 701 free(RD_CUR_RR(rdataset)); 702 RD_CUR_RR(rdataset) = NULL; 703 } 704 705 /* 706 * Get the next RR of the specified type. 707 * SOAs differ. 708 */ 709 if (rdataset->type == dns_rdatatype_soa) { 710 if (RD_NEXT_RR(rdataset) == LIBRPZ_IDX_NULL) { 711 return (ISC_R_NOMORE); 712 } 713 RD_NEXT_RR(rdataset) = LIBRPZ_IDX_NULL; 714 if (!librpz->rsp_soa(&emsg, NULL, &rr, NULL, &rpsdb->result, 715 rpsdb->rsp)) 716 { 717 librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c); 718 return (DNS_R_SERVFAIL); 719 } 720 RD_CUR_RR(rdataset) = rr; 721 return (ISC_R_SUCCESS); 722 } 723 724 rpsdb->result.next_rr = RD_NEXT_RR(rdataset); 725 for (;;) { 726 if (!librpz->rsp_rr(&emsg, &type, &class, NULL, &rr, 727 &rpsdb->result, rpsdb->qname->ndata, 728 rpsdb->qname->length, rpsdb->rsp)) 729 { 730 librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c); 731 return (DNS_R_SERVFAIL); 732 } 733 if (rdataset->type == type && rdataset->rdclass == class) { 734 RD_CUR_RR(rdataset) = rr; 735 RD_NEXT_RR(rdataset) = rpsdb->result.next_rr; 736 return (ISC_R_SUCCESS); 737 } 738 if (type == dns_rdatatype_none) { 739 return (ISC_R_NOMORE); 740 } 741 free(rr); 742 } 743} 744 745static isc_result_t 746rpsdb_rdataset_first(dns_rdataset_t *rdataset) { 747 rpsdb_t *rpsdb; 748 librpz_emsg_t emsg; 749 750 rpsdb = RD_DB(rdataset); 751 REQUIRE(VALID_RPSDB(rpsdb)); 752 753 if (RD_CUR_RR(rdataset) != NULL) { 754 free(RD_CUR_RR(rdataset)); 755 RD_CUR_RR(rdataset) = NULL; 756 } 757 758 if (!librpz->rsp_result(&emsg, &rpsdb->result, true, rpsdb->rsp)) { 759 librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c); 760 return (DNS_R_SERVFAIL); 761 } 762 if (rdataset->type == dns_rdatatype_soa) { 763 RD_NEXT_RR(rdataset) = LIBRPZ_IDX_BAD; 764 } else { 765 RD_NEXT_RR(rdataset) = rpsdb->result.next_rr; 766 } 767 768 return (rpsdb_rdataset_next(rdataset)); 769} 770 771static void 772rpsdb_rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) { 773 rpsdb_t *rpsdb; 774 librpz_rr_t *rr; 775 isc_region_t r; 776 777 rpsdb = RD_DB(rdataset); 778 REQUIRE(VALID_RPSDB(rpsdb)); 779 rr = RD_CUR_RR(rdataset); 780 REQUIRE(rr != NULL); 781 782 r.length = ntohs(rr->rdlength); 783 r.base = rr->rdata; 784 dns_rdata_fromregion(rdata, ntohs(rr->class), ntohs(rr->type), &r); 785} 786 787static void 788rpsdb_rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) { 789 rpsdb_t *rpsdb; 790 dns_db_t *dbp; 791 792 INSIST(!ISC_LINK_LINKED(target, link)); 793 *target = *source; 794 ISC_LINK_INIT(target, link); 795 rpsdb = RD_DB(source); 796 REQUIRE(VALID_RPSDB(rpsdb)); 797 dbp = NULL; 798 dns_db_attach(&rpsdb->common, &dbp); 799 RD_DB(target) = dbp; 800 RD_CUR_RR(target) = NULL; 801 RD_NEXT_RR(target) = LIBRPZ_IDX_NULL; 802} 803 804static unsigned int 805rpsdb_rdataset_count(dns_rdataset_t *rdataset) { 806 rpsdb_t *rpsdb; 807 808 rpsdb = RD_DB(rdataset); 809 REQUIRE(VALID_RPSDB(rpsdb)); 810 811 return (RD_COUNT(rdataset)); 812} 813 814static void 815rpsdb_rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) { 816 rpsdb_t *rpsdb; 817 dns_rdatasetiter_t *iterator; 818 isc_mem_t *mctx; 819 820 iterator = *iteratorp; 821 *iteratorp = NULL; 822 rpsdb = (rpsdb_t *)iterator->db; 823 REQUIRE(VALID_RPSDB(rpsdb)); 824 825 mctx = iterator->db->mctx; 826 dns_db_detachnode(iterator->db, &iterator->node); 827 isc_mem_put(mctx, iterator, sizeof(rpsdb_rdatasetiter_t)); 828} 829 830static isc_result_t 831rpsdb_rdatasetiter_next(dns_rdatasetiter_t *iter) { 832 rpsdb_t *rpsdb; 833 rpsdb_rdatasetiter_t *rpsdb_iter; 834 dns_rdatatype_t next_type, type; 835 dns_rdataclass_t next_class, class; 836 uint32_t ttl; 837 librpz_emsg_t emsg; 838 839 rpsdb = (rpsdb_t *)iter->db; 840 REQUIRE(VALID_RPSDB(rpsdb)); 841 rpsdb_iter = (rpsdb_rdatasetiter_t *)iter; 842 843 /* 844 * This function is only used after a policy has been chosen, 845 * and so without caring whether it is after recursion. 846 */ 847 if (!librpz->rsp_result(&emsg, &rpsdb->result, true, rpsdb->rsp)) { 848 librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c); 849 return (DNS_R_SERVFAIL); 850 } 851 /* 852 * Find the next class and type after the current class and type 853 * among the RRs in current result. 854 * As a side effect, count the number of those RRs. 855 */ 856 rpsdb_iter->count = 0; 857 next_class = dns_rdataclass_reserved0; 858 next_type = dns_rdatatype_none; 859 for (;;) { 860 if (!librpz->rsp_rr(&emsg, &type, &class, &ttl, NULL, 861 &rpsdb->result, rpsdb->qname->ndata, 862 rpsdb->qname->length, rpsdb->rsp)) 863 { 864 librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c); 865 return (DNS_R_SERVFAIL); 866 } 867 if (type == dns_rdatatype_none) { 868 if (next_type == dns_rdatatype_none) { 869 return (ISC_R_NOMORE); 870 } 871 rpsdb_iter->type = next_type; 872 rpsdb_iter->class = next_class; 873 return (ISC_R_SUCCESS); 874 } 875 /* 876 * Skip RRs with the current class and type or before. 877 */ 878 if (rpsdb_iter->class > class || 879 (rpsdb_iter->class = class && rpsdb_iter->type >= type)) 880 { 881 continue; 882 } 883 if (next_type == dns_rdatatype_none || next_class > class || 884 (next_class == class && next_type > type)) 885 { 886 /* 887 * This is the first of a subsequent class and type. 888 */ 889 next_type = type; 890 next_class = class; 891 rpsdb_iter->ttl = ttl; 892 rpsdb_iter->count = 1; 893 rpsdb_iter->next_rr = rpsdb->result.next_rr; 894 } else if (next_type == type && next_class == class) { 895 ++rpsdb_iter->count; 896 } 897 } 898} 899 900static isc_result_t 901rpsdb_rdatasetiter_first(dns_rdatasetiter_t *iterator) { 902 rpsdb_t *rpsdb; 903 rpsdb_rdatasetiter_t *rpsdb_iter; 904 905 rpsdb = (rpsdb_t *)iterator->db; 906 REQUIRE(VALID_RPSDB(rpsdb)); 907 rpsdb_iter = (rpsdb_rdatasetiter_t *)iterator; 908 909 rpsdb_iter->type = dns_rdatatype_none; 910 rpsdb_iter->class = dns_rdataclass_reserved0; 911 return (rpsdb_rdatasetiter_next(iterator)); 912} 913 914static void 915rpsdb_rdatasetiter_current(dns_rdatasetiter_t *iterator, 916 dns_rdataset_t *rdataset) { 917 rpsdb_t *rpsdb; 918 rpsdb_rdatasetiter_t *rpsdb_iter; 919 920 rpsdb = (rpsdb_t *)iterator->db; 921 REQUIRE(VALID_RPSDB(rpsdb)); 922 rpsdb_iter = (rpsdb_rdatasetiter_t *)iterator; 923 REQUIRE(rpsdb_iter->type != dns_rdatatype_none); 924 925 rpsdb_bind_rdataset(rdataset, rpsdb_iter->count, rpsdb_iter->next_rr, 926 rpsdb_iter->type, rpsdb_iter->class, 927 rpsdb_iter->ttl, rpsdb); 928} 929 930static dns_dbmethods_t rpsdb_db_methods = { 931 rpsdb_attach, 932 rpsdb_detach, 933 NULL, /* beginload */ 934 NULL, /* endload */ 935 NULL, /* dump */ 936 NULL, /* currentversion */ 937 NULL, /* newversion */ 938 NULL, /* attachversion */ 939 NULL, /* closeversion */ 940 rpsdb_findnode, 941 rpsdb_finddb, 942 NULL, /* findzonecut*/ 943 rpsdb_attachnode, 944 rpsdb_detachnode, 945 NULL, /* expirenode */ 946 NULL, /* printnode */ 947 NULL, /* createiterator */ 948 rpsdb_findrdataset, 949 rpsdb_allrdatasets, 950 NULL, /* addrdataset */ 951 NULL, /* subtractrdataset */ 952 NULL, /* deleterdataset */ 953 rpsdb_issecure, 954 NULL, /* nodecount */ 955 NULL, /* ispersistent */ 956 NULL, /* overmem */ 957 NULL, /* settask */ 958 rpsdb_getoriginnode, 959 NULL, /* transfernode */ 960 NULL, /* getnsec3parameters */ 961 NULL, /* findnsec3node */ 962 NULL, /* setsigningtime */ 963 NULL, /* getsigningtime */ 964 NULL, /* resigned */ 965 NULL, /* isdnssec */ 966 NULL, /* getrrsetstats */ 967 NULL, /* rpz_attach */ 968 NULL, /* rpz_ready */ 969 NULL, /* findnodeext */ 970 NULL, /* findext */ 971 NULL, /* setcachestats */ 972 NULL, /* hashsize */ 973 NULL, /* nodefullname */ 974 NULL, /* getsize */ 975 NULL, /* setservestalettl */ 976 NULL, /* getservestalettl */ 977 NULL, /* setservestalerefresh */ 978 NULL, /* getservestalerefresh */ 979 NULL, /* setgluecachestats */ 980}; 981 982static dns_rdatasetmethods_t rpsdb_rdataset_methods = { 983 rpsdb_rdataset_disassociate, 984 rpsdb_rdataset_first, 985 rpsdb_rdataset_next, 986 rpsdb_rdataset_current, 987 rpsdb_rdataset_clone, 988 rpsdb_rdataset_count, 989 NULL, 990 NULL, 991 NULL, 992 NULL, 993 NULL, 994 NULL, 995 NULL, 996 NULL, 997 NULL, 998 NULL 999}; 1000 1001static dns_rdatasetitermethods_t rpsdb_rdatasetiter_methods = { 1002 rpsdb_rdatasetiter_destroy, rpsdb_rdatasetiter_first, 1003 rpsdb_rdatasetiter_next, rpsdb_rdatasetiter_current 1004}; 1005 1006#endif /* USE_DNSRPS */ 1007