Commit 4930d1d2 authored by Marek Vavruša's avatar Marek Vavruša

lib: stub NS reputation scoring, use glue presence as score for iter

parent 977d496b
......@@ -25,6 +25,7 @@
#include "lib/resolve.h"
#include "lib/rplan.h"
#include "lib/defines.h"
#include "lib/nsrep.h"
#define DEBUG_MSG(fmt...) QRDEBUG(kr_rplan_current(param->rplan), "iter", fmt)
......@@ -150,41 +151,78 @@ int rr_update_answer(const knot_rrset_t *rr, unsigned hint, struct kr_layer_para
return KNOT_NS_PROC_DONE;
}
int rr_update_nameserver(const knot_rrset_t *rr, unsigned hint, struct kr_layer_param *param)
static bool has_glue(const knot_dname_t *ns_name, knot_pkt_t *pkt)
{
const knot_pktsection_t *ar = knot_pkt_section(pkt, KNOT_ADDITIONAL);
for (unsigned i = 0; i < ar->count; ++i) {
const knot_rrset_t *rr = knot_pkt_rr(ar, i);
if ((rr->type == KNOT_RRTYPE_A || rr->type == KNOT_RRTYPE_AAAA) &&
(knot_dname_is_equal(ns_name, rr->owner))) {
return true;
}
}
return false;
}
static int nameserver_score(const knot_rrset_t *rr, unsigned hint, knot_pkt_t *pkt, struct kr_layer_param *param)
{
struct kr_query *query = kr_rplan_current(param->rplan);
const knot_dname_t *ns_name = knot_ns_name(&rr->rrs, hint);
int score = KR_NS_VALID + 1;
/* Authority MUST be at/below the authority of the nameserver, otherwise
* possible cache injection attempt. */
if (!knot_dname_in(query->zone_cut.name, rr->owner)) {
DEBUG_MSG("NS in query outside of its authority => rejecting\n");
return KNOT_NS_PROC_FAIL;
return KR_NS_INVALID;
}
/* Ignore already resolved zone cut. */
if (knot_dname_is_equal(rr->owner, query->zone_cut.name)) {
return KNOT_NS_PROC_MORE;
return KR_NS_VALID;
}
/* Set zone cut to given name server. */
kr_set_zone_cut(&query->zone_cut, rr->owner, ns_name);
return KNOT_NS_PROC_DONE;
/* Check if contains glue. */
if (has_glue(ns_name, pkt)) {
score += 1;
}
return score;
}
static int process_authority(knot_pkt_t *pkt, struct kr_layer_param *param)
{
struct kr_query *query = kr_rplan_current(param->rplan);
const knot_rrset_t *best_ns = NULL;
int best_score = 0;
/* AA, terminate resolution chain. */
if (knot_wire_get_aa(pkt->wire)) {
return KNOT_NS_PROC_MORE;
}
/* Elect best name server candidate. */
const knot_pktsection_t *ns = knot_pkt_section(pkt, KNOT_AUTHORITY);
for (unsigned i = 0; i < ns->count; ++i) {
const knot_rrset_t *rr = knot_pkt_rr(ns, i);
if (rr->type == KNOT_RRTYPE_NS) {
int state = rr_update_nameserver(rr, 0, param);
if (state != KNOT_NS_PROC_MORE) {
return state;
int score = nameserver_score(rr, 0, pkt, param);
if (score < 0) {
return KNOT_NS_PROC_FAIL;
}
if (score > best_score) {
best_ns = rr;
best_score = score;
}
}
}
/* Update name server candidate. */
if (best_ns != NULL) {
kr_set_zone_cut(&query->zone_cut, best_ns->owner, knot_ns_name(&best_ns->rrs, 0));
return KNOT_NS_PROC_DONE;
}
return KNOT_NS_PROC_MORE;
}
......@@ -202,10 +240,6 @@ static int process_additional(knot_pkt_t *pkt, struct kr_layer_param *param)
}
}
/* Glue not found => resolve NS address. */
(void) kr_rplan_push(param->rplan, query, query->zone_cut.ns, KNOT_CLASS_IN, KNOT_RRTYPE_AAAA);
(void) kr_rplan_push(param->rplan, query, query->zone_cut.ns, KNOT_CLASS_IN, KNOT_RRTYPE_A);
return KNOT_NS_PROC_DONE;
}
......
......@@ -33,9 +33,3 @@ int rr_update_parent(const knot_rrset_t *rr, unsigned hint, struct kr_layer_para
* \note When \a hint is KNOT_PF_FREE, RR is treated as a copy and answer takes its ownership.
*/
int rr_update_answer(const knot_rrset_t *rr, unsigned hint, struct kr_layer_param *param);
/*!
* \brief Result updates current nameserver.
* \note Hint is an index of chosen RR in the set.
*/
int rr_update_nameserver(const knot_rrset_t *rr, unsigned hint, struct kr_layer_param *param);
......@@ -3,6 +3,7 @@ libkresolve_SOURCES := \
lib/layer/itercache.c \
lib/layer/static.c \
lib/layer/stats.c \
lib/nsrep.c \
lib/context.c \
lib/resolve.c \
lib/zonecut.c \
......@@ -15,6 +16,7 @@ libkresolve_HEADERS := \
lib/layer/static.h \
lib/layer/stats.h \
lib/layer.h \
lib/nsrep.h \
lib/context.h \
lib/resolve.h \
lib/zonecut.h \
......
#include "lib/nsrep.h"
int kr_nsrep_score(const knot_dname_t *ns, struct kr_layer_param *param)
{
/* TODO: stub, always returns valid */
return KR_NS_VALID;
}
\ No newline at end of file
/* 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/>.
*/
#pragma once
#include "lib/layer.h"
enum kr_ns_score {
KR_NS_INVALID = 1,
KR_NS_VALID = 0
};
/*! \brief Return name server score (KR_NS_VALID is baseline, the higher the better).
* \param ns evaluated NS name
* \param param layer parameters
* \return enum kr_ns_score or higher positive value
*/
int kr_nsrep_score(const knot_dname_t *ns, struct kr_layer_param *param);
\ No newline at end of file
......@@ -18,6 +18,7 @@
#include <libknot/internal/mempool.h>
#include <libknot/processing/requestor.h>
#include <libknot/rrtype/rdname.h>
#include <libknot/descriptor.h>
#include <dnssec/random.h>
......@@ -66,13 +67,15 @@ static int invalidate_ns(struct kr_rplan *rplan, struct kr_query *qry)
/* Remove record(s) */
if (cached.rrs.rr_count == 0) {
(void) kr_cache_remove(txn, &cached);
kr_find_zone_cut(&qry->zone_cut, qry->sname, txn, qry->timestamp.tv_sec);
} else {
(void) kr_cache_insert(txn, &cached, qry->timestamp.tv_sec);
kr_set_zone_cut(&qry->zone_cut, cached.owner, knot_ns_name(&cached.rrs, 0));
}
knot_rrset_clear(&cached, rplan->pool);
/* Update zone cut and continue. */
return kr_find_zone_cut(&qry->zone_cut, qry->sname, txn, qry->timestamp.tv_sec);
return KNOT_EOK;
}
static int iterate(struct knot_requestor *requestor, struct kr_layer_param *param)
......@@ -91,8 +94,10 @@ static int iterate(struct knot_requestor *requestor, struct kr_layer_param *para
/* Invalid address for current zone cut. */
if (sockaddr_len((struct sockaddr *)&cur->zone_cut.addr) < 1) {
DEBUG_MSG("=> ns missing A/AAAA, invalidating\n");
return invalidate_ns(rplan, cur);
DEBUG_MSG("=> ns missing A/AAAA, fetching\n");
(void) kr_rplan_push(rplan, cur, cur->zone_cut.ns, KNOT_CLASS_IN, KNOT_RRTYPE_AAAA);
(void) kr_rplan_push(rplan, cur, cur->zone_cut.ns, KNOT_CLASS_IN, KNOT_RRTYPE_A);
return KNOT_EOK;
}
/* Prepare query resolution. */
......
......@@ -28,10 +28,16 @@ class Entry:
if code == 'opcode':
return self.__compare_val(expected.opcode(), msg.opcode())
elif code == 'qtype':
if len(expected.question) == 0:
return True
return self.__compare_val(expected.question[0].rdtype, msg.question[0].rdtype)
elif code == 'qname':
if len(expected.question) == 0:
return True
return self.__compare_val(expected.question[0].name, msg.question[0].name)
elif code == 'subdomain':
if len(expected.question) == 0:
return True
return self.__compare_sub(expected.question[0].name, msg.question[0].name)
elif code == 'flags':
return self.__compare_val(dns.flags.to_text(expected.flags), dns.flags.to_text(msg.flags))
......
......@@ -25,6 +25,34 @@ SECTION ADDITIONAL
K.ROOT-SERVERS.NET. IN A 193.0.14.129
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
net. IN NS
SECTION ANSWER
net. IN NS K.ROOT-SERVERS.NET.
SECTION ADDITIONAL
K.ROOT-SERVERS.NET. IN A 193.0.14.129
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
gtld-servers.net. IN NS
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
a.gtld-servers.net. IN AAAA
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
......
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