]> git.ipfire.org Git - thirdparty/knot-dns.git/commitdiff
knot: prepare for integration of the Redis backend
authorDaniel Salzman <daniel.salzman@nic.cz>
Tue, 28 Jan 2025 13:34:34 +0000 (14:34 +0100)
committerDaniel Salzman <daniel.salzman@nic.cz>
Fri, 12 Sep 2025 14:50:41 +0000 (16:50 +0200)
20 files changed:
Knot.files
src/knot/Makefile.inc
src/knot/common/hiredis.c [new file with mode: 0644]
src/knot/common/hiredis.h [new file with mode: 0644]
src/knot/conf/conf.c
src/knot/conf/conf.h
src/knot/conf/schema.c
src/knot/conf/schema.h
src/knot/conf/tools.c
src/knot/conf/tools.h
src/knot/server/server.c
src/knot/server/server.h
src/knot/zone/zone-load.c
src/knot/zone/zonefile.c
src/knot/zone/zonefile.h
src/utils/knotc/commands.c
src/utils/kzonecheck/zone_check.c
tests-fuzz/Makefile.am
tests/Makefile.am
tests/knot/test_digest.c

index 247ef7dc8d800190d01596f9135536bec3bc7710..ced2c8aabf8c4c220c2ede4c7d4236936ab607f0 100644 (file)
@@ -186,6 +186,8 @@ src/knot/common/evsched.c
 src/knot/common/evsched.h
 src/knot/common/fdset.c
 src/knot/common/fdset.h
+src/knot/common/hiredis.c
+src/knot/common/hiredis.h
 src/knot/common/log.c
 src/knot/common/log.h
 src/knot/common/process.c
index 0286d08e0150fa734df98756b9d6a274ec7bf717..b5ecae7123c277b1d4608e288cda917f7bf08d70 100644 (file)
@@ -1,11 +1,13 @@
 libknotd_la_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAG_VISIBILITY) $(libkqueue_CFLAGS) \
                        $(liburcu_CFLAGS) $(lmdb_CFLAGS) $(systemd_CFLAGS) \
-                       $(libdbus_CFLAGS) $(gnutls_CFLAGS) -DKNOTD_MOD_STATIC
+                       $(libdbus_CFLAGS) $(gnutls_CFLAGS) $(libhiredis_CFLAGS) \
+                       -DKNOTD_MOD_STATIC
 libknotd_la_LDFLAGS  = $(AM_LDFLAGS) -export-symbols-regex '^knotd_'
 libknotd_la_LIBADD   = $(dlopen_LIBS) $(libkqueue_LIBS) $(pthread_LIBS)
 libknotd_LIBS        = libknotd.la libknot.la libdnssec.la libzscanner.la \
                        $(libcontrib_LIBS) $(liburcu_LIBS) $(lmdb_LIBS) \
-                       $(systemd_LIBS) $(libdbus_LIBS) $(gnutls_LIBS)
+                       $(systemd_LIBS) $(libdbus_LIBS) $(gnutls_LIBS) \
+                       $(hiredis_LIBS)
 
 if EMBEDDED_LIBNGTCP2
 libknotd_la_LIBADD += $(libembngtcp2_LIBS)
@@ -238,6 +240,12 @@ libknotd_la_SOURCES += \
        knot/server/quic-handler.h
 endif ENABLE_QUIC
 
+if ENABLE_REDIS
+libknotd_la_SOURCES += \
+       knot/common/hiredis.c                   \
+       knot/common/hiredis.h
+endif ENABLE_REDIS
+
 if HAVE_DAEMON
 noinst_LTLIBRARIES += libknotd.la
 pkgconfig_DATA     += knotd.pc
