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