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