]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
lib/cache: check entry rank and TTD before overwriting it
authorMarek Vavruša <marek.vavrusa@nic.cz>
Tue, 6 Oct 2015 17:56:49 +0000 (19:56 +0200)
committerMarek Vavruša <marek.vavrusa@nic.cz>
Tue, 6 Oct 2015 17:58:01 +0000 (19:58 +0200)
lib/cache.c

index e0cffcad669f74e17e9cb9758ba87b5a11b94809..be4821e43673001bfacf43ae4e70c28528570666 100644 (file)
@@ -156,7 +156,7 @@ static size_t cache_key(uint8_t *buf, uint8_t tag, const knot_dname_t *name, uin
        return name_len + KEY_HSIZE;
 }
 
-static struct kr_cache_entry *cache_entry(struct kr_cache_txn *txn, uint8_t tag, const knot_dname_t *name, uint16_t type)
+static struct kr_cache_entry *lookup(struct kr_cache_txn *txn, uint8_t tag, const knot_dname_t *name, uint16_t type)
 {
        uint8_t keybuf[KEY_SIZE];
        size_t key_len = cache_key(keybuf, tag, name, type);
@@ -175,43 +175,50 @@ static struct kr_cache_entry *cache_entry(struct kr_cache_txn *txn, uint8_t tag,
        return (struct kr_cache_entry *)val.data;
 }
 
-int kr_cache_peek(struct kr_cache_txn *txn, uint8_t tag, const knot_dname_t *name, uint16_t type,
-                  struct kr_cache_entry **entry, uint32_t *timestamp)
+static int check_lifetime(struct kr_cache_entry *found, uint32_t *timestamp)
 {
-       if (!txn || !txn->owner || !name || !entry) {
-               return kr_error(EINVAL);
-       }
-
-       struct kr_cache_entry *found = cache_entry(txn, tag, name, type);
-       if (!found) {
-               txn->owner->stats.miss += 1;
-               return kr_error(ENOENT);
-       }       
-
        /* No time constraint */
-       *entry = found;
        if (!timestamp) {
-               txn->owner->stats.hit += 1;
                return kr_ok();
        } else if (*timestamp <= found->timestamp) {
                /* John Connor record cached in the future. */
                *timestamp = 0;
-               txn->owner->stats.hit += 1;
                return kr_ok();
        } else {
                /* Check if the record is still valid. */
                uint32_t drift = *timestamp - found->timestamp;
                if (drift <= found->ttl) {
                        *timestamp = drift;
-                       txn->owner->stats.hit += 1;
                        return kr_ok();
                }
        }
-
-       txn->owner->stats.miss += 1;
        return kr_error(ESTALE);
 }
 
+int kr_cache_peek(struct kr_cache_txn *txn, uint8_t tag, const knot_dname_t *name, uint16_t type,
+                  struct kr_cache_entry **entry, uint32_t *timestamp)
+{
+       if (!txn || !txn->owner || !name || !entry) {
+               return kr_error(EINVAL);
+       }
+
+       struct kr_cache_entry *found = lookup(txn, tag, name, type);
+       if (!found) {
+               txn->owner->stats.miss += 1;
+               return kr_error(ENOENT);
+       }
+
+       /* Check entry lifetime */
+       *entry = found;
+       int ret = check_lifetime(found, timestamp);
+       if (ret == 0) {
+               txn->owner->stats.hit += 1;
+       } else {
+               txn->owner->stats.miss += 1;
+       }
+       return ret;
+}
+
 static void entry_write(struct kr_cache_entry *dst, struct kr_cache_entry *header, namedb_val_t data)
 {
        assert(dst);
@@ -236,6 +243,17 @@ int kr_cache_insert(struct kr_cache_txn *txn, uint8_t tag, const knot_dname_t *n
        namedb_val_t entry = { NULL, sizeof(*header) + data.len };
        const namedb_api_t *db_api = txn_api(txn);
 
+       /* Do not overwrite entries that are higher ranked and not expired. */
+       namedb_val_t old_entry = { NULL, 0 };
+       int ret = txn_api(txn)->find(&txn->t, &key, &old_entry, 0);
+       if (ret == 0) {
+               struct kr_cache_entry *old = old_entry.data;
+               uint32_t timestamp = header->timestamp;
+               if (kr_cache_rank_cmp(old->rank, header->rank) > 0 && check_lifetime(old, &timestamp) == 0) {
+                       return kr_error(EPERM);
+               }
+       }
+
        /* LMDB can do late write and avoid copy */
        txn->owner->stats.insert += 1;
        if (db_api == namedb_lmdb_api()) {
@@ -298,6 +316,9 @@ int kr_cache_peek_rr(struct kr_cache_txn *txn, knot_rrset_t *rr, uint16_t *rank,
        if (ret != 0) {
                return ret;
        }
+       if (rank) {
+               *rank = entry->rank;
+       }
        rr->rrs.rr_count = entry->count;
        rr->rrs.data = entry->data;
        return kr_ok();
@@ -379,6 +400,9 @@ int kr_cache_peek_rrsig(struct kr_cache_txn *txn, knot_rrset_t *rr, uint16_t *ra
        if (ret != 0) {
                return ret;
        }
+       if (rank) {
+               *rank = entry->rank;
+       }
        rr->type = KNOT_RRTYPE_RRSIG;
        rr->rrs.rr_count = entry->count;
        rr->rrs.data = entry->data;