mirror of
https://github.com/isc-projects/bind9.git
synced 2026-06-11 06:29:59 -04:00
[9.20] fix: usr: Fix inbound IXFR performance regression.
Very large inbound IXFR transfers were much slower compared to BIND 9.18. The performance was improved by adding specialized logic to handle IXFR transfers. Closes #5442 Backport of MR !11077 Merge branch 'backport-5442-ixfr-batch-transaction-9.20' into 'bind-9.20' See merge request isc-projects/bind9!11355
This commit is contained in:
commit
318a7535d2
15 changed files with 1121 additions and 236 deletions
|
|
@ -2236,6 +2236,7 @@ respdiff-third-party:
|
|||
.respdiff-recent-named: &respdiff_recent_named
|
||||
<<: *respdiff_job
|
||||
<<: *base_image
|
||||
allow_failure: true #GL!11355
|
||||
needs:
|
||||
- job: ci-variables
|
||||
artifacts: true
|
||||
|
|
|
|||
51
lib/dns/db.c
51
lib/dns/db.c
|
|
@ -315,6 +315,57 @@ dns_db_endload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
|
|||
return ISC_R_NOTIMPLEMENTED;
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_db_beginupdate(dns_db_t *db, dns_dbversion_t *ver,
|
||||
dns_rdatacallbacks_t *callbacks) {
|
||||
/*
|
||||
* Begin updating 'db'.
|
||||
*/
|
||||
|
||||
REQUIRE(DNS_DB_VALID(db));
|
||||
REQUIRE(dns_db_iszone(db));
|
||||
REQUIRE(DNS_CALLBACK_VALID(callbacks));
|
||||
|
||||
if (db->methods->beginupdate != NULL) {
|
||||
return (db->methods->beginupdate)(db, ver, callbacks);
|
||||
}
|
||||
return ISC_R_NOTIMPLEMENTED;
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_db_commitupdate(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
|
||||
/*
|
||||
* Commit the update to 'db'.
|
||||
*/
|
||||
|
||||
REQUIRE(DNS_DB_VALID(db));
|
||||
REQUIRE(dns_db_iszone(db));
|
||||
REQUIRE(DNS_CALLBACK_VALID(callbacks));
|
||||
|
||||
if (db->methods->commitupdate != NULL) {
|
||||
return (db->methods->commitupdate)(db, callbacks);
|
||||
}
|
||||
|
||||
return ISC_R_NOTIMPLEMENTED;
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_db_abortupdate(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
|
||||
/*
|
||||
* Abort the update to 'db'.
|
||||
*/
|
||||
|
||||
REQUIRE(DNS_DB_VALID(db));
|
||||
REQUIRE(dns_db_iszone(db));
|
||||
REQUIRE(DNS_CALLBACK_VALID(callbacks));
|
||||
|
||||
if (db->methods->abortupdate != NULL) {
|
||||
return (db->methods->abortupdate)(db, callbacks);
|
||||
}
|
||||
|
||||
return ISC_R_NOTIMPLEMENTED;
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_db_load(dns_db_t *db, const char *filename, dns_masterformat_t format,
|
||||
unsigned int options) {
|
||||
|
|
|
|||
305
lib/dns/diff.c
305
lib/dns/diff.c
|
|
@ -211,42 +211,6 @@ dns_diff_appendminimal(dns_diff_t *diff, dns_difftuple_t **tuplep) {
|
|||
}
|
||||
}
|
||||
|
||||
static isc_stdtime_t
|
||||
setresign(dns_rdataset_t *modified) {
|
||||
dns_rdata_t rdata = DNS_RDATA_INIT;
|
||||
dns_rdata_rrsig_t sig;
|
||||
int64_t when;
|
||||
isc_result_t result;
|
||||
|
||||
result = dns_rdataset_first(modified);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
dns_rdataset_current(modified, &rdata);
|
||||
(void)dns_rdata_tostruct(&rdata, &sig, NULL);
|
||||
if ((rdata.flags & DNS_RDATA_OFFLINE) != 0) {
|
||||
when = 0;
|
||||
} else {
|
||||
when = dns_time64_from32(sig.timeexpire);
|
||||
}
|
||||
dns_rdata_reset(&rdata);
|
||||
|
||||
result = dns_rdataset_next(modified);
|
||||
while (result == ISC_R_SUCCESS) {
|
||||
dns_rdataset_current(modified, &rdata);
|
||||
(void)dns_rdata_tostruct(&rdata, &sig, NULL);
|
||||
if ((rdata.flags & DNS_RDATA_OFFLINE) != 0) {
|
||||
goto next_rr;
|
||||
}
|
||||
if (when == 0 || dns_time64_from32(sig.timeexpire) < when) {
|
||||
when = dns_time64_from32(sig.timeexpire);
|
||||
}
|
||||
next_rr:
|
||||
dns_rdata_reset(&rdata);
|
||||
result = dns_rdataset_next(modified);
|
||||
}
|
||||
INSIST(result == ISC_R_NOMORE);
|
||||
return (isc_stdtime_t)when;
|
||||
}
|
||||
|
||||
static void
|
||||
getownercase(dns_rdataset_t *rdataset, dns_name_t *name) {
|
||||
if (dns_rdataset_isassociated(rdataset)) {
|
||||
|
|
@ -261,6 +225,91 @@ setownercase(dns_rdataset_t *rdataset, const dns_name_t *name) {
|
|||
}
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
update_rdataset(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
|
||||
dns_rdataset_t *rds, dns_diffop_t op) {
|
||||
isc_result_t result;
|
||||
unsigned int options;
|
||||
dns_rdataset_t ardataset;
|
||||
dns_dbnode_t *node = NULL;
|
||||
bool is_resign;
|
||||
|
||||
dns_rdataset_init(&ardataset);
|
||||
|
||||
is_resign = rds->type == dns_rdatatype_rrsig &&
|
||||
(op == DNS_DIFFOP_DELRESIGN || op == DNS_DIFFOP_ADDRESIGN);
|
||||
|
||||
if (rds->type != dns_rdatatype_nsec3 &&
|
||||
rds->covers != dns_rdatatype_nsec3)
|
||||
{
|
||||
CHECK(dns_db_findnode(db, name, true, &node));
|
||||
} else {
|
||||
CHECK(dns_db_findnsec3node(db, name, true, &node));
|
||||
}
|
||||
|
||||
switch (op) {
|
||||
case DNS_DIFFOP_ADD:
|
||||
case DNS_DIFFOP_ADDRESIGN:
|
||||
options = DNS_DBADD_MERGE | DNS_DBADD_EXACT |
|
||||
DNS_DBADD_EXACTTTL;
|
||||
CHECK(dns_db_addrdataset(db, node, ver, 0, rds, options,
|
||||
&ardataset));
|
||||
switch (result) {
|
||||
case ISC_R_SUCCESS:
|
||||
case DNS_R_UNCHANGED:
|
||||
case DNS_R_NXRRSET:
|
||||
setownercase(&ardataset, name);
|
||||
CHECK(result);
|
||||
break;
|
||||
default:
|
||||
CHECK(result);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case DNS_DIFFOP_DEL:
|
||||
case DNS_DIFFOP_DELRESIGN:
|
||||
options = DNS_DBSUB_EXACT | DNS_DBSUB_WANTOLD;
|
||||
result = dns_db_subtractrdataset(db, node, ver, rds, options,
|
||||
&ardataset);
|
||||
switch (result) {
|
||||
case ISC_R_SUCCESS:
|
||||
case DNS_R_UNCHANGED:
|
||||
case DNS_R_NXRRSET:
|
||||
getownercase(&ardataset, name);
|
||||
CHECK(result);
|
||||
break;
|
||||
default:
|
||||
CHECK(result);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
if (is_resign) {
|
||||
isc_stdtime_t resign;
|
||||
resign = dns_rdataset_minresign(&ardataset);
|
||||
dns_db_setsigningtime(db, &ardataset, resign);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (node != NULL) {
|
||||
dns_db_detachnode(db, &node);
|
||||
}
|
||||
if (dns_rdataset_isassociated(&ardataset)) {
|
||||
dns_rdataset_disassociate(&ardataset);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
update_callback(void *arg, const dns_name_t *name, dns_rdataset_t *rds,
|
||||
dns_diffop_t op DNS__DB_FLARG) {
|
||||
dns_updatectx_t *ctx = arg;
|
||||
return update_rdataset(ctx->db, ctx->ver, (dns_name_t *)name, rds, op);
|
||||
}
|
||||
|
||||
static const char *
|
||||
optotext(dns_diffop_t op) {
|
||||
switch (op) {
|
||||
|
|
@ -278,23 +327,24 @@ optotext(dns_diffop_t op) {
|
|||
}
|
||||
|
||||
static isc_result_t
|
||||
diff_apply(const dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver,
|
||||
bool warn) {
|
||||
diff_apply(const dns_diff_t *diff, dns_rdatacallbacks_t *callbacks) {
|
||||
dns_difftuple_t *t;
|
||||
dns_dbnode_t *node = NULL;
|
||||
isc_result_t result;
|
||||
char namebuf[DNS_NAME_FORMATSIZE];
|
||||
char typebuf[DNS_RDATATYPE_FORMATSIZE];
|
||||
char classbuf[DNS_RDATACLASS_FORMATSIZE];
|
||||
dns_updatectx_t *ctx;
|
||||
|
||||
REQUIRE(DNS_DIFF_VALID(diff));
|
||||
REQUIRE(DNS_DB_VALID(db));
|
||||
REQUIRE(callbacks != NULL);
|
||||
REQUIRE(callbacks->update != NULL);
|
||||
|
||||
ctx = callbacks->add_private;
|
||||
|
||||
t = ISC_LIST_HEAD(diff->tuples);
|
||||
while (t != NULL) {
|
||||
dns_name_t *name;
|
||||
|
||||
INSIST(node == NULL);
|
||||
name = &t->name;
|
||||
/*
|
||||
* Find the node.
|
||||
|
|
@ -311,8 +361,6 @@ diff_apply(const dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver,
|
|||
dns_diffop_t op;
|
||||
dns_rdatalist_t rdl;
|
||||
dns_rdataset_t rds;
|
||||
dns_rdataset_t ardataset;
|
||||
unsigned int options;
|
||||
|
||||
op = t->op;
|
||||
type = t->rdata.type;
|
||||
|
|
@ -340,16 +388,6 @@ diff_apply(const dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver,
|
|||
rdl.rdclass = t->rdata.rdclass;
|
||||
rdl.ttl = t->ttl;
|
||||
|
||||
node = NULL;
|
||||
if (type != dns_rdatatype_nsec3 &&
|
||||
covers != dns_rdatatype_nsec3)
|
||||
{
|
||||
CHECK(dns_db_findnode(db, name, true, &node));
|
||||
} else {
|
||||
CHECK(dns_db_findnsec3node(db, name, true,
|
||||
&node));
|
||||
}
|
||||
|
||||
while (t != NULL && dns_name_equal(&t->name, name) &&
|
||||
t->op == op && t->rdata.type == type &&
|
||||
rdata_covers(&t->rdata) == covers)
|
||||
|
|
@ -359,7 +397,7 @@ diff_apply(const dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver,
|
|||
* dns_rdataset_setownercase.
|
||||
*/
|
||||
name = &t->name;
|
||||
if (t->ttl != rdl.ttl && warn) {
|
||||
if (t->ttl != rdl.ttl && ctx->warn) {
|
||||
dns_name_format(name, namebuf,
|
||||
sizeof(namebuf));
|
||||
dns_rdatatype_format(t->rdata.type,
|
||||
|
|
@ -387,54 +425,22 @@ diff_apply(const dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver,
|
|||
* Convert the rdatalist into a rdataset.
|
||||
*/
|
||||
dns_rdataset_init(&rds);
|
||||
dns_rdataset_init(&ardataset);
|
||||
dns_rdatalist_tordataset(&rdl, &rds);
|
||||
rds.trust = dns_trust_ultimate;
|
||||
|
||||
/*
|
||||
* Merge the rdataset into the database.
|
||||
*/
|
||||
switch (op) {
|
||||
case DNS_DIFFOP_ADD:
|
||||
case DNS_DIFFOP_ADDRESIGN:
|
||||
options = DNS_DBADD_MERGE | DNS_DBADD_EXACT |
|
||||
DNS_DBADD_EXACTTTL;
|
||||
result = dns_db_addrdataset(db, node, ver, 0,
|
||||
&rds, options,
|
||||
&ardataset);
|
||||
break;
|
||||
case DNS_DIFFOP_DEL:
|
||||
case DNS_DIFFOP_DELRESIGN:
|
||||
options = DNS_DBSUB_EXACT | DNS_DBSUB_WANTOLD;
|
||||
result = dns_db_subtractrdataset(db, node, ver,
|
||||
&rds, options,
|
||||
&ardataset);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
result = callbacks->update(callbacks->add_private, name,
|
||||
&rds, op DNS__DB_FILELINE);
|
||||
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
if (rds.type == dns_rdatatype_rrsig &&
|
||||
(op == DNS_DIFFOP_DELRESIGN ||
|
||||
op == DNS_DIFFOP_ADDRESIGN))
|
||||
{
|
||||
isc_stdtime_t resign;
|
||||
resign = setresign(&ardataset);
|
||||
dns_db_setsigningtime(db, &ardataset,
|
||||
resign);
|
||||
}
|
||||
if (op == DNS_DIFFOP_ADD ||
|
||||
op == DNS_DIFFOP_ADDRESIGN)
|
||||
{
|
||||
setownercase(&ardataset, name);
|
||||
}
|
||||
if (op == DNS_DIFFOP_DEL ||
|
||||
op == DNS_DIFFOP_DELRESIGN)
|
||||
{
|
||||
getownercase(&ardataset, name);
|
||||
}
|
||||
} else if (result == DNS_R_UNCHANGED) {
|
||||
switch (result) {
|
||||
case ISC_R_SUCCESS:
|
||||
/*
|
||||
* OK.
|
||||
*/
|
||||
break;
|
||||
case DNS_R_UNCHANGED:
|
||||
/*
|
||||
* This will not happen when executing a
|
||||
* dynamic update, because that code will
|
||||
|
|
@ -443,87 +449,83 @@ diff_apply(const dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver,
|
|||
* from a server that is not as careful.
|
||||
* Issue a warning and continue.
|
||||
*/
|
||||
if (warn) {
|
||||
dns_name_format(dns_db_origin(db),
|
||||
if (ctx->warn) {
|
||||
dns_name_format(dns_db_origin(ctx->db),
|
||||
namebuf,
|
||||
sizeof(namebuf));
|
||||
dns_rdataclass_format(dns_db_class(db),
|
||||
classbuf,
|
||||
sizeof(classbuf));
|
||||
dns_rdataclass_format(
|
||||
dns_db_class(ctx->db), classbuf,
|
||||
sizeof(classbuf));
|
||||
isc_log_write(DIFF_COMMON_LOGARGS,
|
||||
ISC_LOG_WARNING,
|
||||
"%s/%s: dns_diff_apply: "
|
||||
"update with no effect",
|
||||
namebuf, classbuf);
|
||||
}
|
||||
if (op == DNS_DIFFOP_ADD ||
|
||||
op == DNS_DIFFOP_ADDRESIGN)
|
||||
{
|
||||
setownercase(&ardataset, name);
|
||||
}
|
||||
if (op == DNS_DIFFOP_DEL ||
|
||||
op == DNS_DIFFOP_DELRESIGN)
|
||||
{
|
||||
getownercase(&ardataset, name);
|
||||
}
|
||||
} else if (result == DNS_R_NXRRSET) {
|
||||
result = ISC_R_SUCCESS;
|
||||
break;
|
||||
case DNS_R_NXRRSET:
|
||||
/*
|
||||
* OK.
|
||||
*/
|
||||
if (op == DNS_DIFFOP_DEL ||
|
||||
op == DNS_DIFFOP_DELRESIGN)
|
||||
{
|
||||
getownercase(&ardataset, name);
|
||||
}
|
||||
if (dns_rdataset_isassociated(&ardataset)) {
|
||||
dns_rdataset_disassociate(&ardataset);
|
||||
}
|
||||
} else {
|
||||
if (result == DNS_R_NOTEXACT) {
|
||||
dns_name_format(name, namebuf,
|
||||
sizeof(namebuf));
|
||||
dns_rdatatype_format(type, typebuf,
|
||||
sizeof(typebuf));
|
||||
dns_rdataclass_format(rdclass, classbuf,
|
||||
sizeof(classbuf));
|
||||
isc_log_write(
|
||||
DIFF_COMMON_LOGARGS,
|
||||
ISC_LOG_ERROR,
|
||||
"dns_diff_apply: %s/%s/%s: %s "
|
||||
"%s",
|
||||
namebuf, typebuf, classbuf,
|
||||
optotext(op),
|
||||
isc_result_totext(result));
|
||||
}
|
||||
if (dns_rdataset_isassociated(&ardataset)) {
|
||||
dns_rdataset_disassociate(&ardataset);
|
||||
}
|
||||
CHECK(result);
|
||||
}
|
||||
dns_db_detachnode(db, &node);
|
||||
if (dns_rdataset_isassociated(&ardataset)) {
|
||||
dns_rdataset_disassociate(&ardataset);
|
||||
result = ISC_R_SUCCESS;
|
||||
break;
|
||||
case DNS_R_NOTEXACT:
|
||||
dns_name_format(name, namebuf, sizeof(namebuf));
|
||||
dns_rdatatype_format(type, typebuf,
|
||||
sizeof(typebuf));
|
||||
dns_rdataclass_format(rdclass, classbuf,
|
||||
sizeof(classbuf));
|
||||
isc_log_write(DIFF_COMMON_LOGARGS,
|
||||
ISC_LOG_ERROR,
|
||||
"dns_diff_apply: %s/%s/%s: %s "
|
||||
"%s",
|
||||
namebuf, typebuf, classbuf,
|
||||
optotext(op),
|
||||
isc_result_totext(result));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
CHECK(result);
|
||||
}
|
||||
}
|
||||
return ISC_R_SUCCESS;
|
||||
|
||||
cleanup:
|
||||
if (node != NULL) {
|
||||
dns_db_detachnode(db, &node);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_diff_apply(const dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver) {
|
||||
return diff_apply(diff, db, ver, true);
|
||||
dns_updatectx_t ctx = { .db = db, .ver = ver, .warn = true };
|
||||
dns_rdatacallbacks_t callbacks;
|
||||
dns_rdatacallbacks_init(&callbacks);
|
||||
callbacks.update = update_callback;
|
||||
callbacks.add_private = &ctx;
|
||||
return diff_apply(diff, &callbacks);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_diff_applysilently(const dns_diff_t *diff, dns_db_t *db,
|
||||
dns_dbversion_t *ver) {
|
||||
return diff_apply(diff, db, ver, false);
|
||||
dns_updatectx_t ctx = { .db = db, .ver = ver, .warn = false };
|
||||
dns_rdatacallbacks_t callbacks;
|
||||
dns_rdatacallbacks_init(&callbacks);
|
||||
callbacks.update = update_callback;
|
||||
callbacks.add_private = &ctx;
|
||||
return diff_apply(diff, &callbacks);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_diff_apply_with_callbacks(const dns_diff_t *diff,
|
||||
dns_rdatacallbacks_t *callbacks) {
|
||||
REQUIRE(DNS_DIFF_VALID(diff));
|
||||
REQUIRE(callbacks != NULL);
|
||||
REQUIRE(callbacks->update != NULL);
|
||||
|
||||
return diff_apply(diff, callbacks);
|
||||
}
|
||||
|
||||
/* XXX this duplicates lots of code in diff_apply(). */
|
||||
|
|
@ -577,8 +579,9 @@ dns_diff_load(const dns_diff_t *diff, dns_rdatacallbacks_t *callbacks) {
|
|||
rds.trust = dns_trust_ultimate;
|
||||
|
||||
INSIST(op == DNS_DIFFOP_ADD);
|
||||
result = callbacks->add(callbacks->add_private, name,
|
||||
&rds DNS__DB_FILELINE);
|
||||
result = callbacks->update(
|
||||
callbacks->add_private, name, &rds,
|
||||
DNS_DIFFOP_ADD DNS__DB_FILELINE);
|
||||
if (result == DNS_R_UNCHANGED) {
|
||||
isc_log_write(DIFF_COMMON_LOGARGS,
|
||||
ISC_LOG_WARNING,
|
||||
|
|
|
|||
|
|
@ -37,18 +37,18 @@ struct dns_rdatacallbacks {
|
|||
unsigned int magic;
|
||||
|
||||
/*%
|
||||
* dns_load_master calls 'add' when it has an rdataset to add
|
||||
* to the database. If defined, it calls 'setup' before and
|
||||
* 'commit' after adding rdatasets.
|
||||
* dns_load_master calls 'update' when it has an rdataset to update
|
||||
* in the database. If defined, it calls 'setup' before and
|
||||
* 'commit' after updating rdatasets.
|
||||
*
|
||||
* Some database implementations will commit each rdataset as
|
||||
* soon as it's added, in which case 'setup' and 'commit' need
|
||||
* soon as it's updated, in which case 'setup' and 'commit' need
|
||||
* not be defined. However, other implementations can be
|
||||
* optimized by grouping rdatasets into a transaction; the
|
||||
* setup and commit functions allow this transaction to be
|
||||
* opened and committed.
|
||||
*/
|
||||
dns_addrdatasetfunc_t add;
|
||||
dns_addrdatasetfunc_t update;
|
||||
dns_transactionfunc_t setup;
|
||||
dns_transactionfunc_t commit;
|
||||
|
||||
|
|
|
|||
|
|
@ -83,6 +83,12 @@ typedef struct dns_dbmethods {
|
|||
isc_result_t (*beginload)(dns_db_t *db,
|
||||
dns_rdatacallbacks_t *callbacks);
|
||||
isc_result_t (*endload)(dns_db_t *db, dns_rdatacallbacks_t *callbacks);
|
||||
isc_result_t (*beginupdate)(dns_db_t *db, dns_dbversion_t *ver,
|
||||
dns_rdatacallbacks_t *callbacks);
|
||||
isc_result_t (*commitupdate)(dns_db_t *db,
|
||||
dns_rdatacallbacks_t *callbacks);
|
||||
isc_result_t (*abortupdate)(dns_db_t *db,
|
||||
dns_rdatacallbacks_t *callbacks);
|
||||
void (*currentversion)(dns_db_t *db, dns_dbversion_t **versionp);
|
||||
isc_result_t (*newversion)(dns_db_t *db, dns_dbversion_t **versionp);
|
||||
void (*attachversion)(dns_db_t *db, dns_dbversion_t *source,
|
||||
|
|
@ -537,6 +543,91 @@ dns_db_endload(dns_db_t *db, dns_rdatacallbacks_t *callbacks);
|
|||
* implementation used, syntax errors in the master file, etc.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_db_beginupdate(dns_db_t *db, dns_dbversion_t *ver,
|
||||
dns_rdatacallbacks_t *callbacks);
|
||||
/*%<
|
||||
* Begin updating 'db'.
|
||||
*
|
||||
* Requires:
|
||||
*
|
||||
* \li 'db' is a valid database.
|
||||
*
|
||||
* \li 'callbacks' is a pointer to an initialized dns_rdatacallbacks_t
|
||||
* structure.
|
||||
*
|
||||
* Ensures:
|
||||
*
|
||||
* \li On success, callbacks->add will be a valid dns_addrdatasetfunc_t
|
||||
* suitable for updating records in 'db' from IXFR operations.
|
||||
* callbacks->add_private will be a valid DB update context
|
||||
* which should be used as 'arg' when callbacks->add is called.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* \li #ISC_R_SUCCESS
|
||||
*
|
||||
* \li Other results are possible, depending upon the database
|
||||
* implementation used.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_db_commitupdate(dns_db_t *db, dns_rdatacallbacks_t *callbacks);
|
||||
/*%<
|
||||
* Commit the update to 'db'. Must be safe to double-call or call after
|
||||
* dns_db_abortupdate.
|
||||
*
|
||||
* Requires:
|
||||
*
|
||||
* \li 'db' is a valid database that is being updated.
|
||||
*
|
||||
* \li 'callbacks' is a valid dns_rdatacallbacks_t structure.
|
||||
*
|
||||
* \li callbacks->add_private is not NULL and is a valid database update
|
||||
* context.
|
||||
*
|
||||
* Ensures:
|
||||
*
|
||||
* \li 'callbacks' is returned to its state prior to calling
|
||||
* dns_db_beginupdate()
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* \li #ISC_R_SUCCESS
|
||||
*
|
||||
* \li Other results are possible, depending upon the database
|
||||
* implementation used.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_db_abortupdate(dns_db_t *db, dns_rdatacallbacks_t *callbacks);
|
||||
/*%<
|
||||
* Abort the update to 'db'. Must be safe to double-call or call after
|
||||
* dns_db_commitupdate. Must also be safe to call without having called
|
||||
* dns_db_beginupdate first.
|
||||
*
|
||||
* Requires:
|
||||
*
|
||||
* \li 'db' is a valid database that is being updated.
|
||||
*
|
||||
* \li 'callbacks' is a valid dns_rdatacallbacks_t structure.
|
||||
*
|
||||
* \li callbacks->add_private is not NULL and is a valid database update
|
||||
* context.
|
||||
*
|
||||
* Ensures:
|
||||
*
|
||||
* \li 'callbacks' is returned to its state prior to calling
|
||||
* dns_db_beginupdate()
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* \li #ISC_R_SUCCESS
|
||||
*
|
||||
* \li Other results are possible, depending upon the database
|
||||
* implementation used.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_db_load(dns_db_t *db, const char *filename, dns_masterformat_t format,
|
||||
unsigned int options);
|
||||
|
|
|
|||
|
|
@ -60,14 +60,6 @@
|
|||
* timeexpire.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
DNS_DIFFOP_ADD = 0, /*%< Add an RR. */
|
||||
DNS_DIFFOP_DEL = 1, /*%< Delete an RR. */
|
||||
DNS_DIFFOP_EXISTS = 2, /*%< Assert RR existence. */
|
||||
DNS_DIFFOP_ADDRESIGN = 4, /*%< ADD + RESIGN. */
|
||||
DNS_DIFFOP_DELRESIGN = 5 /*%< DEL + RESIGN. */
|
||||
} dns_diffop_t;
|
||||
|
||||
typedef struct dns_difftuple dns_difftuple_t;
|
||||
typedef ISC_LIST(dns_difftuple_t) dns_difftuplelist_t;
|
||||
|
||||
|
|
@ -266,6 +258,37 @@ dns_diff_applysilently(const dns_diff_t *diff, dns_db_t *db,
|
|||
*
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
dns_db_t *db;
|
||||
dns_dbversion_t *ver;
|
||||
bool warn;
|
||||
} dns_updatectx_t;
|
||||
|
||||
isc_result_t
|
||||
dns_diff_apply_with_callbacks(const dns_diff_t *diff,
|
||||
dns_rdatacallbacks_t *callbacks);
|
||||
/*%<
|
||||
* Apply 'diff' to the database using the provided callbacks and context.
|
||||
* The context contains the database, version, and warning flag.
|
||||
* This allows for custom callback implementations.
|
||||
*
|
||||
* Requires:
|
||||
*\li 'callbacks' points to a valid dns_rdatacallbacks_t structure
|
||||
*\li 'callbacks->update' is not NULL
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
update_callback(void *arg, const dns_name_t *name, dns_rdataset_t *rds,
|
||||
dns_diffop_t op DNS__DB_FLARG);
|
||||
/*%<
|
||||
* Standard update callback for dns_rdatacallbacks_t.
|
||||
* Updates a database version by applying DNS record operations.
|
||||
* Used with dns_updatectx_t context.
|
||||
*
|
||||
* Requires:
|
||||
*\li 'arg' is a valid dns_updatectx_t pointer
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_diff_load(const dns_diff_t *diff, dns_rdatacallbacks_t *callbacks);
|
||||
/*%<
|
||||
|
|
|
|||
|
|
@ -691,4 +691,17 @@ dns_trust_totext(dns_trust_t trust);
|
|||
* Display trust in textual form.
|
||||
*/
|
||||
|
||||
isc_stdtime_t
|
||||
dns_rdataset_minresign(dns_rdataset_t *rdataset);
|
||||
/*%<
|
||||
* Return the minimum resign time from an RRSIG rdataset.
|
||||
*
|
||||
* This function iterates through all RRSIG records in the rdataset
|
||||
* and returns the earliest expiration time, which indicates when
|
||||
* the signatures should be resigned.
|
||||
*
|
||||
* Requires:
|
||||
* \li 'rdataset' is a valid rdataset.
|
||||
*/
|
||||
|
||||
ISC_LANG_ENDDECLS
|
||||
|
|
|
|||
|
|
@ -182,6 +182,14 @@ typedef struct dst_gssapi_signverifyctx dst_gssapi_signverifyctx_t;
|
|||
|
||||
typedef enum { dns_hash_sha1 = 1 } dns_hash_t;
|
||||
|
||||
typedef enum {
|
||||
DNS_DIFFOP_ADD = 0, /*%< Add an RR. */
|
||||
DNS_DIFFOP_DEL = 1, /*%< Delete an RR. */
|
||||
DNS_DIFFOP_EXISTS = 2, /*%< Assert RR existence. */
|
||||
DNS_DIFFOP_ADDRESIGN = 4, /*%< ADD + RESIGN. */
|
||||
DNS_DIFFOP_DELRESIGN = 5 /*%< DEL + RESIGN. */
|
||||
} dns_diffop_t;
|
||||
|
||||
typedef enum {
|
||||
dns_fwdpolicy_none = 0,
|
||||
dns_fwdpolicy_first = 1,
|
||||
|
|
@ -433,8 +441,8 @@ typedef void (*dns_loaddonefunc_t)(void *, isc_result_t);
|
|||
typedef void (*dns_rawdatafunc_t)(dns_zone_t *, dns_masterrawheader_t *);
|
||||
|
||||
typedef isc_result_t (*dns_addrdatasetfunc_t)(void *arg, const dns_name_t *name,
|
||||
dns_rdataset_t *rdataset
|
||||
DNS__DB_FLARG);
|
||||
dns_rdataset_t *rdataset,
|
||||
dns_diffop_t op DNS__DB_FLARG);
|
||||
typedef void (*dns_transactionfunc_t)(void *arg);
|
||||
|
||||
typedef isc_result_t (*dns_additionaldatafunc_t)(
|
||||
|
|
|
|||
|
|
@ -511,7 +511,7 @@ loadctx_create(dns_masterformat_t format, isc_mem_t *mctx, unsigned int options,
|
|||
|
||||
REQUIRE(lctxp != NULL && *lctxp == NULL);
|
||||
REQUIRE(callbacks != NULL);
|
||||
REQUIRE(callbacks->add != NULL);
|
||||
REQUIRE(callbacks->update != NULL);
|
||||
REQUIRE(callbacks->error != NULL);
|
||||
REQUIRE(callbacks->warn != NULL);
|
||||
REQUIRE(mctx != NULL);
|
||||
|
|
@ -2948,8 +2948,9 @@ commit(dns_rdatacallbacks_t *callbacks, dns_loadctx_t *lctx,
|
|||
dataset.attributes |= DNS_RDATASETATTR_RESIGN;
|
||||
dataset.resign = resign_fromlist(this, lctx);
|
||||
}
|
||||
result = callbacks->add(callbacks->add_private, owner,
|
||||
&dataset DNS__DB_FILELINE);
|
||||
result = callbacks->update(callbacks->add_private, owner,
|
||||
&dataset,
|
||||
DNS_DIFFOP_ADD DNS__DB_FILELINE);
|
||||
if (result == ISC_R_NOMEMORY) {
|
||||
(*error)(callbacks, "dns_master_load: %s",
|
||||
isc_result_totext(result));
|
||||
|
|
|
|||
372
lib/dns/qpzone.c
372
lib/dns/qpzone.c
|
|
@ -43,6 +43,8 @@
|
|||
#include <dns/callbacks.h>
|
||||
#include <dns/db.h>
|
||||
#include <dns/dbiterator.h>
|
||||
#include <dns/diff.h>
|
||||
#include <dns/dnssec.h>
|
||||
#include <dns/fixedname.h>
|
||||
#include <dns/log.h>
|
||||
#include <dns/masterdump.h>
|
||||
|
|
@ -102,6 +104,17 @@
|
|||
typedef struct qpzonedb qpzonedb_t;
|
||||
typedef struct qpznode qpznode_t;
|
||||
|
||||
/*
|
||||
* Qpzone-specific update context that extends dns_updatectx_t, used in IXFR.
|
||||
*/
|
||||
typedef struct qpzone_updatectx {
|
||||
dns_updatectx_t base;
|
||||
dns_qp_t *qp;
|
||||
dns_qp_t *nsec;
|
||||
dns_qp_t *nsec3;
|
||||
dns_qpread_t qpr;
|
||||
} qpzone_updatectx_t;
|
||||
|
||||
typedef struct qpz_changed {
|
||||
qpznode_t *node;
|
||||
bool dirty;
|
||||
|
|
@ -2045,8 +2058,8 @@ addwildcards(qpzonedb_t *qpdb, dns_qp_t *qp, const dns_name_t *name) {
|
|||
}
|
||||
|
||||
static isc_result_t
|
||||
loading_addrdataset(void *arg, const dns_name_t *name,
|
||||
dns_rdataset_t *rdataset DNS__DB_FLARG) {
|
||||
loading_addrdataset(void *arg, const dns_name_t *name, dns_rdataset_t *rdataset,
|
||||
dns_diffop_t op ISC_ATTR_UNUSED DNS__DB_FLARG) {
|
||||
qpz_load_t *loadctx = arg;
|
||||
qpzonedb_t *qpdb = (qpzonedb_t *)loadctx->db;
|
||||
qpznode_t *node = NULL;
|
||||
|
|
@ -2191,7 +2204,7 @@ beginload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
|
|||
|
||||
RWUNLOCK(&qpdb->lock, isc_rwlocktype_write);
|
||||
|
||||
callbacks->add = loading_addrdataset;
|
||||
callbacks->update = loading_addrdataset;
|
||||
callbacks->setup = loading_setup;
|
||||
callbacks->commit = loading_commit;
|
||||
callbacks->add_private = loadctx;
|
||||
|
|
@ -2226,7 +2239,7 @@ endload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
|
|||
RWUNLOCK(&qpdb->lock, isc_rwlocktype_write);
|
||||
}
|
||||
|
||||
callbacks->add = NULL;
|
||||
callbacks->update = NULL;
|
||||
callbacks->setup = NULL;
|
||||
callbacks->commit = NULL;
|
||||
callbacks->add_private = NULL;
|
||||
|
|
@ -2434,37 +2447,82 @@ setgluecachestats(dns_db_t *db, isc_stats_t *stats) {
|
|||
return ISC_R_SUCCESS;
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
findnodeintree(qpzonedb_t *qpdb, const dns_name_t *name, bool create,
|
||||
bool nsec3, dns_dbnode_t **nodep DNS__DB_FLARG) {
|
||||
isc_result_t result;
|
||||
qpznode_t *node = NULL;
|
||||
dns_qpmulti_t *dbtree = nsec3 ? qpdb->nsec3 : qpdb->tree;
|
||||
dns_qpread_t qpr = { 0 };
|
||||
static dns_qp_t *
|
||||
begin_transaction(dns_qpmulti_t *dbtree, dns_qpread_t *qprp, bool create) {
|
||||
dns_qp_t *qp = NULL;
|
||||
|
||||
if (create) {
|
||||
dns_qpmulti_write(dbtree, &qp);
|
||||
} else {
|
||||
dns_qpmulti_query(dbtree, &qpr);
|
||||
qp = (dns_qp_t *)&qpr;
|
||||
dns_qpmulti_query(dbtree, qprp);
|
||||
qp = (dns_qp_t *)qprp;
|
||||
}
|
||||
|
||||
result = dns_qp_getname(qp, name, (void **)&node, NULL);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
if (!create) {
|
||||
dns_qpread_destroy(dbtree, &qpr);
|
||||
return result;
|
||||
}
|
||||
return qp;
|
||||
}
|
||||
|
||||
static void
|
||||
end_transaction(dns_qpmulti_t *dbtree, dns_qp_t *qp, bool create) {
|
||||
if (create) {
|
||||
dns_qp_compact(qp, DNS_QPGC_MAYBE);
|
||||
dns_qpmulti_commit(dbtree, &qp);
|
||||
} else {
|
||||
dns_qpread_t *qprp = (dns_qpread_t *)qp;
|
||||
dns_qpread_destroy(dbtree, qprp);
|
||||
}
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
findnodeintree(qpzonedb_t *qpdb, dns_qp_t *qp, const dns_name_t *name,
|
||||
bool create, bool nsec3, dns_dbnode_t **nodep DNS__DB_FLARG) {
|
||||
isc_result_t result;
|
||||
qpznode_t *node = NULL;
|
||||
|
||||
/*
|
||||
* findnodeintree is a wrapper around dns_qp_getname that does some
|
||||
* qpzone-specific bookkeeping before returning the lookup result to the
|
||||
* caller.
|
||||
*
|
||||
* First, we do a lookup ...
|
||||
*/
|
||||
result = dns_qp_getname(qp, name, (void **)&node, NULL);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
/*
|
||||
* ... if the lookup is successful, we need to increase both the
|
||||
* internal and external reference count before returning to
|
||||
* the caller. qpznode_acquire takes care of that.
|
||||
*/
|
||||
qpznode_acquire(qpdb, node DNS__DB_FLARG_PASS);
|
||||
} else if (result != ISC_R_SUCCESS && create) {
|
||||
/*
|
||||
* ... if the lookup is unsuccessful, but the caller asked us to
|
||||
* create a new node, create one and insert it into the tree.
|
||||
*/
|
||||
node = new_qpznode(qpdb, name);
|
||||
|
||||
result = dns_qp_insert(qp, node, 0);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
qpznode_unref(node);
|
||||
|
||||
/*
|
||||
* The new node now has two internal references:
|
||||
* - One from new_qpznode, that initializes references at 1.
|
||||
* - One from attach_leaf, that increases the reference by
|
||||
* one at insertion in the qp-tree.
|
||||
* We want the node to have two internal and one external
|
||||
* reference:
|
||||
* - One internal reference from the qp-tree.
|
||||
* - One internal and one external reference from the caller.
|
||||
*
|
||||
* So we increase the external reference count by one.
|
||||
*/
|
||||
qpznode_erefs_increment(qpdb, node DNS__DB_FLARG_PASS);
|
||||
|
||||
if (nsec3) {
|
||||
node->nsec = DNS_DB_NSEC_NSEC3;
|
||||
} else {
|
||||
/*
|
||||
* Add empty non-terminal nodes to help with wildcards.
|
||||
*/
|
||||
addwildcards(qpdb, qp, name);
|
||||
if (dns_name_iswildcard(name)) {
|
||||
wildcardmagic(qpdb, qp, name);
|
||||
|
|
@ -2472,20 +2530,15 @@ findnodeintree(qpzonedb_t *qpdb, const dns_name_t *name, bool create,
|
|||
}
|
||||
}
|
||||
|
||||
INSIST(node->nsec == DNS_DB_NSEC_NSEC3 || !nsec3);
|
||||
|
||||
qpznode_acquire(qpdb, node DNS__DB_FLARG_PASS);
|
||||
|
||||
if (create) {
|
||||
dns_qp_compact(qp, DNS_QPGC_MAYBE);
|
||||
dns_qpmulti_commit(dbtree, &qp);
|
||||
} else {
|
||||
dns_qpread_destroy(dbtree, &qpr);
|
||||
}
|
||||
/*
|
||||
* ... if the lookup is unsuccessful, and the caller didn't ask us
|
||||
* to create a new node, there is nothing to do. Return the result
|
||||
* of the lookup to the caller, and set *nodep to NULL
|
||||
*/
|
||||
|
||||
*nodep = (dns_dbnode_t *)node;
|
||||
|
||||
return ISC_R_SUCCESS;
|
||||
return result;
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
|
|
@ -2495,8 +2548,15 @@ findnode(dns_db_t *db, const dns_name_t *name, bool create,
|
|||
|
||||
REQUIRE(VALID_QPZONE(qpdb));
|
||||
|
||||
return findnodeintree(qpdb, name, create, false,
|
||||
nodep DNS__DB_FLARG_PASS);
|
||||
dns_qpread_t qpr = { 0 };
|
||||
dns_qp_t *qp = begin_transaction(qpdb->tree, &qpr, create);
|
||||
|
||||
isc_result_t result = findnodeintree(qpdb, qp, name, create, false,
|
||||
nodep DNS__DB_FLARG_PASS);
|
||||
|
||||
end_transaction(qpdb->tree, qp, create);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
|
|
@ -2506,8 +2566,15 @@ findnsec3node(dns_db_t *db, const dns_name_t *name, bool create,
|
|||
|
||||
REQUIRE(VALID_QPZONE(qpdb));
|
||||
|
||||
return findnodeintree(qpdb, name, create, true,
|
||||
nodep DNS__DB_FLARG_PASS);
|
||||
dns_qpread_t qpr = { 0 };
|
||||
dns_qp_t *qp = begin_transaction(qpdb->nsec3, &qpr, create);
|
||||
|
||||
isc_result_t result = findnodeintree(qpdb, qp, name, create, true,
|
||||
nodep DNS__DB_FLARG_PASS);
|
||||
|
||||
end_transaction(qpdb->nsec3, qp, create);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool
|
||||
|
|
@ -4646,10 +4713,21 @@ createiterator(dns_db_t *db, unsigned int options,
|
|||
return ISC_R_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Main logic to add a new rdataset to a node.
|
||||
*
|
||||
* The reason this is split from qpzone_addrdataset is to allow the reuse of
|
||||
* the same qp transaction for multiple adds.
|
||||
*
|
||||
* qpzone_subtractrdataset doesn't have the same problem since it cannot delete
|
||||
* nodes, only rdatasets.
|
||||
*/
|
||||
static isc_result_t
|
||||
addrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion,
|
||||
isc_stdtime_t now ISC_ATTR_UNUSED, dns_rdataset_t *rdataset,
|
||||
unsigned int options, dns_rdataset_t *addedrdataset DNS__DB_FLARG) {
|
||||
qpzone_addrdataset_inner(dns_db_t *db, dns_dbnode_t *dbnode,
|
||||
dns_dbversion_t *dbversion,
|
||||
isc_stdtime_t now ISC_ATTR_UNUSED,
|
||||
dns_rdataset_t *rdataset, unsigned int options,
|
||||
dns_rdataset_t *addedrdataset, dns_qp_t *nsec) {
|
||||
isc_result_t result;
|
||||
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
||||
qpznode_t *node = (qpznode_t *)dbnode;
|
||||
|
|
@ -4660,7 +4738,6 @@ addrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion,
|
|||
isc_rwlock_t *nlock = NULL;
|
||||
dns_fixedname_t fn;
|
||||
dns_name_t *name = dns_fixedname_initname(&fn);
|
||||
dns_qp_t *nsec = NULL;
|
||||
|
||||
REQUIRE(VALID_QPZONE(qpdb));
|
||||
REQUIRE(version != NULL && version->qpdb == qpdb);
|
||||
|
|
@ -4721,11 +4798,10 @@ addrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion,
|
|||
/*
|
||||
* Add to the auxiliary NSEC tree if we're adding an NSEC record.
|
||||
*/
|
||||
if (node->nsec != DNS_DB_NSEC_HAS_NSEC &&
|
||||
rdataset->type == dns_rdatatype_nsec)
|
||||
{
|
||||
dns_qpmulti_write(qpdb->nsec, &nsec);
|
||||
}
|
||||
|
||||
bool is_nsec = node->nsec != DNS_DB_NSEC_HAS_NSEC &&
|
||||
rdataset->type == dns_rdatatype_nsec;
|
||||
REQUIRE(!is_nsec || nsec != NULL);
|
||||
|
||||
/*
|
||||
* If we're adding a delegation type or adding to the auxiliary NSEC
|
||||
|
|
@ -4741,7 +4817,8 @@ addrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion,
|
|||
NODE_WRLOCK(nlock, &nlocktype);
|
||||
|
||||
result = ISC_R_SUCCESS;
|
||||
if (nsec != NULL) {
|
||||
|
||||
if (is_nsec) {
|
||||
node->nsec = DNS_DB_NSEC_HAS_NSEC;
|
||||
|
||||
/*
|
||||
|
|
@ -4772,7 +4849,34 @@ addrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion,
|
|||
|
||||
NODE_UNLOCK(nlock, &nlocktype);
|
||||
|
||||
if (nsec != NULL) {
|
||||
return result;
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
addrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion,
|
||||
isc_stdtime_t now ISC_ATTR_UNUSED, dns_rdataset_t *rdataset,
|
||||
unsigned int options, dns_rdataset_t *addedrdataset DNS__DB_FLARG) {
|
||||
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
||||
qpznode_t *node = (qpznode_t *)dbnode;
|
||||
dns_qp_t *nsec = NULL;
|
||||
|
||||
REQUIRE(VALID_QPZONE(qpdb));
|
||||
|
||||
bool is_nsec = node->nsec != DNS_DB_NSEC_HAS_NSEC &&
|
||||
rdataset->type == dns_rdatatype_nsec;
|
||||
|
||||
/*
|
||||
* Add to the auxiliary NSEC tree if we're adding an NSEC record.
|
||||
*/
|
||||
if (is_nsec) {
|
||||
dns_qpmulti_write(qpdb->nsec, &nsec);
|
||||
}
|
||||
|
||||
isc_result_t result = qpzone_addrdataset_inner(db, dbnode, dbversion,
|
||||
now, rdataset, options,
|
||||
addedrdataset, nsec);
|
||||
|
||||
if (is_nsec) {
|
||||
dns_qpmulti_commit(qpdb->nsec, &nsec);
|
||||
}
|
||||
|
||||
|
|
@ -5202,10 +5306,186 @@ setmaxtypepername(dns_db_t *db, uint32_t value) {
|
|||
qpdb->maxtypepername = value;
|
||||
}
|
||||
|
||||
/*
|
||||
* Qpzone specialization of the update function from dns_rdatacallbacks_t,
|
||||
* meant to reuse the same qp transaction for multiple operations.
|
||||
*/
|
||||
static isc_result_t
|
||||
qpzone_update_rdataset(qpzonedb_t *qpdb, qpz_version_t *version,
|
||||
qpzone_updatectx_t *ctx, dns_name_t *name,
|
||||
dns_rdataset_t *rds, dns_diffop_t op) {
|
||||
isc_result_t result;
|
||||
unsigned int options;
|
||||
dns_rdataset_t ardataset;
|
||||
dns_dbnode_t *node = NULL;
|
||||
bool is_nsec3;
|
||||
|
||||
dns_rdataset_init(&ardataset);
|
||||
|
||||
is_nsec3 = (rds->type == dns_rdatatype_nsec3 ||
|
||||
rds->covers == dns_rdatatype_nsec3);
|
||||
dns_qp_t *dbtree = is_nsec3 ? ctx->nsec3 : ctx->qp;
|
||||
|
||||
result = findnodeintree(qpdb, dbtree, name, true, is_nsec3,
|
||||
&node DNS__DB_FLARG_PASS);
|
||||
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
switch (op) {
|
||||
case DNS_DIFFOP_ADD:
|
||||
case DNS_DIFFOP_ADDRESIGN:
|
||||
/*
|
||||
* See the comment on qpzone_addrdataset_inner for why we
|
||||
* cannot use qpzone_addrdataset directly.
|
||||
*/
|
||||
options = DNS_DBADD_MERGE | DNS_DBADD_EXACT |
|
||||
DNS_DBADD_EXACTTTL;
|
||||
result = qpzone_addrdataset_inner(
|
||||
(dns_db_t *)qpdb, node, (dns_dbversion_t *)version, 0,
|
||||
rds, options, &ardataset, ctx->nsec DNS__DB_FLARG_PASS);
|
||||
switch (result) {
|
||||
case ISC_R_SUCCESS:
|
||||
case DNS_R_UNCHANGED:
|
||||
case DNS_R_NXRRSET:
|
||||
dns_rdataset_setownercase(&ardataset, name);
|
||||
CHECK(result);
|
||||
break;
|
||||
default:
|
||||
CHECK(result);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case DNS_DIFFOP_DEL:
|
||||
case DNS_DIFFOP_DELRESIGN:
|
||||
options = DNS_DBSUB_EXACT | DNS_DBSUB_WANTOLD;
|
||||
result = subtractrdataset(
|
||||
(dns_db_t *)qpdb, node, (dns_dbversion_t *)version, rds,
|
||||
options, &ardataset DNS__DB_FLARG_PASS);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
bool is_resign = rds->type == dns_rdatatype_rrsig &&
|
||||
(op == DNS_DIFFOP_DELRESIGN ||
|
||||
op == DNS_DIFFOP_ADDRESIGN);
|
||||
|
||||
if (result == ISC_R_SUCCESS && is_resign) {
|
||||
isc_stdtime_t resign;
|
||||
resign = dns_rdataset_minresign(&ardataset);
|
||||
dns_db_setsigningtime((dns_db_t *)qpdb, &ardataset, resign);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (node != NULL) {
|
||||
dns_db_detachnode((dns_db_t *)qpdb, &node);
|
||||
}
|
||||
if (dns_rdataset_isassociated(&ardataset)) {
|
||||
dns_rdataset_disassociate(&ardataset);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
qpzone_update_callback(void *arg, const dns_name_t *name, dns_rdataset_t *rds,
|
||||
dns_diffop_t op DNS__DB_FLARG) {
|
||||
qpzone_updatectx_t *ctx = arg;
|
||||
qpzonedb_t *qpdb = (qpzonedb_t *)ctx->base.db;
|
||||
qpz_version_t *version = (qpz_version_t *)ctx->base.ver;
|
||||
|
||||
return qpzone_update_rdataset(qpdb, version, ctx, (dns_name_t *)name,
|
||||
rds, op);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
qpzone_beginupdate(dns_db_t *db, dns_dbversion_t *ver,
|
||||
dns_rdatacallbacks_t *callbacks) {
|
||||
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
||||
|
||||
REQUIRE(VALID_QPZONE(qpdb));
|
||||
REQUIRE(ver != NULL);
|
||||
REQUIRE(DNS_CALLBACK_VALID(callbacks));
|
||||
|
||||
qpzone_updatectx_t *ctx = isc_mem_get(qpdb->common.mctx, sizeof(*ctx));
|
||||
*ctx = (qpzone_updatectx_t){
|
||||
.base.db = db,
|
||||
.base.ver = ver,
|
||||
.base.warn = true,
|
||||
.qpr = (dns_qpread_t){ 0 },
|
||||
};
|
||||
ctx->qp = begin_transaction(qpdb->tree, &ctx->qpr, true);
|
||||
ctx->nsec = begin_transaction(qpdb->nsec, &ctx->qpr, true);
|
||||
ctx->nsec3 = begin_transaction(qpdb->nsec3, &ctx->qpr, true);
|
||||
|
||||
callbacks->update = qpzone_update_callback;
|
||||
callbacks->add_private = ctx;
|
||||
|
||||
return ISC_R_SUCCESS;
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
qpzone_commitupdate(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
|
||||
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
||||
qpzone_updatectx_t *ctx;
|
||||
|
||||
REQUIRE(VALID_QPZONE(qpdb));
|
||||
REQUIRE(DNS_CALLBACK_VALID(callbacks));
|
||||
|
||||
ctx = (qpzone_updatectx_t *)callbacks->add_private;
|
||||
if (ctx != NULL) {
|
||||
end_transaction(qpdb->nsec3, ctx->nsec3, true);
|
||||
end_transaction(qpdb->nsec, ctx->nsec, true);
|
||||
end_transaction(qpdb->tree, ctx->qp, true);
|
||||
|
||||
isc_mem_put(qpdb->common.mctx, ctx, sizeof(*ctx));
|
||||
/*
|
||||
* We need to allow the context to be committed or aborted
|
||||
* multiple times, so we set the callback data to NULL
|
||||
* to signal that nothing needs to be done with this context.
|
||||
*/
|
||||
callbacks->add_private = NULL;
|
||||
}
|
||||
|
||||
return ISC_R_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* For now, abortupdate needs to *commit* the results, so that closeversion
|
||||
* cleanup might work.
|
||||
*/
|
||||
static isc_result_t
|
||||
qpzone_abortupdate(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
|
||||
qpzonedb_t *qpdb = (qpzonedb_t *)db;
|
||||
qpzone_updatectx_t *ctx;
|
||||
|
||||
REQUIRE(VALID_QPZONE(qpdb));
|
||||
REQUIRE(DNS_CALLBACK_VALID(callbacks));
|
||||
|
||||
ctx = (qpzone_updatectx_t *)callbacks->add_private;
|
||||
if (ctx != NULL) {
|
||||
end_transaction(qpdb->nsec3, ctx->nsec3, true);
|
||||
end_transaction(qpdb->nsec, ctx->nsec, true);
|
||||
end_transaction(qpdb->tree, ctx->qp, true);
|
||||
|
||||
isc_mem_put(qpdb->common.mctx, ctx, sizeof(*ctx));
|
||||
/*
|
||||
* See qpzone_commitupdate.
|
||||
*/
|
||||
callbacks->add_private = NULL;
|
||||
}
|
||||
|
||||
return ISC_R_SUCCESS;
|
||||
}
|
||||
|
||||
static dns_dbmethods_t qpdb_zonemethods = {
|
||||
.destroy = qpdb_destroy,
|
||||
.beginload = beginload,
|
||||
.endload = endload,
|
||||
.beginupdate = qpzone_beginupdate,
|
||||
.commitupdate = qpzone_commitupdate,
|
||||
.abortupdate = qpzone_abortupdate,
|
||||
.currentversion = currentversion,
|
||||
.newversion = newversion,
|
||||
.attachversion = attachversion,
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
#include <dns/callbacks.h>
|
||||
#include <dns/db.h>
|
||||
#include <dns/dbiterator.h>
|
||||
#include <dns/diff.h>
|
||||
#include <dns/fixedname.h>
|
||||
#include <dns/log.h>
|
||||
#include <dns/masterdump.h>
|
||||
|
|
@ -62,6 +63,7 @@
|
|||
#include <dns/zonekey.h>
|
||||
|
||||
#include "db_p.h"
|
||||
#include "isc/attributes.h"
|
||||
#include "rbtdb_p.h"
|
||||
|
||||
#define EXISTS(header) \
|
||||
|
|
@ -1677,8 +1679,8 @@ done:
|
|||
}
|
||||
|
||||
static isc_result_t
|
||||
loading_addrdataset(void *arg, const dns_name_t *name,
|
||||
dns_rdataset_t *rdataset DNS__DB_FLARG) {
|
||||
loading_addrdataset(void *arg, const dns_name_t *name, dns_rdataset_t *rdataset,
|
||||
dns_diffop_t op ISC_ATTR_UNUSED DNS__DB_FLARG) {
|
||||
rbtdb_load_t *loadctx = arg;
|
||||
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)loadctx->db;
|
||||
dns_rbtnode_t *node = NULL;
|
||||
|
|
@ -1812,7 +1814,7 @@ beginload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
|
|||
|
||||
RWUNLOCK(&rbtdb->lock, isc_rwlocktype_write);
|
||||
|
||||
callbacks->add = loading_addrdataset;
|
||||
callbacks->update = loading_addrdataset;
|
||||
callbacks->add_private = loadctx;
|
||||
|
||||
return ISC_R_SUCCESS;
|
||||
|
|
@ -1849,7 +1851,7 @@ endload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
|
|||
RWUNLOCK(&rbtdb->lock, isc_rwlocktype_write);
|
||||
}
|
||||
|
||||
callbacks->add = NULL;
|
||||
callbacks->update = NULL;
|
||||
callbacks->add_private = NULL;
|
||||
|
||||
isc_mem_put(rbtdb->common.mctx, loadctx, sizeof(*loadctx));
|
||||
|
|
@ -2247,10 +2249,52 @@ addglue(dns_db_t *db, dns_dbversion_t *dbversion, dns_rdataset_t *rdataset,
|
|||
return ISC_R_SUCCESS;
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
rbt_beginupdate(dns_db_t *db, dns_dbversion_t *ver,
|
||||
dns_rdatacallbacks_t *callbacks) {
|
||||
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
|
||||
|
||||
REQUIRE(VALID_RBTDB(rbtdb));
|
||||
REQUIRE(ver != NULL);
|
||||
REQUIRE(DNS_CALLBACK_VALID(callbacks));
|
||||
|
||||
dns_updatectx_t *ctx = isc_mem_get(rbtdb->common.mctx, sizeof(*ctx));
|
||||
*ctx = (dns_updatectx_t){
|
||||
.db = db,
|
||||
.ver = ver,
|
||||
.warn = true,
|
||||
};
|
||||
|
||||
callbacks->update = update_callback;
|
||||
callbacks->add_private = ctx;
|
||||
|
||||
return ISC_R_SUCCESS;
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
rbt_endupdate(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
|
||||
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
|
||||
dns_updatectx_t *ctx;
|
||||
|
||||
REQUIRE(VALID_RBTDB(rbtdb));
|
||||
REQUIRE(DNS_CALLBACK_VALID(callbacks));
|
||||
|
||||
ctx = (dns_updatectx_t *)callbacks->add_private;
|
||||
if (ctx != NULL) {
|
||||
isc_mem_put(rbtdb->common.mctx, ctx, sizeof(*ctx));
|
||||
callbacks->add_private = NULL;
|
||||
}
|
||||
|
||||
return ISC_R_SUCCESS;
|
||||
}
|
||||
|
||||
dns_dbmethods_t dns__rbtdb_zonemethods = {
|
||||
.destroy = dns__rbtdb_destroy,
|
||||
.beginload = beginload,
|
||||
.endload = endload,
|
||||
.beginupdate = rbt_beginupdate,
|
||||
.commitupdate = rbt_endupdate,
|
||||
.abortupdate = rbt_endupdate,
|
||||
.currentversion = dns__rbtdb_currentversion,
|
||||
.newversion = dns__rbtdb_newversion,
|
||||
.attachversion = dns__rbtdb_attachversion,
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@
|
|||
#include <dns/ncache.h>
|
||||
#include <dns/rdata.h>
|
||||
#include <dns/rdataset.h>
|
||||
#include <dns/time.h>
|
||||
#include <dns/types.h>
|
||||
|
||||
static const char *trustnames[] = {
|
||||
"none", "pending-additional",
|
||||
|
|
@ -676,3 +678,41 @@ dns_rdataset_trimttl(dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
|
|||
rdataset->ttl = ttl;
|
||||
sigrdataset->ttl = ttl;
|
||||
}
|
||||
|
||||
isc_stdtime_t
|
||||
dns_rdataset_minresign(dns_rdataset_t *rdataset) {
|
||||
dns_rdata_t rdata = DNS_RDATA_INIT;
|
||||
dns_rdata_rrsig_t sig;
|
||||
int64_t when;
|
||||
isc_result_t result;
|
||||
|
||||
REQUIRE(DNS_RDATASET_VALID(rdataset));
|
||||
|
||||
result = dns_rdataset_first(rdataset);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
dns_rdataset_current(rdataset, &rdata);
|
||||
(void)dns_rdata_tostruct(&rdata, &sig, NULL);
|
||||
if ((rdata.flags & DNS_RDATA_OFFLINE) != 0) {
|
||||
when = 0;
|
||||
} else {
|
||||
when = dns_time64_from32(sig.timeexpire);
|
||||
}
|
||||
dns_rdata_reset(&rdata);
|
||||
|
||||
result = dns_rdataset_next(rdataset);
|
||||
while (result == ISC_R_SUCCESS) {
|
||||
dns_rdataset_current(rdataset, &rdata);
|
||||
(void)dns_rdata_tostruct(&rdata, &sig, NULL);
|
||||
if ((rdata.flags & DNS_RDATA_OFFLINE) != 0) {
|
||||
goto next_rr;
|
||||
}
|
||||
if (when == 0 || dns_time64_from32(sig.timeexpire) < when) {
|
||||
when = dns_time64_from32(sig.timeexpire);
|
||||
}
|
||||
next_rr:
|
||||
dns_rdata_reset(&rdata);
|
||||
result = dns_rdataset_next(rdataset);
|
||||
}
|
||||
INSIST(result == ISC_R_NOMORE);
|
||||
return (isc_stdtime_t)when;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,6 +78,8 @@ typedef enum {
|
|||
* Incoming zone transfer context.
|
||||
*/
|
||||
|
||||
typedef struct dns_ixfr dns_ixfr_t;
|
||||
|
||||
struct dns_xfrin {
|
||||
unsigned int magic;
|
||||
isc_mem_t *mctx;
|
||||
|
|
@ -170,7 +172,7 @@ struct dns_xfrin {
|
|||
*/
|
||||
dns_rdatacallbacks_t axfr;
|
||||
|
||||
struct {
|
||||
struct dns_ixfr {
|
||||
uint32_t request_serial;
|
||||
uint32_t current_serial;
|
||||
dns_journal_t *journal;
|
||||
|
|
@ -485,24 +487,22 @@ cleanup:
|
|||
}
|
||||
|
||||
static isc_result_t
|
||||
ixfr_begin_transaction(dns_xfrin_t *xfr) {
|
||||
ixfr_begin_transaction(dns_ixfr_t *ixfr) {
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
|
||||
if (xfr->ixfr.journal != NULL) {
|
||||
CHECK(dns_journal_begin_transaction(xfr->ixfr.journal));
|
||||
if (ixfr->journal != NULL) {
|
||||
CHECK(dns_journal_begin_transaction(ixfr->journal));
|
||||
}
|
||||
cleanup:
|
||||
return result;
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
ixfr_end_transaction(dns_xfrin_t *xfr) {
|
||||
ixfr_end_transaction(dns_ixfr_t *ixfr) {
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
|
||||
CHECK(dns_zone_verifydb(xfr->zone, xfr->db, xfr->ver));
|
||||
/* XXX enter ready-to-commit state here */
|
||||
if (xfr->ixfr.journal != NULL) {
|
||||
CHECK(dns_journal_commit(xfr->ixfr.journal));
|
||||
if (ixfr->journal != NULL) {
|
||||
CHECK(dns_journal_commit(ixfr->journal));
|
||||
}
|
||||
cleanup:
|
||||
return result;
|
||||
|
|
@ -513,9 +513,14 @@ ixfr_apply_one(dns_xfrin_t *xfr, ixfr_apply_data_t *data) {
|
|||
isc_result_t result = ISC_R_SUCCESS;
|
||||
uint64_t records;
|
||||
|
||||
CHECK(ixfr_begin_transaction(xfr));
|
||||
dns_rdatacallbacks_t callbacks;
|
||||
dns_rdatacallbacks_init(&callbacks);
|
||||
|
||||
CHECK(dns_diff_apply(&data->diff, xfr->db, xfr->ver));
|
||||
CHECK(ixfr_begin_transaction(&xfr->ixfr));
|
||||
|
||||
dns_db_beginupdate(xfr->db, xfr->ver, &callbacks);
|
||||
|
||||
CHECK(dns_diff_apply_with_callbacks(&data->diff, &callbacks));
|
||||
if (xfr->maxrecords != 0U) {
|
||||
result = dns_db_getsize(xfr->db, xfr->ver, &records, NULL);
|
||||
if (result == ISC_R_SUCCESS && records > xfr->maxrecords) {
|
||||
|
|
@ -526,12 +531,29 @@ ixfr_apply_one(dns_xfrin_t *xfr, ixfr_apply_data_t *data) {
|
|||
CHECK(dns_journal_writediff(xfr->ixfr.journal, &data->diff));
|
||||
}
|
||||
|
||||
result = ixfr_end_transaction(xfr);
|
||||
/*
|
||||
* At the moment, rdatacallbacks doesn't offer a way to inspect the
|
||||
* result of a transaction before committing it.
|
||||
*
|
||||
* So we need to commit *before* calling dns_zone_verifydb, and rely
|
||||
* on closeversion to actually do cleanup.
|
||||
*/
|
||||
CHECK(dns_db_commitupdate(xfr->db, &callbacks));
|
||||
|
||||
CHECK(dns_zone_verifydb(xfr->zone, xfr->db, xfr->ver));
|
||||
|
||||
result = ixfr_end_transaction(&xfr->ixfr);
|
||||
|
||||
return result;
|
||||
cleanup:
|
||||
/*
|
||||
* For the reason stated above, dns_db_abortupdate must *commit* the
|
||||
* changes and rely on closeversion to clean them up.
|
||||
*/
|
||||
(void)dns_db_abortupdate(xfr->db, &callbacks);
|
||||
|
||||
/* We need to end the transaction, but keep the previous error */
|
||||
(void)ixfr_end_transaction(xfr);
|
||||
(void)ixfr_end_transaction(&xfr->ixfr);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,13 +63,14 @@ static void
|
|||
rawdata_callback(dns_zone_t *zone, dns_masterrawheader_t *header);
|
||||
|
||||
static isc_result_t
|
||||
add_callback(void *arg, const dns_name_t *owner,
|
||||
dns_rdataset_t *dataset DNS__DB_FLARG) {
|
||||
add_callback(void *arg, const dns_name_t *owner, dns_rdataset_t *dataset,
|
||||
dns_diffop_t op DNS__DB_FLARG) {
|
||||
char buf[BIGBUFLEN];
|
||||
isc_buffer_t target;
|
||||
isc_result_t result;
|
||||
|
||||
UNUSED(arg);
|
||||
UNUSED(op);
|
||||
|
||||
isc_buffer_init(&target, buf, BIGBUFLEN);
|
||||
result = dns_rdataset_totext(dataset, owner, false, false, &target);
|
||||
|
|
@ -107,7 +108,7 @@ setup_master(void (*warn)(struct dns_rdatacallbacks *, const char *, ...),
|
|||
}
|
||||
|
||||
dns_rdatacallbacks_init_stdio(&callbacks);
|
||||
callbacks.add = add_callback;
|
||||
callbacks.update = add_callback;
|
||||
callbacks.rawdata = rawdata_callback;
|
||||
callbacks.zone = NULL;
|
||||
if (warn != NULL) {
|
||||
|
|
@ -133,7 +134,7 @@ test_master(const char *workdir, const char *testfile,
|
|||
}
|
||||
|
||||
dns_rdatacallbacks_init_stdio(&callbacks);
|
||||
callbacks.add = add_callback;
|
||||
callbacks.update = add_callback;
|
||||
callbacks.rawdata = rawdata_callback;
|
||||
callbacks.zone = NULL;
|
||||
if (warn != NULL) {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
#include <isc/util.h>
|
||||
|
||||
#include <dns/callbacks.h>
|
||||
#include <dns/diff.h>
|
||||
#include <dns/qp.h>
|
||||
#include <dns/rdatalist.h>
|
||||
#include <dns/rdataset.h>
|
||||
|
|
@ -45,6 +47,22 @@
|
|||
((atomic_load_acquire(&(header)->attributes) & \
|
||||
DNS_SLABHEADERATTR_CASESET) != 0)
|
||||
|
||||
/*
|
||||
* Macro that uses a for loop to execute a cleanup at the end of scope.
|
||||
*/
|
||||
#define WITH_NEWVERSION(db, version_var, should_commit) \
|
||||
for (dns_dbversion_t *version_var = NULL, *_tmp = ({ \
|
||||
isc_result_t _result = dns_db_newversion(db, \
|
||||
&version_var); \
|
||||
assert_int_equal(_result, ISC_R_SUCCESS); \
|
||||
(dns_dbversion_t *)1; \
|
||||
}); \
|
||||
_tmp != NULL; \
|
||||
_tmp = ({ \
|
||||
dns_db_closeversion(db, &version_var, should_commit); \
|
||||
(dns_dbversion_t *)NULL; \
|
||||
}))
|
||||
|
||||
const char *ownercase_vectors[12][2] = {
|
||||
{
|
||||
"AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz",
|
||||
|
|
@ -96,6 +114,70 @@ const char *ownercase_vectors[12][2] = {
|
|||
}
|
||||
};
|
||||
|
||||
static unsigned char example_org_data[] = { 7, 'e', 'x', 'a', 'm', 'p', 'l',
|
||||
'e', 3, 'o', 'r', 'g', 0 };
|
||||
static unsigned char example_org_offsets[] = { 0, 8, 12 };
|
||||
static dns_name_t example_org_name = DNS_NAME_INITABSOLUTE(example_org_data,
|
||||
example_org_offsets);
|
||||
|
||||
/* IPv6 test addresses */
|
||||
static unsigned char aaaa_test_data[][16] = {
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, /* ::1 */
|
||||
{ 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
2 } /* 2001:db8::2
|
||||
*/
|
||||
};
|
||||
|
||||
/* RRSIG test signatures */
|
||||
static unsigned char rrsig_signature1[64] = {
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
|
||||
0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
|
||||
0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21,
|
||||
0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c,
|
||||
0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
||||
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40
|
||||
};
|
||||
|
||||
static unsigned char rrsig_signature2[64] = {
|
||||
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b,
|
||||
0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56,
|
||||
0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61,
|
||||
0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
|
||||
0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
|
||||
0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80
|
||||
};
|
||||
|
||||
/* RRSIG test structures */
|
||||
static dns_rdata_rrsig_t rrsig_test_data1 = {
|
||||
.common = { .rdtype = dns_rdatatype_rrsig,
|
||||
.rdclass = dns_rdataclass_in },
|
||||
.covered = dns_rdatatype_a,
|
||||
.algorithm = DST_ALG_RSASHA256,
|
||||
.labels = 2,
|
||||
.originalttl = 300,
|
||||
.timeexpire = 1695820800,
|
||||
.timesigned = 1695744000,
|
||||
.keyid = 0x1234,
|
||||
.signer = DNS_NAME_INITABSOLUTE(example_org_data, example_org_offsets),
|
||||
.siglen = 64,
|
||||
.signature = rrsig_signature1,
|
||||
};
|
||||
|
||||
static dns_rdata_rrsig_t rrsig_test_data2 = {
|
||||
.common = { .rdtype = dns_rdatatype_rrsig,
|
||||
.rdclass = dns_rdataclass_in },
|
||||
.covered = dns_rdatatype_a,
|
||||
.algorithm = DST_ALG_RSASHA256,
|
||||
.labels = 2,
|
||||
.originalttl = 300,
|
||||
.timeexpire = 1695820800,
|
||||
.timesigned = 1695744000,
|
||||
.keyid = 0x5678,
|
||||
.signer = DNS_NAME_INITABSOLUTE(example_org_data, example_org_offsets),
|
||||
.siglen = 64,
|
||||
.signature = rrsig_signature2,
|
||||
};
|
||||
|
||||
static bool
|
||||
ownercase_test_one(const char *str1, const char *str2) {
|
||||
isc_result_t result;
|
||||
|
|
@ -165,6 +247,118 @@ ISC_RUN_TEST_IMPL(ownercase) {
|
|||
assert_false(ownercase_test_one("\\216", "\\246"));
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
find_ip_index(const unsigned char *target_ip, unsigned char (*ips)[16],
|
||||
ssize_t count) {
|
||||
for (ssize_t i = 0; i < count; i++) {
|
||||
if (memcmp(target_ip, ips[i], 16) == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
apply_dns_update(dns_db_t *db, dns_dbversion_t *version, const dns_name_t *name,
|
||||
dns_rdatatype_t rdtype, dns_rdataclass_t rdclass, uint32_t ttl,
|
||||
const unsigned char *data, size_t data_len, dns_diffop_t op) {
|
||||
isc_result_t result;
|
||||
dns_rdatacallbacks_t callbacks;
|
||||
dns_rdatalist_t rdatalist;
|
||||
dns_rdataset_t rdataset;
|
||||
dns_rdata_t rdata = DNS_RDATA_INIT;
|
||||
|
||||
dns_rdatacallbacks_init(&callbacks);
|
||||
|
||||
result = dns_db_beginupdate(db, version, &callbacks);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
|
||||
/* Set rdata fields directly without reinitializing */
|
||||
rdata.data = (unsigned char *)data;
|
||||
rdata.length = data_len;
|
||||
rdata.rdclass = rdclass;
|
||||
rdata.type = rdtype;
|
||||
|
||||
dns_rdatalist_init(&rdatalist);
|
||||
rdatalist.ttl = ttl;
|
||||
rdatalist.type = rdtype;
|
||||
rdatalist.rdclass = rdclass;
|
||||
ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
|
||||
|
||||
dns_rdataset_init(&rdataset);
|
||||
dns_rdatalist_tordataset(&rdatalist, &rdataset);
|
||||
|
||||
isc_result_t callback_result = callbacks.update(callbacks.add_private,
|
||||
name, &rdataset, op);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
|
||||
dns_rdataset_disassociate(&rdataset);
|
||||
|
||||
result = dns_db_commitupdate(db, &callbacks);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
|
||||
return callback_result;
|
||||
}
|
||||
|
||||
static void
|
||||
verify_aaaa_records(dns_db_t *db, dns_dbversion_t *version,
|
||||
const dns_name_t *name, unsigned char (*ips)[16],
|
||||
ssize_t expected_count, uint32_t expected_ttl) {
|
||||
isc_result_t result;
|
||||
dns_dbnode_t *node = NULL;
|
||||
dns_rdataset_t rdataset;
|
||||
bool *found_ips = NULL;
|
||||
dns_fixedname_t found_fname;
|
||||
dns_name_t *found_name = dns_fixedname_initname(&found_fname);
|
||||
|
||||
/* Allocate zero-initialized found flags array */
|
||||
found_ips = isc_mem_cget(mctx, (size_t)expected_count, sizeof(bool));
|
||||
|
||||
dns_rdataset_init(&rdataset);
|
||||
|
||||
result = dns_db_find(db, name, version, dns_rdatatype_aaaa, 0, 0, &node,
|
||||
found_name, &rdataset, NULL);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
|
||||
/* Check rdataset metadata */
|
||||
assert_int_equal(rdataset.type, dns_rdatatype_aaaa);
|
||||
assert_int_equal(rdataset.rdclass, dns_rdataclass_in);
|
||||
assert_int_equal(rdataset.ttl, expected_ttl);
|
||||
|
||||
/* Iterate through all AAAA records */
|
||||
for (result = dns_rdataset_first(&rdataset); result == ISC_R_SUCCESS;
|
||||
result = dns_rdataset_next(&rdataset))
|
||||
{
|
||||
dns_rdata_t rdata = DNS_RDATA_INIT;
|
||||
dns_rdataset_current(&rdataset, &rdata);
|
||||
|
||||
/* Verify this is a valid IPv6 address */
|
||||
assert_int_equal(rdata.length, 16);
|
||||
|
||||
/*
|
||||
* Find whether the IP is in our expected list, and detect
|
||||
* duplicates. Index will be -1 if the IP is not found.
|
||||
*/
|
||||
ssize_t index = find_ip_index(rdata.data, ips, expected_count);
|
||||
assert_true(index >= 0);
|
||||
assert_false(found_ips[index]);
|
||||
found_ips[index] = true;
|
||||
}
|
||||
|
||||
/* Count found IPs by summing overt the boolean array */
|
||||
ssize_t found_count = 0;
|
||||
for (ssize_t i = 0; i < expected_count; i++) {
|
||||
found_count += found_ips[i];
|
||||
}
|
||||
|
||||
/* Verify we found exactly the expected number of records */
|
||||
assert_int_equal(found_count, expected_count);
|
||||
|
||||
dns_db_detachnode(db, &node);
|
||||
dns_rdataset_disassociate(&rdataset);
|
||||
isc_mem_cput(mctx, found_ips, (size_t)expected_count, sizeof(bool));
|
||||
}
|
||||
|
||||
ISC_RUN_TEST_IMPL(setownercase) {
|
||||
isc_result_t result;
|
||||
uint8_t qpdb_s[sizeof(qpzonedb_t) + sizeof(qpzone_bucket_t)];
|
||||
|
|
@ -220,9 +414,122 @@ ISC_RUN_TEST_IMPL(setownercase) {
|
|||
assert_true(dns_name_caseequal(name1, name2));
|
||||
}
|
||||
|
||||
ISC_RUN_TEST_IMPL(diffop_add_sub) {
|
||||
isc_result_t result;
|
||||
dns_db_t *db = NULL;
|
||||
|
||||
result = dns__qpzone_create(mctx, &example_org_name, dns_dbtype_zone,
|
||||
dns_rdataclass_in, 0, NULL, NULL, &db);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
assert_non_null(db);
|
||||
|
||||
WITH_NEWVERSION(db, version, true) {
|
||||
apply_dns_update(db, version, &example_org_name,
|
||||
dns_rdatatype_aaaa, dns_rdataclass_in, 300,
|
||||
aaaa_test_data[0], 16, DNS_DIFFOP_ADD);
|
||||
}
|
||||
|
||||
WITH_NEWVERSION(db, version, true) {
|
||||
result = apply_dns_update(db, version, &example_org_name,
|
||||
dns_rdatatype_aaaa, dns_rdataclass_in,
|
||||
300, aaaa_test_data[1], 16,
|
||||
DNS_DIFFOP_ADD);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
|
||||
verify_aaaa_records(db, version, &example_org_name,
|
||||
aaaa_test_data, 2, 300);
|
||||
}
|
||||
|
||||
WITH_NEWVERSION(db, version, true) {
|
||||
result = apply_dns_update(db, version, &example_org_name,
|
||||
dns_rdatatype_aaaa, dns_rdataclass_in,
|
||||
300, aaaa_test_data[0], 16,
|
||||
DNS_DIFFOP_DEL);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
|
||||
verify_aaaa_records(db, version, &example_org_name,
|
||||
&aaaa_test_data[1], 1, 300);
|
||||
}
|
||||
|
||||
WITH_NEWVERSION(db, version, false) {
|
||||
result = apply_dns_update(db, version, &example_org_name,
|
||||
dns_rdatatype_aaaa, dns_rdataclass_in,
|
||||
600, aaaa_test_data[0], 16,
|
||||
DNS_DIFFOP_ADD);
|
||||
assert_int_equal(result, DNS_R_NOTEXACT);
|
||||
}
|
||||
|
||||
dns_db_detach(&db);
|
||||
assert_null(db);
|
||||
}
|
||||
|
||||
ISC_RUN_TEST_IMPL(diffop_addresign) {
|
||||
isc_result_t result;
|
||||
dns_db_t *db = NULL;
|
||||
|
||||
/* Create RRSIG structures and convert to wire format */
|
||||
dns_rdata_t rdata1 = DNS_RDATA_INIT, rdata2 = DNS_RDATA_INIT;
|
||||
isc_buffer_t buffer1, buffer2;
|
||||
unsigned char rrsig_data1[512], rrsig_data2[512];
|
||||
|
||||
isc_buffer_init(&buffer1, rrsig_data1, sizeof(rrsig_data1));
|
||||
result = dns_rdata_fromstruct(&rdata1, dns_rdataclass_in,
|
||||
dns_rdatatype_rrsig, &rrsig_test_data1,
|
||||
&buffer1);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
|
||||
isc_buffer_init(&buffer2, rrsig_data2, sizeof(rrsig_data2));
|
||||
result = dns_rdata_fromstruct(&rdata2, dns_rdataclass_in,
|
||||
dns_rdatatype_rrsig, &rrsig_test_data2,
|
||||
&buffer2);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
|
||||
result = dns__qpzone_create(mctx, &example_org_name, dns_dbtype_zone,
|
||||
dns_rdataclass_in, 0, NULL, NULL, &db);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
assert_non_null(db);
|
||||
|
||||
WITH_NEWVERSION(db, version, true) {
|
||||
result = apply_dns_update(db, version, &example_org_name,
|
||||
dns_rdatatype_rrsig,
|
||||
dns_rdataclass_in, 300, rdata1.data,
|
||||
rdata1.length, DNS_DIFFOP_ADDRESIGN);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
WITH_NEWVERSION(db, version, true) {
|
||||
result = apply_dns_update(db, version, &example_org_name,
|
||||
dns_rdatatype_rrsig,
|
||||
dns_rdataclass_in, 300, rdata2.data,
|
||||
rdata2.length, DNS_DIFFOP_ADDRESIGN);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
WITH_NEWVERSION(db, version, true) {
|
||||
result = apply_dns_update(db, version, &example_org_name,
|
||||
dns_rdatatype_rrsig,
|
||||
dns_rdataclass_in, 300, rdata1.data,
|
||||
rdata1.length, DNS_DIFFOP_DELRESIGN);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
WITH_NEWVERSION(db, version, true) {
|
||||
result = apply_dns_update(db, version, &example_org_name,
|
||||
dns_rdatatype_rrsig,
|
||||
dns_rdataclass_in, 300, rdata2.data,
|
||||
rdata2.length, DNS_DIFFOP_DELRESIGN);
|
||||
assert_int_equal(result, DNS_R_NXRRSET);
|
||||
}
|
||||
|
||||
dns_db_detach(&db);
|
||||
assert_null(db);
|
||||
}
|
||||
|
||||
ISC_TEST_LIST_START
|
||||
ISC_TEST_ENTRY(ownercase)
|
||||
ISC_TEST_ENTRY(setownercase)
|
||||
ISC_TEST_ENTRY(diffop_add_sub)
|
||||
ISC_TEST_ENTRY(diffop_addresign)
|
||||
ISC_TEST_LIST_END
|
||||
|
||||
ISC_TEST_MAIN
|
||||
|
|
|
|||
Loading…
Reference in a new issue