From: Marek VavruĊĦa Date: Tue, 6 Oct 2015 17:56:49 +0000 (+0200) Subject: lib/cache: check entry rank and TTD before overwriting it X-Git-Tag: v1.0.0-beta1~13 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a56eed2b2edfd22072d9b974b2829de2c88d34ca;p=thirdparty%2Fknot-resolver.git lib/cache: check entry rank and TTD before overwriting it --- diff --git a/lib/cache.c b/lib/cache.c index e0cffcad6..be4821e43 100644 --- a/lib/cache.c +++ b/lib/cache.c @@ -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, ×tamp) == 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;