dnsrps.c revision 1.3
1/*	$NetBSD: dnsrps.c,v 1.3 2019/01/09 16:55:11 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	isc_result_t result;
602
603	UNUSED(version);
604	UNUSED(options);
605	UNUSED(now);
606	UNUSED(sigrdataset);
607
608	if (nodep == NULL) {
609		node = NULL;
610		nodep = &node;
611	}
612	rpsdb_findnode(db, name, false, nodep);
613	result = dns_name_copy(name, foundname, NULL);
614	if (result != ISC_R_SUCCESS)
615		return (result);
616	return (rpsdb_findrdataset(db, *nodep, NULL, type, 0, 0,
617				    rdataset, sigrdataset));
618}
619
620static isc_result_t
621rpsdb_allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
622		   isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
623{
624	rpsdb_t *rpsdb = (rpsdb_t *)db;
625	rpsdb_rdatasetiter_t *rpsdb_iter;
626
627	UNUSED(version);
628	UNUSED(now);
629
630	REQUIRE(VALID_RPSDB(rpsdb));
631	REQUIRE(node == &rpsdb->origin_node || node == &rpsdb->data_node);
632
633	rpsdb_iter = isc_mem_get(rpsdb->common.mctx, sizeof(*rpsdb_iter));
634	if (rpsdb_iter == NULL)
635		return (ISC_R_NOMEMORY);
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		RD_NEXT_RR(rdataset) = LIBRPZ_IDX_NULL;
709		if (!librpz->rsp_soa(&emsg, NULL, &rr, NULL,
710				     &rpsdb->result, 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			librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c);
724			return (DNS_R_SERVFAIL);
725		}
726		if (rdataset->type == type &&
727		    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		free(rr);
735	}
736}
737
738static isc_result_t
739rpsdb_rdataset_first(dns_rdataset_t *rdataset) {
740	rpsdb_t *rpsdb;
741	librpz_emsg_t emsg;
742
743	rpsdb = RD_DB(rdataset);
744	REQUIRE(VALID_RPSDB(rpsdb));
745
746	if (RD_CUR_RR(rdataset) != NULL) {
747		free(RD_CUR_RR(rdataset));
748		RD_CUR_RR(rdataset) = NULL;
749	}
750
751	if (!librpz->rsp_result(&emsg, &rpsdb->result, true, rpsdb->rsp)) {
752		librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c);
753		return (DNS_R_SERVFAIL);
754	}
755	if (rdataset->type == dns_rdatatype_soa)
756		RD_NEXT_RR(rdataset) = LIBRPZ_IDX_BAD;
757	else
758		RD_NEXT_RR(rdataset) = rpsdb->result.next_rr;
759
760	return (rpsdb_rdataset_next(rdataset));
761}
762
763static void
764rpsdb_rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
765	rpsdb_t *rpsdb;
766	librpz_rr_t *rr;
767	isc_region_t r;
768
769	rpsdb = RD_DB(rdataset);
770	REQUIRE(VALID_RPSDB(rpsdb));
771	rr = RD_CUR_RR(rdataset);
772	REQUIRE(rr != NULL);
773
774	r.length = ntohs(rr->rdlength);
775	r.base = rr->rdata;
776	dns_rdata_fromregion(rdata, ntohs(rr->class), ntohs(rr->type), &r);
777}
778
779static void
780rpsdb_rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
781	rpsdb_t *rpsdb;
782	dns_db_t *dbp;
783
784	INSIST(!ISC_LINK_LINKED(target, link));
785	*target = *source;
786	ISC_LINK_INIT(target, link);
787	rpsdb = RD_DB(source);
788	REQUIRE(VALID_RPSDB(rpsdb));
789	dbp = NULL;
790	dns_db_attach(&rpsdb->common, &dbp);
791	RD_DB(target) = dbp;
792	RD_CUR_RR(target) = NULL;
793	RD_NEXT_RR(target) = LIBRPZ_IDX_NULL;
794}
795
796static unsigned int
797rpsdb_rdataset_count(dns_rdataset_t *rdataset) {
798	rpsdb_t *rpsdb;
799
800	rpsdb = RD_DB(rdataset);
801	REQUIRE(VALID_RPSDB(rpsdb));
802
803	return (RD_COUNT(rdataset));
804}
805
806static void
807rpsdb_rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
808	rpsdb_t *rpsdb;
809	dns_rdatasetiter_t *iterator;
810	isc_mem_t *mctx;
811
812	iterator = *iteratorp;
813	rpsdb = (rpsdb_t *)iterator->db;
814	REQUIRE(VALID_RPSDB(rpsdb));
815
816	mctx = iterator->db->mctx;
817	dns_db_detachnode(iterator->db, &iterator->node);
818	isc_mem_put(mctx, iterator, sizeof(rpsdb_rdatasetiter_t));
819	*iteratorp = NULL;
820}
821
822static isc_result_t
823rpsdb_rdatasetiter_next(dns_rdatasetiter_t *iter) {
824	rpsdb_t *rpsdb;
825	rpsdb_rdatasetiter_t *rpsdb_iter;
826	dns_rdatatype_t next_type, type;
827	dns_rdataclass_t next_class, class;
828	uint32_t ttl;
829	librpz_emsg_t emsg;
830
831	rpsdb = (rpsdb_t *)iter->db;
832	REQUIRE(VALID_RPSDB(rpsdb));
833	rpsdb_iter = (rpsdb_rdatasetiter_t *)iter;
834
835	/*
836	 * This function is only used after a policy has been chosen,
837	 * and so without caring whether it is after recursion.
838	 */
839	if (!librpz->rsp_result(&emsg, &rpsdb->result, true, rpsdb->rsp)) {
840		librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c);
841		return (DNS_R_SERVFAIL);
842	}
843	/*
844	 * Find the next class and type after the current class and type
845	 * among the RRs in current result.
846	 * As a side effect, count the number of those RRs.
847	 */
848	rpsdb_iter->count = 0;
849	next_class = dns_rdataclass_reserved0;
850	next_type = dns_rdatatype_none;
851	for (;;) {
852		if (!librpz->rsp_rr(&emsg, &type, &class, &ttl,
853				    NULL, &rpsdb->result, rpsdb->qname->ndata,
854				    rpsdb->qname->length, rpsdb->rsp)) {
855			librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c);
856			return (DNS_R_SERVFAIL);
857		}
858		if (type == dns_rdatatype_none) {
859			if (next_type == dns_rdatatype_none)
860				return (ISC_R_NOMORE);
861			rpsdb_iter->type = next_type;
862			rpsdb_iter->class = next_class;
863			return (ISC_R_SUCCESS);
864		}
865		/*
866		 * Skip RRs with the current class and type or before.
867		 */
868		if (rpsdb_iter->class > class ||
869		    (rpsdb_iter->class = class && rpsdb_iter->type >= type))
870			continue;
871		if (next_type == dns_rdatatype_none ||
872		    next_class > class ||
873		    (next_class == class && next_type > type)) {
874			/*
875			 * This is the first of a subsequent class and type.
876			 */
877			next_type = type;
878			next_class = class;
879			rpsdb_iter->ttl = ttl;
880			rpsdb_iter->count = 1;
881			rpsdb_iter->next_rr = rpsdb->result.next_rr;
882		} else if (next_type == type && next_class == class) {
883			++rpsdb_iter->count;
884		}
885	}
886}
887
888static isc_result_t
889rpsdb_rdatasetiter_first(dns_rdatasetiter_t *iterator) {
890	rpsdb_t *rpsdb;
891	rpsdb_rdatasetiter_t *rpsdb_iter;
892
893	rpsdb = (rpsdb_t *)iterator->db;
894	REQUIRE(VALID_RPSDB(rpsdb));
895	rpsdb_iter = (rpsdb_rdatasetiter_t *)iterator;
896
897	rpsdb_iter->type = dns_rdatatype_none;
898	rpsdb_iter->class = dns_rdataclass_reserved0;
899	return (rpsdb_rdatasetiter_next(iterator));
900}
901
902static void
903rpsdb_rdatasetiter_current(dns_rdatasetiter_t *iterator,
904			   dns_rdataset_t *rdataset)
905{
906	rpsdb_t *rpsdb;
907	rpsdb_rdatasetiter_t *rpsdb_iter;
908
909	rpsdb = (rpsdb_t *)iterator->db;
910	REQUIRE(VALID_RPSDB(rpsdb));
911	rpsdb_iter = (rpsdb_rdatasetiter_t *)iterator;
912	REQUIRE(rpsdb_iter->type != dns_rdatatype_none);
913
914	rpsdb_bind_rdataset(rdataset,
915			     rpsdb_iter->count, rpsdb_iter->next_rr,
916			     rpsdb_iter->type, rpsdb_iter->class,
917			     rpsdb_iter->ttl, rpsdb);
918}
919
920static dns_dbmethods_t rpsdb_db_methods = {
921	rpsdb_attach,
922	rpsdb_detach,
923	NULL,			/* beginload */
924	NULL,			/* endload */
925	NULL,			/* serialize */
926	NULL,			/* dump */
927	NULL,			/* currentversion */
928	NULL,			/* newversion */
929	NULL,			/* attachversion */
930	NULL,			/* closeversion */
931	rpsdb_findnode,
932	rpsdb_finddb,
933	NULL,			/* findzonecut*/
934	rpsdb_attachnode,
935	rpsdb_detachnode,
936	NULL,			/* expirenode */
937	NULL,			/* printnode */
938	NULL,			/* createiterator */
939	rpsdb_findrdataset,
940	rpsdb_allrdatasets,
941	NULL,			/* addrdataset */
942	NULL,			/* subtractrdataset */
943	NULL,			/* deleterdataset */
944	rpsdb_issecure,
945	NULL,			/* nodecount */
946	NULL,			/* ispersistent */
947	NULL,			/* overmem */
948	NULL,			/* settask */
949	rpsdb_getoriginnode,
950	NULL,			/* transfernode */
951	NULL,			/* getnsec3parameters */
952	NULL,			/* findnsec3node */
953	NULL,			/* setsigningtime */
954	NULL,			/* getsigningtime */
955	NULL,			/* resigned */
956	NULL,			/* isdnssec */
957	NULL,			/* getrrsetstats */
958	NULL,			/* rpz_attach */
959	NULL,			/* rpz_ready */
960	NULL,			/* findnodeext */
961	NULL,			/* findext */
962	NULL,			/* setcachestats */
963	NULL,			/* hashsize */
964	NULL,			/* nodefullname */
965	NULL,			/* getsize */
966	NULL,			/* setservestalettl */
967	NULL,			/* getservestalettl */
968	NULL			/* setgluecachestats */
969};
970
971static dns_rdatasetmethods_t rpsdb_rdataset_methods = {
972	rpsdb_rdataset_disassociate,
973	rpsdb_rdataset_first,
974	rpsdb_rdataset_next,
975	rpsdb_rdataset_current,
976	rpsdb_rdataset_clone,
977	rpsdb_rdataset_count,
978	NULL,
979	NULL,
980	NULL,
981	NULL,
982	NULL,
983	NULL,
984	NULL,
985	NULL,
986	NULL,
987	NULL
988};
989
990static dns_rdatasetitermethods_t rpsdb_rdatasetiter_methods = {
991	rpsdb_rdatasetiter_destroy,
992	rpsdb_rdatasetiter_first,
993	rpsdb_rdatasetiter_next,
994	rpsdb_rdatasetiter_current
995};
996
997#endif /* USE_DNSRPS */
998