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