ecdb.c revision 234010
1224090Sdougb/* 2234010Sdougb * Copyright (C) 2009-2012 Internet Systems Consortium, Inc. ("ISC") 3224090Sdougb * 4224090Sdougb * Permission to use, copy, modify, and/or distribute this software for any 5224090Sdougb * purpose with or without fee is hereby granted, provided that the above 6224090Sdougb * copyright notice and this permission notice appear in all copies. 7224090Sdougb * 8224090Sdougb * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 9224090Sdougb * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10224090Sdougb * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 11224090Sdougb * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12224090Sdougb * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13224090Sdougb * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14224090Sdougb * PERFORMANCE OF THIS SOFTWARE. 15224090Sdougb */ 16224090Sdougb 17234010Sdougb/* $Id$ */ 18224090Sdougb 19224090Sdougb#include "config.h" 20224090Sdougb 21224090Sdougb#include <isc/result.h> 22224090Sdougb#include <isc/util.h> 23224090Sdougb#include <isc/mutex.h> 24224090Sdougb#include <isc/mem.h> 25224090Sdougb 26224090Sdougb#include <dns/db.h> 27224090Sdougb#include <dns/ecdb.h> 28224090Sdougb#include <dns/rdata.h> 29224090Sdougb#include <dns/rdataset.h> 30224090Sdougb#include <dns/rdatasetiter.h> 31224090Sdougb#include <dns/rdataslab.h> 32224090Sdougb 33224090Sdougb#define ECDB_MAGIC ISC_MAGIC('E', 'C', 'D', 'B') 34224090Sdougb#define VALID_ECDB(db) ((db) != NULL && \ 35224090Sdougb (db)->common.impmagic == ECDB_MAGIC) 36224090Sdougb 37224090Sdougb#define ECDBNODE_MAGIC ISC_MAGIC('E', 'C', 'D', 'N') 38224090Sdougb#define VALID_ECDBNODE(ecdbn) ISC_MAGIC_VALID(ecdbn, ECDBNODE_MAGIC) 39224090Sdougb 40224090Sdougb/*% 41224090Sdougb * The 'ephemeral' cache DB (ecdb) implementation. An ecdb just provides 42224090Sdougb * temporary storage for ongoing name resolution with the common DB interfaces. 43224090Sdougb * It actually doesn't cache anything. The implementation expects any stored 44224090Sdougb * data is released within a short period, and does not care about the 45224090Sdougb * scalability in terms of the number of nodes. 46224090Sdougb */ 47224090Sdougb 48224090Sdougbtypedef struct dns_ecdb { 49224090Sdougb /* Unlocked */ 50224090Sdougb dns_db_t common; 51224090Sdougb isc_mutex_t lock; 52224090Sdougb 53224090Sdougb /* Locked */ 54224090Sdougb unsigned int references; 55224090Sdougb ISC_LIST(struct dns_ecdbnode) nodes; 56224090Sdougb} dns_ecdb_t; 57224090Sdougb 58224090Sdougbtypedef struct dns_ecdbnode { 59224090Sdougb /* Unlocked */ 60224090Sdougb unsigned int magic; 61224090Sdougb isc_mutex_t lock; 62224090Sdougb dns_ecdb_t *ecdb; 63224090Sdougb dns_name_t name; 64224090Sdougb ISC_LINK(struct dns_ecdbnode) link; 65224090Sdougb 66224090Sdougb /* Locked */ 67224090Sdougb ISC_LIST(struct rdatasetheader) rdatasets; 68224090Sdougb unsigned int references; 69224090Sdougb} dns_ecdbnode_t; 70224090Sdougb 71224090Sdougbtypedef struct rdatasetheader { 72224090Sdougb dns_rdatatype_t type; 73224090Sdougb dns_ttl_t ttl; 74224090Sdougb dns_trust_t trust; 75224090Sdougb dns_rdatatype_t covers; 76224090Sdougb unsigned int attributes; 77224090Sdougb 78224090Sdougb ISC_LINK(struct rdatasetheader) link; 79224090Sdougb} rdatasetheader_t; 80224090Sdougb 81224090Sdougb/* Copied from rbtdb.c */ 82224090Sdougb#define RDATASET_ATTR_NXDOMAIN 0x0010 83224090Sdougb#define NXDOMAIN(header) \ 84224090Sdougb (((header)->attributes & RDATASET_ATTR_NXDOMAIN) != 0) 85224090Sdougb 86224090Sdougbstatic isc_result_t dns_ecdb_create(isc_mem_t *mctx, dns_name_t *origin, 87224090Sdougb dns_dbtype_t type, 88224090Sdougb dns_rdataclass_t rdclass, 89224090Sdougb unsigned int argc, char *argv[], 90224090Sdougb void *driverarg, dns_db_t **dbp); 91224090Sdougb 92224090Sdougbstatic void rdataset_disassociate(dns_rdataset_t *rdataset); 93224090Sdougbstatic isc_result_t rdataset_first(dns_rdataset_t *rdataset); 94224090Sdougbstatic isc_result_t rdataset_next(dns_rdataset_t *rdataset); 95224090Sdougbstatic void rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata); 96224090Sdougbstatic void rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target); 97224090Sdougbstatic unsigned int rdataset_count(dns_rdataset_t *rdataset); 98224090Sdougbstatic void rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust); 99224090Sdougb 100224090Sdougbstatic dns_rdatasetmethods_t rdataset_methods = { 101224090Sdougb rdataset_disassociate, 102224090Sdougb rdataset_first, 103224090Sdougb rdataset_next, 104224090Sdougb rdataset_current, 105224090Sdougb rdataset_clone, 106224090Sdougb rdataset_count, 107224090Sdougb NULL, /* addnoqname */ 108224090Sdougb NULL, /* getnoqname */ 109224090Sdougb NULL, /* addclosest */ 110224090Sdougb NULL, /* getclosest */ 111224090Sdougb NULL, /* getadditional */ 112224090Sdougb NULL, /* setadditional */ 113224090Sdougb NULL, /* putadditional */ 114224090Sdougb rdataset_settrust, /* settrust */ 115224090Sdougb NULL /* expire */ 116224090Sdougb}; 117224090Sdougb 118224090Sdougbtypedef struct ecdb_rdatasetiter { 119224090Sdougb dns_rdatasetiter_t common; 120224090Sdougb rdatasetheader_t *current; 121224090Sdougb} ecdb_rdatasetiter_t; 122224090Sdougb 123224090Sdougbstatic void rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp); 124224090Sdougbstatic isc_result_t rdatasetiter_first(dns_rdatasetiter_t *iterator); 125224090Sdougbstatic isc_result_t rdatasetiter_next(dns_rdatasetiter_t *iterator); 126224090Sdougbstatic void rdatasetiter_current(dns_rdatasetiter_t *iterator, 127224090Sdougb dns_rdataset_t *rdataset); 128224090Sdougb 129224090Sdougbstatic dns_rdatasetitermethods_t rdatasetiter_methods = { 130224090Sdougb rdatasetiter_destroy, 131224090Sdougb rdatasetiter_first, 132224090Sdougb rdatasetiter_next, 133224090Sdougb rdatasetiter_current 134224090Sdougb}; 135224090Sdougb 136224090Sdougbisc_result_t 137224090Sdougbdns_ecdb_register(isc_mem_t *mctx, dns_dbimplementation_t **dbimp) { 138224090Sdougb REQUIRE(mctx != NULL); 139224090Sdougb REQUIRE(dbimp != NULL && *dbimp == NULL); 140224090Sdougb 141224090Sdougb return (dns_db_register("ecdb", dns_ecdb_create, NULL, mctx, dbimp)); 142224090Sdougb} 143224090Sdougb 144224090Sdougbvoid 145224090Sdougbdns_ecdb_unregister(dns_dbimplementation_t **dbimp) { 146224090Sdougb REQUIRE(dbimp != NULL && *dbimp != NULL); 147224090Sdougb 148224090Sdougb dns_db_unregister(dbimp); 149224090Sdougb} 150224090Sdougb 151224090Sdougb/*% 152224090Sdougb * DB routines 153224090Sdougb */ 154224090Sdougb 155224090Sdougbstatic void 156224090Sdougbattach(dns_db_t *source, dns_db_t **targetp) { 157224090Sdougb dns_ecdb_t *ecdb = (dns_ecdb_t *)source; 158224090Sdougb 159224090Sdougb REQUIRE(VALID_ECDB(ecdb)); 160224090Sdougb REQUIRE(targetp != NULL && *targetp == NULL); 161224090Sdougb 162224090Sdougb LOCK(&ecdb->lock); 163224090Sdougb ecdb->references++; 164224090Sdougb UNLOCK(&ecdb->lock); 165224090Sdougb 166224090Sdougb *targetp = source; 167224090Sdougb} 168224090Sdougb 169224090Sdougbstatic void 170224090Sdougbdestroy_ecdb(dns_ecdb_t **ecdbp) { 171224090Sdougb dns_ecdb_t *ecdb = *ecdbp; 172224090Sdougb isc_mem_t *mctx = ecdb->common.mctx; 173224090Sdougb 174224090Sdougb if (dns_name_dynamic(&ecdb->common.origin)) 175224090Sdougb dns_name_free(&ecdb->common.origin, mctx); 176224090Sdougb 177224090Sdougb DESTROYLOCK(&ecdb->lock); 178224090Sdougb 179224090Sdougb ecdb->common.impmagic = 0; 180224090Sdougb ecdb->common.magic = 0; 181224090Sdougb 182224090Sdougb isc_mem_putanddetach(&mctx, ecdb, sizeof(*ecdb)); 183224090Sdougb 184224090Sdougb *ecdbp = NULL; 185224090Sdougb} 186224090Sdougb 187224090Sdougbstatic void 188224090Sdougbdetach(dns_db_t **dbp) { 189224090Sdougb dns_ecdb_t *ecdb; 190224090Sdougb isc_boolean_t need_destroy = ISC_FALSE; 191224090Sdougb 192224090Sdougb REQUIRE(dbp != NULL); 193224090Sdougb ecdb = (dns_ecdb_t *)*dbp; 194224090Sdougb REQUIRE(VALID_ECDB(ecdb)); 195224090Sdougb 196224090Sdougb LOCK(&ecdb->lock); 197224090Sdougb ecdb->references--; 198224090Sdougb if (ecdb->references == 0 && ISC_LIST_EMPTY(ecdb->nodes)) 199224090Sdougb need_destroy = ISC_TRUE; 200224090Sdougb UNLOCK(&ecdb->lock); 201224090Sdougb 202224090Sdougb if (need_destroy) 203224090Sdougb destroy_ecdb(&ecdb); 204224090Sdougb 205224090Sdougb *dbp = NULL; 206224090Sdougb} 207224090Sdougb 208224090Sdougbstatic void 209224090Sdougbattachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) { 210224090Sdougb dns_ecdb_t *ecdb = (dns_ecdb_t *)db; 211224090Sdougb dns_ecdbnode_t *node = (dns_ecdbnode_t *)source; 212224090Sdougb 213224090Sdougb REQUIRE(VALID_ECDB(ecdb)); 214224090Sdougb REQUIRE(VALID_ECDBNODE(node)); 215224090Sdougb REQUIRE(targetp != NULL && *targetp == NULL); 216224090Sdougb 217224090Sdougb LOCK(&node->lock); 218224090Sdougb INSIST(node->references > 0); 219224090Sdougb node->references++; 220224090Sdougb INSIST(node->references != 0); /* Catch overflow. */ 221224090Sdougb UNLOCK(&node->lock); 222224090Sdougb 223224090Sdougb *targetp = node; 224224090Sdougb} 225224090Sdougb 226224090Sdougbstatic void 227224090Sdougbdestroynode(dns_ecdbnode_t *node) { 228224090Sdougb isc_mem_t *mctx; 229224090Sdougb dns_ecdb_t *ecdb = node->ecdb; 230224090Sdougb isc_boolean_t need_destroydb = ISC_FALSE; 231224090Sdougb rdatasetheader_t *header; 232224090Sdougb 233224090Sdougb mctx = ecdb->common.mctx; 234224090Sdougb 235224090Sdougb LOCK(&ecdb->lock); 236224090Sdougb ISC_LIST_UNLINK(ecdb->nodes, node, link); 237224090Sdougb if (ecdb->references == 0 && ISC_LIST_EMPTY(ecdb->nodes)) 238224090Sdougb need_destroydb = ISC_TRUE; 239224090Sdougb UNLOCK(&ecdb->lock); 240224090Sdougb 241224090Sdougb dns_name_free(&node->name, mctx); 242224090Sdougb 243224090Sdougb while ((header = ISC_LIST_HEAD(node->rdatasets)) != NULL) { 244224090Sdougb unsigned int headersize; 245224090Sdougb 246224090Sdougb ISC_LIST_UNLINK(node->rdatasets, header, link); 247224090Sdougb headersize = 248224090Sdougb dns_rdataslab_size((unsigned char *)header, 249224090Sdougb sizeof(*header)); 250224090Sdougb isc_mem_put(mctx, header, headersize); 251224090Sdougb } 252224090Sdougb 253224090Sdougb DESTROYLOCK(&node->lock); 254224090Sdougb 255224090Sdougb node->magic = 0; 256224090Sdougb isc_mem_put(mctx, node, sizeof(*node)); 257224090Sdougb 258224090Sdougb if (need_destroydb) 259224090Sdougb destroy_ecdb(&ecdb); 260224090Sdougb} 261224090Sdougb 262224090Sdougbstatic void 263224090Sdougbdetachnode(dns_db_t *db, dns_dbnode_t **nodep) { 264224090Sdougb dns_ecdb_t *ecdb = (dns_ecdb_t *)db; 265224090Sdougb dns_ecdbnode_t *node; 266224090Sdougb isc_boolean_t need_destroy = ISC_FALSE; 267224090Sdougb 268224090Sdougb REQUIRE(VALID_ECDB(ecdb)); 269224090Sdougb REQUIRE(nodep != NULL); 270224090Sdougb node = (dns_ecdbnode_t *)*nodep; 271224090Sdougb REQUIRE(VALID_ECDBNODE(node)); 272224090Sdougb 273224090Sdougb UNUSED(ecdb); /* in case REQUIRE() is empty */ 274224090Sdougb 275224090Sdougb LOCK(&node->lock); 276224090Sdougb INSIST(node->references > 0); 277224090Sdougb node->references--; 278224090Sdougb if (node->references == 0) 279224090Sdougb need_destroy = ISC_TRUE; 280224090Sdougb UNLOCK(&node->lock); 281224090Sdougb 282224090Sdougb if (need_destroy) 283224090Sdougb destroynode(node); 284224090Sdougb 285224090Sdougb *nodep = NULL; 286224090Sdougb} 287224090Sdougb 288224090Sdougbstatic isc_result_t 289224090Sdougbfind(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, 290224090Sdougb dns_rdatatype_t type, unsigned int options, isc_stdtime_t now, 291224090Sdougb dns_dbnode_t **nodep, dns_name_t *foundname, dns_rdataset_t *rdataset, 292224090Sdougb dns_rdataset_t *sigrdataset) 293224090Sdougb{ 294224090Sdougb dns_ecdb_t *ecdb = (dns_ecdb_t *)db; 295224090Sdougb 296224090Sdougb REQUIRE(VALID_ECDB(ecdb)); 297224090Sdougb 298224090Sdougb UNUSED(name); 299224090Sdougb UNUSED(version); 300224090Sdougb UNUSED(type); 301224090Sdougb UNUSED(options); 302224090Sdougb UNUSED(now); 303224090Sdougb UNUSED(nodep); 304224090Sdougb UNUSED(foundname); 305224090Sdougb UNUSED(rdataset); 306224090Sdougb UNUSED(sigrdataset); 307224090Sdougb 308224090Sdougb return (ISC_R_NOTFOUND); 309224090Sdougb} 310224090Sdougb 311224090Sdougbstatic isc_result_t 312224090Sdougbfindzonecut(dns_db_t *db, dns_name_t *name, 313224090Sdougb unsigned int options, isc_stdtime_t now, 314224090Sdougb dns_dbnode_t **nodep, dns_name_t *foundname, 315224090Sdougb dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) 316224090Sdougb{ 317224090Sdougb dns_ecdb_t *ecdb = (dns_ecdb_t *)db; 318224090Sdougb 319224090Sdougb REQUIRE(VALID_ECDB(ecdb)); 320224090Sdougb 321224090Sdougb UNUSED(name); 322224090Sdougb UNUSED(options); 323224090Sdougb UNUSED(now); 324224090Sdougb UNUSED(nodep); 325224090Sdougb UNUSED(foundname); 326224090Sdougb UNUSED(rdataset); 327224090Sdougb UNUSED(sigrdataset); 328224090Sdougb 329224090Sdougb return (ISC_R_NOTFOUND); 330224090Sdougb} 331224090Sdougb 332224090Sdougbstatic isc_result_t 333224090Sdougbfindnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create, 334224090Sdougb dns_dbnode_t **nodep) 335224090Sdougb{ 336224090Sdougb dns_ecdb_t *ecdb = (dns_ecdb_t *)db; 337224090Sdougb isc_mem_t *mctx; 338224090Sdougb dns_ecdbnode_t *node; 339224090Sdougb isc_result_t result; 340224090Sdougb 341224090Sdougb REQUIRE(VALID_ECDB(ecdb)); 342224090Sdougb REQUIRE(nodep != NULL && *nodep == NULL); 343224090Sdougb 344224090Sdougb UNUSED(name); 345224090Sdougb 346224090Sdougb if (create != ISC_TRUE) { 347224090Sdougb /* an 'ephemeral' node is never reused. */ 348224090Sdougb return (ISC_R_NOTFOUND); 349224090Sdougb } 350224090Sdougb 351224090Sdougb mctx = ecdb->common.mctx; 352224090Sdougb node = isc_mem_get(mctx, sizeof(*node)); 353224090Sdougb if (node == NULL) 354224090Sdougb return (ISC_R_NOMEMORY); 355224090Sdougb 356224090Sdougb result = isc_mutex_init(&node->lock); 357224090Sdougb if (result != ISC_R_SUCCESS) { 358224090Sdougb UNEXPECTED_ERROR(__FILE__, __LINE__, 359224090Sdougb "isc_mutex_init() failed: %s", 360224090Sdougb isc_result_totext(result)); 361224090Sdougb isc_mem_put(mctx, node, sizeof(*node)); 362224090Sdougb return (ISC_R_UNEXPECTED); 363224090Sdougb } 364224090Sdougb 365224090Sdougb dns_name_init(&node->name, NULL); 366224090Sdougb result = dns_name_dup(name, mctx, &node->name); 367224090Sdougb if (result != ISC_R_SUCCESS) { 368224090Sdougb DESTROYLOCK(&node->lock); 369224090Sdougb isc_mem_put(mctx, node, sizeof(*node)); 370224090Sdougb return (result); 371224090Sdougb } 372224090Sdougb node->ecdb= ecdb; 373224090Sdougb node->references = 1; 374224090Sdougb ISC_LIST_INIT(node->rdatasets); 375224090Sdougb 376224090Sdougb ISC_LINK_INIT(node, link); 377224090Sdougb 378224090Sdougb LOCK(&ecdb->lock); 379224090Sdougb ISC_LIST_APPEND(ecdb->nodes, node, link); 380224090Sdougb UNLOCK(&ecdb->lock); 381224090Sdougb 382224090Sdougb node->magic = ECDBNODE_MAGIC; 383224090Sdougb 384224090Sdougb *nodep = node; 385224090Sdougb 386224090Sdougb return (ISC_R_SUCCESS); 387224090Sdougb} 388224090Sdougb 389224090Sdougbstatic void 390224090Sdougbbind_rdataset(dns_ecdb_t *ecdb, dns_ecdbnode_t *node, 391224090Sdougb rdatasetheader_t *header, dns_rdataset_t *rdataset) 392224090Sdougb{ 393224090Sdougb unsigned char *raw; 394224090Sdougb 395224090Sdougb /* 396224090Sdougb * Caller must be holding the node lock. 397224090Sdougb */ 398224090Sdougb 399224090Sdougb REQUIRE(!dns_rdataset_isassociated(rdataset)); 400224090Sdougb 401224090Sdougb rdataset->methods = &rdataset_methods; 402224090Sdougb rdataset->rdclass = ecdb->common.rdclass; 403224090Sdougb rdataset->type = header->type; 404224090Sdougb rdataset->covers = header->covers; 405224090Sdougb rdataset->ttl = header->ttl; 406224090Sdougb rdataset->trust = header->trust; 407224090Sdougb if (NXDOMAIN(header)) 408224090Sdougb rdataset->attributes |= DNS_RDATASETATTR_NXDOMAIN; 409224090Sdougb 410224090Sdougb rdataset->private1 = ecdb; 411224090Sdougb rdataset->private2 = node; 412224090Sdougb raw = (unsigned char *)header + sizeof(*header); 413224090Sdougb rdataset->private3 = raw; 414224090Sdougb rdataset->count = 0; 415224090Sdougb 416224090Sdougb /* 417224090Sdougb * Reset iterator state. 418224090Sdougb */ 419224090Sdougb rdataset->privateuint4 = 0; 420224090Sdougb rdataset->private5 = NULL; 421224090Sdougb 422224090Sdougb INSIST(node->references > 0); 423224090Sdougb node->references++; 424224090Sdougb} 425224090Sdougb 426224090Sdougbstatic isc_result_t 427224090Sdougbaddrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, 428224090Sdougb isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options, 429224090Sdougb dns_rdataset_t *addedrdataset) 430224090Sdougb{ 431224090Sdougb dns_ecdb_t *ecdb = (dns_ecdb_t *)db; 432224090Sdougb isc_region_t r; 433224090Sdougb isc_result_t result = ISC_R_SUCCESS; 434224090Sdougb isc_mem_t *mctx; 435224090Sdougb dns_ecdbnode_t *ecdbnode = (dns_ecdbnode_t *)node; 436224090Sdougb rdatasetheader_t *header; 437224090Sdougb 438224090Sdougb REQUIRE(VALID_ECDB(ecdb)); 439224090Sdougb REQUIRE(VALID_ECDBNODE(ecdbnode)); 440224090Sdougb 441224090Sdougb UNUSED(version); 442224090Sdougb UNUSED(now); 443224090Sdougb UNUSED(options); 444224090Sdougb 445224090Sdougb mctx = ecdb->common.mctx; 446224090Sdougb 447224090Sdougb LOCK(&ecdbnode->lock); 448224090Sdougb 449224090Sdougb /* 450224090Sdougb * Sanity check: this implementation does not allow overriding an 451224090Sdougb * existing rdataset of the same type. 452224090Sdougb */ 453224090Sdougb for (header = ISC_LIST_HEAD(ecdbnode->rdatasets); header != NULL; 454224090Sdougb header = ISC_LIST_NEXT(header, link)) { 455224090Sdougb INSIST(header->type != rdataset->type || 456224090Sdougb header->covers != rdataset->covers); 457224090Sdougb } 458224090Sdougb 459224090Sdougb result = dns_rdataslab_fromrdataset(rdataset, mctx, 460224090Sdougb &r, sizeof(rdatasetheader_t)); 461224090Sdougb if (result != ISC_R_SUCCESS) 462224090Sdougb goto unlock; 463224090Sdougb 464224090Sdougb header = (rdatasetheader_t *)r.base; 465224090Sdougb header->type = rdataset->type; 466224090Sdougb header->ttl = rdataset->ttl; 467224090Sdougb header->trust = rdataset->trust; 468224090Sdougb header->covers = rdataset->covers; 469224090Sdougb header->attributes = 0; 470224090Sdougb if ((rdataset->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0) 471224090Sdougb header->attributes |= RDATASET_ATTR_NXDOMAIN; 472224090Sdougb ISC_LINK_INIT(header, link); 473224090Sdougb ISC_LIST_APPEND(ecdbnode->rdatasets, header, link); 474224090Sdougb 475224090Sdougb if (addedrdataset == NULL) 476224090Sdougb goto unlock; 477224090Sdougb 478224090Sdougb bind_rdataset(ecdb, ecdbnode, header, addedrdataset); 479224090Sdougb 480224090Sdougb unlock: 481224090Sdougb UNLOCK(&ecdbnode->lock); 482224090Sdougb 483224090Sdougb return (result); 484224090Sdougb} 485224090Sdougb 486224090Sdougbstatic isc_result_t 487224090Sdougbdeleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, 488224090Sdougb dns_rdatatype_t type, dns_rdatatype_t covers) 489224090Sdougb{ 490224090Sdougb UNUSED(db); 491224090Sdougb UNUSED(node); 492224090Sdougb UNUSED(version); 493224090Sdougb UNUSED(type); 494224090Sdougb UNUSED(covers); 495224090Sdougb 496224090Sdougb return (ISC_R_NOTIMPLEMENTED); 497224090Sdougb} 498224090Sdougb 499224090Sdougbstatic isc_result_t 500224090Sdougbcreateiterator(dns_db_t *db, unsigned int options, 501224090Sdougb dns_dbiterator_t **iteratorp) 502224090Sdougb{ 503224090Sdougb UNUSED(db); 504224090Sdougb UNUSED(options); 505224090Sdougb UNUSED(iteratorp); 506224090Sdougb 507224090Sdougb return (ISC_R_NOTIMPLEMENTED); 508224090Sdougb} 509224090Sdougb 510224090Sdougbstatic isc_result_t 511224090Sdougballrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, 512224090Sdougb isc_stdtime_t now, dns_rdatasetiter_t **iteratorp) 513224090Sdougb{ 514224090Sdougb dns_ecdb_t *ecdb = (dns_ecdb_t *)db; 515224090Sdougb dns_ecdbnode_t *ecdbnode = (dns_ecdbnode_t *)node; 516224090Sdougb isc_mem_t *mctx; 517224090Sdougb ecdb_rdatasetiter_t *iterator; 518224090Sdougb 519224090Sdougb REQUIRE(VALID_ECDB(ecdb)); 520224090Sdougb REQUIRE(VALID_ECDBNODE(ecdbnode)); 521224090Sdougb 522224090Sdougb mctx = ecdb->common.mctx; 523224090Sdougb 524224090Sdougb iterator = isc_mem_get(mctx, sizeof(ecdb_rdatasetiter_t)); 525224090Sdougb if (iterator == NULL) 526224090Sdougb return (ISC_R_NOMEMORY); 527224090Sdougb 528224090Sdougb iterator->common.magic = DNS_RDATASETITER_MAGIC; 529224090Sdougb iterator->common.methods = &rdatasetiter_methods; 530224090Sdougb iterator->common.db = db; 531224090Sdougb iterator->common.node = NULL; 532224090Sdougb attachnode(db, node, &iterator->common.node); 533224090Sdougb iterator->common.version = version; 534224090Sdougb iterator->common.now = now; 535224090Sdougb 536224090Sdougb *iteratorp = (dns_rdatasetiter_t *)iterator; 537224090Sdougb 538224090Sdougb return (ISC_R_SUCCESS); 539224090Sdougb} 540224090Sdougb 541224090Sdougbstatic dns_dbmethods_t ecdb_methods = { 542224090Sdougb attach, 543224090Sdougb detach, 544224090Sdougb NULL, /* beginload */ 545224090Sdougb NULL, /* endload */ 546224090Sdougb NULL, /* dump */ 547224090Sdougb NULL, /* currentversion */ 548224090Sdougb NULL, /* newversion */ 549224090Sdougb NULL, /* attachversion */ 550224090Sdougb NULL, /* closeversion */ 551224090Sdougb findnode, 552224090Sdougb find, 553224090Sdougb findzonecut, 554224090Sdougb attachnode, 555224090Sdougb detachnode, 556224090Sdougb NULL, /* expirenode */ 557224090Sdougb NULL, /* printnode */ 558224090Sdougb createiterator, /* createiterator */ 559224090Sdougb NULL, /* findrdataset */ 560224090Sdougb allrdatasets, 561224090Sdougb addrdataset, 562224090Sdougb NULL, /* subtractrdataset */ 563224090Sdougb deleterdataset, 564224090Sdougb NULL, /* issecure */ 565224090Sdougb NULL, /* nodecount */ 566224090Sdougb NULL, /* ispersistent */ 567224090Sdougb NULL, /* overmem */ 568224090Sdougb NULL, /* settask */ 569224090Sdougb NULL, /* getoriginnode */ 570224090Sdougb NULL, /* transfernode */ 571224090Sdougb NULL, /* getnsec3parameters */ 572224090Sdougb NULL, /* findnsec3node */ 573224090Sdougb NULL, /* setsigningtime */ 574224090Sdougb NULL, /* getsigningtime */ 575224090Sdougb NULL, /* resigned */ 576224090Sdougb NULL, /* isdnssec */ 577224090Sdougb NULL, /* getrrsetstats */ 578224090Sdougb NULL, /* rpz_enabled */ 579224090Sdougb NULL /* rpz_findips */ 580224090Sdougb}; 581224090Sdougb 582224090Sdougbstatic isc_result_t 583224090Sdougbdns_ecdb_create(isc_mem_t *mctx, dns_name_t *origin, dns_dbtype_t type, 584224090Sdougb dns_rdataclass_t rdclass, unsigned int argc, char *argv[], 585224090Sdougb void *driverarg, dns_db_t **dbp) 586224090Sdougb{ 587224090Sdougb dns_ecdb_t *ecdb; 588224090Sdougb isc_result_t result; 589224090Sdougb 590224090Sdougb REQUIRE(mctx != NULL); 591224090Sdougb REQUIRE(origin == dns_rootname); 592224090Sdougb REQUIRE(type == dns_dbtype_cache); 593224090Sdougb REQUIRE(dbp != NULL && *dbp == NULL); 594224090Sdougb 595224090Sdougb UNUSED(argc); 596224090Sdougb UNUSED(argv); 597224090Sdougb UNUSED(driverarg); 598224090Sdougb 599224090Sdougb ecdb = isc_mem_get(mctx, sizeof(*ecdb)); 600224090Sdougb if (ecdb == NULL) 601224090Sdougb return (ISC_R_NOMEMORY); 602224090Sdougb 603224090Sdougb ecdb->common.attributes = DNS_DBATTR_CACHE; 604224090Sdougb ecdb->common.rdclass = rdclass; 605224090Sdougb ecdb->common.methods = &ecdb_methods; 606224090Sdougb dns_name_init(&ecdb->common.origin, NULL); 607224090Sdougb result = dns_name_dupwithoffsets(origin, mctx, &ecdb->common.origin); 608224090Sdougb if (result != ISC_R_SUCCESS) { 609224090Sdougb isc_mem_put(mctx, ecdb, sizeof(*ecdb)); 610224090Sdougb return (result); 611224090Sdougb } 612224090Sdougb 613224090Sdougb result = isc_mutex_init(&ecdb->lock); 614224090Sdougb if (result != ISC_R_SUCCESS) { 615224090Sdougb UNEXPECTED_ERROR(__FILE__, __LINE__, 616224090Sdougb "isc_mutex_init() failed: %s", 617224090Sdougb isc_result_totext(result)); 618224090Sdougb if (dns_name_dynamic(&ecdb->common.origin)) 619224090Sdougb dns_name_free(&ecdb->common.origin, mctx); 620224090Sdougb isc_mem_put(mctx, ecdb, sizeof(*ecdb)); 621224090Sdougb return (ISC_R_UNEXPECTED); 622224090Sdougb } 623224090Sdougb 624224090Sdougb ecdb->references = 1; 625224090Sdougb ISC_LIST_INIT(ecdb->nodes); 626224090Sdougb 627224090Sdougb ecdb->common.mctx = NULL; 628224090Sdougb isc_mem_attach(mctx, &ecdb->common.mctx); 629224090Sdougb ecdb->common.impmagic = ECDB_MAGIC; 630224090Sdougb ecdb->common.magic = DNS_DB_MAGIC; 631224090Sdougb 632224090Sdougb *dbp = (dns_db_t *)ecdb; 633224090Sdougb 634224090Sdougb return (ISC_R_SUCCESS); 635224090Sdougb} 636224090Sdougb 637224090Sdougb/*% 638224090Sdougb * Rdataset Methods 639224090Sdougb */ 640224090Sdougb 641224090Sdougbstatic void 642224090Sdougbrdataset_disassociate(dns_rdataset_t *rdataset) { 643224090Sdougb dns_db_t *db = rdataset->private1; 644224090Sdougb dns_dbnode_t *node = rdataset->private2; 645224090Sdougb 646224090Sdougb dns_db_detachnode(db, &node); 647224090Sdougb} 648224090Sdougb 649224090Sdougbstatic isc_result_t 650224090Sdougbrdataset_first(dns_rdataset_t *rdataset) { 651224090Sdougb unsigned char *raw = rdataset->private3; 652224090Sdougb unsigned int count; 653224090Sdougb 654224090Sdougb count = raw[0] * 256 + raw[1]; 655224090Sdougb if (count == 0) { 656224090Sdougb rdataset->private5 = NULL; 657224090Sdougb return (ISC_R_NOMORE); 658224090Sdougb } 659234010Sdougb#if DNS_RDATASET_FIXED 660234010Sdougb raw += 2 + (4 * count); 661234010Sdougb#else 662224090Sdougb raw += 2; 663234010Sdougb#endif 664224090Sdougb /* 665224090Sdougb * The privateuint4 field is the number of rdata beyond the cursor 666224090Sdougb * position, so we decrement the total count by one before storing 667224090Sdougb * it. 668224090Sdougb */ 669224090Sdougb count--; 670224090Sdougb rdataset->privateuint4 = count; 671224090Sdougb rdataset->private5 = raw; 672224090Sdougb 673224090Sdougb return (ISC_R_SUCCESS); 674224090Sdougb} 675224090Sdougb 676224090Sdougbstatic isc_result_t 677224090Sdougbrdataset_next(dns_rdataset_t *rdataset) { 678224090Sdougb unsigned int count; 679224090Sdougb unsigned int length; 680224090Sdougb unsigned char *raw; 681224090Sdougb 682224090Sdougb count = rdataset->privateuint4; 683224090Sdougb if (count == 0) 684224090Sdougb return (ISC_R_NOMORE); 685224090Sdougb count--; 686224090Sdougb rdataset->privateuint4 = count; 687224090Sdougb raw = rdataset->private5; 688224090Sdougb length = raw[0] * 256 + raw[1]; 689234010Sdougb#if DNS_RDATASET_FIXED 690234010Sdougb raw += length + 4; 691234010Sdougb#else 692224090Sdougb raw += length + 2; 693234010Sdougb#endif 694224090Sdougb rdataset->private5 = raw; 695224090Sdougb 696224090Sdougb return (ISC_R_SUCCESS); 697224090Sdougb} 698224090Sdougb 699224090Sdougbstatic void 700224090Sdougbrdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) { 701224090Sdougb unsigned char *raw = rdataset->private5; 702224090Sdougb isc_region_t r; 703224090Sdougb unsigned int length; 704224090Sdougb unsigned int flags = 0; 705224090Sdougb 706224090Sdougb REQUIRE(raw != NULL); 707224090Sdougb 708224090Sdougb length = raw[0] * 256 + raw[1]; 709234010Sdougb#if DNS_RDATASET_FIXED 710234010Sdougb raw += 4; 711234010Sdougb#else 712224090Sdougb raw += 2; 713234010Sdougb#endif 714224090Sdougb if (rdataset->type == dns_rdatatype_rrsig) { 715224090Sdougb if (*raw & DNS_RDATASLAB_OFFLINE) 716224090Sdougb flags |= DNS_RDATA_OFFLINE; 717224090Sdougb length--; 718224090Sdougb raw++; 719224090Sdougb } 720224090Sdougb r.length = length; 721224090Sdougb r.base = raw; 722224090Sdougb dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r); 723224090Sdougb rdata->flags |= flags; 724224090Sdougb} 725224090Sdougb 726224090Sdougbstatic void 727224090Sdougbrdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) { 728224090Sdougb dns_db_t *db = source->private1; 729224090Sdougb dns_dbnode_t *node = source->private2; 730224090Sdougb dns_dbnode_t *cloned_node = NULL; 731224090Sdougb 732224090Sdougb attachnode(db, node, &cloned_node); 733224090Sdougb *target = *source; 734224090Sdougb 735224090Sdougb /* 736224090Sdougb * Reset iterator state. 737224090Sdougb */ 738224090Sdougb target->privateuint4 = 0; 739224090Sdougb target->private5 = NULL; 740224090Sdougb} 741224090Sdougb 742224090Sdougbstatic unsigned int 743224090Sdougbrdataset_count(dns_rdataset_t *rdataset) { 744224090Sdougb unsigned char *raw = rdataset->private3; 745224090Sdougb unsigned int count; 746224090Sdougb 747224090Sdougb count = raw[0] * 256 + raw[1]; 748224090Sdougb 749224090Sdougb return (count); 750224090Sdougb} 751224090Sdougb 752224090Sdougbstatic void 753224090Sdougbrdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) { 754224090Sdougb rdatasetheader_t *header = rdataset->private3; 755224090Sdougb 756224090Sdougb header--; 757224090Sdougb header->trust = rdataset->trust = trust; 758224090Sdougb} 759224090Sdougb 760224090Sdougb/* 761224090Sdougb * Rdataset Iterator Methods 762224090Sdougb */ 763224090Sdougb 764224090Sdougbstatic void 765224090Sdougbrdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) { 766224090Sdougb ecdb_rdatasetiter_t *ecdbiterator; 767224090Sdougb isc_mem_t *mctx; 768224090Sdougb 769224090Sdougb REQUIRE(iteratorp != NULL); 770224090Sdougb ecdbiterator = (ecdb_rdatasetiter_t *)*iteratorp; 771224090Sdougb REQUIRE(DNS_RDATASETITER_VALID(&ecdbiterator->common)); 772224090Sdougb 773224090Sdougb mctx = ecdbiterator->common.db->mctx; 774224090Sdougb 775224090Sdougb ecdbiterator->common.magic = 0; 776224090Sdougb 777224090Sdougb dns_db_detachnode(ecdbiterator->common.db, &ecdbiterator->common.node); 778224090Sdougb isc_mem_put(mctx, ecdbiterator, sizeof(ecdb_rdatasetiter_t)); 779224090Sdougb 780224090Sdougb *iteratorp = NULL; 781224090Sdougb} 782224090Sdougb 783224090Sdougbstatic isc_result_t 784224090Sdougbrdatasetiter_first(dns_rdatasetiter_t *iterator) { 785224090Sdougb ecdb_rdatasetiter_t *ecdbiterator = (ecdb_rdatasetiter_t *)iterator; 786224090Sdougb dns_ecdbnode_t *ecdbnode = (dns_ecdbnode_t *)iterator->node; 787224090Sdougb 788224090Sdougb REQUIRE(DNS_RDATASETITER_VALID(iterator)); 789224090Sdougb 790224090Sdougb if (ISC_LIST_EMPTY(ecdbnode->rdatasets)) 791224090Sdougb return (ISC_R_NOMORE); 792224090Sdougb ecdbiterator->current = ISC_LIST_HEAD(ecdbnode->rdatasets); 793224090Sdougb return (ISC_R_SUCCESS); 794224090Sdougb} 795224090Sdougb 796224090Sdougbstatic isc_result_t 797224090Sdougbrdatasetiter_next(dns_rdatasetiter_t *iterator) { 798224090Sdougb ecdb_rdatasetiter_t *ecdbiterator = (ecdb_rdatasetiter_t *)iterator; 799224090Sdougb 800224090Sdougb REQUIRE(DNS_RDATASETITER_VALID(iterator)); 801224090Sdougb 802224090Sdougb ecdbiterator->current = ISC_LIST_NEXT(ecdbiterator->current, link); 803224090Sdougb if (ecdbiterator->current == NULL) 804224090Sdougb return (ISC_R_NOMORE); 805224090Sdougb else 806224090Sdougb return (ISC_R_SUCCESS); 807224090Sdougb} 808224090Sdougb 809224090Sdougbstatic void 810224090Sdougbrdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) { 811224090Sdougb ecdb_rdatasetiter_t *ecdbiterator = (ecdb_rdatasetiter_t *)iterator; 812224090Sdougb dns_ecdb_t *ecdb; 813224090Sdougb 814224090Sdougb ecdb = (dns_ecdb_t *)iterator->db; 815224090Sdougb REQUIRE(VALID_ECDB(ecdb)); 816224090Sdougb 817224090Sdougb bind_rdataset(ecdb, iterator->node, ecdbiterator->current, rdataset); 818224090Sdougb} 819