#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)
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;
}
}
}
- /* 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;
}
* \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);
lib/layer/itercache.c \
lib/layer/static.c \
lib/layer/stats.c \
+ lib/nsrep.c \
lib/context.c \
lib/resolve.c \
lib/zonecut.c \
lib/layer/static.h \
lib/layer/stats.h \
lib/layer.h \
+ lib/nsrep.h \
lib/context.h \
lib/resolve.h \
lib/zonecut.h \
--- /dev/null
+#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
--- /dev/null
+/* 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
#include <libknot/internal/mempool.h>
#include <libknot/processing/requestor.h>
+#include <libknot/rrtype/rdname.h>
#include <libknot/descriptor.h>
#include <dnssec/random.h>
/* 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)
/* 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. */
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))
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