1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * SPDX-License-Identifier: MPL-2.0
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 
35 librpz_t *librpz;
36 librpz_emsg_t librpz_lib_open_emsg;
37 static 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 
47 typedef 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 
56 static dns_dbmethods_t rpsdb_db_methods;
57 static dns_rdatasetmethods_t rpsdb_rdataset_methods;
58 static dns_rdatasetitermethods_t rpsdb_rdatasetiter_methods;
59 
60 static librpz_clist_t *clist;
61 
62 static isc_mutex_t dnsrps_mutex;
63 
64 static void
dnsrps_lock(void * mutex0)65 dnsrps_lock(void *mutex0) {
66 	isc_mutex_t *mutex = mutex0;
67 
68 	LOCK(mutex);
69 }
70 
71 static void
dnsrps_unlock(void * mutex0)72 dnsrps_unlock(void *mutex0) {
73 	isc_mutex_t *mutex = mutex0;
74 
75 	UNLOCK(mutex);
76 }
77 
78 static void
dnsrps_mutex_destroy(void * mutex0)79 dnsrps_mutex_destroy(void *mutex0) {
80 	isc_mutex_t *mutex = mutex0;
81 
82 	isc_mutex_destroy(mutex);
83 }
84 
85 static void
dnsrps_log_fnc(librpz_log_level_t level,void * ctxt,const char * buf)86 dnsrps_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  */
130 isc_result_t
dns_dnsrps_server_create(void)131 dns_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  */
172 void
dns_dnsrps_server_destroy(void)173 dns_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  */
194 isc_result_t
dns_dnsrps_view_init(dns_rpz_zones_t * new,char * rps_cstr)195 dns_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  */
218 isc_result_t
dns_dnsrps_connect(dns_rpz_zones_t * rpzs)219 dns_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  */
253 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)254 dns_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  */
290 dns_rpz_policy_t
dns_dnsrps_2policy(librpz_policy_t rps_policy)291 dns_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  */
321 dns_rpz_type_t
dns_dnsrps_trig2type(librpz_trig_t trig)322 dns_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  */
343 librpz_trig_t
dns_dnsrps_type2trig(dns_rpz_type_t type)344 dns_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 
362 static void
rpsdb_attach(dns_db_t * source,dns_db_t ** targetp)363 rpsdb_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 
375 static void
rpsdb_detach(dns_db_t ** dbp)376 rpsdb_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 
396 static void
rpsdb_attachnode(dns_db_t * db,dns_dbnode_t * source,dns_dbnode_t ** targetp)397 rpsdb_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 
411 static void
rpsdb_detachnode(dns_db_t * db,dns_dbnode_t ** targetp)412 rpsdb_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 
423 static isc_result_t
rpsdb_findnode(dns_db_t * db,const dns_name_t * name,bool create,dns_dbnode_t ** nodep)424 rpsdb_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 
449 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)450 rpsdb_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 
470 static isc_result_t
rpsdb_bind_soa(dns_rdataset_t * rdataset,rpsdb_t * rpsdb)471 rpsdb_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  */
490 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)491 rpsdb_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 
600 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)601 rpsdb_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 
622 static isc_result_t
rpsdb_allrdatasets(dns_db_t * db,dns_dbnode_t * node,dns_dbversion_t * version,isc_stdtime_t now,dns_rdatasetiter_t ** iteratorp)623 rpsdb_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 
647 static bool
rpsdb_issecure(dns_db_t * db)648 rpsdb_issecure(dns_db_t *db) {
649 	UNUSED(db);
650 
651 	return (false);
652 }
653 
654 static isc_result_t
rpsdb_getoriginnode(dns_db_t * db,dns_dbnode_t ** nodep)655 rpsdb_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 
665 static void
rpsdb_rdataset_disassociate(dns_rdataset_t * rdataset)666 rpsdb_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 
682 static isc_result_t
rpsdb_rdataset_next(dns_rdataset_t * rdataset)683 rpsdb_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 
739 static isc_result_t
rpsdb_rdataset_first(dns_rdataset_t * rdataset)740 rpsdb_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 
765 static void
rpsdb_rdataset_current(dns_rdataset_t * rdataset,dns_rdata_t * rdata)766 rpsdb_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 
781 static void
rpsdb_rdataset_clone(dns_rdataset_t * source,dns_rdataset_t * target)782 rpsdb_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 
798 static unsigned int
rpsdb_rdataset_count(dns_rdataset_t * rdataset)799 rpsdb_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 
808 static void
rpsdb_rdatasetiter_destroy(dns_rdatasetiter_t ** iteratorp)809 rpsdb_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 
824 static isc_result_t
rpsdb_rdatasetiter_next(dns_rdatasetiter_t * iter)825 rpsdb_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 
894 static isc_result_t
rpsdb_rdatasetiter_first(dns_rdatasetiter_t * iterator)895 rpsdb_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 
908 static void
rpsdb_rdatasetiter_current(dns_rdatasetiter_t * iterator,dns_rdataset_t * rdataset)909 rpsdb_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 
924 static 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 
978 static 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 
997 static 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