📄 sdb.c
字号:
/* * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001, 2003 Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. *//* $Id: sdb.c,v 1.35.12.8 2004/07/22 04:01:58 marka Exp $ */#include <config.h>#include <string.h>#include <isc/buffer.h>#include <isc/lex.h>#include <isc/log.h>#include <isc/magic.h>#include <isc/mem.h>#include <isc/once.h>#include <isc/print.h>#include <isc/region.h>#include <isc/util.h>#include <dns/callbacks.h>#include <dns/db.h>#include <dns/dbiterator.h>#include <dns/fixedname.h>#include <dns/log.h>#include <dns/rdata.h>#include <dns/rdatalist.h>#include <dns/rdataset.h>#include <dns/rdatasetiter.h>#include <dns/rdatatype.h>#include <dns/result.h>#include <dns/sdb.h>#include <dns/types.h>#include "rdatalist_p.h"struct dns_sdbimplementation { const dns_sdbmethods_t *methods; void *driverdata; unsigned int flags; isc_mem_t *mctx; isc_mutex_t driverlock; dns_dbimplementation_t *dbimp;};struct dns_sdb { /* Unlocked */ dns_db_t common; char *zone; dns_sdbimplementation_t *implementation; void *dbdata; isc_mutex_t lock; /* Locked */ unsigned int references;};struct dns_sdblookup { /* Unlocked */ unsigned int magic; dns_sdb_t *sdb; ISC_LIST(dns_rdatalist_t) lists; ISC_LIST(isc_buffer_t) buffers; dns_name_t *name; ISC_LINK(dns_sdblookup_t) link; isc_mutex_t lock; dns_rdatacallbacks_t callbacks; /* Locked */ unsigned int references;};typedef struct dns_sdblookup dns_sdbnode_t;struct dns_sdballnodes { dns_dbiterator_t common; ISC_LIST(dns_sdbnode_t) nodelist; dns_sdbnode_t *current; dns_sdbnode_t *origin;};typedef dns_sdballnodes_t sdb_dbiterator_t;typedef struct sdb_rdatasetiter { dns_rdatasetiter_t common; dns_rdatalist_t *current;} sdb_rdatasetiter_t;#define SDB_MAGIC ISC_MAGIC('S', 'D', 'B', '-')/* * Note that "impmagic" is not the first four bytes of the struct, so * ISC_MAGIC_VALID cannot be used. */#define VALID_SDB(sdb) ((sdb) != NULL && \ (sdb)->common.impmagic == SDB_MAGIC)#define SDBLOOKUP_MAGIC ISC_MAGIC('S','D','B','L')#define VALID_SDBLOOKUP(sdbl) ISC_MAGIC_VALID(sdbl, SDBLOOKUP_MAGIC)#define VALID_SDBNODE(sdbn) VALID_SDBLOOKUP(sdbn)/* These values are taken from RFC 1537 */#define SDB_DEFAULT_REFRESH (60 * 60 * 8)#define SDB_DEFAULT_RETRY (60 * 60 * 2)#define SDB_DEFAULT_EXPIRE (60 * 60 * 24 * 7)#define SDB_DEFAULT_MINIMUM (60 * 60 * 24)/* This is a reasonable value */#define SDB_DEFAULT_TTL (60 * 60 * 24)#define MAYBE_LOCK(sdb) \ do { \ unsigned int flags = sdb->implementation->flags; \ if ((flags & DNS_SDBFLAG_THREADSAFE) == 0) \ LOCK(&sdb->implementation->driverlock); \ } while (0)#define MAYBE_UNLOCK(sdb) \ do { \ unsigned int flags = sdb->implementation->flags; \ if ((flags & DNS_SDBFLAG_THREADSAFE) == 0) \ UNLOCK(&sdb->implementation->driverlock); \ } while (0)static int dummy;static isc_result_t dns_sdb_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);static isc_result_t findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, dns_rdatatype_t type, dns_rdatatype_t covers, isc_stdtime_t now, dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset);static isc_result_t createnode(dns_sdb_t *sdb, dns_sdbnode_t **nodep);static void destroynode(dns_sdbnode_t *node);static void detachnode(dns_db_t *db, dns_dbnode_t **targetp);static void list_tordataset(dns_rdatalist_t *rdatalist, dns_db_t *db, dns_dbnode_t *node, dns_rdataset_t *rdataset);static void dbiterator_destroy(dns_dbiterator_t **iteratorp);static isc_result_t dbiterator_first(dns_dbiterator_t *iterator);static isc_result_t dbiterator_last(dns_dbiterator_t *iterator);static isc_result_t dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name);static isc_result_t dbiterator_prev(dns_dbiterator_t *iterator);static isc_result_t dbiterator_next(dns_dbiterator_t *iterator);static isc_result_t dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep, dns_name_t *name);static isc_result_t dbiterator_pause(dns_dbiterator_t *iterator);static isc_result_t dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name);static dns_dbiteratormethods_t dbiterator_methods = { dbiterator_destroy, dbiterator_first, dbiterator_last, dbiterator_seek, dbiterator_prev, dbiterator_next, dbiterator_current, dbiterator_pause, dbiterator_origin};static void rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp);static isc_result_t rdatasetiter_first(dns_rdatasetiter_t *iterator);static isc_result_t rdatasetiter_next(dns_rdatasetiter_t *iterator);static void rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset);static dns_rdatasetitermethods_t rdatasetiter_methods = { rdatasetiter_destroy, rdatasetiter_first, rdatasetiter_next, rdatasetiter_current};/* * Functions used by implementors of simple databases */isc_result_tdns_sdb_register(const char *drivername, const dns_sdbmethods_t *methods, void *driverdata, unsigned int flags, isc_mem_t *mctx, dns_sdbimplementation_t **sdbimp){ dns_sdbimplementation_t *imp; isc_result_t result; REQUIRE(drivername != NULL); REQUIRE(methods != NULL); REQUIRE(methods->lookup != NULL); REQUIRE(mctx != NULL); REQUIRE(sdbimp != NULL && *sdbimp == NULL); REQUIRE((flags & ~(DNS_SDBFLAG_RELATIVEOWNER | DNS_SDBFLAG_RELATIVERDATA | DNS_SDBFLAG_THREADSAFE)) == 0); imp = isc_mem_get(mctx, sizeof(dns_sdbimplementation_t)); if (imp == NULL) return (ISC_R_NOMEMORY); imp->methods = methods; imp->driverdata = driverdata; imp->flags = flags; imp->mctx = NULL; isc_mem_attach(mctx, &imp->mctx); result = isc_mutex_init(&imp->driverlock); if (result != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_mutex_init() failed: %s", isc_result_totext(result)); goto cleanup_mctx; } imp->dbimp = NULL; result = dns_db_register(drivername, dns_sdb_create, imp, mctx, &imp->dbimp); if (result != ISC_R_SUCCESS) goto cleanup_mutex; *sdbimp = imp; return (ISC_R_SUCCESS); cleanup_mutex: DESTROYLOCK(&imp->driverlock); cleanup_mctx: isc_mem_put(mctx, imp, sizeof(dns_sdbimplementation_t)); return (result);}voiddns_sdb_unregister(dns_sdbimplementation_t **sdbimp) { dns_sdbimplementation_t *imp; isc_mem_t *mctx; REQUIRE(sdbimp != NULL && *sdbimp != NULL); imp = *sdbimp; dns_db_unregister(&imp->dbimp); DESTROYLOCK(&imp->driverlock); mctx = imp->mctx; isc_mem_put(mctx, imp, sizeof(dns_sdbimplementation_t)); isc_mem_detach(&mctx); *sdbimp = NULL;}static inline unsigned intinitial_size(unsigned int len) { unsigned int size; for (size = 64; size < (64 * 1024); size *= 2) if (len < size) return (size); return (64 * 1024);}isc_result_tdns_sdb_putrdata(dns_sdblookup_t *lookup, dns_rdatatype_t typeval, dns_ttl_t ttl, const unsigned char *rdatap, unsigned int rdlen){ dns_rdatalist_t *rdatalist; dns_rdata_t *rdata; isc_buffer_t *rdatabuf = NULL; isc_result_t result; isc_mem_t *mctx; isc_region_t region; mctx = lookup->sdb->common.mctx; rdatalist = ISC_LIST_HEAD(lookup->lists); while (rdatalist != NULL) { if (rdatalist->type == typeval) break; rdatalist = ISC_LIST_NEXT(rdatalist, link); } if (rdatalist == NULL) { rdatalist = isc_mem_get(mctx, sizeof(dns_rdatalist_t)); if (rdatalist == NULL) return (ISC_R_NOMEMORY); rdatalist->rdclass = lookup->sdb->common.rdclass; rdatalist->type = typeval; rdatalist->covers = 0; rdatalist->ttl = ttl; ISC_LIST_INIT(rdatalist->rdata); ISC_LINK_INIT(rdatalist, link); ISC_LIST_APPEND(lookup->lists, rdatalist, link); } else if (rdatalist->ttl != ttl) return (DNS_R_BADTTL); rdata = isc_mem_get(mctx, sizeof(dns_rdata_t)); if (rdata == NULL) return (ISC_R_NOMEMORY); result = isc_buffer_allocate(mctx, &rdatabuf, rdlen); if (result != ISC_R_SUCCESS) goto failure; DE_CONST(rdatap, region.base); region.length = rdlen; isc_buffer_copyregion(rdatabuf, ®ion); isc_buffer_usedregion(rdatabuf, ®ion); dns_rdata_init(rdata); dns_rdata_fromregion(rdata, rdatalist->rdclass, rdatalist->type, ®ion); ISC_LIST_APPEND(rdatalist->rdata, rdata, link); ISC_LIST_APPEND(lookup->buffers, rdatabuf, link); rdata = NULL; failure: if (rdata != NULL) isc_mem_put(mctx, rdata, sizeof(dns_rdata_t)); return (result);} isc_result_tdns_sdb_putrr(dns_sdblookup_t *lookup, const char *type, dns_ttl_t ttl, const char *data){ unsigned int datalen; dns_rdatatype_t typeval; isc_textregion_t r; isc_lex_t *lex = NULL; isc_result_t result; unsigned char *p = NULL; unsigned int size = 0; /* Init to suppress compiler warning */ isc_mem_t *mctx; dns_sdbimplementation_t *imp; dns_name_t *origin; isc_buffer_t b; isc_buffer_t rb; REQUIRE(VALID_SDBLOOKUP(lookup)); REQUIRE(type != NULL); REQUIRE(data != NULL); mctx = lookup->sdb->common.mctx; DE_CONST(type, r.base); r.length = strlen(type); result = dns_rdatatype_fromtext(&typeval, &r); if (result != ISC_R_SUCCESS) return (result); imp = lookup->sdb->implementation; if ((imp->flags & DNS_SDBFLAG_RELATIVERDATA) != 0) origin = &lookup->sdb->common.origin; else origin = dns_rootname; result = isc_lex_create(mctx, 64, &lex); if (result != ISC_R_SUCCESS) goto failure; datalen = strlen(data); size = initial_size(datalen); for (;;) { isc_buffer_init(&b, data, datalen); isc_buffer_add(&b, datalen); result = isc_lex_openbuffer(lex, &b); if (result != ISC_R_SUCCESS) goto failure; p = isc_mem_get(mctx, size); if (p == NULL) { result = ISC_R_NOMEMORY; goto failure; } isc_buffer_init(&rb, p, size); result = dns_rdata_fromtext(NULL, lookup->sdb->common.rdclass, typeval, lex, origin, 0, mctx, &rb, &lookup->callbacks); if (result != ISC_R_NOSPACE) break; isc_mem_put(mctx, p, size); p = NULL; size *= 2; } while (result == ISC_R_NOSPACE); if (result != ISC_R_SUCCESS) goto failure; result = dns_sdb_putrdata(lookup, typeval, ttl, isc_buffer_base(&rb), isc_buffer_usedlength(&rb)); failure: if (p != NULL) isc_mem_put(mctx, p, size); if (lex != NULL) isc_lex_destroy(&lex); return (result);}static isc_result_tgetnode(dns_sdballnodes_t *allnodes, const char *name, dns_sdbnode_t **nodep) { dns_name_t *newname, *origin; dns_fixedname_t fnewname; dns_sdb_t *sdb = (dns_sdb_t *)allnodes->common.db; dns_sdbimplementation_t *imp = sdb->implementation; dns_sdbnode_t *sdbnode; isc_mem_t *mctx = sdb->common.mctx; isc_buffer_t b; isc_result_t result; dns_fixedname_init(&fnewname); newname = dns_fixedname_name(&fnewname); if ((imp->flags & DNS_SDBFLAG_RELATIVERDATA) != 0) origin = &sdb->common.origin; else origin = dns_rootname; isc_buffer_init(&b, name, strlen(name)); isc_buffer_add(&b, strlen(name)); result = dns_name_fromtext(newname, &b, origin, ISC_FALSE, NULL); if (result != ISC_R_SUCCESS) return (result); if (allnodes->common.relative_names) { /* All names are relative to the root */ unsigned int nlabels = dns_name_countlabels(newname); dns_name_getlabelsequence(newname, 0, nlabels - 1, newname); } sdbnode = ISC_LIST_HEAD(allnodes->nodelist); if (sdbnode == NULL || !dns_name_equal(sdbnode->name, newname)) { sdbnode = NULL; result = createnode(sdb, &sdbnode); if (result != ISC_R_SUCCESS) return (result); sdbnode->name = isc_mem_get(mctx, sizeof(dns_name_t)); if (sdbnode->name == NULL) { destroynode(sdbnode); return (ISC_R_NOMEMORY); } dns_name_init(sdbnode->name, NULL); result = dns_name_dup(newname, mctx, sdbnode->name); if (result != ISC_R_SUCCESS) { isc_mem_put(mctx, sdbnode->name, sizeof(dns_name_t)); destroynode(sdbnode); return (result); } ISC_LIST_PREPEND(allnodes->nodelist, sdbnode, link); if (allnodes->origin == NULL && dns_name_equal(newname, &sdb->common.origin)) allnodes->origin = sdbnode; } *nodep = sdbnode; return (ISC_R_SUCCESS);}isc_result_tdns_sdb_putnamedrr(dns_sdballnodes_t *allnodes, const char *name, const char *type, dns_ttl_t ttl, const char *data){ isc_result_t result; dns_sdbnode_t *sdbnode = NULL; result = getnode(allnodes, name, &sdbnode); if (result != ISC_R_SUCCESS) return (result); return (dns_sdb_putrr(sdbnode, type, ttl, data));}isc_result_tdns_sdb_putnamedrdata(dns_sdballnodes_t *allnodes, const char *name, dns_rdatatype_t type, dns_ttl_t ttl, const void *rdata, unsigned int rdlen){ isc_result_t result; dns_sdbnode_t *sdbnode = NULL; result = getnode(allnodes, name, &sdbnode); if (result != ISC_R_SUCCESS) return (result); return (dns_sdb_putrdata(sdbnode, type, ttl, rdata, rdlen));}isc_result_tdns_sdb_putsoa(dns_sdblookup_t *lookup, const char *mname, const char *rname, isc_uint32_t serial){ char str[2 * DNS_NAME_MAXTEXT + 5 * (sizeof("2147483647")) + 7]; int n;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -