move slab rdataset implementation to rdataslab.c

ultimately we want the slab implementation of dns_rdataset to
be usable by more database implementaions than just rbtdb. this
commit moves rdataset_methods to rdataslab.c, renamed
dns_rdataslab_rdatasetmethods.

new database methods have been added: locknode, unlocknode,
addglue, expiredata, and deletedata, allowing external functions to
perform functions that previously required internal access to the
database implementation.

database and heap pointers are now stored in the dns_slabheader object
so that header is the only thing that needs to be passed to some
functions; this will simplify moving functions that process slabheaders
out of rbtdb.c so they can be used by other database implementations.
This commit is contained in:
Evan Hunt 2023-05-09 23:07:50 -07:00 committed by Ondřej Surý
parent 17f85f6c93
commit 445ef1d033
No known key found for this signature in database
GPG key ID: 2820F37E873DEA41
11 changed files with 1337 additions and 1456 deletions

View file

@ -1061,3 +1061,47 @@ dns_db_setgluecachestats(dns_db_t *db, isc_stats_t *stats) {
return (ISC_R_NOTIMPLEMENTED);
}
isc_result_t
dns_db_addglue(dns_db_t *db, dns_dbversion_t *version, dns_rdataset_t *rdataset,
dns_message_t *msg) {
REQUIRE(DNS_DB_VALID(db));
REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
REQUIRE(DNS_RDATASET_VALID(rdataset));
REQUIRE(rdataset->methods != NULL);
REQUIRE(rdataset->type == dns_rdatatype_ns);
if (db->methods->addglue != NULL) {
return ((db->methods->addglue)(db, version, rdataset, msg));
}
return (ISC_R_NOTIMPLEMENTED);
}
void
dns_db_locknode(dns_db_t *db, dns_dbnode_t *node, isc_rwlocktype_t type) {
if (db->methods->locknode != NULL) {
(db->methods->locknode)(db, node, type);
}
}
void
dns_db_unlocknode(dns_db_t *db, dns_dbnode_t *node, isc_rwlocktype_t type) {
if (db->methods->unlocknode != NULL) {
(db->methods->unlocknode)(db, node, type);
}
}
void
dns_db_expiredata(dns_db_t *db, dns_dbnode_t *node, void *data) {
if (db->methods->expiredata != NULL) {
(db->methods->expiredata)(db, node, data);
}
}
void
dns_db_deletedata(dns_db_t *db, dns_dbnode_t *node, void *data) {
if (db->methods->deletedata != NULL) {
(db->methods->deletedata)(db, node, data);
}
}

View file

