Interrupt query processing when query_recurse() attempts to ask the same
name servers for the same QNAME/QTYPE tuple for two times in a row as
this indicates that query processing may be stuck for an indeterminate
period of time, e.g. due to interactions between features able to
restart query_lookup().
check_stale_header() fails to update the pointer to the previous header
while processing rdataset headers eligible for serve-stale, thus
enabling rdataset headers to be leaked (i.e. disassociated from a node
and left on the relevant TTL heap) while iterating through a node. This
can lead to several different assertion failures. Add the missing
pointer update.
A typo in commit d39ab7440e introduced a bug in zone database reference
counting which leads to a crash if dumping one version of a slave zone
is not finished by the time transferring a newer version from a master
completes. Correct the typo to fix reference counting, thus preventing
crashes.
(cherry picked from commit fbd5658db7)
(cherry picked from commit f2838e68e8)
Instead of checking current dnstap output file size and potentially
synchronously calling dns_dt_reopen() upon every call to dns_dt_send():
- call dns_dt_reopen() asynchronously by queuing an event to the task
specified at dnstap environment creation time,
- ensure no roll event is outstanding before checking dnstap output
file size and potentially queuing another roll event.
This causes dnstap output files to exceed their configured size limits,
but prevents any two threads from performing the roll simultaneously
(which causes crashes).
Instead of relying on the caller to set up task-exclusive mode, make
dns_dt_reopen() enforce task-exclusive mode itself, using the task
specified at dnstap environment creation time.
Implement a new variant of dns_dt_create() to enable a dnstap
environment structure to hold the task in the context of which
dns_dt_reopen() will be executed.
Remove a block of code which dates back to commit 8a2ab2b920, when
dns_zone_asyncload() did not yet check DNS_ZONEFLG_LOADPENDING.
Currently, no race in accessing DNS_ZONEFLG_LOADPENDING is possible any
more, because:
- dns_zone_asyncload() is still the only function which may queue
zone_asyncload(),
- dns_zone_asyncload() accesses DNS_ZONEFLG_LOADPENDING under a lock
(and potentially queues an event under the same lock),
- DNS_ZONEFLG_LOADPENDING is not cleared until the load actually
completes.
Thus, the rechecking code can be safely removed from zone_asyncload().
Note that this also brings zone_asyncload() to a state in which the
completion callback is always invoked. This is required to prevent
leaking memory in case something goes wrong in zone_asyncload() and a
zone table the zone belongs to is indefinitely left with a positive
reference count.
Code handling cancellation of asynchronous zone load events was likely
copied over from other functions when asynchronous zone loading was
first implemented in commit 8a2ab2b920. However, unlike those other
functions, asynchronous zone loading events currently have no way of
getting canceled once they get posted, which means the aforementioned
code is effectively dead. Remove it to prevent confusion.
zone_load() is not always synchronous, it may only initiate an
asynchronous load and return DNS_R_CONTINUE, which means zone loading
has not yet been completed. In such a case, zone_asyncload() must not
clear DNS_ZONEFLG_LOADPENDING immediately and leave that up to
zone_postload().
While this is not an issue in named, which only calls
dns_zone_asyncload() from task-exclusive mode, this function is exported
by libdns and thus may in theory be concurrently called for the same
zone by multiple threads. It also does not hurt to be consistent
locking-wise with other DNS_ZONEFLG_LOADPENDING accesses.