Skip to content
Snippets Groups Projects
Commit 770720b2 authored by Marek Vavruša's avatar Marek Vavruša
Browse files

layer/iterate: basic rfc1034-style resolution

parent 8a0e353e
No related branches found
No related tags found
No related merge requests found
......@@ -13,12 +13,144 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
#include <sys/time.h>
#include <libknot/descriptor.h>
#include <libknot/rrtype/rdname.h>
#include <libknot/rrtype/aaaa.h>
#include <libknot/processing/requestor.h>
#include <libknot/dnssec/random.h>
#include "lib/layer/iterate.h"
static int glue_record(knot_pkt_t *pkt, const knot_dname_t *dp, struct sockaddr *sa)
{
/* TODO: API call for find() */
const knot_rrset_t *glue_rr = NULL;
const knot_pktsection_t *ar = knot_pkt_section(pkt, KNOT_ADDITIONAL);
for (unsigned i = 0; i < ar->count; ++i) {
if (knot_dname_is_equal(dp, ar->rr[i].owner)) {
glue_rr = &ar->rr[i];
break;
}
}
/* Delegation, without glue record. */
if (glue_rr == NULL) {
return -1;
}
/* Retrieve an address from glue record. */
switch(glue_rr->type) {
case KNOT_RRTYPE_A:
knot_a_addr(&glue_rr->rrs, 0, (struct sockaddr_in *)sa);
break;
case KNOT_RRTYPE_AAAA:
knot_aaaa_addr(&glue_rr->rrs, 0, (struct sockaddr_in6 *)sa);
break;
default:
return -1;
}
sockaddr_port_set((struct sockaddr_storage *)sa, 53);
return 0;
}
static int evaluate_dp(const knot_dname_t *dp, knot_pkt_t *pkt, struct layer_param *param)
{
struct kr_context *resolve = param->ctx;
/* Check if there's a glue for the record. */
struct sockaddr_storage ss;
int ret = glue_record(pkt, dp, (struct sockaddr *)&ss);
if (ret != 0) {
return -1;
}
/* Add delegation to the SLIST. */
kr_slist_add(resolve, dp, (struct sockaddr *)&ss);
return 0;
}
static int resolve_nonauth(knot_pkt_t *pkt, struct layer_param *param)
{
const knot_pktsection_t *ns = knot_pkt_section(pkt, KNOT_AUTHORITY);
for (unsigned i = 0; i < ns->count; ++i) {
if (ns->rr[i].type == KNOT_RRTYPE_NS) {
const knot_dname_t *dp = knot_ns_name(&ns->rr[i].rrs, 0);
int ret = evaluate_dp(dp, pkt, param);
if (ret != 0) {
return NS_PROC_FAIL;
}
}
}
return NS_PROC_DONE;
}
static void resolve_cname(const knot_rrset_t *rr, struct layer_param *param)
{
struct kr_context *resolve = param->ctx;
/* Follow chain from SNAME. */
if (knot_dname_is_equal(rr->owner, resolve->sname)) {
resolve->state = NS_PROC_MORE;
resolve->sname = knot_dname_copy(knot_cname_name(&rr->rrs), resolve->mm);
}
}
static int resolve_auth(knot_pkt_t *pkt, struct layer_param *param)
{
struct kr_context *resolve = param->ctx;
struct kr_result *result = param->result;
knot_pkt_t *ans = result->ans;
/* Store flags. */
knot_wire_set_rcode(ans->wire, knot_wire_get_rcode(pkt->wire));
/* Add results to the final packet. */
/* TODO: API call */
knot_pkt_begin(ans, KNOT_ANSWER);
const knot_pktsection_t *an = knot_pkt_section(pkt, KNOT_ANSWER);
for (unsigned i = 0; i < an->count; ++i) {
const knot_rrset_t *rr = &an->rr[i];
int ret = knot_pkt_put(ans, COMPR_HINT_NONE, rr, 0);
if (ret != 0) {
knot_wire_set_tc(ans->wire);
return NS_PROC_FAIL;
}
/* Check canonical name. */
/* TODO: these may not come in order, more thorough check is needed */
if (rr->type == KNOT_RRTYPE_CNAME) {
resolve_cname(rr, param);
}
}
/* Finished for the original SNAME. */
resolve->state = NS_PROC_DONE;
/* Store stats. */
gettimeofday(&result->t_end, NULL);
return NS_PROC_DONE;
}
/*! \brief Error handling, RFC1034 5.3.3, 4d. */
static int resolve_error(knot_pkt_t *pkt, struct layer_param *param)
{
return NS_PROC_FAIL;
}
/*! \brief Answer is paired to query. */
static bool is_answer_to_query(const knot_pkt_t *answer, struct kr_context *resolve)
{
return resolve->next_id == knot_wire_get_id(answer->wire) &&
resolve->sclass == knot_pkt_qclass(answer) &&
resolve->stype == knot_pkt_qtype(answer) &&
knot_dname_is_equal(resolve->sname, knot_pkt_qname(answer));
}
/* State-less single resolution iteration step, not needed. */
static int reset(knot_process_t *ctx) { return NS_PROC_MORE; }
static int finish(knot_process_t *ctx) { return NS_PROC_NOOP; }
......@@ -27,89 +159,60 @@ static int finish(knot_process_t *ctx) { return NS_PROC_NOOP; }
static int begin(knot_process_t *ctx, void *module_param)
{
ctx->data = module_param;
return NS_PROC_MORE;
return NS_PROC_FULL;
}
/* Resolve input query or continue resolution with followups. */
/*! \brief Resolve input query or continue resolution with followups.
*
* This roughly corresponds to RFC1034, 5.3.3 4a-d.
*/
static int resolve(knot_pkt_t *pkt, knot_process_t *ctx)
{
assert(pkt && ctx);
struct layer_iterate_param *param = ctx->data;
struct kresolve_ctx *resolution = param->ctx;
struct kresolve_result *result = param->result;
/* Is the answer authoritative? */
bool is_aa = knot_wire_get_aa(pkt->wire);
printf("got packet: AA? %d RRs %d RCODE %d\n", is_aa, pkt->rrset_count, knot_wire_get_rcode(pkt->wire));
if (is_aa) {
/* Add results to the answer section. */
const knot_pktsection_t *an = knot_pkt_section(pkt, KNOT_ANSWER);
for (unsigned i = 0; i < an->count; ++i) {
knot_rrset_t *copy = knot_rrset_copy(an->rr + i, resolution->mm);
result->data[result->count] = copy;
result->count += 1;
}
/* Store canonical name. */
result->cname = knot_dname_copy(knot_pkt_qname(pkt), resolution->mm);
/* TODO: store flags */
/* Finished. */
resolution->state = NS_PROC_DONE;
} else {
/* Is there a NS to add into SLIST? */
knot_pktsection_t *ns = knot_pkt_section(pkt, KNOT_AUTHORITY);
result->ns.name = NULL;
memset(&result->ns.addr, 0, sizeof(result->ns.addr));
for (unsigned i = 0; i < ns->count; ++i) {
if (ns->rr[i].type == KNOT_RRTYPE_NS) {
result->ns.name = knot_ns_name(&ns->rr[i].rrs, 0);
/* TODO: fill SLIST */
printf("next nameserver: %s\n", knot_dname_to_str(result->ns.name));
break;
}
}
struct layer_param *param = ctx->data;
/* No next nameserver? */
if (result->ns.name == NULL) {
printf("no next nameserver\n");
resolution->state = NS_PROC_FAIL;
return NS_PROC_FAIL;
}
/* Check for packet processing errors first. */
if (pkt->parsed < pkt->size) {
return resolve_error(pkt, param);
}
/* Is the address in additional records? */
knot_pktsection_t *ar = knot_pkt_section(pkt, KNOT_ADDITIONAL);
for (unsigned i = 0; i < ar->count; ++i) {
printf("checking additional: %s type %d\n", knot_dname_to_str(ar->rr[i].owner), ar->rr[i].type);
if (knot_dname_is_equal(result->ns.name, ar->rr[i].owner)) {
/* Fill next server address. */
switch(ar->rr[i].type) {
case KNOT_RRTYPE_A:
knot_a_addr(&ar->rr[i].rrs, 0, &result->ns.addr);
break;
case KNOT_RRTYPE_AAAA:
knot_aaaa_addr(&ar->rr[i].rrs, 0, &result->ns.addr);
break;
default:
resolution->state = NS_PROC_FAIL;
return NS_PROC_FAIL;
}
/* Fill port. */
sockaddr_port_set(&result->ns.addr, 53);
break;
}
}
/* Is this the droid we're looking for? */
if (!is_answer_to_query(pkt, param->ctx)) {
return resolve_error(pkt, param);
}
char tmpbuf[512];
sockaddr_tostr(&result->ns.addr, tmpbuf, 512);
printf("next addr: %s\n", tmpbuf);
/* Check response code. */
switch(knot_wire_get_rcode(pkt->wire)) {
case KNOT_RCODE_NOERROR:
case KNOT_RCODE_NXDOMAIN:
break; /* OK */
default:
return resolve_error(pkt, param);
}
printf("done\n");
/* Is the answer delegation? */
if (!knot_wire_get_aa(pkt->wire)) {
return resolve_nonauth(pkt, param);
}
return NS_PROC_DONE;
return resolve_auth(pkt, param);
}
static int issue(knot_pkt_t *pkt, knot_process_t *ctx)
{
assert(pkt && ctx);
struct layer_param *param = ctx->data;
struct kr_context *resolve = param->ctx;
struct kr_result *result = param->result;
knot_pkt_clear(pkt);
knot_pkt_put_question(pkt, resolve->sname, resolve->sclass, resolve->stype);
knot_wire_set_id(pkt->wire, knot_random_uint16_t());
resolve->next_id = knot_wire_get_id(pkt->wire);
result->nr_queries += 1;
return NS_PROC_MORE;
}
/*! \brief Module implementation. */
......@@ -118,7 +221,7 @@ static const knot_process_module_t LAYER_ITERATE_MODULE = {
&reset,
&finish,
&resolve,
&knot_process_noop, /* No output. */
&issue,
&knot_process_noop /* No error processing. */
};
......
......@@ -15,17 +15,8 @@ limitations under the License.
#pragma once
#include <libknot/processing/process.h>
#include "lib/context.h"
#include "lib/layer.h"
/* Processing module implementation. */
const knot_process_module_t *layer_iterate_module(void);
#define LAYER_ITERATE layer_iterate_module()
/*!
* \brief Processing module parameters.
*/
struct layer_iterate_param {
struct kresolve_ctx *ctx;
struct kresolve_result *result;
};
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment