WIP checkpoint

parent 5b288464
......@@ -205,3 +205,85 @@ int32_t base32hex_decode(const uint8_t *in,
return (bin - out);
}
int32_t base32hex_encode(const uint8_t *in,
const uint32_t in_len,
uint8_t *out,
const uint32_t out_len)
{
// Checking inputs.
if (in == NULL || out == NULL) {
return -1;
}
if (in_len > MAX_BIN_DATA_LEN || out_len < ((in_len + 4) / 5) * 8) {
return -1;
}
uint8_t rest_len = in_len % 5;
const uint8_t *stop = in + in_len - rest_len;
uint8_t *text = out;
// Encoding loop takes 5 bytes and creates 8 characters.
while (in < stop) {
text[0] = base32hex_enc[in[0] >> 3];
text[1] = base32hex_enc[(in[0] & 0x07) << 2 | in[1] >> 6];
text[2] = base32hex_enc[(in[1] & 0x3E) >> 1];
text[3] = base32hex_enc[(in[1] & 0x01) << 4 | in[2] >> 4];
text[4] = base32hex_enc[(in[2] & 0x0F) << 1 | in[3] >> 7];
text[5] = base32hex_enc[(in[3] & 0x7C) >> 2];
text[6] = base32hex_enc[(in[3] & 0x03) << 3 | in[4] >> 5];
text[7] = base32hex_enc[in[4] & 0x1F];
text += 8;
in += 5;
}
// Processing of padding, if any.
switch (rest_len) {
case 4:
text[0] = base32hex_enc[in[0] >> 3];
text[1] = base32hex_enc[(in[0] & 0x07) << 2 | in[1] >> 6];
text[2] = base32hex_enc[(in[1] & 0x3E) >> 1];
text[3] = base32hex_enc[(in[1] & 0x01) << 4 | in[2] >> 4];
text[4] = base32hex_enc[(in[2] & 0x0F) << 1 | in[3] >> 7];
text[5] = base32hex_enc[(in[3] & 0x7C) >> 2];
text[6] = base32hex_enc[(in[3] & 0x03) << 3];
text[7] = base32hex_pad;
text += 8;
break;
case 3:
text[0] = base32hex_enc[in[0] >> 3];
text[1] = base32hex_enc[(in[0] & 0x07) << 2 | in[1] >> 6];
text[2] = base32hex_enc[(in[1] & 0x3E) >> 1];
text[3] = base32hex_enc[(in[1] & 0x01) << 4 | in[2] >> 4];
text[4] = base32hex_enc[(in[2] & 0x0F) << 1];
text[5] = base32hex_pad;
text[6] = base32hex_pad;
text[7] = base32hex_pad;
text += 8;
break;
case 2:
text[0] = base32hex_enc[in[0] >> 3];
text[1] = base32hex_enc[(in[0] & 0x07) << 2 | in[1] >> 6];
text[2] = base32hex_enc[(in[1] & 0x3E) >> 1];
text[3] = base32hex_enc[(in[1] & 0x01) << 4];
text[4] = base32hex_pad;
text[5] = base32hex_pad;
text[6] = base32hex_pad;
text[7] = base32hex_pad;
text += 8;
break;
case 1:
text[0] = base32hex_enc[in[0] >> 3];
text[1] = base32hex_enc[(in[0] & 0x07) << 2];
text[2] = base32hex_pad;
text[3] = base32hex_pad;
text[4] = base32hex_pad;
text[5] = base32hex_pad;
text[6] = base32hex_pad;
text[7] = base32hex_pad;
text += 8;
break;
}
return (text - out);
}
......@@ -49,4 +49,24 @@ int32_t base32hex_decode(const uint8_t *in,
uint8_t *out,
const uint32_t out_len);
/*!
* \brief Encodes binary data using Base32hex.
*
* \note Output data buffer contains Base32hex text string which isn't
* terminated with '\0'!
*
* \param in Input binary data.
* \param in_len Length of input data.
* \param out Output data buffer.
* \param out_len Size of output buffer.
*
* \retval >=0 length of output string.
* \retval <0 if error.
*/
int32_t base32hex_encode(const uint8_t *in,
const uint32_t in_len,
uint8_t *out,
const uint32_t out_len);
/*! @} */
......@@ -781,8 +781,14 @@ static ssize_t stash_rrset(struct kr_cache *cache, const struct kr_query *qry, c
struct key k_storage, *k = &k_storage;
knot_db_val_t key;
switch (rr->type) {
case KNOT_RRTYPE_NSEC:
case KNOT_RRTYPE_NSEC3:
if (rr->rrs.rr_count != 1
|| (KNOT_NSEC3_FLAG_OPT_OUT & knot_nsec3_flags(&rr->rrs, 0))) {
/* Skip "suspicious" or opt-out NSEC3 sets. */
return kr_ok();
}
/* fall through */
case KNOT_RRTYPE_NSEC:
if (!kr_rank_test(rank, KR_RANK_SECURE)) {
/* Skip any NSEC*s that aren't validated. */
return kr_ok();
......@@ -805,7 +811,7 @@ static ssize_t stash_rrset(struct kr_cache *cache, const struct kr_query *qry, c
assert(rr->type == KNOT_RRTYPE_NSEC3);
const knot_rdata_t *np_data = knot_rdata_data(rr->rrs.data);
const int np_dlen = nsec_p_rdlen(np_data);
key = key_NSEC3(k, encloser, nsec_p_hash(np_data));
key = key_NSEC3(k, encloser, nsec_p_mkHash(np_data));
if (npp && !*npp) {
*npp = mm_alloc(&qry->request->pool, np_dlen);
if (!*npp) {
......
......@@ -116,11 +116,29 @@ struct key {
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' + name within zone */
/* CACHE_KEY_DEF: zone name lf + 0 ('1' or '3').
* NSEC '1' case continues just with the name within zone. */
return k->zlf_len + 2;
}
static inline size_t key_nsec3_hash_off(const struct key *k)
{
/* CACHE_KEY_DEF NSEC3: tag (nsec_p_hash_t) + 20 bytes NSEC3 name hash) */
return key_nwz_off(k) + sizeof(nsec_p_hash_t);
}
/** Hash is always SHA1; I see no plans to standardize anything else.
* https://www.iana.org/assignments/dnssec-nsec3-parameters/dnssec-nsec3-parameters.xhtml#dnssec-nsec3-parameters-3
*/
static const int NSEC3_HASH_LEN = 20,
NSEC3_HASH_TXT_LEN = 32;
/** Finish constructing string key for for exact search.
* It's assumed that kr_dname_lf(k->buf, owner, *) had been ran.
......@@ -233,7 +251,7 @@ struct answer {
enum {
AR_ANSWER = 0, /**< Positive answer record. It might be wildcard-expanded. */
AR_SOA, /**< SOA record. */
AR_NSEC, /**< NSEC* covering the SNAME. */
AR_NSEC, /**< NSEC* covering 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. */
};
......@@ -289,13 +307,6 @@ int nsec1_src_synth(struct key *k, struct answer *ans, const knot_dname_t *clenc
/* NSEC3 stuff. Implementation in ./nsec3.c */
typedef uint32_t nsec_p_hash_t;
/** \note We assume it's not opt-out. */
static inline nsec_p_hash_t nsec_p_hash(const uint8_t *nsec_p)
{
assert(nsec_p);
return hash((const char *)nsec_p, nsec_p_rdlen(nsec_p));
}
/** Construct a string key for for NSEC3 predecessor-search, from an NSEC3 name.
......@@ -322,3 +333,22 @@ int nsec3_src_synth(struct key *k, struct answer *ans, const knot_dname_t *clenc
/** 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;
memcpy(&tmp, address, sizeof(tmp));
return tmp;
}
......@@ -26,7 +26,6 @@
/** Reconstruct a name into a buffer (assuming length at least KNOT_DNAME_MAXLEN). */
static int dname_wire_reconstruct(knot_dname_t *buf, const struct key *k,
knot_db_val_t kwz)
/* TODO: probably move to a place shared with with NSEC3, perhaps with key_NSEC* */
{
/* Reconstruct from key: first the ending, then zone name. */
int ret = knot_dname_lf2wire(buf, kwz.len, kwz.data);
......@@ -127,14 +126,6 @@ static int kwz_between(knot_db_val_t k1, knot_db_val_t k2, knot_db_val_t k4)
}
}
static 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;
}
/** NSEC1 range search.
*
......@@ -218,7 +209,7 @@ static const char * find_leq_NSEC1(struct kr_cache *cache, const struct kr_query
/* it's *full* name ATM */
const knot_dname_t *next = eh->data + KR_CACHE_RR_COUNT_SIZE
+ 2 /* RDLENGTH from rfc1034 */;
if (!eh->data[0]) {
if (KR_CACHE_RR_COUNT_SIZE != 2 || get_uint16(eh->data) == 0) {
assert(false);
return "ERROR";
/* TODO: more checks? Also, `next` computation is kinda messy. */
......@@ -296,8 +287,6 @@ int nsec1_encloser(struct key *k, struct answer *ans,
return ESKIP;
}
const struct entry_h *nsec_eh = val.data;
const void *nsec_eh_bound = val.data + val.len;
/* Get owner name of the record. */
const knot_dname_t *owner;
......@@ -311,6 +300,8 @@ int nsec1_encloser(struct key *k, struct answer *ans,
}
/* Basic checks OK -> materialize data. */
{
const struct entry_h *nsec_eh = val.data;
const void *nsec_eh_bound = val.data + val.len;
int ret = entry2answer(ans, AR_NSEC, nsec_eh, nsec_eh_bound,
owner, KNOT_RRTYPE_NSEC, new_ttl);
if (ret) return kr_error(ret);
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment