mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-30 14:07:59 +00:00
Add dns_db_subtractrdataset().
Add DNS_R_UNCHANGED results for dns_db_{add,delete}rdataset(). Add merge flag to dns_db_addrdataset(). The way add and delete work should now match the .h file comments.
This commit is contained in:
31
lib/dns/db.c
31
lib/dns/db.c
@@ -420,7 +420,7 @@ dns_db_allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
|||||||
dns_result_t
|
dns_result_t
|
||||||
dns_db_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
dns_db_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
||||||
isc_stdtime_t now, dns_rdataset_t *rdataset,
|
isc_stdtime_t now, dns_rdataset_t *rdataset,
|
||||||
dns_rdataset_t *addedrdataset)
|
isc_boolean_t merge, dns_rdataset_t *addedrdataset)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Add 'rdataset' to 'node' in version 'version' of 'db'.
|
* Add 'rdataset' to 'node' in version 'version' of 'db'.
|
||||||
@@ -429,7 +429,8 @@ dns_db_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
|||||||
REQUIRE(DNS_DB_VALID(db));
|
REQUIRE(DNS_DB_VALID(db));
|
||||||
REQUIRE(node != NULL);
|
REQUIRE(node != NULL);
|
||||||
REQUIRE(((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL)||
|
REQUIRE(((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL)||
|
||||||
((db->attributes & DNS_DBATTR_CACHE) != 0 && version == NULL));
|
((db->attributes & DNS_DBATTR_CACHE) != 0 &&
|
||||||
|
version == NULL && !merge));
|
||||||
REQUIRE(DNS_RDATASET_VALID(rdataset));
|
REQUIRE(DNS_RDATASET_VALID(rdataset));
|
||||||
REQUIRE(rdataset->methods != NULL);
|
REQUIRE(rdataset->methods != NULL);
|
||||||
REQUIRE(rdataset->rdclass == db->rdclass);
|
REQUIRE(rdataset->rdclass == db->rdclass);
|
||||||
@@ -438,7 +439,31 @@ dns_db_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
|||||||
addedrdataset->methods == NULL));
|
addedrdataset->methods == NULL));
|
||||||
|
|
||||||
return ((db->methods->addrdataset)(db, node, version, now, rdataset,
|
return ((db->methods->addrdataset)(db, node, version, now, rdataset,
|
||||||
addedrdataset));
|
merge, addedrdataset));
|
||||||
|
}
|
||||||
|
|
||||||
|
dns_result_t
|
||||||
|
dns_db_subtractrdataset(dns_db_t *db, dns_dbnode_t *node,
|
||||||
|
dns_dbversion_t *version, dns_rdataset_t *rdataset,
|
||||||
|
dns_rdataset_t *newrdataset)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Remove any rdata in 'rdataset' from 'node' in version 'version' of
|
||||||
|
* 'db'.
|
||||||
|
*/
|
||||||
|
|
||||||
|
REQUIRE(DNS_DB_VALID(db));
|
||||||
|
REQUIRE(node != NULL);
|
||||||
|
REQUIRE(((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL));
|
||||||
|
REQUIRE(DNS_RDATASET_VALID(rdataset));
|
||||||
|
REQUIRE(rdataset->methods != NULL);
|
||||||
|
REQUIRE(rdataset->rdclass == db->rdclass);
|
||||||
|
REQUIRE(newrdataset == NULL ||
|
||||||
|
(DNS_RDATASET_VALID(newrdataset) &&
|
||||||
|
newrdataset->methods == NULL));
|
||||||
|
|
||||||
|
return ((db->methods->subtractrdataset)(db, node, version, rdataset,
|
||||||
|
newrdataset));
|
||||||
}
|
}
|
||||||
|
|
||||||
dns_result_t
|
dns_result_t
|
||||||
|
@@ -119,7 +119,12 @@ typedef struct dns_dbmethods {
|
|||||||
dns_dbversion_t *version,
|
dns_dbversion_t *version,
|
||||||
isc_stdtime_t now,
|
isc_stdtime_t now,
|
||||||
dns_rdataset_t *rdataset,
|
dns_rdataset_t *rdataset,
|
||||||
|
isc_boolean_t merge,
|
||||||
dns_rdataset_t *addedrdataset);
|
dns_rdataset_t *addedrdataset);
|
||||||
|
dns_result_t (*subtractrdataset)(dns_db_t *db, dns_dbnode_t *node,
|
||||||
|
dns_dbversion_t *version,
|
||||||
|
dns_rdataset_t *rdataset,
|
||||||
|
dns_rdataset_t *newrdataset);
|
||||||
dns_result_t (*deleterdataset)(dns_db_t *db, dns_dbnode_t *node,
|
dns_result_t (*deleterdataset)(dns_db_t *db, dns_dbnode_t *node,
|
||||||
dns_dbversion_t *version,
|
dns_dbversion_t *version,
|
||||||
dns_rdatatype_t type);
|
dns_rdatatype_t type);
|
||||||
@@ -794,12 +799,18 @@ dns_db_allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
|||||||
dns_result_t
|
dns_result_t
|
||||||
dns_db_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
dns_db_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
||||||
isc_stdtime_t now, dns_rdataset_t *rdataset,
|
isc_stdtime_t now, dns_rdataset_t *rdataset,
|
||||||
dns_rdataset_t *addedrdataset);
|
isc_boolean_t merge, dns_rdataset_t *addedrdataset);
|
||||||
/*
|
/*
|
||||||
* Add 'rdataset' to 'node' in version 'version' of 'db'.
|
* Add 'rdataset' to 'node' in version 'version' of 'db'.
|
||||||
*
|
*
|
||||||
* Notes:
|
* Notes:
|
||||||
*
|
*
|
||||||
|
* If the database has zone semantics, 'merge' is ISC_TRUE, and an
|
||||||
|
* rdataset of the same type as 'rdataset' already exists at 'node',
|
||||||
|
* then the contents of 'rdataset' will be merged with the existing
|
||||||
|
* rdataset. If merge is ISC_FALSE, then rdataset will replace any
|
||||||
|
* existing rdataset of the same type.
|
||||||
|
*
|
||||||
* The 'now' field is ignored if 'db' is a zone database. If 'db' is
|
* The 'now' field is ignored if 'db' is a zone database. If 'db' is
|
||||||
* a cache database, then the added rdataset will expire no later than
|
* a cache database, then the added rdataset will expire no later than
|
||||||
* now + rdataset->ttl.
|
* now + rdataset->ttl.
|
||||||
@@ -822,13 +833,52 @@ dns_db_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
|||||||
* read-write version, or the database has cache semantics
|
* read-write version, or the database has cache semantics
|
||||||
* and version is NULL.
|
* and version is NULL.
|
||||||
*
|
*
|
||||||
|
* If the database has cache semantics, 'merge' must be ISC_FALSE.
|
||||||
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
*
|
*
|
||||||
* DNS_R_SUCCESS
|
* DNS_R_SUCCESS
|
||||||
|
* DNS_R_UNCHANGED The operation did not change anything.
|
||||||
* DNS_R_NOMEMORY
|
* DNS_R_NOMEMORY
|
||||||
* DNS_R_EXISTS An rdataset with the specified
|
*
|
||||||
* rdataset's type and version's serial
|
* Other results are possible, depending upon the database
|
||||||
* number already exists.
|
* implementation used.
|
||||||
|
*/
|
||||||
|
|
||||||
|
dns_result_t
|
||||||
|
dns_db_subtractrdataset(dns_db_t *db, dns_dbnode_t *node,
|
||||||
|
dns_dbversion_t *version, dns_rdataset_t *rdataset,
|
||||||
|
dns_rdataset_t *newrdataset);
|
||||||
|
/*
|
||||||
|
* Remove any rdata in 'rdataset' from 'node' in version 'version' of
|
||||||
|
* 'db'.
|
||||||
|
*
|
||||||
|
* Notes:
|
||||||
|
*
|
||||||
|
* If 'newrdataset' is not NULL, then it will be attached to the
|
||||||
|
* rdataset added to the database, unless the rdataset has become
|
||||||
|
* nonexistent.
|
||||||
|
*
|
||||||
|
* Requires:
|
||||||
|
*
|
||||||
|
* 'db' is a valid database.
|
||||||
|
*
|
||||||
|
* 'node' is a valid node.
|
||||||
|
*
|
||||||
|
* 'rdataset' is a valid, associated rdataset with the same class
|
||||||
|
* as 'db'.
|
||||||
|
*
|
||||||
|
* 'newrdataset' is NULL, or a valid, unassociated rdataset.
|
||||||
|
*
|
||||||
|
* The database has zone semantics and 'version' is a valid
|
||||||
|
* read-write version.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
*
|
||||||
|
* DNS_R_SUCCESS
|
||||||
|
* DNS_R_UNCHANGED The operation did not change anything.
|
||||||
|
* DNS_R_NXRDATASET All rdata of the same type as those
|
||||||
|
* in 'rdataset' have been deleted.
|
||||||
*
|
*
|
||||||
* Other results are possible, depending upon the database
|
* Other results are possible, depending upon the database
|
||||||
* implementation used.
|
* implementation used.
|
||||||
@@ -867,7 +917,8 @@ dns_db_deleterdataset(dns_db_t *db, dns_dbnode_t *node,
|
|||||||
* Returns:
|
* Returns:
|
||||||
*
|
*
|
||||||
* DNS_R_SUCCESS
|
* DNS_R_SUCCESS
|
||||||
* DNS_R_NOTFOUND
|
* DNS_R_UNCHANGED No rdatasets of 'type' existed before
|
||||||
|
* the operation was attempted.
|
||||||
*
|
*
|
||||||
* Other results are possible, depending upon the database
|
* Other results are possible, depending upon the database
|
||||||
* implementation used.
|
* implementation used.
|
||||||
|
@@ -2274,6 +2274,9 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
|
|||||||
rdatasetheader_t *header, *header_prev;
|
rdatasetheader_t *header, *header_prev;
|
||||||
unsigned char *merged;
|
unsigned char *merged;
|
||||||
dns_result_t result;
|
dns_result_t result;
|
||||||
|
isc_boolean_t force = ISC_FALSE;
|
||||||
|
isc_boolean_t header_nx;
|
||||||
|
isc_boolean_t newheader_nx;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add an rdatasetheader_t to a node.
|
* Add an rdatasetheader_t to a node.
|
||||||
@@ -2284,11 +2287,19 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
if (rbtversion != NULL && !loading) {
|
if (rbtversion != NULL && !loading) {
|
||||||
|
/*
|
||||||
|
* We always add a changed record, even if no changes end up
|
||||||
|
* being made to this node, because it's harmless and
|
||||||
|
* simplifies the code.
|
||||||
|
*/
|
||||||
changed = add_changed(rbtdb, rbtversion, rbtnode);
|
changed = add_changed(rbtdb, rbtversion, rbtnode);
|
||||||
if (changed == NULL)
|
if (changed == NULL)
|
||||||
return (DNS_R_NOMEMORY);
|
return (DNS_R_NOMEMORY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
newheader_nx = ((newheader->attributes & RDATASET_ATTR_NONEXISTENT)
|
||||||
|
!= 0 ? ISC_TRUE : ISC_FALSE);
|
||||||
|
|
||||||
header_prev = NULL;
|
header_prev = NULL;
|
||||||
for (header = rbtnode->data; header != NULL; header = header->next) {
|
for (header = rbtnode->data; header != NULL; header = header->next) {
|
||||||
if (header->type == newheader->type)
|
if (header->type == newheader->type)
|
||||||
@@ -2296,13 +2307,28 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
|
|||||||
header_prev = header;
|
header_prev = header;
|
||||||
}
|
}
|
||||||
if (header != NULL) {
|
if (header != NULL) {
|
||||||
|
header_nx = ((header->attributes & RDATASET_ATTR_NONEXISTENT)
|
||||||
|
!= 0 ? ISC_TRUE : ISC_FALSE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Deleting an already non-existent rdataset has no effect.
|
||||||
|
*/
|
||||||
|
if (header_nx && newheader_nx) {
|
||||||
|
free_rdataset(rbtdb->common.mctx, newheader);
|
||||||
|
return (DNS_R_UNCHANGED);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Don't merge if a nonexistent rdataset is involved.
|
* Don't merge if a nonexistent rdataset is involved.
|
||||||
*/
|
*/
|
||||||
if (merge &&
|
if (merge && (header_nx || newheader_nx))
|
||||||
((newheader->attributes & RDATASET_ATTR_NONEXISTENT) != 0
|
|
||||||
|| (header->attributes & RDATASET_ATTR_NONEXISTENT) != 0))
|
|
||||||
merge = ISC_FALSE;
|
merge = ISC_FALSE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXXRTH We should turn off merging for rdata types that
|
||||||
|
* cannot be merged, e.g. SOA, CNAME, WKS.
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If 'merge' is ISC_TRUE, we'll try to create a new rdataset
|
* If 'merge' is ISC_TRUE, we'll try to create a new rdataset
|
||||||
* that is the union of 'newheader' and 'header'.
|
* that is the union of 'newheader' and 'header'.
|
||||||
@@ -2310,6 +2336,12 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
|
|||||||
if (merge) {
|
if (merge) {
|
||||||
INSIST(rbtversion->serial >= header->serial);
|
INSIST(rbtversion->serial >= header->serial);
|
||||||
merged = NULL;
|
merged = NULL;
|
||||||
|
if (newheader->ttl != header->ttl)
|
||||||
|
force = ISC_TRUE;
|
||||||
|
/*
|
||||||
|
* XXXRTH we're going to have to deal with signatures
|
||||||
|
* somehow here...
|
||||||
|
*/
|
||||||
result = dns_rdataslab_merge(
|
result = dns_rdataslab_merge(
|
||||||
(unsigned char *)header,
|
(unsigned char *)header,
|
||||||
(unsigned char *)newheader,
|
(unsigned char *)newheader,
|
||||||
@@ -2317,6 +2349,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
|
|||||||
rbtdb->common.mctx,
|
rbtdb->common.mctx,
|
||||||
rbtdb->common.rdclass,
|
rbtdb->common.rdclass,
|
||||||
header->type,
|
header->type,
|
||||||
|
force,
|
||||||
&merged);
|
&merged);
|
||||||
if (result == DNS_R_SUCCESS) {
|
if (result == DNS_R_SUCCESS) {
|
||||||
/*
|
/*
|
||||||
@@ -2331,13 +2364,6 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
|
|||||||
newheader = (rdatasetheader_t *)merged;
|
newheader = (rdatasetheader_t *)merged;
|
||||||
} else {
|
} else {
|
||||||
free_rdataset(rbtdb->common.mctx, newheader);
|
free_rdataset(rbtdb->common.mctx, newheader);
|
||||||
if (result == DNS_R_UNCHANGED) {
|
|
||||||
if (addedrdataset != NULL)
|
|
||||||
bind_rdataset(rbtdb, rbtnode,
|
|
||||||
header, now,
|
|
||||||
addedrdataset);
|
|
||||||
return (DNS_R_SUCCESS);
|
|
||||||
}
|
|
||||||
return (result);
|
return (result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2368,6 +2394,15 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
|
|||||||
/*
|
/*
|
||||||
* The rdataset type doesn't exist at this node.
|
* The rdataset type doesn't exist at this node.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we're trying to delete it, don't bother.
|
||||||
|
*/
|
||||||
|
if (newheader_nx) {
|
||||||
|
free_rdataset(rbtdb->common.mctx, newheader);
|
||||||
|
return (DNS_R_UNCHANGED);
|
||||||
|
}
|
||||||
|
|
||||||
newheader->next = rbtnode->data;
|
newheader->next = rbtnode->data;
|
||||||
newheader->down = NULL;
|
newheader->down = NULL;
|
||||||
rbtnode->data = newheader;
|
rbtnode->data = newheader;
|
||||||
@@ -2394,7 +2429,7 @@ delegating_type(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
|
|||||||
|
|
||||||
static dns_result_t
|
static dns_result_t
|
||||||
addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
||||||
isc_stdtime_t now, dns_rdataset_t *rdataset,
|
isc_stdtime_t now, dns_rdataset_t *rdataset, isc_boolean_t merge,
|
||||||
dns_rdataset_t *addedrdataset)
|
dns_rdataset_t *addedrdataset)
|
||||||
{
|
{
|
||||||
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
|
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
|
||||||
@@ -2403,7 +2438,7 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
|||||||
isc_region_t region;
|
isc_region_t region;
|
||||||
rdatasetheader_t *newheader;
|
rdatasetheader_t *newheader;
|
||||||
dns_result_t result;
|
dns_result_t result;
|
||||||
isc_boolean_t merge, delegating;
|
isc_boolean_t delegating;
|
||||||
|
|
||||||
REQUIRE(VALID_RBTDB(rbtdb));
|
REQUIRE(VALID_RBTDB(rbtdb));
|
||||||
|
|
||||||
@@ -2459,6 +2494,18 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
|||||||
return (result);
|
return (result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static dns_result_t
|
||||||
|
subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
||||||
|
dns_rdataset_t *rdataset, dns_rdataset_t *newrdataset) {
|
||||||
|
(void)db;
|
||||||
|
(void)node;
|
||||||
|
(void)version;
|
||||||
|
(void)rdataset;
|
||||||
|
(void)newrdataset;
|
||||||
|
|
||||||
|
return (DNS_R_NOTIMPLEMENTED);
|
||||||
|
}
|
||||||
|
|
||||||
static dns_result_t
|
static dns_result_t
|
||||||
deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
|
||||||
dns_rdatatype_t type)
|
dns_rdatatype_t type)
|
||||||
@@ -2659,6 +2706,7 @@ static dns_dbmethods_t zone_methods = {
|
|||||||
zone_findrdataset,
|
zone_findrdataset,
|
||||||
allrdatasets,
|
allrdatasets,
|
||||||
addrdataset,
|
addrdataset,
|
||||||
|
subtractrdataset,
|
||||||
deleterdataset
|
deleterdataset
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2681,6 +2729,7 @@ static dns_dbmethods_t cache_methods = {
|
|||||||
cache_findrdataset,
|
cache_findrdataset,
|
||||||
allrdatasets,
|
allrdatasets,
|
||||||
addrdataset,
|
addrdataset,
|
||||||
|
subtractrdataset,
|
||||||
deleterdataset
|
deleterdataset
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user