uint8_t lowest_rank, const struct kr_query *qry, struct kr_cache *cache);
-static int nsec_p_init(struct nsec_p *nsec_p, const uint8_t *nsec_p_raw, bool with_knot)
+static int nsec_p_init(struct nsec_p *nsec_p, knot_db_val_t nsec_p_entry, bool with_knot)
{
- nsec_p->raw = nsec_p_raw;
- if (!nsec_p_raw) return kr_ok();
+ const size_t stamp_len = sizeof(uint32_t);
+ if (nsec_p_entry.len <= stamp_len) { /* plain NSEC if equal */
+ nsec_p->raw = NULL;
+ return kr_ok();
+ }
+ nsec_p->raw = (uint8_t *)nsec_p_entry.data + stamp_len;
nsec_p->hash = nsec_p_mkHash(nsec_p->raw);
if (!with_knot) return kr_ok();
/* Convert NSEC3 params to another format. */
memset(nsec_p, 0, sizeof(*nsec_p));
}
+/** Compute new TTL for nsec_p entry, using SOA serial arith.
+ * \param new_ttl (optionally) write the new TTL (even if negative)
+ * \return error code, e.g. kr_error(ESTALE) */
+static int nsec_p_ttl(knot_db_val_t entry, const struct kr_query *qry, int32_t *new_ttl)
+{
+ if (!entry.data || !qry) {
+ assert(!EINVAL);
+ return kr_error(EINVAL);
+ }
+ uint32_t stamp;
+ if (!entry.len) {
+ return kr_error(ENOENT);
+ }
+ if (entry.len < sizeof(stamp)) {
+ assert(!EILSEQ);
+ return kr_error(EILSEQ);
+ }
+ memcpy(&stamp, entry.data, sizeof(stamp));
+ int32_t newttl = stamp - qry->timestamp.tv_sec;
+ if (new_ttl) *new_ttl = newttl;
+ return newttl < 0 ? kr_error(ESTALE) : kr_ok();
+}
+
static uint8_t get_lowest_rank(const struct kr_request *req, const struct kr_query *qry)
{
/* TODO: move rank handling into the iterator (DNSSEC_* flags)? */
/* Try the NSEC* parameters in order, until success.
* Let's not mix different parameters for NSEC* RRs in a single proof. */
for (int i = 0; ;) {
- if (!el[i].len) goto cont;
- /* OK iff the stamp is in future */
- uint32_t stamp;
- memcpy(&stamp, el[i].data, sizeof(stamp));
- const int32_t remains = stamp - qry->timestamp.tv_sec; /* using SOA serial arith. */
- if (remains >= 0 || VERBOSE_STATUS) {
- const uint8_t *nsec_p_raw = el[i].len > sizeof(stamp)
- ? (uint8_t *)el[i].data + sizeof(stamp) : NULL;
- nsec_p_init(&ans.nsec_p, nsec_p_raw, remains >= 0);
+ int32_t log_new_ttl;
+ ret = nsec_p_ttl(el[i], qry, &log_new_ttl);
+ if (!ret || VERBOSE_STATUS) {
+ nsec_p_init(&ans.nsec_p, el[i], !ret);
}
- if (remains < 0) {
+ if (ret) {
VERBOSE_MSG(qry, "=> skipping zone: %s, %s, hash %x;"
- "outdated TTL %d\n",
+ "new TTL %d, ret %d\n",
log_zname, (ans.nsec_p.raw ? "NSEC3" : "NSEC"),
- (unsigned)ans.nsec_p.hash, (int)remains);
+ (unsigned)ans.nsec_p.hash, (int)log_new_ttl, ret);
/* no need for nsec_p_cleanup() in this case */
goto cont;
}
need_zero = false;
/* More types are possible; try in order.
* For non-fatal failures just "continue;" to try the next type. */
- for (int i = ENTRY_APEX_NSECS_CNT; i < EL_LENGTH; ++i) {
+ for (int i = 0; i < EL_LENGTH; ++i) { /* TODO: factor most of inside into a function? */
if (!el[i].len
/* On a zone cut we want DS from the parent zone. */
- || (i == EL_NS && exact_match && qry->stype == KNOT_RRTYPE_DS)
+ || (i <= EL_NS && exact_match && qry->stype == KNOT_RRTYPE_DS)
/* CNAME is interesting only if we
* directly hit the name that was asked.
* Note that we want it even in the DS case. */
) {
continue;
}
- /* ^^ LATER(optim.): not having NS but having
- * non-timeouted nsec_p is also OK for a zone cut. */
- /* Find the entry for the type, check positivity, TTL */
- const uint16_t type = EL2RRTYPE(i);
- const struct entry_h *eh = entry_h_consistent(el[i], type);
- if (!eh) {
- VERBOSE_MSG(qry, "=> EH seek ret: %d\n", ret);
- assert(false);
- goto next_label;
- }
- int32_t new_ttl = get_new_ttl(eh, qry, k->zname, type,
+
+ uint16_t type;
+ int32_t new_ttl;
+ if (i < ENTRY_APEX_NSECS_CNT) {
+ type = KNOT_RRTYPE_NS;
+ ret = nsec_p_ttl(el[i], qry, &new_ttl);
+ if (ret) {
+ VERBOSE_MSG(qry,
+ "=> skipping unfit nsec_p: new TTL %d,"
+ " ret %d\n", (int)new_ttl, ret);
+ continue;
+ }
+ } else {
+ type = EL2RRTYPE(i);
+ /* Find the entry for the type, check positivity, TTL */
+ const struct entry_h *eh = entry_h_consistent(el[i], type);
+ if (!eh) {
+ VERBOSE_MSG(qry, "=> EH not consistent\n");
+ assert(false);
+ goto next_label;
+ }
+ 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
- /* For NS any kr_rank is accepted,
- * as insecure or even nonauth is OK */
- || (type != KNOT_RRTYPE_NS && eh->rank < rank_min)) {
-
- WITH_VERBOSE(qry) {
+ const bool ok =
+ /* For NS any kr_rank is accepted,
+ * as insecure or even nonauth is OK */
+ (type == KNOT_RRTYPE_NS || eh->rank >= rank_min)
+ /* Not interested in negative or bogus. */
+ && !eh->is_packet && new_ttl >= 0;
+ WITH_VERBOSE(qry) { if (!ok) {
auto_free char *type_str =
kr_rrtype_text(type);
const char *packet_str =
VERBOSE_MSG(qry, "=> skipping unfit %s %s: "
"rank 0%.2o, new TTL %d\n",
type_str, packet_str,
- eh->rank, new_ttl);
- }
- continue;
+ eh->rank, (int)new_ttl);
+ } }
+ if (!ok) continue;
}
/* We found our match. */
k->type = type;