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