diff --git a/src/knot/common/hiredis.c b/src/knot/common/hiredis.c
new file mode 100644 (file)
index 0000000..ca72df5
--- /dev/null
@@ -0,0 +1,255 @@
+/*  Copyright (C) CZ.NIC, z.s.p.o. and contributors
+ *  SPDX-License-Identifier: GPL-2.0-or-later
+ *  For more information, see <https://www.knot-dns.cz/>
+ */
+
+#include "knot/common/hiredis.h"
+
+#include "contrib/sockaddr.h"
+#include "knot/common/log.h"
+#include "libknot/errcode.h"
+
+#ifdef ENABLE_REDIS_TLS
+#include <hiredis/alloc.h>
+#include <hiredis/sds.h>
+
+#include "libknot/quic/tls.h"
+#include "libknot/quic/tls_common.h"
+
+typedef struct {
+       struct knot_creds *local_creds;
+       struct knot_tls_ctx *tls;
+       struct knot_tls_conn *conn;
+} redis_tls_ctx_t;
+
+static void knot_redis_tls_close(redisContext *ctx);
+static void knot_redis_tls_free(void *privctx);
+static ssize_t knot_redis_tls_read(struct redisContext *ctx, char *buff, size_t size);
+static ssize_t knot_redis_tls_write(struct redisContext *ctx);
+
+redisContextFuncs redisContextGnuTLSFuncs = {
+       .close = knot_redis_tls_close,
+       .free_privctx = knot_redis_tls_free,
+       .read = knot_redis_tls_read,
+       .write = knot_redis_tls_write
+};
+
+static void ctx_deinit(redis_tls_ctx_t *ctx)
+{
+       if (ctx != NULL) {
+               if (ctx->tls != NULL) {
+                       knot_creds_free(ctx->tls->creds);
+                       knot_tls_ctx_free(ctx->tls);
+               }
+               knot_creds_free(ctx->local_creds);
+               hi_free(ctx);
+       }
+}
+
+static void knot_redis_tls_close(redisContext *ctx)
+{
+       redis_tls_ctx_t *tls_ctx = ctx->privctx;
+       if (ctx && ctx->fd != REDIS_INVALID_FD) {
+               knot_tls_conn_del(tls_ctx->conn);
+               close(ctx->fd);
+               ctx->fd = REDIS_INVALID_FD;
+       }
+}
+
+static void knot_redis_tls_free(void *privctx)
+{
+       ctx_deinit((redis_tls_ctx_t *)privctx);
+}
+
+static ssize_t knot_redis_tls_read(struct redisContext *ctx, char *buff, size_t size)
+{
+       redis_tls_ctx_t *tls_ctx = ctx->privctx;
+
+       int ret = knot_tls_recv(tls_ctx->conn, buff, size);
+       if (ret >= 0) {
+               return ret;
+       } else if (ret == KNOT_EBADCERT ||
+                  ret == KNOT_NET_ERECV ||
+                  ret == KNOT_NET_ECONNECT ||
+                  ret == KNOT_NET_EHSHAKE ||
+                  ret == KNOT_ETIMEOUT
+       ) {
+               return -1;
+       }
+       return 0;
+}
+
+static ssize_t knot_redis_tls_write(struct redisContext *ctx)
+{
+       redis_tls_ctx_t *tls_ctx = ctx->privctx;
+
+       int ret = knot_tls_send(tls_ctx->conn, ctx->obuf, sdslen(ctx->obuf));
+       if (ret >= 0) {
+               return ret;
+       } else if (ret == KNOT_EBADCERT ||
+                  ret == KNOT_NET_ESEND ||
+                  ret == KNOT_NET_ECONNECT ||
+                  ret == KNOT_NET_EHSHAKE ||
+                  ret == KNOT_ETIMEOUT
+       ) {
+               return -1;
+       }
+       return 0;
+}
+
+static int hiredis_attach_gnutls(redisContext *ctx, struct knot_creds *local_creds,
+                                 struct knot_creds *creds)
+{
+       redis_tls_ctx_t *privctx = hi_calloc(1, sizeof(redis_tls_ctx_t));
+       if (ctx == NULL) {
+               return KNOT_ENOMEM;
+       }
+       privctx->local_creds = local_creds;
+
+       privctx->tls = knot_tls_ctx_new(creds, 5000, 2000, KNOT_TLS_CLIENT);
+       if (privctx->tls == NULL) {
+               ctx_deinit(privctx);
+               return KNOT_EINVAL;
+       }
+
+       privctx->conn = knot_tls_conn_new(privctx->tls, ctx->fd);
+       if (privctx->conn == NULL) {
+               ctx_deinit(privctx);
+               return KNOT_ECONN;
+       }
+
+       if (knot_tls_handshake(privctx->conn, true) != KNOT_EOK) {
+               return KNOT_ECONN;
+       }
+
+       ctx->funcs = &redisContextGnuTLSFuncs;
+       ctx->privctx = privctx;
+
+       return KNOT_EOK;
+}
+#endif // ENABLE_REDIS_TLS
+
+redisContext *rdb_connect(conf_t *conf)
+{
+       conf_val_t db_listen = conf_db_param(conf, C_ZONE_DB_LISTEN);
+       struct sockaddr_storage addr = conf_addr(&db_listen, NULL);
+
+       int port = sockaddr_port(&addr);
+       sockaddr_port_set(&addr, 0);
+
+       char addr_str[SOCKADDR_STRLEN];
+       if (sockaddr_tostr(addr_str, sizeof(addr_str), &addr) <= 0) {
+               return NULL;
+       }
+
+       const struct timeval timeout = { 10, 0 };
+
+       redisContext *rdb;
+       if (addr.ss_family == AF_UNIX) {
+               rdb = redisConnectUnixWithTimeout(addr_str, timeout);
+       } else {
+               rdb = redisConnectWithTimeout(addr_str, port, timeout);
+       }
+       if (rdb == NULL) {
+               log_error("rdb, failed to connect");
+       } else if (rdb->err) {
+               log_error("rdb, failed to connect (%s)", rdb->errstr);
+               return NULL;
+       }
+
+#ifdef ENABLE_REDIS_TLS
+       if (conf_get_bool(conf, C_DB, C_ZONE_DB_TLS)) {
+               struct knot_creds *local_creds = NULL;
+               char *cert_file = conf_tls(conf, C_CERT_FILE);
+               if (cert_file != NULL) {
+                       char *key_file = conf_tls(conf, C_KEY_FILE);
+                       conf_val_t cafiles_val = conf_get(conf, C_SERVER, C_CA_FILE);
+                       size_t nfiles = conf_val_count(&cafiles_val);
+                       const char *ca_files[nfiles + 1];
+                       bool system_ca = false;
+
+                       memset(ca_files, 0, sizeof(ca_files));
+                       for (size_t i = 0; cafiles_val.code == KNOT_EOK; conf_val_next(&cafiles_val)) {
+                               const char *file = conf_str(&cafiles_val);
+                               if (*file == '\0') {
+                                       system_ca = true;
+                               } else {
+                                       ca_files[i++] = file;
+                               }
+                       }
+
+                       int ret = knot_creds_init(&local_creds, key_file, cert_file,
+                                                 ca_files, system_ca, 0, 0);
+                       free(key_file);
+                       free(cert_file);
+                       if (ret != KNOT_EOK) {
+                               redisFree(rdb);
+                               return NULL;
+                       }
+               }
+
+               const char *hostnames[KNOT_TLS_MAX_PINS] = { 0 };
+               conf_val_t val = conf_db_param(conf, C_ZONE_DB_CERT_HOSTNAME);
+               for (size_t i = 0; val.code == KNOT_EOK; i++) {
+                       hostnames[i] = conf_str(&val);
+                       conf_val_next(&val);
+               }
+
+               const uint8_t *pins[KNOT_TLS_MAX_PINS] = { 0 };
+               val = conf_db_param(conf, C_ZONE_DB_CERT_KEY);
+               for (size_t i = 0; val.code == KNOT_EOK; i++) {
+                       size_t len;
+                       pins[i] = (uint8_t *)conf_bin(&val, &len);
+                       conf_val_next(&val);
+               }
+
+               struct knot_creds *creds = knot_creds_init_peer(local_creds, hostnames, pins);
+               if (creds == NULL) {
+                       knot_creds_free(local_creds);
+                       redisFree(rdb);
+                       return NULL;
+               }
+
+               int ret = hiredis_attach_gnutls(rdb, local_creds, creds);
+               if (ret != KNOT_EOK) {
+                       knot_creds_free(local_creds);
+                       knot_creds_free(creds);
+                       redisFree(rdb);
+                       return NULL;
+               }
+       }
+#endif // ENABLE_REDIS_TLS
+
+       return rdb;
+}
+
+void rdb_disconnect(redisContext* rdb)
+{
+       if (rdb != NULL) {
+               // TODO: is anything more needed for TLS case?
+               redisFree(rdb);
+       }
+}
+
+bool rdb_compatible(redisContext *rdb)
+{
+       if (rdb == NULL) {
+               return false;
+       }
+
+#ifdef ENDIANITY_LITTLE
+  #define ENDIAN 1
+#else
+  #define ENDIAN 0
+#endif
+
+       const char *lua = "local n=1; local s=string.dump(function() return n end); " \
+                         "local e=string.byte(s,7); if e==0 then return 0 else return 1 end";
+
+       redisReply *reply = redisCommand(rdb, "EVAL %s 0", lua);
+       bool res = (reply != NULL &&
+                   reply->type == REDIS_REPLY_INTEGER &&
+                   reply->integer == ENDIAN);
+       freeReplyObject(reply);
+       return res;
+}
diff --git a/src/knot/common/hiredis.h b/src/knot/common/hiredis.h
new file mode 100644 (file)
index 0000000..9064ed7
--- /dev/null
@@ -0,0 +1,20 @@
+/*  Copyright (C) CZ.NIC, z.s.p.o. and contributors
+ *  SPDX-License-Identifier: GPL-2.0-or-later
+ *  For more information, see <https://www.knot-dns.cz/>
+ */
+
+/*!
+ * \brief Extension of Hiredis to support GnuTLS backend.
+ */
+
+#pragma once
+
+#include <hiredis/hiredis.h>
+
+#include "knot/conf/conf.h"
+
+redisContext *rdb_connect(conf_t *conf);
+
+void rdb_disconnect(redisContext* rdb);
+
+bool rdb_compatible(redisContext *rdb);
index dad7897cd13209d61c8abeaad5656559f4ed7de1..97355d6fdf1c566791d70828e57602514972e8cd 100644 (file)
@@ -1507,3 +1507,22 @@ int conf_xdp_iface(
        return KNOT_EOK;
 #endif
 }
