Commit 5b357f3d authored by Grigorii Demidov's avatar Grigorii Demidov Committed by Marek Vavrusa

lib/layer: CNAME chain construction improvement

parent f9ffeca9
...@@ -53,6 +53,7 @@ static inline int __attribute__((__cold__)) kr_error(int x) { ...@@ -53,6 +53,7 @@ static inline int __attribute__((__cold__)) kr_error(int x) {
#define KR_CONN_RTT_MAX 3000 /* Timeout for network activity */ #define KR_CONN_RTT_MAX 3000 /* Timeout for network activity */
#define KR_CONN_RETRY 300 /* Retry interval for network activity */ #define KR_CONN_RETRY 300 /* Retry interval for network activity */
#define KR_ITER_LIMIT 50 /* Built-in iterator limit */ #define KR_ITER_LIMIT 50 /* Built-in iterator limit */
#define KR_CNAME_CHAIN_LIMIT 40 /* Built-in maximum CNAME chain length */
/* /*
* Defines. * Defines.
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <libknot/descriptor.h> #include <libknot/descriptor.h>
#include <libknot/rrtype/rdname.h> #include <libknot/rrtype/rdname.h>
#include <libknot/rrtype/rrsig.h>
#include "lib/layer/iterate.h" #include "lib/layer/iterate.h"
#include "lib/resolve.h" #include "lib/resolve.h"
...@@ -110,19 +111,6 @@ int kr_response_classify(knot_pkt_t *pkt) ...@@ -110,19 +111,6 @@ int kr_response_classify(knot_pkt_t *pkt)
} }
} }
static void follow_cname_chain(const knot_dname_t **cname, const knot_rrset_t *rr,
struct kr_query *cur)
{
if (rr->type == KNOT_RRTYPE_CNAME) {
const knot_dname_t *next_cname = knot_cname_name(&rr->rrs);
if (next_cname)
*cname = next_cname;
} else if (rr->type != KNOT_RRTYPE_RRSIG) {
/* Terminate CNAME chain (if not RRSIG). */
*cname = cur->sname;
}
}
/** @internal Filter ANY or loopback addresses. */ /** @internal Filter ANY or loopback addresses. */
static bool is_valid_addr(const uint8_t *addr, size_t len) static bool is_valid_addr(const uint8_t *addr, size_t len)
{ {
...@@ -346,7 +334,6 @@ static void finalize_answer(knot_pkt_t *pkt, struct kr_query *qry, struct kr_req ...@@ -346,7 +334,6 @@ static void finalize_answer(knot_pkt_t *pkt, struct kr_query *qry, struct kr_req
static int process_answer(knot_pkt_t *pkt, struct kr_request *req) static int process_answer(knot_pkt_t *pkt, struct kr_request *req)
{ {
struct kr_query *query = req->current_query; struct kr_query *query = req->current_query;
/* Response for minimized QNAME. /* Response for minimized QNAME.
* NODATA => may be empty non-terminal, retry (found zone cut) * NODATA => may be empty non-terminal, retry (found zone cut)
* NOERROR => found zone cut, retry * NOERROR => found zone cut, retry
...@@ -371,39 +358,75 @@ static int process_answer(knot_pkt_t *pkt, struct kr_request *req) ...@@ -371,39 +358,75 @@ static int process_answer(knot_pkt_t *pkt, struct kr_request *req)
/* Process answer type */ /* Process answer type */
const knot_pktsection_t *an = knot_pkt_section(pkt, KNOT_ANSWER); const knot_pktsection_t *an = knot_pkt_section(pkt, KNOT_ANSWER);
bool follow_chain = (query->stype != KNOT_RRTYPE_CNAME); const knot_dname_t *cname = NULL;
const knot_dname_t *cname = query->sname; const knot_dname_t *pending_cname = query->sname;
for (unsigned i = 0; i < an->count; ++i) { unsigned cname_chain_len = 0;
/* @todo construct a CNAME chain closure and accept all names from that set */ while (pending_cname) {
const knot_rrset_t *rr = knot_pkt_rr(an, i); /* CNAME was found at previous iteration, but records may not follow the correct order.
if (!knot_dname_is_equal(rr->owner, query->sname) && * Try to find records for pending_cname owner from section start. */
!(follow_chain && knot_dname_is_equal(rr->owner, cname))) { cname = pending_cname;
continue; pending_cname = NULL;
} for (unsigned i = 0; i < an->count; ++i) {
unsigned hint = 0; const knot_rrset_t *rr = knot_pkt_rr(an, i);
if(knot_dname_is_equal(cname, knot_pkt_qname(req->answer))) { if (!knot_dname_is_equal(rr->owner, cname)) {
hint = KNOT_COMPR_HINT_QNAME; continue;
} }
int state = is_final ? update_answer(rr, hint, req->answer) : update_parent(rr, query); /* Process records matching current SNAME */
if (state == KNOT_STATE_FAIL) { unsigned hint = 0;
return state; if(knot_dname_is_equal(cname, knot_pkt_qname(req->answer))) {
} hint = KNOT_COMPR_HINT_QNAME;
/* Follow chain only within current cut (if secure). */ }
if (follow_chain) { int state = is_final ? update_answer(rr, hint, req->answer) : update_parent(rr, query);
follow_cname_chain(&cname, rr, query); if (state == KNOT_STATE_FAIL) {
if (!(query->flags & QUERY_DNSSEC_WANT) || !knot_dname_in(query->zone_cut.name, cname)) { return state;
follow_chain = false; }
/* Jump to next CNAME target */
if ((query->stype == KNOT_RRTYPE_CNAME) || (rr->type != KNOT_RRTYPE_CNAME)) {
continue;
}
cname_chain_len += 1;
pending_cname = knot_cname_name(&rr->rrs);
if (!pending_cname) {
break;
}
if (cname_chain_len > an->count || cname_chain_len > KR_CNAME_CHAIN_LIMIT) {
DEBUG_MSG("<= too long cname chain\n");
return KNOT_STATE_FAIL;
}
/* If secure, don't use pending_cname immediately.
* There are can be RRSIG for "old" cname.
*/
if (query->flags & QUERY_DNSSEC_WANT) {
/* Follow chain only within current cut (if secure). */
if (pending_cname && !knot_dname_in(query->zone_cut.name, pending_cname)) {
pending_cname = NULL;
}
} else {
/* Try to find next cname */
cname = pending_cname;
} }
} }
} }
/* Make sure that this is an authoritative naswer (even with AA=0) for other layers */ /* Make sure that this is an authoritative answer (even with AA=0) for other layers */
knot_wire_set_aa(pkt->wire); knot_wire_set_aa(pkt->wire);
/* Either way it resolves current query. */ /* Either way it resolves current query. */
query->flags |= QUERY_RESOLVED; query->flags |= QUERY_RESOLVED;
/* Follow canonical name as next SNAME. */ /* Follow canonical name as next SNAME. */
if (!knot_dname_is_equal(cname, query->sname)) { if (!knot_dname_is_equal(cname, query->sname)) {
DEBUG_MSG("<= cname chain, following\n"); DEBUG_MSG("<= cname chain, following\n");
/* Check if already resolved */
if (cname && !knot_dname_is_equal(cname, query->sname)) {
for (int i = 0; i < req->rplan.resolved.len; ++i) {
struct kr_query * q = req->rplan.resolved.at[i];
if (q->sclass == query->sclass &&
q->stype == query->stype &&
knot_dname_is_equal(q->sname, cname)) {
DEBUG_MSG("<= cname chain loop\n");
return KNOT_STATE_FAIL;
}
}
}
struct kr_query *next = kr_rplan_push(&req->rplan, query->parent, cname, query->sclass, query->stype); struct kr_query *next = kr_rplan_push(&req->rplan, query->parent, cname, query->sclass, query->stype);
if (!next) { if (!next) {
return KNOT_STATE_FAIL; return KNOT_STATE_FAIL;
......
Subproject commit 8b1a6c6873067d78e88adda48d381142aa107bd4 Subproject commit e73a0854552d94e8bc5306e75c3a2229bc739531
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