@ -55,6 +55,7 @@
#include <isc/lang.h>
#include <isc/magic.h>
#include <isc/rwlock.h>
#include <isc/stats.h>
#include <isc/stdtime.h>
@ -171,6 +172,13 @@ typedef struct dns_dbmethods {
isc_result_t (*setservestalerefresh)(dns_db_t *db, uint32_t interval);
isc_result_t (*getservestalerefresh)(dns_db_t *db, uint32_t *interval);
isc_result_t (*setgluecachestats)(dns_db_t *db, isc_stats_t *stats);
void (*locknode)(dns_db_t *db, dns_dbnode_t *node, isc_rwlocktype_t t);
void (*unlocknode)(dns_db_t *db, dns_dbnode_t *node,
isc_rwlocktype_t t);
isc_result_t (*addglue)(dns_db_t *db, dns_dbversion_t *version,
dns_rdataset_t *rdataset, dns_message_t *msg);
void (*expiredata)(dns_db_t *db, dns_dbnode_t *node, void *data);
void (*deletedata)(dns_db_t *db, dns_dbnode_t *node, void *data);
} dns_dbmethods_t;
typedef isc_result_t (*dns_dbcreatefunc_t)(isc_mem_t *mctx,
@ -1715,4 +1723,50 @@ dns_db_setgluecachestats(dns_db_t *db, isc_stats_t *stats);
* dns_rdatasetstats_create(); otherwise NULL.
*/
void
dns_db_locknode(dns_db_t *db, dns_dbnode_t *node, isc_rwlocktype_t type);
void
dns_db_unlocknode(dns_db_t *db, dns_dbnode_t *node, isc_rwlocktype_t type);
/*%<
* Lock/unlock a single node within a database so that data stored
* there can be manipulated directly.
*/
isc_result_t
dns_db_addglue(dns_db_t *db, dns_dbversion_t *version, dns_rdataset_t *rdataset,
dns_message_t *msg);
/*%<
* Add glue records for rdataset to the additional section of message in
* 'msg'. 'rdataset' must be of type NS.
*
* Requires:
* \li 'db' is a database with 'zone' semantics.
* \li 'version' is the DB version.
* \li 'rdataset' is a valid NS rdataset.
* \li 'msg' is the DNS message to which the glue should be added.
*
* Returns:
*\li #ISC_R_SUCCESS
*\li #ISC_R_NOTIMPLEMENTED
*\li #ISC_R_FAILURE
*\li Any error that dns_rdata_additionaldata() can return.
*/
void
dns_db_expiredata(dns_db_t *db, dns_dbnode_t *node, void *data);
/*%<
* Tell the database 'db' to mark a block of data 'data' stored at
* node 'node' as expired.
*/
void
dns_db_deletedata(dns_db_t *db, dns_dbnode_t *node, void *data);
/*%<
* Tell the database 'db' to prepare to delete the block of data 'data'
* stored at node 'node. This may include, for example, removing the
* data from an LRU list or a heap.
*/
void
dns_db_expiredata(dns_db_t *db, dns_dbnode_t *node, void *data);
ISC_LANG_ENDDECLS

View file

@ -54,6 +54,18 @@
#include <dns/rdatastruct.h>
#include <dns/types.h>
/* Fixed RRSet helper macros */
#define DNS_RDATASET_LENGTH 2;
#if DNS_RDATASET_FIXED
#define DNS_RDATASET_ORDER 2
#define DNS_RDATASET_COUNT (count * 4)
#else /* !DNS_RDATASET_FIXED */
#define DNS_RDATASET_ORDER 0
#define DNS_RDATASET_COUNT 0
#endif /* DNS_RDATASET_FIXED */
ISC_LANG_BEGINDECLS
typedef enum {
@ -648,28 +660,6 @@ dns_rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name);
* according to it. If CASESET is not set, do nothing.
*/
isc_result_t
dns_rdataset_addglue(dns_rdataset_t *rdataset, dns_dbversion_t *version,
dns_message_t *msg);
/*%<
* Add glue records for rdataset to the additional section of message in
* 'msg'. 'rdataset' must be of type NS.
*
* In case a successful result is not returned, the caller should try to
* add glue directly to the message by iterating for additional data.
*
* Requires:
* \li 'rdataset' is a valid NS rdataset.
* \li 'version' is the DB version.
* \li 'msg' is the DNS message to which the glue should be added.
*
* Returns:
*\li #ISC_R_SUCCESS
*\li #ISC_R_NOTIMPLEMENTED
*\li #ISC_R_FAILURE
*\li Any error that dns_rdata_additionaldata() can return.
*/
void
dns_rdataset_trimttl(dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
dns_rdata_rrsig_t *rrsig, isc_stdtime_t now,

View file

@ -43,7 +43,9 @@
#include <stdbool.h>
#include <isc/heap.h>
#include <isc/lang.h>
#include <isc/urcu.h>
#include <dns/types.h>
@ -54,6 +56,109 @@ ISC_LANG_BEGINDECLS
#define DNS_RDATASLAB_OFFLINE 0x01 /* RRSIG is for offline DNSKEY */
struct dns_proof {
dns_name_t name;
void *neg;
void *negsig;
dns_rdatatype_t type;
};
struct dns_slabheader {
/*%
* Locked by the owning node's lock.
*/
uint32_t serial;
dns_ttl_t ttl;
dns_typepair_t type;
atomic_uint_least16_t attributes;
dns_trust_t trust;
unsigned int heap_index;
/*%<
* Used for TTL-based cache cleaning.
*/
isc_stdtime_t resign;
unsigned int resign_lsb : 1;
atomic_uint_fast16_t count;
/*%<
* Monotonically increased every time this rdataset is bound so that
* it is used as the base of the starting point in DNS responses
* when the "cyclic" rrset-order is required.
*/
atomic_uint_fast32_t last_refresh_fail_ts;
dns_proof_t *noqname;
dns_proof_t *closest;
/*%<
* We don't use the LIST macros, because the LIST structure has
* both head and tail pointers, and is doubly linked.
*/
struct dns_slabheader *next;
/*%<
* If this is the top header for an rdataset, 'next' points
* to the top header for the next rdataset (i.e., the next type).
* Otherwise, it points up to the header whose down pointer points
* at this header.
*/
struct dns_slabheader *down;
/*%<
* Points to the header for the next older version of
* this rdataset.
*/
dns_db_t *db;
dns_dbnode_t *node;
/*%<
* The database and database node objects containing
* this rdataset, if any.
*/
isc_stdtime_t last_used;
ISC_LINK(struct dns_slabheader) link;
/*%
* Case vector. If the bit is set then the corresponding
* character in the owner name needs to be AND'd with 0x20,
* rendering that character upper case.
*/
unsigned char upper[32];
isc_heap_t *heap;
dns_glue_t *glue_list;
struct cds_wfs_node wfs_node;
};
enum {
DNS_SLABHEADERATTR_NONEXISTENT = 1 << 0,
DNS_SLABHEADERATTR_STALE = 1 << 1,
DNS_SLABHEADERATTR_IGNORE = 1 << 2,
DNS_SLABHEADERATTR_NXDOMAIN = 1 << 3,
DNS_SLABHEADERATTR_RESIGN = 1 << 4,
DNS_SLABHEADERATTR_STATCOUNT = 1 << 5,
DNS_SLABHEADERATTR_OPTOUT = 1 << 6,
DNS_SLABHEADERATTR_NEGATIVE = 1 << 7,
DNS_SLABHEADERATTR_PREFETCH = 1 << 8,
DNS_SLABHEADERATTR_CASESET = 1 << 9,
DNS_SLABHEADERATTR_ZEROTTL = 1 << 10,
DNS_SLABHEADERATTR_CASEFULLYLOWER = 1 << 11,
DNS_SLABHEADERATTR_ANCIENT = 1 << 12,
DNS_SLABHEADERATTR_STALE_WINDOW = 1 << 13,
};
#define DNS_SLABHEADER_GETATTR(header, attribute) \
(atomic_load_acquire(&(header)->attributes) & attribute)
#define DNS_SLABHEADER_SETATTR(header, attribute) \
atomic_fetch_or_release(&(header)->attributes, attribute)
#define DNS_SLABHEADER_CLRATTR(header, attribute) \
atomic_fetch_and_release(&(header)->attributes, ~(attribute))
extern dns_rdatasetmethods_t dns_rdataslab_rdatasetmethods;
/***
*** Functions
***/
@ -161,4 +266,47 @@ dns_rdataslab_equalx(unsigned char *slab1, unsigned char *slab2,
*\li true if the slabs are equal, #false otherwise.
*/
dns_slabheader_t *
dns_slabheader_fromrdataset(const dns_rdataset_t *rdataset);
/*%
* Returns the address of the slab header for a slab-type rdataset.
*/
void *
dns_slabheader_raw(dns_slabheader_t *header);
/*%
* Returns the address of the raw memory following a dns_slabheader.
*/
void
dns_slabheader_setownercase(dns_slabheader_t *header, const dns_name_t *name);
/*%<
* Store the casing of 'name', into a bitfield in 'header'.
*/
void
dns_slabheader_copycase(dns_slabheader_t *dest, dns_slabheader_t *src);
/*%<
* Copy the casing of 'src', into 'dest'.
*/
void
dns_slabheader_reset(dns_slabheader_t *h, dns_db_t *db, dns_dbnode_t *node);
/*%<
* Reset an rdataslab header 'h' so it can be used to store data in
* database 'db' and node 'node'.
*/
dns_slabheader_t *
dns_slabheader_new(dns_db_t *db, dns_dbnode_t *node);
/*%<
* Allocate memory for an rdataslab header and initialize it for use
* in database 'db'/node 'node'.
*/
void
dns_slabheader_destroy(dns_slabheader_t **headerp);
/*%<
* Free all memory associated with '*headerp'.
*/
ISC_LANG_ENDDECLS

View file

@ -93,6 +93,7 @@ typedef struct dns_forwarders dns_forwarders_t;
typedef struct dns_forwarder dns_forwarder_t;
typedef struct dns_fwdtable dns_fwdtable_t;
typedef struct dns_geoip_databases dns_geoip_databases_t;
typedef struct dns_glue dns_glue_t;
typedef struct dns_iptable dns_iptable_t;
typedef uint32_t dns_iterations_t;
typedef struct dns_kasp dns_kasp_t;

File diff suppressed because it is too large Load diff

View file

@ -13,8 +13,12 @@
#pragma once
#include <isc/heap.h>
#include <isc/lang.h>
#include <isc/urcu.h>
#include <dns/nsec3.h>
#include <dns/rbt.h>
#include <dns/types.h>
/*%
@ -135,6 +139,15 @@
TREE_UNLOCK(l, tp); \
TREE_WRLOCK(l, tp); \
}
#define RDATASET_RBTDB(r) ((dns_rbtdb_t *)(r)->slab.db)
#define RDATASET_DBNODE(r) ((dns_rbtnode_t *)(r)->slab.node)
#define HEADER_NODE(h) ((dns_rbtnode_t *)((h)->node))
#define IS_STUB(rbtdb) (((rbtdb)->common.attributes & DNS_DBATTR_STUB) != 0)
#define IS_CACHE(rbtdb) (((rbtdb)->common.attributes & DNS_DBATTR_CACHE) != 0)
/*****
***** Module Info
*****/
@ -146,6 +159,179 @@
ISC_LANG_BEGINDECLS
typedef struct {
isc_rwlock_t lock;
/* Protected in the refcount routines. */
isc_refcount_t references;
/* Locked by lock. */
bool exiting;
} rbtdb_nodelock_t;
typedef struct rbtdb_changed {
dns_rbtnode_t *node;
bool dirty;
ISC_LINK(struct rbtdb_changed) link;
} rbtdb_changed_t;
typedef ISC_LIST(rbtdb_changed_t) rbtdb_changedlist_t;
struct dns_glue {
struct dns_glue *next;
dns_fixedname_t fixedname;
dns_rdataset_t rdataset_a;
dns_rdataset_t sigrdataset_a;
dns_rdataset_t rdataset_aaaa;
dns_rdataset_t sigrdataset_aaaa;
isc_mem_t *mctx;
struct rcu_head rcu_head;
};
typedef struct {
dns_glue_t *glue_list;
dns_rbtdb_t *rbtdb;
dns_rbtdb_version_t *rbtversion;
dns_name_t *nodename;
} dns_glue_additionaldata_ctx_t;
struct dns_rbtdb_version {
/* Not locked */
uint32_t serial;
dns_rbtdb_t *rbtdb;
/*
* Protected in the refcount routines.
* XXXJT: should we change the lock policy based on the refcount
* performance?
*/
isc_refcount_t references;
/* Locked by database lock. */
bool writer;
bool commit_ok;
rbtdb_changedlist_t changed_list;
dns_slabheaderlist_t resigned_list;
ISC_LINK(dns_rbtdb_version_t) link;
bool secure;
bool havensec3;
/* NSEC3 parameters */
dns_hash_t hash;
uint8_t flags;
uint16_t iterations;
uint8_t salt_length;
unsigned char salt[DNS_NSEC3_SALTSIZE];
/*
* records and xfrsize are covered by rwlock.
*/
isc_rwlock_t rwlock;
uint64_t records;
uint64_t xfrsize;
struct cds_wfs_stack glue_stack;
};
typedef ISC_LIST(dns_rbtdb_version_t) rbtdb_versionlist_t;
struct dns_rbtdb {
/* Unlocked. */
dns_db_t common;
/* Locks the data in this struct */
isc_rwlock_t lock;
/* Locks the tree structure (prevents nodes appearing/disappearing) */
isc_rwlock_t tree_lock;
/* Locks for individual tree nodes */
unsigned int node_lock_count;
rbtdb_nodelock_t *node_locks;
dns_rbtnode_t *origin_node;
dns_rbtnode_t *nsec3_origin_node;
dns_stats_t *rrsetstats; /* cache DB only */
isc_stats_t *cachestats; /* cache DB only */
isc_stats_t *gluecachestats; /* zone DB only */
/* Locked by lock. */
unsigned int active;
unsigned int attributes;
uint32_t current_serial;
uint32_t least_serial;
uint32_t next_serial;
dns_rbtdb_version_t *current_version;
dns_rbtdb_version_t *future_version;
rbtdb_versionlist_t open_versions;
isc_loop_t *loop;
dns_dbnode_t *soanode;
dns_dbnode_t *nsnode;
/*
* The time after a failed lookup, where stale answers from cache
* may be used directly in a DNS response without attempting a
* new iterative lookup.
*/
uint32_t serve_stale_refresh;
/*
* This is a linked list used to implement the LRU cache. There will
* be node_lock_count linked lists here. Nodes in bucket 1 will be
* placed on the linked list lru[1].
*/
dns_slabheaderlist_t *lru;
/*%
* Temporary storage for stale cache nodes and dynamically deleted
* nodes that await being cleaned up.
*/
dns_rbtnodelist_t *deadnodes;
/*
* Heaps. These are used for TTL based expiry in a cache,
* or for zone resigning in a zone DB. hmctx is the memory
* context to use for the heap (which differs from the main
* database memory context in the case of a cache).
*/
isc_mem_t *hmctx;
isc_heap_t **heaps;
/* Locked by tree_lock. */
dns_rbt_t *tree;
dns_rbt_t *nsec;
dns_rbt_t *nsec3;
/* Unlocked */
unsigned int quantum;
};
/*%
* Search Context
*/
typedef struct {
dns_rbtdb_t *rbtdb;
dns_rbtdb_version_t *rbtversion;
uint32_t serial;
unsigned int options;
dns_rbtnodechain_t chain;
bool copy_name;
bool need_cleanup;
bool wild;
dns_rbtnode_t *zonecut;
dns_slabheader_t *zonecut_header;
dns_slabheader_t *zonecut_sigheader;
dns_fixedname_t zonecut_name;
isc_stdtime_t now;
} rbtdb_search_t;
/*%
* Load Context
*/
typedef struct {
dns_rbtdb_t *rbtdb;
isc_stdtime_t now;
} rbtdb_load_t;
/*%
* Prune context
*/
typedef struct {
dns_db_t *db;
dns_rbtnode_t *node;
} prune_t;
extern dns_dbmethods_t dns__rbtdb_zonemethods;
extern dns_dbmethods_t dns__rbtdb_cachemethods;
@ -187,7 +373,10 @@ dns__rbtdb_closeversion(dns_db_t *db, dns_dbversion_t **versionp,
isc_result_t
dns__rbtdb_findnode(dns_db_t *db, const dns_name_t *name, bool create,
dns_dbnode_t **nodep DNS__DB_FLARG);
isc_result_t
dns__rbtdb_findnodeintree(dns_rbtdb_t *rbtdb, dns_rbt_t *tree,
const dns_name_t *name, bool create,
dns_dbnode_t **nodep DNS__DB_FLARG);
void
dns__rbtdb_attachnode(dns_db_t *db, dns_dbnode_t *source,
dns_dbnode_t **targetp DNS__DB_FLARG);
@ -237,8 +426,33 @@ dns__rbtdb_bindrdataset(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
dns_rdataset_t *rdataset DNS__DB_FLARG);
void
dns__rbtdb_expireheader(dns_rbtdb_t *rbtdb, dns_slabheader_t *header,
isc_rwlocktype_t *nlocktypep,
isc_rwlocktype_t *tlocktypep,
dns__rbtdb_expireheader(dns_slabheader_t *header, isc_rwlocktype_t *tlocktypep,
dns_expire_t reason DNS__DB_FLARG);
void
dns__rbtdb_locknode(dns_db_t *db, dns_dbnode_t *node, isc_rwlocktype_t type);
void
dns__rbtdb_unlocknode(dns_db_t *db, dns_dbnode_t *node, isc_rwlocktype_t type);
isc_result_t
dns__rbtdb_nodefullname(dns_db_t *db, dns_dbnode_t *node, dns_name_t *name);
void
dns__rbtdb_freeglue(dns_glue_t *glue_list);
bool
dns__rbtdb_decref(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
uint32_t least_serial, isc_rwlocktype_t *nlocktypep,
isc_rwlocktype_t *tlocktypep, bool tryupgrade,
bool pruning DNS__DB_FLARG);
void
dns__rbtdb_resigninsert(dns_rbtdb_t *rbtdb, int idx,
dns_slabheader_t *newheader);
void
dns__rbtdb_resigndelete(dns_rbtdb_t *rbtdb, dns_rbtdb_version_t *version,
dns_slabheader_t *header DNS__DB_FLARG);
isc_result_t
dns__rbtdb_add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode,
const dns_name_t *nodename, dns_rbtdb_version_t *rbtversion,
dns_slabheader_t *newheader, unsigned int options,
bool loading, dns_rdataset_t *addedrdataset,
isc_stdtime_t now DNS__DB_FLARG);
ISC_LANG_ENDDECLS

View file

@ -671,17 +671,3 @@ dns_rdataset_trimttl(dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
rdataset->ttl = ttl;
sigrdataset->ttl = ttl;
}
isc_result_t
dns_rdataset_addglue(dns_rdataset_t *rdataset, dns_dbversion_t *version,
dns_message_t *msg) {
REQUIRE(DNS_RDATASET_VALID(rdataset));
REQUIRE(rdataset->methods != NULL);
REQUIRE(rdataset->type == dns_rdatatype_ns);
if (rdataset->methods->addglue == NULL) {
return (ISC_R_NOTIMPLEMENTED);
}
return ((rdataset->methods->addglue)(rdataset, version, msg));
}

View file

@ -13,18 +13,32 @@
/*! \file */
#include <ctype.h>
#include <stdbool.h>
#include <stdlib.h>
#include <isc/ascii.h>
#include <isc/mem.h>
#include <isc/region.h>
#include <isc/result.h>
#include <isc/string.h>
#include <isc/util.h>
#include <dns/db.h>
#include <dns/rdata.h>
#include <dns/rdataset.h>
#include <dns/rdataslab.h>
#include <dns/stats.h>
#define CASESET(header) \
((atomic_load_acquire(&(header)->attributes) & \
DNS_SLABHEADERATTR_CASESET) != 0)
#define CASEFULLYLOWER(header) \
((atomic_load_acquire(&(header)->attributes) & \
DNS_SLABHEADERATTR_CASEFULLYLOWER) != 0)
#define NONEXISTENT(header) \
((atomic_load_acquire(&(header)->attributes) & \
DNS_SLABHEADERATTR_NONEXISTENT) != 0)
/*
* The rdataslab structure allows iteration to occur in both load order
@ -75,6 +89,52 @@ struct xrdata {
#endif /* if DNS_RDATASET_FIXED */
};
struct dns_glue {
struct dns_glue *next;
dns_fixedname_t fixedname;
dns_rdataset_t rdataset_a;
dns_rdataset_t sigrdataset_a;
dns_rdataset_t rdataset_aaaa;
dns_rdataset_t sigrdataset_aaaa;
struct cds_wfs_node wfs_node;
};
typedef struct {
dns_glue_t *glue_list;
dns_rbtdb_t *rbtdb;
dns_rbtdb_version_t *rbtversion;
dns_name_t *nodename;
} dns_glue_additionaldata_ctx_t;
static void
rdataset_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG);
static isc_result_t
rdataset_first(dns_rdataset_t *rdataset);
static isc_result_t
rdataset_next(dns_rdataset_t *rdataset);
static void
rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata);
static void
rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target DNS__DB_FLARG);
static unsigned int
rdataset_count(dns_rdataset_t *rdataset);
static isc_result_t
rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
dns_rdataset_t *neg, dns_rdataset_t *negsig DNS__DB_FLARG);
static isc_result_t
rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name,
dns_rdataset_t *neg, dns_rdataset_t *negsig DNS__DB_FLARG);
static void
rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust);
static void
rdataset_expire(dns_rdataset_t *rdataset DNS__DB_FLARG);
static void
rdataset_clearprefetch(dns_rdataset_t *rdataset);
static void
rdataset_setownercase(dns_rdataset_t *rdataset, const dns_name_t *name);
static void
rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name);
/*% Note: the "const void *" are just to make qsort happy. */
static int
compare_rdata(const void *p1, const void *p2) {
@ -919,7 +979,7 @@ dns_rdataslab_subtract(unsigned char *mslab, unsigned char *sslab,
bool
dns_rdataslab_equal(unsigned char *slab1, unsigned char *slab2,
unsigned int reservelen) {
unsigned char *current1, *current2;
unsigned char *current1 = NULL, *current2 = NULL;
unsigned int count1, count2;
unsigned int length1, length2;
@ -970,7 +1030,7 @@ bool
dns_rdataslab_equalx(unsigned char *slab1, unsigned char *slab2,
unsigned int reservelen, dns_rdataclass_t rdclass,
dns_rdatatype_t type) {
unsigned char *current1, *current2;
unsigned char *current1 = NULL, *current2 = NULL;
unsigned int count1, count2;
dns_rdata_t rdata1 = DNS_RDATA_INIT;
dns_rdata_t rdata2 = DNS_RDATA_INIT;
@ -1003,3 +1063,441 @@ dns_rdataslab_equalx(unsigned char *slab1, unsigned char *slab2,
}
return (true);
}
dns_slabheader_t *
dns_slabheader_fromrdataset(const dns_rdataset_t *rdataset) {
dns_slabheader_t *header = (dns_slabheader_t *)rdataset->slab.raw;
return (header - 1);
}
void *
dns_slabheader_raw(dns_slabheader_t *header) {
return (header + 1);
}
void
dns_slabheader_setownercase(dns_slabheader_t *header, const dns_name_t *name) {
unsigned int i;
bool fully_lower;
/*
* We do not need to worry about label lengths as they are all
* less than or equal to 63.
*/
memset(header->upper, 0, sizeof(header->upper));
fully_lower = true;
for (i = 0; i < name->length; i++) {
if (isupper(name->ndata[i])) {
header->upper[i / 8] |= 1 << (i % 8);
fully_lower = false;
}
}
DNS_SLABHEADER_SETATTR(header, DNS_SLABHEADERATTR_CASESET);
if (fully_lower) {
DNS_SLABHEADER_SETATTR(header,
DNS_SLABHEADERATTR_CASEFULLYLOWER);
}
}
void
dns_slabheader_copycase(dns_slabheader_t *dest, dns_slabheader_t *src) {
if (CASESET(src)) {
uint_least16_t attr = DNS_SLABHEADER_GETATTR(
src, (DNS_SLABHEADERATTR_CASESET |
DNS_SLABHEADERATTR_CASEFULLYLOWER));
DNS_SLABHEADER_SETATTR(dest, attr);
memmove(dest->upper, src->upper, sizeof(src->upper));
}
}
void
dns_slabheader_reset(dns_slabheader_t *h, dns_db_t *db, dns_dbnode_t *node) {
ISC_LINK_INIT(h, link);
h->heap_index = 0;
h->heap = NULL;
h->glue_list = NULL;
h->db = db;
h->node = node;
atomic_init(&h->attributes, 0);
atomic_init(&h->last_refresh_fail_ts, 0);
cds_wfs_node_init(&h->wfs_node);
STATIC_ASSERT((sizeof(h->attributes) == 2),
"The .attributes field of dns_slabheader_t needs to be "
"16-bit int type exactly.");
}
dns_slabheader_t *
dns_slabheader_new(dns_db_t *db, dns_dbnode_t *node) {
dns_slabheader_t *h = NULL;
h = isc_mem_get(db->mctx, sizeof(*h));
*h = (dns_slabheader_t){
.link = ISC_LINK_INITIALIZER,
};
dns_slabheader_reset(h, db, node);
return (h);
}
void
dns_slabheader_destroy(dns_slabheader_t **headerp) {
unsigned int size;
dns_slabheader_t *header = *headerp;
*headerp = NULL;
isc_mem_t *mctx = header->db->mctx;
dns_db_deletedata(header->db, header->node, header);
if (NONEXISTENT(header)) {
size = sizeof(*header);
} else {
size = dns_rdataslab_size((unsigned char *)header,
sizeof(*header));
}
isc_mem_put(mctx, header, size);
}
dns_rdatasetmethods_t dns_rdataslab_rdatasetmethods = {
.disassociate = rdataset_disassociate,
.first = rdataset_first,
.next = rdataset_next,
.current = rdataset_current,
.clone = rdataset_clone,
.count = rdataset_count,
.getnoqname = rdataset_getnoqname,
.getclosest = rdataset_getclosest,
.settrust = rdataset_settrust,
.expire = rdataset_expire,
.clearprefetch = rdataset_clearprefetch,
.setownercase = rdataset_setownercase,
.getownercase = rdataset_getownercase,
};
/* Fixed RRSet helper macros */
#define DNS_RDATASET_LENGTH 2;
#if DNS_RDATASET_FIXED
#define DNS_RDATASET_ORDER 2
#define DNS_RDATASET_COUNT (count * 4)
#else /* !DNS_RDATASET_FIXED */
#define DNS_RDATASET_ORDER 0
#define DNS_RDATASET_COUNT 0
#endif /* DNS_RDATASET_FIXED */
static void
rdataset_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG) {
dns_db_t *db = rdataset->slab.db;
dns_dbnode_t *node = rdataset->slab.node;
dns__db_detachnode(db, &node DNS__DB_FLARG_PASS);
}
static isc_result_t
rdataset_first(dns_rdataset_t *rdataset) {
unsigned char *raw = NULL;
unsigned int count;
raw = rdataset->slab.raw;
count = raw[0] * 256 + raw[1];
if (count == 0) {
rdataset->slab.iter_pos = NULL;
rdataset->slab.iter_count = 0;
return (ISC_R_NOMORE);
}
if ((rdataset->attributes & DNS_RDATASETATTR_LOADORDER) == 0) {
raw += DNS_RDATASET_COUNT;
}
/*
* iter_count is the number of rdata beyond the cursor
* position, so we decrement the total count by one before
* storing it.
*
* If DNS_RDATASETATTR_LOADORDER is not set 'raw' points to the
* first record. If DNS_RDATASETATTR_LOADORDER is set 'raw' points
* to the first entry in the offset table.
*/
rdataset->slab.iter_pos = raw + DNS_RDATASET_LENGTH;
rdataset->slab.iter_count = count - 1;
return (ISC_R_SUCCESS);
}
static isc_result_t
rdataset_next(dns_rdataset_t *rdataset) {
unsigned int count;
unsigned int length;
unsigned char *raw = NULL;
count = rdataset->slab.iter_count;
if (count == 0) {
rdataset->slab.iter_pos = NULL;
return (ISC_R_NOMORE);
}
rdataset->slab.iter_count = count - 1;
/*
* Skip forward one record (length + 4) or one offset (4).
*/
raw = rdataset->slab.iter_pos;
#if DNS_RDATASET_FIXED
if ((rdataset->attributes & DNS_RDATASETATTR_LOADORDER) == 0)
#endif /* DNS_RDATASET_FIXED */
{
length = raw[0] * 256 + raw[1];
raw += length;
}
rdataset->slab.iter_pos = raw + DNS_RDATASET_ORDER +
DNS_RDATASET_LENGTH;
return (ISC_R_SUCCESS);
}
static void
rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
unsigned char *raw = NULL;
unsigned int length;
isc_region_t r;
unsigned int flags = 0;
raw = rdataset->slab.iter_pos;
REQUIRE(raw != NULL);
/*
* Find the start of the record if not already in iter_pos
* then skip the length and order fields.
*/
#if DNS_RDATASET_FIXED
if ((rdataset->attributes & DNS_RDATASETATTR_LOADORDER) != 0) {
unsigned int offset;
offset = ((unsigned int)raw[0] << 24) +
((unsigned int)raw[1] << 16) +
((unsigned int)raw[2] << 8) + (unsigned int)raw[3];
raw = rdataset->slab.raw + offset;
}
#endif /* if DNS_RDATASET_FIXED */
length = raw[0] * 256 + raw[1];
raw += DNS_RDATASET_ORDER + DNS_RDATASET_LENGTH;
if (rdataset->type == dns_rdatatype_rrsig) {
if (*raw & DNS_RDATASLAB_OFFLINE) {
flags |= DNS_RDATA_OFFLINE;
}
length--;
raw++;
}
r.length = length;
r.base = raw;
dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
rdata->flags |= flags;
}
static void
rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target DNS__DB_FLARG) {
dns_db_t *db = source->slab.db;
dns_dbnode_t *node = source->slab.node;
dns_dbnode_t *cloned_node = NULL;
dns__db_attachnode(db, node, &cloned_node DNS__DB_FLARG_PASS);
INSIST(!ISC_LINK_LINKED(target, link));
*target = *source;
ISC_LINK_INIT(target, link);
target->slab.iter_pos = NULL;
target->slab.iter_count = 0;
}
static unsigned int
rdataset_count(dns_rdataset_t *rdataset) {
unsigned char *raw = NULL;
unsigned int count;
raw = rdataset->slab.raw;
count = raw[0] * 256 + raw[1];
return (count);
}
static isc_result_t
rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
dns_rdataset_t *nsec,
dns_rdataset_t *nsecsig DNS__DB_FLARG) {
dns_db_t *db = rdataset->slab.db;
dns_dbnode_t *node = rdataset->slab.node;
const dns_proof_t *noqname = rdataset->slab.noqname;
/*
* Usually, rdataset->slab.raw refers the data following a
* dns_slabheader, but in this case it points to a bare
* rdataslab belonging to the dns_slabheader's `noqname` field.
* The DNS_RDATASETATTR_KEEPCASE attribute is set to prevent
* setownercase and getownercase methods from affecting the
* case of NSEC/NSEC3 owner names.
*/
dns__db_attachnode(db, node,
&(dns_dbnode_t *){ NULL } DNS__DB_FLARG_PASS);
*nsec = (dns_rdataset_t){
.methods = &dns_rdataslab_rdatasetmethods,
.rdclass = db->rdclass,
.type = noqname->type,
.ttl = rdataset->ttl,
.trust = rdataset->trust,
.slab.db = db,
.slab.node = node,
.slab.raw = noqname->neg,
.link = nsec->link,
.count = nsec->count,
.attributes = nsec->attributes | DNS_RDATASETATTR_KEEPCASE,
.magic = nsec->magic,
};
dns__db_attachnode(db, node,
&(dns_dbnode_t *){ NULL } DNS__DB_FLARG_PASS);
*nsecsig = (dns_rdataset_t){
.methods = &dns_rdataslab_rdatasetmethods,
.rdclass = db->rdclass,
.type = dns_rdatatype_rrsig,
.covers = noqname->type,
.ttl = rdataset->ttl,
.trust = rdataset->trust,
.slab.db = db,
.slab.node = node,
.slab.raw = noqname->negsig,
.link = nsecsig->link,
.count = nsecsig->count,
.attributes = nsecsig->attributes | DNS_RDATASETATTR_KEEPCASE,
.magic = nsecsig->magic,
};
dns_name_clone(&noqname->name, name);
return (ISC_R_SUCCESS);
}
static isc_result_t
rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name,
dns_rdataset_t *nsec,
dns_rdataset_t *nsecsig DNS__DB_FLARG) {
dns_db_t *db = rdataset->slab.db;
dns_dbnode_t *node = rdataset->slab.node;
const dns_proof_t *closest = rdataset->slab.closest;
/*
* As mentioned above, rdataset->slab.raw usually refers the data
* following an dns_slabheader, but in this case it points to a bare
* rdataslab belonging to the dns_slabheader's `closest` field.
*/
dns__db_attachnode(db, node,
&(dns_dbnode_t *){ NULL } DNS__DB_FLARG_PASS);
*nsec = (dns_rdataset_t){
.methods = &dns_rdataslab_rdatasetmethods,
.rdclass = db->rdclass,
.type = closest->type,
.ttl = rdataset->ttl,
.trust = rdataset->trust,
.slab.db = db,
.slab.node = node,
.slab.raw = closest->neg,
.link = nsec->link,
.count = nsec->count,
.attributes = nsec->attributes | DNS_RDATASETATTR_KEEPCASE,
.magic = nsec->magic,
};
dns__db_attachnode(db, node,
&(dns_dbnode_t *){ NULL } DNS__DB_FLARG_PASS);
*nsecsig = (dns_rdataset_t){
.methods = &dns_rdataslab_rdatasetmethods,
.rdclass = db->rdclass,
.type = dns_rdatatype_rrsig,
.covers = closest->type,
.ttl = rdataset->ttl,
.trust = rdataset->trust,
.slab.db = db,
.slab.node = node,
.slab.raw = closest->negsig,
.link = nsecsig->link,
.count = nsecsig->count,
.attributes = nsecsig->attributes | DNS_RDATASETATTR_KEEPCASE,
.magic = nsecsig->magic,
};
dns_name_clone(&closest->name, name);
return (ISC_R_SUCCESS);
}
static void
rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) {
dns_slabheader_t *header = dns_slabheader_fromrdataset(rdataset);
dns_db_locknode(header->db, header->node, isc_rwlocktype_write);
header->trust = rdataset->trust = trust;
dns_db_unlocknode(header->db, header->node, isc_rwlocktype_write);
}
static void
rdataset_expire(dns_rdataset_t *rdataset DNS__DB_FLARG) {
dns_slabheader_t *header = dns_slabheader_fromrdataset(rdataset);
dns_db_expiredata(header->db, header->node, header);
}
static void
rdataset_clearprefetch(dns_rdataset_t *rdataset) {
dns_slabheader_t *header = dns_slabheader_fromrdataset(rdataset);
dns_db_locknode(header->db, header->node, isc_rwlocktype_write);
DNS_SLABHEADER_CLRATTR(header, DNS_SLABHEADERATTR_PREFETCH);
dns_db_unlocknode(header->db, header->node, isc_rwlocktype_write);
}
static void
rdataset_setownercase(dns_rdataset_t *rdataset, const dns_name_t *name) {
dns_slabheader_t *header = dns_slabheader_fromrdataset(rdataset);
dns_db_locknode(header->db, header->node, isc_rwlocktype_write);
dns_slabheader_setownercase(header, name);
dns_db_unlocknode(header->db, header->node, isc_rwlocktype_write);
}
static void
rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name) {
dns_slabheader_t *header = dns_slabheader_fromrdataset(rdataset);
uint8_t mask = (1 << 7);
uint8_t bits = 0;
dns_db_locknode(header->db, header->node, isc_rwlocktype_write);
if (!CASESET(header)) {
goto unlock;
}
if (CASEFULLYLOWER(header)) {
isc_ascii_lowercopy(name->ndata, name->ndata, name->length);
} else {
uint8_t *nd = name->ndata;
for (size_t i = 0; i < name->length; i++) {
if (mask == (1 << 7)) {
bits = header->upper[i / 8];
mask = 1;
} else {
mask <<= 1;
}
nd[i] = (bits & mask) ? isc_ascii_toupper(nd[i])
: isc_ascii_tolower(nd[i]);
}
}
unlock:
dns_db_unlocknode(header->db, header->node, isc_rwlocktype_write);
}

