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