/* We never keep any item longer than 10min in our cache */
#define CACHE_TTL_MAX_USEC (10 * USEC_PER_MINUTE)
+typedef enum DnsCacheItemType DnsCacheItemType;
+typedef struct DnsCacheItem DnsCacheItem;
+
+enum DnsCacheItemType {
+ DNS_CACHE_POSITIVE,
+ DNS_CACHE_NODATA,
+ DNS_CACHE_NXDOMAIN,
+};
+
+struct DnsCacheItem {
+ DnsResourceKey *key;
+ DnsResourceRecord *rr;
+ usec_t until;
+ DnsCacheItemType type;
+ unsigned prioq_idx;
+ LIST_FIELDS(DnsCacheItem, by_key);
+};
+
static void dns_cache_item_free(DnsCacheItem *i) {
if (!i)
return;
break;
if (t <= 0)
- t = now(CLOCK_MONOTONIC);
+ t = now(CLOCK_BOOTTIME);
if (i->until > t)
break;
return 0;
}
-static int init_cache(DnsCache *c) {
+static int dns_cache_init(DnsCache *c) {
int r;
+ assert(c);
+
r = prioq_ensure_allocated(&c->by_expiry, dns_cache_item_prioq_compare_func);
if (r < 0)
return r;
return 0;
}
+ if (rr->key->class == DNS_CLASS_ANY)
+ return 0;
+ if (rr->key->type == DNS_TYPE_ANY)
+ return 0;
+
/* Entry exists already? Update TTL and timestamp */
existing = dns_cache_get(c, rr);
if (existing) {
}
/* Otherwise, add the new RR */
- r = init_cache(c);
+ r = dns_cache_init(c);
if (r < 0)
return r;
dns_cache_remove(c, key);
+ if (key->class == DNS_CLASS_ANY)
+ return 0;
+ if (key->type == DNS_TYPE_ANY)
+ return 0;
+ if (soa_ttl <= 0)
+ return 0;
+
if (!IN_SET(rcode, DNS_RCODE_SUCCESS, DNS_RCODE_NXDOMAIN))
return 0;
- r = init_cache(c);
+ r = dns_cache_init(c);
if (r < 0)
return r;
return 0;
}
-int dns_cache_put(DnsCache *c, DnsQuestion *q, int rcode, DnsAnswer *answer, usec_t timestamp) {
+int dns_cache_put(DnsCache *c, DnsQuestion *q, int rcode, DnsAnswer *answer, unsigned max_rrs, usec_t timestamp) {
unsigned i;
int r;
assert(c);
- assert(answer);
+ assert(q);
/* First, delete all matching old RRs, so that we only keep
* complete by_key in place. */
for (i = 0; i < q->n_keys; i++)
dns_cache_remove(c, q->keys[i]);
+
+ if (!answer)
+ return 0;
+
for (i = 0; i < answer->n_rrs; i++)
dns_cache_remove(c, answer->rrs[i]->key);
dns_cache_make_space(c, answer->n_rrs + q->n_keys);
if (timestamp <= 0)
- timestamp = now(CLOCK_MONOTONIC);
+ timestamp = now(CLOCK_BOOTTIME);
/* Second, add in positive entries for all contained RRs */
- for (i = 0; i < answer->n_rrs; i++) {
+ for (i = 0; i < MIN(max_rrs, answer->n_rrs); i++) {
r = dns_cache_put_positive(c, answer->rrs[i], timestamp);
if (r < 0)
goto fail;
assert(c);
assert(q);
+ assert(rcode);
assert(ret);
if (q->n_keys <= 0) {
for (i = 0; i < q->n_keys; i++) {
DnsCacheItem *j;
+ if (q->keys[i]->type == DNS_TYPE_ANY ||
+ q->keys[i]->class == DNS_CLASS_ANY) {
+ /* If we have ANY lookups we simply refresh */
+ *ret = NULL;
+ *rcode = 0;
+ return 0;
+ }
+
j = hashmap_get(c->by_key, q->keys[i]);
if (!j) {
/* If one question cannot be answered we need to refresh */