If the auth responds *very* slowly and the records expire in between,
the capping of TTLs is not enforced for lack of data.
This does not happen on regular resolve as then then the child
records are used immediately if not expired and thus valid, or the
records *are* expired, and in that case not used. So this case can
only happen if almost expired records are used to refresh the
authoritative NS records.
Signed-off-by: Otto Moerbeek <otto.moerbeek@open-xchange.com>
*age = static_cast<uint32_t>(now - iter->d_creation);
// we know ttl is > 0
auto ttl = static_cast<uint32_t>(iter->d_ttd - now);
- if (s_refresh_ttlperc > 0 && !iter->d_submitted && taskQTypeIsSupported(qtype)) {
+ // Be wary of refreshing NS records, it could lead to ghosts if the record cache entry expires between
+ // sending out the request and the reply coming back in, as then the TTL capping does not work.
+ if (s_refresh_ttlperc > 0 && !iter->d_submitted && taskQTypeIsSupported(qtype) && qtype != QType::NS) {
const dnsheader_aligned header(iter->d_packet.data());
const auto* headerPtr = header.get();
if (headerPtr->rcode == RCode::NoError) {
if (refresh) {
return -1;
}
- if (!entry->d_submitted) {
+ // We do not want to refresh auth NS entries, as it could lead to ghost domains if an entry
+ // expires between submit and response coming in, as the TTL capping then does not work for
+ // lack of current TTL info.
+ if (!entry->d_submitted && (qtype != QType::NS || !entry->d_auth)) {
pushRefreshTask(qname, qtype, entry->d_ttd, entry->d_netmask);
entry->d_submitted = true;
}