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