WIP: nsec3_encloser() finished, maybe?

parent ffc310ae
......@@ -23,9 +23,9 @@
#define MAX_BIN_DATA_LEN ((INT32_MAX / 8) * 5)
/*! \brief Base32hex padding character. */
const uint8_t base32hex_pad = '=';
/*! \brief Base32hex alphabet. */
const uint8_t base32hex_enc[] = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
static const uint8_t base32hex_pad = '=';
/*! \brief Base32hex alphabet. Beware: original code was upper-case. */
static const uint8_t base32hex_enc[] = "0123456789abcdefghijklmnopqrstuv";
/*! \brief Indicates bad Base32hex character. */
#define KO 255
......@@ -33,7 +33,7 @@ const uint8_t base32hex_enc[] = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
#define PD 32
/*! \brief Transformation and validation table for decoding Base32hex. */
const uint8_t base32hex_dec[256] = {
static const uint8_t base32hex_dec[256] = {
[ 0] = KO, [ 43] = KO, ['V'] = 31, [129] = KO, [172] = KO, [215] = KO,
[ 1] = KO, [ 44] = KO, ['W'] = KO, [130] = KO, [173] = KO, [216] = KO,
[ 2] = KO, [ 45] = KO, ['X'] = KO, [131] = KO, [174] = KO, [217] = KO,
......
......@@ -51,7 +51,7 @@ int32_t base32hex_decode(const uint8_t *in,
/*!
* \brief Encodes binary data using Base32hex.
* \brief Encodes binary data using Base32hex. Lower case is used!
*
* \note Output data buffer contains Base32hex text string which isn't
* terminated with '\0'!
......
......@@ -334,7 +334,7 @@ static int try_wild(struct key *k, struct answer *ans, const knot_dname_t *clenc
const struct kr_query *qry, struct kr_cache *cache);
static int peek_encloser(
struct key *k, struct answer *ans, const uint8_t *nsec_p, const int sname_labels,
struct key *k, struct answer *ans, const int sname_labels,
uint8_t lowest_rank, const struct kr_query *qry, struct kr_cache *cache);
/** function for .produce phase */
......@@ -481,10 +481,10 @@ static int peek_nosync(kr_layer_t *ctx, knot_pkt_t *pkt)
memcpy(&stamp, el[i].data, sizeof(stamp));
const int32_t remains = stamp - qry->timestamp.tv_sec; /* using SOA serial arith. */
if (remains < 0) goto cont;
const uint8_t *nsec_p = el[i].len > sizeof(stamp) ?
ans.nsec_p = el[i].len > sizeof(stamp) ?
el[i].data + sizeof(stamp) : NULL;
/**** 2. and 3. inside */
ret = peek_encloser(k, &ans, nsec_p, sname_labels,
ret = peek_encloser(k, &ans, sname_labels,
lowest_rank, qry, cache);
if (!ret) break;
if (ret < 0) return ctx->state;
......@@ -580,11 +580,9 @@ static int peek_nosync(kr_layer_t *ctx, knot_pkt_t *pkt)
* \return 0: success (may need SOA); >0: try other nsec_p; <0: exit cache immediately.
*/
static int peek_encloser(
struct key *k, struct answer *ans, const uint8_t *nsec_p, const int sname_labels,
struct key *k, struct answer *ans, const int sname_labels,
uint8_t lowest_rank, const struct kr_query *qry, struct kr_cache *cache)
{
ans->nsec_v = nsec_p ? 3 : 1;
/** Start of NSEC* covering the sname;
* it's part of key - the one within zone (read only) */
knot_db_val_t cover_low_kwz = { NULL, 0 };
......@@ -597,11 +595,11 @@ static int peek_encloser(
/**** 2. Find a closest (provable) encloser (of sname). */
int clencl_labels = -1;
if (!nsec_p) { /* NSEC */
if (!ans->nsec_p) { /* NSEC */
int ret = nsec1_encloser(k, ans, sname_labels, &clencl_labels,
&cover_low_kwz, &cover_hi_kwz, qry, cache);
if (ret) return ret;
} else { //XXX NSEC3
} else {
int ret = nsec3_encloser(k, ans, sname_labels, &clencl_labels,
&cover_low_kwz, &cover_hi_kwz, qry, cache);
if (ret) return ret;
......@@ -622,14 +620,14 @@ static int peek_encloser(
/**** 3. source of synthesis checks, in case sname was covered.
**** 3a. We want to query for NSEC* of source of synthesis (SS) or its
* predecessor, providing us with a proof of its existence or non-existence. */
if (sname_covered && !nsec_p) {
if (sname_covered && !ans->nsec_p) {
int ret = nsec1_src_synth(k, ans, clencl_name,
cover_low_kwz, cover_hi_kwz, qry, cache);
if (ret == AR_SOA) return 0;
assert(ret <= 0);
if (ret) return ret;
} else if (sname_covered && nsec_p) {
} else if (sname_covered && ans->nsec_p) {
//XXX NSEC3
int ret = nsec3_src_synth(k, ans, clencl_name,
cover_low_kwz, cover_hi_kwz, qry, cache);
......
......@@ -241,7 +241,7 @@ int rdataset_dematerialize(const knot_rdataset_t *rds, void * restrict data);
/** Partially constructed answer when gathering RRsets from cache. */
struct answer {
int rcode; /**< PKT_NODATA, etc. */
uint8_t nsec_v; /**< 1 or 3; Let's avoid mixing NSEC with NSEC3 in one answer. */
const uint8_t *nsec_p; /**< Let's avoid mixing different NSEC* parameters in one answer. */
knot_mm_t *mm; /**< Allocator for rrsets */
struct answer_rrset {
ranked_rr_array_entry_t set; /**< set+rank for the main data */
......@@ -251,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 (next closer name in NSEC3 case). */
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. */
};
......
......@@ -287,7 +287,6 @@ int nsec1_encloser(struct key *k, struct answer *ans,
return ESKIP;
}
/* Get owner name of the record. */
const knot_dname_t *owner;
knot_dname_t owner_buf[KNOT_DNAME_MAXLEN];
......@@ -312,10 +311,10 @@ int nsec1_encloser(struct key *k, struct answer *ans,
uint8_t *bm = NULL;
uint16_t bm_size = 0;
knot_nsec_bitmap(&nsec_rr->rrs, &bm, &bm_size);
assert(bm);
if (exact_match) {
if (kr_nsec_bitmap_nodata_check(bm, bm_size, qry->stype, nsec_rr->owner) != 0) {
assert(bm);
VERBOSE_MSG(qry,
"=> NSEC sname: match but failed type check\n");
return ESKIP;
......
......@@ -254,30 +254,28 @@ int nsec3_encloser(struct key *k, struct answer *ans,
return kr_error(EINVAL);
}
// FIXME get *nsec_p - possibly just add to the parameter list
const uint8_t *nsec_p = NULL;
const nsec_p_hash_t nsec_p_hash = nsec_p_mkHash(nsec_p);
const nsec_p_hash_t nsec_p_hash = nsec_p_mkHash(ans->nsec_p);
/* Convert NSEC3 params to another format. */
dnssec_nsec3_params_t nsec3_p;
{
const dnssec_binary_t rdata = {
.size = nsec_p_rdlen(nsec_p),
.data = (uint8_t *)/*const-cast*/nsec_p,
.size = nsec_p_rdlen(ans->nsec_p),
.data = (uint8_t *)/*const-cast*/ans->nsec_p,
};
int ret = dnssec_nsec3_params_from_rdata(&nsec3_p, &rdata);
if (ret != DNSSEC_EOK) return kr_error(ret);
}
/*** Find and cover the next closer name - cycle: name starting at sname,
* proceeding while longer than zname, shortening by one label on step. */
/*** Find the closest encloser - cycle: name starting at sname,
* proceeding while longer than zname, shortening by one label on step.
* We need a pair where a name doesn't exist *and* its parent does. */
const int zname_labels = knot_dname_labels(k->zname, NULL);
int last_nxproven_labels = -1;
const knot_dname_t *name = qry->sname;
for (int name_labels = sname_labels; name_labels > zname_labels;
for (int name_labels = sname_labels; name_labels >= zname_labels;
--name_labels, name += 1 + name[0]) {
/*** Find a previous-or-equal NSEC3 in cache covering the name,
* checking TTL etc.
* Exit if match is found (may have NODATA proof if the first iteration),
* break if cover is found. */
/* Find a previous-or-equal NSEC3 in cache covering the name,
* checking TTL etc. */
const knot_db_val_t key =
key_NSEC3_name(k, name, false, nsec_p_hash, &nsec3_p);
if (!key.data) continue;
......@@ -295,16 +293,16 @@ int nsec3_encloser(struct key *k, struct answer *ans,
}
continue;
}
if (exact_match && name_labels != sname_labels) {
/* This name exists (checked rank and TTL), so we do not
* continue trying to prove non-existence above this name. */
if (exact_match && name_labels != sname_labels
&& name_labels + 1 != last_nxproven_labels) {
/* This name exists (checked rank and TTL), and it's
* neither of the two interesting cases, so we do not
* keep searching for non-existence above this name. */
VERBOSE_MSG(qry,
"=> NSEC3 encloser: only found existence of an ancestor\n");
return ESKIP;
}
/* FIXME XXX: rethink delegation/ancestor checks */
/* Get owner name of the record. */
const knot_dname_t *owner;
knot_dname_t owner_buf[KNOT_DNAME_MAXLEN];
......@@ -318,24 +316,45 @@ int nsec3_encloser(struct key *k, struct answer *ans,
}
owner = owner_buf;
}
/* Basic checks OK -> materialize data. */
/* Basic checks OK -> materialize data, cleaning any previous
* records on that answer index (unsuccessful attempts). */
const int ans_id = (exact_match && name_labels + 1 == last_nxproven_labels)
? AR_WILD : AR_NSEC;
{
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,
memset(&ans->rrsets[ans_id], 0, sizeof(ans->rrsets[ans_id]));
int ret = entry2answer(ans, ans_id, nsec_eh, nsec_eh_bound,
owner, KNOT_RRTYPE_NSEC3, new_ttl);
if (ret) return kr_error(ret);
}
/* Final checks, split for matching vs. covering our name. */
const knot_rrset_t *nsec_rr = ans->rrsets[AR_NSEC].set.rr;
if (!exact_match) {
/* Non-existence proven, but we don't know if `name`
* is the next closer name.
* Note: we don't need to check for the sname being
* delegated away by this record, as with NSEC3 only
* *exact* match on an ancestor could do that. */
last_nxproven_labels = name_labels;
WITH_VERBOSE(qry) {
char hash_low_txt[NSEC3_HASH_TXT_LEN + 1];
nsec3_hash2text(owner, hash_low_txt);
VERBOSE_MSG(qry,
"=> NSEC3: depth %d covered by: %s -> TODO, new TTL %d\n",
name_labels - zname_labels, hash_low_txt, new_ttl);
}
continue;
}
/* Exactly matched NSEC3: two cases, one after another. */
const knot_rrset_t *nsec_rr = ans->rrsets[ans_id].set.rr;
uint8_t *bm = NULL;
uint16_t bm_size = 0;
knot_nsec_bitmap(&nsec_rr->rrs, &bm, &bm_size);
if (exact_match) {
assert(name_labels == sname_labels);
assert(bm);
if (name_labels == sname_labels) {
if (kr_nsec_bitmap_nodata_check(bm, bm_size, qry->stype,
nsec_rr->owner) != 0) {
assert(bm);
VERBOSE_MSG(qry,
"=> NSEC3 sname: match but failed type check\n");
return ESKIP;
......@@ -346,33 +365,37 @@ int nsec3_encloser(struct key *k, struct answer *ans,
new_ttl);
ans->rcode = PKT_NODATA;
return kr_ok();
} /* else */
/* Inexact match. First check if name is delegated by that NSEC3. */
if (kr_nsec_children_in_zone_check(bm, bm_size) != 0
&& knot_dname_matched_labels()) {
assert(name_labels + 1 == last_nxproven_labels);
if (kr_nsec_children_in_zone_check(bm, bm_size) != 0) {
VERBOSE_MSG(qry,
"=> NSEC3 sname: covered but delegated (or error)\n");
"=> NSEC3 encloser: found but delegated (or error)\n");
return ESKIP;
}
/*** One more step but searching for match this time
* - that's the closest (provable) encloser. */
/* Non-existence proven *except* for wildcards. */
/* NXDOMAIN proven *except* for wildcards. */
WITH_VERBOSE(qry) {
char hash_low_txt[NSEC3_HASH_TXT_LEN + 1];
nsec3_hash2text(owner, hash_low_txt);
char hash_clencl_txt[NSEC3_HASH_TXT_LEN + 1];
nsec3_hash2text(owner, hash_clencl_txt);
VERBOSE_MSG(qry,
"=> NSEC3 sname: covered by: %s -> TODO, new TTL %d\n",
hash_low_txt, new_ttl);
"=> NSEC3 encloser: confirmed as %s, new TTL %d\n",
hash_clencl_txt, new_ttl);
}
*clencl_labels = name_labels;
ans->rcode = PKT_NXDOMAIN;
/* Avoid repeated NSEC3 - remove either if the hashes match.
* This is very unlikely in larger zones: 1/size (per attempt). */
if (unlikely(0 == memcmp(ans->rrsets[AR_NSEC].set.rr->owner + 1,
ans->rrsets[AR_WILD].set.rr->owner + 1,
NSEC3_HASH_LEN))) {
memset(&ans->rrsets[AR_WILD], 0, sizeof(ans->rrsets[AR_WILD]));
}
return kr_ok();
}
//assert(false);
return -ENOSYS;
/* ran out of options */
return ESKIP;
}
int nsec3_src_synth(struct key *k, struct answer *ans, const knot_dname_t *clencl_name,
......
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