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