+
+bool conf_zone_rdb_enabled(
+       conf_t *conf,
+       const knot_dname_t *zone,
+       bool input,
+       uint8_t *instance)
+{
+       if (instance == NULL) {
+               return false;
+       }
+
+       conf_val_t val = conf_zone_get(conf, input ? C_ZONE_DB_IN : C_ZONE_DB_OUT, zone);
+       int64_t num = conf_int(&val);
+       if (num > 0) {
+               *instance = num;
+               return true;
+       }
+       return false;
+}
index 1de23c6f79636414e4a3ba0f08480c61c3a739da..b496bb1fa3998e7ad1204e31e09afbc879f19d06 100644 (file)
@@ -991,3 +991,21 @@ int conf_xdp_iface(
        struct sockaddr_storage *addr,
        conf_xdp_iface_t *iface
 );
+
+/*!
+ * Checks if zone database backend is enabled for the zone.
+ *
+ * \param[in] conf       Configuration.
+ * \param[in] zone       Zone name.
+ * \param[in] input      Input backend indication; Output backend otherwise.
+ * \param[out] instance  Configured instance number.
+ *
+ * \retval true   if enabled.
+ * \retval false  if disabled.
+ */
+bool conf_zone_rdb_enabled(
+       conf_t *conf,
+       const knot_dname_t *zone,
+       bool input,
+       uint8_t *instance
+);
index bb3cf2e499536f5c9bb7a65224959a2dd7ff219e..bc8b3ae7c1bdeb7c1d4f4596939529e2b7dccd28 100644 (file)
@@ -299,21 +299,25 @@ static const yp_item_t desc_stats[] = {
 };
 
 static const yp_item_t desc_database[] = {
-       { C_STORAGE,             YP_TSTR,  YP_VSTR = { STORAGE_DIR } },
-       { C_JOURNAL_DB,          YP_TSTR,  YP_VSTR = { "journal" } },
-       { C_JOURNAL_DB_MODE,     YP_TOPT,  YP_VOPT = { journal_modes, JOURNAL_MODE_ROBUST } },
-       { C_JOURNAL_DB_MAX_SIZE, YP_TINT,  YP_VINT = { MEGA(1), VIRT_MEM_LIMIT(TERA(100)),
-                                                      VIRT_MEM_LIMIT(GIGA(20)), YP_SSIZE } },
-       { C_KASP_DB,             YP_TSTR,  YP_VSTR = { "keys" } },
-       { C_KASP_DB_MAX_SIZE,    YP_TINT,  YP_VINT = { MEGA(5), VIRT_MEM_LIMIT(GIGA(100)),
-                                                      MEGA(500), YP_SSIZE } },
-       { C_TIMER_DB,            YP_TSTR,  YP_VSTR = { "timers" } },
-       { C_TIMER_DB_MAX_SIZE,   YP_TINT,  YP_VINT = { MEGA(1), VIRT_MEM_LIMIT(GIGA(100)),
-                                                      MEGA(100), YP_SSIZE } },
-       { C_CATALOG_DB,          YP_TSTR,  YP_VSTR = { "catalog" } },
-       { C_CATALOG_DB_MAX_SIZE, YP_TINT,  YP_VINT = { MEGA(5), VIRT_MEM_LIMIT(GIGA(100)),
-                                                      VIRT_MEM_LIMIT(GIGA(20)), YP_SSIZE } },
-       { C_COMMENT,             YP_TSTR,  YP_VNONE },
+       { C_STORAGE,               YP_TSTR,  YP_VSTR = { STORAGE_DIR } },
+       { C_JOURNAL_DB,            YP_TSTR,  YP_VSTR = { "journal" } },
+       { C_JOURNAL_DB_MODE,       YP_TOPT,  YP_VOPT = { journal_modes, JOURNAL_MODE_ROBUST } },
+       { C_JOURNAL_DB_MAX_SIZE,   YP_TINT,  YP_VINT = { MEGA(1), VIRT_MEM_LIMIT(TERA(100)),
+                                                        VIRT_MEM_LIMIT(GIGA(20)), YP_SSIZE } },
+       { C_KASP_DB,               YP_TSTR,  YP_VSTR = { "keys" } },
+       { C_KASP_DB_MAX_SIZE,      YP_TINT,  YP_VINT = { MEGA(5), VIRT_MEM_LIMIT(GIGA(100)),
+                                                        MEGA(500), YP_SSIZE } },
+       { C_TIMER_DB,              YP_TSTR,  YP_VSTR = { "timers" } },
+       { C_TIMER_DB_MAX_SIZE,     YP_TINT,  YP_VINT = { MEGA(1), VIRT_MEM_LIMIT(GIGA(100)),
+                                                        MEGA(100), YP_SSIZE } },
+       { C_CATALOG_DB,            YP_TSTR,  YP_VSTR = { "catalog" } },
+       { C_CATALOG_DB_MAX_SIZE,   YP_TINT,  YP_VINT = { MEGA(5), VIRT_MEM_LIMIT(GIGA(100)),
+                                                        VIRT_MEM_LIMIT(GIGA(20)), YP_SSIZE } },
+       { C_ZONE_DB_LISTEN,        YP_TADDR, YP_VADDR = { 6379 }, YP_FNONE, { check_rdb, check_listen } },
+       { C_ZONE_DB_TLS,           YP_TBOOL, YP_VNONE },
+       { C_ZONE_DB_CERT_KEY,      YP_TB64,  YP_VNONE, YP_FMULTI, { check_cert_pin } },
+       { C_ZONE_DB_CERT_HOSTNAME, YP_TSTR,  YP_VNONE, YP_FMULTI },
+       { C_COMMENT,               YP_TSTR,  YP_VNONE },
        { NULL }
 };
 