View file

@ -2140,15 +2140,15 @@ query_additional(query_ctx_t *qctx, dns_name_t *name,
if (rdataset->type == dns_rdatatype_ns &&
client->query.gluedb != NULL && dns_db_iszone(client->query.gluedb))
{
ns_dbversion_t *dbversion;
ns_dbversion_t *dbversion = NULL;
dbversion = ns_client_findversion(client, client->query.gluedb);
if (dbversion == NULL) {
goto regular;
}
result = dns_rdataset_addglue(rdataset, dbversion->version,
client->message);
result = dns_db_addglue(qctx->db, dbversion->version, rdataset,
client->message);
if (result == ISC_R_SUCCESS) {
return;
}

View file

@ -96,16 +96,23 @@ static bool
ownercase_test_one(const char *str1, const char *str2) {
isc_result_t result;
rbtdb_nodelock_t node_locks[1];
dns_rbtdb_t rbtdb = { .node_locks = node_locks };
dns_rbtdb_t rbtdb = {
.common.methods = &dns__rbtdb_zonemethods,
.common.mctx = mctx,
.node_locks = node_locks,
};
dns_rbtnode_t rbtnode = { .locknum = 0 };
dns_slabheader_t header = { 0 };
dns_slabheader_t header = {
.node = &rbtnode,
.db = (dns_db_t *)&rbtdb,
};
unsigned char *raw = (unsigned char *)(&header) + sizeof(header);
dns_rdataset_t rdataset = {
.magic = DNS_RDATASET_MAGIC,
.slab = { .db = (dns_db_t *)&rbtdb,
.node = &rbtnode,
.raw = raw },
.methods = &rdataset_methods,
.methods = &dns_rdataslab_rdatasetmethods,
};
isc_buffer_t b;
dns_fixedname_t fname1, fname2;
@ -156,16 +163,23 @@ ISC_RUN_TEST_IMPL(ownercase) {
ISC_RUN_TEST_IMPL(setownercase) {
isc_result_t result;
rbtdb_nodelock_t node_locks[1];
dns_rbtdb_t rbtdb = { .node_locks = node_locks };
dns_rbtdb_t rbtdb = {
.common.methods = &dns__rbtdb_zonemethods,
.common.mctx = mctx,
.node_locks = node_locks,
};
dns_rbtnode_t rbtnode = { .locknum = 0 };
dns_slabheader_t header = { 0 };
dns_slabheader_t header = {
.node = &rbtnode,
.db = (dns_db_t *)&rbtdb,
};
unsigned char *raw = (unsigned char *)(&header) + sizeof(header);
dns_rdataset_t rdataset = {
.magic = DNS_RDATASET_MAGIC,
.slab = { .db = (dns_db_t *)&rbtdb,
.node = &rbtnode,
.raw = raw },
.methods = &rdataset_methods,
.methods = &dns_rdataslab_rdatasetmethods,
};
const char *str1 =
"AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz";