From: Marek VavruĊĦa Date: Sun, 15 Feb 2015 22:25:11 +0000 (+0100) Subject: lib: stub NS reputation scoring, use glue presence as score for iter X-Git-Tag: v1.0.0-beta1~304^2~4^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4930d1d2ff0ae711cbd257bd00ab46e9518d314d;p=thirdparty%2Fknot-resolver.git lib: stub NS reputation scoring, use glue presence as score for iter --- diff --git a/lib/layer/iterate.c b/lib/layer/iterate.c index a15c3292e..efeb1eec7 100644 --- a/lib/layer/iterate.c +++ b/lib/layer/iterate.c @@ -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; } diff --git a/lib/layer/iterate.h b/lib/layer/iterate.h index f9338c731..a5821ac9b 100644 --- a/lib/layer/iterate.h +++ b/lib/layer/iterate.h @@ -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); diff --git a/lib/libkresolve.mk b/lib/libkresolve.mk index 09a1badb4..9dddbb69b 100644 --- a/lib/libkresolve.mk +++ b/lib/libkresolve.mk @@ -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 \ diff --git a/lib/nsrep.c b/lib/nsrep.c new file mode 100644 index 000000000..bc19c28c1 --- /dev/null +++ b/lib/nsrep.c @@ -0,0 +1,7 @@ +#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 diff --git a/lib/nsrep.h b/lib/nsrep.h new file mode 100644 index 000000000..b92eda549 --- /dev/null +++ b/lib/nsrep.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2014 CZ.NIC, z.s.p.o. + + 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 . + */ + +#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 diff --git a/lib/resolve.c b/lib/resolve.c index 1ba465a50..b936185bc 100755 --- a/lib/resolve.c +++ b/lib/resolve.c @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -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. */ diff --git a/tests/pydnstest/scenario.py b/tests/pydnstest/scenario.py index 5d1d89f95..6170724e1 100644 --- a/tests/pydnstest/scenario.py +++ b/tests/pydnstest/scenario.py @@ -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)) diff --git a/tests/testdata/iter_minim_ns.rpl b/tests/testdata/iter_minim_ns.rpl index 34da53be6..da704dd4c 100644 --- a/tests/testdata/iter_minim_ns.rpl +++ b/tests/testdata/iter_minim_ns.rpl @@ -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