@@ -467,6 +471,8 @@ static const yp_item_t desc_external[] = {
 #define ZONE_ITEMS(FLAGS) \
        { C_STORAGE,             YP_TSTR,  YP_VSTR = { STORAGE_DIR }, FLAGS }, \
        { C_FILE,                YP_TSTR,  YP_VNONE, FLAGS }, \
+       { C_ZONE_DB_IN,          YP_TINT,  YP_VINT = { -1, 8, -1 }, FLAGS, { check_db_instance } }, \
+       { C_ZONE_DB_OUT,         YP_TINT,  YP_VINT = { -1, 8, -1 }, FLAGS, { check_db_instance } }, \
        { C_MASTER,              YP_TREF,  YP_VREF = { C_RMT, C_RMTS }, YP_FMULTI | CONF_REF_EMPTY, \
                                           { check_ref } }, \
        { C_DDNS_MASTER,         YP_TREF,  YP_VREF = { C_RMT }, YP_FNONE, { check_ref_empty } }, \
index 7b48c3a2e904f254dd8ee0973e03252b6d3195d4..f9b6c7b276fe9ebdb325dd996248b1bdf8575b96 100644 (file)
 #define C_ZONEFILE_SYNC                "\x0D""zonefile-sync"
 #define C_ZONEMD_GENERATE      "\x0F""zonemd-generate"
 #define C_ZONEMD_VERIFY                "\x0D""zonemd-verify"
+#define C_ZONE_DB_CERT_HOSTNAME        "\x15""zone-db-cert-hostname"
+#define C_ZONE_DB_CERT_KEY     "\x10""zone-db-cert-key"
+#define C_ZONE_DB_IN           "\x0D""zone-db-input"
+#define C_ZONE_DB_LISTEN       "\x0E""zone-db-listen"
+#define C_ZONE_DB_OUT          "\x0E""zone-db-output"
+#define C_ZONE_DB_TLS          "\x0B""zone-db-tls"
 #define C_ZONE_MAX_SIZE                "\x0D""zone-max-size"
 #define C_ZONE_MAX_TTL         "\x0C""zone-max-ttl"
 #define C_ZSK_LIFETIME         "\x0C""zsk-lifetime"
index b937cd45b8a06e12dbc2dcdc8621e83652cd7b1f..62a926efd762a133581e67c8e81c73b36fb861bb 100644 (file)
@@ -1213,6 +1213,29 @@ int check_catalog_tpl(
        return check_zone_or_tpl(args);
 }
 
+int check_rdb(
+       knotd_conf_check_args_t *args)
+{
+#ifndef ENABLE_REDIS
+       args->err_str = "Zone database support not available";
+       return KNOT_ENOTSUP;
+#else
+       return KNOT_EOK;
+#endif
+}
+
+int check_db_instance(
+       knotd_conf_check_args_t *args)
+{
+       int64_t instance = yp_int(args->data);
+       if (instance == 0) {
+               args->err_str = "instance number must be 1-8";
+               return KNOT_EINVAL;
+       }
+
+       return KNOT_EOK;
+}
+
 static int glob_error(
        const char *epath,
        int eerrno)
index f48ed5bbc5b535fd43ada11dcd35b72562840a4e..42be2e509bb4e14cff0d09048371e19e232b679e 100644 (file)
@@ -163,6 +163,14 @@ int check_catalog_tpl(
        knotd_conf_check_args_t *args
 );
 
+int check_rdb(
+       knotd_conf_check_args_t *args
+);
+
+int check_db_instance(
+       knotd_conf_check_args_t *args
+);
+
 int include_file(
        knotd_conf_check_args_t *args
 );
index d80a0b0ab7ce6450e3988375a1258e13538f90de..f6d73f8e47ae687513d5bde60f34eb9bd7e68cec 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <assert.h>
 #include <gnutls/x509.h>
+#include <string.h>
 #include <sys/types.h>   // OpenBSD
 #include <netinet/tcp.h> // TCP_FASTOPEN
 #include <sys/resource.h>
@@ -831,16 +832,161 @@ static int configure_sockets(conf_t *conf, server_t *s)
        return KNOT_EOK;
 }
 
+#ifdef ENABLE_REDIS
+#include "contrib/openbsd/strlcpy.h"
+#include "contrib/strtonum.h"
+#include "redis/knot.h"
+#include "knot/common/hiredis.h"
+
+#define RDB_TIMESTAMP_SIZE 42 // 2x uint64_t as string (2x20) + dash separator + zero byte.
+
+static void rdb_process_event(redisReply *reply, knot_zonedb_t *zone_db,
+                              char since[static RDB_TIMESTAMP_SIZE])
+{
+       redisReply *timestamp = reply->element[0];
+       redisReply *data = reply->element[1];
+       if (data->type != REDIS_REPLY_ARRAY ||
+           data->elements % 2 != 0 ||
+           timestamp->len > RDB_TIMESTAMP_SIZE) {
+               goto failed;
+       }
+       strlcpy(since, timestamp->str, RDB_TIMESTAMP_SIZE);
+
+       uint8_t type = 0;
+       uint8_t instance = 0;
+       uint32_t serial = 0;
+       const knot_dname_t *origin = NULL;
+
+       for (int idx = 0; idx < data->elements; ++idx) {
+               redisReply *key = data->element[idx++];
+               redisReply *val = data->element[idx];
+               if (key->type != REDIS_REPLY_STRING) {
+                       goto failed;
+               }
+               if (strcmp(key->str, RDB_EVENT_ARG_EVENT) == 0) {
+                       if (str_to_u8(val->str, &type) != KNOT_EOK) {
+                               goto failed;
+                       }
+               } else if (strcmp(key->str, RDB_EVENT_ARG_ORIGIN) == 0) {
+                       origin = (const knot_dname_t *)val->str;
+               } else if (strcmp(key->str, RDB_EVENT_ARG_INSTANCE) == 0) {
+                       if (str_to_u8(val->str, &instance) != KNOT_EOK) {
+                               goto failed;
+                       }
+               } else if (strcmp(key->str, RDB_EVENT_ARG_SERIAL) == 0) {
+                       if (str_to_u32(val->str, &serial) != KNOT_EOK) {
+                               goto failed;
+                       }
+               }
+       }
+
+       if (type == 0 || origin == NULL || instance == 0) {
+               goto failed;
+       }
+
+       uint8_t db_instance = 0;
+       bool db_enabled = conf_zone_rdb_enabled(conf(), origin, true, &db_instance);
+       if (!db_enabled || db_instance != instance) {
+               return;
+       }
+       zone_t *zone = knot_zonedb_find(zone_db, origin);
+       if (zone == NULL) {
+               return;
+       }
+
+       switch (type) {
+       case RDB_EVENT_ZONE:
+       case RDB_EVENT_UPD:
+               zone_events_schedule_now(zone, ZONE_EVENT_LOAD);
+               break;
+       default:
+               break;
+       }
+
+       return;
+failed:
+       log_error("rdb, invalid event parameters");
+}
+
+static void rdb_process_events(redisReply *reply, knot_zonedb_t *zone_db,
+                               char since[static RDB_TIMESTAMP_SIZE])
+{
+       if (reply->type != REDIS_REPLY_ARRAY) {
+               log_error("rdb, unexpected response");
+               return;
+       }
+
+       for (int idx = 0; idx < reply->elements; ++idx) {
+               if (reply->element[idx]->type != REDIS_REPLY_ARRAY) {
+                       log_error("rdb, unexpected response");
+                       continue;
+               }
+               redisReply *events = reply->element[idx]->element[1];
+               for (int event_idx = 0; event_idx < events->elements; ++event_idx) {
+                       rdb_process_event(events->element[event_idx], zone_db, since);
+               }
+       }
+}
+
+static int rdb_listener_run(struct dthread *thread)
+{
+       server_t *s = thread->data;
+
+       s->rdb_ctx = NULL;
+       char since[RDB_TIMESTAMP_SIZE] = "$";
+
+       while (thread->state & ThreadActive) {
+               if (s->rdb_ctx == NULL) {
+                       s->rdb_ctx = rdb_connect(conf());
+                       if (s->rdb_ctx == NULL) {
+                               log_error("rdb, failed to connect");
+                               sleep(2);
+                               continue;
+                       } else if (!rdb_compatible(s->rdb_ctx)) {
+                               log_error("rdb, incompatible CPU endianness");
+                               break;
+                       }
+               }
+
+               redisReply *reply = redisCommand(s->rdb_ctx, "XREAD BLOCK %d STREAMS %b %s",
+                                                10000, RDB_EVENT_KEY, strlen(RDB_EVENT_KEY), since);
+               if (reply == NULL) {
+                       if (thread->state & ThreadDead) {
+                               break;
+                       }
+                       if (s->rdb_ctx->err != REDIS_OK) {
+                               log_error("rdb, failed to read events (%s)", s->rdb_ctx->errstr);
+                       }
+                       sleep(2);
+                       continue;
+               }
+               if (reply->type == REDIS_REPLY_NIL) {
+                       freeReplyObject(reply);
+                       continue;
+               }
+
+               knot_zonedb_t *zone_db = s->zone_db;
+               if (zone_db != NULL) {
+                       rdb_process_events(reply, zone_db, since);
+               }
+               freeReplyObject(reply);
+       }
+
+       rdb_disconnect(s->rdb_ctx);
+       s->rdb_ctx = NULL;
+
+       return KNOT_EOK;
+}
+#endif // ENABLE_REDIS
+
 int server_init(server_t *server, int bg_workers)
 {
        if (server == NULL) {
                return KNOT_EINVAL;
        }
 
-       /* Clear the structure. */
        memset(server, 0, sizeof(server_t));
 
-       /* Initialize event scheduler. */
        if (evsched_init(&server->sched, server) != KNOT_EOK) {
                return KNOT_ENOMEM;
        }
@@ -851,8 +997,22 @@ int server_init(server_t *server, int bg_workers)
                return KNOT_ENOMEM;
        }
 
