summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2012-03-09 20:18:12 +0100
committerOndřej Surý <ondrej@sury.org>2012-03-09 20:18:12 +0100
commitb5c64fe14e2b779a715756d47d7d4c7e8e5729ea (patch)
treeab7eccc306d6bef3cf66e37203331a0198cfd235
parent329f909f84efaecfc56fa80a329fb91e576b4f31 (diff)
downloadknot-b5c64fe14e2b779a715756d47d7d4c7e8e5729ea.tar.gz
Imported Upstream version 1.0.1upstream/1.0.1
-rw-r--r--RELNOTES16
-rwxr-xr-xconfigure20
-rw-r--r--configure.ac2
-rw-r--r--src/common/evsched.c2
-rw-r--r--src/common/evsched.h3
-rw-r--r--src/common/fdset.c4
-rw-r--r--src/common/fdset.h3
-rw-r--r--src/knot/common.h11
-rw-r--r--src/knot/conf/conf.c17
-rw-r--r--src/knot/ctl/knotc_main.c19
-rw-r--r--src/knot/main.c10
-rw-r--r--src/knot/server/journal.c74
-rw-r--r--src/knot/server/journal.h3
-rw-r--r--src/knot/server/server.c16
-rw-r--r--src/knot/server/tcp-handler.c39
-rw-r--r--src/knot/server/udp-handler.c38
-rw-r--r--src/knot/server/xfr-handler.c338
-rw-r--r--src/knot/server/zones.c189
-rw-r--r--src/knot/server/zones.h7
-rw-r--r--src/knot/zone/zone-dump-text.c103
-rw-r--r--src/knot/zone/zone-dump.h2
-rw-r--r--src/knot/zone/zone-load.c86
-rw-r--r--src/libknot/edns.c3
-rw-r--r--src/libknot/hash/cuckoo-hash-table.c15
-rw-r--r--src/libknot/nameserver/name-server.h15
-rw-r--r--src/libknot/nsec3.c5
-rw-r--r--src/libknot/tsig.c2
-rw-r--r--src/libknot/updates/ddns.c4
-rw-r--r--src/libknot/updates/xfr-in.c6
-rw-r--r--src/libknot/util/error.h4
-rw-r--r--src/libknot/util/libknot_error.c2
-rw-r--r--src/tests/common/events_tests.c2
-rw-r--r--src/zcompile/zcompile.c8
-rw-r--r--src/zcompile/zcompile_main.c7
34 files changed, 633 insertions, 442 deletions
diff --git a/RELNOTES b/RELNOTES
index 85a3121..5e80be9 100644
--- a/RELNOTES
+++ b/RELNOTES
@@ -1,3 +1,19 @@
+v1.0.1 - Mar 9, 2012
+--------------------
+
+New features:
+ * Implemented jitter to REFRESH/RETRY timers.
+ * Implemented magic bytes for journal.
+ * Improved error messages.
+
+Bugfixes:
+ * Problem with creating IXFR journal for bootstrapped zone.
+ * Race condition in processing NOTIFY/SOA queries.
+ * Leak when reloading zone with NSEC3.
+ * Processing of APL RR.
+ * TSIG improper assignment of algorithm type.
+
+
v1.0.0 - Feb 29, 2012
---------------------
diff --git a/configure b/configure
index 89e5f3d..9620f3e 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.68 for knot 1.0.0.
+# Generated by GNU Autoconf 2.68 for knot 1.0.1.
#
# Report bugs to <knot-dns@labs.nic.cz>.
#
@@ -570,8 +570,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='knot'
PACKAGE_TARNAME='knot'
-PACKAGE_VERSION='1.0.0'
-PACKAGE_STRING='knot 1.0.0'
+PACKAGE_VERSION='1.0.1'
+PACKAGE_STRING='knot 1.0.1'
PACKAGE_BUGREPORT='knot-dns@labs.nic.cz'
PACKAGE_URL=''
@@ -1303,7 +1303,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures knot 1.0.0 to adapt to many kinds of systems.
+\`configure' configures knot 1.0.1 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1373,7 +1373,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of knot 1.0.0:";;
+ short | recursive ) echo "Configuration of knot 1.0.1:";;
esac
cat <<\_ACEOF
@@ -1491,7 +1491,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-knot configure 1.0.0
+knot configure 1.0.1
generated by GNU Autoconf 2.68
Copyright (C) 2010 Free Software Foundation, Inc.
@@ -2041,7 +2041,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by knot $as_me 1.0.0, which was
+It was created by knot $as_me 1.0.1, which was
generated by GNU Autoconf 2.68. Invocation command line was
$ $0 $@
@@ -2859,7 +2859,7 @@ fi
# Define the identity of the package.
PACKAGE='knot'
- VERSION='1.0.0'
+ VERSION='1.0.1'
cat >>confdefs.h <<_ACEOF
@@ -14892,7 +14892,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by knot $as_me 1.0.0, which was
+This file was extended by knot $as_me 1.0.1, which was
generated by GNU Autoconf 2.68. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -14958,7 +14958,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-knot config.status 1.0.0
+knot config.status 1.0.1
configured by $0, generated by GNU Autoconf 2.68,
with options \\"\$ac_cs_config\\"
diff --git a/configure.ac b/configure.ac
index f5551dc..208cbde 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,7 +1,7 @@
# -*- Autoconf -*-
AC_PREREQ([2.65])
-AC_INIT([knot], [1.0.0], [knot-dns@labs.nic.cz])
+AC_INIT([knot], [1.0.1], [knot-dns@labs.nic.cz])
AM_INIT_AUTOMAKE([gnu -Wall -Werror])
AC_CONFIG_SRCDIR([src/knot/main.c])
AC_CONFIG_HEADERS([src/config.h])
diff --git a/src/common/evsched.c b/src/common/evsched.c
index 386478a..cc2cf7c 100644
--- a/src/common/evsched.c
+++ b/src/common/evsched.c
@@ -325,6 +325,6 @@ int evsched_cancel(evsched_t *s, event_t *ev)
/* Enable running events. */
pthread_mutex_unlock(&s->rl);
- return 0;
+ return found;
}
diff --git a/src/common/evsched.h b/src/common/evsched.h
index 2a682e1..8ca9c62 100644
--- a/src/common/evsched.h
+++ b/src/common/evsched.h
@@ -212,7 +212,8 @@ event_t* evsched_schedule_term(evsched_t *s, uint32_t dt);
* \param s Event scheduler.
* \param ev Scheduled event.
*
- * \retval 0 on success.
+ * \retval 0 if already ran.
+ * \retval 1 if found and cancelled.
* \retval <0 on error.
*/
int evsched_cancel(evsched_t *s, event_t *ev);
diff --git a/src/common/fdset.c b/src/common/fdset.c
index a281473..d674d4a 100644
--- a/src/common/fdset.c
+++ b/src/common/fdset.c
@@ -173,7 +173,7 @@ int fdset_set_watchdog(fdset_t* fdset, int fd, int interval)
return 0;
}
-int fdset_sweep(fdset_t* fdset, void(*cb)(fdset_t*, int))
+int fdset_sweep(fdset_t* fdset, void(*cb)(fdset_t*, int, void*), void *data)
{
fdset_base_t *base = (fdset_base_t*)fdset;
if (base == NULL || base->atimes == NULL) {
@@ -195,7 +195,7 @@ int fdset_sweep(fdset_t* fdset, void(*cb)(fdset_t*, int))
/* Evaluate */
timev_t *ts = (timev_t*)n->value;
if (ts->tv_sec <= now.tv_sec) {
- cb(fdset, (int)(((ssize_t)n->key)));
+ cb(fdset, (int)(((ssize_t)n->key)), data);
++sweeped;
}
n = pnext;
diff --git a/src/common/fdset.h b/src/common/fdset.h
index a40cb4a..ead4d5b 100644
--- a/src/common/fdset.h
+++ b/src/common/fdset.h
@@ -224,11 +224,12 @@ int fdset_set_watchdog(fdset_t* fdset, int fd, int interval);
*
* \param fdset Target set.
* \param cb Callback for sweeped descriptors.
+ * \param data Custom data for sweep operation.
*
* \retval number of sweeped descriptors.
* \retval -1 on errors.
*/
-int fdset_sweep(fdset_t* fdset, void(*cb)(fdset_t* set, int fd));
+int fdset_sweep(fdset_t* fdset, void(*cb)(fdset_t*, int, void*), void *data);
#endif /* _KNOTD_FDSET_H_ */
diff --git a/src/knot/common.h b/src/knot/common.h
index e9cfce1..027962a 100644
--- a/src/knot/common.h
+++ b/src/knot/common.h
@@ -128,6 +128,17 @@ typedef unsigned int uint; /*!< \brief Unsigned. */
} while (0)
#endif
+/* Workarounds for clock_gettime() not available on some platforms. */
+#ifdef HAVE_CLOCK_GETTIME
+#define time_now(x) clock_gettime(CLOCK_MONOTONIC, (x))
+typedef struct timespec timev_t;
+#elif HAVE_GETTIMEOFDAY
+#define time_now(x) gettimeofday((x), NULL)
+typedef struct timeval timev_t;
+#else
+#error Neither clock_gettime() nor gettimeofday() found. At least one is required.
+#endif
+
#endif /* _KNOTD_COMMON_H_ */
/*! @} */
diff --git a/src/knot/conf/conf.c b/src/knot/conf/conf.c
index 2c5747a..2cb4516 100644
--- a/src/knot/conf/conf.c
+++ b/src/knot/conf/conf.c
@@ -234,6 +234,23 @@ static int conf_process(conf_t *conf)
if (zone->ixfr_fslimit == 0) {
zone->ixfr_fslimit = conf->ixfr_fslimit;
}
+
+ // Relative zone filenames should be relative to storage
+ if (zone->file[0] != '/') {
+ size_t prefix_len = strlen(conf->storage) + 1; // + '\0'
+ size_t zp_len = strlen(zone->file) + 1;
+ char *ap = malloc(prefix_len + zp_len);
+ if (ap != NULL) {
+ memcpy(ap, conf->storage, prefix_len);
+ ap[prefix_len - 1] = '/';
+ memcpy(ap + prefix_len, zone->file, zp_len);
+ free(zone->file);
+ zone->file = ap;
+ } else {
+ ret = KNOTD_ENOMEM;
+ continue;
+ }
+ }
// Normalize zone filename
zone->file = strcpath(zone->file);
diff --git a/src/knot/ctl/knotc_main.c b/src/knot/ctl/knotc_main.c
index 59556c1..814fbc3 100644
--- a/src/knot/ctl/knotc_main.c
+++ b/src/knot/ctl/knotc_main.c
@@ -91,7 +91,22 @@ int check_zone(const char *db, const char* source)
/* Check zonefile. */
struct stat st;
if (stat(source, &st) != 0) {
- fprintf(stderr, "Zone file '%s' doesn't exist.\n", source);
+ int reason = errno;
+ const char *emsg = "";
+ switch(reason) {
+ case EACCES:
+ emsg = "Not enough permissions to access zone file '%s'.\n";
+ break;
+ case ENOENT:
+ emsg = "Zone file '%s' doesn't exist.\n";
+ break;
+ default:
+ emsg = "Unable to stat zone file '%s'.\n";
+ break;
+ }
+
+ fprintf(stderr, "error: ");
+ fprintf(stderr, emsg, source);
return KNOTD_ENOENT;
}
@@ -546,7 +561,7 @@ int execute(const char *action, char **argv, int argc, pid_t pid,
/* Wait for all running tasks. */
while (running > 0) {
- zctask_wait(tasks, jobs);
+ rc |= zctask_wait(tasks, jobs);
--running;
}
free(tasks);
diff --git a/src/knot/main.c b/src/knot/main.c
index f63916a..e83551c 100644
--- a/src/knot/main.c
+++ b/src/knot/main.c
@@ -249,7 +249,7 @@ int main(int argc, char **argv)
// Run server
int res = 0;
log_server_info("Starting server...\n");
- if ((res = server_start(server)) == KNOTD_EOK) {
+ if ((server_start(server)) == KNOTD_EOK) {
// Save PID
int has_pid = 1;
@@ -264,7 +264,9 @@ int main(int argc, char **argv)
if (daemonize) {
log_server_info("Server started as a daemon, "
"PID = %ld\n", (long)getpid());
- res = chdir("/");
+ if (chdir("/") != 0) {
+ res = 1;
+ }
} else {
log_server_info("Server started in foreground, "
"PID = %ld\n", (long)getpid());
@@ -339,9 +341,10 @@ int main(int argc, char **argv)
}
pthread_sigmask(SIG_UNBLOCK, &sa.sa_mask, NULL);
- if ((res = server_wait(server)) != KNOTD_EOK) {
+ if ((server_wait(server)) != KNOTD_EOK) {
log_server_error("An error occured while "
"waiting for server to finish.\n");
+ res = 1;
} else {
log_server_info("Server finished.\n");
}
@@ -349,6 +352,7 @@ int main(int argc, char **argv)
} else {
log_server_fatal("An error occured while "
"starting the server.\n");
+ res = 1;
}
// Stop server and close log
diff --git a/src/knot/server/journal.c b/src/knot/server/journal.c
index 02e0547..6b566f6 100644
--- a/src/knot/server/journal.c
+++ b/src/knot/server/journal.c
@@ -23,6 +23,7 @@
#include "knot/other/error.h"
#include "knot/other/debug.h"
+#include "knot/zone/zone-dump.h"
#include "journal.h"
/*! \brief Infinite file size limit. */
@@ -159,6 +160,13 @@ int journal_create(const char *fn, uint16_t max_nodes)
/* Create journal header. */
dbg_journal("journal: creating header\n");
+ const char magic[MAGIC_LENGTH] = MAGIC_BYTES;
+ if (!sfwrite(magic, MAGIC_LENGTH, fd)) {
+ fcntl(fd, F_SETLK, &fl);
+ close(fd);
+ remove(fn);
+ return KNOTD_ERROR;
+ }
if (!sfwrite(&max_nodes, sizeof(uint16_t), fd)) {
fcntl(fd, F_SETLK, &fl);
close(fd);
@@ -229,20 +237,12 @@ journal_t* journal_open(const char *fn, size_t fslimit, int mode, uint16_t bflag
if (fn == NULL) {
return NULL;
}
-
- /* Check for lazy mode. */
- if (mode & JOURNAL_LAZY) {
- dbg_journal("journal: opening journal %s lazily\n", fn);
- journal_t *j = malloc(sizeof(journal_t));
- if (j != NULL) {
- memset(j, 0, sizeof(journal_t));
- j->fd = -1;
- j->path = strdup(fn);
- j->fslimit = fslimit;
- j->bflags = bflags;
- j->refs = 1;
- }
- return j;
+
+ /* Open journal file for r/w (returns error if not exists). */
+ int fd = open(fn, O_RDWR);
+ if (fd < 0) {
+ dbg_journal("journal: failed to open file '%s'\n", fn);
+ return NULL;
}
/* File lock. */
@@ -253,13 +253,6 @@ journal_t* journal_open(const char *fn, size_t fslimit, int mode, uint16_t bflag
fl.l_start = 0;
fl.l_len = 0;
fl.l_pid = getpid();
-
- /* Open journal file for r/w (returns error if not exists). */
- int fd = open(fn, O_RDWR);
- if (fd < 0) {
- dbg_journal("journal: failed to open file '%s'\n", fn);
- return NULL;
- }
/* Attempt to lock. */
dbg_journal_verb("journal: locking journal %s\n", fn);
@@ -278,6 +271,41 @@ journal_t* journal_open(const char *fn, size_t fslimit, int mode, uint16_t bflag
}
fl.l_type = F_UNLCK;
dbg_journal("journal: locked journal %s (returned %d)\n", fn, ret);
+
+ /* Read magic bytes. */
+ dbg_journal("journal: reading magic bytes\n");
+ const char magic_req[MAGIC_LENGTH] = MAGIC_BYTES;
+ char magic[MAGIC_LENGTH];
+ if (!sfread(magic, MAGIC_LENGTH, fd)) {
+ dbg_journal_detail("journal: cannot read magic bytes\n");
+ fcntl(fd, F_SETLK, &fl);
+ close(fd);
+ return NULL;
+ }
+ if (memcmp(magic, magic_req, MAGIC_LENGTH) != 0) {
+ log_server_warning("Journal file '%s' version is too old, "
+ "it will be flushed.\n", fn);
+ fcntl(fd, F_SETLK, &fl);
+ close(fd);
+ return NULL;
+ }
+
+ /* Check for lazy mode. */
+ if (mode & JOURNAL_LAZY) {
+ dbg_journal("journal: opening journal %s lazily\n", fn);
+ journal_t *j = malloc(sizeof(journal_t));
+ if (j != NULL) {
+ memset(j, 0, sizeof(journal_t));
+ j->fd = -1;
+ j->path = strdup(fn);
+ j->fslimit = fslimit;
+ j->bflags = bflags;
+ j->refs = 1;
+ }
+ fcntl(fd, F_SETLK, &fl);
+ close(fd);
+ return j;
+ }
/* Read maximum number of entries. */
uint16_t max_nodes = 512;
@@ -299,13 +327,13 @@ journal_t* journal_open(const char *fn, size_t fslimit, int mode, uint16_t bflag
/* Allocate journal structure. */
const size_t node_len = sizeof(journal_node_t);
journal_t *j = malloc(sizeof(journal_t) + max_nodes * node_len);
- memset(j, 0, sizeof(journal_t) + max_nodes * node_len);
- if (!j) {
+ if (j == NULL) {
dbg_journal_detail("journal: cannot allocate journal\n");
fcntl(fd, F_SETLK, &fl);
close(fd);
return NULL;
}
+ memset(j, 0, sizeof(journal_t) + max_nodes * node_len);
j->qhead = j->qtail = 0;
j->fd = fd;
j->max_nodes = max_nodes;
diff --git a/src/knot/server/journal.h b/src/knot/server/journal.h
index b04945d..b12bfc9 100644
--- a/src/knot/server/journal.h
+++ b/src/knot/server/journal.h
@@ -43,6 +43,7 @@
#include <stdint.h>
#include <fcntl.h>
+#include "knot/zone/zone-dump.h"
/*!
* \brief Journal entry flags.
@@ -124,7 +125,7 @@ typedef int (*journal_apply_t)(journal_t *j, journal_node_t *n);
* Journal defaults and constants.
*/
#define JOURNAL_NCOUNT 1024 /*!< Default node count. */
-#define JOURNAL_HSIZE (sizeof(uint16_t) * 3) /*!< max_entries, qhead, qtail */
+#define JOURNAL_HSIZE (MAGIC_LENGTH + sizeof(uint16_t) * 3) /*!< magic, max_entries, qhead, qtail */
/*!
* \brief Create new journal.
diff --git a/src/knot/server/server.c b/src/knot/server/server.c
index 5e7b6e0..ceab716 100644
--- a/src/knot/server/server.c
+++ b/src/knot/server/server.c
@@ -156,12 +156,12 @@ static int server_init_iface(iface_t *new_if, conf_iface_t *cfg_if)
char ebuf[512];
if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &snd_opt, sizeof(snd_opt)) < 0) {
strerror_r(errno, ebuf, sizeof(ebuf));
- log_server_warning("Failed to configure socket "
- "write buffers: %s.\n", ebuf);
+// log_server_warning("Failed to configure socket "
+// "write buffers: %s.\n", ebuf);
}
if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
strerror_r(errno, ebuf, sizeof(ebuf));
- log_server_warning("Failed to configure socket read buffers: %s.\n", ebuf);
+// log_server_warning("Failed to configure socket read buffers: %s.\n", ebuf);
}
/* Create TCP socket. */
@@ -717,7 +717,7 @@ int server_conf_hook(const struct conf_t *conf, void *data)
/* Collect results. */
if (ret < 0) {
log_server_error("Failed to set supplementary groups "
- "for uid=%d %s\n",
+ "for uid '%d' (%s).\n",
getuid(), strerror(errno));
priv_failed = 1;
}
@@ -726,17 +726,17 @@ int server_conf_hook(const struct conf_t *conf, void *data)
/* Watch uid/gid. */
if (conf->gid > -1 && conf->gid != getgid()) {
- log_server_info("Changing group id to %d.\n", conf->gid);
+ log_server_info("Changing group id to '%d'.\n", conf->gid);
if (setregid(conf->gid, conf->gid) < 0) {
- log_server_error("Failed to change gid to %d.\n",
+ log_server_error("Failed to change gid to '%d'.\n",
conf->gid);
priv_failed = 1;
}
}
if (conf->uid > -1 && conf->uid != getuid()) {
- log_server_info("Changing user id to %d.\n", conf->uid);
+ log_server_info("Changing user id to '%d'.\n", conf->uid);
if (setreuid(conf->uid, conf->uid) < 0) {
- log_server_error("Failed to change uid to %d.\n",
+ log_server_error("Failed to change uid to '%d'.\n",
conf->uid);
priv_failed = 1;
}
diff --git a/src/knot/server/tcp-handler.c b/src/knot/server/tcp-handler.c
index 8f4b990..a59ba7c 100644
--- a/src/knot/server/tcp-handler.c
+++ b/src/knot/server/tcp-handler.c
@@ -40,18 +40,6 @@
#include "libknot/util/error.h"
#include "libknot/util/wire.h"
-/* Workarounds for clock_gettime() not available on some platforms. */
-#ifdef HAVE_CLOCK_GETTIME
-#define time_now(x) clock_gettime(CLOCK_MONOTONIC, (x))
-typedef struct timespec timev_t;
-#elif HAVE_GETTIMEOFDAY
-#define time_now(x) gettimeofday((x), NULL)
-typedef struct timeval timev_t;
-#else
-#error Neither clock_gettime() nor gettimeofday() found. At least one is required.
-#endif
-
-
/* Defines */
#define TCP_BUFFER_SIZE 65535 /*! Do not change, as it is used for maximum DNS/TCP packet size. */
@@ -108,7 +96,10 @@ static int tcp_reply(int fd, uint8_t *qbuf, size_t resp_len)
}
/*! \brief Sweep TCP connection. */
-static void tcp_sweep(fdset_t *set, int fd) {
+static void tcp_sweep(fdset_t *set, int fd, void* data)
+{
+ UNUSED(data);
+
char r_addr[SOCKADDR_STRLEN] = { '\0' };
int r_port = 0;
struct sockaddr_storage addr;
@@ -183,10 +174,7 @@ static int tcp_handle(tcp_worker_t *w, int fd, uint8_t *qbuf, size_t qbuf_maxlen
/* Parse query. */
// knot_response_t *resp = knot_response_new(qbuf_maxlen);
size_t resp_len = qbuf_maxlen; // 64K
-
- /* Parse query. */
knot_packet_type_t qtype = KNOT_QUERY_NORMAL;
-
knot_packet_t *packet =
knot_packet_new(KNOT_PACKET_PREALLOC_QUERY);
if (packet == NULL) {
@@ -197,11 +185,11 @@ static int tcp_handle(tcp_worker_t *w, int fd, uint8_t *qbuf, size_t qbuf_maxlen
return KNOTD_EOK;
}
- int res = knot_ns_parse_packet(qbuf, n, packet, &qtype);
- if (unlikely(res != KNOT_EOK)) {
- if (res > 0) { /* Returned RCODE */
+ int parse_res = knot_ns_parse_packet(qbuf, n, packet, &qtype);
+ if (unlikely(parse_res != KNOT_EOK)) {
+ if (parse_res > 0) { /* Returned RCODE */
uint16_t pkt_id = knot_wire_get_id(qbuf);
- knot_ns_error_response(ns, pkt_id, res,
+ knot_ns_error_response(ns, pkt_id, parse_res,
qbuf, &resp_len);
tcp_reply(fd, qbuf, resp_len);
}
@@ -212,13 +200,16 @@ static int tcp_handle(tcp_worker_t *w, int fd, uint8_t *qbuf, size_t qbuf_maxlen
/* Handle query. */
int xfrt = -1;
knot_ns_xfr_t xfr;
- res = KNOTD_ERROR;
+ int res = KNOTD_ERROR;
switch(qtype) {
/* Query types. */
case KNOT_QUERY_NORMAL:
//res = knot_ns_answer_normal(ns, packet, qbuf, &resp_len);
- res = zones_normal_query_answer(ns, packet, &addr, qbuf, &resp_len);
+ if (zones_normal_query_answer(ns, packet, &addr,
+ qbuf, &resp_len) == KNOT_EOK) {
+ res = KNOTD_EOK;
+ }
break;
case KNOT_QUERY_AXFR:
case KNOT_QUERY_IXFR:
@@ -288,7 +279,7 @@ static int tcp_handle(tcp_worker_t *w, int fd, uint8_t *qbuf, size_t qbuf_maxlen
qtype, fd, knotd_strerror(res));;
}
- return KNOTD_EOK;
+ return res;
}
static int tcp_accept(int fd)
@@ -591,7 +582,7 @@ int tcp_loop_worker(dthread_t *thread)
timev_t now;
if (time_now(&now) == 0) {
if (now.tv_sec >= next_sweep.tv_sec) {
- fdset_sweep(w->fdset, &tcp_sweep);
+ fdset_sweep(w->fdset, &tcp_sweep, NULL);
memcpy(&next_sweep, &now, sizeof(next_sweep));
next_sweep.tv_sec += TCP_SWEEP_INTERVAL;
}
diff --git a/src/knot/server/udp-handler.c b/src/knot/server/udp-handler.c
index 5276c24..6e50926 100644
--- a/src/knot/server/udp-handler.c
+++ b/src/knot/server/udp-handler.c
@@ -194,6 +194,7 @@ static inline int udp_master_recvfrom(dthread_t *thread, stat_t *thread_stat)
knot_nameserver_t *ns = h->server->nameserver;
+ /* Initialize remote party address. */
sockaddr_t addr;
if (sockaddr_init(&addr, h->type) != KNOTD_EOK) {
log_server_error("Socket type %d is not supported, "
@@ -202,6 +203,14 @@ static inline int udp_master_recvfrom(dthread_t *thread, stat_t *thread_stat)
return KNOTD_ENOTSUP;
}
+ /* Allocate buffer for answering. */
+ uint8_t *qbuf = malloc(SOCKET_MTU_SZ);
+ if (qbuf == NULL) {
+ dbg_net("udp: out of memory when allocating buffer.\n");
+ return KNOTD_ENOMEM;
+ }
+
+ /* Duplicate socket for performance reasons on some OS's */
int sock = h->fd;
int sock_dup = dup(h->fd);
if (sock_dup < 0) {
@@ -209,7 +218,6 @@ static inline int udp_master_recvfrom(dthread_t *thread, stat_t *thread_stat)
} else {
sock = sock_dup;
}
- uint8_t qbuf[SOCKET_MTU_SZ];
/* Loop until all data is read. */
ssize_t n = 0;
@@ -263,6 +271,8 @@ static inline int udp_master_recvfrom(dthread_t *thread, stat_t *thread_stat)
if (sock_dup >= 0) {
close(sock_dup);
}
+
+ free(qbuf);
return KNOTD_EOK;
}
@@ -336,12 +346,27 @@ static inline int udp_master_recvmmsg(dthread_t *thread, stat_t *thread_stat)
iohandler_t *h = (iohandler_t *)thread->data;
knot_nameserver_t *ns = h->server->nameserver;
int sock = dup(h->fd);
+
+ /* Check socket. */
+ if (sock < 0) {
+ dbg_net("udp: unable to dup() socket, finishing.\n");
+ return KNOTD_EINVAL;
+ }
/* Allocate batch for N packets. */
char *iobuf = malloc(SOCKET_MTU_SZ * RECVMMSG_BATCHLEN);
sockaddr_t *addrs = malloc(sizeof(sockaddr_t) * RECVMMSG_BATCHLEN);
struct iovec *iov = malloc(sizeof(struct iovec) * RECVMMSG_BATCHLEN);
struct mmsghdr *msgs = malloc(sizeof(struct mmsghdr) * RECVMMSG_BATCHLEN);
+
+ /* Check, free(NULL) is valid, so no need to nitpick. */
+ if (iobuf == NULL || addrs == NULL || iov == NULL || msgs == NULL) {
+ free(iobuf);
+ free(addrs);
+ free(iov);
+ free(msgs);
+ return KNOTD_ENOMEM;
+ }
/* Prepare batch. */
memset(msgs, 0, sizeof(struct mmsghdr) * RECVMMSG_BATCHLEN);
@@ -498,12 +523,17 @@ int udp_master(dthread_t *thread)
/* Execute proper handler. */
dbg_net_verb("udp: thread started (worker %p).\n", thread);
- int ret = KNOTD_EOK;
-
- ret = _udp_master(thread, thread_stat);
+ int ret = _udp_master(thread, thread_stat);
+ if (ret != KNOTD_EOK) {
+ log_server_warning("UDP answering module finished "
+ "with an error (%s).\n",
+ knotd_strerror(ret));
+ }
stat_free(thread_stat);
dbg_net_verb("udp: worker %p finished.\n", thread);
+
+
return ret;
}
diff --git a/src/knot/server/xfr-handler.c b/src/knot/server/xfr-handler.c
index 588670c..3a1b7da 100644
--- a/src/knot/server/xfr-handler.c
+++ b/src/knot/server/xfr-handler.c
@@ -42,6 +42,8 @@
#include "common/prng.h"
/* Constants */
+#define XFR_QUERY_WD 10 /*!< SOA/NOTIFY query timeout [s]. */
+#define XFR_SWEEP_INTERVAL 2 /*! [seconds] between sweeps. */
#define XFR_BUFFER_SIZE 65535 /*! Do not change this - maximum value for UDP packet length. */
void xfr_interrupt(xfrhandler_t *h)
@@ -59,24 +61,72 @@ static void xfr_request_deinit(knot_ns_xfr_t *r)
}
}
-/*!
- * \brief SOA query timeout handler.
- */
-static int xfr_udp_timeout(event_t *e)
+/*! \todo Document me (issue #1586) */
+static void xfr_free_task(knot_ns_xfr_t *task)
{
- knot_ns_xfr_t *data = (knot_ns_xfr_t *)e->data;
- if (!data) {
- return KNOTD_EINVAL;
+ if (!task) {
+ return;
+ }
+
+ xfrworker_t *w = (xfrworker_t *)task->owner;
+ if (!w) {
+ free(task);
+ return;
+ }
+
+ /* Remove from fdset. */
+ if (w->fdset) {
+ dbg_xfr("xfr_free_task: freeing fd=%d.\n", task->session);
+ fdset_remove(w->fdset, task->session);
}
- /* Remove reference to this event. */
- if (data->zone != NULL) {
- zonedata_t *zd = (zonedata_t *)knot_zone_data(data->zone);
- if (zd != NULL && zd->soa_pending == e) {
- zd->soa_pending = NULL;
+ /* Unlock if XFR/IN.*/
+ if (task->type == XFR_TYPE_AIN || task->type == XFR_TYPE_IIN) {
+ knot_zone_t *zone = task->zone;
+ zonedata_t *zd = (zonedata_t *)knot_zone_data(zone);
+ if (zd) {
+ zd->xfr_in.wrkr = 0;
+ pthread_mutex_unlock(&zd->xfr_in.lock);
}
}
+ /* Remove fd-related data. */
+ xfrhandler_t *h = w->master;
+ pthread_mutex_lock(&h->tasks_mx);
+ skip_remove(h->tasks, (void*)((size_t)task->session), 0, 0);
+ pthread_mutex_unlock(&h->tasks_mx);
+
+ /* Deinitialize */
+ xfr_request_deinit(task);
+
+ close(task->session);
+ free(task);
+}
+
+static knot_ns_xfr_t *xfr_handler_task(xfrworker_t *w, int fd)
+{
+ xfrhandler_t *h = w->master;
+ pthread_mutex_lock(&h->tasks_mx);
+ knot_ns_xfr_t *data = skip_find(h->tasks, (void*)((size_t)fd));
+ pthread_mutex_unlock(&h->tasks_mx);
+
+ if (data == NULL) {
+ dbg_xfr_verb("xfr: worker=%p processing event on "
+ "fd=%d got empty data.\n",
+ w, fd);
+ fdset_remove(w->fdset, fd);
+ close(fd); /* Always dup()'d or created. */
+ return NULL;
+ }
+
+ return data;
+}
+
+/*!
+ * \brief SOA query timeout handler.
+ */
+static int xfr_udp_timeout(knot_ns_xfr_t *data)
+{
/* Close socket. */
knot_zone_t *z = data->zone;
if (z && knot_zone_get_contents(z) && knot_zone_data(z)) {
@@ -84,21 +134,13 @@ static int xfr_udp_timeout(event_t *e)
data->msgpref);
}
- knot_ns_xfr_t cr = {};
- cr.type = XFR_TYPE_CLOSE;
- cr.session = data->session;
- cr.data = data;
- cr.zone = data->zone;
- xfrworker_t *w = (xfrworker_t *)data->owner;
- if (w) {
- evqueue_write(w->q, &cr, sizeof(knot_ns_xfr_t));
- }
-
+ /* Invalidate pending query. */
+ xfr_free_task(data);
return KNOTD_EOK;
}
/*!
- * \brief Query reponse event handler function.
+ * \brief Query response event handler function.
*
* Handle single query response event.
*
@@ -106,7 +148,7 @@ static int xfr_udp_timeout(event_t *e)
* \param w Associated socket watcher.
* \param revents Returned events.
*/
-static int xfr_process_udp_query(xfrworker_t *w, int fd, knot_ns_xfr_t *data)
+static int xfr_process_udp_resp(xfrworker_t *w, int fd, knot_ns_xfr_t *data)
{
/* Receive msg. */
ssize_t n = recvfrom(data->session, data->wire, data->wire_size, 0, data->addr.ptr, &data->addr.len);
@@ -114,77 +156,36 @@ static int xfr_process_udp_query(xfrworker_t *w, int fd, knot_ns_xfr_t *data)
if (n > 0) {
udp_handle(fd, data->wire, n, &resp_len, &data->addr, w->ns);
}
-
- if(data->type == XFR_TYPE_SOA && data->zone) {
- zonedata_t * zd = (zonedata_t*)knot_zone_data(data->zone);
- zd->soa_pending = NULL;
- }
-
- /* Disable timeout. */
- evsched_t *sched =
- ((server_t *)knot_ns_get_data(w->ns))->sched;
- event_t *ev = (event_t *)data->data;
- if (ev) {
- dbg_xfr("xfr: cancelling UDP query timeout\n");
- evsched_cancel(sched, ev);
- ev = (event_t *)data->data;
- if (ev) {
- evsched_event_free(sched, ev);
- data->data = 0;
- }
-
- /* Close after receiving response. */
- knot_ns_xfr_t cr = {};
- cr.type = XFR_TYPE_CLOSE;
- cr.session = data->session;
- cr.data = data;
- cr.zone = data->zone;
- evqueue_write(w->q, &cr, sizeof(knot_ns_xfr_t));
- }
-
+
+ xfr_free_task(data);
return KNOTD_EOK;
}
-/*! \todo Document me (issue #1586) */
-static void xfr_free_task(knot_ns_xfr_t *task)
+/*! \brief Sweep non-replied connection. */
+static void xfr_sweep(fdset_t *set, int fd, void *data)
{
- if (!task) {
- return;
- }
+ dbg_xfr("xfr: sweeping fd=%d\n", fd);
- xfrworker_t *w = (xfrworker_t *)task->owner;
- if (!w) {
- free(task);
+ if (!set || !data) {
+ dbg_xfr("xfr: invalid sweep operation on NULL worker or set\n");
return;
}
-
- /* Remove from fdset. */
- if (w->fdset) {
- dbg_xfr("xfr_free_task: freeing fd=%d.\n", task->session);
- fdset_remove(w->fdset, task->session);
+ knot_ns_xfr_t *t = xfr_handler_task((xfrworker_t *)data, fd);
+ if (!t) {
+ dbg_xfr("xfr: NULL data to sweep\n");
+ return;
}
- /* Unlock if XFR/IN.*/
- if (task->type == XFR_TYPE_AIN || task->type == XFR_TYPE_IIN) {
- knot_zone_t *zone = task->zone;
- zonedata_t *zd = (zonedata_t *)knot_zone_data(zone);
- if (zd) {
- zd->xfr_in.wrkr = 0;
- pthread_mutex_unlock(&zd->xfr_in.lock);
- }
+ /* Skip non-sweepable types. */
+ switch(t->type) {
+ case XFR_TYPE_SOA:
+ case XFR_TYPE_NOTIFY:
+ xfr_udp_timeout(t);
+ break;
+ default:
+ dbg_xfr("xfr: sweep request on unsupported type\n");
+ break;
}
-
- /* Remove fd-related data. */
- xfrhandler_t *h = w->master;
- pthread_mutex_lock(&h->tasks_mx);
- skip_remove(h->tasks, (void*)((size_t)task->session), 0, 0);
- pthread_mutex_unlock(&h->tasks_mx);
-
- /* Deinitialize */
- xfr_request_deinit(task);
-
- close(task->session);
- free(task);
}
/*! \todo Document me (issue #1586) */
@@ -197,6 +198,7 @@ static knot_ns_xfr_t *xfr_register_task(xfrworker_t *w, knot_ns_xfr_t *req)
memcpy(t, req, sizeof(knot_ns_xfr_t));
sockaddr_update(&t->addr);
+ sockaddr_update(&t->saddr);
/* Update request. */
t->wire = 0; /* Invalidate shared buffer. */
@@ -287,24 +289,27 @@ static int xfr_xfrin_finalize(xfrworker_t *w, knot_ns_xfr_t *data)
// }
int ret = KNOTD_EOK;
+ int apply_ret = KNOT_EOK;
+ int switch_ret = KNOT_EOK;
knot_changesets_t *chs = NULL;
switch(data->type) {
case XFR_TYPE_AIN:
- dbg_xfr("xfr: AXFR/IN saving new zone\n");
+ dbg_xfr("xfr: %s Saving new zone file.\n", data->msgpref);
ret = zones_save_zone(data);
if (ret != KNOTD_EOK) {
xfr_xfrin_cleanup(w, data);
log_zone_error("%s Failed to save transferred zone - %s\n",
data->msgpref, knotd_strerror(ret));
} else {
- dbg_xfr("xfr: AXFR/IN new zone saved.\n");
- ret = knot_ns_switch_zone(w->ns, data);
- if (ret != KNOT_EOK) {
+ dbg_xfr("xfr: %s New zone saved.\n", data->msgpref);
+ switch_ret = knot_ns_switch_zone(w->ns, data);
+ if (switch_ret != KNOT_EOK) {
log_zone_error("%s Failed to switch in-memory "
"zone - %s\n", data->msgpref,
- knot_strerror(ret));
+ knot_strerror(switch_ret));
xfr_xfrin_cleanup(w, data);
+ ret = KNOTD_ERROR;
}
}
if (ret == KNOTD_EOK) {
@@ -327,21 +332,21 @@ static int xfr_xfrin_finalize(xfrworker_t *w, knot_ns_xfr_t *data)
}
/* Now, try to apply the changesets to the zone. */
- ret = xfrin_apply_changesets(data->zone, chs,
- &data->new_contents);
+ apply_ret = xfrin_apply_changesets(data->zone, chs,
+ &data->new_contents);
- if (ret != KNOT_EOK) {
+ if (apply_ret != KNOT_EOK) {
log_zone_error("%s Failed to apply changesets - %s\n",
data->msgpref,
- knot_strerror(ret));
+ knot_strerror(apply_ret));
/* Free changesets, but not the data. */
knot_free_changesets(&chs);
data->data = 0;
-
ret = KNOTD_ERROR;
break;
}
+
/* Save changesets. */
dbg_xfr("xfr: IXFR/IN saving changesets\n");
@@ -366,14 +371,14 @@ static int xfr_xfrin_finalize(xfrworker_t *w, knot_ns_xfr_t *data)
break;
}
/* Switch zone contents. */
- ret = xfrin_switch_zone(data->zone, data->new_contents,
- data->type);
+ switch_ret = xfrin_switch_zone(data->zone, data->new_contents,
+ data->type);
- if (ret != KNOT_EOK) {
+ if (switch_ret != KNOT_EOK) {
log_zone_error("%s Failed to replace "
"current zone - %s\n",
data->msgpref,
- knot_strerror(ret));
+ knot_strerror(switch_ret));
// Cleanup old and new contents
xfrin_rollback_update(data->zone->contents,
&data->new_contents,
@@ -382,7 +387,6 @@ static int xfr_xfrin_finalize(xfrworker_t *w, knot_ns_xfr_t *data)
/* Free changesets, but not the data. */
knot_free_changesets(&chs);
data->data = 0;
-
ret = KNOTD_ERROR;
break;
}
@@ -488,24 +492,14 @@ static int xfr_check_tsig(knot_ns_xfr_t *xfr, knot_rcode_t *rcode, char **tag)
if (key && kname && knot_dname_compare(key->name, kname) == 0) {
dbg_xfr("xfr: found claimed TSIG key for comparison\n");
} else {
- /*! \todo These ifs are redundant (issue #1586) */
- *rcode = KNOT_RCODE_NOTAUTH;
- /* TSIG is mandatory if configured for interface. */
- if (key && !kname) {
- dbg_xfr("xfr: TSIG key is mandatory for "
- "this interface\n");
- ret = KNOT_TSIG_EBADKEY;
- xfr->tsig_rcode = KNOT_TSIG_RCODE_BADKEY;
- }
+ /* TSIG is mandatory if configured for interface. */
/* Configured, but doesn't match. */
- if (kname) {
- dbg_xfr("xfr: no claimed key configured, "
- "treating as bad key\n");
- ret = KNOT_TSIG_EBADKEY;
- xfr->tsig_rcode = KNOT_TSIG_RCODE_BADKEY;
- }
-
+ dbg_xfr("xfr: no claimed key configured or not received"
+ ", treating as bad key\n");
+ *rcode = KNOT_RCODE_NOTAUTH;
+ ret = KNOT_TSIG_EBADKEY;
+ xfr->tsig_rcode = KNOT_TSIG_RCODE_BADKEY;
key = 0; /* Invalidate, ret already set to BADKEY */
}
@@ -593,7 +587,7 @@ int xfr_process_event(xfrworker_t *w, int fd, knot_ns_xfr_t *data, uint8_t *buf,
/* Handle SOA/NOTIFY responses. */
if (data->type == XFR_TYPE_NOTIFY || data->type == XFR_TYPE_SOA) {
- return xfr_process_udp_query(w, fd, data);
+ return xfr_process_udp_resp(w, fd, data);
}
/* Read DNS/TCP packet. */
@@ -752,6 +746,7 @@ static int xfr_client_start(xfrworker_t *w, knot_ns_xfr_t *data)
return KNOTD_EOK;
} else {
zd->xfr_in.wrkr = w;
+ --zd->xfr_in.scheduled;
}
/* Connect to remote. */
@@ -858,7 +853,10 @@ static int xfr_client_start(xfrworker_t *w, knot_ns_xfr_t *data)
/* Start transfer. */
ret = data->send(data->session, &data->addr, data->wire, bufsize);
if (ret != bufsize) {
- log_server_info("%s Failed to send query.\n", data->msgpref);
+ char buf[1024];
+ strerror_r(errno, buf, sizeof(buf));
+ log_server_info("%s Failed to send query (%s).\n",
+ data->msgpref, buf);
pthread_mutex_unlock(&zd->xfr_in.lock);
return KNOTD_ECONNREFUSED;
}
@@ -952,12 +950,6 @@ static int xfr_update_msgpref(knot_ns_xfr_t *req, const char *keytag)
return KNOTD_EINVAL;
}
- /* Update address. */
- if (req->msgpref) {
- free(req->msgpref);
- req->msgpref = NULL;
- }
-
char r_addr[SOCKADDR_STRLEN];
char *r_key = NULL;
int r_port = sockaddr_portnum(&req->addr);
@@ -1092,7 +1084,7 @@ xfrhandler_t *xfr_create(size_t thrcount, knot_nameserver_t *ns)
return NULL;
}
memset(data, 0, sizeof(xfrhandler_t));
-
+
/* Create RR mutex. */
pthread_mutex_init(&data->rr_mx, 0);
@@ -1220,11 +1212,15 @@ int xfr_request(xfrhandler_t *handler, knot_ns_xfr_t *req)
return KNOTD_EINVAL;
}
- /* Get next worker in RR fashion */
- pthread_mutex_lock(&handler->rr_mx);
- evqueue_t *q = handler->workers[handler->rr]->q;
- handler->rr = get_next_rr(handler->rr, handler->unit->size);
- pthread_mutex_unlock(&handler->rr_mx);
+ /* Assign UDP requests to handler 0. */
+ evqueue_t *q = handler->workers[0]->q;
+ if (!(req->flags & XFR_FLAG_UDP)) {
+ /* Get next worker in RR fashion */
+ pthread_mutex_lock(&handler->rr_mx);
+ q = handler->workers[handler->rr + 1]->q;
+ handler->rr = get_next_rr(handler->rr, handler->unit->size - 1);
+ pthread_mutex_unlock(&handler->rr_mx);
+ }
/* Delegate request. */
int ret = evqueue_write(q, req, sizeof(knot_ns_xfr_t));
@@ -1257,9 +1253,9 @@ int xfr_answer(knot_nameserver_t *ns, knot_ns_xfr_t *xfr)
/* Check requested zone. */
if (!xfr_failed) {
- ret = zones_xfr_check_zone(xfr, &xfr->rcode);
- xfr_failed = (ret != KNOTD_EOK);
- errstr = knotd_strerror(ret);
+ int zcheck_ret = zones_xfr_check_zone(xfr, &xfr->rcode);
+ xfr_failed = (zcheck_ret != KNOTD_EOK);
+ errstr = knotd_strerror(zcheck_ret);
}
/* Check TSIG. */
@@ -1270,22 +1266,21 @@ int xfr_answer(knot_nameserver_t *ns, knot_ns_xfr_t *xfr)
errstr = knot_strerror(ret);
}
- ret = xfr_update_msgpref(xfr, keytag);
- free(keytag);
- if (ret != KNOTD_EOK) {
+ if (xfr_update_msgpref(xfr, keytag) != KNOTD_EOK) {
xfr->msgpref = strdup("XFR:");
}
+ free(keytag);
/* Prepare place for TSIG data */
xfr->tsig_data = malloc(KNOT_NS_TSIG_DATA_MAX_SIZE);
if (xfr->tsig_data) {
dbg_xfr("xfr: TSIG data allocated: %zu.\n",
- KNOT_NS_TSIG_DATA_MAX_SIZE);
+ KNOT_NS_TSIG_DATA_MAX_SIZE);
xfr->tsig_data_size = 0;
} else {
dbg_xfr("xfr: failed to allocate TSIG data "
- "buffer (%zu kB)\n",
- KNOT_NS_TSIG_DATA_MAX_SIZE / 1024);
+ "buffer (%zu kB)\n",
+ KNOT_NS_TSIG_DATA_MAX_SIZE / 1024);
}
/* Finally, answer AXFR/IXFR. */
@@ -1298,7 +1293,9 @@ int xfr_answer(knot_nameserver_t *ns, knot_ns_xfr_t *xfr)
case XFR_TYPE_IOUT:
ret = xfr_answer_ixfr(ns, xfr);
break;
- default: ret = KNOTD_ENOTSUP; break;
+ default:
+ ret = KNOT_ENOTSUP;
+ break;
}
xfr_failed = (ret != KNOT_EOK);
@@ -1312,10 +1309,8 @@ int xfr_answer(knot_nameserver_t *ns, knot_ns_xfr_t *xfr)
knot_ns_xfr_send_error(ns, xfr, xfr->rcode);
}
log_server_notice("%s %s\n", xfr->msgpref, errstr);
- ret = KNOTD_ERROR;
} else {
log_server_info("%s Finished.\n", xfr->msgpref);
- ret = KNOTD_EOK;
}
/* Free allocated data. */
@@ -1330,7 +1325,11 @@ int xfr_answer(knot_nameserver_t *ns, knot_ns_xfr_t *xfr)
knot_packet_free(&xfr->response); /* Free response. */
knot_free_changesets((knot_changesets_t **)(&xfr->data));
free(xfr->zname);
- return ret;
+ if (xfr_failed) {
+ return KNOTD_ERROR;
+ }
+
+ return KNOTD_EOK;
}
static int xfr_process_request(xfrworker_t *w, uint8_t *buf, size_t buflen)
@@ -1353,14 +1352,9 @@ static int xfr_process_request(xfrworker_t *w, uint8_t *buf, size_t buflen)
conf_read_lock();
/* Handle request. */
- zonedata_t *zd = NULL;
- if(xfr.zone != NULL) {
- zd = (zonedata_t *)knot_zone_data(xfr.zone);
- }
knot_ns_xfr_t *task = NULL;
- evsched_t *sch = NULL;
- dbg_xfr_verb("xfr: processing request type '%d'\n", xfr.type);
- dbg_xfr_verb("xfr: query ptr: %p\n", xfr.query);
+ dbg_xfr("%s processing request type '%d'\n", xfr.msgpref, xfr.type);
+ dbg_xfr_verb("%s query ptr: %p\n", xfr.msgpref, xfr.query);
switch(xfr.type) {
case XFR_TYPE_AIN:
case XFR_TYPE_IIN:
@@ -1383,20 +1377,10 @@ static int xfr_process_request(xfrworker_t *w, uint8_t *buf, size_t buflen)
}
/* Add timeout. */
- sch = ((server_t *)knot_ns_get_data(w->ns))->sched;
- task->data = evsched_schedule_cb(sch, xfr_udp_timeout,
- task, SOA_QRY_TIMEOUT);
- if (zd && xfr.type == XFR_TYPE_SOA) {
- zd->soa_pending = (event_t*)task->data;
- }
+ fdset_set_watchdog(w->fdset, task->session, XFR_QUERY_WD);
log_server_info("%s Query issued.\n", xfr.msgpref);
ret = KNOTD_EOK;
break;
- /* Socket close event. */
- case XFR_TYPE_CLOSE:
- xfr_free_task((knot_ns_xfr_t *)xfr.data);
- ret = KNOTD_EOK;
- break;
default:
log_server_error("Unknown XFR request type (%d).\n", xfr.type);
break;
@@ -1430,6 +1414,10 @@ int xfr_worker(dthread_t *thread)
return KNOTD_ENOMEM;
}
+ /* Next sweep time. */
+ timev_t next_sweep;
+ time_now(&next_sweep);
+ next_sweep.tv_sec += XFR_SWEEP_INTERVAL;
/* Accept requests. */
int ret = 0;
@@ -1442,8 +1430,8 @@ int xfr_worker(dthread_t *thread)
}
/* Poll fdset. */
- int nfds = fdset_wait(w->fdset, OS_EV_FOREVER);
- if (nfds <= 0) {
+ int nfds = fdset_wait(w->fdset, (XFR_SWEEP_INTERVAL * 1000)/2);
+ if (nfds < 0) {
continue;
}
@@ -1453,12 +1441,11 @@ int xfr_worker(dthread_t *thread)
}
/* Iterate fdset. */
- xfrhandler_t *h = w->master;
knot_ns_xfr_t *data = 0;
int rfd = evqueue_pollfd(w->q);
fdset_it_t it;
fdset_begin(w->fdset, &it);
- while(1) {
+ while(nfds > 0) {
/* Check if it request. */
if (it.fd == rfd) {
@@ -1470,16 +1457,8 @@ int xfr_worker(dthread_t *thread)
}
} else {
/* Find data. */
- pthread_mutex_lock(&h->tasks_mx);
- data = skip_find(h->tasks, (void*)((size_t)it.fd));
- pthread_mutex_unlock(&h->tasks_mx);
+ data = xfr_handler_task(w, it.fd);
if (data == NULL) {
- dbg_xfr_verb("xfr: worker=%p processing event on "
- "fd=%d got empty data.\n",
- w, it.fd);
- fdset_remove(w->fdset, it.fd);
- close(it.fd); /* Always dup()'d or created. */
-
/* Next fd. */
if (fdset_next(w->fdset, &it) < 0) {
break;
@@ -1501,9 +1480,18 @@ int xfr_worker(dthread_t *thread)
break;
}
}
+
+ /* Sweep inactive. */
+ timev_t now;
+ if (time_now(&now) == 0) {
+ if (now.tv_sec >= next_sweep.tv_sec) {
+ fdset_sweep(w->fdset, &xfr_sweep, w);
+ memcpy(&next_sweep, &now, sizeof(next_sweep));
+ next_sweep.tv_sec += XFR_SWEEP_INTERVAL;
+ }
+ }
}
-
/* Stop whole unit. */
free(buf);
dbg_xfr_verb("xfr: worker=%p finished.\n", w);
diff --git a/src/knot/server/zones.c b/src/knot/server/zones.c
index dbc1340..be072e8 100644
--- a/src/knot/server/zones.c
+++ b/src/knot/server/zones.c
@@ -211,6 +211,19 @@ static int zonedata_init(conf_zone_t *cfg, knot_zone_t *zone)
}
/*!
+ * \brief Apply jitter to time interval.
+ *
+ * Amount of jitter is specified by ZONES_JITTER_PCT.
+ *
+ * \param interval base value.
+ * \return interval value minus rand(0, ZONES_JITTER_PCT) %
+ */
+static uint32_t zones_jitter(uint32_t interval)
+{
+ return (interval * (100 - (tls_rand() * ZONES_JITTER_PCT))) / 100;
+}
+
+/*!
* \brief Return SOA timer value.
*
* \param zone Pointer to zone.
@@ -361,10 +374,6 @@ static int zones_refresh_ev(event_t *e)
return KNOTD_EINVAL;
}
- /* Prepare buffer for query. */
- uint8_t qbuf[SOCKET_MTU_SZ];
- size_t buflen = SOCKET_MTU_SZ;
-
/* Lock RCU. */
rcu_read_lock();
@@ -388,21 +397,35 @@ static int zones_refresh_ev(event_t *e)
xfr_req.tsig_key = &zd->xfr_in.tsig_key;
}
- /* Unlock zone contents. */
- rcu_read_unlock();
-
/* Enqueue XFR request. */
int locked = pthread_mutex_trylock(&zd->xfr_in.lock);
if (locked != 0) {
dbg_zones("zones: already bootstrapping '%s'\n",
zd->conf->name);
+ rcu_read_unlock();
return KNOTD_EOK;
}
+ if (zd->xfr_in.scheduled > 0) {
+ /* Already pending bootstrap (unprocessed). */
+ pthread_mutex_unlock(&zd->xfr_in.lock);
+ dbg_zones("zones: already bootstrapping '%s' (q'd)\n",
+ zd->conf->name);
+ rcu_read_unlock();
+ return KNOTD_EOK;
+ }
+
log_zone_info("Attempting to bootstrap zone %s from master\n",
zd->conf->name);
+ ++zd->xfr_in.scheduled;
pthread_mutex_unlock(&zd->xfr_in.lock);
+ /* Unlock zone contents. */
+ rcu_read_unlock();
+
+ /* Mark as finished to prevent stalling. */
+ evsched_event_finished(e->parent);
+
return xfr_request(zd->server->xfr_h, &xfr_req);
}
@@ -414,9 +437,10 @@ static int zones_refresh_ev(event_t *e)
zd->conf->name);
/* Reschedule as RETRY timer. */
- evsched_schedule(e->parent, e, zones_soa_retry(zone));
+ uint32_t retry_tmr = zones_jitter(zones_soa_retry(zone));
+ evsched_schedule(e->parent, e, retry_tmr);
dbg_zones("zones: RETRY of '%s' after %u seconds\n",
- zd->conf->name, zones_soa_retry(zone) / 1000);
+ zd->conf->name, retry_tmr / 1000);
/* Unlock RCU. */
rcu_read_unlock();
@@ -425,9 +449,32 @@ static int zones_refresh_ev(event_t *e)
pthread_mutex_unlock(&zd->xfr_in.lock);
}
- /* Invalidate pending SOA query. */
- event_t *soa_pending = zd->soa_pending;
- zd->soa_pending = NULL;
+ /* Schedule EXPIRE timer on first attempt. */
+ if (!zd->xfr_in.expire) {
+ uint32_t expire_tmr = zones_jitter(zones_soa_expire(zone));
+ zd->xfr_in.expire = evsched_schedule_cb(
+ e->parent,
+ zones_expire_ev,
+ zone, expire_tmr);
+ dbg_zones("zones: EXPIRE of '%s' after %u seconds\n",
+ zd->conf->name, expire_tmr / 1000);
+ }
+
+ /* Reschedule as RETRY timer. */
+ uint32_t retry_tmr = zones_jitter(zones_soa_retry(zone));
+ evsched_schedule(e->parent, e, retry_tmr);
+ dbg_zones("zones: RETRY of '%s' after %u seconds\n",
+ zd->conf->name, retry_tmr / 1000);
+
+ /* Prepare buffer for query. */
+ uint8_t *qbuf = malloc(SOCKET_MTU_SZ);
+ if (qbuf == NULL) {
+ log_zone_error("Not enough memory to allocate SOA query.\n");
+ rcu_read_unlock();
+ return KNOTD_ENOMEM;
+ }
+
+ size_t buflen = SOCKET_MTU_SZ;
/*! \todo [TSIG] CHANGE!!! only for compatibility now. */
knot_ns_xfr_t xfr_req;
@@ -435,13 +482,13 @@ static int zones_refresh_ev(event_t *e)
xfr_req.wire = qbuf;
/* Create query. */
+ int sock = -1;
+ sockaddr_t *master = &zd->xfr_in.master;
int ret = xfrin_create_soa_query(zone->name, &xfr_req, &buflen);
if (ret == KNOT_EOK) {
- sockaddr_t *master = &zd->xfr_in.master;
-
/* Create socket on random port. */
- int sock = socket_create(master->family, SOCK_DGRAM);
+ sock = socket_create(master->family, SOCK_DGRAM);
/* Check requested source. */
sockaddr_t *via = &zd->xfr_in.via;
@@ -473,52 +520,39 @@ static int zones_refresh_ev(event_t *e)
dbg_zones("zones: expecting SOA response "
"ID=%d for '%s'\n",
zd->xfr_in.next_id, zd->conf->name);
-
- /* Watch socket. */
- knot_ns_xfr_t req;
- memset(&req, 0, sizeof(req));
- req.session = sock;
- req.type = XFR_TYPE_SOA;
- req.zone = zone;
- memcpy(&req.addr, master, sizeof(sockaddr_t));
- memcpy(&req.saddr, &zd->xfr_in.via, sizeof(sockaddr_t));
- sockaddr_update(&req.addr);
- ret = xfr_request(zd->server->xfr_h, &req);
}
} else {
ret = KNOTD_ERROR;
}
+
+ /* Mark as finished to prevent stalling. */
+ evsched_event_finished(e->parent);
+
+ /* Watch socket. */
+ knot_ns_xfr_t req;
+ memset(&req, 0, sizeof(req));
+ req.session = sock;
+ req.type = XFR_TYPE_SOA;
+ req.flags |= XFR_FLAG_UDP;
+ req.zone = zone;
+ memcpy(&req.addr, master, sizeof(sockaddr_t));
+ memcpy(&req.saddr, &zd->xfr_in.via, sizeof(sockaddr_t));
+ sockaddr_update(&req.addr);
+ sockaddr_update(&req.saddr);
+ if (ret == KNOTD_EOK) {
+ ret = xfr_request(zd->server->xfr_h, &req);
+ }
if (ret != KNOTD_EOK) {
log_server_warning("Failed to issue SOA query for zone '%s'.\n",
zd->conf->name);
}
-
- /* Schedule EXPIRE timer on first attempt. */
- if (!zd->xfr_in.expire) {
- uint32_t expire_tmr = zones_soa_expire(zone);
- zd->xfr_in.expire = evsched_schedule_cb(
- e->parent,
- zones_expire_ev,
- zone, expire_tmr);
- dbg_zones("zones: EXPIRE of '%s' after %u seconds\n",
- zd->conf->name, expire_tmr / 1000);
- }
-
- /* Reschedule as RETRY timer. */
- evsched_schedule(e->parent, e, zones_soa_retry(zone));
- dbg_zones("zones: RETRY of '%s' after %u seconds\n",
- zd->conf->name, zones_soa_retry(zone) / 1000);
+
+ free(qbuf);
/* Unlock RCU. */
rcu_read_unlock();
-
- /* Close invalidated SOA query. */
- evsched_event_finished(e->parent);
- if (soa_pending != NULL) {
- /* Execute */
- evsched_schedule(e->parent, soa_pending, 0);
- }
+
return ret;
}
@@ -558,10 +592,6 @@ static int zones_notify_send(event_t *e)
return KNOTD_EMALF;
}
- /* Prepare buffer for query. */
- uint8_t qbuf[SOCKET_MTU_SZ];
- size_t buflen = sizeof(qbuf);
-
/* RFC suggests 60s, but it is configurable. */
int retry_tmr = ev->timeout * 1000;
@@ -571,6 +601,15 @@ static int zones_notify_send(event_t *e)
dbg_notify("notify: Query RETRY after %u secs (zone '%s')\n",
retry_tmr / 1000, zd->conf->name);
conf_read_unlock();
+
+ /* Prepare buffer for query. */
+ uint8_t *qbuf = malloc(SOCKET_MTU_SZ);
+ if (qbuf == NULL) {
+ log_zone_error("Not enough memory to allocate NOTIFY query.\n");
+ return KNOTD_ENOMEM;
+ }
+
+ size_t buflen = SOCKET_MTU_SZ;
/* Create query. */
int ret = notify_create_request(contents, qbuf, &buflen);
@@ -602,20 +641,26 @@ static int zones_notify_send(event_t *e)
ev->msgid = knot_wire_get_id(qbuf);
}
+
+ /* Unlock RCU */
+ rcu_read_unlock();
+
+ /* Mark as finished to prevent stalling. */
+ evsched_event_finished(e->parent);
/* Watch socket. */
knot_ns_xfr_t req;
memset(&req, 0, sizeof(req));
req.session = sock;
req.type = XFR_TYPE_NOTIFY;
+ req.flags |= XFR_FLAG_UDP;
req.zone = zone;
memcpy(&req.addr, &ev->addr, sizeof(sockaddr_t));
memcpy(&req.saddr, &ev->saddr, sizeof(sockaddr_t));
xfr_request(zd->server->xfr_h, &req);
-
- /* Unlock RCU */
- rcu_read_unlock();
}
+
+ free(qbuf);
return ret;
}
@@ -759,6 +804,17 @@ static int zones_load_zone(knot_zonedb_t *zonedb, const char *zone_name,
}
zname[zlen - 1] = '\0'; /* Trim last dot */
+
+ /* Check if the compiled file still exists. */
+ struct stat st;
+ if (stat(source, &st) != 0) {
+ char reason[1024];
+ strerror_r(errno, reason, sizeof(reason));
+ log_server_warning("Failed to open zone file '%s' (%s).\n",
+ zname, reason);
+ free(zname);
+ return KNOTD_EZONEINVAL;
+ }
/* Check path */
if (filename) {
@@ -769,7 +825,12 @@ static int zones_load_zone(knot_zonedb_t *zonedb, const char *zone_name,
case KNOT_EOK:
/* OK */
break;
- case KNOT_EFEWDATA:
+ case KNOT_EACCES:
+ log_server_error("Failed to open compiled zone '%s' "
+ "(Permission denied).\n", filename);
+ free(zname);
+ return KNOTD_EZONEINVAL;
+ case KNOT_ENOENT:
log_server_error("Couldn't find compiled zone. "
"Please recompile '%s'.\n", zname);
free(zname);
@@ -787,6 +848,7 @@ static int zones_load_zone(knot_zonedb_t *zonedb, const char *zone_name,
filename, zname);
free(zname);
return KNOTD_EZONEINVAL;
+ case KNOT_EFEWDATA:
case KNOT_ERROR:
case KNOT_ENOMEM:
default:
@@ -795,8 +857,8 @@ static int zones_load_zone(knot_zonedb_t *zonedb, const char *zone_name,
free(zname);
return KNOTD_EZONEINVAL;
}
-
- /* Check if the db is up-to-date */
+
+ /* Check the source file */
int src_changed = strcmp(source, zl->source) != 0;
if (src_changed || knot_zload_needs_update(zl)) {
log_server_warning("Database for zone '%s' is not "
@@ -2195,6 +2257,7 @@ int zones_process_response(knot_nameserver_t *nameserver,
assert(ret > 0);
/* Already transferring. */
+ int xfrtype = zones_transfer_to_use(contents);
if (pthread_mutex_trylock(&zd->xfr_in.lock) != 0) {
/* Unlock zone contents. */
dbg_zones("zones: SOA response received, but zone is "
@@ -2203,6 +2266,7 @@ int zones_process_response(knot_nameserver_t *nameserver,
rcu_read_unlock();
return KNOTD_EOK;
} else {
+ ++zd->xfr_in.scheduled;
pthread_mutex_unlock(&zd->xfr_in.lock);
}
@@ -2215,7 +2279,7 @@ int zones_process_response(knot_nameserver_t *nameserver,
xfr_req.send = zones_send_cb;
/* Select transfer method. */
- xfr_req.type = zones_transfer_to_use(contents);
+ xfr_req.type = xfrtype;
/* Select TSIG key. */
if (zd->xfr_in.tsig_key.name) {
@@ -2818,13 +2882,14 @@ int zones_timers_update(knot_zone_t *zone, conf_zone_t *cfzone, evsched_t *sch)
/* Schedule REFRESH timer. */
uint32_t refresh_tmr = 0;
if (knot_zone_contents(zone)) {
- refresh_tmr = zones_soa_refresh(zone);
+ refresh_tmr = zones_jitter(zones_soa_refresh(zone));
} else {
refresh_tmr = zd->xfr_in.bootstrap_retry;
}
zd->xfr_in.timer = evsched_schedule_cb(sch, zones_refresh_ev,
zone, refresh_tmr);
- dbg_zones("zone: REFRESH set to %u\n", refresh_tmr);
+ dbg_zones("zone: REFRESH '%s' set to %u\n",
+ cfzone->name, refresh_tmr);
}
/* Schedule IXFR database syncing. */
diff --git a/src/knot/server/zones.h b/src/knot/server/zones.h
index 1822b84..8421f30 100644
--- a/src/knot/server/zones.h
+++ b/src/knot/server/zones.h
@@ -42,7 +42,7 @@
#include "libknot/updates/xfr-in.h"
/* Constants. */
-#define SOA_QRY_TIMEOUT 10000 /*!< SOA query timeout (ms). */
+#define ZONES_JITTER_PCT 10 /*!< +-N% jitter to timers. */
#define IXFR_DBSYNC_TIMEOUT (60*1000) /*!< Database sync timeout = 60s. */
#define AXFR_BOOTSTRAP_RETRY (60*1000) /*!< Interval between AXFR BS retries. */
@@ -77,13 +77,14 @@ typedef struct zonedata_t
void *wrkr; /*!< Pending XFR/IN worker. */
int next_id; /*!< ID of the next awaited SOA resp.*/
uint32_t bootstrap_retry;/*!< AXFR/IN bootstrap retry. */
+ unsigned scheduled;/*!< Scheduled operations. */
} xfr_in;
/*! \brief List of pending NOTIFY events. */
list notify_pending;
- /*! \brief List of pending SOA queries. */
- struct event_t* soa_pending;
+ /*! \brief List of fds with pending SOA queries. */
+ int soa_pending;
/*! \brief Zone IXFR history. */
journal_t *ixfr_db;
diff --git a/src/knot/zone/zone-dump-text.c b/src/knot/zone/zone-dump-text.c
index 4a45d64..2d0b9c0 100644
--- a/src/knot/zone/zone-dump-text.c
+++ b/src/knot/zone/zone-dump-text.c
@@ -636,81 +636,60 @@ char *rdata_nsap_to_string(knot_rdata_item_t item)
char *rdata_apl_to_string(knot_rdata_item_t item)
{
uint8_t *data = rdata_item_data(item);
- uint16_t address_family = knot_wire_read_u16(data);
- uint8_t prefix = data[2];
- uint8_t length = data[3];
- int negated = length & APL_NEGATION_MASK;
- int af = -1;
-
- char *ret = malloc(sizeof(char) * MAX_NSEC_BIT_STR_LEN);
-
- memset(ret, 0, MAX_NSEC_BIT_STR_LEN);
-
- length &= APL_LENGTH_MASK;
- switch (address_family) {
- case 1: af = AF_INET; break;
- case 2: af = AF_INET6; break;
- }
-
- if (af != -1) {
- char text_address[1000];
- uint8_t address[128];
- memset(address, 0, sizeof(address));
- memcpy(address, data + 4, length);
- if (inet_ntop(af, address,
- text_address,
- sizeof(text_address))) {
- snprintf(ret, sizeof(text_address) +
- U32_MAX_STR_LEN * 2,
- "%s%d:%s/%d",
- negated ? "!" : "",
- (int) address_family,
- text_address,
- (int) prefix);
- }
+ size_t read = 0;
+ char *pos = malloc(sizeof(char) * MAX_NSEC_BIT_STR_LEN);
+ if (pos == NULL) {
+ ERR_ALLOC_FAILED;
+ return NULL;
}
-
- return ret;
-
- /*
- int result = 0;
- buffer_type packet;
-
- buffer_create_from(
- &packet, rdata_item_data(rdata), rdata_atom_size(rdata));
-
- if (buffer_available(&packet, 4)) {
- uint16_t address_family = buffer_read_u16(&packet);
- uint8_t prefix = buffer_read_u8(&packet);
- uint8_t length = buffer_read_u8(&packet);
+ memset(pos, 0, MAX_NSEC_BIT_STR_LEN);
+
+ char *ret_base = pos;
+
+ while (read < rdata_item_size(item)) {
+ uint16_t address_family = knot_wire_read_u16(data);
+ uint8_t prefix = data[2];
+ uint8_t length = data[3];
int negated = length & APL_NEGATION_MASK;
int af = -1;
length &= APL_LENGTH_MASK;
switch (address_family) {
- case 1: af = AF_INET; break;
- *case 2: af = AF_INET6; break;
+ case 1: af = AF_INET; break;
+ case 2: af = AF_INET6; break;
}
- if (af != -1 && buffer_available(&packet, length)) {
- char text_address[1000];
+
+ if (af != -1) {
+ char text_address[1024];
+ memset(text_address, 0, sizeof(text_address));
uint8_t address[128];
memset(address, 0, sizeof(address));
- buffer_read(&packet, address, length);
- if (inet_ntop(af, address, text_address,
- sizeof(text_address))) {
- buffer_printf(output, "%s%d:%s/%d",
- negated ? "!" : "",
- (int) address_family,
- text_address,
- (int) prefix);
- result = 1;
+ memcpy(address, data + 4, length);
+ /* Only valid data should be present here. */
+ assert((data + 4) - rdata_item_data(item) <= rdata_item_size(item));
+ /* Move pointer at the end of already written data. */
+ pos = ret_base + strlen(ret_base);
+ if (inet_ntop(af, address,
+ text_address,
+ sizeof(text_address))) {
+ snprintf(pos, sizeof(text_address) +
+ U32_MAX_STR_LEN * 2,
+ "%s%d:%s/%d%s",
+ negated ? "!" : "",
+ (int) address_family,
+ text_address,
+ (int) prefix,
+ /* Last item should not have trailing space. */
+ (read + 4 + length < rdata_item_size(item))
+ ? " " : "");
}
}
- }
- return result;
- */
+ data += 4 + length;
+ read += 4 + length;
+ }
+ return ret_base;
}
char *rdata_services_to_string(knot_rdata_item_t item)
diff --git a/src/knot/zone/zone-dump.h b/src/knot/zone/zone-dump.h
index 77a395c..975b8e8 100644
--- a/src/knot/zone/zone-dump.h
+++ b/src/knot/zone/zone-dump.h
@@ -38,7 +38,7 @@ enum {
};
/*! \brief Magic identifier: { "knot", maj_ver, min_ver, revision } */
-#define MAGIC_BYTES {'k', 'n', 'o', 't', '1', 'r', 'c'}
+#define MAGIC_BYTES {'k', 'n', 'o', 't', '1', '0', '0'}
/*!
* \brief Dumps given zone to binary file.
diff --git a/src/knot/zone/zone-load.c b/src/knot/zone/zone-load.c
index f64cfaa..69ea58f 100644
--- a/src/knot/zone/zone-load.c
+++ b/src/knot/zone/zone-load.c
@@ -20,8 +20,11 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
+#include <sys/types.h>
#include <sys/stat.h>
+#include <fcntl.h>
#include <time.h>
+#include <unistd.h>
#include "common/crc.h"
#include "libknot/common.h"
@@ -698,8 +701,8 @@ static unsigned long calculate_crc(FILE *f)
size_t file_size = ftell(f);
fseek(f, 0L, SEEK_SET);
- const size_t chunk_size = 1024;
- /* read chunks of 1 kB */
+ const size_t chunk_size = 4096;
+ /* read chunks of 4 kB */
size_t read_bytes = 0;
/* Prealocate chunk */
unsigned char *chunk = malloc(sizeof(unsigned char) * chunk_size);
@@ -731,6 +734,8 @@ static unsigned long calculate_crc(FILE *f)
int knot_zload_open(zloader_t **dst, const char *filename)
{
+ char crc_buf[65];
+
if (!dst || !filename) {
return KNOT_EBADARG;
}
@@ -742,8 +747,16 @@ int knot_zload_open(zloader_t **dst, const char *filename)
/* Open file for binary read. */
FILE *f = fopen(filename, "rb");
if (unlikely(!f)) {
+ int reason = errno;
dbg_zload("knot_zload_open: failed to open '%s'\n",
filename);
+ switch (reason) {
+ case EACCES: return KNOT_EACCES; break;
+ case ENOENT: return KNOT_ENOENT; break;
+ case ENOMEM: return KNOT_ENOMEM; break;
+ default: break;
+ }
+
return KNOT_EFEWDATA; // No such file or directory (POSIX.1)
}
@@ -752,38 +765,56 @@ int knot_zload_open(zloader_t **dst, const char *filename)
/* Read CRC from filename.crc file */
char *crc_path =
- malloc(sizeof(char) * (strlen(filename) + strlen(".crc") + 1));
+ malloc(sizeof(char) * (strlen(filename) + 4 /* strlen(".crc") */ + 1));
if (unlikely(!crc_path)) {
fclose(f);
return KNOT_ENOMEM;
}
- memset(crc_path, 0,
- sizeof(char) * (strlen(filename) + strlen(".crc") + 1));
+ memcpy(crc_path, filename, strlen(filename));
+ memcpy(crc_path + strlen(filename), ".crc", 4);
+ crc_path[strlen(filename) + 4] = '\0';
- memcpy(crc_path, filename, sizeof(char) * strlen(filename));
-
- crc_path = strncat(crc_path, ".crc", strlen(".crc"));
- FILE *f_crc = fopen(crc_path, "r");
- if (unlikely(!f_crc)) {
+ int f_crc = open(crc_path, O_RDONLY);
+ if (f_crc == -1) {
+ /* FIXME: Print strerror_r(errno) in dbg message */
dbg_zload("knot_zload_open: failed to open '%s'\n",
- crc_path);
+ crc_path);
+ free(crc_path);
fclose(f);
+ return KNOT_ECRC;
+ }
+
+ ssize_t crc_read_bytes = 0;
+ crc_read_bytes = read(f_crc, crc_buf, 64);
+ if (crc_read_bytes == -1) {
+ /* FIXME: Print strerror_r(errno) in dbg message */
+ dbg_zload("knot_zload_open: could not read "
+ "CRC from file '%s'\n",
+ crc_path);
free(crc_path);
+ close(f_crc);
+ fclose(f);
return KNOT_ECRC;
}
+ crc_buf[crc_read_bytes] = '\0';
unsigned long crc_from_file = 0;
- if (fscanf(f_crc, "%64lu\n", &crc_from_file) != 1) {
- dbg_zload("knot_zload_open: could not read "
+ errno = 0;
+ crc_from_file = strtoul(crc_buf, (char **) NULL, 10);
+ if (errno != 0) {
+ /* FIXME: Print strerror_r(errno) in dbg message */
+ dbg_zload("knot_zload_open: could not convert "
"CRC from file '%s'\n",
crc_path);
- fclose(f_crc);
+ close(f_crc);
fclose(f);
free(crc_path);
return KNOT_ERROR;
}
+
+ /* Free some value and close the CRC file */
free(crc_path);
- fclose(f_crc);
+ close(f_crc);
/* Compare calculated and read CRCs. */
if (crc_from_file != crc_calculated) {
@@ -1161,18 +1192,19 @@ int knot_zload_needs_update(zloader_t *loader)
if (!loader) {
return 1;
}
-
- /* Check if the source still exists. */
- struct stat st_src;
- if (stat(loader->source, &st_src) != 0) {
- return 1;
- }
-
- /* Check if the compiled file still exists. */
- struct stat st_bin;
- if (stat(loader->filename, &st_bin) != 0) {
- return 1;
- }
+
+ /* Check if the source still exists. */
+ struct stat st_src;
+ if (stat(loader->source, &st_src) != 0) {
+ return 1;
+ }
+
+ /* Check if the compiled file still exists. */
+ struct stat st_bin;
+ if (stat(loader->filename, &st_bin) != 0) {
+ return 1;
+ }
+
/* Compare the mtime of the source and file. */
/*! \todo Inspect types on Linux. */
diff --git a/src/libknot/edns.c b/src/libknot/edns.c
index d12861c..d421be7 100644
--- a/src/libknot/edns.c
+++ b/src/libknot/edns.c
@@ -307,7 +307,8 @@ int knot_edns_add_option(knot_opt_rr_t *opt_rr, uint16_t code,
(opt_rr->options_max + KNOT_EDNS_OPTION_STEP),
sizeof(knot_opt_option_t));
CHECK_ALLOC_LOG(options_new, KNOT_ENOMEM);
- memcpy(options_new, opt_rr->options, opt_rr->option_count);
+ memcpy(options_new, opt_rr->options,
+ opt_rr->option_count * sizeof(knot_opt_option_t));
knot_opt_option_t *old_options = opt_rr->options;
opt_rr->options = options_new;
diff --git a/src/libknot/hash/cuckoo-hash-table.c b/src/libknot/hash/cuckoo-hash-table.c
index 73d1980..831aef8 100644
--- a/src/libknot/hash/cuckoo-hash-table.c
+++ b/src/libknot/hash/cuckoo-hash-table.c
@@ -343,14 +343,14 @@ static inline void ck_put_item(ck_hash_table_item_t **to,
static uint ck_check_used_twice(da_array_t *used, uint32_t hash)
{
uint i = 0, found = 0;
- while (i <= da_get_count(used) && found < 2) {
- ++i;
+ while (i < da_get_count(used) && found < 2) {
if (((uint *)(da_get_items(used)))[i] == hash) {
++found;
}
+ ++i;
}
- if (i <= da_get_count(used) && found == 2) {
+ if (found == 2) {
dbg_ck_hash("Hashing entered infinite loop.\n");
return -1;
} else {
@@ -412,10 +412,6 @@ static ck_hash_table_item_t **ck_find_in_stash(const ck_hash_table_t *table,
{
ck_stash_item_t *item = table->stash;
while (item != NULL) {
- dbg_ck("Comparing item in stash (key: %.*s (size %zu))"
- "with searched item (key %.*s (size %u)).\n",
- (int)item->item->key_length, item->item->key,
- item->item->key_length, (int)length, key, length);
/*! \todo Can the item be NULL?
* Sometimes it crashed on assert in ck_items_match(),
* But I'm not sure if this may happen or if the
@@ -423,6 +419,11 @@ static ck_hash_table_item_t **ck_find_in_stash(const ck_hash_table_t *table,
* non-NULL.
*/
if (item->item && ck_items_match(item->item, key, length)) {
+ dbg_ck("Comparing item in stash (key: %.*s (size %zu))"
+ "with searched item (key %.*s (size %u)).\n",
+ (int)item->item->key_length, item->item->key,
+ item->item->key_length, (int)length, key,
+ length);
return &item->item;
}
item = item->next;
diff --git a/src/libknot/nameserver/name-server.h b/src/libknot/nameserver/name-server.h
index 8ec3e50..1ae309c 100644
--- a/src/libknot/nameserver/name-server.h
+++ b/src/libknot/nameserver/name-server.h
@@ -160,16 +160,13 @@ enum knot_ns_xfr_flag_t {
* \brief XFR request types.
*/
typedef enum knot_ns_xfr_type_t {
- /* Special events. */
- XFR_TYPE_CLOSE = -1, /*!< Close connection event. */
-
/* DNS events. */
- XFR_TYPE_AIN = 0, /*!< AXFR-IN request (start transfer). */
- XFR_TYPE_AOUT, /*!< AXFR-OUT request (incoming transfer). */
- XFR_TYPE_IIN, /*!< IXFR-IN request (start transfer). */
- XFR_TYPE_IOUT, /*!< IXFR-OUT request (incoming transfer). */
- XFR_TYPE_SOA, /*!< Pending SOA request. */
- XFR_TYPE_NOTIFY /*!< Pending NOTIFY query. */
+ XFR_TYPE_AIN = 1 << 0, /*!< AXFR-IN request (start transfer). */
+ XFR_TYPE_AOUT= 1 << 1, /*!< AXFR-OUT request (incoming transfer). */
+ XFR_TYPE_IIN = 1 << 2, /*!< IXFR-IN request (start transfer). */
+ XFR_TYPE_IOUT = 1 << 3, /*!< IXFR-OUT request (incoming transfer). */
+ XFR_TYPE_SOA = 1 << 4, /*!< Pending SOA request. */
+ XFR_TYPE_NOTIFY = 1 << 5 /*!< Pending NOTIFY query. */
} knot_ns_xfr_type_t;
/*----------------------------------------------------------------------------*/
diff --git a/src/libknot/nsec3.c b/src/libknot/nsec3.c
index 303d2e6..1414e7e 100644
--- a/src/libknot/nsec3.c
+++ b/src/libknot/nsec3.c
@@ -55,6 +55,11 @@ int knot_nsec3_params_from_wire(knot_nsec3_params_t *params,
((uint8_t *)knot_rdata_item(rdata, 3)->raw_data)[2];
if (params->salt_length > 0) {
+ /* It is called also on reload, so we need to free if exists. */
+ if (params->salt != NULL) {
+ free(params->salt);
+ params->salt = NULL;
+ }
params->salt = (uint8_t *)malloc(params->salt_length);
CHECK_ALLOC_LOG(params->salt, -1);
memcpy(params->salt,
diff --git a/src/libknot/tsig.c b/src/libknot/tsig.c
index e9da295..e8df92e 100644
--- a/src/libknot/tsig.c
+++ b/src/libknot/tsig.c
@@ -546,6 +546,8 @@ uint16_t tsig_alg_digest_length(tsig_algorithm_t alg)
case KNOT_TSIG_ALG_HMAC_SHA224:
return KNOT_TSIG_ALG_DIG_LENGTH_SHA224;
case KNOT_TSIG_ALG_HMAC_SHA256:
+ return KNOT_TSIG_ALG_DIG_LENGTH_SHA256;
+ case KNOT_TSIG_ALG_HMAC_SHA384:
return KNOT_TSIG_ALG_DIG_LENGTH_SHA384;
case KNOT_TSIG_ALG_HMAC_SHA512:
return KNOT_TSIG_ALG_DIG_LENGTH_SHA512;
diff --git a/src/libknot/updates/ddns.c b/src/libknot/updates/ddns.c
index 4c6ab7b..025cd6b 100644
--- a/src/libknot/updates/ddns.c
+++ b/src/libknot/updates/ddns.c
@@ -39,7 +39,7 @@ static int knot_ddns_prereq_check_rrsets(knot_rrset_t ***rrsets,
return KNOT_ENOMEM;
}
- memcpy(rrsets_new, *rrsets, *count);
+ memcpy(rrsets_new, *rrsets, (*count) * sizeof(knot_rrset_t *));
*rrsets = rrsets_new;
*allocated = new_count;
@@ -62,7 +62,7 @@ static int knot_ddns_prereq_check_dnames(knot_dname_t ***dnames,
return KNOT_ENOMEM;
}
- memcpy(dnames_new, *dnames, *count);
+ memcpy(dnames_new, *dnames, (*count) * sizeof(knot_dname_t *));
*dnames = dnames_new;
*allocated = new_count;
diff --git a/src/libknot/updates/xfr-in.c b/src/libknot/updates/xfr-in.c
index f411e47..75d7fd7 100644
--- a/src/libknot/updates/xfr-in.c
+++ b/src/libknot/updates/xfr-in.c
@@ -2374,7 +2374,7 @@ void xfrin_rollback_update(knot_zone_contents_t *old_contents,
}
for (int i = 0; i < (*changes)->new_rdata_count; ++i) {
- fprintf(stderr, "Freeing %d. RDATA chain: %p\n", i,
+ dbg_xfrin("Freeing %d. RDATA chain: %p\n", i,
(*changes)->new_rdata[i]);
/*
@@ -2397,7 +2397,7 @@ void xfrin_rollback_update(knot_zone_contents_t *old_contents,
(*changes)->new_rdata[i]) {
assert(rdata->next != rdata);
rdata_next = rdata->next;
- fprintf(stderr, " Deleting RDATA: %p\n", rdata);
+ dbg_xfrin(" Deleting RDATA: %p\n", rdata);
knot_rdata_deep_free(&rdata,
(*changes)->new_rdata_types[i], 1);
rdata = rdata_next;
@@ -2406,7 +2406,7 @@ void xfrin_rollback_update(knot_zone_contents_t *old_contents,
assert(rdata == NULL
|| rdata->next == (*changes)->new_rdata[i]);
- fprintf(stderr, " Deleting RDATA: %p\n", rdata);
+ dbg_xfrin(" Deleting RDATA: %p\n", rdata);
knot_rdata_deep_free(&rdata,
(*changes)->new_rdata_types[i], 1);
diff --git a/src/libknot/util/error.h b/src/libknot/util/error.h
index 317c681..888669a 100644
--- a/src/libknot/util/error.h
+++ b/src/libknot/util/error.h
@@ -48,6 +48,8 @@ enum knot_error {
KNOT_EFEWDATA, /*!< Not enough data to parse. */
KNOT_ESPACE, /*!< Not enough space provided. */
KNOT_EMALF, /*!< Malformed data. */
+ KNOT_ENOENT, /*!< Resource not found. */
+ KNOT_EACCES, /*!< Permission is denied. */
KNOT_ECRYPTO, /*!< Error in crypto library. */
KNOT_ENSEC3PAR, /*!< Missing or wrong NSEC3PARAM record. */
KNOT_EBADZONE, /*!< Domain name does not belong to the zone. */
@@ -66,7 +68,7 @@ enum knot_error {
KNOT_ECONN, /*!< Connection reset. */
KNOT_EIXFRSPACE, /*!< IXFR reply did not fit in. */
KNOT_ECNAME, /*!< CNAME loop found in zone. */
- KNOT_ERROR_COUNT = 32
+ KNOT_ERROR_COUNT = 34
};
/*! \brief Table linking error messages to error codes. */
diff --git a/src/libknot/util/libknot_error.c b/src/libknot/util/libknot_error.c
index a5a9de0..f787565 100644
--- a/src/libknot/util/libknot_error.c
+++ b/src/libknot/util/libknot_error.c
@@ -28,6 +28,8 @@ const error_table_t knot_error_msgs[KNOT_ERROR_COUNT] = {
{KNOT_EFEWDATA, "Not enough data to parse."},
{KNOT_ESPACE, "Not enough space provided."},
{KNOT_EMALF, "Malformed data."},
+ {KNOT_ENOENT, "Resource not found."},
+ {KNOT_EACCES, "Permission to perform requested operation is denied."},
{KNOT_ECRYPTO, "Error in crypto library."},
{KNOT_ENSEC3PAR, "Missing or wrong NSEC3PARAM record."},
{KNOT_EBADZONE, "Domain name does not belong to the given zone."},
diff --git a/src/tests/common/events_tests.c b/src/tests/common/events_tests.c
index d7702fe..0acd706 100644
--- a/src/tests/common/events_tests.c
+++ b/src/tests/common/events_tests.c
@@ -154,7 +154,7 @@ static int events_tests_run(int argc, char *argv[])
// 7. Insert and immediately cancel an event
e = evsched_schedule_cb(s, 0, (void*)0xdead, 1000);
ret = evsched_cancel(s, e);
- ok(ret == 0, "evsched: inserted and cancelled an event");
+ ok(ret >= 0, "evsched: inserted and cancelled an event");
if (e) {
evsched_event_free(s, e);
}
diff --git a/src/zcompile/zcompile.c b/src/zcompile/zcompile.c
index 25de281..d84feb7 100644
--- a/src/zcompile/zcompile.c
+++ b/src/zcompile/zcompile.c
@@ -507,8 +507,8 @@ int zone_read(const char *name, const char *zonefile, const char *outfile,
/* Check that we can write to outfile. */
FILE *f = fopen(outfile, "wb");
if (f == NULL) {
- fprintf(stderr, "Cannot write zone db to file '%s'\n",
- outfile);
+ fprintf(stderr, "Cannot write zone db to file '%s' (%s).\n",
+ outfile, strerror(errno));
return KNOTDZCOMPILE_EINVAL;
}
fclose(f);
@@ -552,8 +552,8 @@ int zone_read(const char *name, const char *zonefile, const char *outfile,
if (!zone_open(zonefile, 3600, KNOT_CLASS_IN, origin_node, scanner,
origin_from_config)) {
- zc_error_prev_line("Cannot open '%s'\n",
- zonefile);
+ zc_error_prev_line("Cannot open '%s' (%s).",
+ zonefile, strerror(errno));
zparser_free();
zp_lex_destroy(scanner);
knot_dname_release(origin_from_config);
diff --git a/src/zcompile/zcompile_main.c b/src/zcompile/zcompile_main.c
index c02b780..c873af6 100644
--- a/src/zcompile/zcompile_main.c
+++ b/src/zcompile/zcompile_main.c
@@ -97,7 +97,7 @@ int main(int argc, char **argv)
int error = zone_read(origin, zonefile, outfile, semantic_checks);
- if (error) {
+ if (error != 0) {
/* FIXME! */
// if (error < 0) {
// fprintf(stderr, "Finished with error: %s.\n",
@@ -105,10 +105,11 @@ int main(int argc, char **argv)
// } else {
// fprintf(stderr, "Finished with %u errors.\n");
// }
+ return 1;
} else {
printf("Compilation successful.\n");
}
//log_close();
-
- return error;
+
+ return 0;
}