]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
layer/iterate: basic rfc1034-style resolution
authorMarek Vavruša <marek.vavrusa@nic.cz>
Tue, 5 Aug 2014 20:15:36 +0000 (22:15 +0200)
committerMarek Vavruša <marek.vavrusa@nic.cz>
Tue, 5 Aug 2014 20:15:36 +0000 (22:15 +0200)
lib/layer/iterate.c
lib/layer/iterate.h

index 5662099b3a0595d133a9a802632044b1ffd30825..b2a99de5ef4ceea5fa2e34c190d45fecb0b5c2fe 100644 (file)
@@ -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. */
 };
 
index e8f9f7e0207164cd226f050378e78799072f75ce..3f17c3ceb05448ba1d80c4eba1ffa4f2cfa32efd 100644 (file)
@@ -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;
-};