+#ifdef ENABLE_REDIS
+       conf_val_t rdb = conf_db_param(conf(), C_ZONE_DB_LISTEN);
+       if (rdb.code == KNOT_EOK) {
+               server->rdb_events = dt_create(1, rdb_listener_run, NULL, server);
+               if (server->rdb_events == NULL) {
+                       worker_pool_destroy(server->workers);
+                       evsched_deinit(&server->sched);
+                       return KNOT_ENOMEM;
+               }
+       }
+#endif // ENABLE_REDIS
+
        int ret = catalog_update_init(&server->catalog_upd);
        if (ret != KNOT_EOK) {
+               dt_stop(server->rdb_events);
+               dt_delete(&server->rdb_events);
                worker_pool_destroy(server->workers);
                evsched_deinit(&server->sched);
                return ret;
@@ -909,6 +1069,9 @@ void server_deinit(server_t *server)
        /* Free threads and event handlers. */
        worker_pool_destroy(server->workers);
 
+       /* Free optional zone DB event thread. */
+       dt_delete(&server->rdb_events);
+
        /* Free zone database. */
        knot_zonedb_deep_free(&server->zone_db, true);
 
@@ -1023,6 +1186,9 @@ int server_start(server_t *server, bool answering)
        /* Start workers. */
        worker_pool_start(server->workers);
 
+       /* Start zone DB event loop. */
+       dt_start(server->rdb_events);
+
        /* Start evsched handler. */
        evsched_start(&server->sched);
 
@@ -1399,6 +1565,14 @@ void server_stop(server_t *server)
        log_info("stopping server");
        systemd_stopping_notify();
 
+#ifdef ENABLE_REDIS
+       /* Interrupt and stop XREAD BLOCK loop. */
+       if (server->rdb_ctx != NULL) {
+               redisSetTimeout(server->rdb_ctx, (struct timeval){ 0, 1 });
+       }
+       dt_stop(server->rdb_events);
+#endif // ENABLE_REDIS
+
        /* Stop scheduler. */
        evsched_stop(&server->sched);
        /* Mark the server is shutting down. */
index b37f2b1268498393bd19d4b4a1ea493b8eebec5c..5faf0102101bdef88ef5692c4b5adb8318744f8c 100644 (file)
@@ -108,6 +108,10 @@ typedef struct server {
        /*! \brief Background jobs. */
        worker_pool_t *workers;
 
+       /*! \brief Zone DB event loop context. */
+       dt_unit_t *rdb_events;
+       struct redisContext *rdb_ctx;
+
        /*! \brief Event scheduler. */
        evsched_t sched;
 
index b4d7ef91b662e188af220184af35c54f1d251208..b4e149119585b95a49cf1294e3f95a120dc2d851 100644 (file)
@@ -28,28 +28,25 @@ int zone_load_contents(conf_t *conf, const knot_dname_t *zone_name,
                return ret;
        }
 
+       zloader_t loader;
+       sem_handler_t handler = {
+               .cb = err_handler_logger
+       };
+
        char *zonefile = conf_zonefile(conf, zone_name);
        conf_val_t val = conf_zone_get(conf, C_DEFAULT_TTL, zone_name);
        uint32_t dflt_ttl = conf_int(&val);
 
-       zloader_t zl;
-       ret = zonefile_open(&zl, zonefile, zone_name, dflt_ttl,
-                           semcheck_mode, time(NULL));
+       ret = zonefile_open(&loader, zonefile, zone_name, dflt_ttl,
+                           semcheck_mode, &handler, time(NULL), &skip);
        free(zonefile);
        if (ret != KNOT_EOK) {
                zone_skip_free(&skip);
                return ret;
        }
 
-       sem_handler_t handler = {
-               .cb = err_handler_logger
-       };
-
-       zl.err_handler = &handler;
-       zl.creator->skip = &skip;
-
-       *contents = zonefile_load(&zl, 0);
-       zonefile_close(&zl);
+       *contents = zonefile_load(&loader, 0);
+       zonefile_close(&loader);
        zone_skip_free(&skip);
        if (*contents == NULL) {
                return KNOT_ERROR;
index 25431c38919767ff8ab2e36c049d8593179f3f6c..65f3b09f657bb6b65981d6e80cfffacc6521a847 100644 (file)
@@ -4,10 +4,8 @@
  */
 
 #include <assert.h>
-#include <errno.h>
 #include <inttypes.h>
 #include <libgen.h>
-#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
@@ -17,8 +15,8 @@
 
 #include "libknot/libknot.h"
 #include "contrib/files.h"
+#include "contrib/time.h"
 #include "knot/common/log.h"
-#include "knot/dnssec/zone-nsec.h"
 #include "knot/zone/semantic-check.h"
 #include "knot/zone/adjust.h"
 #include "knot/zone/contents.h"
@@ -31,8 +29,8 @@
 
 static void process_error(zs_scanner_t *s)
 {
-       zcreator_t *zc = s->process.data;
-       const knot_dname_t *zname = zc->z->apex->owner;
+       zloader_t *loader = s->process.data;
+       const knot_dname_t *zname = loader->contents->apex->owner;
 
        ERROR(zname, "%s in zone, file '%s', line %"PRIu64" (%s)",
              s->error.fatal ? "fatal error" : "error",
@@ -84,18 +82,18 @@ int zcreator_step(zone_contents_t *contents, const knot_rrset_t *rr, zone_skip_t
        return KNOT_EOK;
 }
 
-/*! \brief Creates RR from parser input, passes it to handling function. */
 static void process_data(zs_scanner_t *scanner)
 {
-       zcreator_t *zc = scanner->process.data;
-       if (zc->ret != KNOT_EOK) {
+       zloader_t *zl = scanner->process.data;
+
+       if (zl->ret != KNOT_EOK) {
                scanner->state = ZS_STATE_STOP;
                return;
        }
 
        knot_dname_t *owner = knot_dname_copy(scanner->r_owner, NULL);
        if (owner == NULL) {
-               zc->ret = KNOT_ENOMEM;
+               zl->ret = KNOT_ENOMEM;
                return;
        }
 
@@ -105,19 +103,19 @@ static void process_data(zs_scanner_t *scanner)
        int ret = knot_rrset_add_rdata(&rr, scanner->r_data, scanner->r_data_length, NULL);
        if (ret != KNOT_EOK) {
                knot_rrset_clear(&rr, NULL);
-               zc->ret = ret;
+               zl->ret = ret;
                return;
        }
 
-       /* Convert RDATA dnames to lowercase before adding to zone. */
        ret = knot_rrset_rr_to_canonical(&rr);
        if (ret != KNOT_EOK) {
                knot_rrset_clear(&rr, NULL);
-               zc->ret = ret;
+               zl->ret = ret;
                return;
        }
 
-       zc->ret = zcreator_step(zc->z, &rr, zc->skip);
+       zl->ret = zcreator_step(zl->contents, &rr, zl->skip);
+
        knot_rrset_clear(&rr, NULL);
 }
 
@@ -139,24 +137,17 @@ static void error_origin(zs_scanner_t *s)
 }
 
 int zonefile_open(zloader_t *loader, const char *source, const knot_dname_t *origin,
-                  uint32_t dflt_ttl, semcheck_optional_t semantic_checks, time_t time)
+                  uint32_t dflt_ttl, semcheck_optional_t sem_checks,
+                  sem_handler_t *sem_err_handler, time_t time, zone_skip_t *skip)
 {
        if (loader == NULL || source == NULL) {
                return KNOT_EINVAL;
        }
 
-       memset(loader, 0, sizeof(zloader_t));
-
        if (access(source, F_OK | R_OK) != 0) {
                return knot_map_errno();
        }
 
-       zcreator_t *zc = malloc(sizeof(zcreator_t));
-       if (zc == NULL) {
-               return KNOT_ENOMEM;
-       }
-       memset(zc, 0, sizeof(zcreator_t));
-
        uint8_t origin_buf[1 + KNOT_DNAME_MAXLEN];
        if (origin == NULL) { // Origin autodetection based on SOA owner and source.
                const char *ext = ".zone";
@@ -175,19 +166,16 @@ int zonefile_open(zloader_t *loader, const char *source, const knot_dname_t *ori
                    zs_set_processing(&s, check_origin, error_origin, &origin_buf) != 0) {
                        free(origin_str);
                        zs_deinit(&s);
-                       free(zc);
                        return KNOT_EFILE;
                }
                free(origin_str);
                if (zs_parse_all(&s) != 0 && s.error.fatal) {
                        zs_deinit(&s);
-                       free(zc);
                        return KNOT_EPARSEFAIL;
                }
                zs_deinit(&s);
 
                if (origin_buf[0] == 0) {
-                       free(zc);
                        return KNOT_ESOAINVAL;
                }
                origin = origin_buf + 1;
@@ -195,101 +183,91 @@ int zonefile_open(zloader_t *loader, const char *source, const knot_dname_t *ori
 
        knot_dname_txt_storage_t origin_str;
        if (knot_dname_to_str(origin_str, origin, sizeof(origin_str)) == NULL) {
-               free(zc);
                return KNOT_EINVAL;
        }
 
        if (zs_init(&loader->scanner, origin_str, KNOT_CLASS_IN, dflt_ttl) != 0 ||
            zs_set_input_file(&loader->scanner, source) != 0 ||
-           zs_set_processing(&loader->scanner, process_data, process_error, zc) != 0) {
+           zs_set_processing(&loader->scanner, process_data, process_error, loader) != 0) {
                zs_deinit(&loader->scanner);
-               free(zc);
                return KNOT_EFILE;
        }
 
-       zc->z = zone_contents_new(origin, true);
-       if (zc->z == NULL) {
+       loader->contents = zone_contents_new(origin, true);
+       if (loader->contents == NULL) {
                zs_deinit(&loader->scanner);
-               free(zc);
                return KNOT_ENOMEM;
        }
 
        loader->source = strdup(source);
-       loader->creator = zc;
-       loader->semantic_checks = semantic_checks;
+       loader->sem_checks = sem_checks;
+       loader->err_handler = sem_err_handler;
+       loader->skip = skip;
        loader->time = time;
+       loader->ret = KNOT_EOK;
 
        return KNOT_EOK;
 }
 
 zone_contents_t *zonefile_load(zloader_t *loader, uint16_t threads)
 {
-       if (!loader) {
+       if (loader == NULL) {
                return NULL;
        }
 
-       zcreator_t *zc = loader->creator;
-       const knot_dname_t *zname = zc->z->apex->owner;
+       const knot_dname_t *zname = loader->contents->apex->owner;
 
-       assert(zc);
        int ret = zs_parse_all(&loader->scanner);
        if (ret != 0 && loader->scanner.error.counter == 0) {
-               ERROR(zname, "failed to load zone, file '%s' (%s)",
+               ERROR(zname, "failed to load, file '%s' (%s)",
                      loader->source, zs_strerror(loader->scanner.error.code));
                goto fail;
-       }
-
-       if (zc->ret != KNOT_EOK) {
-               ERROR(zname, "failed to load zone, file '%s' (%s)",
-                     loader->source, knot_strerror(zc->ret));
+       } else if (loader->ret != KNOT_EOK) {
+               ERROR(zname, "failed to load, file '%s' (%s)",
+                     loader->source, knot_strerror(loader->ret));
                goto fail;
-       }
-
-       if (loader->scanner.error.counter > 0) {
-               ERROR(zname, "failed to load zone, file '%s', %"PRIu64" errors",
+       } else if (loader->scanner.error.counter > 0) {
+               ERROR(zname, "failed to load, file '%s', %"PRIu64" errors",
                      loader->source, loader->scanner.error.counter);
                goto fail;
        }
 
-       knot_rdataset_t *soa = node_rdataset(zc->z->apex, KNOT_RRTYPE_SOA);
+       knot_rdataset_t *soa = node_rdataset(loader->contents->apex, KNOT_RRTYPE_SOA);
        if (soa == NULL || soa->count != 1) {
                sem_error_t code = (soa == NULL) ? SEM_ERR_SOA_NONE : SEM_ERR_SOA_MULTIPLE;
                loader->err_handler->error = true;
-               loader->err_handler->cb(loader->err_handler, zc->z, NULL, code, NULL);
+               loader->err_handler->cb(loader->err_handler, loader->contents, NULL, code, NULL);
                goto fail;
        }
 
-       ret = zone_adjust_contents(zc->z, adjust_cb_flags_and_nsec3, adjust_cb_nsec3_flags,
-                                  true, true, 1, NULL);
+       ret = zone_adjust_contents(loader->contents, adjust_cb_flags_and_nsec3,
+                                  adjust_cb_nsec3_flags, true, true, 1, NULL);
        if (ret != KNOT_EOK) {
-               ERROR(zname, "failed to finalize zone contents (%s)",
-                     knot_strerror(ret));
+               ERROR(zname, "failed to finalize zone contents (%s)", knot_strerror(ret));
                goto fail;
        }
 
-       ret = sem_checks_process(zc->z, loader->semantic_checks,
+       ret = sem_checks_process(loader->contents, loader->sem_checks,
                                 loader->err_handler, loader->time, threads);
 
        if (ret != KNOT_EOK) {
-               ERROR(zname, "failed to load zone, file '%s' (%s)",
-                     loader->source, knot_strerror(ret));
+               ERROR(zname, "failed to check zone (%s)", knot_strerror(ret));
                goto fail;
        }
 
        /* The contents will now change possibly messing up NSEC3 tree, it will
           be adjusted again at zone_update_commit. */
-       ret = zone_adjust_contents(zc->z, unadjust_cb_point_to_nsec3, NULL,
-                                  false, false, 1, NULL);
+       ret = zone_adjust_contents(loader->contents, unadjust_cb_point_to_nsec3,
+                                  NULL, false, false, 1, NULL);
        if (ret != KNOT_EOK) {
-               ERROR(zname, "failed to finalize zone contents (%s)",
-                     knot_strerror(ret));
+               ERROR(zname, "failed to finalize zone contents (%s)", knot_strerror(ret));
                goto fail;
        }
 
-       return zc->z;
-
+       return loader->contents;
 fail:
-       zone_contents_deep_free(zc->z);
+       zone_contents_deep_free(loader->contents);
+
        return NULL;
 }
 
@@ -359,13 +337,12 @@ int zonefile_write(const char *path, zone_contents_t *zone, zone_skip_t *skip)
 
 void zonefile_close(zloader_t *loader)
 {
-       if (!loader) {
+       if (loader == NULL) {
                return;
        }
 
        zs_deinit(&loader->scanner);
        free(loader->source);
-       free(loader->creator);
 }
 
 void err_handler_logger(sem_handler_t *handler, const zone_contents_t *zone,
index e1991c8b92a1e6f32d02aa77535ad7c5586be49b..d3eabdca167a7da15653a0f2c99185b6d45f49ba 100644 (file)
@@ -5,33 +5,20 @@
 
 #pragma once
 
-#include <stdbool.h>
-#include <stdio.h>
-
 #include "knot/zone/skip.h"
 #include "knot/zone/zone.h"
 #include "knot/zone/semantic-check.h"
 #include "libzscanner/scanner.h"
 
-/*!
- * \brief Zone creator structure.
- */
-typedef struct zcreator {
-       zone_contents_t *z;  /*!< Created zone. */
-       zone_skip_t *skip;   /*!< Skip configured types. */
-       int ret;             /*!< Return value. */
-} zcreator_t;
-
-/*!
- * \brief Zone loader structure.
- */
 typedef struct {
-       char *source;                /*!< Zone source file. */
-       semcheck_optional_t semantic_checks;  /*!< Do semantic checks. */
-       sem_handler_t *err_handler;  /*!< Semantic checks error handler. */
-       zcreator_t *creator;         /*!< Loader context. */
-       zs_scanner_t scanner;        /*!< Zone scanner. */
-       time_t time;                 /*!< time for zone check. */
+       char *source;                    /*!< Zone source file. */
+       zs_scanner_t scanner;            /*!< Zone scanner. */
+       zone_contents_t *contents;       /*!< Created zone. */
+       semcheck_optional_t sem_checks;  /*!< Do semantic checks. */
+       sem_handler_t *err_handler;      /*!< Semantic checks error handler. */
+       zone_skip_t *skip;               /*!< Skip configured types. */
+       time_t time;                     /*!< Time for zone check. */
+       int ret;                         /*!< Callback return value. */
 } zloader_t;
 
 void err_handler_logger(sem_handler_t *handler, const zone_contents_t *zone,
@@ -44,14 +31,17 @@ void err_handler_logger(sem_handler_t *handler, const zone_contents_t *zone,
  * \param source Source file name.
  * \param origin Zone origin.
  * \param dflt_ttl Default TTL.
- * \param semantic_checks Perform semantic checks.
+ * \param sem_checks Perform semantic checks.
+ * \param sem_err_handler Semantic checks error handler.
  * \param time Time for semantic check.
+ * \param skip RRTypes to be skipped.
  *
  * \retval Initialized loader on success.
  * \retval NULL on error.
  */
 int zonefile_open(zloader_t *loader, const char *source, const knot_dname_t *origin,
-                  uint32_t dflt_ttl, semcheck_optional_t semantic_checks, time_t time);
+                  uint32_t dflt_ttl, semcheck_optional_t sem_checks,
+                  sem_handler_t *sem_err_handler, time_t time, zone_skip_t *skip);
 
 /*!
  * \brief Loads zone from a zone file.
index 1797536a104870850e27be3e7bcf3445bdaa3c91..73e01063e2b69c25b8fa7269a0d3b94a12413368 100644 (file)
@@ -562,7 +562,7 @@ static int zone_check(const knot_dname_t *dname, void *data)
        if (ret != KNOT_EOK && ret != KNOT_ESEMCHECK) {
                knot_dname_txt_storage_t name;
                (void)knot_dname_to_str(name, dname, sizeof(name));
-               log_error("[%s] failed to check zone file (%s)", name, knot_strerror(ret));
+               log_error("[%s] failed to check zone (%s)", name, knot_strerror(ret));
        }
 
        return ret;
index 68d06827dc508a7e3e7c04ed627adb5be72bd98b..6a6c59e10464ce0a8f06e75dd147b66e9914d2b6 100644 (file)
@@ -61,8 +61,9 @@ int zone_check(const char *zone_file, const knot_dname_t *zone_name, bool zonemd
                .handler = { .cb = err_callback },
        };
 
-       zloader_t zl;
-       int ret = zonefile_open(&zl, zone_file, zone_name, dflt_ttl, optional, time);
+       zloader_t loader;
+       int ret = zonefile_open(&loader, zone_file, zone_name, dflt_ttl, optional,
+                               (sem_handler_t *)&stats, time, NULL);
        switch (ret) {
        case KNOT_EOK:
                break;
@@ -77,17 +78,16 @@ int zone_check(const char *zone_file, const knot_dname_t *zone_name, bool zonemd
                ERR2("failed to run semantic checks (%s)", knot_strerror(ret));
                return ret;
        }
-       zl.err_handler = (sem_handler_t *)&stats;
 
        if (zone_name == NULL) {
                knot_dname_txt_storage_t origin;
-               if (knot_dname_to_str(origin, zl.scanner.zone_origin, sizeof(origin)) != NULL) {
+               if (knot_dname_to_str(origin, loader.scanner.zone_origin, sizeof(origin)) != NULL) {
                        log_debug("detected zone origin %s", origin);
                }
        }
 
-       zone_contents_t *contents = zonefile_load(&zl, threads);
-       zonefile_close(&zl);
+       zone_contents_t *contents = zonefile_load(&loader, threads);
+       zonefile_close(&loader);
        if (contents == NULL && !stats.handler.error) {
                ERR2("failed to run semantic checks");
                return KNOT_ERROR;
index 489153dbf9c7f80fddee7f527e76f19c95742ea9..20ff9b5f35395cb3f367598b33b16d6976ad10c7 100644 (file)
@@ -45,7 +45,8 @@ knotd_stdio_LDADD = \
        $(liburcu_LIBS)                         \
        $(lmdb_LIBS)                            \
        $(systemd_LIBS)                         \
-       $(libdbus_LIBS)
+       $(libdbus_LIBS)                         \
+       $(hiredis_LIBS)
 
 BUILT_SOURCES = knotd_wrap/main.c
 CLEANFILES = knotd_wrap/main.c
index ac88c46721fe74a3ad69c7d23791903abd14fb42..258ef902a58434f75a92ac258afdec0967c1e783 100644 (file)
@@ -15,7 +15,8 @@ LDADD += \
        $(top_builddir)/src/libknotd.la         \
        $(liburcu_LIBS)                         \
        $(systemd_LIBS)                         \
-       $(libdbus_LIBS)
+       $(libdbus_LIBS)                         \
+       $(hiredis_LIBS)
 endif HAVE_DAEMON
 
 LDADD += \
index e9c5abc07bc82a62dc235b254b2ba4f6d652f6c6..14e6b4c2b50c26e4ae90f7ab9c7e4d1d2d998e18 100644 (file)
@@ -3,56 +3,35 @@
  *  For more information, see <https://www.knot-dns.cz/>
  */
 
-#include "knot/zone/digest.h"
-
+#include <stdio.h>
 #include <string.h>
 #include <tap/basic.h>
 
-#include "knot/zone/zonefile.h"
+#include "knot/zone/digest.h"
 #include "libzscanner/scanner.h"
 
-// copy-pasted from knot/zone/zonefile.c
 static void process_data(zs_scanner_t *scanner)
 {
-       zcreator_t *zc = scanner->process.data;
-       if (zc->ret != KNOT_EOK) {
-               scanner->state = ZS_STATE_STOP;
-               return;
-       }
+       zone_contents_t *cont = scanner->process.data;
 
        knot_dname_t *owner = knot_dname_copy(scanner->r_owner, NULL);
-       if (owner == NULL) {
-               zc->ret = KNOT_ENOMEM;
-               return;
-       }
+       assert(owner != NULL);
 
        knot_rrset_t rr;
        knot_rrset_init(&rr, owner, scanner->r_type, scanner->r_class, scanner->r_ttl);
 
-       int ret = knot_rrset_add_rdata(&rr, scanner->r_data, scanner->r_data_length, NULL);
-       if (ret != KNOT_EOK) {
-               knot_rrset_clear(&rr, NULL);
-               zc->ret = ret;
-               return;
+       if (knot_rrset_add_rdata(&rr, scanner->r_data, scanner->r_data_length, NULL) == KNOT_EOK &&
+           knot_rrset_rr_to_canonical(&rr) == KNOT_EOK) {
+               zone_node_t *node = NULL;
+               int ret = zone_contents_add_rr(cont, &rr, &node);
+               if (ret != KNOT_EOK && ret != KNOT_EOUTOFZONE) {
+                       scanner->error.code = ZS_STATE_ERROR;
+               }
        }
 
-       ret = knot_rrset_rr_to_canonical(&rr);
-       if (ret != KNOT_EOK) {
-               knot_rrset_clear(&rr, NULL);
-               zc->ret = ret;
-               return;
-       }
-
-       zc->ret = zcreator_step(zc->z, &rr, zc->skip);
        knot_rrset_clear(&rr, NULL);
 }
 
-static void process_error(zs_scanner_t *s)
-{
-       (void)s;
-       assert(0);
-}
-
 static zone_contents_t *str2contents(const char *zone_str)
 {
        knot_dname_txt_storage_t origin_str;
@@ -65,13 +44,12 @@ static zone_contents_t *str2contents(const char *zone_str)
        assert(cont != NULL);
        knot_dname_free(origin, NULL);
 
-       zcreator_t zc = { cont, NULL, KNOT_EOK };
-
        zs_scanner_t sc;
        ok(zs_init(&sc, origin_str, KNOT_CLASS_IN, 3600) == 0 &&
           zs_set_input_string(&sc, zone_str, strlen(zone_str)) == 0 &&
-          zs_set_processing(&sc, process_data, process_error, &zc) == 0 &&
-          zs_parse_all(&sc) == 0, "zscanner initialization");
+          zs_set_processing(&sc, process_data, NULL, cont) == 0 &&
+          zs_parse_all(&sc) == 0 &&
+          sc.error.code == ZS_OK, "zscanner processing");
        zs_deinit(&sc);
 
        return cont;