Commit 899e447d authored by Karel Slaný's avatar Karel Slaný

layer/validate: removed struct contained_ids

RRSets are merged by using stash_add().
parent 5700cec6
......@@ -25,16 +25,11 @@
#include "lib/layer/iterate.h"
#include "lib/cache.h"
#include "lib/module.h"
#include "lib/rrset_stash.h"
#define DEBUG_MSG(fmt...) QRDEBUG(kr_rplan_current(rplan), " rc ", fmt)
#define DEFAULT_MINTTL (5) /* Short-time "no data" retention to avoid bursts */
/* Stash key flags */
#define KEY_FLAG_NO 0x01
#define KEY_FLAG_RRSIG 0x02
#define KEY_FLAG_SET(key, flag) key[0] = (flag);
#define KEY_COVERING_RRSIG(key) (key[0] & KEY_FLAG_RRSIG)
/** Record is expiring if it has less than 1% TTL (or less than 5s) */
static inline bool is_expiring(const knot_rrset_t *rr, uint32_t drift)
{
......@@ -210,45 +205,6 @@ static int stash_commit(map_t *stash, struct kr_query *qry, struct kr_cache_txn
return map_walk(stash, &commit_rr, &baton);
}
static int stash_add(const knot_pkt_t *pkt, map_t *stash, const knot_rrset_t *rr, mm_ctx_t *pool)
{
/* Stash key = {[1] flags, [1-255] owner, [1-5] type, [1] \x00 } */
char key[9 + KNOT_DNAME_MAXLEN];
uint16_t rrtype = rr->type;
KEY_FLAG_SET(key, KEY_FLAG_NO);
/* Stash RRSIGs in a special cache, flag them and set type to its covering RR.
* This way it the stash won't merge RRSIGs together. */
if (rr->type == KNOT_RRTYPE_RRSIG) {
rrtype = knot_rrsig_type_covered(&rr->rrs, 0);
KEY_FLAG_SET(key, KEY_FLAG_RRSIG);
}
uint8_t *key_buf = (uint8_t *)key + 1;
int ret = knot_dname_to_wire(key_buf, rr->owner, KNOT_DNAME_MAXLEN);
if (ret <= 0) {
return ret;
}
knot_dname_to_lower(key_buf);
/* Must convert to string, as the key must not contain 0x00 */
ret = snprintf((char *)key_buf + ret - 1, sizeof(key) - KNOT_DNAME_MAXLEN, "%hu", rrtype);
if (ret <= 0 || ret >= KNOT_DNAME_MAXLEN) {
return kr_error(EILSEQ);
}
/* Check if already exists */
knot_rrset_t *stashed = map_get(stash, key);
if (!stashed) {
stashed = knot_rrset_copy(rr, pool);
if (!stashed) {
return kr_error(ENOMEM);
}
return map_set(stash, key, stashed);
}
/* Merge rdataset */
return knot_rdataset_merge(&stashed->rrs, &rr->rrs, pool);
}
static void stash_glue(map_t *stash, knot_pkt_t *pkt, const knot_dname_t *ns_name, mm_ctx_t *pool)
{
const knot_pktsection_t *additional = knot_pkt_section(pkt, KNOT_ADDITIONAL);
......
......@@ -31,66 +31,35 @@
#include "lib/layer.h"
#include "lib/resolve.h"
#include "lib/rplan.h"
#include "lib/rrset_stash.h"
#include "lib/defines.h"
#include "lib/module.h"
#define DEBUG_MSG(qry, fmt...) QRDEBUG(qry, "vldr", fmt)
struct rrset_ids {
const knot_dname_t *owner;
uint16_t type;
uint32_t ttl;
/** @internal Baton for validate_section */
struct stash_baton {
const knot_pkt_t *pkt;
knot_section_t section_id;
const knot_rrset_t *keys;
const knot_dname_t *zone_name;
uint32_t timestamp;
bool has_nsec3;
int result;
};
/** Simplistic structure holding RR types that are contained in the packet. */
struct contained_ids {
struct rrset_ids *ids;
size_t size;
size_t max;
mm_ctx_t *pool;
};
static int rrtypes_add(struct contained_ids *stored, const knot_rrset_t *rr)
static int validate_rrset(const char *key, void *val, void *data)
{
if (!stored || !rr) {
return kr_error(EINVAL);
}
size_t i;
for (i = 0; i < stored->size; ++i) {
if ((knot_dname_cmp(stored->ids[i].owner, rr->owner) == 0) &&
(stored->ids[i].type == rr->type)) {
break;
}
}
uint32_t rr_ttl = knot_rdata_ttl(knot_rdataset_at(&rr->rrs, 0));
if (i < stored->size) {
if (stored->ids[i].ttl == rr_ttl) {
return kr_ok(); /* Type is stored. */
} else {
/* RFC2181 5.2 */
return kr_error(EINVAL);
}
}
knot_rrset_t *rr = val;
struct stash_baton *baton = data;
if (stored->max == stored->size) {
#define INCREMENT 8
struct rrset_ids *new = mm_realloc(stored->pool, stored->ids, stored->max + INCREMENT * sizeof(*stored->ids), stored->max);
if (new) {
stored->ids = new;
stored->max += INCREMENT * sizeof(uint16_t);
} else {
return kr_error(ENOMEM);
}
#undef INCREMENT
if (baton->result != 0) {
return baton->result;
}
assert(stored->max > stored->size);
stored->ids[stored->size].owner = rr->owner;
stored->ids[stored->size].type = rr->type;
stored->ids[stored->size].ttl = rr_ttl;
++stored->size;
return kr_ok();
baton->result = kr_rrset_validate(baton->pkt, baton->section_id, rr,
baton->keys, baton->zone_name,
baton->timestamp, baton->has_nsec3);
return baton->result;
}
static int validate_section(struct kr_query *qry, knot_pkt_t *answer,
......@@ -103,9 +72,11 @@ static int validate_section(struct kr_query *qry, knot_pkt_t *answer,
}
int ret = kr_ok();
struct contained_ids stored = {0, };
stored.pool = pool;
knot_rrset_t *covered = NULL;
map_t stash = map_make();
stash.malloc = (map_alloc_f) mm_alloc;
stash.free = (map_free_f) mm_free;
stash.baton = pool;
/* Determine RR types contained in the section. */
for (unsigned i = 0; i < sec->count; ++i) {
......@@ -116,49 +87,32 @@ static int validate_section(struct kr_query *qry, knot_pkt_t *answer,
if ((rr->type == KNOT_RRTYPE_NS) && (section_id == KNOT_AUTHORITY)) {
continue;
}
ret = rrtypes_add(&stored, rr);
ret = stash_add(answer, &stash, rr, pool);
if (ret != 0) {
goto fail;
}
}
for (size_t i = 0; i < stored.size; ++i) {
knot_rrset_free(&covered, pool);
/* Construct a RRSet. */
for (unsigned j = 0; j < sec->count; ++j) {
const knot_rrset_t *rr = knot_pkt_rr(sec, j);
if ((rr->type != stored.ids[i].type) ||
(knot_dname_cmp(rr->owner, stored.ids[i].owner) != 0)) {
continue;
}
if (covered) {
ret = knot_rdataset_merge(&covered->rrs, &rr->rrs, pool);
if (ret != 0) {
goto fail;
}
} else {
covered = knot_rrset_copy(rr, pool);
if (!covered) {
ret = kr_error(ENOMEM);
goto fail;
}
}
}
/* Validate RRSet. */
struct stash_baton baton = {
.pkt = answer,
.section_id = section_id,
.keys = qry->zone_cut.key,
/* Can't use qry->zone_cut.name directly, as this name can
* change when updating cut information before validation.
*/
const knot_dname_t *zone_name = qry->zone_cut.key ? qry->zone_cut.key->owner : NULL;
ret = kr_rrset_validate(answer, section_id, covered, qry->zone_cut.key, zone_name, qry->timestamp.tv_sec, has_nsec3);
if (ret != 0) {
break;
}
.zone_name = qry->zone_cut.key ? qry->zone_cut.key->owner : NULL,
.timestamp = qry->timestamp.tv_sec,
.has_nsec3 = has_nsec3,
.result = 0
};
ret = map_walk(&stash, &validate_rrset, &baton);
if (ret != 0) {
return ret;
}
ret = baton.result;
fail:
mm_free(stored.pool, stored.ids);
knot_rrset_free(&covered, pool);
return ret;
}
......@@ -404,7 +358,7 @@ static int validate(knot_layer_t *ctx, knot_pkt_t *pkt)
/* Validate non-existence proof if not positive answer. */
if (pkt_rcode == KNOT_RCODE_NXDOMAIN) {
/* @todo If knot_pkt_qname(pkt) is used instead of qry->sname then the test crash. */
/* @todo If knot_pkt_qname(pkt) is used instead of qry->sname then the tests crash. */
if (!has_nsec3) {
ret = kr_nsec_name_error_response_check(pkt, KNOT_AUTHORITY, qry->sname, &req->pool);
} else {
......
......@@ -22,6 +22,7 @@ libkres_SOURCES := \
lib/nsrep.c \
lib/module.c \
lib/resolve.c \
lib/rrset_stash.c \
lib/zonecut.c \
lib/rplan.c \
lib/cache.c
......@@ -42,6 +43,7 @@ libkres_HEADERS := \
lib/nsrep.h \
lib/module.h \
lib/resolve.h \
lib/rrset_stash.h \
lib/zonecut.h \
lib/rplan.h \
lib/cache.h
......
/* Copyright (C) 2014 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libknot/descriptor.h>
#include <libknot/dname.h>
#include <libknot/rrtype/rrsig.h>
#include <stdio.h>
#include "lib/defines.h"
#include "lib/rrset_stash.h"
int stash_add(const knot_pkt_t *pkt, map_t *stash, const knot_rrset_t *rr, mm_ctx_t *pool)
{
(void) pkt;
/* Stash key = {[1] flags, [1-255] owner, [1-5] type, [1] \x00 } */
char key[9 + KNOT_DNAME_MAXLEN];
uint16_t rrtype = rr->type;
KEY_FLAG_SET(key, KEY_FLAG_NO);
/* Stash RRSIGs in a special cache, flag them and set type to its covering RR.
* This way it the stash won't merge RRSIGs together. */
if (rr->type == KNOT_RRTYPE_RRSIG) {
rrtype = knot_rrsig_type_covered(&rr->rrs, 0);
KEY_FLAG_SET(key, KEY_FLAG_RRSIG);
}
uint8_t *key_buf = (uint8_t *)key + 1;
int ret = knot_dname_to_wire(key_buf, rr->owner, KNOT_DNAME_MAXLEN);
if (ret <= 0) {
return ret;
}
knot_dname_to_lower(key_buf);
/* Must convert to string, as the key must not contain 0x00 */
ret = snprintf((char *)key_buf + ret - 1, sizeof(key) - KNOT_DNAME_MAXLEN, "%hu", rrtype);
if (ret <= 0 || ret >= KNOT_DNAME_MAXLEN) {
return kr_error(EILSEQ);
}
/* Check if already exists */
knot_rrset_t *stashed = map_get(stash, key);
if (!stashed) {
stashed = knot_rrset_copy(rr, pool);
if (!stashed) {
return kr_error(ENOMEM);
}
return map_set(stash, key, stashed);
}
/* Merge rdataset */
return knot_rdataset_merge(&stashed->rrs, &rr->rrs, pool);
}
/* Copyright (C) 2015 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <libknot/internal/mempattern.h>
#include <libknot/packet/pkt.h>
#include <libknot/rrset.h>
#include "lib/generic/map.h"
/* Stash key flags */
#define KEY_FLAG_NO 0x01
#define KEY_FLAG_RRSIG 0x02
#define KEY_FLAG_SET(key, flag) key[0] = (flag);
#define KEY_COVERING_RRSIG(key) (key[0] & KEY_FLAG_RRSIG)
/**
* Merges RRSets with matching owner name and type together.
* @note RRSIG RRSets are merged according the type covered fields.
* @param pkt Packet which the rset belongs to.
* @param stash Holds the merged RRSets.
* @param rr RRSet to be added.
* @param pool Memory pool.
* @return 0 or an error
*/
int stash_add(const knot_pkt_t *pkt, map_t *stash, const knot_rrset_t *rr, mm_ctx_t *pool);
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