From 562fad4ba1f6243d21850ef367235dd83ec3ce16 Mon Sep 17 00:00:00 2001 From: Jan Vcelak Date: Tue, 14 Aug 2018 12:41:06 +0200 Subject: [PATCH] zone_forward: prototype of new module --- modules/modules.mk | 3 +- modules/zone_forward/README.rst | 22 ++++ modules/zone_forward/zone_forward.c | 166 +++++++++++++++++++++++++++ modules/zone_forward/zone_forward.mk | 5 + 4 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 modules/zone_forward/README.rst create mode 100644 modules/zone_forward/zone_forward.c create mode 100644 modules/zone_forward/zone_forward.mk diff --git a/modules/modules.mk b/modules/modules.mk index c6c1174ad..a60324d5e 100644 --- a/modules/modules.mk +++ b/modules/modules.mk @@ -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 index 000000000..e69edbd9b --- /dev/null +++ b/modules/zone_forward/README.rst @@ -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 index 000000000..50432b664 --- /dev/null +++ b/modules/zone_forward/zone_forward.c @@ -0,0 +1,166 @@ +#include "lib/module.h" +#include "lib/resolve.h" +#include "lib/utils.h" +#include +#include +#include + +/** + * 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 index 000000000..79eaf209d --- /dev/null +++ b/modules/zone_forward/zone_forward.mk @@ -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) -- 2.47.2