diff options
34 files changed, 633 insertions, 442 deletions
@@ -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 --------------------- @@ -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; } |