Commit 37c7be97 authored by Marek Vavrusa's avatar Marek Vavrusa

Implemented CNAME resolution with loop checks.

parent be9f5f06
......@@ -108,7 +108,7 @@ const knot_zone_t *ns_get_zone_for_qname(knot_zonedb_t *zdb,
* \return The synthetized RRSet (this is a newly created RRSet, remember to
* free it).
*/
static knot_rrset_t *ns_synth_from_wildcard(
knot_rrset_t *ns_synth_from_wildcard(
const knot_rrset_t *wildcard_rrset, const knot_dname_t *qname)
{
knot_rrset_t *rrset = NULL;
......@@ -184,7 +184,7 @@ dbg_ns_exec_verb(
* \return KNOT_ENOMEM
* \return KNOT_ESPACE
*/
static int ns_add_rrsigs(knot_rrset_t *rrset, knot_pkt_t *resp,
int ns_add_rrsigs(knot_rrset_t *rrset, knot_pkt_t *resp,
const knot_dname_t *name,
uint32_t flags)
{
......@@ -203,13 +203,16 @@ static int ns_add_rrsigs(knot_rrset_t *rrset, knot_pkt_t *resp,
|| knot_pkt_qtype(resp) == KNOT_RRTYPE_ANY)
&& (rrsigs = knot_rrset_get_rrsigs(rrset)) != NULL) {
if (name != NULL) {
knot_rrset_t *rrsigs_orig = rrsigs;
int ret = ns_check_wildcard(name, resp, &rrsigs);
if (ret != KNOT_EOK) {
dbg_ns("Failed to process wildcard: %s\n",
knot_strerror(ret));
return ret;
}
/* #10 will leak if synthetized new */
if (rrsigs != rrsigs_orig) {
flags |= KNOT_PF_FREE;
}
}
return knot_pkt_put(resp, 0, rrsigs, flags|KNOT_PF_CHECKDUP);
}
......@@ -476,14 +479,20 @@ dbg_ns_exec_verb(
if (knot_rrset_rdata_rr_count(rrset) > 0
|| knot_rrset_type(rrset) == KNOT_RRTYPE_APL) {
knot_rrset_t *rrset_orig = rrset;
ret = ns_check_wildcard(name, resp, &rrset);
if (ret != KNOT_EOK) {
dbg_ns("Failed to process wildcard.\n");
break;
}
unsigned flags = 0;
if (rrset != rrset_orig) {
flags |= KNOT_PF_FREE;
}
assert(KNOT_PKT_IN_AN(resp));
ret = knot_pkt_put(resp, 0, rrset, 0);
ret = knot_pkt_put(resp, 0, rrset, flags);
if (ret != KNOT_EOK) {
dbg_ns("Failed add Answer RRSet: %s\n",
knot_strerror(ret));
......@@ -526,14 +535,20 @@ dbg_ns_exec_verb(
continue;
}
knot_rrset_t *rrset_orig = rrset;
ret = ns_check_wildcard(name, resp, &rrset);
if (ret != KNOT_EOK) {
dbg_ns("Failed to process wildcard.\n");
break;
}
unsigned flags = 0;
if (rrset != rrset_orig) {
flags |= KNOT_PF_FREE;
}
assert(KNOT_PKT_IN_AN(resp));
ret = knot_pkt_put(resp, 0, rrset, 0);
ret = knot_pkt_put(resp, 0, rrset, flags);
if (ret != KNOT_EOK) {
dbg_ns("Failed add Answer RRSet: %s\n",
knot_strerror(ret));
......@@ -553,14 +568,20 @@ dbg_ns_exec_verb(
if (rrset != NULL && knot_rrset_rdata_rr_count(rrset)) {
dbg_ns_verb("Found RRSet of type %u\n", type);
knot_rrset_t *rrset2_orig = rrset2;
ret = ns_check_wildcard(name, resp, &rrset2);
if (ret != KNOT_EOK) {
dbg_ns("Failed to process wildcard.\n");
break;
}
unsigned flags = 0;
if (rrset2 != rrset2_orig) {
flags |= KNOT_PF_FREE;
}
assert(KNOT_PKT_IN_AN(resp));
ret = knot_pkt_put(resp, 0, rrset2, 0);
ret = knot_pkt_put(resp, 0, rrset2, flags);
if (ret != KNOT_EOK) {
dbg_ns("Failed add Answer RRSet: %s\n",
knot_strerror(ret));
......@@ -674,9 +695,14 @@ dbg_ns_exec(
return ret;
}
unsigned flags = KNOT_PF_NOTRUNC|KNOT_PF_CHECKDUP;
if (rrset_add2 != rrset_add) {
flags |= KNOT_PF_FREE;
}
assert(KNOT_PKT_IN_AR(resp));
ret = knot_pkt_put(
resp, compr_hint, rrset_add2, KNOT_PF_NOTRUNC|KNOT_PF_CHECKDUP);
resp, compr_hint, rrset_add2, flags);
if (ret != KNOT_EOK) {
dbg_ns("Failed to add A RRSet to "
......@@ -711,9 +737,14 @@ dbg_ns_exec(
return ret;
}
unsigned flags = KNOT_PF_NOTRUNC|KNOT_PF_CHECKDUP;
if (rrset_add2 != rrset_add) {
flags |= KNOT_PF_FREE;
}
assert(KNOT_PKT_IN_AR(resp));
ret = knot_pkt_put(
resp, compr_hint, rrset_add2, KNOT_PF_NOTRUNC|KNOT_PF_CHECKDUP);
resp, compr_hint, rrset_add2, flags);
if (ret != KNOT_EOK) {
dbg_ns("Failed to add AAAA RRSet to "
......@@ -4117,6 +4148,10 @@ int ns_proc_out(uint8_t *wire, uint16_t *wire_len, ns_proc_context_t *ctx)
}
*wire_len = pkt->size;
/* Free packet. */
knot_pkt_free(&pkt);
return ctx->state;
}
......
......@@ -418,6 +418,11 @@ int ns_referral(const knot_node_t *node,
knot_pkt_t *resp,
uint16_t qtype);
knot_rrset_t *ns_synth_from_wildcard(const knot_rrset_t *wildcard_rrset, const knot_dname_t *qname);
int ns_add_rrsigs(knot_rrset_t *rrset, knot_pkt_t *resp,
const knot_dname_t *name,
uint32_t flags);
/* #10 >>> Exposed API. */
/* #10 <<< Next-gen API. */
......
......@@ -6,15 +6,17 @@
#include "common/descriptor.h"
#include "libknot/common.h"
#include "libknot/consts.h"
#include "libknot/rdata.h"
#include "libknot/util/debug.h"
#include "libknot/nameserver/chaos.h"
struct query_data {
int state;
uint16_t rcode;
uint16_t rcode_tsig;
knot_pkt_t *pkt;
const knot_node_t *node, *encloser, *previous;
list_t wildcards;
mm_ctx_t *mm;
};
/* Forward decls. */
......@@ -44,7 +46,13 @@ int ns_proc_query_begin(ns_proc_context_t *ctx)
assert(ctx);
ctx->type = NS_PROC_QUERY_ID;
ctx->data = ctx->mm.alloc(ctx->mm.ctx, sizeof(struct query_data));
memset(ctx->data, 0, sizeof(struct query_data));
struct query_data *data = QUERY_DATA(ctx);
memset(data, 0, sizeof(struct query_data));
data->mm = &ctx->mm;
/* Initialize list. */
init_list(&data->wildcards);
/* Await packet. */
return NS_PROC_MORE;
......@@ -56,7 +64,12 @@ int ns_proc_query_reset(ns_proc_context_t *ctx)
assert(ctx);
struct query_data *data = QUERY_DATA(ctx);
knot_pkt_free(&data->pkt);
memset(data, 0, sizeof(struct query_data));
data->rcode = KNOT_RCODE_NOERROR;
data->rcode_tsig = 0;
data->node = data->encloser = data->previous = NULL;
/* Free wildcard list. */
ptrlist_free(&data->wildcards, data->mm);
/* Await packet. */
return NS_PROC_MORE;
......@@ -283,6 +296,90 @@ enum {
ERROR
};
int in_zone_name_cname(knot_pkt_t *pkt, const knot_dname_t **name, struct query_data *qdata)
{
dbg_ns("%s(%p, %p, %p)\n", __func__, name, pkt, qdata);
const knot_node_t *cname_node = qdata->node;
knot_rrset_t *cname_rr = knot_node_get_rrset(qdata->node, KNOT_RRTYPE_CNAME);
knot_rrset_t *rr_to_add = cname_rr;
unsigned flags = 0;
int ret = KNOT_EOK;
assert(cname_rr != NULL);
/* Is node a wildcard? */
if (knot_dname_is_wildcard(cname_node->owner)) {
/* Check if is not in wildcard nodes (loop). */
dbg_ns("%s: CNAME node %p is wildcard\n", __func__, cname_node);
if (ptrlist_contains(&qdata->wildcards, cname_node)) {
dbg_ns("%s: node %p already visited => CNAME loop\n",
__func__, cname_node);
return HIT;
}
/* Put to wildcard node list. */
if (ptrlist_add(&qdata->wildcards, cname_node, qdata->mm) == NULL) {
qdata->rcode = KNOT_RCODE_SERVFAIL;
return ERROR;
}
/* Synthetic RRSet. */
rr_to_add = ns_synth_from_wildcard(cname_rr, *name);
/* Free RRSet with packet. */
flags |= KNOT_PF_FREE;
} else {
/* Normal CNAME name, check for duplicate. */
flags |= KNOT_PF_CHECKDUP;
}
/* Now, try to put CNAME to answer. */
ret = knot_pkt_put(pkt, 0, rr_to_add, flags);
if (ret != KNOT_EOK) {
/* Free if synthetized. */
if (rr_to_add != cname_rr) {
knot_rrset_deep_free(&rr_to_add, 1);
}
/* Duplicate found, end resolving chain. */
if (ret == KNOT_ENORRSET) {
dbg_ns("%s: RR %p already inserted => CNAME loop\n",
__func__, rr_to_add);
return HIT;
} else {
qdata->rcode = KNOT_RCODE_SERVFAIL;
return ERROR;
}
}
/* Add RR signatures (from original RR). */
ret = ns_add_rrsigs(cname_rr, pkt, *name, 0);
if (ret != KNOT_EOK) {
dbg_ns("%s: couldn't add rrsigs for CNAME RRSet %p\n",
__func__, cname_rr);
qdata->rcode = KNOT_RCODE_SERVFAIL;
return ERROR;
}
/* Now follow the next CNAME TARGET. */
*name = knot_rdata_cname_name(cname_rr);
#ifdef KNOT_NS_DEBUG
char *cname_str = knot_dname_to_str(cname_node->owner);
char *target_str = knot_dname_to_str(*name);
dbg_ns("%s: FOLLOW '%s' -> '%s'\n", __func__, cname_str, target_str);
free(cname_str);
free(target_str);
#endif /* KNOT_NS_DEBUG */
/* Invalidate current node. */
qdata->node = qdata->encloser = qdata->previous = NULL;
return FOLLOW;
}
static int in_zone_name_found(knot_pkt_t *pkt, const knot_dname_t **name,
struct query_data *qdata)
{
......@@ -292,9 +389,7 @@ static int in_zone_name_found(knot_pkt_t *pkt, const knot_dname_t **name,
if (knot_node_rrset(qdata->node, KNOT_RRTYPE_CNAME) != NULL
&& qtype != KNOT_RRTYPE_CNAME && qtype != KNOT_RRTYPE_RRSIG) {
dbg_ns("%s: solving CNAME\n", __func__);
qdata->rcode = KNOT_RCODE_NOTIMPL;
return ERROR;
assert(0); /*! \todo Implement CNAME solving. */
return in_zone_name_cname(pkt, name, qdata);
}
// now we have the node for answering
......
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