]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
zone_forward: prototype of new module zone-forward
authorJan Vcelak <jvcelak@ns1.com>
Tue, 14 Aug 2018 10:41:06 +0000 (12:41 +0200)
committerJan Vcelak <jvcelak@ns1.com>
Tue, 14 Aug 2018 10:41:06 +0000 (12:41 +0200)
modules/modules.mk
modules/zone_forward/README.rst [new file with mode: 0644]
modules/zone_forward/zone_forward.c [new file with mode: 0644]
modules/zone_forward/zone_forward.mk [new file with mode: 0644]

index c6c1174ad8b57148708327ed6b4aaa3eb73f2a16..a60324d5e95db581a931d258f1b6915723d4ad14 100644 (file)
@@ -40,7 +40,8 @@ modules_TARGETS += bogus_log \
                    serve_stale \
                    detect_time_skew \
                    detect_time_jump \
-                   prefill
+                   prefill \
+                   zone_forward
 endif
 
 # Make C module
diff --git a/modules/zone_forward/README.rst b/modules/zone_forward/README.rst
new file mode 100644 (file)
index 0000000..e69edbd
--- /dev/null
@@ -0,0 +1,22 @@
+.. _mod-zone_forward:
+
+Zone forwarding
+---------------
+
+Prototype.
+
+This is a module to provide zone forwarding to an authoritative server. In
+comparison to policy module's FORWARD, this modules enables forwarding even
+when following CNAMEs and respects delegations present within the forwarded
+zone.
+
+Examples
+^^^^^^^^
+
+.. code-block:: lua
+
+    -- Zone forwards need to be processed first
+    modules = { 'zone_forward < iterate' }
+
+    -- Configure forwarding
+    zone_forward.config { zone="example.com.", ip="192.0.2.42" }
diff --git a/modules/zone_forward/zone_forward.c b/modules/zone_forward/zone_forward.c
new file mode 100644 (file)
index 0000000..50432b6
--- /dev/null
@@ -0,0 +1,166 @@
+#include "lib/module.h"
+#include "lib/resolve.h"
+#include "lib/utils.h"
+#include <ccan/json/json.h>
+#include <libknot/rdata.h>
+#include <libknot/rrtype/opt.h>
+
+/**
+ * Module inserts synthetic zone cut for forwarded zones.
+ *
+ * Needs to run before iterate, otherwise query minimization works incorrectly.
+ *
+ * TODO:
+ *
+ * - How to control if DNSSEC should be enabled or disabled.
+ * - How to configure port number for the zone cut.
+ * - How to disable cache just for queries for the forwarded zone.
+ * - How the config should look like.
+ * - How to make it scale for thousands of zones.
+ * - Should this be part of policy module.
+ */
+
+#define LOG(fmt, args...) kr_log_info("[     ][zfwd]   " fmt "\n", ##args)
+
+struct zone_forward_ctx {
+       knot_dname_t *zone;
+       struct sockaddr *server;
+};
+
+KR_EXPORT
+int zone_forward_init(struct kr_module *module)
+{
+       struct zone_forward_ctx *ctx = calloc(1, sizeof(*ctx));
+       if (!ctx) {
+               return kr_error(KNOT_ENOMEM);
+       }
+
+       module->data = ctx;
+
+       return kr_ok();
+}
+
+KR_EXPORT
+int zone_forward_deinit(struct kr_module *module)
+{
+       struct zone_forward_ctx *ctx = module->data;
+
+       knot_dname_free(&ctx->zone, NULL);
+       free(ctx->server);
+
+       free(ctx);
+
+       return kr_ok();
+}
+
+static char *zone_forward_config(void *env, struct kr_module *module, const char *json)
+{
+       struct zone_forward_ctx *ctx = module->data;
+
+       if (!json) {
+               return NULL;
+       }
+
+       JsonNode *root = json_decode(json);
+       if (!root) {
+               return NULL;
+       }
+
+       if (root->tag != JSON_OBJECT) {
+               json_delete(root);
+               return NULL;
+       }
+
+       JsonNode *node = NULL;
+       json_foreach(node, root) {
+               if (node->tag != JSON_STRING) {
+                       continue;
+               }
+
+               if (strcmp(node->key, "zone") == 0) {
+                       knot_dname_t *zone = knot_dname_from_str_alloc(node->string_);
+                       if (zone) {
+                               knot_dname_free(&ctx->zone, NULL);
+                               ctx->zone = zone;
+                       }
+               } else if (strcmp(node->key, "ip") == 0) {
+                       struct sockaddr *sock = kr_straddr_socket(node->string_, 0);
+                       if (sock) {
+                               free(ctx->server);
+                               ctx->server = sock;
+                       }
+               }
+       }
+
+       json_delete(root);
+       return NULL;
+}
+
+static void inject_zone_cut(struct kr_zonecut *cut, const struct zone_forward_ctx *ctx)
+{
+       char cut_str[256] = {0};
+       knot_dname_to_str(cut_str, ctx->zone, sizeof(cut_str));
+       char addr_str[256] = {0};
+       size_t addr_size = sizeof(addr_str);
+       kr_inaddr_str(ctx->server, addr_str, &addr_size);
+       LOG("injecting zone cut for '%s' to '%s'", cut_str, addr_str);
+
+       const size_t rdlen = kr_inaddr_len(ctx->server);
+       const uint8_t *data = (uint8_t *)kr_inaddr(ctx->server);
+
+       size_t size = knot_rdata_array_size(rdlen);
+       uint8_t rdata[size];
+       memset(rdata, 0, sizeof(rdata));
+       knot_rdata_init(rdata, rdlen, data, 0);
+
+       kr_zonecut_init(cut, ctx->zone, cut->pool);
+       kr_zonecut_add(cut, (const uint8_t *)"", rdata);
+}
+
+static int produce(kr_layer_t *ctx, knot_pkt_t *pkt)
+{
+       struct kr_module *mod = ctx->api->data;
+       struct zone_forward_ctx *fwd = mod->data;
+
+       if (!fwd->server || !fwd->zone) {
+               return ctx->state;
+       }
+
+       struct kr_query *cur = ctx->req->current_query;
+       if (!trie_empty(cur->zone_cut.nsset) || !knot_dname_in(fwd->zone, cur->sname)) {
+               return ctx->state;
+       }
+
+       inject_zone_cut(&cur->zone_cut, fwd);
+
+       cur->flags.NO_CACHE = true;
+       cur->flags.DNSSEC_WANT = false;
+       cur->flags.KEEP_CUT = true;
+
+       return ctx->state;
+}
+
+KR_EXPORT
+struct kr_prop *zone_forward_props(void)
+{
+       static struct kr_prop props[] = {
+               { zone_forward_config, "config", "Configure zone forward." },
+               { NULL },
+       };
+
+       return props;
+}
+
+KR_EXPORT
+const kr_layer_api_t *zone_forward_layer(struct kr_module *module)
+{
+       static kr_layer_api_t layer = {
+               .produce = produce,
+       };
+
+       layer.data = module;
+
+       return &layer;
+}
+
+KR_MODULE_EXPORT(zone_forward);
diff --git a/modules/zone_forward/zone_forward.mk b/modules/zone_forward/zone_forward.mk
new file mode 100644 (file)
index 0000000..79eaf20
--- /dev/null
@@ -0,0 +1,5 @@
+zone_forward_CFLAGS := -fPIC
+zone_forward_SOURCES := modules/zone_forward/zone_forward.c
+zone_forward_DEPEND := $(libkres)
+zone_forward_LIBS := $(contrib_TARGET) $(libkres_TARGET) $(libkres_LIBS)
+$(call make_c_module,zone_forward)