Commit 3e7844f8 authored by Marek Vavruša's avatar Marek Vavruša

lib/zonecut: use SBELT only when necessary, prefer cached information

before the algorithm was happy with root hints for all queries starting
at root, however they're often overloaded and result in timeouts
the updated code provides SBELT only for root NS query lookup and tries
to use cached information as much as possible
parent 83a2e2b6
......@@ -77,7 +77,7 @@ static int invalidate_ns(struct kr_rplan *rplan, struct kr_query *qry)
static int ns_fetch_cut(struct kr_query *qry, struct kr_request *req, bool secured)
{
int ret = 0;
int ret = kr_error(ENOENT);
/* Find closest zone cut from cache */
struct kr_cache_txn txn;
......@@ -92,8 +92,6 @@ static int ns_fetch_cut(struct kr_query *qry, struct kr_request *req, bool secur
ret = kr_zonecut_find_cached(req->ctx, &qry->zone_cut, qry->sname, &txn, qry->timestamp.tv_sec, secured);
}
kr_cache_txn_abort(&txn);
} else {
ret = kr_zonecut_set_sbelt(req->ctx, &qry->zone_cut);
}
return ret;
}
......@@ -122,6 +120,12 @@ static int ns_resolve_addr(struct kr_query *qry, struct kr_request *param)
}
/* Bail out if the query is already pending or dependency loop. */
if (!next_type || kr_rplan_satisfies(qry->parent, qry->ns.name, KNOT_CLASS_IN, next_type)) {
/* Fall back to SBELT if root server query fails. */
if (!next_type && qry->zone_cut.name[0] == '\0') {
DEBUG_MSG("=> fallback to root hints\n");
kr_zonecut_set_sbelt(ctx, &qry->zone_cut);
return kr_error(EAGAIN);
}
/* No IPv4 nor IPv6, flag server as unuseable. */
DEBUG_MSG("=> unresolvable NS address, bailing out\n");
qry->ns.reputation |= KR_NS_NOIP4 | KR_NS_NOIP6;
......@@ -134,9 +138,14 @@ static int ns_resolve_addr(struct kr_query *qry, struct kr_request *param)
if (!next) {
return kr_error(ENOMEM);
}
next->flags |= QUERY_AWAIT_CUT;
return kr_ok();
/* At the root level with no NS addresses, revert to SBELT. */
int ret = 0;
if (qry->zone_cut.name[0] == '\0') {
ret = kr_zonecut_set_sbelt(ctx, &qry->zone_cut);
} else {
next->flags |= QUERY_AWAIT_CUT;
}
return ret;
}
static int edns_put(knot_pkt_t *pkt)
......@@ -378,7 +387,19 @@ static int zone_cut_check(struct kr_request *request, struct kr_query *qry, knot
}
int ret = ns_fetch_cut(qry, request, (qry->flags & QUERY_DNSSEC_WANT));
if (ret != 0) {
return KNOT_STATE_FAIL;
/* No cached cut found, start from SBELT and issue priming query. */
if (ret == kr_error(ENOENT)) {
DEBUG_MSG("=> root priming query\n");
ret = kr_zonecut_set_sbelt(request->ctx, &qry->zone_cut);
if (ret != 0) {
return KNOT_STATE_FAIL;
}
zone_cut_subreq(rplan, qry, qry->zone_cut.name, KNOT_RRTYPE_NS);
qry->flags &= ~QUERY_AWAIT_CUT;
return KNOT_STATE_DONE;
} else {
return KNOT_STATE_FAIL;
}
}
/* Update minimized QNAME if zone cut changed */
if (qry->zone_cut.name[0] != '\0' && !(qry->flags & QUERY_NO_MINIMIZE)) {
......@@ -494,7 +515,8 @@ int kr_resolve_produce(struct kr_request *request, struct sockaddr **dst, int *t
/* Resolve address records */
if (qry->ns.addr[0].ip.sa_family == AF_UNSPEC) {
if (ns_resolve_addr(qry, request) != 0) {
int ret = ns_resolve_addr(qry, request);
if (ret != 0) {
qry->flags &= ~(QUERY_AWAIT_IPV6|QUERY_AWAIT_IPV4|QUERY_TCP);
goto ns_election; /* Must try different NS */
}
......
......@@ -257,32 +257,29 @@ int kr_zonecut_set_sbelt(struct kr_context *ctx, struct kr_zonecut *cut)
}
update_cut_name(cut, U8(""));
map_walk(&cut->nsset, free_addr_set, cut->pool);
map_clear(&cut->nsset);
/* Copy root hints from resolution context. */
int ret = 0;
if (ctx->root_hints.nsset.root) {
int ret = kr_zonecut_copy(cut, &ctx->root_hints);
if (ret == 0) {
ret = kr_zonecut_copy_trust(cut, &ctx->root_hints);
}
if (ret == 0) {
return ret;
}
}
/* Copy compiled-in root hints */
for (unsigned i = 0; i < HINT_COUNT; ++i) {
const struct hint_info *hint = &SBELT[i];
knot_rdata_t rdata[knot_rdata_array_size(HINT_ADDRLEN)];
knot_rdata_init(rdata, HINT_ADDRLEN, hint->addr, 0);
int ret = kr_zonecut_add(cut, hint->name, rdata);
if (ret != 0) {
return ret;
ret = kr_zonecut_copy(cut, &ctx->root_hints);
} else {
/* Copy compiled-in root hints */
for (unsigned i = 0; i < HINT_COUNT; ++i) {
const struct hint_info *hint = &SBELT[i];
knot_rdata_t rdata[knot_rdata_array_size(HINT_ADDRLEN)];
knot_rdata_init(rdata, HINT_ADDRLEN, hint->addr, 0);
ret = kr_zonecut_add(cut, hint->name, rdata);
if (ret != 0) {
break;
}
}
}
/* Set trust anchor. */
knot_rrset_free(&cut->trust_anchor, cut->pool);
return kr_ok();
return ret;
}
/** Fetch address for zone cut. */
......@@ -330,11 +327,6 @@ static int fetch_ns(struct kr_context *ctx, struct kr_zonecut *cut, const knot_d
}
}
/* Always keep SBELT as a backup for root */
if (name[0] == '\0') {
kr_zonecut_set_sbelt(ctx, cut);
}
return kr_ok();
}
......@@ -411,6 +403,5 @@ int kr_zonecut_find_cached(struct kr_context *ctx, struct kr_zonecut *cut, const
name = knot_wire_next_label(name, NULL);
}
/* Name server not found, start with SBELT. */
return kr_zonecut_set_sbelt(ctx, cut);
return kr_error(ENOENT);
}
......@@ -126,7 +126,7 @@ int kr_zonecut_set_sbelt(struct kr_context *ctx, struct kr_zonecut *cut);
* @param txn cache transaction (read)
* @param timestamp transaction timestamp
* @param secured search nearest containing a DNSKEY
* @return 0 or error code
* @return 0 or error code (ENOENT if it doesn't find anything)
*/
int kr_zonecut_find_cached(struct kr_context *ctx, struct kr_zonecut *cut, const knot_dname_t *name,
struct kr_cache_txn *txn, uint32_t timestamp, bool secured);
net = { '{{SELF_ADDR}}' }
modules = {'stats', 'policy', 'hints'}
cache.size = 1*MB
hints.root({['k.root-servers.net'] = '{{ROOT_ADDR}}'})
option('NO_MINIMIZE', {{NO_MINIMIZE}})
option('ALLOW_LOCAL', true)
hints.config('/dev/null')
hints.root({['k.root-servers.net'] = '{{ROOT_ADDR}}'})
trust_anchors.add('{{TRUST_ANCHOR}}')
verbose(true)
......
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