From: Marek VavruĊĦa Date: Tue, 5 Aug 2014 20:15:36 +0000 (+0200) Subject: layer/iterate: basic rfc1034-style resolution X-Git-Tag: v1.0.0-beta1~440 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=770720b219a5d79ea91165e2155198ce3daba6d9;p=thirdparty%2Fknot-resolver.git layer/iterate: basic rfc1034-style resolution --- diff --git a/lib/layer/iterate.c b/lib/layer/iterate.c index 5662099b3..b2a99de5e 100644 --- a/lib/layer/iterate.c +++ b/lib/layer/iterate.c @@ -13,12 +13,144 @@ See the License for the specific language governing permissions and limitations under the License. */ +#include + #include #include #include +#include +#include #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. */ }; diff --git a/lib/layer/iterate.h b/lib/layer/iterate.h index e8f9f7e02..3f17c3ceb 100644 --- a/lib/layer/iterate.h +++ b/lib/layer/iterate.h @@ -15,17 +15,8 @@ limitations under the License. #pragma once -#include -#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; -};