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