1 /* $NetBSD: ecdb.c,v 1.9 2015/07/08 17:28:58 christos Exp $ */
2
3 /*
4 * Copyright (C) 2009-2014 Internet Systems Consortium, Inc. ("ISC")
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include "config.h"
20
21 #include <isc/result.h>
22 #include <isc/util.h>
23 #include <isc/mutex.h>
24 #include <isc/mem.h>
25
26 #include <dns/db.h>
27 #include <dns/ecdb.h>
28 #include <dns/rdata.h>
29 #include <dns/rdataset.h>
30 #include <dns/rdatasetiter.h>
31 #include <dns/rdataslab.h>
32
33 #define ECDB_MAGIC ISC_MAGIC('E', 'C', 'D', 'B')
34 #define VALID_ECDB(db) ((db) != NULL && \
35 (db)->common.impmagic == ECDB_MAGIC)
36
37 #define ECDBNODE_MAGIC ISC_MAGIC('E', 'C', 'D', 'N')
38 #define VALID_ECDBNODE(ecdbn) ISC_MAGIC_VALID(ecdbn, ECDBNODE_MAGIC)
39
40 /*%
41 * The 'ephemeral' cache DB (ecdb) implementation. An ecdb just provides
42 * temporary storage for ongoing name resolution with the common DB interfaces.
43 * It actually doesn't cache anything. The implementation expects any stored
44 * data is released within a short period, and does not care about the
45 * scalability in terms of the number of nodes.
46 */
47
48 typedef struct dns_ecdb {
49 /* Unlocked */
50 dns_db_t common;
51 isc_mutex_t lock;
52
53 /* Locked */
54 unsigned int references;
55 ISC_LIST(struct dns_ecdbnode) nodes;
56 } dns_ecdb_t;
57
58 typedef struct dns_ecdbnode {
59 /* Unlocked */
60 unsigned int magic;
61 isc_mutex_t lock;
62 dns_ecdb_t *ecdb;
63 dns_name_t name;
64 ISC_LINK(struct dns_ecdbnode) link;
65
66 /* Locked */
67 ISC_LIST(struct rdatasetheader) rdatasets;
68 unsigned int references;
69 } dns_ecdbnode_t;
70
71 typedef struct rdatasetheader {
72 dns_rdatatype_t type;
73 dns_ttl_t ttl;
74 dns_trust_t trust;
75 dns_rdatatype_t covers;
76 unsigned int attributes;
77
78 ISC_LINK(struct rdatasetheader) link;
79 } rdatasetheader_t;
80
81 /* Copied from rbtdb.c */
82 #define RDATASET_ATTR_NXDOMAIN 0x0010
83 #define RDATASET_ATTR_NEGATIVE 0x0100
84 #define NXDOMAIN(header) \
85 (((header)->attributes & RDATASET_ATTR_NXDOMAIN) != 0)
86 #define NEGATIVE(header) \
87 (((header)->attributes & RDATASET_ATTR_NEGATIVE) != 0)
88
89 static isc_result_t dns_ecdb_create(isc_mem_t *mctx, dns_name_t *origin,
90 dns_dbtype_t type,
91 dns_rdataclass_t rdclass,
92 unsigned int argc, char *argv[],
93 void *driverarg, dns_db_t **dbp);
94
95 static void rdataset_disassociate(dns_rdataset_t *rdataset);
96 static isc_result_t rdataset_first(dns_rdataset_t *rdataset);
97 static isc_result_t rdataset_next(dns_rdataset_t *rdataset);
98 static void rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata);
99 static void rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target);
100 static unsigned int rdataset_count(dns_rdataset_t *rdataset);
101 static void rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust);
102
103 static dns_rdatasetmethods_t rdataset_methods = {
104 rdataset_disassociate,
105 rdataset_first,
106 rdataset_next,
107 rdataset_current,
108 rdataset_clone,
109 rdataset_count,
110 NULL, /* addnoqname */
111 NULL, /* getnoqname */
112 NULL, /* addclosest */
113 NULL, /* getclosest */
114 NULL, /* getadditional */
115 NULL, /* setadditional */
116 NULL, /* putadditional */
117 rdataset_settrust, /* settrust */
118 NULL, /* expire */
119 NULL /* clearprefetch */
120 };
121
122 typedef struct ecdb_rdatasetiter {
123 dns_rdatasetiter_t common;
124 rdatasetheader_t *current;
125 } ecdb_rdatasetiter_t;
126
127 static void rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp);
128 static isc_result_t rdatasetiter_first(dns_rdatasetiter_t *iterator);
129 static isc_result_t rdatasetiter_next(dns_rdatasetiter_t *iterator);
130 static void rdatasetiter_current(dns_rdatasetiter_t *iterator,
131 dns_rdataset_t *rdataset);
132
133 static dns_rdatasetitermethods_t rdatasetiter_methods = {
134 rdatasetiter_destroy,
135 rdatasetiter_first,
136 rdatasetiter_next,
137 rdatasetiter_current
138 };
139
140 isc_result_t
dns_ecdb_register(isc_mem_t * mctx,dns_dbimplementation_t ** dbimp)141 dns_ecdb_register(isc_mem_t *mctx, dns_dbimplementation_t **dbimp) {
142 REQUIRE(mctx != NULL);
143 REQUIRE(dbimp != NULL && *dbimp == NULL);
144
145 return (dns_db_register("ecdb", dns_ecdb_create, NULL, mctx, dbimp));
146 }
147
148 void
dns_ecdb_unregister(dns_dbimplementation_t ** dbimp)149 dns_ecdb_unregister(dns_dbimplementation_t **dbimp) {
150 REQUIRE(dbimp != NULL && *dbimp != NULL);
151
152 dns_db_unregister(dbimp);
153 }
154
155 /*%
156 * DB routines
157 */
158
159 static void
attach(dns_db_t * source,dns_db_t ** targetp)160 attach(dns_db_t *source, dns_db_t **targetp) {
161 dns_ecdb_t *ecdb = (dns_ecdb_t *)source;
162
163 REQUIRE(VALID_ECDB(ecdb));
164 REQUIRE(targetp != NULL && *targetp == NULL);
165
166 LOCK(&ecdb->lock);
167 ecdb->references++;
168 UNLOCK(&ecdb->lock);
169
170 *targetp = source;
171 }
172
173 static void
destroy_ecdb(dns_ecdb_t ** ecdbp)174 destroy_ecdb(dns_ecdb_t **ecdbp) {
175 dns_ecdb_t *ecdb = *ecdbp;
176 isc_mem_t *mctx = ecdb->common.mctx;
177
178 if (dns_name_dynamic(&ecdb->common.origin))
179 dns_name_free(&ecdb->common.origin, mctx);
180
181 DESTROYLOCK(&ecdb->lock);
182
183 ecdb->common.impmagic = 0;
184 ecdb->common.magic = 0;
185
186 isc_mem_putanddetach(&mctx, ecdb, sizeof(*ecdb));
187
188 *ecdbp = NULL;
189 }
190
191 static void
detach(dns_db_t ** dbp)192 detach(dns_db_t **dbp) {
193 dns_ecdb_t *ecdb;
194 isc_boolean_t need_destroy = ISC_FALSE;
195
196 REQUIRE(dbp != NULL);
197 ecdb = (dns_ecdb_t *)*dbp;
198 REQUIRE(VALID_ECDB(ecdb));
199
200 LOCK(&ecdb->lock);
201 ecdb->references--;
202 if (ecdb->references == 0 && ISC_LIST_EMPTY(ecdb->nodes))
203 need_destroy = ISC_TRUE;
204 UNLOCK(&ecdb->lock);
205
206 if (need_destroy)
207 destroy_ecdb(&ecdb);
208
209 *dbp = NULL;
210 }
211
212 static void
attachnode(dns_db_t * db,dns_dbnode_t * source,dns_dbnode_t ** targetp)213 attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
214 dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
215 dns_ecdbnode_t *node = (dns_ecdbnode_t *)source;
216
217 REQUIRE(VALID_ECDB(ecdb));
218 REQUIRE(VALID_ECDBNODE(node));
219 REQUIRE(targetp != NULL && *targetp == NULL);
220
221 LOCK(&node->lock);
222 INSIST(node->references > 0);
223 node->references++;
224 INSIST(node->references != 0); /* Catch overflow. */
225 UNLOCK(&node->lock);
226
227 *targetp = node;
228 }
229
230 static void
destroynode(dns_ecdbnode_t * node)231 destroynode(dns_ecdbnode_t *node) {
232 isc_mem_t *mctx;
233 dns_ecdb_t *ecdb = node->ecdb;
234 isc_boolean_t need_destroydb = ISC_FALSE;
235 rdatasetheader_t *header;
236
237 mctx = ecdb->common.mctx;
238
239 LOCK(&ecdb->lock);
240 ISC_LIST_UNLINK(ecdb->nodes, node, link);
241 if (ecdb->references == 0 && ISC_LIST_EMPTY(ecdb->nodes))
242 need_destroydb = ISC_TRUE;
243 UNLOCK(&ecdb->lock);
244
245 dns_name_free(&node->name, mctx);
246
247 while ((header = ISC_LIST_HEAD(node->rdatasets)) != NULL) {
248 unsigned int headersize;
249
250 ISC_LIST_UNLINK(node->rdatasets, header, link);
251 headersize =
252 dns_rdataslab_size((unsigned char *)header,
253 sizeof(*header));
254 isc_mem_put(mctx, header, headersize);
255 }
256
257 DESTROYLOCK(&node->lock);
258
259 node->magic = 0;
260 isc_mem_put(mctx, node, sizeof(*node));
261
262 if (need_destroydb)
263 destroy_ecdb(&ecdb);
264 }
265
266 static void
detachnode(dns_db_t * db,dns_dbnode_t ** nodep)267 detachnode(dns_db_t *db, dns_dbnode_t **nodep) {
268 dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
269 dns_ecdbnode_t *node;
270 isc_boolean_t need_destroy = ISC_FALSE;
271
272 REQUIRE(VALID_ECDB(ecdb));
273 REQUIRE(nodep != NULL);
274 node = (dns_ecdbnode_t *)*nodep;
275 REQUIRE(VALID_ECDBNODE(node));
276
277 UNUSED(ecdb); /* in case REQUIRE() is empty */
278
279 LOCK(&node->lock);
280 INSIST(node->references > 0);
281 node->references--;
282 if (node->references == 0)
283 need_destroy = ISC_TRUE;
284 UNLOCK(&node->lock);
285
286 if (need_destroy)
287 destroynode(node);
288
289 *nodep = NULL;
290 }
291
292 static isc_result_t
find(dns_db_t * db,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)293 find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
294 dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
295 dns_dbnode_t **nodep, dns_name_t *foundname, dns_rdataset_t *rdataset,
296 dns_rdataset_t *sigrdataset)
297 {
298 dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
299
300 REQUIRE(VALID_ECDB(ecdb));
301
302 UNUSED(name);
303 UNUSED(version);
304 UNUSED(type);
305 UNUSED(options);
306 UNUSED(now);
307 UNUSED(nodep);
308 UNUSED(foundname);
309 UNUSED(rdataset);
310 UNUSED(sigrdataset);
311
312 return (ISC_R_NOTFOUND);
313 }
314
315 static isc_result_t
findzonecut(dns_db_t * db,dns_name_t * name,unsigned int options,isc_stdtime_t now,dns_dbnode_t ** nodep,dns_name_t * foundname,dns_rdataset_t * rdataset,dns_rdataset_t * sigrdataset)316 findzonecut(dns_db_t *db, dns_name_t *name,
317 unsigned int options, isc_stdtime_t now,
318 dns_dbnode_t **nodep, dns_name_t *foundname,
319 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
320 {
321 dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
322
323 REQUIRE(VALID_ECDB(ecdb));
324
325 UNUSED(name);
326 UNUSED(options);
327 UNUSED(now);
328 UNUSED(nodep);
329 UNUSED(foundname);
330 UNUSED(rdataset);
331 UNUSED(sigrdataset);
332
333 return (ISC_R_NOTFOUND);
334 }
335
336 static isc_result_t
findnode(dns_db_t * db,dns_name_t * name,isc_boolean_t create,dns_dbnode_t ** nodep)337 findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
338 dns_dbnode_t **nodep)
339 {
340 dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
341 isc_mem_t *mctx;
342 dns_ecdbnode_t *node;
343 isc_result_t result;
344
345 REQUIRE(VALID_ECDB(ecdb));
346 REQUIRE(nodep != NULL && *nodep == NULL);
347
348 UNUSED(name);
349
350 if (create != ISC_TRUE) {
351 /* an 'ephemeral' node is never reused. */
352 return (ISC_R_NOTFOUND);
353 }
354
355 mctx = ecdb->common.mctx;
356 node = isc_mem_get(mctx, sizeof(*node));
357 if (node == NULL)
358 return (ISC_R_NOMEMORY);
359
360 result = isc_mutex_init(&node->lock);
361 if (result != ISC_R_SUCCESS) {
362 UNEXPECTED_ERROR(__FILE__, __LINE__,
363 "isc_mutex_init() failed: %s",
364 isc_result_totext(result));
365 isc_mem_put(mctx, node, sizeof(*node));
366 return (ISC_R_UNEXPECTED);
367 }
368
369 dns_name_init(&node->name, NULL);
370 result = dns_name_dup(name, mctx, &node->name);
371 if (result != ISC_R_SUCCESS) {
372 DESTROYLOCK(&node->lock);
373 isc_mem_put(mctx, node, sizeof(*node));
374 return (result);
375 }
376 node->ecdb= ecdb;
377 node->references = 1;
378 ISC_LIST_INIT(node->rdatasets);
379
380 ISC_LINK_INIT(node, link);
381
382 LOCK(&ecdb->lock);
383 ISC_LIST_APPEND(ecdb->nodes, node, link);
384 UNLOCK(&ecdb->lock);
385
386 node->magic = ECDBNODE_MAGIC;
387
388 *nodep = node;
389
390 return (ISC_R_SUCCESS);
391 }
392
393 static void
bind_rdataset(dns_ecdb_t * ecdb,dns_ecdbnode_t * node,rdatasetheader_t * header,dns_rdataset_t * rdataset)394 bind_rdataset(dns_ecdb_t *ecdb, dns_ecdbnode_t *node,
395 rdatasetheader_t *header, dns_rdataset_t *rdataset)
396 {
397 unsigned char *raw;
398
399 /*
400 * Caller must be holding the node lock.
401 */
402
403 REQUIRE(!dns_rdataset_isassociated(rdataset));
404
405 rdataset->methods = &rdataset_methods;
406 rdataset->rdclass = ecdb->common.rdclass;
407 rdataset->type = header->type;
408 rdataset->covers = header->covers;
409 rdataset->ttl = header->ttl;
410 rdataset->trust = header->trust;
411 if (NXDOMAIN(header))
412 rdataset->attributes |= DNS_RDATASETATTR_NXDOMAIN;
413 if (NEGATIVE(header))
414 rdataset->attributes |= DNS_RDATASETATTR_NEGATIVE;
415
416 rdataset->private1 = ecdb;
417 rdataset->private2 = node;
418 raw = (unsigned char *)header + sizeof(*header);
419 rdataset->private3 = raw;
420 rdataset->count = 0;
421
422 /*
423 * Reset iterator state.
424 */
425 rdataset->privateuint4 = 0;
426 rdataset->private5 = NULL;
427
428 INSIST(node->references > 0);
429 node->references++;
430 }
431
432 static isc_result_t
addrdataset(dns_db_t * db,dns_dbnode_t * node,dns_dbversion_t * version,isc_stdtime_t now,dns_rdataset_t * rdataset,unsigned int options,dns_rdataset_t * addedrdataset)433 addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
434 isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
435 dns_rdataset_t *addedrdataset)
436 {
437 dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
438 isc_region_t r;
439 isc_result_t result = ISC_R_SUCCESS;
440 isc_mem_t *mctx;
441 dns_ecdbnode_t *ecdbnode = (dns_ecdbnode_t *)node;
442 rdatasetheader_t *header;
443
444 REQUIRE(VALID_ECDB(ecdb));
445 REQUIRE(VALID_ECDBNODE(ecdbnode));
446
447 UNUSED(version);
448 UNUSED(now);
449 UNUSED(options);
450
451 mctx = ecdb->common.mctx;
452
453 LOCK(&ecdbnode->lock);
454
455 /*
456 * Sanity check: this implementation does not allow overriding an
457 * existing rdataset of the same type.
458 */
459 for (header = ISC_LIST_HEAD(ecdbnode->rdatasets); header != NULL;
460 header = ISC_LIST_NEXT(header, link)) {
461 INSIST(header->type != rdataset->type ||
462 header->covers != rdataset->covers);
463 }
464
465 result = dns_rdataslab_fromrdataset(rdataset, mctx,
466 &r, sizeof(rdatasetheader_t));
467 if (result != ISC_R_SUCCESS)
468 goto unlock;
469
470 header = (rdatasetheader_t *)r.base;
471 header->type = rdataset->type;
472 header->ttl = rdataset->ttl;
473 header->trust = rdataset->trust;
474 header->covers = rdataset->covers;
475 header->attributes = 0;
476 if ((rdataset->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
477 header->attributes |= RDATASET_ATTR_NXDOMAIN;
478 if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0)
479 header->attributes |= RDATASET_ATTR_NEGATIVE;
480 ISC_LINK_INIT(header, link);
481 ISC_LIST_APPEND(ecdbnode->rdatasets, header, link);
482
483 if (addedrdataset == NULL)
484 goto unlock;
485
486 bind_rdataset(ecdb, ecdbnode, header, addedrdataset);
487
488 unlock:
489 UNLOCK(&ecdbnode->lock);
490
491 return (result);
492 }
493
494 static isc_result_t
deleterdataset(dns_db_t * db,dns_dbnode_t * node,dns_dbversion_t * version,dns_rdatatype_t type,dns_rdatatype_t covers)495 deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
496 dns_rdatatype_t type, dns_rdatatype_t covers)
497 {
498 UNUSED(db);
499 UNUSED(node);
500 UNUSED(version);
501 UNUSED(type);
502 UNUSED(covers);
503
504 return (ISC_R_NOTIMPLEMENTED);
505 }
506
507 static isc_result_t
createiterator(dns_db_t * db,unsigned int options,dns_dbiterator_t ** iteratorp)508 createiterator(dns_db_t *db, unsigned int options,
509 dns_dbiterator_t **iteratorp)
510 {
511 UNUSED(db);
512 UNUSED(options);
513 UNUSED(iteratorp);
514
515 return (ISC_R_NOTIMPLEMENTED);
516 }
517
518 static isc_result_t
allrdatasets(dns_db_t * db,dns_dbnode_t * node,dns_dbversion_t * version,isc_stdtime_t now,dns_rdatasetiter_t ** iteratorp)519 allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
520 isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
521 {
522 dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
523 dns_ecdbnode_t *ecdbnode = (dns_ecdbnode_t *)node;
524 isc_mem_t *mctx;
525 ecdb_rdatasetiter_t *iterator;
526
527 REQUIRE(VALID_ECDB(ecdb));
528 REQUIRE(VALID_ECDBNODE(ecdbnode));
529
530 mctx = ecdb->common.mctx;
531
532 iterator = isc_mem_get(mctx, sizeof(ecdb_rdatasetiter_t));
533 if (iterator == NULL)
534 return (ISC_R_NOMEMORY);
535
536 iterator->common.magic = DNS_RDATASETITER_MAGIC;
537 iterator->common.methods = &rdatasetiter_methods;
538 iterator->common.db = db;
539 iterator->common.node = NULL;
540 attachnode(db, node, &iterator->common.node);
541 iterator->common.version = version;
542 iterator->common.now = now;
543
544 *iteratorp = (dns_rdatasetiter_t *)iterator;
545
546 return (ISC_R_SUCCESS);
547 }
548
549 static dns_dbmethods_t ecdb_methods = {
550 attach,
551 detach,
552 NULL, /* beginload */
553 NULL, /* endload */
554 NULL, /* serialize */
555 NULL, /* dump */
556 NULL, /* currentversion */
557 NULL, /* newversion */
558 NULL, /* attachversion */
559 NULL, /* closeversion */
560 findnode,
561 find,
562 findzonecut,
563 attachnode,
564 detachnode,
565 NULL, /* expirenode */
566 NULL, /* printnode */
567 createiterator, /* createiterator */
568 NULL, /* findrdataset */
569 allrdatasets,
570 addrdataset,
571 NULL, /* subtractrdataset */
572 deleterdataset,
573 NULL, /* issecure */
574 NULL, /* nodecount */
575 NULL, /* ispersistent */
576 NULL, /* overmem */
577 NULL, /* settask */
578 NULL, /* getoriginnode */
579 NULL, /* transfernode */
580 NULL, /* getnsec3parameters */
581 NULL, /* findnsec3node */
582 NULL, /* setsigningtime */
583 NULL, /* getsigningtime */
584 NULL, /* resigned */
585 NULL, /* isdnssec */
586 NULL, /* getrrsetstats */
587 NULL, /* rpz_attach */
588 NULL, /* rpz_ready */
589 NULL, /* findnodeext */
590 NULL, /* findext */
591 NULL, /* setcachestats */
592 NULL /* hashsize */
593 };
594
595 static isc_result_t
dns_ecdb_create(isc_mem_t * mctx,dns_name_t * origin,dns_dbtype_t type,dns_rdataclass_t rdclass,unsigned int argc,char * argv[],void * driverarg,dns_db_t ** dbp)596 dns_ecdb_create(isc_mem_t *mctx, dns_name_t *origin, dns_dbtype_t type,
597 dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
598 void *driverarg, dns_db_t **dbp)
599 {
600 dns_ecdb_t *ecdb;
601 isc_result_t result;
602
603 REQUIRE(mctx != NULL);
604 REQUIRE(origin == dns_rootname);
605 REQUIRE(type == dns_dbtype_cache);
606 REQUIRE(dbp != NULL && *dbp == NULL);
607
608 UNUSED(argc);
609 UNUSED(argv);
610 UNUSED(driverarg);
611
612 ecdb = isc_mem_get(mctx, sizeof(*ecdb));
613 if (ecdb == NULL)
614 return (ISC_R_NOMEMORY);
615
616 ecdb->common.attributes = DNS_DBATTR_CACHE;
617 ecdb->common.rdclass = rdclass;
618 ecdb->common.methods = &ecdb_methods;
619 dns_name_init(&ecdb->common.origin, NULL);
620 result = dns_name_dupwithoffsets(origin, mctx, &ecdb->common.origin);
621 if (result != ISC_R_SUCCESS) {
622 isc_mem_put(mctx, ecdb, sizeof(*ecdb));
623 return (result);
624 }
625
626 result = isc_mutex_init(&ecdb->lock);
627 if (result != ISC_R_SUCCESS) {
628 UNEXPECTED_ERROR(__FILE__, __LINE__,
629 "isc_mutex_init() failed: %s",
630 isc_result_totext(result));
631 if (dns_name_dynamic(&ecdb->common.origin))
632 dns_name_free(&ecdb->common.origin, mctx);
633 isc_mem_put(mctx, ecdb, sizeof(*ecdb));
634 return (ISC_R_UNEXPECTED);
635 }
636
637 ecdb->references = 1;
638 ISC_LIST_INIT(ecdb->nodes);
639
640 ecdb->common.mctx = NULL;
641 isc_mem_attach(mctx, &ecdb->common.mctx);
642 ecdb->common.impmagic = ECDB_MAGIC;
643 ecdb->common.magic = DNS_DB_MAGIC;
644
645 *dbp = (dns_db_t *)ecdb;
646
647 return (ISC_R_SUCCESS);
648 }
649
650 /*%
651 * Rdataset Methods
652 */
653
654 static void
rdataset_disassociate(dns_rdataset_t * rdataset)655 rdataset_disassociate(dns_rdataset_t *rdataset) {
656 dns_db_t *db = rdataset->private1;
657 dns_dbnode_t *node = rdataset->private2;
658
659 dns_db_detachnode(db, &node);
660 }
661
662 static isc_result_t
rdataset_first(dns_rdataset_t * rdataset)663 rdataset_first(dns_rdataset_t *rdataset) {
664 unsigned char *raw = rdataset->private3;
665 unsigned int count;
666
667 count = raw[0] * 256 + raw[1];
668 if (count == 0) {
669 rdataset->private5 = NULL;
670 return (ISC_R_NOMORE);
671 }
672 #if DNS_RDATASET_FIXED
673 raw += 2 + (4 * count);
674 #else
675 raw += 2;
676 #endif
677 /*
678 * The privateuint4 field is the number of rdata beyond the cursor
679 * position, so we decrement the total count by one before storing
680 * it.
681 */
682 count--;
683 rdataset->privateuint4 = count;
684 rdataset->private5 = raw;
685
686 return (ISC_R_SUCCESS);
687 }
688
689 static isc_result_t
rdataset_next(dns_rdataset_t * rdataset)690 rdataset_next(dns_rdataset_t *rdataset) {
691 unsigned int count;
692 unsigned int length;
693 unsigned char *raw;
694
695 count = rdataset->privateuint4;
696 if (count == 0)
697 return (ISC_R_NOMORE);
698 count--;
699 rdataset->privateuint4 = count;
700 raw = rdataset->private5;
701 length = raw[0] * 256 + raw[1];
702 #if DNS_RDATASET_FIXED
703 raw += length + 4;
704 #else
705 raw += length + 2;
706 #endif
707 rdataset->private5 = raw;
708
709 return (ISC_R_SUCCESS);
710 }
711
712 static void
rdataset_current(dns_rdataset_t * rdataset,dns_rdata_t * rdata)713 rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
714 unsigned char *raw = rdataset->private5;
715 isc_region_t r;
716 unsigned int length;
717 unsigned int flags = 0;
718
719 REQUIRE(raw != NULL);
720
721 length = raw[0] * 256 + raw[1];
722 #if DNS_RDATASET_FIXED
723 raw += 4;
724 #else
725 raw += 2;
726 #endif
727 if (rdataset->type == dns_rdatatype_rrsig) {
728 if (*raw & DNS_RDATASLAB_OFFLINE)
729 flags |= DNS_RDATA_OFFLINE;
730 length--;
731 raw++;
732 }
733 r.length = length;
734 r.base = raw;
735 dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
736 rdata->flags |= flags;
737 }
738
739 static void
rdataset_clone(dns_rdataset_t * source,dns_rdataset_t * target)740 rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
741 dns_db_t *db = source->private1;
742 dns_dbnode_t *node = source->private2;
743 dns_dbnode_t *cloned_node = NULL;
744
745 attachnode(db, node, &cloned_node);
746 *target = *source;
747
748 /*
749 * Reset iterator state.
750 */
751 target->privateuint4 = 0;
752 target->private5 = NULL;
753 }
754
755 static unsigned int
rdataset_count(dns_rdataset_t * rdataset)756 rdataset_count(dns_rdataset_t *rdataset) {
757 unsigned char *raw = rdataset->private3;
758 unsigned int count;
759
760 count = raw[0] * 256 + raw[1];
761
762 return (count);
763 }
764
765 static void
rdataset_settrust(dns_rdataset_t * rdataset,dns_trust_t trust)766 rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) {
767 rdatasetheader_t *header = rdataset->private3;
768
769 header--;
770 header->trust = rdataset->trust = trust;
771 }
772
773 /*
774 * Rdataset Iterator Methods
775 */
776
777 static void
rdatasetiter_destroy(dns_rdatasetiter_t ** iteratorp)778 rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
779 isc_mem_t *mctx;
780 union {
781 dns_rdatasetiter_t *rdatasetiterator;
782 ecdb_rdatasetiter_t *ecdbiterator;
783 } u;
784
785 REQUIRE(iteratorp != NULL);
786 REQUIRE(DNS_RDATASETITER_VALID(*iteratorp));
787
788 u.rdatasetiterator = *iteratorp;
789
790 mctx = u.ecdbiterator->common.db->mctx;
791 u.ecdbiterator->common.magic = 0;
792
793 dns_db_detachnode(u.ecdbiterator->common.db,
794 &u.ecdbiterator->common.node);
795 isc_mem_put(mctx, u.ecdbiterator,
796 sizeof(ecdb_rdatasetiter_t));
797
798 *iteratorp = NULL;
799 }
800
801 static isc_result_t
rdatasetiter_first(dns_rdatasetiter_t * iterator)802 rdatasetiter_first(dns_rdatasetiter_t *iterator) {
803 ecdb_rdatasetiter_t *ecdbiterator = (ecdb_rdatasetiter_t *)iterator;
804 dns_ecdbnode_t *ecdbnode = (dns_ecdbnode_t *)iterator->node;
805
806 REQUIRE(DNS_RDATASETITER_VALID(iterator));
807
808 if (ISC_LIST_EMPTY(ecdbnode->rdatasets))
809 return (ISC_R_NOMORE);
810 ecdbiterator->current = ISC_LIST_HEAD(ecdbnode->rdatasets);
811 return (ISC_R_SUCCESS);
812 }
813
814 static isc_result_t
rdatasetiter_next(dns_rdatasetiter_t * iterator)815 rdatasetiter_next(dns_rdatasetiter_t *iterator) {
816 ecdb_rdatasetiter_t *ecdbiterator = (ecdb_rdatasetiter_t *)iterator;
817
818 REQUIRE(DNS_RDATASETITER_VALID(iterator));
819
820 ecdbiterator->current = ISC_LIST_NEXT(ecdbiterator->current, link);
821 if (ecdbiterator->current == NULL)
822 return (ISC_R_NOMORE);
823 else
824 return (ISC_R_SUCCESS);
825 }
826
827 static void
rdatasetiter_current(dns_rdatasetiter_t * iterator,dns_rdataset_t * rdataset)828 rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) {
829 ecdb_rdatasetiter_t *ecdbiterator = (ecdb_rdatasetiter_t *)iterator;
830 dns_ecdb_t *ecdb;
831
832 ecdb = (dns_ecdb_t *)iterator->db;
833 REQUIRE(VALID_ECDB(ecdb));
834
835 bind_rdataset(ecdb, iterator->node, ecdbiterator->current, rdataset);
836 }
837