/** Cache version */
-static const uint16_t CACHE_VERSION = 3;
+static const uint16_t CACHE_VERSION = 4;
/** Key size */
#define KEY_HSIZE (sizeof(uint8_t) + sizeof(uint16_t))
#define KEY_SIZE (KEY_HSIZE + KNOT_DNAME_MAXLEN)
return ctx->state;
}
/* Check if the record is OK. */
- int32_t new_ttl = get_new_ttl(eh, qry, k->zname, KNOT_RRTYPE_SOA, qry->timestamp.tv_sec);
+ int32_t new_ttl = get_new_ttl(eh, qry, k->zname, KNOT_RRTYPE_SOA,
+ qry->timestamp.tv_sec);
if (new_ttl < 0 || eh->rank < lowest_rank || eh->is_packet) {
VERBOSE_MSG(qry, "=> SOA unfit %s: rank 0%.2o, new TTL %d\n",
(eh->is_packet ? "packet" : "RR"),
}
VERBOSE_MSG(qry, "=> FEH consistent OK \n");
- int32_t new_ttl = get_new_ttl(eh, qry, qry->sname, qry->stype, qry->timestamp.tv_sec);
+ int32_t new_ttl = get_new_ttl(eh, qry, qry->sname, qry->stype,
+ qry->timestamp.tv_sec);
if (new_ttl < 0 || eh->rank < lowest_rank) {
/* Positive record with stale TTL or bad rank.
* LATER(optim.): It's unlikely that we find a negative one,
assert(false);
goto next_label;
}
- int32_t new_ttl = get_new_ttl(eh, qry, k->zname, type, qry->timestamp.tv_sec);
+ int32_t new_ttl = get_new_ttl(eh, qry, k->zname, type,
+ qry->timestamp.tv_sec);
if (new_ttl < 0
/* Not interested in negative or bogus. */
|| eh->is_packet
#include "lib/cache/cdb_api.h"
#include "lib/resolve.h"
-/** Cache entry header
+/* Cache entry values - binary layout.
+ *
+ * It depends on type which is recognizable by the key.
+ * Code depending on the meaning of the key is marked by CACHE_KEY_DEF.
*
* 'E' entry (exact hit):
- * - ktype == NS: entry_apex and multiple chained entry_h, based on has_* : 1 flags;
+ * - ktype == NS: entry_apex and multiple chained entry_h, based on has_* flags;
* - is_packet: uint16_t length, otherwise opaque and handled by ./entry_pkt.c
* - otherwise RRset + its RRSIG set (possibly empty).
- * '1' entry (NSEC1)
- * - contents is the same as for exact hit for NSEC
+ * '1' or '3' entry (NSEC or NSEC3)
+ * - contents is the same as for exact hit
* - flags don't make sense there
- * */
+ */
+
struct entry_h {
uint32_t time; /**< The time of inception. */
uint32_t ttl; /**< TTL at inception moment. Assuming it fits into int32_t ATM. */
bool has_optout : 1; /**< Only for packets with NSEC3. */
uint8_t data[];
};
+struct entry_apex;
-enum { ENTRY_APEX_NSECS_CNT = 2 };
-
-struct entry_apex {
- /* ENTRY_H_FLAGS */
- bool has_ns : 1;
- bool has_cname : 1;
- bool has_dname : 1;
-
- uint8_t pad_;
- int8_t nsecs[ENTRY_APEX_NSECS_CNT]; /**< values: 0: none, 1: NSEC, 3: NSEC3 */
- uint8_t data[];
- /* XXX: if not first, stamp of last being the first?
- * Purpose: save cache operations if rolled the algo/params long ago. */
-};
+/** Check basic consistency of entry_h for 'E' entries, not looking into ->data.
+ * (for is_packet the length of data is checked)
+ */
+struct entry_h * entry_h_consistent(knot_db_val_t data, uint16_t type);
-/** Indices for decompressed entry_list_t. */
-enum EL {
- EL_NS = ENTRY_APEX_NSECS_CNT,
- EL_CNAME,
- EL_DNAME,
- EL_LENGTH
-};
-/** Note: arrays are passed "by reference" to functions (in C99). */
-typedef knot_db_val_t entry_list_t[EL_LENGTH];
+struct entry_apex * entry_apex_consistent(knot_db_val_t val);
-static inline uint16_t EL2RRTYPE(enum EL i)
+/** Consistency check, ATM common for NSEC and NSEC3. */
+static inline struct entry_h * entry_h_consistent_NSEC(knot_db_val_t data)
{
- switch (i) {
- case EL_NS: return KNOT_RRTYPE_NS;
- case EL_CNAME: return KNOT_RRTYPE_CNAME;
- case EL_DNAME: return KNOT_RRTYPE_DNAME;
- default: assert(false); return 0;
- }
+ /* ATM it's enough to just extend the checks for exact entries. */
+ const struct entry_h *eh = entry_h_consistent(data, KNOT_RRTYPE_NSEC);
+ bool ok = eh != NULL;
+ ok = ok && !eh->is_packet && !eh->has_optout;
+ return ok ? /*const-cast*/(struct entry_h *)eh : NULL;
}
+
+/* nsec_p* - NSEC* chain parameters */
+
static inline int nsec_p_rdlen(const uint8_t *rdata)
{
//TODO: the zero case? // FIXME security: overflow potential
return rdata ? 5 + rdata[4] : 0; /* rfc5155 4.2 and 3.2. */
}
-static const int NSEC_P_MAXLEN = sizeof(uint32_t) + 5 + 255;
+static const int NSEC_P_MAXLEN = sizeof(uint32_t) + 5 + 255; // TODO: remove??
+
+/** Hash of NSEC3 parameters, used as a tag to separate different chains for same zone. */
+typedef uint32_t nsec_p_hash_t;
+static inline nsec_p_hash_t nsec_p_mkHash(const uint8_t *nsec_p)
+{
+ assert(nsec_p && !(KNOT_NSEC3_FLAG_OPT_OUT & nsec_p[1]));
+ return hash((const char *)nsec_p, nsec_p_rdlen(nsec_p));
+}
+/** NSEC* parameters for the chain. */
+struct nsec_p {
+ const uint8_t *raw; /**< Pointer to raw NSEC3 parameters; NULL for NSEC. */
+ nsec_p_hash_t hash; /**< Hash of `raw`, used for cache keys. */
+ dnssec_nsec3_params_t libknot; /**< Format for libknot; owns malloced memory! */
+};
-/** Check basic consistency of entry_h for 'E' entries, not looking into ->data.
- * (for is_packet the length of data is checked)
- */
-struct entry_h * entry_h_consistent(knot_db_val_t data, uint16_t type);
-struct entry_apex * entry_apex_consistent(knot_db_val_t val);
-// TODO
-#define KR_CACHE_KEY_MAXLEN (KNOT_DNAME_MAXLEN + 100)
+/** LATER(optim.): this is overshot, but struct key usage should be cheap ATM. */
+#define KR_CACHE_KEY_MAXLEN (KNOT_DNAME_MAXLEN + 100) /* CACHE_KEY_DEF */
struct key {
const knot_dname_t *zname; /**< current zone name (points within qry->sname) */
uint8_t buf[KR_CACHE_KEY_MAXLEN];
};
-/** Hash of NSEC3 parameters, used as a tag to separate different chains for same zone. */
-typedef uint32_t nsec_p_hash_t;
-static inline nsec_p_hash_t nsec_p_mkHash(const uint8_t *nsec_p)
-{
- assert(nsec_p && !(KNOT_NSEC3_FLAG_OPT_OUT & nsec_p[1]));
- return hash((const char *)nsec_p, nsec_p_rdlen(nsec_p));
-}
static inline size_t key_nwz_off(const struct key *k)
{
/* CACHE_KEY_DEF: zone name lf + 0 ('1' or '3').
knot_db_val_t key_exact_type_maypkt(struct key *k, uint16_t type);
+
/* entry_h chaining; implementation in ./entry_list.c */
+enum { ENTRY_APEX_NSECS_CNT = 2 };
+
+/** Header of 'E' entry with ktype == NS. Inside is private to ./entry_list.c */
+struct entry_apex {
+ /* ENTRY_H_FLAGS */
+ bool has_ns : 1;
+ bool has_cname : 1;
+ bool has_dname : 1;
+
+ uint8_t pad_; /**< Weird: 1 byte + 2 bytes + x bytes; let's do 2+2+x. */
+ int8_t nsecs[ENTRY_APEX_NSECS_CNT]; /**< values: 0: none, 1: NSEC, 3: NSEC3 */
+ uint8_t data[];
+ /* XXX: if not first, stamp of last being the first?
+ * Purpose: save cache operations if rolled the algo/params long ago. */
+};
+
+/** Indices for decompressed entry_list_t. */
+enum EL {
+ EL_NS = ENTRY_APEX_NSECS_CNT,
+ EL_CNAME,
+ EL_DNAME,
+ EL_LENGTH
+};
+/** Note: arrays are passed "by reference" to functions (in C99). */
+typedef knot_db_val_t entry_list_t[EL_LENGTH];
+
+static inline uint16_t EL2RRTYPE(enum EL i)
+{
+ switch (i) {
+ case EL_NS: return KNOT_RRTYPE_NS;
+ case EL_CNAME: return KNOT_RRTYPE_CNAME;
+ case EL_DNAME: return KNOT_RRTYPE_DNAME;
+ default: assert(false); return 0;
+ }
+}
+
/** There may be multiple entries within, so rewind `val` to the one we want.
*
* ATM there are multiple types only for the NS ktype - it also accommodates xNAMEs.
void entry_list_memcpy(struct entry_apex *ea, entry_list_t list);
+
/* Packet caching; implementation in ./entry_pkt.c */
/** Stash the packet into cache (if suitable, etc.) */
/** Returns signed result so you can inspect how much stale the RR is.
*
* @param owner name for stale-serving decisions. You may pass NULL to disable stale.
- * FIXME: NSEC uses zone name ATM.
+ * @note: NSEC* uses zone name ATM; for NSEC3 the owner may not even be knowable.
* @param type for stale-serving.
*/
int32_t get_new_ttl(const struct entry_h *entry, const struct kr_query *qry,
const knot_dname_t *owner, uint16_t type, uint32_t now);
+
/* RRset (de)materialization; implementation in ./entry_rr.c */
/** Size of the RR count field */
/** Compute size of dematerialized rdataset. NULL is accepted as empty set. */
static inline int rdataset_dematerialize_size(const knot_rdataset_t *rds)
{
- return KR_CACHE_RR_COUNT_SIZE + (rds
- ? knot_rdataset_size(rds) - 4 * rds->rr_count /*TTLs*/
- : 0);
+ return KR_CACHE_RR_COUNT_SIZE + (rds == NULL ? 0
+ : knot_rdataset_size(rds) - 4 * rds->rr_count /*TTLs*/);
}
/** Dematerialize a rdataset. */
int rdataset_dematerialize(const knot_rdataset_t *rds, uint8_t * restrict data);
-/** NSEC* parameters; almost nothing is meaningful for NSEC. */
-struct nsec_p {
- const uint8_t *raw; /**< Pointer to raw NSEC3 parameters; NULL for NSEC. */
- nsec_p_hash_t hash; /**< Hash of `raw`, used for cache keys. */
- dnssec_nsec3_params_t libknot; /**< Format for libknot; owns malloced memory! */
-};
+
/** Partially constructed answer when gathering RRsets from cache. */
struct answer {
} rrsets[1+1+3]; /**< see AR_ANSWER and friends; only required records are filled */
};
enum {
- AR_ANSWER = 0, /**< Positive answer record. It might be wildcard-expanded. */
- AR_SOA, /**< SOA record. */
- AR_NSEC, /**< NSEC* covering or matching the SNAME (next closer name in NSEC3 case). */
- AR_WILD, /**< NSEC* covering or matching the source of synthesis. */
- AR_CPE, /**< NSEC3 matching the closest provable encloser. */
+ AR_ANSWER = 0, /**< Positive answer record. It might be wildcard-expanded. */
+ AR_SOA, /**< SOA record. */
+ AR_NSEC, /**< NSEC* covering or matching the SNAME (next closer name in NSEC3 case). */
+ AR_WILD, /**< NSEC* covering or matching the source of synthesis. */
+ AR_CPE, /**< NSEC3 matching the closest provable encloser. */
};
/** Materialize RRset + RRSIGs into ans->rrsets[id].
/* NSEC3 stuff. Implementation in ./nsec3.c */
-
-
/** Construct a string key for for NSEC3 predecessor-search, from an NSEC3 name.
* \note k->zlf_len is assumed to have been correctly set */
knot_db_val_t key_NSEC3(struct key *k, const knot_dname_t *nsec3_name,
const struct kr_query *qry, struct kr_cache *cache);
-#define VERBOSE_MSG(qry, fmt...) QRVERBOSE((qry), "cach", fmt)
-
+#define VERBOSE_MSG(qry, fmt...) QRVERBOSE((qry), "cach", fmt)
/** Shorthand for operations on cache backend */
#define cache_op(cache, op, ...) (cache)->api->op((cache)->db, ## __VA_ARGS__)
-
-/** Consistency check, ATM common for NSEC and NSEC3. */
-static inline struct entry_h * entry_h_consistent_NSEC(knot_db_val_t data)
-{
- /* ATM it's enough to just extend the checks for exact entries. */
- const struct entry_h *eh = entry_h_consistent(data, KNOT_RRTYPE_NSEC);
- bool ok = eh != NULL;
- ok = ok && !eh->is_packet && !eh->has_optout;
- return ok ? /*const-cast*/(struct entry_h *)eh : NULL;
-}
-
static inline uint16_t get_uint16(const void *address)
{
uint16_t tmp;