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