Home | History | Annotate | Line # | Download | only in dns
dnsrps.c revision 1.1.4.2
      1 /*	$NetBSD: dnsrps.c,v 1.1.4.2 2024/02/29 11:38:38 martin 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 
     37 librpz_t *librpz;
     38 librpz_emsg_t librpz_lib_open_emsg;
     39 static 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 
     49 typedef 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 
     58 static dns_dbmethods_t rpsdb_db_methods;
     59 static dns_rdatasetmethods_t rpsdb_rdataset_methods;
     60 static dns_rdatasetitermethods_t rpsdb_rdatasetiter_methods;
     61 
     62 static librpz_clist_t *clist;
     63 
     64 static isc_mutex_t dnsrps_mutex;
     65 
     66 static void
     67 dnsrps_lock(void *mutex0) {
     68 	isc_mutex_t *mutex = mutex0;
     69 
     70 	LOCK(mutex);
     71 }
     72 
     73 static void
     74 dnsrps_unlock(void *mutex0) {
     75 	isc_mutex_t *mutex = mutex0;
     76 
     77 	UNLOCK(mutex);
     78 }
     79 
     80 static void
     81 dnsrps_mutex_destroy(void *mutex0) {
     82 	isc_mutex_t *mutex = mutex0;
     83 
     84 	isc_mutex_destroy(mutex);
     85 }
     86 
     87 static void
     88 dnsrps_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  */
    132 isc_result_t
    133 dns_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  */
    174 void
    175 dns_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  */
    196 isc_result_t
    197 dns_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  */
    220 isc_result_t
    221 dns_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  */
    255 isc_result_t
    256 dns_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  */
    292 dns_rpz_policy_t
    293 dns_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  */
    322 dns_rpz_type_t
    323 dns_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  */
    344 librpz_trig_t
    345 dns_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 
    363 static void
    364 rpsdb_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 
    376 static void
    377 rpsdb_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 
    397 static void
    398 rpsdb_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 
    412 static void
    413 rpsdb_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 
    424 static isc_result_t
    425 rpsdb_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 
    450 static void
    451 rpsdb_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 
    471 static isc_result_t
    472 rpsdb_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 	{
    479 		librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c);
    480 		return (DNS_R_SERVFAIL);
    481 	}
    482 	rpsdb_bind_rdataset(rdataset, 1, LIBRPZ_IDX_BAD, dns_rdatatype_soa,
    483 			    dns_rdataclass_in, ttl, rpsdb);
    484 	return (ISC_R_SUCCESS);
    485 }
    486 
    487 /*
    488  * Forge an rdataset of the desired type from a librpz result.
    489  * This is written for simplicity instead of speed, because RPZ rewriting
    490  * should be rare compared to normal BIND operations.
    491  */
    492 static isc_result_t
    493 rpsdb_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
    494 		   dns_rdatatype_t type, dns_rdatatype_t covers,
    495 		   isc_stdtime_t now, dns_rdataset_t *rdataset,
    496 		   dns_rdataset_t *sigrdataset) {
    497 	rpsdb_t *rpsdb = (rpsdb_t *)db;
    498 	dns_rdatatype_t foundtype;
    499 	dns_rdataclass_t class;
    500 	uint32_t ttl;
    501 	uint count;
    502 	librpz_emsg_t emsg;
    503 
    504 	UNUSED(version);
    505 	UNUSED(covers);
    506 	UNUSED(now);
    507 	UNUSED(sigrdataset);
    508 
    509 	REQUIRE(VALID_RPSDB(rpsdb));
    510 
    511 	if (node == &rpsdb->origin_node) {
    512 		if (type == dns_rdatatype_any) {
    513 			return (ISC_R_SUCCESS);
    514 		}
    515 		if (type == dns_rdatatype_soa) {
    516 			return (rpsdb_bind_soa(rdataset, rpsdb));
    517 		}
    518 		return (DNS_R_NXRRSET);
    519 	}
    520 
    521 	REQUIRE(node == &rpsdb->data_node);
    522 
    523 	switch (rpsdb->result.policy) {
    524 	case LIBRPZ_POLICY_UNDEFINED:
    525 	case LIBRPZ_POLICY_DELETED:
    526 	case LIBRPZ_POLICY_PASSTHRU:
    527 	case LIBRPZ_POLICY_DROP:
    528 	case LIBRPZ_POLICY_TCP_ONLY:
    529 	case LIBRPZ_POLICY_GIVEN:
    530 	case LIBRPZ_POLICY_DISABLED:
    531 	default:
    532 		librpz->log(LIBRPZ_LOG_ERROR, NULL,
    533 			    "impossible dnsrps policy %d at %s:%d",
    534 			    rpsdb->result.policy, __FILE__, __LINE__);
    535 		return (DNS_R_SERVFAIL);
    536 
    537 	case LIBRPZ_POLICY_NXDOMAIN:
    538 		return (DNS_R_NXDOMAIN);
    539 
    540 	case LIBRPZ_POLICY_NODATA:
    541 		return (DNS_R_NXRRSET);
    542 
    543 	case LIBRPZ_POLICY_RECORD:
    544 	case LIBRPZ_POLICY_CNAME:
    545 		break;
    546 	}
    547 
    548 	if (type == dns_rdatatype_soa) {
    549 		return (rpsdb_bind_soa(rdataset, rpsdb));
    550 	}
    551 
    552 	/*
    553 	 * There is little to do for an ANY query.
    554 	 */
    555 	if (type == dns_rdatatype_any) {
    556 		return (ISC_R_SUCCESS);
    557 	}
    558 
    559 	/*
    560 	 * Reset to the start of the RRs.
    561 	 * This function is only used after a policy has been chosen,
    562 	 * and so without caring whether it is after recursion.
    563 	 */
    564 	if (!librpz->rsp_result(&emsg, &rpsdb->result, true, rpsdb->rsp)) {
    565 		librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c);
    566 		return (DNS_R_SERVFAIL);
    567 	}
    568 	if (!librpz->rsp_rr(&emsg, &foundtype, &class, &ttl, NULL,
    569 			    &rpsdb->result, rpsdb->qname->ndata,
    570 			    rpsdb->qname->length, rpsdb->rsp))
    571 	{
    572 		librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c);
    573 		return (DNS_R_SERVFAIL);
    574 	}
    575 	REQUIRE(foundtype != dns_rdatatype_none);
    576 
    577 	/*
    578 	 * Ho many of the target RR type are available?
    579 	 */
    580 	count = 0;
    581 	do {
    582 		if (type == foundtype || type == dns_rdatatype_any) {
    583 			++count;
    584 		}
    585 
    586 		if (!librpz->rsp_rr(&emsg, &foundtype, NULL, NULL, NULL,
    587 				    &rpsdb->result, rpsdb->qname->ndata,
    588 				    rpsdb->qname->length, rpsdb->rsp))
    589 		{
    590 			librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c);
    591 			return (DNS_R_SERVFAIL);
    592 		}
    593 	} while (foundtype != dns_rdatatype_none);
    594 	if (count == 0) {
    595 		return (DNS_R_NXRRSET);
    596 	}
    597 	rpsdb_bind_rdataset(rdataset, count, rpsdb->result.next_rr, type, class,
    598 			    ttl, rpsdb);
    599 	return (ISC_R_SUCCESS);
    600 }
    601 
    602 static isc_result_t
    603 rpsdb_finddb(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
    604 	     dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
    605 	     dns_dbnode_t **nodep, dns_name_t *foundname,
    606 	     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
    607 	dns_dbnode_t *node;
    608 
    609 	UNUSED(version);
    610 	UNUSED(options);
    611 	UNUSED(now);
    612 	UNUSED(sigrdataset);
    613 
    614 	if (nodep == NULL) {
    615 		node = NULL;
    616 		nodep = &node;
    617 	}
    618 	rpsdb_findnode(db, name, false, nodep);
    619 	dns_name_copynf(name, foundname);
    620 	return (rpsdb_findrdataset(db, *nodep, NULL, type, 0, 0, rdataset,
    621 				   sigrdataset));
    622 }
    623 
    624 static isc_result_t
    625 rpsdb_allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
    626 		   unsigned int options, isc_stdtime_t now,
    627 		   dns_rdatasetiter_t **iteratorp) {
    628 	rpsdb_t *rpsdb = (rpsdb_t *)db;
    629 	rpsdb_rdatasetiter_t *rpsdb_iter;
    630 
    631 	UNUSED(version);
    632 	UNUSED(now);
    633 
    634 	REQUIRE(VALID_RPSDB(rpsdb));
    635 	REQUIRE(node == &rpsdb->origin_node || node == &rpsdb->data_node);
    636 
    637 	rpsdb_iter = isc_mem_get(rpsdb->common.mctx, sizeof(*rpsdb_iter));
    638 
    639 	memset(rpsdb_iter, 0, sizeof(*rpsdb_iter));
    640 	rpsdb_iter->common.magic = DNS_RDATASETITER_MAGIC;
    641 	rpsdb_iter->common.methods = &rpsdb_rdatasetiter_methods;
    642 	rpsdb_iter->common.db = db;
    643 	rpsdb_iter->common.options = options;
    644 	rpsdb_attachnode(db, node, &rpsdb_iter->common.node);
    645 
    646 	*iteratorp = &rpsdb_iter->common;
    647 
    648 	return (ISC_R_SUCCESS);
    649 }
    650 
    651 static bool
    652 rpsdb_issecure(dns_db_t *db) {
    653 	UNUSED(db);
    654 
    655 	return (false);
    656 }
    657 
    658 static isc_result_t
    659 rpsdb_getoriginnode(dns_db_t *db, dns_dbnode_t **nodep) {
    660 	rpsdb_t *rpsdb = (rpsdb_t *)db;
    661 
    662 	REQUIRE(VALID_RPSDB(rpsdb));
    663 	REQUIRE(nodep != NULL && *nodep == NULL);
    664 
    665 	rpsdb_attachnode(db, &rpsdb->origin_node, nodep);
    666 	return (ISC_R_SUCCESS);
    667 }
    668 
    669 static void
    670 rpsdb_rdataset_disassociate(dns_rdataset_t *rdataset) {
    671 	dns_db_t *db;
    672 
    673 	/*
    674 	 * Detach the last RR delivered.
    675 	 */
    676 	if (RD_CUR_RR(rdataset) != NULL) {
    677 		free(RD_CUR_RR(rdataset));
    678 		RD_CUR_RR(rdataset) = NULL;
    679 	}
    680 
    681 	db = RD_DB(rdataset);
    682 	RD_DB(rdataset) = NULL;
    683 	dns_db_detach(&db);
    684 }
    685 
    686 static isc_result_t
    687 rpsdb_rdataset_next(dns_rdataset_t *rdataset) {
    688 	rpsdb_t *rpsdb;
    689 	uint16_t type;
    690 	dns_rdataclass_t class;
    691 	librpz_rr_t *rr;
    692 	librpz_emsg_t emsg;
    693 
    694 	rpsdb = RD_DB(rdataset);
    695 
    696 	/*
    697 	 * Detach the previous RR.
    698 	 */
    699 	if (RD_CUR_RR(rdataset) != NULL) {
    700 		free(RD_CUR_RR(rdataset));
    701 		RD_CUR_RR(rdataset) = NULL;
    702 	}
    703 
    704 	/*
    705 	 * Get the next RR of the specified type.
    706 	 * SOAs differ.
    707 	 */
    708 	if (rdataset->type == dns_rdatatype_soa) {
    709 		if (RD_NEXT_RR(rdataset) == LIBRPZ_IDX_NULL) {
    710 			return (ISC_R_NOMORE);
    711 		}
    712 		RD_NEXT_RR(rdataset) = LIBRPZ_IDX_NULL;
    713 		if (!librpz->rsp_soa(&emsg, NULL, &rr, NULL, &rpsdb->result,
    714 				     rpsdb->rsp))
    715 		{
    716 			librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c);
    717 			return (DNS_R_SERVFAIL);
    718 		}
    719 		RD_CUR_RR(rdataset) = rr;
    720 		return (ISC_R_SUCCESS);
    721 	}
    722 
    723 	rpsdb->result.next_rr = RD_NEXT_RR(rdataset);
    724 	for (;;) {
    725 		if (!librpz->rsp_rr(&emsg, &type, &class, NULL, &rr,
    726 				    &rpsdb->result, rpsdb->qname->ndata,
    727 				    rpsdb->qname->length, rpsdb->rsp))
    728 		{
    729 			librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c);
    730 			return (DNS_R_SERVFAIL);
    731 		}
    732 		if (rdataset->type == type && rdataset->rdclass == class) {
    733 			RD_CUR_RR(rdataset) = rr;
    734 			RD_NEXT_RR(rdataset) = rpsdb->result.next_rr;
    735 			return (ISC_R_SUCCESS);
    736 		}
    737 		if (type == dns_rdatatype_none) {
    738 			return (ISC_R_NOMORE);
    739 		}
    740 		free(rr);
    741 	}
    742 }
    743 
    744 static isc_result_t
    745 rpsdb_rdataset_first(dns_rdataset_t *rdataset) {
    746 	rpsdb_t *rpsdb;
    747 	librpz_emsg_t emsg;
    748 
    749 	rpsdb = RD_DB(rdataset);
    750 	REQUIRE(VALID_RPSDB(rpsdb));
    751 
    752 	if (RD_CUR_RR(rdataset) != NULL) {
    753 		free(RD_CUR_RR(rdataset));
    754 		RD_CUR_RR(rdataset) = NULL;
    755 	}
    756 
    757 	if (!librpz->rsp_result(&emsg, &rpsdb->result, true, rpsdb->rsp)) {
    758 		librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c);
    759 		return (DNS_R_SERVFAIL);
    760 	}
    761 	if (rdataset->type == dns_rdatatype_soa) {
    762 		RD_NEXT_RR(rdataset) = LIBRPZ_IDX_BAD;
    763 	} else {
    764 		RD_NEXT_RR(rdataset) = rpsdb->result.next_rr;
    765 	}
    766 
    767 	return (rpsdb_rdataset_next(rdataset));
    768 }
    769 
    770 static void
    771 rpsdb_rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
    772 	rpsdb_t *rpsdb;
    773 	librpz_rr_t *rr;
    774 	isc_region_t r;
    775 
    776 	rpsdb = RD_DB(rdataset);
    777 	REQUIRE(VALID_RPSDB(rpsdb));
    778 	rr = RD_CUR_RR(rdataset);
    779 	REQUIRE(rr != NULL);
    780 
    781 	r.length = ntohs(rr->rdlength);
    782 	r.base = rr->rdata;
    783 	dns_rdata_fromregion(rdata, ntohs(rr->class), ntohs(rr->type), &r);
    784 }
    785 
    786 static void
    787 rpsdb_rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
    788 	rpsdb_t *rpsdb;
    789 	dns_db_t *dbp;
    790 
    791 	INSIST(!ISC_LINK_LINKED(target, link));
    792 	*target = *source;
    793 	ISC_LINK_INIT(target, link);
    794 	rpsdb = RD_DB(source);
    795 	REQUIRE(VALID_RPSDB(rpsdb));
    796 	dbp = NULL;
    797 	dns_db_attach(&rpsdb->common, &dbp);
    798 	RD_DB(target) = dbp;
    799 	RD_CUR_RR(target) = NULL;
    800 	RD_NEXT_RR(target) = LIBRPZ_IDX_NULL;
    801 }
    802 
    803 static unsigned int
    804 rpsdb_rdataset_count(dns_rdataset_t *rdataset) {
    805 	rpsdb_t *rpsdb;
    806 
    807 	rpsdb = RD_DB(rdataset);
    808 	REQUIRE(VALID_RPSDB(rpsdb));
    809 
    810 	return (RD_COUNT(rdataset));
    811 }
    812 
    813 static void
    814 rpsdb_rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
    815 	rpsdb_t *rpsdb;
    816 	dns_rdatasetiter_t *iterator;
    817 	isc_mem_t *mctx;
    818 
    819 	iterator = *iteratorp;
    820 	*iteratorp = NULL;
    821 	rpsdb = (rpsdb_t *)iterator->db;
    822 	REQUIRE(VALID_RPSDB(rpsdb));
    823 
    824 	mctx = iterator->db->mctx;
    825 	dns_db_detachnode(iterator->db, &iterator->node);
    826 	isc_mem_put(mctx, iterator, sizeof(rpsdb_rdatasetiter_t));
    827 }
    828 
    829 static isc_result_t
    830 rpsdb_rdatasetiter_next(dns_rdatasetiter_t *iter) {
    831 	rpsdb_t *rpsdb;
    832 	rpsdb_rdatasetiter_t *rpsdb_iter;
    833 	dns_rdatatype_t next_type, type;
    834 	dns_rdataclass_t next_class, class;
    835 	uint32_t ttl;
    836 	librpz_emsg_t emsg;
    837 
    838 	rpsdb = (rpsdb_t *)iter->db;
    839 	REQUIRE(VALID_RPSDB(rpsdb));
    840 	rpsdb_iter = (rpsdb_rdatasetiter_t *)iter;
    841 
    842 	/*
    843 	 * This function is only used after a policy has been chosen,
    844 	 * and so without caring whether it is after recursion.
    845 	 */
    846 	if (!librpz->rsp_result(&emsg, &rpsdb->result, true, rpsdb->rsp)) {
    847 		librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c);
    848 		return (DNS_R_SERVFAIL);
    849 	}
    850 	/*
    851 	 * Find the next class and type after the current class and type
    852 	 * among the RRs in current result.
    853 	 * As a side effect, count the number of those RRs.
    854 	 */
    855 	rpsdb_iter->count = 0;
    856 	next_class = dns_rdataclass_reserved0;
    857 	next_type = dns_rdatatype_none;
    858 	for (;;) {
    859 		if (!librpz->rsp_rr(&emsg, &type, &class, &ttl, NULL,
    860 				    &rpsdb->result, rpsdb->qname->ndata,
    861 				    rpsdb->qname->length, rpsdb->rsp))
    862 		{
    863 			librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c);
    864 			return (DNS_R_SERVFAIL);
    865 		}
    866 		if (type == dns_rdatatype_none) {
    867 			if (next_type == dns_rdatatype_none) {
    868 				return (ISC_R_NOMORE);
    869 			}
    870 			rpsdb_iter->type = next_type;
    871 			rpsdb_iter->class = next_class;
    872 			return (ISC_R_SUCCESS);
    873 		}
    874 		/*
    875 		 * Skip RRs with the current class and type or before.
    876 		 */
    877 		if (rpsdb_iter->class > class ||
    878 		    (rpsdb_iter->class = class && rpsdb_iter->type >= type))
    879 		{
    880 			continue;
    881 		}
    882 		if (next_type == dns_rdatatype_none || next_class > class ||
    883 		    (next_class == class && next_type > type))
    884 		{
    885 			/*
    886 			 * This is the first of a subsequent class and type.
    887 			 */
    888 			next_type = type;
    889 			next_class = class;
    890 			rpsdb_iter->ttl = ttl;
    891 			rpsdb_iter->count = 1;
    892 			rpsdb_iter->next_rr = rpsdb->result.next_rr;
    893 		} else if (next_type == type && next_class == class) {
    894 			++rpsdb_iter->count;
    895 		}
    896 	}
    897 }
    898 
    899 static isc_result_t
    900 rpsdb_rdatasetiter_first(dns_rdatasetiter_t *iterator) {
    901 	rpsdb_t *rpsdb;
    902 	rpsdb_rdatasetiter_t *rpsdb_iter;
    903 
    904 	rpsdb = (rpsdb_t *)iterator->db;
    905 	REQUIRE(VALID_RPSDB(rpsdb));
    906 	rpsdb_iter = (rpsdb_rdatasetiter_t *)iterator;
    907 
    908 	rpsdb_iter->type = dns_rdatatype_none;
    909 	rpsdb_iter->class = dns_rdataclass_reserved0;
    910 	return (rpsdb_rdatasetiter_next(iterator));
    911 }
    912 
    913 static void
    914 rpsdb_rdatasetiter_current(dns_rdatasetiter_t *iterator,
    915 			   dns_rdataset_t *rdataset) {
    916 	rpsdb_t *rpsdb;
    917 	rpsdb_rdatasetiter_t *rpsdb_iter;
    918 
    919 	rpsdb = (rpsdb_t *)iterator->db;
    920 	REQUIRE(VALID_RPSDB(rpsdb));
    921 	rpsdb_iter = (rpsdb_rdatasetiter_t *)iterator;
    922 	REQUIRE(rpsdb_iter->type != dns_rdatatype_none);
    923 
    924 	rpsdb_bind_rdataset(rdataset, rpsdb_iter->count, rpsdb_iter->next_rr,
    925 			    rpsdb_iter->type, rpsdb_iter->class,
    926 			    rpsdb_iter->ttl, rpsdb);
    927 }
    928 
    929 static dns_dbmethods_t rpsdb_db_methods = {
    930 	rpsdb_attach,
    931 	rpsdb_detach,
    932 	NULL, /* beginload */
    933 	NULL, /* endload */
    934 	NULL, /* serialize */
    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 	NULL  /* adjusthashsize */
    981 };
    982 
    983 static dns_rdatasetmethods_t rpsdb_rdataset_methods = {
    984 	rpsdb_rdataset_disassociate,
    985 	rpsdb_rdataset_first,
    986 	rpsdb_rdataset_next,
    987 	rpsdb_rdataset_current,
    988 	rpsdb_rdataset_clone,
    989 	rpsdb_rdataset_count,
    990 	NULL,
    991 	NULL,
    992 	NULL,
    993 	NULL,
    994 	NULL,
    995 	NULL,
    996 	NULL,
    997 	NULL,
    998 	NULL,
    999 	NULL
   1000 };
   1001 
   1002 static dns_rdatasetitermethods_t rpsdb_rdatasetiter_methods = {
   1003 	rpsdb_rdatasetiter_destroy, rpsdb_rdatasetiter_first,
   1004 	rpsdb_rdatasetiter_next, rpsdb_rdatasetiter_current
   1005 };
   1006 
   1007 #endif /* USE_DNSRPS */
   1008