mirror of
https://github.com/isc-projects/bind9.git
synced 2026-05-28 04:34:54 -04:00
CNAME/DNAME chaining (initial support; A6 still missing)
This commit is contained in:
parent
5dbf258e2c
commit
4abed3e356
2 changed files with 155 additions and 35 deletions
181
lib/dns/adb.c
181
lib/dns/adb.c
|
|
@ -307,7 +307,7 @@ static void clean_target(dns_adb_t *, dns_name_t *);
|
|||
static void clean_finds_at_name(dns_adbname_t *, isc_eventtype_t,
|
||||
unsigned int);
|
||||
static void check_expire_namehooks(dns_adbname_t *, isc_stdtime_t);
|
||||
static void cancel_fetches_at_name(dns_adb_t *, dns_adbname_t *);
|
||||
static void cancel_fetches_at_name(dns_adbname_t *);
|
||||
static isc_result_t dbfind_name(dns_adbname_t *, isc_stdtime_t,
|
||||
isc_boolean_t, dns_rdatatype_t);
|
||||
static isc_result_t fetch_name_v4(dns_adbname_t *, isc_boolean_t);
|
||||
|
|
@ -659,7 +659,7 @@ kill_name(dns_adbname_t **n, isc_eventtype_t ev)
|
|||
free_adbname(adb, &name);
|
||||
} else {
|
||||
name->flags |= NAME_IS_DEAD;
|
||||
cancel_fetches_at_name(adb, name);
|
||||
cancel_fetches_at_name(name);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -868,21 +868,21 @@ shutdown_entries(dns_adb_t *adb)
|
|||
* Name bucket must be locked
|
||||
*/
|
||||
static void
|
||||
cancel_fetches_at_name(dns_adb_t *adb, dns_adbname_t *name)
|
||||
cancel_fetches_at_name(dns_adbname_t *name)
|
||||
{
|
||||
dns_adbfetch6_t *fetch6;
|
||||
|
||||
if (NAME_FETCH_A(name))
|
||||
dns_resolver_cancelfetch(adb->view->resolver,
|
||||
name->fetch_a->fetch);
|
||||
dns_resolver_cancelfetch(name->fetch_a->fetch);
|
||||
|
||||
|
||||
if (NAME_FETCH_AAAA(name))
|
||||
dns_resolver_cancelfetch(adb->view->resolver,
|
||||
name->fetch_aaaa->fetch);
|
||||
dns_resolver_cancelfetch(name->fetch_aaaa->fetch);
|
||||
|
||||
|
||||
fetch6 = ISC_LIST_HEAD(name->fetches_a6);
|
||||
while (fetch6 != NULL) {
|
||||
dns_resolver_cancelfetch(adb->view->resolver, fetch6->fetch);
|
||||
dns_resolver_cancelfetch(fetch6->fetch);
|
||||
fetch6 = ISC_LIST_NEXT(fetch6, plink);
|
||||
}
|
||||
}
|
||||
|
|
@ -955,6 +955,8 @@ set_target(dns_adb_t *adb, dns_name_t *name, dns_name_t *fname,
|
|||
dns_fixedname_t fixed1, fixed2;
|
||||
dns_name_t *prefix, *new_target;
|
||||
|
||||
REQUIRE(dns_name_countlabels(target) == 0);
|
||||
|
||||
if (rdataset->type == dns_rdatatype_cname) {
|
||||
/*
|
||||
* Copy the CNAME's target into the target name.
|
||||
|
|
@ -1226,7 +1228,8 @@ dec_entry_refcnt(dns_adb_t *adb, dns_adbentry_t *entry, isc_boolean_t lock)
|
|||
entry->refcnt--;
|
||||
|
||||
destroy_entry = ISC_FALSE;
|
||||
if (entry->refcnt == 0 && entry->expires == 0) {
|
||||
if (entry->refcnt == 0 &&
|
||||
(adb->entry_sd[bucket] || entry->expires == 0)) {
|
||||
destroy_entry = ISC_TRUE;
|
||||
unlink_entry(adb, entry);
|
||||
}
|
||||
|
|
@ -2361,13 +2364,13 @@ dns_adb_shutdown(dns_adb_t *adb) {
|
|||
isc_result_t
|
||||
dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
|
||||
void *arg, dns_name_t *name, dns_name_t *zone,
|
||||
unsigned int options, isc_stdtime_t now,
|
||||
unsigned int options, isc_stdtime_t now, dns_name_t *target,
|
||||
dns_adbfind_t **findp)
|
||||
{
|
||||
dns_adbfind_t *find;
|
||||
dns_adbname_t *adbname;
|
||||
int bucket;
|
||||
isc_boolean_t use_hints, want_event, start_at_root;
|
||||
isc_boolean_t use_hints, want_event, start_at_root, alias;
|
||||
isc_result_t result;
|
||||
unsigned int wanted_addresses;
|
||||
unsigned int wanted_fetches;
|
||||
|
|
@ -2380,6 +2383,7 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
|
|||
REQUIRE(name != NULL);
|
||||
REQUIRE(zone != NULL);
|
||||
REQUIRE(findp != NULL && *findp == NULL);
|
||||
REQUIRE(target == NULL || dns_name_hasbuffer(target));
|
||||
|
||||
REQUIRE((options & DNS_ADBFIND_ADDRESSMASK) != 0);
|
||||
|
||||
|
|
@ -2389,6 +2393,7 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
|
|||
query_pending = 0;
|
||||
want_event = ISC_FALSE;
|
||||
start_at_root = ISC_FALSE;
|
||||
alias = ISC_FALSE;
|
||||
|
||||
if (now == 0)
|
||||
isc_stdtime_get(&now);
|
||||
|
|
@ -2460,6 +2465,20 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
|
|||
|
||||
use_hints = dns_name_equal(zone, dns_rootname);
|
||||
|
||||
/*
|
||||
* Do we know that the name is an alias?
|
||||
*/
|
||||
if (!EXPIRE_OK(adbname->expire_target, now)) {
|
||||
/*
|
||||
* Yes, it is.
|
||||
*/
|
||||
DP(DEF_LEVEL,
|
||||
"dns_adb_createfind: name %p is an alias (cached)",
|
||||
adbname);
|
||||
alias = ISC_TRUE;
|
||||
goto post_copy;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to populate the name from the database and/or
|
||||
* start fetches.
|
||||
|
|
@ -2475,6 +2494,17 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
|
|||
goto v6;
|
||||
}
|
||||
|
||||
/*
|
||||
* Did we get a CNAME or DNAME?
|
||||
*/
|
||||
if (result == DNS_R_CNAME || result == DNS_R_DNAME) {
|
||||
DP(DEF_LEVEL,
|
||||
"dns_adb_createfind: name %p is an alias",
|
||||
adbname);
|
||||
alias = ISC_TRUE;
|
||||
goto post_copy;
|
||||
}
|
||||
|
||||
/*
|
||||
* Listen to negative cache hints, and don't start
|
||||
* another query.
|
||||
|
|
@ -2497,6 +2527,17 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
|
|||
goto fetch;
|
||||
}
|
||||
|
||||
/*
|
||||
* Did we get a CNAME or DNAME?
|
||||
*/
|
||||
if (result == DNS_R_CNAME || result == DNS_R_DNAME) {
|
||||
DP(DEF_LEVEL,
|
||||
"dns_adb_createfind: name %p is an alias",
|
||||
adbname);
|
||||
alias = ISC_TRUE;
|
||||
goto post_copy;
|
||||
}
|
||||
|
||||
/*
|
||||
* Listen to negative cache hints, and don't start
|
||||
* another query.
|
||||
|
|
@ -2554,6 +2595,7 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
|
|||
if (NAME_FETCH_V6(adbname))
|
||||
query_pending |= DNS_ADBFIND_INET6;
|
||||
|
||||
post_copy:
|
||||
/*
|
||||
* Attach to the name's query list if there are queries
|
||||
* already running, and we have been asked to.
|
||||
|
|
@ -2565,6 +2607,8 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
|
|||
want_event = ISC_FALSE;
|
||||
if ((wanted_addresses & query_pending) == 0)
|
||||
want_event = ISC_FALSE;
|
||||
if (alias)
|
||||
want_event = ISC_FALSE;
|
||||
if (want_event) {
|
||||
find->adbname = adbname;
|
||||
find->name_bucket = bucket;
|
||||
|
|
@ -2587,7 +2631,16 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
|
|||
}
|
||||
|
||||
find->partial_result |= (adbname->partial_result & wanted_addresses);
|
||||
result = ISC_R_SUCCESS;
|
||||
if (alias) {
|
||||
if (target != NULL) {
|
||||
result = dns_name_concatenate(&adbname->target, NULL,
|
||||
target, NULL);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
goto out;
|
||||
}
|
||||
result = DNS_R_ALIAS;
|
||||
} else
|
||||
result = ISC_R_SUCCESS;
|
||||
|
||||
out:
|
||||
if (find != NULL) {
|
||||
|
|
@ -2970,8 +3023,11 @@ dump_adb(dns_adb_t *adb, FILE *f)
|
|||
else
|
||||
fprintf(f, "%d] ", name->expire_target - now);
|
||||
print_dns_name(f, &name->name);
|
||||
if (dns_name_countlabels(&name->target) > 0) {
|
||||
fprintf(f, "\t\t alias for ");
|
||||
print_dns_name(f, &name->target);
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
/* XXXRTH print alias target, if it is valid. */
|
||||
print_namehook_list(f, name);
|
||||
print_fetch_list(f, name);
|
||||
print_find_list(f, name);
|
||||
|
|
@ -3090,16 +3146,18 @@ dns_adb_dumpfind(dns_adbfind_t *find, FILE *f)
|
|||
static void
|
||||
print_dns_name(FILE *f, dns_name_t *name)
|
||||
{
|
||||
char buf[257];
|
||||
char buf[1024];
|
||||
isc_buffer_t b;
|
||||
isc_region_t r;
|
||||
|
||||
INSIST(f != NULL);
|
||||
|
||||
memset(buf, 0, sizeof (buf));
|
||||
isc_buffer_init(&b, buf, sizeof (buf) - 1, ISC_BUFFERTYPE_TEXT);
|
||||
isc_buffer_init(&b, buf, sizeof buf, ISC_BUFFERTYPE_TEXT);
|
||||
|
||||
dns_name_totext(name, ISC_FALSE, &b);
|
||||
fprintf(f, buf); /* safe, since names < 256 chars, and we memset */
|
||||
if (dns_name_totext(name, ISC_FALSE, &b) == ISC_R_SUCCESS) {
|
||||
isc_buffer_used(&b, &r);
|
||||
fprintf(f, "%.*s", (int)r.length, r.base);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -3169,17 +3227,21 @@ dbfind_name(dns_adbname_t *adbname, isc_stdtime_t now,
|
|||
isc_result_t result;
|
||||
dns_rdataset_t rdataset;
|
||||
dns_adb_t *adb;
|
||||
dns_fixedname_t foundname;
|
||||
dns_name_t *fname;
|
||||
|
||||
INSIST(DNS_ADBNAME_VALID(adbname));
|
||||
adb = adbname->adb;
|
||||
INSIST(DNS_ADB_VALID(adb));
|
||||
INSIST(rdtype == dns_rdatatype_a || rdtype == dns_rdatatype_aaaa);
|
||||
|
||||
dns_fixedname_init(&foundname);
|
||||
fname = dns_fixedname_name(&foundname);
|
||||
dns_rdataset_init(&rdataset);
|
||||
|
||||
result = dns_view_simplefind(adb->view, &adbname->name, rdtype,
|
||||
now, DNS_DBFIND_GLUEOK, use_hints,
|
||||
&rdataset, NULL);
|
||||
result = dns_view_find(adb->view, &adbname->name, rdtype, now,
|
||||
DNS_DBFIND_GLUEOK, use_hints, fname,
|
||||
&rdataset, NULL);
|
||||
switch (result) {
|
||||
case DNS_R_GLUE:
|
||||
case DNS_R_HINT:
|
||||
|
|
@ -3232,6 +3294,20 @@ dbfind_name(dns_adbname_t *adbname, isc_stdtime_t now,
|
|||
adbname->expire_v6 = rdataset.ttl + now;
|
||||
}
|
||||
break;
|
||||
case DNS_R_CNAME:
|
||||
case DNS_R_DNAME:
|
||||
rdataset.ttl = ISC_MAX(rdataset.ttl, ADB_CACHE_MINIMUM);
|
||||
clean_target(adb, &adbname->target);
|
||||
adbname->expire_target = INT_MAX;
|
||||
result = set_target(adb, &adbname->name, fname, &rdataset,
|
||||
&adbname->target);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
DP(NCACHE_LEVEL,
|
||||
"adb name %p: caching alias target",
|
||||
adbname);
|
||||
adbname->expire_target = rdataset.ttl + now;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (dns_rdataset_isassociated(&rdataset))
|
||||
|
|
@ -3247,6 +3323,8 @@ dbfind_a6(dns_adbname_t *adbname, isc_stdtime_t now, isc_boolean_t use_hints)
|
|||
dns_rdataset_t rdataset;
|
||||
dns_adb_t *adb;
|
||||
dns_a6context_t a6ctx;
|
||||
dns_fixedname_t foundname;
|
||||
dns_name_t *fname;
|
||||
|
||||
INSIST(DNS_ADBNAME_VALID(adbname));
|
||||
adb = adbname->adb;
|
||||
|
|
@ -3255,11 +3333,13 @@ dbfind_a6(dns_adbname_t *adbname, isc_stdtime_t now, isc_boolean_t use_hints)
|
|||
|
||||
result = ISC_R_UNEXPECTED;
|
||||
|
||||
dns_fixedname_init(&foundname);
|
||||
fname = dns_fixedname_name(&foundname);
|
||||
dns_rdataset_init(&rdataset);
|
||||
|
||||
result = dns_view_simplefind(adb->view, &adbname->name,
|
||||
dns_rdatatype_a6, now, DNS_DBFIND_GLUEOK,
|
||||
use_hints, &rdataset, NULL);
|
||||
result = dns_view_find(adb->view, &adbname->name, dns_rdatatype_a6,
|
||||
now, DNS_DBFIND_GLUEOK, use_hints, fname,
|
||||
&rdataset, NULL);
|
||||
switch (result) {
|
||||
case DNS_R_GLUE:
|
||||
case DNS_R_HINT:
|
||||
|
|
@ -3300,6 +3380,21 @@ dbfind_a6(dns_adbname_t *adbname, isc_stdtime_t now, isc_boolean_t use_hints)
|
|||
adbname, rdataset.ttl);
|
||||
adbname->expire_v6 = ISC_MIN(rdataset.ttl + now,
|
||||
adbname->expire_v6);
|
||||
break;
|
||||
case DNS_R_CNAME:
|
||||
case DNS_R_DNAME:
|
||||
rdataset.ttl = ISC_MAX(rdataset.ttl, ADB_CACHE_MINIMUM);
|
||||
clean_target(adb, &adbname->target);
|
||||
adbname->expire_target = INT_MAX;
|
||||
result = set_target(adb, &adbname->name, fname, &rdataset,
|
||||
&adbname->target);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
DP(NCACHE_LEVEL,
|
||||
"adb name %p: caching alias target",
|
||||
adbname);
|
||||
adbname->expire_target = rdataset.ttl + now;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (dns_rdataset_isassociated(&rdataset))
|
||||
|
|
@ -3348,7 +3443,7 @@ fetch_callback(isc_task_t *task, isc_event_t *ev)
|
|||
}
|
||||
INSIST(address_type != 0);
|
||||
|
||||
dns_resolver_destroyfetch(adb->view->resolver, &fetch->fetch);
|
||||
dns_resolver_destroyfetch(&fetch->fetch);
|
||||
dev->fetch = NULL;
|
||||
|
||||
ev_status = DNS_EVENT_ADBNOMOREADDRESSES;
|
||||
|
|
@ -3389,6 +3484,8 @@ fetch_callback(isc_task_t *task, isc_event_t *ev)
|
|||
return;
|
||||
}
|
||||
|
||||
isc_stdtime_get(&now);
|
||||
|
||||
/*
|
||||
* If we got a negative cache response, remember it.
|
||||
*/
|
||||
|
|
@ -3412,11 +3509,25 @@ fetch_callback(isc_task_t *task, isc_event_t *ev)
|
|||
}
|
||||
|
||||
/*
|
||||
* XXXRTH CNAME/DNAME? We don't need to do this for targets
|
||||
* of NS records, but what about other names?
|
||||
*
|
||||
* Need to do this for A6 too!
|
||||
* Handle CNAME/DNAME.
|
||||
*/
|
||||
if (dev->result == DNS_R_CNAME || dev->result == DNS_R_DNAME) {
|
||||
dev->rdataset->ttl = ISC_MAX(dev->rdataset->ttl,
|
||||
ADB_CACHE_MINIMUM);
|
||||
clean_target(adb, &name->target);
|
||||
name->expire_target = INT_MAX;
|
||||
result = set_target(adb, &name->name,
|
||||
dns_fixedname_name(&dev->foundname),
|
||||
dev->rdataset,
|
||||
&name->target);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
DP(NCACHE_LEVEL,
|
||||
"adb fetch name %p: caching alias target",
|
||||
name);
|
||||
name->expire_target = dev->rdataset->ttl + now;
|
||||
}
|
||||
goto check_result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Did we get back junk? If so, and there are no more fetches
|
||||
|
|
@ -3437,8 +3548,9 @@ fetch_callback(isc_task_t *task, isc_event_t *ev)
|
|||
/*
|
||||
* We got something potentially useful.
|
||||
*/
|
||||
isc_stdtime_get(&now);
|
||||
result = import_rdataset(name, &fetch->rdataset, now);
|
||||
|
||||
check_result:
|
||||
if (result == ISC_R_SUCCESS)
|
||||
ev_status = DNS_EVENT_ADBMOREADDRESSES;
|
||||
|
||||
|
|
@ -3449,9 +3561,6 @@ fetch_callback(isc_task_t *task, isc_event_t *ev)
|
|||
clean_finds_at_name(name, ev_status, address_type);
|
||||
|
||||
UNLOCK(&adb->namelocks[bucket]);
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -3490,7 +3599,7 @@ fetch_callback_a6(isc_task_t *task, isc_event_t *ev)
|
|||
|
||||
DP(ENTER_LEVEL, "ENTER: fetch_callback_a6() name %p", name);
|
||||
|
||||
dns_resolver_destroyfetch(adb->view->resolver, &fetch->fetch);
|
||||
dns_resolver_destroyfetch(&fetch->fetch);
|
||||
dev->fetch = NULL;
|
||||
|
||||
/*
|
||||
|
|
@ -3555,6 +3664,10 @@ fetch_callback_a6(isc_task_t *task, isc_event_t *ev)
|
|||
dev->rdataset->ttl + now);
|
||||
}
|
||||
|
||||
/*
|
||||
* XXXRTH Handle CNAME/DNAME.
|
||||
*/
|
||||
|
||||
if (FETCH_USEHINTS(fetch))
|
||||
use_hints = ISC_TRUE;
|
||||
else
|
||||
|
|
|
|||
|
|
@ -258,7 +258,7 @@ dns_adb_shutdown(dns_adb_t *adb);
|
|||
isc_result_t
|
||||
dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
|
||||
void *arg, dns_name_t *name, dns_name_t *zone,
|
||||
unsigned int options, isc_stdtime_t now,
|
||||
unsigned int options, isc_stdtime_t now, dns_name_t *target,
|
||||
dns_adbfind_t **find);
|
||||
/*
|
||||
* Main interface for clients. The adb will look up the name given in
|
||||
|
|
@ -283,6 +283,10 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
|
|||
* the running database. If specified as zero, the current time will
|
||||
* be retrieved and used.
|
||||
*
|
||||
* If 'target' is not NULL and 'name' is an alias (i.e. the name is
|
||||
* CNAME'd or DNAME'd to another name), then 'target' will be updated with
|
||||
* the domain name that 'name' is aliased to.
|
||||
*
|
||||
* XXXMLG Document options, especially the flags which control how
|
||||
* events are sent.
|
||||
*
|
||||
|
|
@ -297,6 +301,8 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
|
|||
*
|
||||
* zone != NULL and *zone be a valid dns_name_t.
|
||||
*
|
||||
* target == NULL or target is a valid name with a buffer.
|
||||
*
|
||||
* find != NULL && *find == NULL.
|
||||
*
|
||||
* Returns:
|
||||
|
|
@ -307,6 +313,7 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
|
|||
* will ever be posted for this context. This is only
|
||||
* returned if task != NULL.
|
||||
* ISC_R_NOMEMORY insufficient resources
|
||||
* DNS_R_ALIAS 'name' is an alias for another name.
|
||||
*
|
||||
* Calls, and returns error codes from:
|
||||
*
|
||||
|
|
|
|||
Loading…
Reference in a new issue