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