xref: /netbsd-src/external/mpl/dhcp/bind/dist/lib/dns/dnsrps.c (revision 4afad4b7fa6d4a0d3dedf41d1587a7250710ae54)
1 /*	$NetBSD: dnsrps.c,v 1.1 2024/02/18 20:57:31 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
dnsrps_lock(void * mutex0)67 dnsrps_lock(void *mutex0) {
68 	isc_mutex_t *mutex = mutex0;
69 
70 	LOCK(mutex);
71 }
72 
73 static void
dnsrps_unlock(void * mutex0)74 dnsrps_unlock(void *mutex0) {
75 	isc_mutex_t *mutex = mutex0;
76 
77 	UNLOCK(mutex);
78 }
79 
80 static void
dnsrps_mutex_destroy(void * mutex0)81 dnsrps_mutex_destroy(void *mutex0) {
82 	isc_mutex_t *mutex = mutex0;
83 
84 	isc_mutex_destroy(mutex);
85 }
86 
87 static void
dnsrps_log_fnc(librpz_log_level_t level,void * ctxt,const char * buf)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
dns_dnsrps_server_create(void)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
dns_dnsrps_server_destroy(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
dns_dnsrps_view_init(dns_rpz_zones_t * new,char * rps_cstr)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
dns_dnsrps_connect(dns_rpz_zones_t * rpzs)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
dns_dnsrps_rewrite_init(librpz_emsg_t * emsg,dns_rpz_st_t * st,dns_rpz_zones_t * rpzs,const dns_name_t * qname,isc_mem_t * mctx,bool have_rd)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
dns_dnsrps_2policy(librpz_policy_t rps_policy)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
dns_dnsrps_trig2type(librpz_trig_t trig)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
dns_dnsrps_type2trig(dns_rpz_type_t type)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
rpsdb_attach(dns_db_t * source,dns_db_t ** targetp)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
rpsdb_detach(dns_db_t ** dbp)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
rpsdb_attachnode(dns_db_t * db,dns_dbnode_t * source,dns_dbnode_t ** targetp)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
rpsdb_detachnode(dns_db_t * db,dns_dbnode_t ** targetp)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
rpsdb_findnode(dns_db_t * db,const dns_name_t * name,bool create,dns_dbnode_t ** nodep)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
rpsdb_bind_rdataset(dns_rdataset_t * rdataset,uint count,librpz_idx_t next_rr,dns_rdatatype_t type,uint16_t class,uint32_t ttl,rpsdb_t * rpsdb)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
rpsdb_bind_soa(dns_rdataset_t * rdataset,rpsdb_t * rpsdb)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
rpsdb_findrdataset(dns_db_t * db,dns_dbnode_t * node,dns_dbversion_t * version,dns_rdatatype_t type,dns_rdatatype_t covers,isc_stdtime_t now,dns_rdataset_t * rdataset,dns_rdataset_t * sigrdataset)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
rpsdb_finddb(dns_db_t * db,const dns_name_t * name,dns_dbversion_t * version,dns_rdatatype_t type,unsigned int options,isc_stdtime_t now,dns_dbnode_t ** nodep,dns_name_t * foundname,dns_rdataset_t * rdataset,dns_rdataset_t * sigrdataset)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
rpsdb_allrdatasets(dns_db_t * db,dns_dbnode_t * node,dns_dbversion_t * version,unsigned int options,isc_stdtime_t now,dns_rdatasetiter_t ** iteratorp)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_iter->common.options = options;
644 	rpsdb_attachnode(db, node, &rpsdb_iter->common.node);
645 
646 	*iteratorp = &rpsdb_iter->common;
647 
648 	return (ISC_R_SUCCESS);
649 }
650 
651 static bool
rpsdb_issecure(dns_db_t * db)652 rpsdb_issecure(dns_db_t *db) {
653 	UNUSED(db);
654 
655 	return (false);
656 }
657 
658 static isc_result_t
rpsdb_getoriginnode(dns_db_t * db,dns_dbnode_t ** nodep)659 rpsdb_getoriginnode(dns_db_t *db, dns_dbnode_t **nodep) {
660 	rpsdb_t *rpsdb = (rpsdb_t *)db;
661 
662 	REQUIRE(VALID_RPSDB(rpsdb));
663 	REQUIRE(nodep != NULL && *nodep == NULL);
664 
665 	rpsdb_attachnode(db, &rpsdb->origin_node, nodep);
666 	return (ISC_R_SUCCESS);
667 }
668 
669 static void
rpsdb_rdataset_disassociate(dns_rdataset_t * rdataset)670 rpsdb_rdataset_disassociate(dns_rdataset_t *rdataset) {
671 	dns_db_t *db;
672 
673 	/*
674 	 * Detach the last RR delivered.
675 	 */
676 	if (RD_CUR_RR(rdataset) != NULL) {
677 		free(RD_CUR_RR(rdataset));
678 		RD_CUR_RR(rdataset) = NULL;
679 	}
680 
681 	db = RD_DB(rdataset);
682 	RD_DB(rdataset) = NULL;
683 	dns_db_detach(&db);
684 }
685 
686 static isc_result_t
rpsdb_rdataset_next(dns_rdataset_t * rdataset)687 rpsdb_rdataset_next(dns_rdataset_t *rdataset) {
688 	rpsdb_t *rpsdb;
689 	uint16_t type;
690 	dns_rdataclass_t class;
691 	librpz_rr_t *rr;
692 	librpz_emsg_t emsg;
693 
694 	rpsdb = RD_DB(rdataset);
695 
696 	/*
697 	 * Detach the previous RR.
698 	 */
699 	if (RD_CUR_RR(rdataset) != NULL) {
700 		free(RD_CUR_RR(rdataset));
701 		RD_CUR_RR(rdataset) = NULL;
702 	}
703 
704 	/*
705 	 * Get the next RR of the specified type.
706 	 * SOAs differ.
707 	 */
708 	if (rdataset->type == dns_rdatatype_soa) {
709 		if (RD_NEXT_RR(rdataset) == LIBRPZ_IDX_NULL) {
710 			return (ISC_R_NOMORE);
711 		}
712 		RD_NEXT_RR(rdataset) = LIBRPZ_IDX_NULL;
713 		if (!librpz->rsp_soa(&emsg, NULL, &rr, NULL, &rpsdb->result,
714 				     rpsdb->rsp))
715 		{
716 			librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c);
717 			return (DNS_R_SERVFAIL);
718 		}
719 		RD_CUR_RR(rdataset) = rr;
720 		return (ISC_R_SUCCESS);
721 	}
722 
723 	rpsdb->result.next_rr = RD_NEXT_RR(rdataset);
724 	for (;;) {
725 		if (!librpz->rsp_rr(&emsg, &type, &class, NULL, &rr,
726 				    &rpsdb->result, rpsdb->qname->ndata,
727 				    rpsdb->qname->length, rpsdb->rsp))
728 		{
729 			librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c);
730 			return (DNS_R_SERVFAIL);
731 		}
732 		if (rdataset->type == type && rdataset->rdclass == class) {
733 			RD_CUR_RR(rdataset) = rr;
734 			RD_NEXT_RR(rdataset) = rpsdb->result.next_rr;
735 			return (ISC_R_SUCCESS);
736 		}
737 		if (type == dns_rdatatype_none) {
738 			return (ISC_R_NOMORE);
739 		}
740 		free(rr);
741 	}
742 }
743 
744 static isc_result_t
rpsdb_rdataset_first(dns_rdataset_t * rdataset)745 rpsdb_rdataset_first(dns_rdataset_t *rdataset) {
746 	rpsdb_t *rpsdb;
747 	librpz_emsg_t emsg;
748 
749 	rpsdb = RD_DB(rdataset);
750 	REQUIRE(VALID_RPSDB(rpsdb));
751 
752 	if (RD_CUR_RR(rdataset) != NULL) {
753 		free(RD_CUR_RR(rdataset));
754 		RD_CUR_RR(rdataset) = NULL;
755 	}
756 
757 	if (!librpz->rsp_result(&emsg, &rpsdb->result, true, rpsdb->rsp)) {
758 		librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c);
759 		return (DNS_R_SERVFAIL);
760 	}
761 	if (rdataset->type == dns_rdatatype_soa) {
762 		RD_NEXT_RR(rdataset) = LIBRPZ_IDX_BAD;
763 	} else {
764 		RD_NEXT_RR(rdataset) = rpsdb->result.next_rr;
765 	}
766 
767 	return (rpsdb_rdataset_next(rdataset));
768 }
769 
770 static void
rpsdb_rdataset_current(dns_rdataset_t * rdataset,dns_rdata_t * rdata)771 rpsdb_rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
772 	rpsdb_t *rpsdb;
773 	librpz_rr_t *rr;
774 	isc_region_t r;
775 
776 	rpsdb = RD_DB(rdataset);
777 	REQUIRE(VALID_RPSDB(rpsdb));
778 	rr = RD_CUR_RR(rdataset);
779 	REQUIRE(rr != NULL);
780 
781 	r.length = ntohs(rr->rdlength);
782 	r.base = rr->rdata;
783 	dns_rdata_fromregion(rdata, ntohs(rr->class), ntohs(rr->type), &r);
784 }
785 
786 static void
rpsdb_rdataset_clone(dns_rdataset_t * source,dns_rdataset_t * target)787 rpsdb_rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
788 	rpsdb_t *rpsdb;
789 	dns_db_t *dbp;
790 
791 	INSIST(!ISC_LINK_LINKED(target, link));
792 	*target = *source;
793 	ISC_LINK_INIT(target, link);
794 	rpsdb = RD_DB(source);
795 	REQUIRE(VALID_RPSDB(rpsdb));
796 	dbp = NULL;
797 	dns_db_attach(&rpsdb->common, &dbp);
798 	RD_DB(target) = dbp;
799 	RD_CUR_RR(target) = NULL;
800 	RD_NEXT_RR(target) = LIBRPZ_IDX_NULL;
801 }
802 
803 static unsigned int
rpsdb_rdataset_count(dns_rdataset_t * rdataset)804 rpsdb_rdataset_count(dns_rdataset_t *rdataset) {
805 	rpsdb_t *rpsdb;
806 
807 	rpsdb = RD_DB(rdataset);
808 	REQUIRE(VALID_RPSDB(rpsdb));
809 
810 	return (RD_COUNT(rdataset));
811 }
812 
813 static void
rpsdb_rdatasetiter_destroy(dns_rdatasetiter_t ** iteratorp)814 rpsdb_rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
815 	rpsdb_t *rpsdb;
816 	dns_rdatasetiter_t *iterator;
817 	isc_mem_t *mctx;
818 
819 	iterator = *iteratorp;
820 	*iteratorp = NULL;
821 	rpsdb = (rpsdb_t *)iterator->db;
822 	REQUIRE(VALID_RPSDB(rpsdb));
823 
824 	mctx = iterator->db->mctx;
825 	dns_db_detachnode(iterator->db, &iterator->node);
826 	isc_mem_put(mctx, iterator, sizeof(rpsdb_rdatasetiter_t));
827 }
828 
829 static isc_result_t
rpsdb_rdatasetiter_next(dns_rdatasetiter_t * iter)830 rpsdb_rdatasetiter_next(dns_rdatasetiter_t *iter) {
831 	rpsdb_t *rpsdb;
832 	rpsdb_rdatasetiter_t *rpsdb_iter;
833 	dns_rdatatype_t next_type, type;
834 	dns_rdataclass_t next_class, class;
835 	uint32_t ttl;
836 	librpz_emsg_t emsg;
837 
838 	rpsdb = (rpsdb_t *)iter->db;
839 	REQUIRE(VALID_RPSDB(rpsdb));
840 	rpsdb_iter = (rpsdb_rdatasetiter_t *)iter;
841 
842 	/*
843 	 * This function is only used after a policy has been chosen,
844 	 * and so without caring whether it is after recursion.
845 	 */
846 	if (!librpz->rsp_result(&emsg, &rpsdb->result, true, rpsdb->rsp)) {
847 		librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c);
848 		return (DNS_R_SERVFAIL);
849 	}
850 	/*
851 	 * Find the next class and type after the current class and type
852 	 * among the RRs in current result.
853 	 * As a side effect, count the number of those RRs.
854 	 */
855 	rpsdb_iter->count = 0;
856 	next_class = dns_rdataclass_reserved0;
857 	next_type = dns_rdatatype_none;
858 	for (;;) {
859 		if (!librpz->rsp_rr(&emsg, &type, &class, &ttl, NULL,
860 				    &rpsdb->result, rpsdb->qname->ndata,
861 				    rpsdb->qname->length, rpsdb->rsp))
862 		{
863 			librpz->log(LIBRPZ_LOG_ERROR, NULL, "%s", emsg.c);
864 			return (DNS_R_SERVFAIL);
865 		}
866 		if (type == dns_rdatatype_none) {
867 			if (next_type == dns_rdatatype_none) {
868 				return (ISC_R_NOMORE);
869 			}
870 			rpsdb_iter->type = next_type;
871 			rpsdb_iter->class = next_class;
872 			return (ISC_R_SUCCESS);
873 		}
874 		/*
875 		 * Skip RRs with the current class and type or before.
876 		 */
877 		if (rpsdb_iter->class > class ||
878 		    (rpsdb_iter->class = class && rpsdb_iter->type >= type))
879 		{
880 			continue;
881 		}
882 		if (next_type == dns_rdatatype_none || next_class > class ||
883 		    (next_class == class && next_type > type))
884 		{
885 			/*
886 			 * This is the first of a subsequent class and type.
887 			 */
888 			next_type = type;
889 			next_class = class;
890 			rpsdb_iter->ttl = ttl;
891 			rpsdb_iter->count = 1;
892 			rpsdb_iter->next_rr = rpsdb->result.next_rr;
893 		} else if (next_type == type && next_class == class) {
894 			++rpsdb_iter->count;
895 		}
896 	}
897 }
898 
899 static isc_result_t
rpsdb_rdatasetiter_first(dns_rdatasetiter_t * iterator)900 rpsdb_rdatasetiter_first(dns_rdatasetiter_t *iterator) {
901 	rpsdb_t *rpsdb;
902 	rpsdb_rdatasetiter_t *rpsdb_iter;
903 
904 	rpsdb = (rpsdb_t *)iterator->db;
905 	REQUIRE(VALID_RPSDB(rpsdb));
906 	rpsdb_iter = (rpsdb_rdatasetiter_t *)iterator;
907 
908 	rpsdb_iter->type = dns_rdatatype_none;
909 	rpsdb_iter->class = dns_rdataclass_reserved0;
910 	return (rpsdb_rdatasetiter_next(iterator));
911 }
912 
913 static void
rpsdb_rdatasetiter_current(dns_rdatasetiter_t * iterator,dns_rdataset_t * rdataset)914 rpsdb_rdatasetiter_current(dns_rdatasetiter_t *iterator,
915 			   dns_rdataset_t *rdataset) {
916 	rpsdb_t *rpsdb;
917 	rpsdb_rdatasetiter_t *rpsdb_iter;
918 
919 	rpsdb = (rpsdb_t *)iterator->db;
920 	REQUIRE(VALID_RPSDB(rpsdb));
921 	rpsdb_iter = (rpsdb_rdatasetiter_t *)iterator;
922 	REQUIRE(rpsdb_iter->type != dns_rdatatype_none);
923 
924 	rpsdb_bind_rdataset(rdataset, rpsdb_iter->count, rpsdb_iter->next_rr,
925 			    rpsdb_iter->type, rpsdb_iter->class,
926 			    rpsdb_iter->ttl, rpsdb);
927 }
928 
929 static dns_dbmethods_t rpsdb_db_methods = {
930 	rpsdb_attach,
931 	rpsdb_detach,
932 	NULL, /* beginload */
933 	NULL, /* endload */
934 	NULL, /* serialize */
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 	NULL  /* adjusthashsize */
981 };
982 
983 static dns_rdatasetmethods_t rpsdb_rdataset_methods = {
984 	rpsdb_rdataset_disassociate,
985 	rpsdb_rdataset_first,
986 	rpsdb_rdataset_next,
987 	rpsdb_rdataset_current,
988 	rpsdb_rdataset_clone,
989 	rpsdb_rdataset_count,
990 	NULL,
991 	NULL,
992 	NULL,
993 	NULL,
994 	NULL,
995 	NULL,
996 	NULL,
997 	NULL,
998 	NULL,
999 	NULL
1000 };
1001 
1002 static dns_rdatasetitermethods_t rpsdb_rdatasetiter_methods = {
1003 	rpsdb_rdatasetiter_destroy, rpsdb_rdatasetiter_first,
1004 	rpsdb_rdatasetiter_next, rpsdb_rdatasetiter_current
1005 };
1006 
1007 #endif /* USE_DNSRPS */
1008