summaryrefslogtreecommitdiff
path: root/util/data
diff options
context:
space:
mode:
Diffstat (limited to 'util/data')
-rw-r--r--util/data/msgparse.h2
-rw-r--r--util/data/msgreply.c47
-rw-r--r--util/data/msgreply.h39
-rw-r--r--util/data/packed_rrset.h3
4 files changed, 82 insertions, 9 deletions
diff --git a/util/data/msgparse.h b/util/data/msgparse.h
index aebd48efac34..62f0d5aacd80 100644
--- a/util/data/msgparse.h
+++ b/util/data/msgparse.h
@@ -89,6 +89,8 @@ extern time_t MIN_NEG_TTL;
extern int SERVE_EXPIRED;
/** Time to serve records after expiration */
extern time_t SERVE_EXPIRED_TTL;
+/** Reset serve expired TTL after failed update attempt */
+extern time_t SERVE_EXPIRED_TTL_RESET;
/** TTL to use for expired records */
extern time_t SERVE_EXPIRED_REPLY_TTL;
/** Negative cache time (for entries without any RRs.) */
diff --git a/util/data/msgreply.c b/util/data/msgreply.c
index c9d7bbf3ad47..78e4fb1c323a 100644
--- a/util/data/msgreply.c
+++ b/util/data/msgreply.c
@@ -67,6 +67,8 @@ time_t MIN_NEG_TTL = 0;
int SERVE_EXPIRED = 0;
/** Time to serve records after expiration */
time_t SERVE_EXPIRED_TTL = 0;
+/** Reset serve expired TTL after failed update attempt */
+time_t SERVE_EXPIRED_TTL_RESET = 0;
/** TTL to use for expired records */
time_t SERVE_EXPIRED_REPLY_TTL = 30;
/** If we serve the original TTL or decrementing TTLs */
@@ -95,8 +97,9 @@ parse_create_qinfo(sldns_buffer* pkt, struct msg_parse* msg,
/** constructor for replyinfo */
struct reply_info*
construct_reply_info_base(struct regional* region, uint16_t flags, size_t qd,
- time_t ttl, time_t prettl, time_t expttl, size_t an, size_t ns,
- size_t ar, size_t total, enum sec_status sec, sldns_ede_code reason_bogus)
+ time_t ttl, time_t prettl, time_t expttl, time_t norecttl, size_t an,
+ size_t ns, size_t ar, size_t total, enum sec_status sec,
+ sldns_ede_code reason_bogus)
{
struct reply_info* rep;
/* rrset_count-1 because the first ref is part of the struct. */
@@ -114,6 +117,7 @@ construct_reply_info_base(struct regional* region, uint16_t flags, size_t qd,
rep->ttl = ttl;
rep->prefetch_ttl = prettl;
rep->serve_expired_ttl = expttl;
+ rep->serve_expired_norec_ttl = norecttl;
rep->an_numrrsets = an;
rep->ns_numrrsets = ns;
rep->ar_numrrsets = ar;
@@ -139,8 +143,8 @@ static int
parse_create_repinfo(struct msg_parse* msg, struct reply_info** rep,
struct regional* region)
{
- *rep = construct_reply_info_base(region, msg->flags, msg->qdcount, 0,
- 0, 0, msg->an_rrsets, msg->ns_rrsets, msg->ar_rrsets,
+ *rep = construct_reply_info_base(region, msg->flags, msg->qdcount, 0,
+ 0, 0, 0, msg->an_rrsets, msg->ns_rrsets, msg->ar_rrsets,
msg->rrset_count, sec_status_unchecked, LDNS_EDE_NONE);
if(!*rep)
return 0;
@@ -171,6 +175,32 @@ reply_info_alloc_rrset_keys(struct reply_info* rep, struct alloc_cache* alloc,
return 1;
}
+int
+reply_info_can_answer_expired(struct reply_info* rep, time_t timenow)
+{
+ log_assert(rep->ttl < timenow);
+ /* Really expired */
+ if(SERVE_EXPIRED_TTL && rep->serve_expired_ttl < timenow) return 0;
+ /* Ignore expired failure answers */
+ if(FLAGS_GET_RCODE(rep->flags) != LDNS_RCODE_NOERROR &&
+ FLAGS_GET_RCODE(rep->flags) != LDNS_RCODE_NXDOMAIN &&
+ FLAGS_GET_RCODE(rep->flags) != LDNS_RCODE_YXDOMAIN) return 0;
+ return 1;
+}
+
+int reply_info_could_use_expired(struct reply_info* rep, time_t timenow)
+{
+ log_assert(rep->ttl < timenow);
+ /* Really expired */
+ if(SERVE_EXPIRED_TTL && rep->serve_expired_ttl < timenow &&
+ !SERVE_EXPIRED_TTL_RESET) return 0;
+ /* Ignore expired failure answers */
+ if(FLAGS_GET_RCODE(rep->flags) != LDNS_RCODE_NOERROR &&
+ FLAGS_GET_RCODE(rep->flags) != LDNS_RCODE_NXDOMAIN &&
+ FLAGS_GET_RCODE(rep->flags) != LDNS_RCODE_YXDOMAIN) return 0;
+ return 1;
+}
+
struct reply_info *
make_new_reply_info(const struct reply_info* rep, struct regional* region,
size_t an_numrrsets, size_t copy_rrsets)
@@ -185,7 +215,8 @@ make_new_reply_info(const struct reply_info* rep, struct regional* region,
* so the total number of RRsets is an_numrrsets. */
new_rep = construct_reply_info_base(region, rep->flags,
rep->qdcount, rep->ttl, rep->prefetch_ttl,
- rep->serve_expired_ttl, an_numrrsets, 0, 0, an_numrrsets,
+ rep->serve_expired_ttl, rep->serve_expired_norec_ttl,
+ an_numrrsets, 0, 0, an_numrrsets,
sec_status_insecure, LDNS_EDE_NONE);
if(!new_rep)
return NULL;
@@ -486,6 +517,8 @@ parse_copy_decompress(sldns_buffer* pkt, struct msg_parse* msg,
}
rep->prefetch_ttl = PREFETCH_TTL_CALC(rep->ttl);
rep->serve_expired_ttl = rep->ttl + SERVE_EXPIRED_TTL;
+ /* rep->serve_expired_norec_ttl should stay at 0 */
+ log_assert(rep->serve_expired_norec_ttl == 0);
return 1;
}
@@ -568,6 +601,9 @@ reply_info_set_ttls(struct reply_info* rep, time_t timenow)
rep->ttl += timenow;
rep->prefetch_ttl += timenow;
rep->serve_expired_ttl += timenow;
+ /* Don't set rep->serve_expired_norec_ttl; this should only be set
+ * on cached records when encountering an error */
+ log_assert(rep->serve_expired_norec_ttl == 0);
for(i=0; i<rep->rrset_count; i++) {
struct packed_rrset_data* data = (struct packed_rrset_data*)
rep->ref[i].key->entry.data;
@@ -763,6 +799,7 @@ reply_info_copy(struct reply_info* rep, struct alloc_cache* alloc,
struct reply_info* cp;
cp = construct_reply_info_base(region, rep->flags, rep->qdcount,
rep->ttl, rep->prefetch_ttl, rep->serve_expired_ttl,
+ rep->serve_expired_norec_ttl,
rep->an_numrrsets, rep->ns_numrrsets, rep->ar_numrrsets,
rep->rrset_count, rep->security, rep->reason_bogus);
if(!cp)
diff --git a/util/data/msgreply.h b/util/data/msgreply.h
index 4b93b12c8f33..d1c2bfa4bdfc 100644
--- a/util/data/msgreply.h
+++ b/util/data/msgreply.h
@@ -145,7 +145,7 @@ struct reply_info {
/** 32 bit padding to pad struct member alignment to 64 bits. */
uint32_t padding;
- /**
+ /**
* TTL of the entire reply (for negative caching).
* only for use when there are 0 RRsets in this message.
* if there are RRsets, check those instead.
@@ -158,13 +158,25 @@ struct reply_info {
*/
time_t prefetch_ttl;
- /**
+ /**
* Reply TTL extended with serve expired TTL, to limit time to serve
* expired message.
*/
time_t serve_expired_ttl;
/**
+ * TTL for an expired entry to be used without attempting recursion
+ * since a previous recursion attempt failed to update the message.
+ * This is just an efficiency timer when serve-expired-client-timeout
+ * is configured. It will make Unbound immediately reply with the
+ * expired entry instead of trying resolution first.
+ * It is set on cached entries by modules that identified problems
+ * while resolving, e.g., failed upstreams from Iterator, or failed
+ * validation from Validator.
+ */
+ time_t serve_expired_norec_ttl;
+
+ /**
* The security status from DNSSEC validation of this message.
*/
enum sec_status security;
@@ -244,6 +256,7 @@ struct msgreply_entry {
* @param ttl: TTL of replyinfo
* @param prettl: prefetch ttl
* @param expttl: serve expired ttl
+ * @param norecttl: serve expired no recursion ttl
* @param an: an count
* @param ns: ns count
* @param ar: ar count
@@ -255,8 +268,8 @@ struct msgreply_entry {
*/
struct reply_info*
construct_reply_info_base(struct regional* region, uint16_t flags, size_t qd,
- time_t ttl, time_t prettl, time_t expttl, size_t an, size_t ns,
- size_t ar, size_t total, enum sec_status sec,
+ time_t ttl, time_t prettl, time_t expttl, time_t norecttl, size_t an,
+ size_t ns, size_t ar, size_t total, enum sec_status sec,
sldns_ede_code reason_bogus);
/**
@@ -399,6 +412,24 @@ struct reply_info* reply_info_copy(struct reply_info* rep,
int reply_info_alloc_rrset_keys(struct reply_info* rep,
struct alloc_cache* alloc, struct regional* region);
+/**
+ * Check if an *expired* (checked by the caller already) reply info can be used
+ * as an expired answer.
+ * @param rep: expired reply info to check.
+ * @param timenow: the current time.
+ * @return 1 if it can be used as an answer, 0 otherwise.
+ */
+int reply_info_can_answer_expired(struct reply_info* rep, time_t timenow);
+
+/**
+ * Check if an *expired* (checked by the caller already) reply info could be
+ * useful data to stay in the cache.
+ * @param rep: expired reply info to check.
+ * @param timenow: the current time.
+ * @return 1 if it is useful, 0 otherwise.
+ */
+int reply_info_could_use_expired(struct reply_info* rep, time_t timenow);
+
/*
* Create a new reply_info based on 'rep'. The new info is based on
* the passed 'rep', but ignores any rrsets except for the first 'an_numrrsets'
diff --git a/util/data/packed_rrset.h b/util/data/packed_rrset.h
index e1feb22bb7f6..776e8d0923cc 100644
--- a/util/data/packed_rrset.h
+++ b/util/data/packed_rrset.h
@@ -68,6 +68,8 @@ typedef uint64_t rrset_id_type;
* actual network. But messages with these records in it can be stored in
* the cache and retrieved for a reply. */
#define PACKED_RRSET_RPZ 0x8
+/** this rrset is A/AAAA and is an unverified glue record */
+#define PACKED_RRSET_UNVERIFIED_GLUE 0x10
/** number of rrs and rrsets for integer overflow protection. More than
* this is not really possible (64K packet has much less RRs and RRsets) in
@@ -96,6 +98,7 @@ struct packed_rrset_key {
* o PACKED_RRSET_SOA_NEG
* o PACKED_RRSET_FIXEDTTL (not supposed to be cached)
* o PACKED_RRSET_RPZ
+ * o PACKED_RRSET_UNVERIFIED_GLUE
*/
uint32_t flags;
/** the rrset type in network format */