mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-31 06:25:31 +00:00
Merge branch '2927-lame-server-loop' into 'main'
check for loops in ADB finds Closes #2927 See merge request isc-projects/bind9!5474
This commit is contained in:
7
CHANGES
7
CHANGES
@@ -1,3 +1,10 @@
|
|||||||
|
5746. [bug] A lame server delegation could lead to a loop in which
|
||||||
|
a resolver fetch depends on an ADB find which depends
|
||||||
|
on the same resolver fetch. Previously, this would
|
||||||
|
cause the fetch to hang until timing out, but after
|
||||||
|
change #5730 it would hang forever. The condition is
|
||||||
|
now detected and avoided. [GL #2927]
|
||||||
|
|
||||||
5745. [bug] Fetch context objects now use attach/detach
|
5745. [bug] Fetch context objects now use attach/detach
|
||||||
semantics to make it easier to find and debug
|
semantics to make it easier to find and debug
|
||||||
reference-counting errors, and several such errors
|
reference-counting errors, and several such errors
|
||||||
|
@@ -102,6 +102,11 @@ for (;;) {
|
|||||||
} elsif ($qname =~ /example\.net/) {
|
} elsif ($qname =~ /example\.net/) {
|
||||||
$packet->push("authority", new Net::DNS::RR("example.net 300 NS ns.example.net"));
|
$packet->push("authority", new Net::DNS::RR("example.net 300 NS ns.example.net"));
|
||||||
$packet->push("additional", new Net::DNS::RR("ns.example.net 300 A 10.53.0.3"));
|
$packet->push("additional", new Net::DNS::RR("ns.example.net 300 A 10.53.0.3"));
|
||||||
|
} elsif ($qname =~ /lame\.example\.org/) {
|
||||||
|
$packet->header->ad(0);
|
||||||
|
$packet->header->aa(0);
|
||||||
|
$packet->push("authority", new Net::DNS::RR("lame.example.org 300 NS ns.lame.example.org"));
|
||||||
|
$packet->push("additional", new Net::DNS::RR("ns.lame.example.org 300 A 10.53.0.3"));
|
||||||
} elsif ($qname =~ /sub\.example\.org/) {
|
} elsif ($qname =~ /sub\.example\.org/) {
|
||||||
# Data for CNAME/DNAME filtering. The final answers are
|
# Data for CNAME/DNAME filtering. The final answers are
|
||||||
# expected to be accepted regardless of the filter setting.
|
# expected to be accepted regardless of the filter setting.
|
||||||
|
@@ -98,6 +98,11 @@ for (;;) {
|
|||||||
} elsif ($qname =~ /^nxdomain\.example\.net$/i) {
|
} elsif ($qname =~ /^nxdomain\.example\.net$/i) {
|
||||||
$packet->header->aa(1);
|
$packet->header->aa(1);
|
||||||
$packet->header->rcode(NXDOMAIN);
|
$packet->header->rcode(NXDOMAIN);
|
||||||
|
} elsif ($qname =~ /lame\.example\.org/) {
|
||||||
|
$packet->header->ad(0);
|
||||||
|
$packet->header->aa(0);
|
||||||
|
$packet->push("authority", new Net::DNS::RR("lame.example.org 300 NS ns.lame.example.org"));
|
||||||
|
$packet->push("additional", new Net::DNS::RR("ns.lame.example.org 300 A 10.53.0.3"));
|
||||||
} elsif ($qname eq "cname.sub.example.org") {
|
} elsif ($qname eq "cname.sub.example.org") {
|
||||||
$packet->push("answer",
|
$packet->push("answer",
|
||||||
new Net::DNS::RR($qname .
|
new Net::DNS::RR($qname .
|
||||||
|
@@ -889,5 +889,13 @@ grep 'cname-next\.example\.net\..*CNAME.http-server\.example\.net\.' dig.out.ns7
|
|||||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||||
status=`expr $status + $ret`
|
status=`expr $status + $ret`
|
||||||
|
|
||||||
|
n=`expr $n + 1`
|
||||||
|
echo_i "check ADB find loops are detected ($n)"
|
||||||
|
ret=0
|
||||||
|
$DIG $DIGOPTS +tcp +tries=1 +timeout=5 @10.53.0.1 fake.lame.example.org > dig.out.ns1.${n} || ret=1
|
||||||
|
grep "status: SERVFAIL" dig.out.ns1.${n} > /dev/null || ret=1
|
||||||
|
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||||
|
status=`expr $status + $ret`
|
||||||
|
|
||||||
echo_i "exit status: $status"
|
echo_i "exit status: $status"
|
||||||
[ $status -eq 0 ] || exit 1
|
[ $status -eq 0 ] || exit 1
|
||||||
|
@@ -112,3 +112,8 @@ Bug Fixes
|
|||||||
- Logfiles using ``timestamp``-style suffixes were not always correctly
|
- Logfiles using ``timestamp``-style suffixes were not always correctly
|
||||||
removed when the number of files exceeded the limit set by ``versions``.
|
removed when the number of files exceeded the limit set by ``versions``.
|
||||||
:gl:`#828`
|
:gl:`#828`
|
||||||
|
|
||||||
|
- Some lame delegations could trigger a dependency loop, in which a
|
||||||
|
resolver fetch was waiting for a name server address lookup which was
|
||||||
|
waiting for the same resolver fetch. This could cause a recursive lookup
|
||||||
|
to hang until timing out. This now detected and avoided. :gl:`#2927`
|
||||||
|
@@ -407,14 +407,10 @@ log_quota(dns_adbentry_t *entry, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3);
|
|||||||
* Fetches are broken out into A and AAAA types. In some cases,
|
* Fetches are broken out into A and AAAA types. In some cases,
|
||||||
* however, it makes more sense to test for a particular class of fetches,
|
* however, it makes more sense to test for a particular class of fetches,
|
||||||
* like V4 or V6 above.
|
* like V4 or V6 above.
|
||||||
* Note: since we have removed the support of A6 in adb, FETCH_A and FETCH_AAAA
|
|
||||||
* are now equal to FETCH_V4 and FETCH_V6, respectively.
|
|
||||||
*/
|
*/
|
||||||
#define NAME_FETCH_A(n) ((n)->fetch_a != NULL)
|
#define NAME_FETCH_A(n) ((n)->fetch_a != NULL)
|
||||||
#define NAME_FETCH_AAAA(n) ((n)->fetch_aaaa != NULL)
|
#define NAME_FETCH_AAAA(n) ((n)->fetch_aaaa != NULL)
|
||||||
#define NAME_FETCH_V4(n) (NAME_FETCH_A(n))
|
#define NAME_FETCH(n) (NAME_FETCH_A(n) || NAME_FETCH_AAAA(n))
|
||||||
#define NAME_FETCH_V6(n) (NAME_FETCH_AAAA(n))
|
|
||||||
#define NAME_FETCH(n) (NAME_FETCH_V4(n) || NAME_FETCH_V6(n))
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find options and tests to see if there are addresses on the list.
|
* Find options and tests to see if there are addresses on the list.
|
||||||
@@ -898,18 +894,18 @@ static isc_result_t
|
|||||||
import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset,
|
import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset,
|
||||||
isc_stdtime_t now) {
|
isc_stdtime_t now) {
|
||||||
isc_result_t result;
|
isc_result_t result;
|
||||||
dns_adb_t *adb;
|
dns_adb_t *adb = NULL;
|
||||||
dns_adbnamehook_t *nh;
|
dns_adbnamehook_t *nh = NULL;
|
||||||
dns_adbnamehook_t *anh;
|
dns_adbnamehook_t *anh = NULL;
|
||||||
dns_rdata_t rdata = DNS_RDATA_INIT;
|
dns_rdata_t rdata = DNS_RDATA_INIT;
|
||||||
struct in_addr ina;
|
struct in_addr ina;
|
||||||
struct in6_addr in6a;
|
struct in6_addr in6a;
|
||||||
isc_sockaddr_t sockaddr;
|
isc_sockaddr_t sockaddr;
|
||||||
dns_adbentry_t *foundentry; /* NO CLEAN UP! */
|
dns_adbentry_t *foundentry = NULL; /* NO CLEAN UP! */
|
||||||
int addr_bucket;
|
int addr_bucket;
|
||||||
bool new_addresses_added;
|
bool new_addresses_added;
|
||||||
dns_rdatatype_t rdtype;
|
dns_rdatatype_t rdtype;
|
||||||
dns_adbnamehooklist_t *hookhead;
|
dns_adbnamehooklist_t *hookhead = NULL;
|
||||||
|
|
||||||
INSIST(DNS_ADBNAME_VALID(adbname));
|
INSIST(DNS_ADBNAME_VALID(adbname));
|
||||||
adb = adbname->adb;
|
adb = adbname->adb;
|
||||||
@@ -921,7 +917,6 @@ import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset,
|
|||||||
addr_bucket = DNS_ADB_INVALIDBUCKET;
|
addr_bucket = DNS_ADB_INVALIDBUCKET;
|
||||||
new_addresses_added = false;
|
new_addresses_added = false;
|
||||||
|
|
||||||
nh = NULL;
|
|
||||||
result = dns_rdataset_first(rdataset);
|
result = dns_rdataset_first(rdataset);
|
||||||
while (result == ISC_R_SUCCESS) {
|
while (result == ISC_R_SUCCESS) {
|
||||||
dns_rdata_reset(&rdata);
|
dns_rdata_reset(&rdata);
|
||||||
@@ -978,10 +973,6 @@ import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset,
|
|||||||
result = dns_rdataset_next(rdataset);
|
result = dns_rdataset_next(rdataset);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nh != NULL) {
|
|
||||||
free_adbnamehook(adb, &nh);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (addr_bucket != DNS_ADB_INVALIDBUCKET) {
|
if (addr_bucket != DNS_ADB_INVALIDBUCKET) {
|
||||||
UNLOCK(&adb->entrylocks[addr_bucket]);
|
UNLOCK(&adb->entrylocks[addr_bucket]);
|
||||||
}
|
}
|
||||||
@@ -1103,7 +1094,7 @@ check_expire_namehooks(dns_adbname_t *name, isc_stdtime_t now) {
|
|||||||
/*
|
/*
|
||||||
* Check to see if we need to remove the v4 addresses
|
* Check to see if we need to remove the v4 addresses
|
||||||
*/
|
*/
|
||||||
if (!NAME_FETCH_V4(name) && EXPIRE_OK(name->expire_v4, now)) {
|
if (!NAME_FETCH_A(name) && EXPIRE_OK(name->expire_v4, now)) {
|
||||||
if (NAME_HAS_V4(name)) {
|
if (NAME_HAS_V4(name)) {
|
||||||
DP(DEF_LEVEL, "expiring v4 for name %p", name);
|
DP(DEF_LEVEL, "expiring v4 for name %p", name);
|
||||||
result4 = clean_namehooks(adb, &name->v4);
|
result4 = clean_namehooks(adb, &name->v4);
|
||||||
@@ -1116,7 +1107,7 @@ check_expire_namehooks(dns_adbname_t *name, isc_stdtime_t now) {
|
|||||||
/*
|
/*
|
||||||
* Check to see if we need to remove the v6 addresses
|
* Check to see if we need to remove the v6 addresses
|
||||||
*/
|
*/
|
||||||
if (!NAME_FETCH_V6(name) && EXPIRE_OK(name->expire_v6, now)) {
|
if (!NAME_FETCH_AAAA(name) && EXPIRE_OK(name->expire_v6, now)) {
|
||||||
if (NAME_HAS_V6(name)) {
|
if (NAME_HAS_V6(name)) {
|
||||||
DP(DEF_LEVEL, "expiring v6 for name %p", name);
|
DP(DEF_LEVEL, "expiring v6 for name %p", name);
|
||||||
result6 = clean_namehooks(adb, &name->v6);
|
result6 = clean_namehooks(adb, &name->v6);
|
||||||
@@ -2867,14 +2858,17 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
|
|||||||
isc_stdtime_t now, dns_name_t *target, in_port_t port,
|
isc_stdtime_t now, dns_name_t *target, in_port_t port,
|
||||||
unsigned int depth, isc_counter_t *qc,
|
unsigned int depth, isc_counter_t *qc,
|
||||||
dns_adbfind_t **findp) {
|
dns_adbfind_t **findp) {
|
||||||
dns_adbfind_t *find;
|
dns_adbfind_t *find = NULL;
|
||||||
dns_adbname_t *adbname;
|
dns_adbname_t *adbname = NULL;
|
||||||
int bucket;
|
int bucket;
|
||||||
bool want_event, start_at_zone, alias, have_address;
|
bool want_event = true;
|
||||||
|
bool start_at_zone = false;
|
||||||
|
bool alias = false;
|
||||||
|
bool have_address = false;
|
||||||
isc_result_t result;
|
isc_result_t result;
|
||||||
unsigned int wanted_addresses;
|
unsigned int wanted_addresses = (options & DNS_ADBFIND_ADDRESSMASK);
|
||||||
unsigned int wanted_fetches;
|
unsigned int wanted_fetches = 0;
|
||||||
unsigned int query_pending;
|
unsigned int query_pending = 0;
|
||||||
char namebuf[DNS_NAME_FORMATSIZE];
|
char namebuf[DNS_NAME_FORMATSIZE];
|
||||||
|
|
||||||
REQUIRE(DNS_ADB_VALID(adb));
|
REQUIRE(DNS_ADB_VALID(adb));
|
||||||
@@ -2890,12 +2884,6 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
|
|||||||
|
|
||||||
result = ISC_R_UNEXPECTED;
|
result = ISC_R_UNEXPECTED;
|
||||||
POST(result);
|
POST(result);
|
||||||
wanted_addresses = (options & DNS_ADBFIND_ADDRESSMASK);
|
|
||||||
wanted_fetches = 0;
|
|
||||||
query_pending = 0;
|
|
||||||
want_event = false;
|
|
||||||
start_at_zone = false;
|
|
||||||
alias = false;
|
|
||||||
|
|
||||||
if (now == 0) {
|
if (now == 0) {
|
||||||
isc_stdtime_get(&now);
|
isc_stdtime_get(&now);
|
||||||
@@ -3043,7 +3031,7 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
|
|||||||
goto v6;
|
goto v6;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!NAME_FETCH_V4(adbname)) {
|
if (!NAME_FETCH_A(adbname)) {
|
||||||
wanted_fetches |= DNS_ADBFIND_INET;
|
wanted_fetches |= DNS_ADBFIND_INET;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3079,7 +3067,7 @@ v6:
|
|||||||
goto fetch;
|
goto fetch;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!NAME_FETCH_V6(adbname)) {
|
if (!NAME_FETCH_AAAA(adbname)) {
|
||||||
wanted_fetches |= DNS_ADBFIND_INET6;
|
wanted_fetches |= DNS_ADBFIND_INET6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3140,10 +3128,10 @@ fetch:
|
|||||||
copy_namehook_lists(adb, find, qname, qtype, adbname, now);
|
copy_namehook_lists(adb, find, qname, qtype, adbname, now);
|
||||||
|
|
||||||
post_copy:
|
post_copy:
|
||||||
if (NAME_FETCH_V4(adbname)) {
|
if (NAME_FETCH_A(adbname)) {
|
||||||
query_pending |= DNS_ADBFIND_INET;
|
query_pending |= DNS_ADBFIND_INET;
|
||||||
}
|
}
|
||||||
if (NAME_FETCH_V6(adbname)) {
|
if (NAME_FETCH_AAAA(adbname)) {
|
||||||
query_pending |= DNS_ADBFIND_INET6;
|
query_pending |= DNS_ADBFIND_INET6;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3151,7 +3139,6 @@ post_copy:
|
|||||||
* Attach to the name's query list if there are queries
|
* Attach to the name's query list if there are queries
|
||||||
* already running, and we have been asked to.
|
* already running, and we have been asked to.
|
||||||
*/
|
*/
|
||||||
want_event = true;
|
|
||||||
if (!FIND_WANTEVENT(find)) {
|
if (!FIND_WANTEVENT(find)) {
|
||||||
want_event = false;
|
want_event = false;
|
||||||
}
|
}
|
||||||
@@ -3165,16 +3152,15 @@ post_copy:
|
|||||||
want_event = false;
|
want_event = false;
|
||||||
}
|
}
|
||||||
if (want_event) {
|
if (want_event) {
|
||||||
|
bool empty;
|
||||||
find->adbname = adbname;
|
find->adbname = adbname;
|
||||||
find->name_bucket = bucket;
|
find->name_bucket = bucket;
|
||||||
bool empty = ISC_LIST_EMPTY(adbname->finds);
|
empty = ISC_LIST_EMPTY(adbname->finds);
|
||||||
ISC_LIST_APPEND(adbname->finds, find, plink);
|
ISC_LIST_APPEND(adbname->finds, find, plink);
|
||||||
find->query_pending = (query_pending & wanted_addresses);
|
find->query_pending = (query_pending & wanted_addresses);
|
||||||
find->flags &= ~DNS_ADBFIND_ADDRESSMASK;
|
find->flags &= ~DNS_ADBFIND_ADDRESSMASK;
|
||||||
find->flags |= (find->query_pending & DNS_ADBFIND_ADDRESSMASK);
|
find->flags |= (find->query_pending & DNS_ADBFIND_ADDRESSMASK);
|
||||||
DP(DEF_LEVEL,
|
DP(DEF_LEVEL, "createfind: attaching find %p to adbname %p %d",
|
||||||
"createfind: attaching find %p to adbname "
|
|
||||||
"%p %d",
|
|
||||||
find, adbname, empty);
|
find, adbname, empty);
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
@@ -3207,22 +3193,20 @@ post_copy:
|
|||||||
|
|
||||||
out:
|
out:
|
||||||
if (find != NULL) {
|
if (find != NULL) {
|
||||||
*findp = find;
|
|
||||||
|
|
||||||
if (want_event) {
|
if (want_event) {
|
||||||
isc_task_t *taskp;
|
isc_task_t *taskp = NULL;
|
||||||
|
|
||||||
INSIST((find->flags & DNS_ADBFIND_ADDRESSMASK) != 0);
|
INSIST((find->flags & DNS_ADBFIND_ADDRESSMASK) != 0);
|
||||||
taskp = NULL;
|
|
||||||
isc_task_attach(task, &taskp);
|
isc_task_attach(task, &taskp);
|
||||||
find->event.ev_sender = taskp;
|
find->event.ev_sender = taskp;
|
||||||
find->event.ev_action = action;
|
find->event.ev_action = action;
|
||||||
find->event.ev_arg = arg;
|
find->event.ev_arg = arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*findp = find;
|
||||||
}
|
}
|
||||||
|
|
||||||
UNLOCK(&adb->namelocks[bucket]);
|
UNLOCK(&adb->namelocks[bucket]);
|
||||||
|
|
||||||
return (result);
|
return (result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4011,8 +3995,8 @@ fetch_name(dns_adbname_t *adbname, bool start_at_zone, unsigned int depth,
|
|||||||
adb = adbname->adb;
|
adb = adbname->adb;
|
||||||
INSIST(DNS_ADB_VALID(adb));
|
INSIST(DNS_ADB_VALID(adb));
|
||||||
|
|
||||||
INSIST((type == dns_rdatatype_a && !NAME_FETCH_V4(adbname)) ||
|
INSIST((type == dns_rdatatype_a && !NAME_FETCH_A(adbname)) ||
|
||||||
(type == dns_rdatatype_aaaa && !NAME_FETCH_V6(adbname)));
|
(type == dns_rdatatype_aaaa && !NAME_FETCH_AAAA(adbname)));
|
||||||
|
|
||||||
adbname->fetch_err = FIND_ERR_NOTFOUND;
|
adbname->fetch_err = FIND_ERR_NOTFOUND;
|
||||||
|
|
||||||
|
@@ -408,8 +408,8 @@ struct fetchctx {
|
|||||||
/*%
|
/*%
|
||||||
* Fetch-local statistics for detailed logging.
|
* Fetch-local statistics for detailed logging.
|
||||||
*/
|
*/
|
||||||
isc_result_t result; /*%< fetch result */
|
isc_result_t result; /*%< fetch result */
|
||||||
isc_result_t vresult; /*%< validation result */
|
isc_result_t vresult; /*%< validation result */
|
||||||
int exitline;
|
int exitline;
|
||||||
isc_time_t start;
|
isc_time_t start;
|
||||||
uint64_t duration;
|
uint64_t duration;
|
||||||
@@ -1786,7 +1786,7 @@ resquery_senddone(isc_result_t eresult, isc_region_t *region, void *arg) {
|
|||||||
case ISC_R_NOPERM:
|
case ISC_R_NOPERM:
|
||||||
case ISC_R_ADDRNOTAVAIL:
|
case ISC_R_ADDRNOTAVAIL:
|
||||||
case ISC_R_CONNREFUSED:
|
case ISC_R_CONNREFUSED:
|
||||||
/* No route to remote. */
|
/* No route to remote. */
|
||||||
FCTXTRACE3("query canceled in resquery_senddone(): "
|
FCTXTRACE3("query canceled in resquery_senddone(): "
|
||||||
"no route to host; no response",
|
"no route to host; no response",
|
||||||
eresult);
|
eresult);
|
||||||
@@ -3209,20 +3209,51 @@ sort_finds(dns_adbfindlist_t *findlist, unsigned int bias) {
|
|||||||
*findlist = sorted;
|
*findlist = sorted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return true iff the ADB find has a pending fetch for 'type'. This is
|
||||||
|
* used to find out whether we're in a loop, where a fetch is waiting for a
|
||||||
|
* find which is waiting for that same fetch.
|
||||||
|
*
|
||||||
|
* Note: This could be done with either an equivalence check (e.g.,
|
||||||
|
* query_pending == DNS_ADBFIND_INET) or with a bit check, as below. If
|
||||||
|
* we checked for equivalence, that would mean we could only detect a loop
|
||||||
|
* when there is exactly one pending fetch, and we're it. If there were
|
||||||
|
* pending fetches for *both* address families, then a loop would be
|
||||||
|
* undetected.
|
||||||
|
*
|
||||||
|
* However, using a bit check means that in theory, an ADB find might be
|
||||||
|
* aborted that could have succeeded, if the other fetch had returned an
|
||||||
|
* answer.
|
||||||
|
*
|
||||||
|
* Since there's a good chance the server is broken and won't answer either
|
||||||
|
* query, and since an ADB find with two pending fetches is a very rare
|
||||||
|
* occurrance anyway, we regard this theoretical SERVFAIL as the lesser
|
||||||
|
* evil.
|
||||||
|
*/
|
||||||
|
static inline bool
|
||||||
|
waiting_for(dns_adbfind_t *find, dns_rdatatype_t type) {
|
||||||
|
switch (type) {
|
||||||
|
case dns_rdatatype_a:
|
||||||
|
return ((find->query_pending & DNS_ADBFIND_INET) != 0);
|
||||||
|
case dns_rdatatype_aaaa:
|
||||||
|
return ((find->query_pending & DNS_ADBFIND_INET6) != 0);
|
||||||
|
default:
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
findname(fetchctx_t *fctx, const dns_name_t *name, in_port_t port,
|
findname(fetchctx_t *fctx, const dns_name_t *name, in_port_t port,
|
||||||
unsigned int options, unsigned int flags, isc_stdtime_t now,
|
unsigned int options, unsigned int flags, isc_stdtime_t now,
|
||||||
bool *overquota, bool *need_alternate, unsigned int *no_addresses) {
|
bool *overquota, bool *need_alternate, unsigned int *no_addresses) {
|
||||||
dns_adbaddrinfo_t *ai;
|
dns_adbaddrinfo_t *ai = NULL;
|
||||||
dns_adbfind_t *find;
|
dns_adbfind_t *find = NULL;
|
||||||
dns_resolver_t *res;
|
dns_resolver_t *res = fctx->res;
|
||||||
bool unshared;
|
bool unshared = ((fctx->options & DNS_FETCHOPT_UNSHARED) != 0);
|
||||||
isc_result_t result;
|
isc_result_t result;
|
||||||
fetchctx_t *ev_fctx = NULL;
|
|
||||||
|
|
||||||
FCTXTRACE("FINDNAME");
|
FCTXTRACE("FINDNAME");
|
||||||
res = fctx->res;
|
|
||||||
unshared = ((fctx->options & DNS_FETCHOPT_UNSHARED) != 0);
|
|
||||||
/*
|
/*
|
||||||
* If this name is a subdomain of the query domain, tell
|
* If this name is a subdomain of the query domain, tell
|
||||||
* the ADB to start looking using zone/hint data. This keeps us
|
* the ADB to start looking using zone/hint data. This keeps us
|
||||||
@@ -3239,11 +3270,10 @@ findname(fetchctx_t *fctx, const dns_name_t *name, in_port_t port,
|
|||||||
/*
|
/*
|
||||||
* See what we know about this address.
|
* See what we know about this address.
|
||||||
*/
|
*/
|
||||||
find = NULL;
|
fctx_attach(fctx, &(fetchctx_t *){ NULL });
|
||||||
fctx_attach(fctx, &ev_fctx);
|
|
||||||
result = dns_adb_createfind(
|
result = dns_adb_createfind(
|
||||||
fctx->adb, res->buckets[fctx->bucketnum].task, fctx_finddone,
|
fctx->adb, res->buckets[fctx->bucketnum].task, fctx_finddone,
|
||||||
ev_fctx, name, fctx->name, fctx->type, options, now, NULL,
|
fctx, name, fctx->name, fctx->type, options, now, NULL,
|
||||||
res->view->dstport, fctx->depth + 1, fctx->qc, &find);
|
res->view->dstport, fctx->depth + 1, fctx->qc, &find);
|
||||||
|
|
||||||
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
|
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
|
||||||
@@ -3267,7 +3297,7 @@ findname(fetchctx_t *fctx, const dns_name_t *name, in_port_t port,
|
|||||||
"is a CNAME, while resolving '%s'",
|
"is a CNAME, while resolving '%s'",
|
||||||
namebuf, fctx->info);
|
namebuf, fctx->info);
|
||||||
}
|
}
|
||||||
fctx_detach(&ev_fctx);
|
fctx_detach(&fctx);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3298,12 +3328,33 @@ findname(fetchctx_t *fctx, const dns_name_t *name, in_port_t port,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* We don't know any of the addresses for this name.
|
* We don't know any of the addresses for this name.
|
||||||
|
*
|
||||||
|
* The find may be waiting on a resolver fetch for a server
|
||||||
|
* address. We need to make sure it isn't waiting on *this*
|
||||||
|
* fetch, because if it is, we won't be answering it and it
|
||||||
|
* won't be answering us.
|
||||||
|
*/
|
||||||
|
if (waiting_for(find, fctx->type) && dns_name_equal(name, fctx->name)) {
|
||||||
|
fctx->adberr++;
|
||||||
|
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
|
||||||
|
DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO,
|
||||||
|
"loop detected resolving '%s'", fctx->info);
|
||||||
|
|
||||||
|
if ((find->options & DNS_ADBFIND_WANTEVENT) != 0) {
|
||||||
|
atomic_fetch_add_relaxed(&fctx->pending, 1);
|
||||||
|
dns_adb_cancelfind(find);
|
||||||
|
} else {
|
||||||
|
dns_adb_destroyfind(&find);
|
||||||
|
fctx_detach(&fctx);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We may be waiting for another fetch to complete, and
|
||||||
|
* we'll get an event later when the find has what it needs.
|
||||||
*/
|
*/
|
||||||
if ((find->options & DNS_ADBFIND_WANTEVENT) != 0) {
|
if ((find->options & DNS_ADBFIND_WANTEVENT) != 0) {
|
||||||
/*
|
|
||||||
* We're looking for them and will get an
|
|
||||||
* event about it later.
|
|
||||||
*/
|
|
||||||
atomic_fetch_add_relaxed(&fctx->pending, 1);
|
atomic_fetch_add_relaxed(&fctx->pending, 1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -3323,17 +3374,18 @@ findname(fetchctx_t *fctx, const dns_name_t *name, in_port_t port,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* No addresses and no pending events: the find failed.
|
||||||
|
*/
|
||||||
if ((find->options & DNS_ADBFIND_OVERQUOTA) != 0) {
|
if ((find->options & DNS_ADBFIND_OVERQUOTA) != 0) {
|
||||||
if (overquota != NULL) {
|
if (overquota != NULL) {
|
||||||
*overquota = true;
|
*overquota = true;
|
||||||
}
|
}
|
||||||
fctx->quotacount++; /* quota exceeded */
|
fctx->quotacount++; /* quota exceeded */
|
||||||
} else if ((find->options & DNS_ADBFIND_LAMEPRUNED) != 0) {
|
} else if ((find->options & DNS_ADBFIND_LAMEPRUNED) != 0) {
|
||||||
fctx->lamecount++; /* cached lame server
|
fctx->lamecount++; /* cached lame server */
|
||||||
*/
|
|
||||||
} else {
|
} else {
|
||||||
fctx->adberr++; /* unreachable server,
|
fctx->adberr++; /* unreachable server, etc. */
|
||||||
etc. */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -3347,7 +3399,7 @@ findname(fetchctx_t *fctx, const dns_name_t *name, in_port_t port,
|
|||||||
*need_alternate = true;
|
*need_alternate = true;
|
||||||
}
|
}
|
||||||
dns_adb_destroyfind(&find);
|
dns_adb_destroyfind(&find);
|
||||||
fctx_detach(&ev_fctx);
|
fctx_detach(&fctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
Reference in New Issue
Block a user