1224090Sdougb/* 2254897Serwin * Copyright (C) 2009-2011, 2013 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 17254897Serwin/* $Id: ecdb.c,v 1.10 2011/12/20 00:06:53 marka Exp $ */ 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 83254402Serwin#define RDATASET_ATTR_NEGATIVE 0x0100 84224090Sdougb#define NXDOMAIN(header) \ 85224090Sdougb (((header)->attributes & RDATASET_ATTR_NXDOMAIN) != 0) 86254402Serwin#define NEGATIVE(header) \ 87254402Serwin (((header)->attributes & RDATASET_ATTR_NEGATIVE) != 0) 88224090Sdougb 89224090Sdougbstatic isc_result_t dns_ecdb_create(isc_mem_t *mctx, dns_name_t *origin, 90224090Sdougb dns_dbtype_t type, 91224090Sdougb dns_rdataclass_t rdclass, 92224090Sdougb unsigned int argc, char *argv[], 93224090Sdougb void *driverarg, dns_db_t **dbp); 94224090Sdougb 95224090Sdougbstatic void rdataset_disassociate(dns_rdataset_t *rdataset); 96224090Sdougbstatic isc_result_t rdataset_first(dns_rdataset_t *rdataset); 97224090Sdougbstatic isc_result_t rdataset_next(dns_rdataset_t *rdataset); 98224090Sdougbstatic void rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata); 99224090Sdougbstatic void rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target); 100224090Sdougbstatic unsigned int rdataset_count(dns_rdataset_t *rdataset); 101224090Sdougbstatic void rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust); 102224090Sdougb 103224090Sdougbstatic dns_rdatasetmethods_t rdataset_methods = { 104224090Sdougb rdataset_disassociate, 105224090Sdougb rdataset_first, 106224090Sdougb rdataset_next, 107224090Sdougb rdataset_current, 108224090Sdougb rdataset_clone, 109224090Sdougb rdataset_count, 110224090Sdougb NULL, /* addnoqname */ 111224090Sdougb NULL, /* getnoqname */ 112224090Sdougb NULL, /* addclosest */ 113224090Sdougb NULL, /* getclosest */ 114224090Sdougb NULL, /* getadditional */ 115224090Sdougb NULL, /* setadditional */ 116224090Sdougb NULL, /* putadditional */ 117224090Sdougb rdataset_settrust, /* settrust */ 118224090Sdougb NULL /* expire */ 119224090Sdougb}; 120224090Sdougb 121224090Sdougbtypedef struct ecdb_rdatasetiter { 122224090Sdougb dns_rdatasetiter_t common; 123224090Sdougb rdatasetheader_t *current; 124224090Sdougb} ecdb_rdatasetiter_t; 125224090Sdougb 126224090Sdougbstatic void rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp); 127224090Sdougbstatic isc_result_t rdatasetiter_first(dns_rdatasetiter_t *iterator); 128224090Sdougbstatic isc_result_t rdatasetiter_next(dns_rdatasetiter_t *iterator); 129224090Sdougbstatic void rdatasetiter_current(dns_rdatasetiter_t *iterator, 130224090Sdougb dns_rdataset_t *rdataset); 131224090Sdougb 132224090Sdougbstatic dns_rdatasetitermethods_t rdatasetiter_methods = { 133224090Sdougb rdatasetiter_destroy, 134224090Sdougb rdatasetiter_first, 135224090Sdougb rdatasetiter_next, 136224090Sdougb rdatasetiter_current 137224090Sdougb}; 138224090Sdougb 139224090Sdougbisc_result_t 140224090Sdougbdns_ecdb_register(isc_mem_t *mctx, dns_dbimplementation_t **dbimp) { 141224090Sdougb REQUIRE(mctx != NULL); 142224090Sdougb REQUIRE(dbimp != NULL && *dbimp == NULL); 143224090Sdougb 144224090Sdougb return (dns_db_register("ecdb", dns_ecdb_create, NULL, mctx, dbimp)); 145224090Sdougb} 146224090Sdougb 147224090Sdougbvoid 148224090Sdougbdns_ecdb_unregister(dns_dbimplementation_t **dbimp) { 149224090Sdougb REQUIRE(dbimp != NULL && *dbimp != NULL); 150224090Sdougb 151224090Sdougb dns_db_unregister(dbimp); 152224090Sdougb} 153224090Sdougb 154224090Sdougb/*% 155224090Sdougb * DB routines 156224090Sdougb */ 157224090Sdougb 158224090Sdougbstatic void 159224090Sdougbattach(dns_db_t *source, dns_db_t **targetp) { 160224090Sdougb dns_ecdb_t *ecdb = (dns_ecdb_t *)source; 161224090Sdougb 162224090Sdougb REQUIRE(VALID_ECDB(ecdb)); 163224090Sdougb REQUIRE(targetp != NULL && *targetp == NULL); 164224090Sdougb 165224090Sdougb LOCK(&ecdb->lock); 166224090Sdougb ecdb->references++; 167224090Sdougb UNLOCK(&ecdb->lock); 168224090Sdougb 169224090Sdougb *targetp = source; 170224090Sdougb} 171224090Sdougb 172224090Sdougbstatic void 173224090Sdougbdestroy_ecdb(dns_ecdb_t **ecdbp) { 174224090Sdougb dns_ecdb_t *ecdb = *ecdbp; 175224090Sdougb isc_mem_t *mctx = ecdb->common.mctx; 176224090Sdougb 177224090Sdougb if (dns_name_dynamic(&ecdb->common.origin)) 178224090Sdougb dns_name_free(&ecdb->common.origin, mctx); 179224090Sdougb 180224090Sdougb DESTROYLOCK(&ecdb->lock); 181224090Sdougb 182224090Sdougb ecdb->common.impmagic = 0; 183224090Sdougb ecdb->common.magic = 0; 184224090Sdougb 185224090Sdougb isc_mem_putanddetach(&mctx, ecdb, sizeof(*ecdb)); 186224090Sdougb 187224090Sdougb *ecdbp = NULL; 188224090Sdougb} 189224090Sdougb 190224090Sdougbstatic void 191224090Sdougbdetach(dns_db_t **dbp) { 192224090Sdougb dns_ecdb_t *ecdb; 193224090Sdougb isc_boolean_t need_destroy = ISC_FALSE; 194224090Sdougb 195224090Sdougb REQUIRE(dbp != NULL); 196224090Sdougb ecdb = (dns_ecdb_t *)*dbp; 197224090Sdougb REQUIRE(VALID_ECDB(ecdb)); 198224090Sdougb 199224090Sdougb LOCK(&ecdb->lock); 200224090Sdougb ecdb->references--; 201224090Sdougb if (ecdb->references == 0 && ISC_LIST_EMPTY(ecdb->nodes)) 202224090Sdougb need_destroy = ISC_TRUE; 203224090Sdougb UNLOCK(&ecdb->lock); 204224090Sdougb 205224090Sdougb if (need_destroy) 206224090Sdougb destroy_ecdb(&ecdb); 207224090Sdougb 208224090Sdougb *dbp = NULL; 209224090Sdougb} 210224090Sdougb 211224090Sdougbstatic void 212224090Sdougbattachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) { 213224090Sdougb dns_ecdb_t *ecdb = (dns_ecdb_t *)db; 214224090Sdougb dns_ecdbnode_t *node = (dns_ecdbnode_t *)source; 215224090Sdougb 216224090Sdougb REQUIRE(VALID_ECDB(ecdb)); 217224090Sdougb REQUIRE(VALID_ECDBNODE(node)); 218224090Sdougb REQUIRE(targetp != NULL && *targetp == NULL); 219224090Sdougb 220224090Sdougb LOCK(&node->lock); 221224090Sdougb INSIST(node->references > 0); 222224090Sdougb node->references++; 223224090Sdougb INSIST(node->references != 0); /* Catch overflow. */ 224224090Sdougb UNLOCK(&node->lock); 225224090Sdougb 226224090Sdougb *targetp = node; 227224090Sdougb} 228224090Sdougb 229224090Sdougbstatic void 230224090Sdougbdestroynode(dns_ecdbnode_t *node) { 231224090Sdougb isc_mem_t *mctx; 232224090Sdougb dns_ecdb_t *ecdb = node->ecdb; 233224090Sdougb isc_boolean_t need_destroydb = ISC_FALSE; 234224090Sdougb rdatasetheader_t *header; 235224090Sdougb 236224090Sdougb mctx = ecdb->common.mctx; 237224090Sdougb 238224090Sdougb LOCK(&ecdb->lock); 239224090Sdougb ISC_LIST_UNLINK(ecdb->nodes, node, link); 240224090Sdougb if (ecdb->references == 0 && ISC_LIST_EMPTY(ecdb->nodes)) 241224090Sdougb need_destroydb = ISC_TRUE; 242224090Sdougb UNLOCK(&ecdb->lock); 243224090Sdougb 244224090Sdougb dns_name_free(&node->name, mctx); 245224090Sdougb 246224090Sdougb while ((header = ISC_LIST_HEAD(node->rdatasets)) != NULL) { 247224090Sdougb unsigned int headersize; 248224090Sdougb 249224090Sdougb ISC_LIST_UNLINK(node->rdatasets, header, link); 250224090Sdougb headersize = 251224090Sdougb dns_rdataslab_size((unsigned char *)header, 252224090Sdougb sizeof(*header)); 253224090Sdougb isc_mem_put(mctx, header, headersize); 254224090Sdougb } 255224090Sdougb 256224090Sdougb DESTROYLOCK(&node->lock); 257224090Sdougb 258224090Sdougb node->magic = 0; 259224090Sdougb isc_mem_put(mctx, node, sizeof(*node)); 260224090Sdougb 261224090Sdougb if (need_destroydb) 262224090Sdougb destroy_ecdb(&ecdb); 263224090Sdougb} 264224090Sdougb 265224090Sdougbstatic void 266224090Sdougbdetachnode(dns_db_t *db, dns_dbnode_t **nodep) { 267224090Sdougb dns_ecdb_t *ecdb = (dns_ecdb_t *)db; 268224090Sdougb dns_ecdbnode_t *node; 269224090Sdougb isc_boolean_t need_destroy = ISC_FALSE; 270224090Sdougb 271224090Sdougb REQUIRE(VALID_ECDB(ecdb)); 272224090Sdougb REQUIRE(nodep != NULL); 273224090Sdougb node = (dns_ecdbnode_t *)*nodep; 274224090Sdougb REQUIRE(VALID_ECDBNODE(node)); 275224090Sdougb 276224090Sdougb UNUSED(ecdb); /* in case REQUIRE() is empty */ 277224090Sdougb 278224090Sdougb LOCK(&node->lock); 279224090Sdougb INSIST(node->references > 0); 280224090Sdougb node->references--; 281224090Sdougb if (node->references == 0) 282224090Sdougb need_destroy = ISC_TRUE; 283224090Sdougb UNLOCK(&node->lock); 284224090Sdougb 285224090Sdougb if (need_destroy) 286224090Sdougb destroynode(node); 287224090Sdougb 288224090Sdougb *nodep = NULL; 289224090Sdougb} 290224090Sdougb 291224090Sdougbstatic isc_result_t 292224090Sdougbfind(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, 293224090Sdougb dns_rdatatype_t type, unsigned int options, isc_stdtime_t now, 294224090Sdougb dns_dbnode_t **nodep, dns_name_t *foundname, dns_rdataset_t *rdataset, 295224090Sdougb dns_rdataset_t *sigrdataset) 296224090Sdougb{ 297224090Sdougb dns_ecdb_t *ecdb = (dns_ecdb_t *)db; 298224090Sdougb 299224090Sdougb REQUIRE(VALID_ECDB(ecdb)); 300224090Sdougb 301224090Sdougb UNUSED(name); 302224090Sdougb UNUSED(version); 303224090Sdougb UNUSED(type); 304224090Sdougb UNUSED(options); 305224090Sdougb UNUSED(now); 306224090Sdougb UNUSED(nodep); 307224090Sdougb UNUSED(foundname); 308224090Sdougb UNUSED(rdataset); 309224090Sdougb UNUSED(sigrdataset); 310224090Sdougb 311224090Sdougb return (ISC_R_NOTFOUND); 312224090Sdougb} 313224090Sdougb 314224090Sdougbstatic isc_result_t 315224090Sdougbfindzonecut(dns_db_t *db, dns_name_t *name, 316224090Sdougb unsigned int options, isc_stdtime_t now, 317224090Sdougb dns_dbnode_t **nodep, dns_name_t *foundname, 318224090Sdougb dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) 319224090Sdougb{ 320224090Sdougb dns_ecdb_t *ecdb = (dns_ecdb_t *)db; 321224090Sdougb 322224090Sdougb REQUIRE(VALID_ECDB(ecdb)); 323224090Sdougb 324224090Sdougb UNUSED(name); 325224090Sdougb UNUSED(options); 326224090Sdougb UNUSED(now); 327224090Sdougb UNUSED(nodep); 328224090Sdougb UNUSED(foundname); 329224090Sdougb UNUSED(rdataset); 330224090Sdougb UNUSED(sigrdataset); 331224090Sdougb 332224090Sdougb return (ISC_R_NOTFOUND); 333224090Sdougb} 334224090Sdougb 335224090Sdougbstatic isc_result_t 336224090Sdougbfindnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create, 337224090Sdougb dns_dbnode_t **nodep) 338224090Sdougb{ 339224090Sdougb dns_ecdb_t *ecdb = (dns_ecdb_t *)db; 340224090Sdougb isc_mem_t *mctx; 341224090Sdougb dns_ecdbnode_t *node; 342224090Sdougb isc_result_t result; 343224090Sdougb 344224090Sdougb REQUIRE(VALID_ECDB(ecdb)); 345224090Sdougb REQUIRE(nodep != NULL && *nodep == NULL); 346224090Sdougb 347224090Sdougb UNUSED(name); 348224090Sdougb 349224090Sdougb if (create != ISC_TRUE) { 350224090Sdougb /* an 'ephemeral' node is never reused. */ 351224090Sdougb return (ISC_R_NOTFOUND); 352224090Sdougb } 353224090Sdougb 354224090Sdougb mctx = ecdb->common.mctx; 355224090Sdougb node = isc_mem_get(mctx, sizeof(*node)); 356224090Sdougb if (node == NULL) 357224090Sdougb return (ISC_R_NOMEMORY); 358224090Sdougb 359224090Sdougb result = isc_mutex_init(&node->lock); 360224090Sdougb if (result != ISC_R_SUCCESS) { 361224090Sdougb UNEXPECTED_ERROR(__FILE__, __LINE__, 362224090Sdougb "isc_mutex_init() failed: %s", 363224090Sdougb isc_result_totext(result)); 364224090Sdougb isc_mem_put(mctx, node, sizeof(*node)); 365224090Sdougb return (ISC_R_UNEXPECTED); 366224090Sdougb } 367224090Sdougb 368224090Sdougb dns_name_init(&node->name, NULL); 369224090Sdougb result = dns_name_dup(name, mctx, &node->name); 370224090Sdougb if (result != ISC_R_SUCCESS) { 371224090Sdougb DESTROYLOCK(&node->lock); 372224090Sdougb isc_mem_put(mctx, node, sizeof(*node)); 373224090Sdougb return (result); 374224090Sdougb } 375224090Sdougb node->ecdb= ecdb; 376224090Sdougb node->references = 1; 377224090Sdougb ISC_LIST_INIT(node->rdatasets); 378224090Sdougb 379224090Sdougb ISC_LINK_INIT(node, link); 380224090Sdougb 381224090Sdougb LOCK(&ecdb->lock); 382224090Sdougb ISC_LIST_APPEND(ecdb->nodes, node, link); 383224090Sdougb UNLOCK(&ecdb->lock); 384224090Sdougb 385224090Sdougb node->magic = ECDBNODE_MAGIC; 386224090Sdougb 387224090Sdougb *nodep = node; 388224090Sdougb 389224090Sdougb return (ISC_R_SUCCESS); 390224090Sdougb} 391224090Sdougb 392224090Sdougbstatic void 393224090Sdougbbind_rdataset(dns_ecdb_t *ecdb, dns_ecdbnode_t *node, 394224090Sdougb rdatasetheader_t *header, dns_rdataset_t *rdataset) 395224090Sdougb{ 396224090Sdougb unsigned char *raw; 397224090Sdougb 398224090Sdougb /* 399224090Sdougb * Caller must be holding the node lock. 400224090Sdougb */ 401224090Sdougb 402224090Sdougb REQUIRE(!dns_rdataset_isassociated(rdataset)); 403224090Sdougb 404224090Sdougb rdataset->methods = &rdataset_methods; 405224090Sdougb rdataset->rdclass = ecdb->common.rdclass; 406224090Sdougb rdataset->type = header->type; 407224090Sdougb rdataset->covers = header->covers; 408224090Sdougb rdataset->ttl = header->ttl; 409224090Sdougb rdataset->trust = header->trust; 410224090Sdougb if (NXDOMAIN(header)) 411224090Sdougb rdataset->attributes |= DNS_RDATASETATTR_NXDOMAIN; 412254402Serwin if (NEGATIVE(header)) 413254402Serwin rdataset->attributes |= DNS_RDATASETATTR_NEGATIVE; 414224090Sdougb 415224090Sdougb rdataset->private1 = ecdb; 416224090Sdougb rdataset->private2 = node; 417224090Sdougb raw = (unsigned char *)header + sizeof(*header); 418224090Sdougb rdataset->private3 = raw; 419224090Sdougb rdataset->count = 0; 420224090Sdougb 421224090Sdougb /* 422224090Sdougb * Reset iterator state. 423224090Sdougb */ 424224090Sdougb rdataset->privateuint4 = 0; 425224090Sdougb rdataset->private5 = NULL; 426224090Sdougb 427224090Sdougb INSIST(node->references > 0); 428224090Sdougb node->references++; 429224090Sdougb} 430224090Sdougb 431224090Sdougbstatic isc_result_t 432224090Sdougbaddrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, 433224090Sdougb isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options, 434224090Sdougb dns_rdataset_t *addedrdataset) 435224090Sdougb{ 436224090Sdougb dns_ecdb_t *ecdb = (dns_ecdb_t *)db; 437224090Sdougb isc_region_t r; 438224090Sdougb isc_result_t result = ISC_R_SUCCESS; 439224090Sdougb isc_mem_t *mctx; 440224090Sdougb dns_ecdbnode_t *ecdbnode = (dns_ecdbnode_t *)node; 441224090Sdougb rdatasetheader_t *header; 442224090Sdougb 443224090Sdougb REQUIRE(VALID_ECDB(ecdb)); 444224090Sdougb REQUIRE(VALID_ECDBNODE(ecdbnode)); 445224090Sdougb 446224090Sdougb UNUSED(version); 447224090Sdougb UNUSED(now); 448224090Sdougb UNUSED(options); 449224090Sdougb 450224090Sdougb mctx = ecdb->common.mctx; 451224090Sdougb 452224090Sdougb LOCK(&ecdbnode->lock); 453224090Sdougb 454224090Sdougb /* 455224090Sdougb * Sanity check: this implementation does not allow overriding an 456224090Sdougb * existing rdataset of the same type. 457224090Sdougb */ 458224090Sdougb for (header = ISC_LIST_HEAD(ecdbnode->rdatasets); header != NULL; 459224090Sdougb header = ISC_LIST_NEXT(header, link)) { 460224090Sdougb INSIST(header->type != rdataset->type || 461224090Sdougb header->covers != rdataset->covers); 462224090Sdougb } 463224090Sdougb 464224090Sdougb result = dns_rdataslab_fromrdataset(rdataset, mctx, 465224090Sdougb &r, sizeof(rdatasetheader_t)); 466224090Sdougb if (result != ISC_R_SUCCESS) 467224090Sdougb goto unlock; 468224090Sdougb 469224090Sdougb header = (rdatasetheader_t *)r.base; 470224090Sdougb header->type = rdataset->type; 471224090Sdougb header->ttl = rdataset->ttl; 472224090Sdougb header->trust = rdataset->trust; 473224090Sdougb header->covers = rdataset->covers; 474224090Sdougb header->attributes = 0; 475224090Sdougb if ((rdataset->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0) 476224090Sdougb header->attributes |= RDATASET_ATTR_NXDOMAIN; 477254402Serwin if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) 478254402Serwin header->attributes |= RDATASET_ATTR_NEGATIVE; 479224090Sdougb ISC_LINK_INIT(header, link); 480224090Sdougb ISC_LIST_APPEND(ecdbnode->rdatasets, header, link); 481224090Sdougb 482224090Sdougb if (addedrdataset == NULL) 483224090Sdougb goto unlock; 484224090Sdougb 485224090Sdougb bind_rdataset(ecdb, ecdbnode, header, addedrdataset); 486224090Sdougb 487224090Sdougb unlock: 488224090Sdougb UNLOCK(&ecdbnode->lock); 489224090Sdougb 490224090Sdougb return (result); 491224090Sdougb} 492224090Sdougb 493224090Sdougbstatic isc_result_t 494224090Sdougbdeleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, 495224090Sdougb dns_rdatatype_t type, dns_rdatatype_t covers) 496224090Sdougb{ 497224090Sdougb UNUSED(db); 498224090Sdougb UNUSED(node); 499224090Sdougb UNUSED(version); 500224090Sdougb UNUSED(type); 501224090Sdougb UNUSED(covers); 502224090Sdougb 503224090Sdougb return (ISC_R_NOTIMPLEMENTED); 504224090Sdougb} 505224090Sdougb 506224090Sdougbstatic isc_result_t 507224090Sdougbcreateiterator(dns_db_t *db, unsigned int options, 508224090Sdougb dns_dbiterator_t **iteratorp) 509224090Sdougb{ 510224090Sdougb UNUSED(db); 511224090Sdougb UNUSED(options); 512224090Sdougb UNUSED(iteratorp); 513224090Sdougb 514224090Sdougb return (ISC_R_NOTIMPLEMENTED); 515224090Sdougb} 516224090Sdougb 517224090Sdougbstatic isc_result_t 518224090Sdougballrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, 519224090Sdougb isc_stdtime_t now, dns_rdatasetiter_t **iteratorp) 520224090Sdougb{ 521224090Sdougb dns_ecdb_t *ecdb = (dns_ecdb_t *)db; 522224090Sdougb dns_ecdbnode_t *ecdbnode = (dns_ecdbnode_t *)node; 523224090Sdougb isc_mem_t *mctx; 524224090Sdougb ecdb_rdatasetiter_t *iterator; 525224090Sdougb 526224090Sdougb REQUIRE(VALID_ECDB(ecdb)); 527224090Sdougb REQUIRE(VALID_ECDBNODE(ecdbnode)); 528224090Sdougb 529224090Sdougb mctx = ecdb->common.mctx; 530224090Sdougb 531224090Sdougb iterator = isc_mem_get(mctx, sizeof(ecdb_rdatasetiter_t)); 532224090Sdougb if (iterator == NULL) 533224090Sdougb return (ISC_R_NOMEMORY); 534224090Sdougb 535224090Sdougb iterator->common.magic = DNS_RDATASETITER_MAGIC; 536224090Sdougb iterator->common.methods = &rdatasetiter_methods; 537224090Sdougb iterator->common.db = db; 538224090Sdougb iterator->common.node = NULL; 539224090Sdougb attachnode(db, node, &iterator->common.node); 540224090Sdougb iterator->common.version = version; 541224090Sdougb iterator->common.now = now; 542224090Sdougb 543224090Sdougb *iteratorp = (dns_rdatasetiter_t *)iterator; 544224090Sdougb 545224090Sdougb return (ISC_R_SUCCESS); 546224090Sdougb} 547224090Sdougb 548224090Sdougbstatic dns_dbmethods_t ecdb_methods = { 549224090Sdougb attach, 550224090Sdougb detach, 551224090Sdougb NULL, /* beginload */ 552224090Sdougb NULL, /* endload */ 553224090Sdougb NULL, /* dump */ 554224090Sdougb NULL, /* currentversion */ 555224090Sdougb NULL, /* newversion */ 556224090Sdougb NULL, /* attachversion */ 557224090Sdougb NULL, /* closeversion */ 558224090Sdougb findnode, 559224090Sdougb find, 560224090Sdougb findzonecut, 561224090Sdougb attachnode, 562224090Sdougb detachnode, 563224090Sdougb NULL, /* expirenode */ 564224090Sdougb NULL, /* printnode */ 565224090Sdougb createiterator, /* createiterator */ 566224090Sdougb NULL, /* findrdataset */ 567224090Sdougb allrdatasets, 568224090Sdougb addrdataset, 569224090Sdougb NULL, /* subtractrdataset */ 570224090Sdougb deleterdataset, 571224090Sdougb NULL, /* issecure */ 572224090Sdougb NULL, /* nodecount */ 573224090Sdougb NULL, /* ispersistent */ 574224090Sdougb NULL, /* overmem */ 575224090Sdougb NULL, /* settask */ 576224090Sdougb NULL, /* getoriginnode */ 577224090Sdougb NULL, /* transfernode */ 578224090Sdougb NULL, /* getnsec3parameters */ 579224090Sdougb NULL, /* findnsec3node */ 580224090Sdougb NULL, /* setsigningtime */ 581224090Sdougb NULL, /* getsigningtime */ 582224090Sdougb NULL, /* resigned */ 583224090Sdougb NULL, /* isdnssec */ 584224090Sdougb NULL, /* getrrsetstats */ 585224090Sdougb NULL, /* rpz_enabled */ 586254897Serwin NULL, /* rpz_findips */ 587254897Serwin NULL, /* findnodeext */ 588254897Serwin NULL /* findext */ 589224090Sdougb}; 590224090Sdougb 591224090Sdougbstatic isc_result_t 592224090Sdougbdns_ecdb_create(isc_mem_t *mctx, dns_name_t *origin, dns_dbtype_t type, 593224090Sdougb dns_rdataclass_t rdclass, unsigned int argc, char *argv[], 594224090Sdougb void *driverarg, dns_db_t **dbp) 595224090Sdougb{ 596224090Sdougb dns_ecdb_t *ecdb; 597224090Sdougb isc_result_t result; 598224090Sdougb 599224090Sdougb REQUIRE(mctx != NULL); 600224090Sdougb REQUIRE(origin == dns_rootname); 601224090Sdougb REQUIRE(type == dns_dbtype_cache); 602224090Sdougb REQUIRE(dbp != NULL && *dbp == NULL); 603224090Sdougb 604224090Sdougb UNUSED(argc); 605224090Sdougb UNUSED(argv); 606224090Sdougb UNUSED(driverarg); 607224090Sdougb 608224090Sdougb ecdb = isc_mem_get(mctx, sizeof(*ecdb)); 609224090Sdougb if (ecdb == NULL) 610224090Sdougb return (ISC_R_NOMEMORY); 611224090Sdougb 612224090Sdougb ecdb->common.attributes = DNS_DBATTR_CACHE; 613224090Sdougb ecdb->common.rdclass = rdclass; 614224090Sdougb ecdb->common.methods = &ecdb_methods; 615224090Sdougb dns_name_init(&ecdb->common.origin, NULL); 616224090Sdougb result = dns_name_dupwithoffsets(origin, mctx, &ecdb->common.origin); 617224090Sdougb if (result != ISC_R_SUCCESS) { 618224090Sdougb isc_mem_put(mctx, ecdb, sizeof(*ecdb)); 619224090Sdougb return (result); 620224090Sdougb } 621224090Sdougb 622224090Sdougb result = isc_mutex_init(&ecdb->lock); 623224090Sdougb if (result != ISC_R_SUCCESS) { 624224090Sdougb UNEXPECTED_ERROR(__FILE__, __LINE__, 625224090Sdougb "isc_mutex_init() failed: %s", 626224090Sdougb isc_result_totext(result)); 627224090Sdougb if (dns_name_dynamic(&ecdb->common.origin)) 628224090Sdougb dns_name_free(&ecdb->common.origin, mctx); 629224090Sdougb isc_mem_put(mctx, ecdb, sizeof(*ecdb)); 630224090Sdougb return (ISC_R_UNEXPECTED); 631224090Sdougb } 632224090Sdougb 633224090Sdougb ecdb->references = 1; 634224090Sdougb ISC_LIST_INIT(ecdb->nodes); 635224090Sdougb 636224090Sdougb ecdb->common.mctx = NULL; 637224090Sdougb isc_mem_attach(mctx, &ecdb->common.mctx); 638224090Sdougb ecdb->common.impmagic = ECDB_MAGIC; 639224090Sdougb ecdb->common.magic = DNS_DB_MAGIC; 640224090Sdougb 641224090Sdougb *dbp = (dns_db_t *)ecdb; 642224090Sdougb 643224090Sdougb return (ISC_R_SUCCESS); 644224090Sdougb} 645224090Sdougb 646224090Sdougb/*% 647224090Sdougb * Rdataset Methods 648224090Sdougb */ 649224090Sdougb 650224090Sdougbstatic void 651224090Sdougbrdataset_disassociate(dns_rdataset_t *rdataset) { 652224090Sdougb dns_db_t *db = rdataset->private1; 653224090Sdougb dns_dbnode_t *node = rdataset->private2; 654224090Sdougb 655224090Sdougb dns_db_detachnode(db, &node); 656224090Sdougb} 657224090Sdougb 658224090Sdougbstatic isc_result_t 659224090Sdougbrdataset_first(dns_rdataset_t *rdataset) { 660224090Sdougb unsigned char *raw = rdataset->private3; 661224090Sdougb unsigned int count; 662224090Sdougb 663224090Sdougb count = raw[0] * 256 + raw[1]; 664224090Sdougb if (count == 0) { 665224090Sdougb rdataset->private5 = NULL; 666224090Sdougb return (ISC_R_NOMORE); 667224090Sdougb } 668234010Sdougb#if DNS_RDATASET_FIXED 669234010Sdougb raw += 2 + (4 * count); 670234010Sdougb#else 671224090Sdougb raw += 2; 672234010Sdougb#endif 673224090Sdougb /* 674224090Sdougb * The privateuint4 field is the number of rdata beyond the cursor 675224090Sdougb * position, so we decrement the total count by one before storing 676224090Sdougb * it. 677224090Sdougb */ 678224090Sdougb count--; 679224090Sdougb rdataset->privateuint4 = count; 680224090Sdougb rdataset->private5 = raw; 681224090Sdougb 682224090Sdougb return (ISC_R_SUCCESS); 683224090Sdougb} 684224090Sdougb 685224090Sdougbstatic isc_result_t 686224090Sdougbrdataset_next(dns_rdataset_t *rdataset) { 687224090Sdougb unsigned int count; 688224090Sdougb unsigned int length; 689224090Sdougb unsigned char *raw; 690224090Sdougb 691224090Sdougb count = rdataset->privateuint4; 692224090Sdougb if (count == 0) 693224090Sdougb return (ISC_R_NOMORE); 694224090Sdougb count--; 695224090Sdougb rdataset->privateuint4 = count; 696224090Sdougb raw = rdataset->private5; 697224090Sdougb length = raw[0] * 256 + raw[1]; 698234010Sdougb#if DNS_RDATASET_FIXED 699234010Sdougb raw += length + 4; 700234010Sdougb#else 701224090Sdougb raw += length + 2; 702234010Sdougb#endif 703224090Sdougb rdataset->private5 = raw; 704224090Sdougb 705224090Sdougb return (ISC_R_SUCCESS); 706224090Sdougb} 707224090Sdougb 708224090Sdougbstatic void 709224090Sdougbrdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) { 710224090Sdougb unsigned char *raw = rdataset->private5; 711224090Sdougb isc_region_t r; 712224090Sdougb unsigned int length; 713224090Sdougb unsigned int flags = 0; 714224090Sdougb 715224090Sdougb REQUIRE(raw != NULL); 716224090Sdougb 717224090Sdougb length = raw[0] * 256 + raw[1]; 718234010Sdougb#if DNS_RDATASET_FIXED 719234010Sdougb raw += 4; 720234010Sdougb#else 721224090Sdougb raw += 2; 722234010Sdougb#endif 723224090Sdougb if (rdataset->type == dns_rdatatype_rrsig) { 724224090Sdougb if (*raw & DNS_RDATASLAB_OFFLINE) 725224090Sdougb flags |= DNS_RDATA_OFFLINE; 726224090Sdougb length--; 727224090Sdougb raw++; 728224090Sdougb } 729224090Sdougb r.length = length; 730224090Sdougb r.base = raw; 731224090Sdougb dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r); 732224090Sdougb rdata->flags |= flags; 733224090Sdougb} 734224090Sdougb 735224090Sdougbstatic void 736224090Sdougbrdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) { 737224090Sdougb dns_db_t *db = source->private1; 738224090Sdougb dns_dbnode_t *node = source->private2; 739224090Sdougb dns_dbnode_t *cloned_node = NULL; 740224090Sdougb 741224090Sdougb attachnode(db, node, &cloned_node); 742224090Sdougb *target = *source; 743224090Sdougb 744224090Sdougb /* 745224090Sdougb * Reset iterator state. 746224090Sdougb */ 747224090Sdougb target->privateuint4 = 0; 748224090Sdougb target->private5 = NULL; 749224090Sdougb} 750224090Sdougb 751224090Sdougbstatic unsigned int 752224090Sdougbrdataset_count(dns_rdataset_t *rdataset) { 753224090Sdougb unsigned char *raw = rdataset->private3; 754224090Sdougb unsigned int count; 755224090Sdougb 756224090Sdougb count = raw[0] * 256 + raw[1]; 757224090Sdougb 758224090Sdougb return (count); 759224090Sdougb} 760224090Sdougb 761224090Sdougbstatic void 762224090Sdougbrdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) { 763224090Sdougb rdatasetheader_t *header = rdataset->private3; 764224090Sdougb 765224090Sdougb header--; 766224090Sdougb header->trust = rdataset->trust = trust; 767224090Sdougb} 768224090Sdougb 769224090Sdougb/* 770224090Sdougb * Rdataset Iterator Methods 771224090Sdougb */ 772224090Sdougb 773224090Sdougbstatic void 774224090Sdougbrdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) { 775224090Sdougb ecdb_rdatasetiter_t *ecdbiterator; 776224090Sdougb isc_mem_t *mctx; 777224090Sdougb 778224090Sdougb REQUIRE(iteratorp != NULL); 779224090Sdougb ecdbiterator = (ecdb_rdatasetiter_t *)*iteratorp; 780224090Sdougb REQUIRE(DNS_RDATASETITER_VALID(&ecdbiterator->common)); 781224090Sdougb 782224090Sdougb mctx = ecdbiterator->common.db->mctx; 783224090Sdougb 784224090Sdougb ecdbiterator->common.magic = 0; 785224090Sdougb 786224090Sdougb dns_db_detachnode(ecdbiterator->common.db, &ecdbiterator->common.node); 787224090Sdougb isc_mem_put(mctx, ecdbiterator, sizeof(ecdb_rdatasetiter_t)); 788224090Sdougb 789224090Sdougb *iteratorp = NULL; 790224090Sdougb} 791224090Sdougb 792224090Sdougbstatic isc_result_t 793224090Sdougbrdatasetiter_first(dns_rdatasetiter_t *iterator) { 794224090Sdougb ecdb_rdatasetiter_t *ecdbiterator = (ecdb_rdatasetiter_t *)iterator; 795224090Sdougb dns_ecdbnode_t *ecdbnode = (dns_ecdbnode_t *)iterator->node; 796224090Sdougb 797224090Sdougb REQUIRE(DNS_RDATASETITER_VALID(iterator)); 798224090Sdougb 799224090Sdougb if (ISC_LIST_EMPTY(ecdbnode->rdatasets)) 800224090Sdougb return (ISC_R_NOMORE); 801224090Sdougb ecdbiterator->current = ISC_LIST_HEAD(ecdbnode->rdatasets); 802224090Sdougb return (ISC_R_SUCCESS); 803224090Sdougb} 804224090Sdougb 805224090Sdougbstatic isc_result_t 806224090Sdougbrdatasetiter_next(dns_rdatasetiter_t *iterator) { 807224090Sdougb ecdb_rdatasetiter_t *ecdbiterator = (ecdb_rdatasetiter_t *)iterator; 808224090Sdougb 809224090Sdougb REQUIRE(DNS_RDATASETITER_VALID(iterator)); 810224090Sdougb 811224090Sdougb ecdbiterator->current = ISC_LIST_NEXT(ecdbiterator->current, link); 812224090Sdougb if (ecdbiterator->current == NULL) 813224090Sdougb return (ISC_R_NOMORE); 814224090Sdougb else 815224090Sdougb return (ISC_R_SUCCESS); 816224090Sdougb} 817224090Sdougb 818224090Sdougbstatic void 819224090Sdougbrdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) { 820224090Sdougb ecdb_rdatasetiter_t *ecdbiterator = (ecdb_rdatasetiter_t *)iterator; 821224090Sdougb dns_ecdb_t *ecdb; 822224090Sdougb 823224090Sdougb ecdb = (dns_ecdb_t *)iterator->db; 824224090Sdougb REQUIRE(VALID_ECDB(ecdb)); 825224090Sdougb 826224090Sdougb bind_rdataset(ecdb, iterator->node, ecdbiterator->current, rdataset); 827224090Sdougb} 828