diff options
author | Ondřej Surý <ondrej@sury.org> | 2012-02-29 18:44:03 +0100 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2012-02-29 18:44:03 +0100 |
commit | 329f909f84efaecfc56fa80a329fb91e576b4f31 (patch) | |
tree | fa93093335802e524febd61c4bf1486535318f47 | |
parent | a3a4fcd0e5a4bbc54fc6f6c555b3656798f3a5aa (diff) | |
download | knot-329f909f84efaecfc56fa80a329fb91e576b4f31.tar.gz |
Imported Upstream version 1.0.0upstream/1.0.0
75 files changed, 2629 insertions, 1777 deletions
diff --git a/KNOWN_ISSUES b/KNOWN_ISSUES index e46c167..1d87958 100644 --- a/KNOWN_ISSUES +++ b/KNOWN_ISSUES @@ -4,14 +4,11 @@ Features not supported Here is a list of the most notable features that are not supported in the current version of Knot. -* NSID (RFC5001) -* Root zone support * Other DNS classes than IN (CH, CS, HS) * Dynamic updates Known bugs ========== -* Few minor bugs -* IXFR code might be flaky sometimes * IXFR may be slow when too much (10 000+) RRSets are transfered at once. +* Slow start with too many zones. @@ -1,3 +1,17 @@ +v1.0.0 - Feb 29, 2012 +--------------------- + +New features: + * Support for subnets in ACL. + * Debug messages enabling in configure. + * Optimized memory consuption of zone structures. + +Bugfixes: + * Memory errors and leaks. + * Fixed improper handling of failed IXFR/IN. + * Several other minor bugfixes. + + v1.0-rc1 - Feb 14, 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-rc1. +# Generated by GNU Autoconf 2.68 for knot 1.0.0. # # 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-rc1' -PACKAGE_STRING='knot 1.0-rc1' +PACKAGE_VERSION='1.0.0' +PACKAGE_STRING='knot 1.0.0' PACKAGE_BUGREPORT='knot-dns@labs.nic.cz' PACKAGE_URL='' @@ -747,6 +747,7 @@ with_sysroot enable_libtool_lock enable_ldns enable_debug +enable_debuglevel enable_recvmmsg ' ac_precious_vars='build_alias @@ -1302,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-rc1 to adapt to many kinds of systems. +\`configure' configures knot 1.0.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1372,7 +1373,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of knot 1.0-rc1:";; + short | recursive ) echo "Configuration of knot 1.0.0:";; esac cat <<\_ACEOF @@ -1390,7 +1391,9 @@ Optional Features: optimize for fast installation [default=yes] --disable-libtool-lock avoid locking (might break parallel builds) --enable-ldns=yes|no Enable tests with ldns [default=no] - --enable-debug=brief|verbose|details + --enable-debug=server,zones,xfr,packet,dname,rr,ns,hash,compiler + compile selected debug modules [default=none] + --enable-debuglevel=brief|verbose|details enable given debug level [default=disabled] --enable-recvmmsg=yes|no enable recvmmsg() network API under Linux (kernel @@ -1488,7 +1491,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -knot configure 1.0-rc1 +knot configure 1.0.0 generated by GNU Autoconf 2.68 Copyright (C) 2010 Free Software Foundation, Inc. @@ -2038,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-rc1, which was +It was created by knot $as_me 1.0.0, which was generated by GNU Autoconf 2.68. Invocation command line was $ $0 $@ @@ -2856,7 +2859,7 @@ fi # Define the identity of the package. PACKAGE='knot' - VERSION='1.0-rc1' + VERSION='1.0.0' cat >>confdefs.h <<_ACEOF @@ -13134,10 +13137,49 @@ else fi -# Debug level +# Debug modules # Check whether --enable-debug was given. if test "${enable_debug+set}" = set; then : - enableval=$enable_debug; # Not all shells support fall-through with ;& so I have to duplicate + enableval=$enable_debug; + echo ${enableval}|tr "," "\n"|while read val; do + case "${val}" in + server) +$as_echo "#define KNOTD_SERVER_DEBUG 1" >>confdefs.h + ;; + zones) +$as_echo "#define KNOT_ZONES_DEBUG 1" >>confdefs.h + ;; + xfr) +$as_echo "#define KNOT_XFR_DEBUG 1" >>confdefs.h + ;; + packet) +$as_echo "#define KNOT_PACKET_DEBUG 1" >>confdefs.h + ;; + dname) +$as_echo "#define KNOT_DNAME_DEBUG 1" >>confdefs.h + ;; + rr) +$as_echo "#define KNOT_RR_DEBUG 1" >>confdefs.h + ;; + ns) +$as_echo "#define KNOT_NS_DEBUG 1" >>confdefs.h + ;; + hash) +$as_echo "#define KNOT_HASH_DEBUG 1" >>confdefs.h + ;; + compiler) +$as_echo "#define KNOT_COMPILER_DEBUG 1" >>confdefs.h + ;; + esac + done + +fi + + +# Debug level +# Check whether --enable-debuglevel was given. +if test "${enable_debuglevel+set}" = set; then : + enableval=$enable_debuglevel; # Not all shells support fall-through with ;& so I have to duplicate case "x${enableval}" in xdetails) @@ -14850,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-rc1, which was +This file was extended by knot $as_me 1.0.0, which was generated by GNU Autoconf 2.68. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -14916,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-rc1 +knot config.status 1.0.0 configured by $0, generated by GNU Autoconf 2.68, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index e1fb61d..f5551dc 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ # -*- Autoconf -*- AC_PREREQ([2.65]) -AC_INIT([knot], [1.0-rc1], [knot-dns@labs.nic.cz]) +AC_INIT([knot], [1.0.0], [knot-dns@labs.nic.cz]) AM_INIT_AUTOMAKE([gnu -Wall -Werror]) AC_CONFIG_SRCDIR([src/knot/main.c]) AC_CONFIG_HEADERS([src/config.h]) @@ -64,10 +64,30 @@ AC_ARG_ENABLE([ldns], no) ldns=false ;; *) AC_MSG_ERROR([bad value ${enableval} for --enable-ldns]) ;; esac],[ldns=false]) + +# Debug modules +AC_ARG_ENABLE([debug], + AS_HELP_STRING([--enable-debug=server,zones,xfr,packet,dname,rr,ns,hash,compiler], + [compile selected debug modules [default=none]]), + [ + echo ${enableval}|tr "," "\n"|while read val; do + case "${val}" in + server) AC_DEFINE([KNOTD_SERVER_DEBUG], [1], [Server debug.]) ;; + zones) AC_DEFINE([KNOT_ZONES_DEBUG], [1], [Zones debug.]) ;; + xfr) AC_DEFINE([KNOT_XFR_DEBUG], [1], [XFR debug.]) ;; + packet) AC_DEFINE([KNOT_PACKET_DEBUG], [1], [Packet debug.]) ;; + dname) AC_DEFINE([KNOT_DNAME_DEBUG], [1], [Domain names debug.]) ;; + rr) AC_DEFINE([KNOT_RR_DEBUG], [1], [RR debug.]) ;; + ns) AC_DEFINE([KNOT_NS_DEBUG], [1], [Nameserver debug.]) ;; + hash) AC_DEFINE([KNOT_HASH_DEBUG], [1], [Hashtable debug.]) ;; + compiler) AC_DEFINE([KNOT_COMPILER_DEBUG], [1], [Zone compiler debug.]) ;; + esac + done + ], []) # Debug level -AC_ARG_ENABLE([debug], - AS_HELP_STRING([--enable-debug=brief|verbose|details], [enable given debug level [default=disabled]]), +AC_ARG_ENABLE([debuglevel], + AS_HELP_STRING([--enable-debuglevel=brief|verbose|details], [enable given debug level [default=disabled]]), # Not all shells support fall-through with ;& so I have to duplicate [case "x${enableval}" in xdetails) diff --git a/src/common/acl.c b/src/common/acl.c index a1c3a6e..d739319 100644 --- a/src/common/acl.c +++ b/src/common/acl.c @@ -16,9 +16,30 @@ #include <string.h> #include <stdlib.h> +#include <assert.h> #include "common/acl.h" +static inline uint32_t acl_sa_ipv4(sockaddr_t *a) { + return a->addr4.sin_addr.s_addr; +} + +static inline uint32_t acl_fill_mask32(short c) { + /*! \todo Consider optimizing using LUT. */ + assert(c >= 0 && c <= 32); + unsigned r = 0; + /*! This actually builds big-endian mask + * as we will match against addresses in + * network byte-order (big-endian). + * Otherwise it should be built from + * HO bit -> LO bit. + */ + for (char i = 0; i < c; ++i) { + r |= (1 << i); + } + return r; +} + static int acl_compare(void *k1, void *k2) { sockaddr_t* a1 = (sockaddr_t *)k1; @@ -32,56 +53,54 @@ static int acl_compare(void *k1, void *k2) /* Compare integers if IPv4. */ if (a1->len == sizeof(struct sockaddr_in)) { - - /* Allow if k1 == INADDR_ANY. */ - if (a1->addr4.sin_addr.s_addr == 0) { - return 0; - } + + /* Compute mask .*/ + uint32_t mask = acl_fill_mask32(a1->prefix); /* Compare address. */ - ldiff = a1->addr4.sin_addr.s_addr - a2->addr4.sin_addr.s_addr; - if (ldiff != 0) { - return ldiff < 0 ? -1 : 1; - } - - /* Port = 0 means any port match. */ - if (a1->addr4.sin_port == 0) { + ldiff = (int)((acl_sa_ipv4(a1) & mask) - (acl_sa_ipv4(a2) & mask)); + if (ldiff < 0) { + return -1; + } else if (ldiff > 0) { + return 1; + } else { return 0; } - /* Compare ports on address match. */ - ldiff = ntohs(a1->addr4.sin_port) - ntohs(a2->addr4.sin_port); - if (ldiff != 0) { - return ldiff < 0 ? -1 : 1; - } return 0; } /* IPv6 matching. */ #ifndef DISABLE_IPV6 if (a1->len == sizeof(struct sockaddr_in6)) { - - /* Compare address. */ - ldiff = memcmp(&a1->addr6.sin6_addr, - &a2->addr6.sin6_addr, - sizeof(struct in6_addr)); - if (ldiff < 0) { - return -1; - } - if (ldiff > 0) { - return 1; - } - - /* Port = 0 means any port match. */ - if (a1->addr6.sin6_port == 0) { - return 0; + + /* Get mask .*/ + short chunk = a1->prefix; + + /* Compare address by 32bit chunks. */ + uint32_t* a1p = (uint32_t*)&a1->addr6.sin6_addr; + uint32_t* a2p = (uint32_t*)&a2->addr6.sin6_addr; + + /* Mask 0 = 0 bits to compare from LO->HO (in big-endian). + * Mask 128 = 128 bits to compare. + */ + while (chunk > 0) { + uint32_t mask = 0xffffffff; + if (chunk > sizeof(mask) << 3) { + chunk -= sizeof(mask) << 3; + } else { + mask = acl_fill_mask32(chunk); + chunk = 0; + } + + ldiff = (*(a1p++) & mask) ^ (*(a2p++) & mask); + if (ldiff < 0) { + return -1; + } else if (ldiff > 0) { + return 1; + } } - /* Compare ports on address match. */ - ldiff = ntohs(a1->addr6.sin6_port) - ntohs(a2->addr6.sin6_port); - if (ldiff != 0) { - return ldiff < 0 ? -1 : 1; - } return 0; } #endif @@ -111,6 +130,19 @@ acl_t *acl_new(acl_rule_t default_rule, const char *name) free(acl); return 0; } + + /* Initialize skip list for rules with TSIG. */ + /*! \todo This needs a better structure to make + * nodes with TSIG preferred, but for now + * it will do to sort nodes into two lists. + * (issue #1675) + */ + acl->rules_pref = skip_create_list(acl_compare); + if (!acl->rules_pref) { + skip_destroy_list(&acl->rules, 0, free); + free(acl); + return 0; + } /* Initialize. */ memcpy(&acl->name, name, name_len); @@ -134,7 +166,8 @@ void acl_delete(acl_t **acl) *acl = 0; } -int acl_create(acl_t *acl, const sockaddr_t* addr, acl_rule_t rule, void *val) +int acl_create(acl_t *acl, const sockaddr_t* addr, acl_rule_t rule, void *val, + unsigned flags) { if (!acl || !addr) { return ACL_ERROR; @@ -142,12 +175,21 @@ int acl_create(acl_t *acl, const sockaddr_t* addr, acl_rule_t rule, void *val) /* Insert into skip list. */ acl_key_t *key = malloc(sizeof(acl_key_t)); + if (key == NULL) { + return ACL_ERROR; + } + memcpy(&key->addr, addr, sizeof(sockaddr_t)); sockaddr_update(&key->addr); key->rule = rule; key->val = val; - skip_insert(acl->rules, &key->addr, key, 0); + + if (flags & ACL_PREFER) { + skip_insert(acl->rules_pref, &key->addr, key, 0); + } else { + skip_insert(acl->rules, &key->addr, key, 0); + } return ACL_ACCEPT; } @@ -158,15 +200,18 @@ int acl_match(acl_t *acl, const sockaddr_t* addr, acl_key_t **key) return ACL_ERROR; } - acl_key_t *found = skip_find(acl->rules, (void*)addr); + acl_key_t *found = skip_find(acl->rules_pref, (void*)addr); + if (found == NULL) { + found = skip_find(acl->rules, (void*)addr); + } /* Set stored value if exists. */ - if (key != 0) { + if (key != NULL) { *key = found; } /* Return appropriate rule. */ - if (!found) { + if (found == NULL) { return acl->default_rule; } @@ -181,6 +226,7 @@ int acl_truncate(acl_t *acl) /* Destroy all rules. */ skip_destroy_list(&acl->rules, 0, free); + skip_destroy_list(&acl->rules_pref, 0, free); return ACL_ACCEPT; } diff --git a/src/common/acl.h b/src/common/acl.h index 7303de8..7ce8f26 100644 --- a/src/common/acl.h +++ b/src/common/acl.h @@ -40,10 +40,16 @@ typedef enum acl_rule_t { ACL_ACCEPT = 1 } acl_rule_t; +/*! \brief ACL flags. */ +enum acl_flag_t { + ACL_PREFER = 1 << 0 /* Preferred node. */ +}; + /*! \brief ACL structure. */ typedef struct acl_t { acl_rule_t default_rule; /*!< \brief Default rule. */ skip_list_t *rules; /*!< \brief Data container. */ + skip_list_t *rules_pref; /*!< \brief Preferred data container. */ const char name[]; /*!< \brief ACL semantic name. */ } acl_t; @@ -81,11 +87,13 @@ void acl_delete(acl_t **acl); * \param addr IP address. * \param rule Rule for given address. * \param val Value to be stored for given address (or NULL). + * \param flags Bitfield of ACL flags. * * \retval ACL_ACCEPT if successful. * \retval ACP_ERROR on error. */ -int acl_create(acl_t *acl, const sockaddr_t* addr, acl_rule_t rule, void *val); +int acl_create(acl_t *acl, const sockaddr_t* addr, acl_rule_t rule, void *val, + unsigned flags); /*! * \brief Match address against ACL. diff --git a/src/common/dynamic-array.c b/src/common/dynamic-array.c index 1e2efac..e948821 100644 --- a/src/common/dynamic-array.c +++ b/src/common/dynamic-array.c @@ -118,6 +118,7 @@ int da_initialize(da_array_t *array, unsigned count, size_t item_size) array->allocated = 0; array->count = 0; ERR_ALLOC_FAILED; + pthread_mutex_unlock(&array->mtx); return -1; } diff --git a/src/common/evsched.c b/src/common/evsched.c index 067977f..386478a 100644 --- a/src/common/evsched.c +++ b/src/common/evsched.c @@ -165,10 +165,10 @@ event_t* evsched_next(evsched_t *s) /* Immediately return. */ if (timercmp(&dt, &next_ev->tv, >=)) { + s->current = next_ev; rem_node(&next_ev->n); pthread_mutex_unlock(&s->mx); pthread_mutex_lock(&s->rl); - s->current = next_ev; return next_ev; } diff --git a/src/common/fdset_kqueue.c b/src/common/fdset_kqueue.c index bbb35fc..b9f639d 100644 --- a/src/common/fdset_kqueue.c +++ b/src/common/fdset_kqueue.c @@ -15,7 +15,6 @@ */ #include <config.h> - #ifdef HAVE_KQUEUE #include <stdint.h> diff --git a/src/common/general-tree.c b/src/common/general-tree.c index 202b31a..e1048e7 100644 --- a/src/common/general-tree.c +++ b/src/common/general-tree.c @@ -19,7 +19,6 @@ #include <string.h> #include <assert.h> #include "common/general-tree.h" -#include "common/errors.h" MOD_TREE_DEFINE(general_tree_node, avl); @@ -202,6 +201,7 @@ general_tree_t *gen_tree_shallow_copy(general_tree_t *tree) if (gen_tree_copy_node(tree->tree->th_root, &new_tree->tree->th_root) != 0) { + free(new_tree); return NULL; } diff --git a/src/common/libtap/tap.c b/src/common/libtap/tap.c index 8b660fe..d6bb995 100644 --- a/src/common/libtap/tap.c +++ b/src/common/libtap/tap.c @@ -1,26 +1,14 @@ -/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. - */ +/* +libtap - Write tests in C +Copyright (C) 2011 Jake Gelbman <gelbman@gmail.com> +This file is licensed under the GPL v3 +*/ #include <config.h> #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <string.h> - -//#include "common.h" #include "tap.h" static int expected_tests = NO_PLAN; @@ -28,13 +16,6 @@ static int failed_tests; static int current_test; static char *todo_mesg; -void -plan (int tests) { - expected_tests = tests; - if (tests != NO_PLAN) - printf("1..%d\n", tests); -} - static char * vstrdupf (const char *fmt, va_list args) { char *str; @@ -50,42 +31,57 @@ vstrdupf (const char *fmt, va_list args) { return str; } +void +cplan (int tests, const char *fmt, ...) { + expected_tests = tests; + if (tests == SKIP_ALL) { + char *why; + va_list args; + va_start(args, fmt); + why = vstrdupf(fmt, args); + va_end(args); + printf("1..0 "); + note("SKIP %s\n", why); + exit(0); + } + if (tests != NO_PLAN) { + printf("1..%d\n", tests); + } +} + int -vok_at_loc (const char *file, int line, int test, int verbose, const char *fmt, +vok_at_loc (const char *file, int line, int test, const char *fmt, va_list args) { - if (verbose) { - char *name = vstrdupf(fmt, args); - printf("%sok %d", test ? "" : "not ", ++current_test); - if (*name) - printf(" - %s", name); - if (todo_mesg) { - printf(" # TODO"); - if (*todo_mesg) - printf(" %s", todo_mesg); - } - printf("\n"); - if (!test) { - if (*name) - diag(" Failed%s test '%s'\n at %s line %d.", - todo_mesg ? " (TODO)" : "", name, file, line); - else - diag(" Failed%s test at %s line %d.", - todo_mesg ? " (TODO)" : "", file, line); - if (!todo_mesg) - failed_tests++; - - free(name); - } + char *name = vstrdupf(fmt, args); + printf("%sok %d", test ? "" : "not ", ++current_test); + if (*name) + printf(" - %s", name); + if (todo_mesg) { + printf(" # TODO"); + if (*todo_mesg) + printf(" %s", todo_mesg); } + printf("\n"); + if (!test) { + if (*name) + diag(" Failed%s test '%s'\n at %s line %d.", + todo_mesg ? " (TODO)" : "", name, file, line); + else + diag(" Failed%s test at %s line %d.", + todo_mesg ? " (TODO)" : "", file, line); + if (!todo_mesg) + failed_tests++; + } + free(name); return test; } int -ok_at_loc (const char *file, int line, int verbose, int test, const char *fmt, ...) { +ok_at_loc (const char *file, int line, int test, const char *fmt, ...) { va_list args; va_start(args, fmt); - vok_at_loc(file, line, test, verbose, fmt, args); + vok_at_loc(file, line, test, fmt, args); va_end(args); return test; } @@ -105,7 +101,7 @@ is_at_loc (const char *file, int line, const char *got, const char *expected, int test = eq(got, expected); va_list args; va_start(args, fmt); - vok_at_loc(file, line, test, 1, fmt, args); + vok_at_loc(file, line, test, fmt, args); va_end(args); if (!test) { diag(" got: '%s'", got); @@ -116,13 +112,12 @@ is_at_loc (const char *file, int line, const char *got, const char *expected, int isnt_at_loc (const char *file, int line, const char *got, const char *expected, - int verbose, const char *fmt, ...) { int test = ne(got, expected); va_list args; va_start(args, fmt); - vok_at_loc(file, line, test, verbose, fmt, args); + vok_at_loc(file, line, test, fmt, args); va_end(args); if (!test) { diag(" got: '%s'", got); @@ -156,7 +151,7 @@ cmp_ok_at_loc (const char *file, int line, int a, const char *op, int b, : diag("unrecognized operator '%s'", op); va_list args; va_start(args, fmt); - vok_at_loc(file, line, test, 1, fmt, args); + vok_at_loc(file, line, test, fmt, args); va_end(args); if (!test) { diag(" %d", a); @@ -179,9 +174,10 @@ vdiag_to_fh (FILE *fh, const char *fmt, va_list args) { if (!c || c == '\n') { mesg[i] = '\0'; fprintf(fh, "# %s\n", line); - if (!c) break; + if (!c) + break; mesg[i] = c; - line = &mesg[i+1]; + line = mesg + i + 1; } } free(mesg); @@ -228,6 +224,18 @@ exit_status () { return retval; } +int +bail_out (int ignore, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + printf("Bail out! "); + vprintf(fmt, args); + printf("\n"); + va_end(args); + exit(255); + return 0; +} + void skippy (int n, const char *fmt, ...) { char *why; @@ -260,7 +268,7 @@ cendtodo () { #include <sys/mman.h> #include <regex.h> -#ifndef MAP_ANONYMOUS +#ifndef MAP_ANONYMOUS #define MAP_ANONYMOUS MAP_ANON #endif @@ -282,10 +290,11 @@ tap_test_died (int status) { int like_at_loc (int for_match, const char *file, int line, const char *got, - const char *expected, int verbose, const char *fmt, ...) + const char *expected, const char *fmt, ...) { int test; regex_t re; + va_list args; int err = regcomp(&re, expected, REG_EXTENDED); if (err) { char errbuf[256]; @@ -297,9 +306,8 @@ like_at_loc (int for_match, const char *file, int line, const char *got, err = regexec(&re, got, 0, NULL, 0); regfree(&re); test = for_match ? !err : err; - va_list args; va_start(args, fmt); - vok_at_loc(file, line, test, verbose, fmt, args); + vok_at_loc(file, line, test, fmt, args); va_end(args); if (!test) { if (for_match) { diff --git a/src/common/libtap/tap.h b/src/common/libtap/tap.h index 4522fbb..89484f4 100644 --- a/src/common/libtap/tap.h +++ b/src/common/libtap/tap.h @@ -1,104 +1,114 @@ -/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. - */ +/* +libtap - Write tests in C +Copyright (C) 2011 Jake Gelbman <gelbman@gmail.com> +This file is licensed under the GPL v3 +*/ #ifndef __TAP_H__ #define __TAP_H__ +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef va_copy +#ifdef __va_copy +#define va_copy __va_copy +#else +#define va_copy(d, s) ((d) = (s)) +#endif +#endif + #include <stdio.h> #include <stdlib.h> #include <stdarg.h> -#define NO_PLAN -1 -#define ok(...) ok_at_loc(__FILE__, __LINE__, 1, __VA_ARGS__, NULL) -#define pass(...) ok(1, ## __VA_ARGS__) -#define fail(...) ok(0, ## __VA_ARGS__) -#define is(...) is_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) -#define isnt(...) isnt_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) -#define cmp_ok(...) cmp_ok_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) - -int vok_at_loc (const char *file, int line, int test, int verbose, const char *fmt, +int vok_at_loc (const char *file, int line, int test, const char *fmt, va_list args); -void plan (int tests); -int ok_at_loc (const char *file, int line, int test, int verbose, const char *fmt, +int ok_at_loc (const char *file, int line, int test, const char *fmt, ...); +int is_at_loc (const char *file, int line, const char *got, + const char *expected, const char *fmt, ...); +int isnt_at_loc (const char *file, int line, const char *got, + const char *expected, const char *fmt, ...); +int cmp_ok_at_loc (const char *file, int line, int a, const char *op, + int b, const char *fmt, ...); +int bail_out (int ignore, const char *fmt, ...); +void cplan (int tests, const char *fmt, ...); int diag (const char *fmt, ...); int note (const char *fmt, ...); int exit_status (void); void skippy (int n, const char *fmt, ...); void ctodo (int ignore, const char *fmt, ...); void cendtodo (void); -int is_at_loc (const char *file, int line, const char *got, - const char *expected, - const char *fmt, ...); -int isnt_at_loc (const char *file, int line, const char *got, - const char *expected, int verbose, const char *fmt, ...); -int cmp_ok_at_loc (const char *file, int line, int a, const char *op, - int b, const char *fmt, ...); -#ifdef _WIN32 -#define like(...) skippy(1, "like is not implemented on MSWin32") -#define unlike(...) like() -#else -#define like(...) like_at_loc(1, __FILE__, __LINE__, __VA_ARGS__, NULL) -#define unlike(...) like_at_loc(0, __FILE__, __LINE__, __VA_ARGS__, NULL) -int like_at_loc (int for_match, const char *file, int line, - const char *got, const char *expected, - int verbose, - const char *fmt, ...); -#endif +#define NO_PLAN -1 +#define SKIP_ALL -2 +#define ok(...) ok_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) +#define is(...) is_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) +#define isnt(...) isnt_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) +#define cmp_ok(...) cmp_ok_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) +#define plan(...) cplan(__VA_ARGS__, NULL) +#define done_testing() return exit_status() +#define BAIL_OUT(...) bail_out(0, "" __VA_ARGS__, NULL) +#define pass(...) ok(1, "" __VA_ARGS__) +#define fail(...) ok(0, "" __VA_ARGS__) #define skip(test, ...) do {if (test) {skippy(__VA_ARGS__, NULL); break;} #define endskip } while (0) -#define todo(...) ctodo(0, ## __VA_ARGS__, NULL) +#define todo(...) ctodo(0, "" __VA_ARGS__, NULL) #define endtodo cendtodo() -#define dies_ok(code, ...) dies_ok_common(code, 1, 1, ## __VA_ARGS__) -#define lives_ok(code, ...) dies_ok_common(code, 0, 1, ## __VA_ARGS__) -#define lives_ok_silent(code, ...) dies_ok_common(code, 0, 0, ## __VA_ARGS__) +#define dies_ok(...) dies_ok_common(1, __VA_ARGS__) +#define lives_ok(...) dies_ok_common(0, __VA_ARGS__) #ifdef _WIN32 +#define like(...) skippy(1, "like is not implemented on MSWin32") +#define unlike like #define dies_ok_common(...) \ skippy(1, "Death detection is not supported on MSWin32") #else +#define like(...) like_at_loc(1, __FILE__, __LINE__, __VA_ARGS__, NULL) +#define unlike(...) like_at_loc(0, __FILE__, __LINE__, __VA_ARGS__, NULL) +int like_at_loc (int for_match, const char *file, int line, + const char *got, const char *expected, + const char *fmt, ...); #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> int tap_test_died (int status); -#define dies_ok_common(code, for_death, verbose, ...) \ +#define dies_ok_common(for_death, code, ...) \ do { \ + int cpid; \ + int it_died; \ tap_test_died(1); \ - int cpid = fork(); \ + cpid = fork(); \ switch (cpid) { \ case -1: \ perror("fork error"); \ - exit(EXIT_FAILURE); \ - case 0: /* child */ \ - close(1); close(2); \ + exit(1); \ + case 0: \ + close(1); \ + close(2); \ code \ tap_test_died(0); \ - exit(EXIT_SUCCESS); \ + exit(0); \ } \ if (waitpid(cpid, NULL, 0) < 0) { \ perror("waitpid error"); \ - exit(EXIT_FAILURE); \ + exit(1); \ } \ - int it_died = tap_test_died(0); \ - if (!it_died) {code} \ - ok_at_loc(__FILE__, __LINE__, verbose, for_death ? it_died : !it_died, ## __VA_ARGS__); \ + it_died = tap_test_died(0); \ + if (!it_died) \ + {code} \ + ok(for_death ? it_died : !it_died, "" __VA_ARGS__); \ } while (0) #endif + +#ifdef __cplusplus +} #endif + +#endif + diff --git a/src/common/skip-list.c b/src/common/skip-list.c index 79e9429..cde08d7 100644 --- a/src/common/skip-list.c +++ b/src/common/skip-list.c @@ -66,10 +66,10 @@ static float frand() /*! * \brief Returns random level between 0 and MAX_LEVEL. */ -static int skip_random_level() +static unsigned skip_random_level() { static int first = 1; - int lvl = 0; + unsigned lvl = 0; if (first) { first = 0; @@ -216,6 +216,7 @@ void *skip_find(const skip_list_t *list, void *key) && list->compare_keys(x->forward[i]->key, key) == -1) { x = x->forward[i]; } + if (i == 0) break; } x = x->forward[0]; @@ -240,6 +241,7 @@ void *skip_find_less_or_equal(const skip_list_t *list, void *key) && list->compare_keys(x->forward[i]->key, key) <= 0) { x = x->forward[i]; } + if (i == 0) break; } return x->value; @@ -265,11 +267,12 @@ int skip_insert(skip_list_t *list, void *key, void *value, x = x->forward[i]; } update[i] = x; + if (i == 0) break; } x = x->forward[0]; if (x == NULL || list->compare_keys(x->key, key) != 0) { - int lvl = skip_random_level(); + unsigned lvl = skip_random_level(); if (lvl > list->level) { for (i = list->level + 1; i <= lvl; i++) { @@ -319,6 +322,7 @@ int skip_remove(skip_list_t *list, void *key, void (*destroy_key)(void *), x = x->forward[i]; } update[i] = x; + if (i == 0) break; } x = x->forward[0]; diff --git a/src/common/sockaddr.c b/src/common/sockaddr.c index cd3a4b9..48551bc 100644 --- a/src/common/sockaddr.c +++ b/src/common/sockaddr.c @@ -32,10 +32,12 @@ int sockaddr_init(sockaddr_t *addr, int af) switch(af) { case AF_INET: addr->len = sizeof(struct sockaddr_in); + addr->prefix = IPV4_PREFIXLEN; break; #ifndef DISABLE_IPV6 case AF_INET6: addr->len = sizeof(struct sockaddr_in6); + addr->prefix = IPV6_PREFIXLEN; break; #endif default: @@ -86,6 +88,7 @@ int sockaddr_set(sockaddr_t *dst, int family, const char* addr, int port) dst->addr4.sin_port = htons(port); paddr = &dst->addr4.sin_addr; dst->addr4.sin_addr.s_addr = INADDR_ANY; + dst->prefix = IPV4_PREFIXLEN; break; #ifndef DISABLE_IPV6 case AF_INET6: @@ -94,6 +97,7 @@ int sockaddr_set(sockaddr_t *dst, int family, const char* addr, int port) paddr = &dst->addr6.sin6_addr; memcpy(&dst->addr6.sin6_addr, &in6addr_any, sizeof(in6addr_any)); + dst->prefix = IPV6_PREFIXLEN; break; #endif default: @@ -104,6 +108,15 @@ int sockaddr_set(sockaddr_t *dst, int family, const char* addr, int port) return inet_pton(family, addr, paddr); } +int sockaddr_setprefix(sockaddr_t *dst, int prefix) +{ + if (dst == NULL || prefix < 0) { + return -1; + } + + return dst->prefix = prefix; +} + int sockaddr_tostr(sockaddr_t *addr, char *dst, size_t size) { if (!addr || !dst || size == 0) { diff --git a/src/common/sockaddr.h b/src/common/sockaddr.h index 51ba779..b2725c0 100644 --- a/src/common/sockaddr.h +++ b/src/common/sockaddr.h @@ -38,6 +38,7 @@ /*! \brief Universal socket address. */ typedef struct sockaddr_t { int family; /*!< Address family. */ + short prefix; /*!< Address prefix. */ struct sockaddr* ptr; /*!< Pointer to used sockaddr. */ socklen_t len; /*!< Length of used sockaddr. */ union { @@ -48,6 +49,10 @@ typedef struct sockaddr_t { }; } sockaddr_t; +/* Subnet maximum prefix length. */ +#define IPV4_PREFIXLEN 32 +#define IPV6_PREFIXLEN 128 + /*! \brief Maximum address length in string format. */ #ifdef DISABLE_IPV6 #define SOCKADDR_STRLEN INET_ADDRSTRLEN @@ -94,6 +99,17 @@ int sockaddr_update(sockaddr_t *addr); int sockaddr_set(sockaddr_t *dst, int family, const char* addr, int port); /*! + * \brief Set address prefix. + * + * \param dst Target address structure. + * \param prefix Prefix. + * + * \retval 0 if success. + * \retval -1 on error. + */ +int sockaddr_setprefix(sockaddr_t *dst, int prefix); + +/*! * \brief Return string representation of socket address. * * \param addr Socket address structure. diff --git a/src/config.h.in b/src/config.h.in index 4761e6b..dfcea86 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -210,6 +210,33 @@ /* Define to 1 if the system has the type `_Bool'. */ #undef HAVE__BOOL +/* Server debug. */ +#undef KNOTD_SERVER_DEBUG + +/* Zone compiler debug. */ +#undef KNOT_COMPILER_DEBUG + +/* Domain names debug. */ +#undef KNOT_DNAME_DEBUG + +/* Hashtable debug. */ +#undef KNOT_HASH_DEBUG + +/* Nameserver debug. */ +#undef KNOT_NS_DEBUG + +/* Packet debug. */ +#undef KNOT_PACKET_DEBUG + +/* RR debug. */ +#undef KNOT_RR_DEBUG + +/* XFR debug. */ +#undef KNOT_XFR_DEBUG + +/* Zones debug. */ +#undef KNOT_ZONES_DEBUG + /* Define to the sub-directory in which libtool stores uninstalled libraries. */ #undef LT_OBJDIR diff --git a/src/knot/conf/cf-parse.y b/src/knot/conf/cf-parse.y index 9d68d90..c7efa10 100644 --- a/src/knot/conf/cf-parse.y +++ b/src/knot/conf/cf-parse.y @@ -12,6 +12,7 @@ #include <stdlib.h> #include <pwd.h> #include <grp.h> +#include "common/sockaddr.h" #include "libknot/dname.h" #include "knot/conf/conf.h" #include "libknotd_la-cf-parse.h" /* Automake generated header. */ @@ -27,9 +28,13 @@ static conf_log_t *this_log = 0; static conf_log_map_t *this_logmap = 0; //#define YYERROR_VERBOSE 1 -static void conf_start_iface(char* ifname) +static void conf_start_iface(void *scanner, char* ifname) { this_iface = malloc(sizeof(conf_iface_t)); + if (this_iface == NULL) { + cf_error(scanner, "not enough memory when allocating interface"); + return; + } memset(this_iface, 0, sizeof(conf_iface_t)); this_iface->name = ifname; this_iface->port = CONFIG_DEFAULT_PORT; @@ -37,9 +42,13 @@ static void conf_start_iface(char* ifname) ++new_config->ifaces_count; } -static void conf_start_remote(char *remote) +static void conf_start_remote(void *scanner, char *remote) { this_remote = malloc(sizeof(conf_iface_t)); + if (this_remote == NULL) { + cf_error(scanner, "not enough memory when allocating remote"); + return; + } memset(this_remote, 0, sizeof(conf_iface_t)); this_remote->name = remote; add_tail(&new_config->remotes, &this_remote->n); @@ -149,6 +158,69 @@ static int conf_key_add(void *scanner, knot_key_t **key, char *item) return 1; } +static void conf_zone_start(void *scanner, char *name) { + this_zone = malloc(sizeof(conf_zone_t)); + if (this_zone == NULL || name == NULL) { + cf_error(scanner, "out of memory while allocating zone config"); + return; + } + memset(this_zone, 0, sizeof(conf_zone_t)); + this_zone->enable_checks = -1; // Default policy applies + this_zone->notify_timeout = -1; // Default policy applies + this_zone->notify_retries = 0; // Default policy applies + this_zone->ixfr_fslimit = -1; // Default policy applies + this_zone->dbsync_timeout = -1; // Default policy applies + + // Append mising dot to ensure FQDN + size_t nlen = strlen(name); + if (name[nlen - 1] != '.') { + this_zone->name = malloc(nlen + 2); + if (this_zone->name != NULL) { + memcpy(this_zone->name, name, nlen); + this_zone->name[nlen] = '.'; + this_zone->name[nlen + 1] = '\0'; + } + free(name); + } else { + this_zone->name = name; /* Already FQDN */ + } + + /* Check domain name. */ + knot_dname_t *dn = NULL; + if (this_zone->name != NULL) { + dn = knot_dname_new_from_str(this_zone->name, nlen + 1, 0); + } + if (dn == NULL) { + free(this_zone->name); + free(this_zone); + this_zone = NULL; + cf_error(scanner, "invalid zone origin"); + } else { + /* Directly discard dname, won't be needed. */ + knot_dname_free(&dn); + add_tail(&new_config->zones, &this_zone->n); + ++new_config->zones_count; + + /* Initialize ACL lists. */ + init_list(&this_zone->acl.xfr_in); + init_list(&this_zone->acl.xfr_out); + init_list(&this_zone->acl.notify_in); + init_list(&this_zone->acl.notify_out); + } +} + +static int conf_mask(void* scanner, int nval, int prefixlen) { + if (nval < 0 || nval > prefixlen) { + char buf[512]; + snprintf(buf, sizeof(buf), "IPv%c subnet prefix '%d' is " + "out of range <0,%d>", + prefixlen == IPV4_PREFIXLEN ? '4' : '6', nval, prefixlen); + cf_error(scanner, buf); + return prefixlen; /* single host */ + } + return nval; +} + %} %pure-parser @@ -212,11 +284,11 @@ conf_entries: ; interface_start: - | TEXT { conf_start_iface($1.t); } - | REMOTES { conf_start_iface(strdup($1.t)); } /* Allow strings reserved by token. */ - | LOG_SRC { conf_start_iface(strdup($1.t)); } - | LOG { conf_start_iface(strdup($1.t)); } - | LOG_LEVEL { conf_start_iface(strdup($1.t)); } + | TEXT { conf_start_iface(scanner, $1.t); } + | REMOTES { conf_start_iface(scanner, strdup($1.t)); } /* Allow strings reserved by token. */ + | LOG_SRC { conf_start_iface(scanner, strdup($1.t)); } + | LOG { conf_start_iface(scanner, strdup($1.t)); } + | LOG_LEVEL { conf_start_iface(scanner, strdup($1.t)); } ; interface: @@ -382,10 +454,10 @@ keys: } remote_start: - | TEXT { conf_start_remote($1.t); } - | LOG_SRC { conf_start_remote(strdup($1.t)); } - | LOG { conf_start_remote(strdup($1.t)); } - | LOG_LEVEL { conf_start_remote(strdup($1.t)); } + | TEXT { conf_start_remote(scanner, $1.t); } + | LOG_SRC { conf_start_remote(scanner, strdup($1.t)); } + | LOG { conf_start_remote(scanner, strdup($1.t)); } + | LOG_LEVEL { conf_start_remote(scanner, strdup($1.t)); } ; remote: @@ -402,15 +474,26 @@ remote: cf_error(scanner, "only one address is allowed in remote section\n"); } else { this_remote->address = $3.t; + this_remote->prefix = IPV4_PREFIXLEN; this_remote->family = AF_INET; } } + | remote ADDRESS IPA '/' NUM ';' { + if (this_remote->address != 0) { + cf_error(scanner, "only one address is allowed in remote section\n"); + } else { + this_remote->address = $3.t; + this_remote->family = AF_INET; + this_remote->prefix = conf_mask(scanner, $5.i, IPV4_PREFIXLEN); + } + } | remote ADDRESS IPA '@' NUM ';' { if (this_remote->address != 0) { cf_error(scanner, "only one address is allowed in remote section\n"); } else { this_remote->address = $3.t; this_remote->family = AF_INET; + this_remote->prefix = IPV4_PREFIXLEN; if (this_remote->port != 0) { cf_error(scanner, "only one port definition is allowed in remote section\n"); } else { @@ -424,14 +507,25 @@ remote: } else { this_remote->address = $3.t; this_remote->family = AF_INET6; + this_remote->prefix = IPV6_PREFIXLEN; } } + | remote ADDRESS IPA6 '/' NUM ';' { + if (this_remote->address != 0) { + cf_error(scanner, "only one address is allowed in remote section\n"); + } else { + this_remote->address = $3.t; + this_remote->family = AF_INET6; + this_remote->prefix = conf_mask(scanner, $5.i, IPV6_PREFIXLEN); + } + } | remote ADDRESS IPA6 '@' NUM ';' { if (this_remote->address != 0) { cf_error(scanner, "only one address is allowed in remote section\n"); } else { this_remote->address = $3.t; this_remote->family = AF_INET6; + this_remote->prefix = IPV6_PREFIXLEN; if (this_remote->port != 0) { cf_error(scanner, "only one port definition is allowed in remote section\n"); } else { @@ -528,52 +622,13 @@ zone_acl: } ; -zone_start: TEXT { - this_zone = malloc(sizeof(conf_zone_t)); - memset(this_zone, 0, sizeof(conf_zone_t)); - this_zone->enable_checks = -1; // Default policy applies - this_zone->notify_timeout = -1; // Default policy applies - this_zone->notify_retries = 0; // Default policy applies - this_zone->ixfr_fslimit = -1; // Default policy applies - this_zone->dbsync_timeout = -1; // Default policy applies - - // Append mising dot to ensure FQDN - char *name = $1.t; - size_t nlen = strlen(name); - if (name[nlen - 1] != '.') { - this_zone->name = malloc(nlen + 2); - if (this_zone->name != NULL) { - memcpy(this_zone->name, name, nlen); - this_zone->name[nlen] = '.'; - this_zone->name[nlen + 1] = '\0'; - } - free(name); - } else { - this_zone->name = name; /* Already FQDN */ - } - - /* Check domain name. */ - knot_dname_t *dn = NULL; - if (this_zone->name != NULL) { - dn = knot_dname_new_from_str(this_zone->name, nlen + 1, 0); - } - if (dn == NULL) { - free(this_zone->name); - free(this_zone); - cf_error(scanner, "invalid zone origin"); - } else { - /* Directly discard dname, won't be needed. */ - knot_dname_free(&dn); - add_tail(&new_config->zones, &this_zone->n); - ++new_config->zones_count; - - /* Initialize ACL lists. */ - init_list(&this_zone->acl.xfr_in); - init_list(&this_zone->acl.xfr_out); - init_list(&this_zone->acl.notify_in); - init_list(&this_zone->acl.notify_out); - } - } +zone_start: + | TEXT { conf_zone_start(scanner, $1.t); } + | USER { conf_zone_start(scanner, strdup($1.t)); } + | REMOTES { conf_zone_start(scanner, strdup($1.t)); } + | LOG_SRC { conf_zone_start(scanner, strdup($1.t)); } + | LOG { conf_zone_start(scanner, strdup($1.t)); } + | LOG_LEVEL { conf_zone_start(scanner, strdup($1.t)); } ; zone: diff --git a/src/knot/conf/conf.c b/src/knot/conf/conf.c index a382bba..2c5747a 100644 --- a/src/knot/conf/conf.c +++ b/src/knot/conf/conf.c @@ -43,26 +43,6 @@ static const char *DEFAULT_CONFIG[] = { * Utilities. */ -/*! - * \brief Recursively create directories. - * - * Similar to "mkdir -p". - * * \retval 0 on success. - * \retval <0 on error. - */ -static int rmkdir(char *path, int mode) -{ - char *p = path; - while((p = strchr(p + 1, '/'))) { - *p = '\0'; - mkdir(path, mode); - *p = '/'; - } - - // Final path - return mkdir(path, mode); -} - /* Prototypes for cf-parse.y */ extern int cf_parse(void *scanner); extern int cf_get_lineno(void *scanner); @@ -192,27 +172,36 @@ static void conf_update_hooks(conf_t *conf) static int conf_process(conf_t *conf) { // Check - if (!conf->storage) { + if (conf->storage == NULL) { conf->storage = strdup("/var/lib/"PROJECT_EXEC); + if (conf->storage == NULL) { + return KNOTD_ENOMEM; + } } // Normalize paths conf->storage = strcpath(conf->storage); + + // Storage directory exists? struct stat st; - if (stat(conf->storage, &st) != 0) { - rmkdir(conf->storage, S_IRWXU); - if (conf->uid >= 0) { - if (chown(conf->storage, conf->uid, conf->gid) < 0) { - log_server_warning("Could not change ownership" - " of '%s' to uid=%d.\n", - conf->storage, conf->uid); - } - } + if (stat(conf->storage, &st) == -1) { + log_server_error("Could not open storage directory '%s'\n", conf->storage); + // I assume that conf->* is freed elsewhere + return KNOTD_EINVAL; + } + + // Storage directory is a directory? + if (S_ISDIR(st.st_mode) == 0) { + log_server_error("Configured storage '%s' not a directory\n", conf->storage); + return KNOTD_EINVAL; } // Create PID file if (conf->pidfile == NULL) { conf->pidfile = strcdup(conf->storage, "/" PID_FILE); + if (conf->pidfile == NULL) { + return KNOTD_ENOMEM; + } } // Postprocess zones @@ -248,32 +237,40 @@ static int conf_process(conf_t *conf) // Normalize zone filename zone->file = strcpath(zone->file); + if (zone->file == NULL) { + zone->db = NULL; + ret = KNOTD_ENOMEM; + continue; + } // Create zone db filename size_t zname_len = strlen(zone->name); size_t stor_len = strlen(conf->storage); - size_t size = stor_len + zname_len + 4; // db/,\0 + size_t size = stor_len + zname_len + 4; // /db,\0 char *dest = malloc(size); if (dest == NULL) { zone->db = NULL; /* Not enough memory. */ ret = KNOTD_ENOMEM; /* Error report. */ continue; } + char *dpos = dest; /* Since we have already allocd dest to accomodate * storage/zname length strcpy is safe. */ - strncpy(dest, conf->storage, stor_len + 1); - if (conf->storage[stor_len - 1] != '/') { - strncat(dest, "/", 1); + memcpy(dpos, conf->storage, stor_len + 1); + dpos += stor_len; + if (*(dpos - 1) != '/') { + *(dpos++) = '/'; + *dpos = '\0'; } - strncat(dest, zone->name, zname_len); - strncat(dest, "db", 2); + memcpy(dpos, zone->name, zname_len + 1); + memcpy(dpos + zname_len, "db", 3); zone->db = dest; // Create IXFR db filename stor_len = strlen(conf->storage); - size = stor_len + zname_len + 9; // diff.db/,\0 + size = stor_len + zname_len + 9; // /diff.db,\0 dest = malloc(size); if (dest == NULL) { zone->ixfr_db = NULL; /* Not enough memory. */ @@ -483,10 +480,11 @@ int conf_parse(conf_t *conf) int ret = conf_fparser(conf); /* Postprocess config. */ - conf_process(conf); - - /* Update hooks. */ - conf_update_hooks(conf); + if (ret == 0) { + ret = conf_process(conf); + /* Update hooks. */ + conf_update_hooks(conf); + } if (ret < 0) { return KNOTD_EPARSEFAIL; @@ -649,6 +647,11 @@ int conf_open(const char* path) /* Parse config. */ int ret = conf_fparser(nconf); + if (ret == KNOTD_EOK) { + /* Postprocess config. */ + ret = conf_process(nconf); + } + if (ret != KNOTD_EOK) { conf_free(nconf); return ret; @@ -667,9 +670,6 @@ int conf_open(const char* path) } } - /* Postprocess config. */ - conf_process(nconf); - /* Synchronize. */ synchronize_rcu(); @@ -719,6 +719,10 @@ char* strcpath(char *path) // Expand '~' char* remainder = strchr(path,'~'); if (remainder != NULL) { + if (remainder[1] != '/') { + log_server_warning("Cannot expand non-login user home directory '%s', use full path instead", path); + } + // Get full path char *tild_exp_unsafe = getenv("HOME"); if (tild_exp_unsafe == NULL) { @@ -726,11 +730,12 @@ char* strcpath(char *path) } // Sanitize size_t tild_len = strlen(tild_exp_unsafe); - char *tild_exp = malloc(tild_len); + char *tild_exp = malloc(tild_len + 1); if (tild_exp == NULL) { return NULL; } - strncpy(tild_exp, tild_exp_unsafe, tild_len + 1); + // Duplicate tild_exp including terminating NULL + memcpy(tild_exp, tild_exp_unsafe, tild_len + 1); if (tild_exp[tild_len - 1] == '/') { tild_exp[--tild_len] = '\0'; } @@ -747,11 +752,11 @@ char* strcpath(char *path) // Append remainder ++remainder; - size_t remainder_len = strlen(remainder); - strncat(npath, remainder, remainder_len); + strncat(npath, remainder, strlen(remainder)); + + free(tild_exp); free(path); path = npath; - free(tild_exp); } return path; diff --git a/src/knot/conf/conf.h b/src/knot/conf/conf.h index b5c1afa..1e6644e 100644 --- a/src/knot/conf/conf.h +++ b/src/knot/conf/conf.h @@ -56,6 +56,7 @@ typedef struct conf_iface_t { node n; char *name; /*!< Internal name for the interface. */ char *address; /*!< IP (IPv4/v6) address for this interface */ + unsigned prefix; /*!< IP subnet prefix. */ int port; /*!< Port number for this interface */ int family; /*!< Address family. */ knot_key_t *key; /*!< TSIG key (only valid for remotes). */ diff --git a/src/knot/ctl/knotc_main.c b/src/knot/ctl/knotc_main.c index f111f25..59556c1 100644 --- a/src/knot/ctl/knotc_main.c +++ b/src/knot/ctl/knotc_main.c @@ -271,6 +271,15 @@ int execute(const char *action, char **argv, int argc, pid_t pid, int valid_cmd = 0; int rc = 0; if (strcmp(action, "start") == 0) { + // Check pidfile for w+ + FILE* chkf = fopen(pidfile, "w+"); + if (chkf == NULL) { + fprintf(stderr, "control: PID file '%s' is not writeable, refusing to start\n", pidfile); + return 1; + } else { + fclose(chkf); + chkf = NULL; + } // Check PID valid_cmd = 1; @@ -573,7 +582,7 @@ int main(int argc, char **argv) {"verbose", no_argument, 0, 'v'}, {"interactive", no_argument, 0, 'i'}, {"auto", no_argument, 0, 'a'}, - {"jobs", required_argument, 0, 'c'}, + {"jobs", required_argument, 0, 'j'}, {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0} diff --git a/src/knot/ctl/process.c b/src/knot/ctl/process.c index e46fa37..bb61804 100644 --- a/src/knot/ctl/process.c +++ b/src/knot/ctl/process.c @@ -33,7 +33,7 @@ char* pid_filename() /* Read configuration. */ char* ret = 0; - if (conf()) { + if (conf() && conf()->pidfile != NULL) { ret = strdup(conf()->pidfile); } diff --git a/src/knot/main.c b/src/knot/main.c index d4c6bca..f63916a 100644 --- a/src/knot/main.c +++ b/src/knot/main.c @@ -55,7 +55,6 @@ void interrupt_handle(int s) sig_req_stop = 1; sig_stopping = 1; } else { - log_server_notice("OK! Exiting immediately.\n"); exit(1); } } @@ -234,6 +233,7 @@ int main(int argc, char **argv) log_server_error("Failed to parse configuration '%s'.\n", config_fn); } + server_wait(server); server_destroy(&server); free(config_fn); return 1; diff --git a/src/knot/other/debug.h b/src/knot/other/debug.h index 93b52fe..7768d22 100644 --- a/src/knot/other/debug.h +++ b/src/knot/other/debug.h @@ -29,20 +29,29 @@ #include "config.h" /* autoconf generated */ +#ifdef KNOTD_SERVER_DEBUG + #define KNOTD_THREADS_DEBUG + #define KNOTD_JOURNAL_DEBUG + #define KNOTD_NET_DEBUG +#endif + +#ifdef KNOT_ZONES_DEBUG + #define KNOTD_ZONES_DEBUG +#endif + +#ifdef KNOT_XFR_DEBUG + #define KNOTD_XFR_DEBUG + #define KNOTD_NOTIFY_DEBUG +#endif + +#ifdef KNOT_COMPILER_DEBUG + #define KNOTD_ZDUMP_DEBUG + #define KNOTD_ZLOAD_DEBUG +#endif + #include "knot/other/log.h" #include "common/print.h" -/*! \todo Set these during configure as well (issue #1585). */ -//#define KNOTD_SERVER_DEBUG -//#define KNOTD_THREADS_DEBUG -//#define KNOTD_JOURNAL_DEBUG -//#define KNOTD_NET_DEBUG -//#define KNOTD_ZONES_DEBUG -//#define KNOTD_XFR_DEBUG -//#define KNOTD_NOTIFY_DEBUG -//#define KNOTD_ZDUMP_DEBUG -//#define KNOTD_ZLOAD_DEBUG - /******************************************************************************/ #ifdef KNOTD_NOTIFY_DEBUG @@ -363,9 +372,11 @@ #ifdef DEBUG_ENABLE_DETAILS #define dbg_zdump_detail(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) #define dbg_zdump_hex_detail(data, len) hex_log(LOG_SERVER, (data), (len)) +#define dbg_zdump_exec_detail(cmds) do { cmds } while (0) #else #define dbg_zdump_detail(msg...) #define dbg_zdump_hex_detail(data, len) +#define dbg_zdump_exec_detail(cmds) #endif /* No messages. */ @@ -376,6 +387,7 @@ #define dbg_zdump_hex_verb(data, len) #define dbg_zdump_detail(msg...) #define dbg_zdump_hex_detail(data, len) +#define dbg_zdump_exec_detail(cmds) #endif /******************************************************************************/ @@ -404,9 +416,11 @@ #ifdef DEBUG_ENABLE_DETAILS #define dbg_zload_detail(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) #define dbg_zload_hex_detail(data, len) hex_log(LOG_SERVER, (data), (len)) +#define dbg_zload_exec_detail(cmds) do { cmds } while (0) #else #define dbg_zload_detail(msg...) #define dbg_zload_hex_detail(data, len) +#define dbg_zload_exec_detail(cmds) #endif /* No messages. */ @@ -417,6 +431,7 @@ #define dbg_zload_hex_verb(data, len) #define dbg_zload_detail(msg...) #define dbg_zload_hex_detail(data, len) +#define dbg_zload_exec_detail(cmds) #endif /******************************************************************************/ diff --git a/src/knot/other/error.c b/src/knot/other/error.c index a149966..0ab7568 100644 --- a/src/knot/other/error.c +++ b/src/knot/other/error.c @@ -27,7 +27,7 @@ const error_table_t knotd_error_msgs[] = { {KNOTD_EBUSY, "Requested resource is busy."}, {KNOTD_EAGAIN, "The system lacked the necessary resource, try again."}, {KNOTD_EACCES, "Permission to perform requested operation is denied."}, - {KNOTD_ECONNREFUSED, "Connection is refused."}, + {KNOTD_ECONNREFUSED, "Connection refused."}, {KNOTD_EISCONN, "Already connected."}, {KNOTD_EADDRINUSE, "Address already in use."}, {KNOTD_ENOENT, "Resource not found."}, diff --git a/src/knot/server/journal.c b/src/knot/server/journal.c index cd3e342..02e0547 100644 --- a/src/knot/server/journal.c +++ b/src/knot/server/journal.c @@ -133,6 +133,10 @@ static int journal_recover(journal_t *j) int journal_create(const char *fn, uint16_t max_nodes) { + if (fn == NULL) { + return KNOTD_EINVAL; + } + /* File lock. */ struct flock fl; memset(&fl, 0, sizeof(struct flock)); @@ -143,7 +147,7 @@ int journal_create(const char *fn, uint16_t max_nodes) fl.l_pid = getpid(); /* Create journal file. */ - int fd = open(fn, O_RDWR|O_CREAT|O_TRUNC, S_IRWXU|S_IRWXG); + int fd = open(fn, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); if (fd < 0) { dbg_journal("journal: failed to create file '%s'\n", fn); return KNOTD_EINVAL; @@ -219,10 +223,28 @@ int journal_create(const char *fn, uint16_t max_nodes) return KNOTD_EOK; } -journal_t* journal_open(const char *fn, size_t fslimit, uint16_t bflags) +journal_t* journal_open(const char *fn, size_t fslimit, int mode, uint16_t bflags) { /*! \todo Memory mapping may be faster than stdio? (issue #964) */ + 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; + } + /* File lock. */ struct flock fl; memset(&fl, 0, sizeof(struct flock)); @@ -277,6 +299,7 @@ journal_t* journal_open(const char *fn, size_t fslimit, uint16_t bflags) /* 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) { dbg_journal_detail("journal: cannot allocate journal\n"); fcntl(fd, F_SETLK, &fl); @@ -287,6 +310,7 @@ journal_t* journal_open(const char *fn, size_t fslimit, uint16_t bflags) j->fd = fd; j->max_nodes = max_nodes; j->bflags = bflags; + j->refs = 1; /* Load node queue state. */ if (!sfread(&j->qhead, sizeof(uint16_t), fd)) { @@ -646,18 +670,54 @@ int journal_close(journal_t *journal) return KNOTD_EINVAL; } - /* Unlock journal file. */ - journal->fl.l_type = F_UNLCK; - fcntl(journal->fd, F_SETLK, &journal->fl); - dbg_journal("journal: unlocked journal %p\n", journal); - - /* Close file. */ - close(journal->fd); + /* Check if lazy. */ + if (journal->fd < 0) { + free(journal->path); + } else { + /* Unlock journal file. */ + journal->fl.l_type = F_UNLCK; + fcntl(journal->fd, F_SETLK, &journal->fl); + dbg_journal("journal: unlocked journal %p\n", journal); + /* Close file. */ + close(journal->fd); + } + dbg_journal("journal: closed journal %p\n", journal); /* Free allocated resources. */ + free(journal); return KNOTD_EOK; } + +journal_t *journal_retain(journal_t *journal) +{ + /* Return active journal if opened lazily. */ + if (journal != NULL) { + if (journal->fd < 0) { + dbg_journal("journal: retain(), opening for rw\n"); + journal = journal_open(journal->path, journal->fslimit, + 0, journal->bflags); + } else { + ++journal->refs; + dbg_journal("journal: retain(), ++refcount\n"); + } + } + + return journal; +} + + +void journal_release(journal_t *journal) { + if (journal != NULL) { + if (journal->refs == 1) { + dbg_journal("journal: release(), closing last\n"); + journal_close(journal); + } else { + --journal->refs; + dbg_journal_verb("journal: release(), --refcount\n"); + } + } +} diff --git a/src/knot/server/journal.h b/src/knot/server/journal.h index 564f0fe..b04945d 100644 --- a/src/knot/server/journal.h +++ b/src/knot/server/journal.h @@ -55,6 +55,14 @@ typedef enum journal_flag_t { } journal_flag_t; /*! + * \brief Journal mode. + */ +typedef enum journal_mode_t { + JOURNAL_PERSISTENT = 0 << 0, /*!< Persistent mode (open keeps fd). */ + JOURNAL_LAZY = 1 << 0 /*!< Lazy mode (open doesn't keep fd). */ +} journal_mode_t; + +/*! * \brief Journal node structure. * * Each node represents journal entry and points @@ -83,6 +91,8 @@ typedef struct journal_t { int fd; struct flock fl; /*!< File lock. */ + char *path; /*!< Path to journal file. */ + int refs; /*!< Number of references. */ uint16_t max_nodes; /*!< Number of nodes. */ uint16_t qhead; /*!< Node queue head. */ uint16_t qtail; /*!< Node queue tail. */ @@ -133,12 +143,13 @@ int journal_create(const char *fn, uint16_t max_nodes); * * \param fn Journal file name. * \param fslimit File size limit (0 for no limit). + * \param mode Open mode (0 for normal). * \param bflags Initial flags for each written node. * * \retval new journal instance if successful. * \retval NULL on error. */ -journal_t* journal_open(const char *fn, size_t fslimit, uint16_t bflags); +journal_t* journal_open(const char *fn, size_t fslimit, int mode, uint16_t bflags); /*! * \brief Fetch entry node for given identifier. @@ -240,4 +251,22 @@ int journal_update(journal_t *journal, journal_node_t *n); */ int journal_close(journal_t *journal); +/*! + * \brief Retain journal for use. + * + * Allows to track usage of lazily-opened journals. + * + * \param journal Journal. + * + * \return Retained journal. + */ +journal_t *journal_retain(journal_t *journal); + +/*! + * \brief Release retained journal. + * + * \param journal Retained journal. + */ +void journal_release(journal_t *journal); + #endif /* _KNOTD_JOURNAL_H_ */ diff --git a/src/knot/server/notify.c b/src/knot/server/notify.c index 8736372..566d66f 100644 --- a/src/knot/server/notify.c +++ b/src/knot/server/notify.c @@ -317,8 +317,6 @@ int notify_process_response(knot_nameserver_t *nameserver, /* Found waiting NOTIFY query? */ if (!match) { - log_server_notice("No pending NOTIFY query found for ID=%u\n", - pkt_id); pthread_mutex_unlock(&zd->lock); return KNOTD_ERROR; } @@ -329,9 +327,6 @@ int notify_process_response(knot_nameserver_t *nameserver, /* Zone was removed/reloaded. */ pthread_mutex_unlock(&zd->lock); - log_server_info("Received response for pending NOTIFY query ID=%u\n", - pkt_id); - return KNOTD_EOK; } diff --git a/src/knot/server/tcp-handler.c b/src/knot/server/tcp-handler.c index 0af85a9..8f4b990 100644 --- a/src/knot/server/tcp-handler.c +++ b/src/knot/server/tcp-handler.c @@ -31,7 +31,6 @@ #include "common/sockaddr.h" #include "common/skip-list.h" #include "common/fdset.h" -#include "common/prng.h" #include "knot/common.h" #include "knot/server/tcp-handler.h" #include "knot/server/xfr-handler.h" diff --git a/src/knot/server/udp-handler.c b/src/knot/server/udp-handler.c index 60b0843..5276c24 100644 --- a/src/knot/server/udp-handler.c +++ b/src/knot/server/udp-handler.c @@ -202,7 +202,13 @@ static inline int udp_master_recvfrom(dthread_t *thread, stat_t *thread_stat) return KNOTD_ENOTSUP; } - int sock = dup(h->fd); + int sock = h->fd; + int sock_dup = dup(h->fd); + if (sock_dup < 0) { + log_server_warning("Couldn't duplicate UDP socket for listening.\n"); + } else { + sock = sock_dup; + } uint8_t qbuf[SOCKET_MTU_SZ]; /* Loop until all data is read. */ @@ -254,7 +260,9 @@ static inline int udp_master_recvfrom(dthread_t *thread, stat_t *thread_stat) } /* Free allocd resources. */ - close(sock); + if (sock_dup >= 0) { + close(sock_dup); + } return KNOTD_EOK; } diff --git a/src/knot/server/xfr-handler.c b/src/knot/server/xfr-handler.c index fe7c0ab..588670c 100644 --- a/src/knot/server/xfr-handler.c +++ b/src/knot/server/xfr-handler.c @@ -51,6 +51,14 @@ void xfr_interrupt(xfrhandler_t *h) } } +static void xfr_request_deinit(knot_ns_xfr_t *r) +{ + if (r) { + free(r->msgpref); + r->msgpref = NULL; + } +} + /*! * \brief SOA query timeout handler. */ @@ -69,19 +77,11 @@ static int xfr_udp_timeout(event_t *e) } } - sockaddr_update(&data->addr); - char r_addr[SOCKADDR_STRLEN]; - sockaddr_tostr(&data->addr, r_addr, sizeof(r_addr)); - int r_port = sockaddr_portnum(&data->addr); - /* Close socket. */ knot_zone_t *z = data->zone; if (z && knot_zone_get_contents(z) && knot_zone_data(z)) { - zonedata_t *zd = (zonedata_t *)knot_zone_data(z); - log_zone_info("%s '%s' query to %s:%d - timeout exceeded.\n", - data->type == XFR_TYPE_SOA ? "SOA" : "NOTIFY", - zd->conf->name, - r_addr, r_port); + log_zone_info("%s Failed, timeout exceeded.\n", + data->msgpref); } knot_ns_xfr_t cr = {}; @@ -179,6 +179,9 @@ static void xfr_free_task(knot_ns_xfr_t *task) 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); @@ -189,7 +192,7 @@ static knot_ns_xfr_t *xfr_register_task(xfrworker_t *w, knot_ns_xfr_t *req) { knot_ns_xfr_t *t = malloc(sizeof(knot_ns_xfr_t)); if (!t) { - return 0; + return NULL; } memcpy(t, req, sizeof(knot_ns_xfr_t)); @@ -199,16 +202,27 @@ static knot_ns_xfr_t *xfr_register_task(xfrworker_t *w, knot_ns_xfr_t *req) t->wire = 0; /* Invalidate shared buffer. */ t->wire_size = 0; t->data = 0; /* New zone will be built. */ + t->msgpref = strdup(t->msgpref); /* Copy message. */ /* Register data. */ xfrhandler_t * h = w->master; pthread_mutex_lock(&h->tasks_mx); - skip_insert(h->tasks, (void*)((ssize_t)t->session), t, 0); + int ret = skip_insert(h->tasks, (void*)((ssize_t)t->session), t, 0); pthread_mutex_unlock(&h->tasks_mx); /* Add to set. */ - fdset_add(w->fdset, t->session, OS_EV_READ); - t->owner = w; + if (ret == 0) { + ret = fdset_add(w->fdset, t->session, OS_EV_READ); + } + /* Evaluate final return code. */ + if (ret == 0) { + t->owner = w; + } else { + /* Attempt to remove from list anyway. */ + skip_remove(h->tasks, (void*)((ssize_t)t->session), NULL, NULL); + free(t); + t = NULL; + } return t; } @@ -222,11 +236,11 @@ static int xfr_xfrin_cleanup(xfrworker_t *w, knot_ns_xfr_t *data) switch(data->type) { case XFR_TYPE_AIN: - if (data->data) { - if (data->flags & XFR_FLAG_AXFR_FINISHED) { - knot_zone_contents_deep_free( - (knot_zone_contents_t **)&data->data, 0); - } else { + if (data->flags & XFR_FLAG_AXFR_FINISHED) { + knot_zone_contents_deep_free( + &data->new_contents, 1); + } else { + if (data->data) { xfrin_constructed_zone_t *constr_zone = (xfrin_constructed_zone_t *)data->data; knot_zone_contents_deep_free( @@ -242,6 +256,10 @@ static int xfr_xfrin_cleanup(xfrworker_t *w, knot_ns_xfr_t *data) chs = (knot_changesets_t *)data->data; knot_free_changesets(&chs); } + + // this function is called before new contents are created + assert(data->new_contents == NULL); + break; } @@ -259,10 +277,6 @@ static int xfr_xfrin_cleanup(xfrworker_t *w, knot_ns_xfr_t *data) */ static int xfr_xfrin_finalize(xfrworker_t *w, knot_ns_xfr_t *data) { - knot_zone_t *zone = (knot_zone_t *)data->zone; - zonedata_t *zd = (zonedata_t *)knot_zone_data(zone); - const char *zorigin = zd->conf->name; - /* CLEANUP */ // // get the zone name from Question // dbg_xfr_verb("Query: %p, response: %p\n", data->query, data->response); @@ -281,54 +295,105 @@ static int xfr_xfrin_finalize(xfrworker_t *w, knot_ns_xfr_t *data) ret = zones_save_zone(data); if (ret != KNOTD_EOK) { xfr_xfrin_cleanup(w, data); - log_zone_error("AXFR failed to save " - "transferred zone '%s/IN' - %s\n", - zorigin, knotd_strerror(ret)); + 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 != KNOTD_EOK) { - log_zone_error("AXFR failed to " - "switch in-memory zone " - "'%s/IN' - %s\n", - zorigin, - knotd_strerror(ret)); + if (ret != KNOT_EOK) { + log_zone_error("%s Failed to switch in-memory " + "zone - %s\n", data->msgpref, + knot_strerror(ret)); + xfr_xfrin_cleanup(w, data); } } - log_zone_info("AXFR transfer of zone '%s/IN' " - "%s.\n", zorigin, - ret == KNOTD_EOK ? "finished" : "failed"); + if (ret == KNOTD_EOK) { + log_zone_info("%s Finished.\n", data->msgpref); + } break; case XFR_TYPE_IIN: + chs = (knot_changesets_t *)data->data; + + /* First, serialize changesets. */ + ret = zones_changesets_to_binary(chs); + if (ret != KNOTD_EOK) { + log_zone_error("%s Failed to serialize changesets - %s" + "\n", data->msgpref, + knotd_strerror(ret)); + /* Free changesets, but not the data. */ + knot_free_changesets(&chs); + data->data = 0; + break; + } + + /* Now, try to apply the changesets to the zone. */ + ret = xfrin_apply_changesets(data->zone, chs, + &data->new_contents); + + if (ret != KNOT_EOK) { + log_zone_error("%s Failed to apply changesets - %s\n", + data->msgpref, + knot_strerror(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"); + + /*! \note Here, the changesets may already be modified. + * Only the 'data' field of each changeset contains the + * proper serialized changesets. Serials should be + * OK too. + */ ret = zones_store_changesets(data); if (ret != KNOTD_EOK) { - log_zone_error("IXFR failed to save " - "transferred changesets " - "for zone '%s/IN' - %s\n", - zorigin, knotd_strerror(ret)); - } else { - /* Update zone. */ - ret = zones_apply_changesets(data); - if (ret != KNOT_EOK) { - log_zone_error("IXFR failed to " - "apply changesets to " - "zone '%s/IN' - %s\n", - zorigin, - knot_strerror(ret)); - } + log_zone_error("%s Failed to save " + "transferred changesets - %s\n", + data->msgpref, knotd_strerror(ret)); + + // Cleanup old and new contents + xfrin_rollback_update(data->zone->contents, + &data->new_contents, + &chs->changes); + /* Free changesets, but not the data. */ + knot_free_changesets(&chs); + data->data = 0; + break; } + /* Switch zone contents. */ + ret = xfrin_switch_zone(data->zone, data->new_contents, + data->type); + + if (ret != KNOT_EOK) { + log_zone_error("%s Failed to replace " + "current zone - %s\n", + data->msgpref, + knot_strerror(ret)); + // Cleanup old and new contents + xfrin_rollback_update(data->zone->contents, + &data->new_contents, + &chs->changes); + + /* Free changesets, but not the data. */ + knot_free_changesets(&chs); + data->data = 0; + + ret = KNOTD_ERROR; + break; + } + + xfrin_cleanup_successful_update( &chs->changes); + /* Free changesets, but not the data. */ - chs = (knot_changesets_t *)data->data; knot_free_changesets(&chs); - /* CLEANUP */ -// free(chs->sets); -// free(chs); data->data = 0; - log_zone_info("IXFR transfer of zone '%s/IN' " - "%s.\n", zorigin, - ret == KNOTD_EOK ? "finished" : "failed"); + assert(ret == KNOTD_EOK); + log_zone_info("%s Finished.\n", data->msgpref); break; default: ret = KNOTD_EINVAL; @@ -364,7 +429,7 @@ static int xfr_prepare_tsig(knot_ns_xfr_t *xfr, knot_key_t *key) /*! * \brief Check TSIG if exists. */ -static int xfr_check_tsig(knot_ns_xfr_t *xfr, knot_rcode_t *rcode) +static int xfr_check_tsig(knot_ns_xfr_t *xfr, knot_rcode_t *rcode, char **tag) { /* Parse rest of the packet. */ int ret = KNOT_EOK; @@ -382,6 +447,10 @@ static int xfr_check_tsig(knot_ns_xfr_t *xfr, knot_rcode_t *rcode) if (knot_rrset_type(tsig_rr) == KNOT_RRTYPE_TSIG) { dbg_xfr("xfr: found TSIG in AR\n"); kname = knot_rrset_owner(tsig_rr); + if (tag) { + *tag = knot_dname_to_str(kname); + + } } else { tsig_rr = 0; } @@ -390,8 +459,6 @@ static int xfr_check_tsig(knot_ns_xfr_t *xfr, knot_rcode_t *rcode) dbg_xfr("xfr: TSIG not found in AR\n"); char *name = knot_dname_to_str( knot_zone_name(xfr->zone)); - log_answer_warning("Unauthorized request for XFR '%s/" - "OUT'. (TSIG)\n", name); free(name); // return REFUSED @@ -402,9 +469,10 @@ static int xfr_check_tsig(knot_ns_xfr_t *xfr, knot_rcode_t *rcode) if (tsig_rr) { tsig_algorithm_t alg = tsig_rdata_alg(tsig_rr); if (tsig_alg_digest_length(alg) == 0) { - log_server_info("Unsupported digest algorithm " + log_server_info("%s Unsupported digest algorithm " "requested, treating as " - "bad key.\n"); + "bad key.\n", + xfr->msgpref); *rcode = KNOT_RCODE_NOTAUTH; xfr->tsig_key = NULL; xfr->tsig_rcode = KNOT_TSIG_RCODE_BADKEY; @@ -518,23 +586,10 @@ static int xfr_check_tsig(knot_ns_xfr_t *xfr, knot_rcode_t *rcode) */ int xfr_process_event(xfrworker_t *w, int fd, knot_ns_xfr_t *data, uint8_t *buf, size_t buflen) { - /* Fetch associated zone. */ - const char *zname = "<unknown>"; - knot_zone_t *zone = (knot_zone_t *)data->zone; - if (zone) { - zonedata_t *zd = (zonedata_t *)knot_zone_data(zone); - if (zd) { - zname = zd->conf->name; - } - } - /* Update xfer state. */ + knot_zone_t *zone = (knot_zone_t *)data->zone; data->wire = buf; data->wire_size = buflen; - - char r_addr[SOCKADDR_STRLEN]; - sockaddr_tostr(&data->addr, r_addr, sizeof(r_addr)); - int r_port = sockaddr_portnum(&data->addr); /* Handle SOA/NOTIFY responses. */ if (data->type == XFR_TYPE_NOTIFY || data->type == XFR_TYPE_SOA) { @@ -566,11 +621,10 @@ int xfr_process_event(xfrworker_t *w, int fd, knot_ns_xfr_t *data, uint8_t *buf, /* AXFR-style IXFR. */ if (ret == KNOT_ENOIXFR) { - log_server_notice("IXFR of '%s/IN' with %s:%d - " - "Fallback to AXFR/IN.\n", - zname, r_addr, r_port); assert(data->type == XFR_TYPE_IIN); + log_server_notice("%s Fallback to AXFR/IN.\n", data->msgpref); data->type = XFR_TYPE_AIN; + data->msgpref[0] = 'A'; ret = knot_ns_process_axfrin(w->ns, data); } @@ -585,9 +639,8 @@ int xfr_process_event(xfrworker_t *w, int fd, knot_ns_xfr_t *data, uint8_t *buf, /* IXFR refused, try again with AXFR. */ if (zone && data->type == XFR_TYPE_IIN && ret == KNOT_EXFRREFUSED) { - log_server_notice("IXFR of '%s/IN' with %s:%d failed, attempting " - "to use AXFR/IN instead.\n", - zname, r_addr, r_port); + log_server_notice("%s Transfer failed, fallback to AXFR/IN.\n", + data->msgpref); size_t bufsize = buflen; data->wire_size = buflen; /* Reset maximum bufsize */ ret = xfrin_create_axfr_query(zone->name, data, @@ -599,6 +652,7 @@ int xfr_process_event(xfrworker_t *w, int fd, knot_ns_xfr_t *data, uint8_t *buf, /* Switch to AIN type XFR and return now. */ if (ret == bufsize) { data->type = XFR_TYPE_AIN; + data->msgpref[0] = 'A'; return KNOTD_EOK; } } @@ -606,17 +660,11 @@ int xfr_process_event(xfrworker_t *w, int fd, knot_ns_xfr_t *data, uint8_t *buf, /* Handle errors. */ if (ret == KNOT_ENOXFR) { - log_server_warning("%cXFR request of '%s/IN' with %s:%d " - "finished - %s\n", - data->type == XFR_TYPE_AIN ? 'A' : 'I', - zname, r_addr, r_port, - knot_strerror(ret)); + log_server_warning("%s Finished, %s\n", + data->msgpref, knot_strerror(ret)); } else if (ret < 0) { - log_server_error("%cXFR/IN request of '%s/IN' with %s:%d " - "failed - %s\n", - data->type == XFR_TYPE_AIN ? 'A' : 'I', - zname, r_addr, r_port, - knot_strerror(ret)); + log_server_error("%s %s\n", + data->msgpref, knot_strerror(ret)); } @@ -638,9 +686,9 @@ int xfr_process_event(xfrworker_t *w, int fd, knot_ns_xfr_t *data, uint8_t *buf, int tmr_s = AXFR_BOOTSTRAP_RETRY; tmr_s += (30.0 * 1000) * (tls_rand()); zd->xfr_in.bootstrap_retry = tmr_s; - log_zone_info("Another attempt to AXFR bootstrap " - "zone '%s' in %d seconds.\n", - zname, tmr_s/1000); + log_zone_info("%s Next attempt to bootstrap " + "in %d seconds.\n", + data->msgpref, tmr_s / 1000); } rcu_read_unlock(); @@ -698,18 +746,14 @@ static int xfr_client_start(xfrworker_t *w, knot_ns_xfr_t *data) if (nextw == 0) { nextw = w; } + + /* Free data updated in this processing. */ evqueue_write(nextw->q, data, sizeof(knot_ns_xfr_t)); return KNOTD_EOK; } else { zd->xfr_in.wrkr = w; } - /* Update address. */ - sockaddr_update(&data->addr); - char r_addr[SOCKADDR_STRLEN]; - sockaddr_tostr(&data->addr, r_addr, sizeof(r_addr)); - int r_port = sockaddr_portnum(&data->addr); - /* Connect to remote. */ if (data->session <= 0) { int fd = socket_create(data->addr.family, SOCK_STREAM); @@ -722,21 +766,18 @@ static int xfr_client_start(xfrworker_t *w, knot_ns_xfr_t *data) } } else { pthread_mutex_unlock(&zd->xfr_in.lock); - log_server_warning("Failed to create socket " - "(type=%s, family=%s).\n", - "SOCK_STREAM", - data->addr.family == AF_INET ? - "AF_INET" : "AF_INET6"); + log_server_warning("%s Failed to create socket " + "(type=%s, family=%s).\n", + "SOCK_STREAM", + data->msgpref, + data->addr.family == AF_INET ? + "AF_INET" : "AF_INET6"); return KNOTD_ERROR; } ret = connect(fd, data->addr.ptr, data->addr.len); if (ret < 0) { pthread_mutex_unlock(&zd->xfr_in.lock); - log_server_warning("Failed to connect to %cXFR master " - "at %s:%d.\n", - data->type == XFR_TYPE_AIN ? 'A' : 'I', - r_addr, r_port); if (!knot_zone_contents(zone)) { /* Reschedule request (120 - 240s random delay). */ int tmr_s = AXFR_BOOTSTRAP_RETRY * 2; /* Malus x2 */ @@ -746,9 +787,9 @@ static int xfr_client_start(xfrworker_t *w, knot_ns_xfr_t *data) evsched_cancel(ev->parent, ev); evsched_schedule(ev->parent, ev, tmr_s); } - log_zone_notice("Zone AXFR bootstrap failed, " - "another attempt in %d seconds." - "\n", tmr_s / 1000); + log_zone_notice("%s Bootstrap failed, next " + "attempt in %d seconds.\n", + data->msgpref, tmr_s / 1000); } return KNOTD_ECONNREFUSED; } @@ -766,8 +807,8 @@ static int xfr_client_start(xfrworker_t *w, knot_ns_xfr_t *data) if (!contents && data->type == XFR_TYPE_IIN) { pthread_mutex_unlock(&zd->xfr_in.lock); rcu_read_unlock(); - log_server_warning("Failed start IXFR on zone with no " - "contents\n"); + log_server_warning("%s Refusing to start IXFR/IN on zone with no " + "contents.\n", data->msgpref); return KNOTD_EINVAL; } @@ -806,7 +847,7 @@ static int xfr_client_start(xfrworker_t *w, knot_ns_xfr_t *data) /* Handle errors. */ if (ret != KNOT_EOK) { pthread_mutex_unlock(&zd->xfr_in.lock); - dbg_xfr("xfr: failed to create XFR query type %d: %s\n", + fprintf(stderr, "xfr: failed to create XFR query type %d: %s\n", data->type, knot_strerror(ret)); return KNOTD_ERROR; } @@ -814,24 +855,19 @@ static int xfr_client_start(xfrworker_t *w, knot_ns_xfr_t *data) /* Unlock zone contents. */ rcu_read_unlock(); - /* Add to pending transfers. */ - knot_ns_xfr_t *task = xfr_register_task(w, 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); pthread_mutex_unlock(&zd->xfr_in.lock); - log_server_notice("Failed to send %cXFR query.", - data->type == XFR_TYPE_AIN ? 'A' : 'I'); - xfr_free_task(task); - return KNOTD_ERROR; + return KNOTD_ECONNREFUSED; } + /* Add to pending transfers. */ + knot_ns_xfr_t *task = xfr_register_task(w, data); + /* Send XFR query. */ - log_server_info("%cXFR transfer of zone '%s/IN' with %s:%d started.\n", - data->type == XFR_TYPE_AIN ? 'A' : 'I', - zd->conf->name, - r_addr, r_port); - + log_server_info("%s Started.\n", task->msgpref); return KNOTD_EOK; } @@ -883,12 +919,12 @@ static int xfr_answer_ixfr(knot_nameserver_t *ns, knot_ns_xfr_t *xfr) if (chsload != KNOTD_EOK) { /* History cannot be reconstructed, fallback to AXFR. */ if (chsload == KNOTD_ERANGE || chsload == KNOTD_ENOENT) { - log_server_info("IXFR transfer of zone '%s/OUT'" - " - failed to load data from journal: " + log_server_info("%s Failed to load data from journal: " " Incomplete history. " "Fallback to AXFR.\n", - xfr->zname); + xfr->msgpref); xfr->type = XFR_TYPE_AOUT; + xfr->msgpref[0] = 'A'; return xfr_answer_axfr(ns, xfr); } else if (chsload == KNOTD_EMALF) { xfr->rcode = KNOT_RCODE_FORMERR; @@ -909,6 +945,101 @@ static int xfr_answer_ixfr(knot_nameserver_t *ns, knot_ns_xfr_t *xfr) return ret; } +static int xfr_update_msgpref(knot_ns_xfr_t *req, const char *keytag) +{ + /* Check */ + if (req == NULL) { + 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); + sockaddr_tostr(&req->addr, r_addr, sizeof(r_addr)); + char *tag = NULL; + if (keytag) { + tag = strdup(keytag); + } else if (req->tsig_key) { + tag = knot_dname_to_str(req->tsig_key->name); + } + if (tag) { + /* Allocate: " key '$key' " (7 extra bytes + \0) */ + size_t dnlen = strlen(tag); + r_key = malloc(dnlen + 7 + 1); + if (r_key) { + char *kp = r_key; + memcpy(kp, " key '", 6); kp += 6; + /* Trim trailing '.' */ + memcpy(kp, tag, dnlen); kp += dnlen - 1; + memcpy(kp, "'", 2); /* 1 + '\0' */ + } + free(tag); + tag = NULL; + } + + /* Prepare log message. */ + conf_read_lock(); + const char *zname = req->zname; + if (zname == NULL && req->zone != NULL) { + zonedata_t *zd = (zonedata_t *)knot_zone_data(req->zone); + if (zd == NULL) { + free(r_key); + return KNOTD_EINVAL; + } else { + zname = zd->conf->name; + } + } + const char *pformat = NULL; + switch (req->type) { + case XFR_TYPE_AIN: + pformat = "AXFR transfer of '%s/IN' with %s:%d%s:"; + break; + case XFR_TYPE_IIN: + pformat = "IXFR transfer of '%s/IN' with %s:%d%s:"; + break; + case XFR_TYPE_AOUT: + pformat = "AXFR transfer of '%s/OUT' to %s:%d%s:"; + break; + case XFR_TYPE_IOUT: + pformat = "IXFR transfer of '%s/OUT' to %s:%d%s:"; + break; + case XFR_TYPE_NOTIFY: + pformat = "NOTIFY query of '%s' to %s:%d%s:"; + break; + case XFR_TYPE_SOA: + pformat = "SOA query of '%s' to %s:%d%s:"; + break; + default: + pformat = ""; + break; + } + + int len = 512; + char *msg = malloc(len + 1); + if (msg) { + memset(msg, 0, len + 1); + len = snprintf(msg, len + 1, pformat, zname, r_addr, r_port, + r_key ? r_key : ""); + /* Shorten as some implementations (<C99) don't allow + * printing to NULL to estimate size. */ + if (len > 0) { + msg = realloc(msg, len + 1); + } + + req->msgpref = msg; + } + + conf_read_unlock(); + free(r_key); + return KNOTD_EOK; +} + /* * Public APIs. */ @@ -1094,7 +1225,7 @@ int xfr_request(xfrhandler_t *handler, knot_ns_xfr_t *req) evqueue_t *q = handler->workers[handler->rr]->q; handler->rr = get_next_rr(handler->rr, handler->unit->size); pthread_mutex_unlock(&handler->rr_mx); - + /* Delegate request. */ int ret = evqueue_write(q, req, sizeof(knot_ns_xfr_t)); if (ret < 0) { @@ -1113,6 +1244,16 @@ int xfr_answer(knot_nameserver_t *ns, knot_ns_xfr_t *xfr) int ret = knot_ns_init_xfr(ns, xfr); int xfr_failed = (ret != KNOT_EOK); const char * errstr = knot_strerror(ret); + + // use the QNAME as the zone name to get names also for + // zones that are not in the server + /*! \todo Update msgpref with zname from query. */ + const knot_dname_t *qname = knot_packet_qname(xfr->query); + if (qname != NULL) { + xfr->zname = knot_dname_to_str(qname); + } else { + xfr->zname = strdup("(unknown)"); + } /* Check requested zone. */ if (!xfr_failed) { @@ -1122,12 +1263,19 @@ int xfr_answer(knot_nameserver_t *ns, knot_ns_xfr_t *xfr) } /* Check TSIG. */ + char *keytag = NULL; if (!xfr_failed && xfr->tsig_key != NULL) { - ret = xfr_check_tsig(xfr, &xfr->rcode); + ret = xfr_check_tsig(xfr, &xfr->rcode, &keytag); xfr_failed = (ret != KNOT_EOK); errstr = knot_strerror(ret); } + ret = xfr_update_msgpref(xfr, keytag); + free(keytag); + if (ret != KNOTD_EOK) { + xfr->msgpref = strdup("XFR:"); + } + /* Prepare place for TSIG data */ xfr->tsig_data = malloc(KNOT_NS_TSIG_DATA_MAX_SIZE); if (xfr->tsig_data) { @@ -1140,15 +1288,6 @@ int xfr_answer(knot_nameserver_t *ns, knot_ns_xfr_t *xfr) KNOT_NS_TSIG_DATA_MAX_SIZE / 1024); } - // use the QNAME as the zone name to get names also for - // zones that are not in the server - const knot_dname_t *qname = knot_packet_qname(xfr->query); - if (qname != NULL) { - xfr->zname = knot_dname_to_str(qname); - } else { - xfr->zname = strdup("(unknown)"); - } - /* Finally, answer AXFR/IXFR. */ int io_error = 0; if (!xfr_failed) { @@ -1167,33 +1306,22 @@ int xfr_answer(knot_nameserver_t *ns, knot_ns_xfr_t *xfr) io_error = (ret == KNOT_ECONN); } - /* Remote address identification. */ - char r_addr[SOCKADDR_STRLEN]; - sockaddr_tostr(&xfr->addr, r_addr, sizeof(r_addr)); - int r_port = sockaddr_portnum(&xfr->addr); - /* Check results. */ if (xfr_failed) { if (!io_error) { knot_ns_xfr_send_error(ns, xfr, xfr->rcode); } - log_server_notice("%cXFR transfer of zone '%s/OUT' " - "%s:%d failed: %s\n", - xfr_strtype(xfr) , xfr->zname, - r_addr, r_port, - errstr); + log_server_notice("%s %s\n", xfr->msgpref, errstr); ret = KNOTD_ERROR; } else { - log_server_info("%cXFR transfer of zone '%s/OUT' " - "to %s:%d successful.\n", - xfr_strtype(xfr), xfr->zname, - r_addr, r_port); + log_server_info("%s Finished.\n", xfr->msgpref); ret = KNOTD_EOK; } /* Free allocated data. */ free(xfr->tsig_data); xfr->tsig_data = NULL; + xfr_request_deinit(xfr); /* Cleanup. */ free(xfr->digest); @@ -1214,14 +1342,13 @@ static int xfr_process_request(xfrworker_t *w, uint8_t *buf, size_t buflen) dbg_xfr_verb("xfr: evqueue_read() returned %d.\n", ret); return KNOTD_ENOTRUNNING; } - + /* Update request. */ - sockaddr_update(&xfr.addr); xfr.wire = buf; xfr.wire_size = buflen; - char r_addr[SOCKADDR_STRLEN]; - sockaddr_tostr(&xfr.addr, r_addr, sizeof(r_addr)); - int r_port = sockaddr_portnum(&xfr.addr); + + /* Update XFR message prefix. */ + xfr_update_msgpref(&xfr, NULL); conf_read_lock(); @@ -1230,27 +1357,21 @@ static int xfr_process_request(xfrworker_t *w, uint8_t *buf, size_t buflen) if(xfr.zone != NULL) { zd = (zonedata_t *)knot_zone_data(xfr.zone); } - knot_ns_xfr_t *task = 0; - evsched_t *sch = 0; - const char *req_type = ""; + 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); switch(xfr.type) { case XFR_TYPE_AIN: case XFR_TYPE_IIN: - if (xfr.type == XFR_TYPE_IIN) { - req_type = "IXFR/IN"; - } else { - req_type = "AXFR/IN"; - } ret = xfr_client_start(w, &xfr); /* Report. */ if (ret != KNOTD_EOK && ret != KNOTD_EACCES) { - log_server_error("%s request from %s:%d failed: %s\n", - req_type, r_addr, r_port, - knotd_strerror(ret)); + log_server_error("%s %s\n", + xfr.msgpref, knotd_strerror(ret)); } + break; case XFR_TYPE_SOA: case XFR_TYPE_NOTIFY: @@ -1260,11 +1381,7 @@ static int xfr_process_request(xfrworker_t *w, uint8_t *buf, size_t buflen) ret = KNOTD_ENOMEM; break; } - - req_type = "SOA or NOTIFY"; - dbg_xfr("xfr: waiting for %s query response\n", - xfr.type == XFR_TYPE_SOA ? "SOA" : "NOTIFY"); - + /* Add timeout. */ sch = ((server_t *)knot_ns_get_data(w->ns))->sched; task->data = evsched_schedule_cb(sch, xfr_udp_timeout, @@ -1272,6 +1389,7 @@ static int xfr_process_request(xfrworker_t *w, uint8_t *buf, size_t buflen) if (zd && xfr.type == XFR_TYPE_SOA) { zd->soa_pending = (event_t*)task->data; } + log_server_info("%s Query issued.\n", xfr.msgpref); ret = KNOTD_EOK; break; /* Socket close event. */ @@ -1286,6 +1404,11 @@ static int xfr_process_request(xfrworker_t *w, uint8_t *buf, size_t buflen) conf_read_unlock(); + /* Deinitialize (it is already registered, or discarded). + * Right now, this only frees temporary msgpref. + */ + xfr_request_deinit(&xfr); + return ret; } @@ -1350,6 +1473,20 @@ int xfr_worker(dthread_t *thread) pthread_mutex_lock(&h->tasks_mx); data = skip_find(h->tasks, (void*)((size_t)it.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, 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; + } else { + continue; + } + } dbg_xfr_verb("xfr: worker=%p processing event on " "fd=%d data=%p.\n", w, it.fd, data); diff --git a/src/knot/server/zones.c b/src/knot/server/zones.c index a196462..dbc1340 100644 --- a/src/knot/server/zones.c +++ b/src/knot/server/zones.c @@ -15,6 +15,7 @@ */ #include <sys/stat.h> +#include <unistd.h> #include "common/lists.h" #include "common/prng.h" @@ -42,6 +43,9 @@ static const size_t XFRIN_CHANGESET_BINARY_SIZE = 100; static const size_t XFRIN_CHANGESET_BINARY_STEP = 100; +/* Forward declarations. */ +static int zones_dump_zone_text(knot_zone_contents_t *zone, const char *zf); + /*----------------------------------------------------------------------------*/ /*! @@ -111,7 +115,7 @@ static int zonedata_destroy(knot_zone_t *zone) acl_delete(&zd->notify_out); /* Close IXFR db. */ - journal_close(zd->ixfr_db); + journal_release(zd->ixfr_db); free(zd); @@ -161,7 +165,7 @@ static int zonedata_init(conf_zone_t *cfg, knot_zone_t *zone) /* Initialize IXFR database. */ zd->ixfr_db = journal_open(cfg->ixfr_db, cfg->ixfr_fslimit, - JOURNAL_DIRTY); + JOURNAL_LAZY, JOURNAL_DIRTY); if (!zd->ixfr_db) { int ret = journal_create(cfg->ixfr_db, JOURNAL_NCOUNT); if (ret != KNOTD_EOK) { @@ -169,7 +173,7 @@ static int zonedata_init(conf_zone_t *cfg, knot_zone_t *zone) "'%s'\n", cfg->ixfr_db); } zd->ixfr_db = journal_open(cfg->ixfr_db, cfg->ixfr_fslimit, - JOURNAL_DIRTY); + JOURNAL_LAZY, JOURNAL_DIRTY); } if (zd->ixfr_db == 0) { @@ -194,6 +198,7 @@ static int zonedata_init(conf_zone_t *cfg, knot_zone_t *zone) if (contents) { soa_rrs = knot_node_rrset(knot_zone_contents_apex(contents), KNOT_RRTYPE_SOA); + assert(soa_rrs != NULL); soa_rr = knot_rrset_rdata(soa_rrs); int64_t serial = knot_rdata_soa_serial(soa_rr); zd->zonefile_serial = (uint32_t)serial; @@ -232,6 +237,7 @@ static uint32_t zones_soa_timer(knot_zone_t *zone, soa_rrs = knot_node_rrset(knot_zone_contents_apex(zc), KNOT_RRTYPE_SOA); + assert(soa_rrs != NULL); soa_rr = knot_rrset_rdata(soa_rrs); ret = rr_func(soa_rr); @@ -542,7 +548,7 @@ static int zones_notify_send(event_t *e) /* Check number of retries. */ if (ev->retries < 0) { log_server_notice("NOTIFY query maximum number of retries " - "for zone %s exceeded.\n", + "for zone '%s' exceeded.\n", zd->conf->name); pthread_mutex_lock(&zd->lock); rem_node(&ev->n); @@ -593,14 +599,7 @@ static int zones_notify_send(event_t *e) /* Store ID of the awaited response. */ if (ret == buflen) { - char r_addr[SOCKADDR_STRLEN]; - sockaddr_tostr(&ev->addr, r_addr, sizeof(r_addr)); - int r_port = sockaddr_portnum(&ev->addr); ev->msgid = knot_wire_get_id(qbuf); - log_server_info("Issued '%s' NOTIFY query to %s:%d, " - "expecting response ID=%d\n", - zd->conf->name, r_addr, r_port, - ev->msgid); } @@ -611,6 +610,7 @@ static int zones_notify_send(event_t *e) req.type = XFR_TYPE_NOTIFY; 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 */ @@ -656,7 +656,9 @@ static int zones_zonefile_sync_ev(event_t *e) } /* Execute zonefile sync. */ - int ret = zones_zonefile_sync(zone); + journal_t *j = journal_retain(zd->ixfr_db); + int ret = zones_zonefile_sync(zone, j); + journal_release(j); if (ret == KNOTD_EOK) { log_zone_info("Applied differences of '%s' to zonefile.\n", zd->conf->name); @@ -710,11 +712,20 @@ static int zones_set_acl(acl_t **acl, list* acl_list) sockaddr_t addr; conf_iface_t *cfg_if = r->remote; int ret = sockaddr_set(&addr, cfg_if->family, - cfg_if->address, 0); + cfg_if->address, 0); + sockaddr_setprefix(&addr, cfg_if->prefix); /* Load rule. */ if (ret > 0) { - acl_create(*acl, &addr, ACL_ACCEPT, cfg_if); + /*! \todo Correct search for the longest prefix match. + * This just favorizes remotes with TSIG. + * (issue #1675) + */ + unsigned flags = 0; + if (cfg_if->key != NULL) { + flags = ACL_PREFER; + } + acl_create(*acl, &addr, ACL_ACCEPT, cfg_if, flags); } } @@ -1040,18 +1051,22 @@ static int zones_load_changesets(const knot_zone_t *zone, dbg_zones_detail("Bad arguments: zd->ixfr_db=%p\n", zone->data); return KNOTD_EINVAL; } + + /* Retain journal for changeset loading. */ + journal_t *j = journal_retain(zd->ixfr_db); /* Read entries from starting serial until finished. */ uint32_t found_to = from; journal_node_t *n = 0; - int ret = journal_fetch(zd->ixfr_db, from, ixfrdb_key_from_cmp, &n); + int ret = journal_fetch(j, from, ixfrdb_key_from_cmp, &n); if (ret != KNOTD_EOK) { dbg_xfr("xfr: failed to fetch starting changeset: %s\n", knotd_strerror(ret)); + journal_release(j); return ret; } - while (n != 0 && n != journal_end(zd->ixfr_db)) { + while (n != 0 && n != journal_end(j)) { /* Check for history end. */ if (to == found_to) { @@ -1068,6 +1083,7 @@ static int zones_load_changesets(const knot_zone_t *zone, --dst->count; dbg_xfr("xfr: failed to check changesets size: %s\n", knot_strerror(ret)); + journal_release(j); return KNOTD_ERROR; } @@ -1079,15 +1095,16 @@ static int zones_load_changesets(const knot_zone_t *zone, chs->serial_to = ixfrdb_key_to(n->id); chs->data = malloc(n->len); if (!chs->data) { + journal_release(j); return KNOTD_ENOMEM; } /* Read journal entry. */ - ret = journal_read(zd->ixfr_db, n->id, - 0, (char*)chs->data); + ret = journal_read(j, n->id, 0, (char*)chs->data); if (ret != KNOTD_EOK) { dbg_xfr("xfr: failed to read data from journal\n"); free(chs->data); + journal_release(j); return KNOTD_ERROR; } @@ -1103,6 +1120,7 @@ static int zones_load_changesets(const knot_zone_t *zone, } dbg_xfr_detail("xfr: Journal entries read.\n"); + journal_release(j); /* Unpack binary data. */ int unpack_ret = zones_changesets_from_binary(dst); @@ -1153,6 +1171,7 @@ static int zones_journal_apply(knot_zone_t *zone) const knot_rdata_t *soa_rr = 0; soa_rrs = knot_node_rrset(knot_zone_contents_apex(contents), KNOT_RRTYPE_SOA); + assert(soa_rrs != NULL); soa_rr = knot_rrset_rdata(soa_rrs); int64_t serial_ret = knot_rdata_soa_serial(soa_rr); if (serial_ret < 0) { @@ -1173,13 +1192,39 @@ static int zones_journal_apply(knot_zone_t *zone) log_server_info("Applying '%zu' changesets from journal " "to zone '%s'.\n", chsets->count, zd->conf->name); - int apply_ret = xfrin_apply_changesets(zone, chsets); + knot_zone_contents_t *contents = NULL; + int apply_ret = xfrin_apply_changesets(zone, chsets, + &contents); if (apply_ret != KNOT_EOK) { - log_server_error("Failed to apply changesets to " - "'%s' - %s\n", + log_server_error("Failed to apply changesets to" + "'%s' - Apply failed: %s\n", zd->conf->name, knot_strerror(apply_ret)); ret = KNOTD_ERROR; + + // Cleanup old and new contents + xfrin_rollback_update(zone->contents, + &contents, + &chsets->changes); + } + + /* Switch zone immediately. */ + apply_ret = xfrin_switch_zone(zone, contents, + XFR_TYPE_IIN); + if (apply_ret == KNOT_EOK) { + xfrin_cleanup_successful_update( + &chsets->changes); + } else { + log_server_error("Failed to apply changesets to" + " '%s' - Switch failed: %s\n", + zd->conf->name, + knot_strerror(apply_ret)); + ret = KNOTD_ERROR; + + // Cleanup old and new contents + xfrin_rollback_update(zone->contents, + &contents, + &chsets->changes); } } } else { @@ -1238,9 +1283,9 @@ static int zones_insert_zones(knot_nameserver_t *ns, int reload = 0; /* Attempt to bootstrap if db or source does not exist. */ - struct stat s; + struct stat s = {}; int stat_ret = stat(z->file, &s); - if (zone != NULL) { + if (zone != NULL && stat_ret == 0) { /* if found, check timestamp of the file against the * loaded zone */ @@ -1325,8 +1370,11 @@ static int zones_insert_zones(knot_nameserver_t *ns, dbg_zones_verb("zones: found '%s' in old database, " "copying to new.\n", z->name); - log_server_info("Zone '%s' is up-to-date, no need " - "for reload.\n", z->name); + /* Only if zone file exists. */ + if (stat_ret == 0) { + log_server_info("Zone '%s' is up-to-date, no need " + "for reload.\n", z->name); + } int ret = knot_zonedb_add_zone(db_new, zone); if (ret != KNOT_EOK) { log_server_error("Error adding known zone '%s' to" @@ -1691,7 +1739,7 @@ int zones_update_db_from_config(const conf_t *conf, knot_nameserver_t *ns, return KNOTD_EOK; } -int zones_zonefile_sync(knot_zone_t *zone) +int zones_zonefile_sync(knot_zone_t *zone, journal_t *journal) { if (!zone) { return KNOTD_EINVAL; @@ -1718,6 +1766,8 @@ int zones_zonefile_sync(knot_zone_t *zone) const knot_rdata_t *soa_rr = 0; soa_rrs = knot_node_rrset(knot_zone_contents_apex(contents), KNOT_RRTYPE_SOA); + assert(soa_rrs != NULL); + soa_rr = knot_rrset_rdata(soa_rrs); int64_t serial_ret = knot_rdata_soa_serial(soa_rr); if (serial_ret < 0) { @@ -1734,14 +1784,21 @@ int zones_zonefile_sync(knot_zone_t *zone) dbg_zones("zones: syncing '%s' differences to '%s' " "(SOA serial %u)\n", zd->conf->name, zd->conf->file, serial_to); - zone_dump_text(contents, zd->conf->file); + ret = zones_dump_zone_text(contents, zd->conf->file); + if (ret != KNOTD_EOK) { + dbg_zones("zones: failed to sync '%s' to '%s'\n", + zd->conf->name, zd->conf->file); + pthread_mutex_unlock(&zd->lock); + return ret; + } + conf_read_unlock(); /* Update journal entries. */ dbg_zones_verb("zones: unmarking all dirty nodes " "in '%s' journal\n", zd->conf->name); - journal_walk(zd->ixfr_db, zones_ixfrdb_sync_apply); + journal_walk(journal, zones_ixfrdb_sync_apply); /* Update zone file serial. */ dbg_zones("zones: new '%s' zonefile serial is %u\n", @@ -1766,7 +1823,10 @@ int zones_query_check_zone(const knot_zone_t *zone, const sockaddr_t *addr, { if (addr == NULL || tsig_key == NULL || rcode == NULL) { dbg_zones_verb("Wrong arguments.\n"); - *rcode = KNOT_RCODE_SERVFAIL; + + if (rcode != NULL) { + *rcode = KNOT_RCODE_SERVFAIL; + } return KNOTD_EINVAL; } @@ -2107,7 +2167,8 @@ int zones_process_response(knot_nameserver_t *nameserver, /* Check SOA SERIAL. */ int ret = xfrin_transfer_needed(contents, packet); - dbg_zones_verb("xfrin_transfer_needed() returned %d\n", ret); + dbg_zones_verb("xfrin_transfer_needed() returned %s\n", + knot_strerror(ret)); if (ret < 0) { /* RETRY/EXPIRE timers running, do not interfere. */ rcu_read_unlock(); @@ -2118,8 +2179,12 @@ int zones_process_response(knot_nameserver_t *nameserver, evsched_t *sched = ((server_t *)knot_ns_get_data(nameserver))->sched; if (ret == 0) { - log_zone_info("SOA query for zone '%s' answered, no " - "transfer needed.\n", zd->conf->name); + char r_addr[SOCKADDR_STRLEN]; + int r_port = sockaddr_portnum(from); + sockaddr_tostr(from, r_addr, sizeof(r_addr)); + log_zone_info("SOA query of '%s' to %s:%d: Answered, no " + "transfer needed.\n", + zd->conf->name, r_addr, r_port); rcu_read_unlock(); /* Reinstall timers. */ @@ -2217,136 +2282,171 @@ static int zones_find_zone_for_xfr(const knot_zone_contents_t *zone, /*----------------------------------------------------------------------------*/ -static char *zones_find_free_filename(const char *old_name) +static int zones_open_free_filename(const char *old_name, char **new_name) { /* find zone name not present on the disk */ - int free_name = 0; size_t name_size = strlen(old_name); - - char *new_name = malloc(name_size + 3); - if (new_name == NULL) { - return NULL; - } - memcpy(new_name, old_name, name_size); - new_name[name_size] = '.'; - new_name[name_size + 2] = 0; - - dbg_zones_verb("zones: finding free name for the zone file.\n"); - int c = 48; - FILE *file; - while (!free_name && c < 58) { - new_name[name_size + 1] = c; - dbg_zones_verb("zones: trying file name %s\n", new_name); - if ((file = fopen(new_name, "r")) != NULL) { - fclose(file); - ++c; - } else { - free_name = 1; - } - } - - if (free_name) { - return new_name; - } else { - free(new_name); - return NULL; + *new_name = malloc(name_size + 7 + 1); + if (*new_name == NULL) { + return -1; + } + memcpy(*new_name, old_name, name_size + 1); + strncat(*new_name, ".XXXXXX", 7); + dbg_zones_verb("zones: creating temporary zone file\n"); + mode_t old_mode = umask(077); + int fd = mkstemp(*new_name); + (void) umask(old_mode); + if (fd < 0) { + dbg_zones_verb("zones: couldn't create temporary zone file\n"); + free(*new_name); + *new_name = NULL; } + + return fd; } /*----------------------------------------------------------------------------*/ -static int zones_dump_xfr_zone_text(knot_zone_contents_t *zone, - const char *zonefile) +static int zones_dump_zone_text(knot_zone_contents_t *zone, const char *fname) { - assert(zone != NULL && zonefile != NULL); - - /*! \todo new_zonefile may be created by another process, - * until the zone_dump_text is called. Needs to be opened in - * this function for writing. - * Use open() for exclusive open and fcntl() for locking. - * (issue #1587) - */ - - char *new_zonefile = zones_find_free_filename(zonefile); + assert(zone != NULL && fname != NULL); - if (new_zonefile == NULL) { + char *new_fname = NULL; + int fd = zones_open_free_filename(fname, &new_fname); + if (fd < 0) { log_zone_warning("Failed to find filename for temporary " "storage of the transferred zone.\n"); - return KNOTD_ERROR; /*! \todo New error code? */ + return KNOTD_ERROR; } - - int rc = zone_dump_text(zone, new_zonefile); - - if (rc != KNOTD_EOK) { + + if (zone_dump_text(zone, fd) != KNOTD_EOK) { log_zone_warning("Failed to save the transferred zone to '%s'.\n", - new_zonefile); - free(new_zonefile); + new_fname); + close(fd); + unlink(new_fname); + free(new_fname); return KNOTD_ERROR; } - /*! \todo this would also need locking as well (issue #1587) */ - remove(zonefile); /* Don't care, as the rename will trigger the error. */ - if (rename(new_zonefile, zonefile) != 0) { + /* Swap temporary zonefile and new zonefile. */ + close(fd); + int ret = rename(new_fname, fname); + if (ret < 0 && ret != EEXIST) { log_zone_warning("Failed to replace old zone file '%s'' with a new" - " zone file '%s'.\n", zonefile, new_zonefile); - /*! \todo with proper locking, this shouldn't happen, - * revise it later on (issue #1587) - */ - zone_dump_text(zone, zonefile); - free(new_zonefile); + " zone file '%s'.\n", fname, new_fname); + unlink(new_fname); + free(new_fname); return KNOTD_ERROR; } - free(new_zonefile); + free(new_fname); return KNOTD_EOK; } /*----------------------------------------------------------------------------*/ -static int ns_dump_xfr_zone_binary(knot_zone_contents_t *zone, +static int zones_dump_zone_binary(knot_zone_contents_t *zone, const char *zonedb, const char *zonefile) { assert(zone != NULL && zonedb != NULL); - /*! \todo new_zonedb may be created by another process, - * until the zone_dump_text is called. Needs to be opened in - * this function for writing. - * Use open() for exclusive open and fcntl() for locking. - * (issue #1587) - */ - char *new_zonedb = zones_find_free_filename(zonedb); - - if (new_zonedb == NULL) { + char *new_zonedb = NULL; + int fd = zones_open_free_filename(zonedb, &new_zonedb); + if (fd < 0) { dbg_zones("zones: failed to find free filename for temporary " "storage of the zone binary file '%s'\n", zonedb); - return KNOTD_ERROR; /*! \todo New error code? */ + return KNOTD_ERROR; } - /*! \todo this would also need locking as well (issue #1587) */ - int rc = knot_zdump_dump_and_swap(zone, new_zonedb, zonedb, zonefile); - free(new_zonedb); + crc_t crc_value; + if (knot_zdump_dump(zone, fd, zonefile, &crc_value) != KNOT_EOK) { + close(fd); + unlink(new_zonedb); + free(new_zonedb); + return KNOTD_ERROR; + } - if (rc != KNOT_EOK) { + /* Delete old CRC file. */ + char *zonedb_crc = knot_zdump_crc_file(zonedb); + if (zonedb_crc == NULL) { + close(fd); + unlink(new_zonedb); + free(new_zonedb); + return KNOTD_ENOMEM; + } + remove(zonedb_crc); + + /* New CRC file. */ + char *new_zonedb_crc = knot_zdump_crc_file(new_zonedb); + if (new_zonedb_crc == NULL) { + dbg_zdump("Failed to create CRC file path from %s.\n", + new_zonedb); + free(zonedb_crc); + close(fd); + unlink(new_zonedb); + free(new_zonedb); + return KNOTD_ENOMEM; + } + + /* Write CRC value to CRC file. */ + FILE *f_crc = fopen(new_zonedb_crc, "w"); + if (f_crc == NULL) { + dbg_zdump("Cannot open CRC file %s!\n", + zonedb_crc); + unlink(new_zonedb); return KNOTD_ERROR; + } else { + fprintf(f_crc, "%lu\n", + (unsigned long)crc_value); + fclose(f_crc); } + /* Swap CRC files. */ + int ret = KNOTD_EOK; + if (rename(new_zonedb_crc, zonedb_crc) < 0) { + dbg_zdump("Failed to replace old zonedb CRC %s " + "with new CRC zone file %s.\n", + zonedb_crc, + new_zonedb_crc); + unlink(new_zonedb); + unlink(new_zonedb_crc); + ret = KNOTD_ERROR; + } else { + /* Swap zone databases. */ + int swap_res = rename(new_zonedb, zonedb); + if (swap_res < 0 && swap_res != EEXIST) { + dbg_zdump("Failed to replace old zonedb %s " + "with new zone file %s.\n", + new_zonedb, + zonedb); + ret = KNOTD_ERROR; + unlink(new_zonedb); + } else { - return KNOTD_EOK; + } + } + + free(new_zonedb_crc); + free(zonedb_crc); + close(fd); + free(new_zonedb); + + + return ret; } /*----------------------------------------------------------------------------*/ int zones_save_zone(const knot_ns_xfr_t *xfr) { - if (xfr == NULL || xfr->data == NULL) { + if (xfr == NULL || xfr->new_contents == NULL) { return KNOTD_EINVAL; } - knot_zone_contents_t *zone = - (knot_zone_contents_t *)xfr->data; + knot_zone_contents_t *zone = xfr->new_contents; const char *zonefile = NULL; const char *zonedb = NULL; @@ -2359,12 +2459,12 @@ int zones_save_zone(const knot_ns_xfr_t *xfr) assert(zonefile != NULL && zonedb != NULL); /* dump the zone into text zone file */ - ret = zones_dump_xfr_zone_text(zone, zonefile); + ret = zones_dump_zone_text(zone, zonefile); if (ret != KNOTD_EOK) { return KNOTD_ERROR; } /* dump the zone into binary db file */ - ret = ns_dump_xfr_zone_binary(zone, zonedb, zonefile); + ret = zones_dump_zone_binary(zone, zonedb, zonefile); if (ret != KNOTD_EOK) { return KNOTD_ERROR; } @@ -2447,13 +2547,15 @@ static int zones_changeset_rrset_to_binary(uint8_t **data, size_t *size, size_t actual_size = 0; int ret = knot_zdump_rrset_serialize(rrset, &binary, &actual_size); if (ret != KNOT_EOK || binary == NULL) { + dbg_zones("knot_zdump_rrset_serialize() returned %s\n", + knot_strerror(ret)); return KNOTD_ERROR; /*! \todo Other code? */ } ret = zones_check_binary_size(data, allocated, *size + actual_size); - if (ret != KNOT_EOK) { + if (ret != KNOTD_EOK) { free(binary); - return KNOTD_ERROR; + return ret; } memcpy(*data + *size, binary, actual_size); @@ -2465,7 +2567,7 @@ static int zones_changeset_rrset_to_binary(uint8_t **data, size_t *size, /*----------------------------------------------------------------------------*/ -static int zones_changesets_to_binary(knot_changesets_t *chgsets) +int zones_changesets_to_binary(knot_changesets_t *chgsets) { assert(chgsets != NULL); assert(chgsets->allocated >= chgsets->count); @@ -2484,12 +2586,12 @@ static int zones_changesets_to_binary(knot_changesets_t *chgsets) /* 1) origin SOA */ ret = zones_changeset_rrset_to_binary(&ch->data, &ch->size, &ch->allocated, ch->soa_from); - if (ret != KNOT_EOK) { + if (ret != KNOTD_EOK) { free(ch->data); ch->data = NULL; dbg_zones("zones_changeset_rrset_to_binary(): %s\n", knot_strerror(ret)); - return KNOTD_ERROR; + return ret; } int j; @@ -2501,24 +2603,24 @@ static int zones_changesets_to_binary(knot_changesets_t *chgsets) &ch->size, &ch->allocated, ch->remove[j]); - if (ret != KNOT_EOK) { + if (ret != KNOTD_EOK) { free(ch->data); ch->data = NULL; dbg_zones("zones_changeset_rrset_to_binary(): %s\n", knot_strerror(ret)); - return KNOTD_ERROR; + return ret; } } /* 3) new SOA */ ret = zones_changeset_rrset_to_binary(&ch->data, &ch->size, &ch->allocated, ch->soa_to); - if (ret != KNOT_EOK) { + if (ret != KNOTD_EOK) { free(ch->data); ch->data = NULL; dbg_zones("zones_changeset_rrset_to_binary(): %s\n", knot_strerror(ret)); - return KNOTD_ERROR; + return ret; } /* 4) add RRsets */ @@ -2528,12 +2630,12 @@ static int zones_changesets_to_binary(knot_changesets_t *chgsets) &ch->size, &ch->allocated, ch->add[j]); - if (ret != KNOT_EOK) { + if (ret != KNOTD_EOK) { free(ch->data); ch->data = NULL; dbg_zones("zones_changeset_rrset_to_binary(): %s\n", knot_strerror(ret)); - return KNOTD_ERROR; + return ret; } } } @@ -2551,11 +2653,6 @@ int zones_store_changesets(knot_ns_xfr_t *xfr) knot_zone_t *zone = xfr->zone; knot_changesets_t *src = (knot_changesets_t *)xfr->data; - - int ret = zones_changesets_to_binary(src); - if (ret != KNOTD_EOK) { - return ret; - } /* Fetch zone-specific data. */ zonedata_t *zd = (zonedata_t *)zone->data; @@ -2563,6 +2660,9 @@ int zones_store_changesets(knot_ns_xfr_t *xfr) return KNOTD_EINVAL; } + /* Retain journal for changeset loading. */ + journal_t *j = journal_retain(zd->ixfr_db); + /* Begin writing to journal. */ for (unsigned i = 0; i < src->count; ++i) { @@ -2571,8 +2671,7 @@ int zones_store_changesets(knot_ns_xfr_t *xfr) uint64_t k = ixfrdb_key_make(chs->serial_from, chs->serial_to); /* Write entry. */ - int ret = journal_write(zd->ixfr_db, k, (const char*)chs->data, - chs->size); + int ret = journal_write(j, k, (const char*)chs->data, chs->size); /* Check for errors. */ while (ret != KNOTD_EOK) { @@ -2593,7 +2692,7 @@ int zones_store_changesets(knot_ns_xfr_t *xfr) dbg_xfr_verb("xfr: forcing zonefile SYNC " "of '%s'\n", zd->conf->name); - ret = zones_zonefile_sync(zone); + ret = zones_zonefile_sync(zone, j); if (ret != KNOTD_EOK && ret != KNOTD_ERANGE) { continue; } @@ -2616,11 +2715,11 @@ int zones_store_changesets(knot_ns_xfr_t *xfr) } /* Attempt to write again. */ - ret = journal_write(zd->ixfr_db, k, - (const char*)chs->data, + ret = journal_write(j, k, (const char*)chs->data, chs->size); } else { /* Other errors. */ + journal_release(j); return KNOTD_ERROR; } } @@ -2630,6 +2729,9 @@ int zones_store_changesets(knot_ns_xfr_t *xfr) chs->data = 0; chs->size = 0; } + + /* Release journal. */ + journal_release(j); /* Written changesets to journal. */ return KNOTD_EOK; @@ -2676,18 +2778,6 @@ int zones_xfr_load_changesets(knot_ns_xfr_t *xfr, uint32_t serial_from, /*----------------------------------------------------------------------------*/ -int zones_apply_changesets(knot_ns_xfr_t *xfr) -{ - if (xfr == NULL || xfr->zone == NULL || xfr->data == NULL) { - return KNOT_EBADARG; - } - - return xfrin_apply_changesets(xfr->zone, - (knot_changesets_t *)xfr->data); -} - -/*----------------------------------------------------------------------------*/ - int zones_timers_update(knot_zone_t *zone, conf_zone_t *cfzone, evsched_t *sch) { if (!sch || !zone) { diff --git a/src/knot/server/zones.h b/src/knot/server/zones.h index 53c5290..1822b84 100644 --- a/src/knot/server/zones.h +++ b/src/knot/server/zones.h @@ -73,9 +73,9 @@ typedef struct zonedata_t knot_key_t tsig_key; /*!< Master TSIG key. */ struct event_t *timer; /*!< Timer for REFRESH/RETRY. */ struct event_t *expire; /*!< Timer for REFRESH. */ - int next_id; /*!< ID of the next awaited SOA resp.*/ pthread_mutex_t lock; /*!< Pending XFR/IN lock. */ void *wrkr; /*!< Pending XFR/IN worker. */ + int next_id; /*!< ID of the next awaited SOA resp.*/ uint32_t bootstrap_retry;/*!< AXFR/IN bootstrap retry. */ } xfr_in; @@ -125,13 +125,14 @@ int zones_update_db_from_config(const conf_t *conf, knot_nameserver_t *ns, * \note Current implementation rewrites the zone file. * * \param zone Evaluated zone. + * \param journal Journal to sync. * * \retval KNOTD_EOK if successful. * \retval KNOTD_ERANGE if zonefile is in sync with journal. * \retval KNOTD_EINVAL on invalid parameter. * \retval KNOTD_ERROR on unspecified error during processing. */ -int zones_zonefile_sync(knot_zone_t *zone); +int zones_zonefile_sync(knot_zone_t *zone, journal_t *journal); /*! * \todo Document me. @@ -213,6 +214,8 @@ int zones_ns_conf_hook(const struct conf_t *conf, void *data); */ int zones_store_changesets(knot_ns_xfr_t *xfr); +int zones_changesets_to_binary(knot_changesets_t *chgsets); + /*! * \brief Load changesets from journal. * @@ -237,20 +240,6 @@ int zones_xfr_load_changesets(knot_ns_xfr_t *xfr, uint32_t serial_from, uint32_t serial_to); /*! - * \brief Apply changesets to zone. - * - * Applies a list of XFR-style changesets to the given zone. Also checks if the - * changesets are applicable (i.e. zone is right and has the right serial). - * - * \param zone Zone to which the changesets should be applied. - * \param chsets Changesets to be applied to the zone. - * - * \retval KNOTD_EOK - * \retval KNOTD_EINVAL - */ -int zones_apply_changesets(knot_ns_xfr_t *xfr); - -/*! * \brief Update zone timers. * * REFRESH/RETRY/EXPIRE timers are updated according to SOA. diff --git a/src/knot/zone/semantic-check.c b/src/knot/zone/semantic-check.c index f511f35..f900951 100644 --- a/src/knot/zone/semantic-check.c +++ b/src/knot/zone/semantic-check.c @@ -156,12 +156,11 @@ int err_handler_handle_error(err_handler_t *handler, assert(handler && node); if ((error != 0) && (error > ZC_ERR_GLUE_GENERAL_ERROR)) { - return ZC_ERR_UNKNOWN; + return KNOT_EBADARG; } /*!< \todo this is so wrong! This should not even return anything. */ - if (error == ZC_ERR_ALLOC || error == KNOT_ERROR - || error == KNOT_EBADARG) { + if (error == ZC_ERR_ALLOC || error == 0) { return KNOT_EBADARG; } @@ -382,10 +381,13 @@ static int check_cname_cycles_in_zone(knot_zone_contents_t *zone, knot_dname_new_from_str("*", strlen("*"), NULL); if (wc == NULL) { + knot_dname_free(&chopped_next); return KNOT_ENOMEM; } if (knot_dname_cat(wc, chopped_next) == NULL) { + knot_dname_free(&chopped_next); + knot_dname_free(&wc); return KNOT_ERROR; } @@ -552,6 +554,9 @@ static int dnskey_to_wire(const knot_rdata_t *rdata, uint8_t **wire, /* TODO check if we really have that many items */ if (rdata->count < 4) { + free(*wire); + *wire = NULL; + *size = 0; return KNOT_ERROR; } @@ -915,16 +920,14 @@ static int check_nsec3_node_in_zone(knot_zone_contents_t *zone, knot_node_t *nod knot_node_rrset(knot_zone_contents_apex(zone), KNOT_RRTYPE_SOA); assert(soa_rrset); - - uint32_t minimum_ttl = - knot_wire_read_u32((uint8_t *) - rdata_item_data( - knot_rdata_item( - knot_rrset_rdata( - knot_node_rrset( - knot_zone_contents_apex(zone), KNOT_RRTYPE_SOA)), 6))); - /* Are those getters even worth this? - * Now I have no idea what this code does. */ + + const knot_rdata_t *soa_rdata = knot_rrset_rdata(soa_rrset); + if (soa_rdata == NULL) { + err_handler_handle_error(handler, node, ZC_ERR_UNKNOWN); + return KNOT_EOK; + } + + uint32_t minimum_ttl = knot_rdata_soa_minimum(soa_rdata); if (knot_rrset_ttl(nsec3_rrset) != minimum_ttl) { err_handler_handle_error(handler, node, @@ -1012,6 +1015,22 @@ static int check_nsec3_node_in_zone(knot_zone_contents_t *zone, knot_node_t *nod return KNOT_EOK; } +struct sem_check_param { + int node_count; +}; + +/*! + * \brief Used only to count number of nodes in zone tree. + * + * \param node Node to be counted + * \param data Count casted to void * + */ +static void count_nodes_in_tree(knot_node_t *node, void *data) +{ + struct sem_check_param *param = (struct sem_check_param *)data; + param->node_count++; +} + /*! * \brief Run semantic checks for node without DNSSEC-related types. * @@ -1089,9 +1108,34 @@ static int semantic_checks_plain(knot_zone_contents_t *zone, } if (node->children != 0) { - *fatal_error = 1; - err_handler_handle_error(handler, node, - ZC_ERR_DNAME_CHILDREN); + /* + * With DNSSEC and node being zone apex, + * NSEC3 and its RRSIG can be present. + */ + + /* The NSEC3 tree can thus only have one node. */ + struct sem_check_param param; + param.node_count = 0; + int ret_apply = + knot_zone_contents_nsec3_apply_inorder(zone, + count_nodes_in_tree, + ¶m); + if (ret_apply != KNOT_EOK || param.node_count != 1) { + *fatal_error = 1; + err_handler_handle_error(handler, node, + ZC_ERR_DNAME_CHILDREN); + /* + * Valid case: Node is apex, it has NSEC3 node + * and that node has only one RRSet. + */ + } else if (!((knot_zone_contents_apex(zone) == node) && + knot_node_nsec3_node(node) && + knot_node_rrset_count(knot_node_nsec3_node( + node)) == 1)) { + *fatal_error = 1; + err_handler_handle_error(handler, node, + ZC_ERR_DNAME_CHILDREN); + } } } @@ -1173,10 +1217,6 @@ static int semantic_checks_dnssec(knot_zone_contents_t *zone, if (auth && !deleg && (ret = check_rrsig_in_rrset(rrset, dnskey_rrset, nsec3)) != 0) { - /* CLEANUP */ -/* log_zone_error("RRSIG %d node %s\n", ret, - knot_dname_to_str(node->owner));*/ - err_handler_handle_error(handler, node, ret); } @@ -1189,13 +1229,6 @@ static int semantic_checks_dnssec(knot_zone_contents_t *zone, if (nsec_rrset == NULL) { err_handler_handle_error(handler, node, ZC_ERR_NO_NSEC); - /* CLEANUP */ -/* char *name = - knot_dname_to_str(node->owner); - log_zone_error("Missing NSEC in node: " - "%s\n", name); - free(name); - return; */ } else { /* check NSEC/NSEC3 bitmap */ @@ -1229,18 +1262,6 @@ static int semantic_checks_dnssec(knot_zone_contents_t *zone, handler, node, ZC_ERR_NSEC_RDATA_BITMAP); - /* CLEANUP */ - /* char *name = - knot_dname_to_str( - knot_node_owner(node)); - - log_zone_error("Node %s does " - "not contain RRSet of type %s " - "but NSEC bitmap says " - "it does!\n", name, - knot_rrtype_to_string(type)); - - free(name); */ } } free(array); diff --git a/src/knot/zone/zone-dump-text.c b/src/knot/zone/zone-dump-text.c index dcb9add..4a45d64 100644 --- a/src/knot/zone/zone-dump-text.c +++ b/src/knot/zone/zone-dump-text.c @@ -54,7 +54,7 @@ #include "common/skip-list.h" #include "common/base32hex.h" -/* TODO max length of alg */ +/*!< \todo #1683 Find all maximum lengths to be used in strcnat. */ enum uint_max_length { U8_MAX_STR_LEN = 4, U16_MAX_STR_LEN = 6, @@ -114,7 +114,6 @@ enum uint_max_length { * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. */ #include <sys/types.h> -#include <sys/param.h> #include <sys/socket.h> #include <netinet/in.h> @@ -361,30 +360,30 @@ static char *rdata_txt_data_to_string(const uint8_t *data) } memset(ret, 0, current_length); - strcat(ret, "\""); + strncat(ret, "\"", 3); for (i = 1; i <= length; i++) { char ch = (char) data[i]; if (isprint((int)ch)) { if (ch == '"' || ch == '\\') { - strcat(ret, "\""); + strncat(ret, "\"", 3); } /* for the love of god, how to this better, but w/o obscure self-made functions */ char tmp_str[2]; tmp_str[0] = ch; tmp_str[1] = 0; - strcat(ret, tmp_str); + strncat(ret, tmp_str, 2); } else { - strcat(ret, "\\"); + strncat(ret, "\\", 3); char tmp_str[2]; tmp_str[0] = ch - '0'; tmp_str[1] = 0; - strcat(ret, tmp_str); + strncat(ret, tmp_str, 2); } } - strcat(ret, "\""); + strncat(ret, "\"", 3); return ret; } @@ -412,8 +411,8 @@ char *rdata_text_to_string(knot_rdata_item_t item) char del[2]; del[0] = ' '; del[1] = '\0'; - strcat(ret, txt); - strcat(ret, del); + strncat(ret, txt, strlen(txt)); + strncat(ret, del, 2); free(txt); } @@ -423,7 +422,7 @@ char *rdata_text_to_string(knot_rdata_item_t item) char *rdata_byte_to_string(knot_rdata_item_t item) { assert(item.raw_data[0] == 1); - uint8_t data = item.raw_data[1]; + uint8_t data = *((uint8_t *)(item.raw_data + 1)); char *ret = malloc(sizeof(char) * U8_MAX_STR_LEN); snprintf(ret, U8_MAX_STR_LEN, "%d", (char) data); return ret; @@ -629,7 +628,7 @@ char *rdata_nsap_to_string(knot_rdata_item_t item) return NULL; } - strcat(ret, converted); + strncat(ret, converted, rdata_item_size(item) * 2 + 1); free(converted); return ret; } @@ -729,9 +728,10 @@ char *rdata_services_to_string(knot_rdata_item_t item) if (proto) { int i; - strcpy(ret, proto->p_name); + /*!< \todo #1863 see below, but we can trust getprotobynumber... */ + strncpy(ret, proto->p_name, strlen(proto->p_name)); - strcat(ret, " "); + strncat(ret, " ", 2); for (i = 0; i < bitmap_size * 8; ++i) { if (get_bit(bitmap, i)) { @@ -739,13 +739,20 @@ char *rdata_services_to_string(knot_rdata_item_t item) getservbyport((int)htons(i), proto->p_name); if (service) { - strcat(ret, service->s_name); - strcat(ret, " "); + /*!< \todo #1863 + * using strncat with strlen + * does not make a whole lot of sense. + * At least it will crash wil + * Use max length of service name! + */ + strncat(ret, service->s_name, + strlen(service->s_name)); + strncat(ret, " ", 2); } else { char tmp[U32_MAX_STR_LEN]; snprintf(tmp, U32_MAX_STR_LEN, "%d ", i); - strcat(ret, tmp); + strncat(ret, tmp, U32_MAX_STR_LEN); } } } @@ -832,8 +839,9 @@ char *rdata_nxt_to_string(knot_rdata_item_t item) for (i = 0; i < bitmap_size * 8; ++i) { if (get_bit(bitmap, i)) { - strcat(ret, knot_rrtype_to_string(i)); - strcat(ret, " "); + strncat(ret, knot_rrtype_to_string(i), + MAX_RR_TYPE_LEN); + strncat(ret, " ", 2); } } @@ -871,10 +879,11 @@ char *rdata_nsec_to_string(knot_rdata_item_t item) for (int j = 0; j < bitmap_size * 8; j++) { if (get_bit(bitmap, j)) { - strcat(ret, + strncat(ret, knot_rrtype_to_string(j + - window * 256)); - strcat(ret, " "); + window * 256), + MAX_RR_TYPE_LEN); + strncat(ret, " ", 2); } } @@ -925,7 +934,7 @@ char *rdata_unknown_to_string(knot_rdata_item_t item) strlen("\\# ") + U16_MAX_STR_LEN + 1, "%lu ", (unsigned long) size); char *converted = hex_to_string(rdata_item_data(item), size); - strcat(ret, converted); + strncat(ret, converted, size * 2 + 1); free(converted); return ret; } @@ -1131,9 +1140,9 @@ void node_dump_text(knot_node_t *node, void *data) free(rrsets); } -int zone_dump_text(knot_zone_contents_t *zone, const char *filename) +int zone_dump_text(knot_zone_contents_t *zone, int fd) { - FILE *f = fopen(filename, "w"); + FILE *f = fdopen(fd, "w"); if (f == NULL) { return KNOT_EBADARG; } diff --git a/src/knot/zone/zone-dump-text.h b/src/knot/zone/zone-dump-text.h index 70dcff4..2a35643 100644 --- a/src/knot/zone/zone-dump-text.h +++ b/src/knot/zone/zone-dump-text.h @@ -34,12 +34,12 @@ * \brief Dumps given zone to text (BIND-like) file. * * \param zone Zone to be saved. - * \param filename Name of file to be created. + * \param fd File descriptor to write to. * * \retval KNOT_EOK on success. * \retval KNOT_EBADARG if the specified file is not valid for writing. */ -int zone_dump_text(knot_zone_contents_t *zone, const char *filename); +int zone_dump_text(knot_zone_contents_t *zone, int fd); #endif // _KNOT_ZONE_DUMP_TEXT_H_ diff --git a/src/knot/zone/zone-dump.c b/src/knot/zone/zone-dump.c index 0be1ac7..6ca969f 100644 --- a/src/knot/zone/zone-dump.c +++ b/src/knot/zone/zone-dump.c @@ -51,16 +51,15 @@ * or raw data stored like this: data_len [data] */ -static inline int fwrite_to_file_crc(const void *src, - size_t size, size_t n, FILE *f, +static inline int write_to_file_crc(const void *src, + size_t size, size_t n, int fd, crc_t *crc) { - size_t rc = fwrite(src, size, n, f); - if (rc != n) { + ssize_t rc = write(fd, src, size * n); + if (rc != size * n) { fprintf(stderr, "fwrite: invalid write %zu (expected %zu)\n", rc, n); } - /* \todo this seems to be wrong, if you fwrite less than n items, you probably should not continue */ if (size * n > 0) { *crc = @@ -68,13 +67,16 @@ static inline int fwrite_to_file_crc(const void *src, size * n); } - /* \todo the rc return is certainly wrong as it is used in the caller function */ -// return rc == n; - return (int)rc; + /* + * It was meant differtely, caller function does not + * care how many bytes had been written, it just cares about + * success/fail (not that it is checked anyway) (#1684). + */ + return rc == n; } -static inline int fwrite_to_stream(const void *src, +static inline int write_to_stream(const void *src, size_t size, size_t n, uint8_t **stream, size_t *stream_size) @@ -97,17 +99,17 @@ static inline int fwrite_to_stream(const void *src, return KNOT_EOK; } -static int fwrite_wrapper(const void *src, - size_t size, size_t n, FILE *fp, +static int write_wrapper(const void *src, + size_t size, size_t n, int fd, uint8_t **stream, size_t *stream_size, crc_t *crc) { - if (fp == NULL) { + if (fd < 0) { assert(stream && stream_size); assert(crc == NULL); - return fwrite_to_stream(src, size, n, stream, stream_size); + return write_to_stream(src, size, n, stream, stream_size); } else { assert(stream == NULL && stream_size == NULL); - return fwrite_to_file_crc(src, size, n, fp, crc); + return write_to_file_crc(src, size, n, fd, crc); } } @@ -117,17 +119,17 @@ static int fwrite_wrapper(const void *src, * \param dname Dname whose labels are to be dumped. * \param f Output file. */ -static void knot_labels_dump_binary(const knot_dname_t *dname, FILE *f, +static void knot_labels_dump_binary(const knot_dname_t *dname, int fd, uint8_t **stream, size_t *stream_size, crc_t *crc) { dbg_zdump("label count: %d\n", dname->label_count); uint16_t label_count = dname->label_count; - /* \todo check the return value */ - fwrite_wrapper(&label_count, sizeof(label_count), 1, f, stream, + /*!< \todo #1684 check the return value */ + write_wrapper(&label_count, sizeof(label_count), 1, fd, stream, stream_size, crc); - /* \todo check the return value */ - fwrite_wrapper(dname->labels, sizeof(uint8_t), dname->label_count, f, + /*!< \todo #1684 check the return value */ + write_wrapper(dname->labels, sizeof(uint8_t), dname->label_count, fd, stream, stream_size, crc); } @@ -137,31 +139,31 @@ static void knot_labels_dump_binary(const knot_dname_t *dname, FILE *f, * \param dname Dname to be dumped. * \param f Output file. */ -static void knot_dname_dump_binary(const knot_dname_t *dname, FILE *f, +static void knot_dname_dump_binary(const knot_dname_t *dname, int fd, uint8_t **stream, size_t *stream_size, crc_t *crc) { uint32_t dname_size = dname->size; - /* \todo check the return value */ - fwrite_wrapper(&dname_size, sizeof(dname_size), 1, f, stream, + /*!< \todo #1684 check the return value */ + write_wrapper(&dname_size, sizeof(dname_size), 1, fd, stream, stream_size, crc); - /* \todo check the return value */ - fwrite_wrapper(dname->name, sizeof(uint8_t), dname->size, f, + /*!< \todo #1684 check the return value */ + write_wrapper(dname->name, sizeof(uint8_t), dname->size, fd, stream, stream_size, crc); dbg_zdump("dname size: %d\n", dname->size); - knot_labels_dump_binary(dname, f, stream, stream_size, crc); + knot_labels_dump_binary(dname, fd, stream, stream_size, crc); } -/*!< \todo some global variable indicating error! */ -static void dump_dname_with_id(const knot_dname_t *dname, FILE *f, +/*!< \todo #1684 some global variable indicating error! */ +static void dump_dname_with_id(const knot_dname_t *dname, int fd, uint8_t **stream, size_t *stream_size, crc_t *crc) { uint32_t id = dname->id; - /* \todo check the return value */ - fwrite_wrapper(&id, sizeof(id), 1, f, stream, stream_size, crc); - knot_dname_dump_binary(dname, f, stream, stream_size, crc); -/* if (!fwrite_wrapper_safe(&dname->id, sizeof(dname->id), 1, f)) { + /*!< \todo #1684 check the return value */ + write_wrapper(&id, sizeof(id), 1, fd, stream, stream_size, crc); + knot_dname_dump_binary(dname, fd, stream, stream_size, crc); +/* if (!write_wrapper_safe(&dname->id, sizeof(dname->id), 1, f)) { return KNOT_ERROR; } */ } @@ -174,11 +176,10 @@ static void dump_dname_with_id(const knot_dname_t *dname, FILE *f, * \param data Arguments to be propagated. */ static void knot_rdata_dump_binary(knot_rdata_t *rdata, - uint32_t type, void *data, int use_ids, + uint32_t type, int fd, int use_ids, uint8_t **stream, size_t *stream_size, crc_t *crc) { - FILE *f = (FILE *)((arg_t *)data)->arg1; knot_rrtype_descriptor_t *desc = knot_rrtype_descriptor_by_type(type); assert(desc != NULL); @@ -190,9 +191,9 @@ static void knot_rdata_dump_binary(knot_rdata_t *rdata, } /* Write rdata count. */ - /* \todo check the return value */ - fwrite_wrapper(&(rdata->count), - sizeof(rdata->count), 1, f, stream, stream_size, crc); + /*!< \todo #1684 check the return value */ + write_wrapper(&(rdata->count), + sizeof(rdata->count), 1, fd, stream, stream_size, crc); for (int i = 0; i < rdata->count; i++) { if (&(rdata->items[i]) == NULL) { @@ -215,48 +216,46 @@ static void knot_rdata_dump_binary(knot_rdata_t *rdata, if (use_ids) { /* Write ID. */ - dbg_zload("%s \n", - knot_dname_to_str(rdata->items[i].dname)); assert(rdata->items[i].dname->id != 0); uint32_t id = rdata->items[i].dname->id; - /* \todo check the return value */ - fwrite_wrapper(&id, - sizeof(id), 1, f, stream, stream_size, + /*!< \todo #1684 check the return value */ + write_wrapper(&id, + sizeof(id), 1, fd, stream, stream_size, crc); } else { // assert(rdata->items[i].dname->id != 0); dump_dname_with_id(rdata->items[i].dname, - f, stream, + fd, stream, stream_size, crc); } /* Write in the zone bit */ if (rdata->items[i].dname->node != NULL && !wildcard) { - /* \todo check the return value */ - fwrite_wrapper((uint8_t *)"\1", - sizeof(uint8_t), 1, f, stream, + /*!< \todo #1684 check the return value */ + write_wrapper((uint8_t *)"\1", + sizeof(uint8_t), 1, fd, stream, stream_size, crc); } else { - /* \todo check the return value */ - fwrite_wrapper((uint8_t *)"\0", sizeof(uint8_t), - 1, f, stream, stream_size, crc); + /*!< \todo #1684 check the return value */ + write_wrapper((uint8_t *)"\0", sizeof(uint8_t), + 1, fd, stream, stream_size, crc); } if (use_ids && wildcard) { - /* \todo check the return value */ - fwrite_wrapper((uint8_t *)"\1", - sizeof(uint8_t), 1, f, stream, + /*!< \todo #1684 check the return value */ + write_wrapper((uint8_t *)"\1", + sizeof(uint8_t), 1, fd, stream, stream_size, crc); uint32_t wildcard_id = wildcard->id; - /* \todo check the return value */ - fwrite_wrapper(&wildcard_id, - sizeof(wildcard_id), 1, f, stream, + /*!< \todo #1684 check the return value */ + write_wrapper(&wildcard_id, + sizeof(wildcard_id), 1, fd, stream, stream_size, crc); } else { - /* \todo check the return value */ - fwrite_wrapper((uint8_t *)"\0", sizeof(uint8_t), - 1, f, stream, + /*!< \todo #1684 check the return value */ + write_wrapper((uint8_t *)"\0", sizeof(uint8_t), + 1, fd, stream, stream_size, crc); } @@ -264,10 +263,10 @@ static void knot_rdata_dump_binary(knot_rdata_t *rdata, dbg_zdump("Writing raw data. Item nr.: %d\n", i); assert(rdata->items[i].raw_data != NULL); - /* \todo check the return value */ - fwrite_wrapper(rdata->items[i].raw_data, + /*!< \todo #1684 check the return value */ + write_wrapper(rdata->items[i].raw_data, sizeof(uint8_t), - rdata->items[i].raw_data[0] + 2, f, + rdata->items[i].raw_data[0] + 2, fd, stream, stream_size, crc); dbg_zdump("Written %d long raw data\n", @@ -282,22 +281,25 @@ static void knot_rdata_dump_binary(knot_rdata_t *rdata, * \param rrsig RRSIG to be dumped. * \param data Arguments to be propagated. */ -static void knot_rrsig_set_dump_binary(knot_rrset_t *rrsig, arg_t *data, +static void knot_rrsig_set_dump_binary(knot_rrset_t *rrsig, int fd, int use_ids, uint8_t **stream, size_t *stream_size, crc_t *crc) { - dbg_zdump("Dumping rrset \\w owner: %s\n", - knot_dname_to_str(rrsig->owner)); +dbg_zdump_exec_detail( + char *name = knot_dname_to_str(knot_rrset_owner(rrsig)); + dbg_zdump("Dumping RRSIG \\w owner: %s\n", + name); + free(name); +); assert(rrsig->type == KNOT_RRTYPE_RRSIG); assert(rrsig->rdata); - FILE *f = (FILE *)((arg_t *)data)->arg1; - /* \todo check the return value */ - fwrite_wrapper(&rrsig->type, sizeof(rrsig->type), 1, f, + /*!< \todo #1684 check the return value */ + write_wrapper(&rrsig->type, sizeof(rrsig->type), 1, fd, stream, stream_size, crc); - fwrite_wrapper(&rrsig->rclass, sizeof(rrsig->rclass), 1, f, + write_wrapper(&rrsig->rclass, sizeof(rrsig->rclass), 1, fd, stream, stream_size, crc); - fwrite_wrapper(&rrsig->ttl, sizeof(rrsig->ttl), 1, f, + write_wrapper(&rrsig->ttl, sizeof(rrsig->ttl), 1, fd, stream, stream_size, crc); uint32_t rdata_count = 1; @@ -308,16 +310,16 @@ static void knot_rrsig_set_dump_binary(knot_rrset_t *rrsig, arg_t *data, rdata_count++; } - fwrite_wrapper(&rdata_count, sizeof(rdata_count), 1, f, + write_wrapper(&rdata_count, sizeof(rdata_count), 1, fd, stream, stream_size, crc); tmp_rdata = rrsig->rdata; while (tmp_rdata->next != rrsig->rdata) { - knot_rdata_dump_binary(tmp_rdata, KNOT_RRTYPE_RRSIG, data, + knot_rdata_dump_binary(tmp_rdata, KNOT_RRTYPE_RRSIG, fd, use_ids, stream, stream_size, crc); tmp_rdata = tmp_rdata->next; } - knot_rdata_dump_binary(tmp_rdata, KNOT_RRTYPE_RRSIG, data, use_ids, + knot_rdata_dump_binary(tmp_rdata, KNOT_RRTYPE_RRSIG, fd, use_ids, stream, stream_size, crc); } @@ -327,23 +329,24 @@ static void knot_rrsig_set_dump_binary(knot_rrset_t *rrsig, arg_t *data, * \param rrset RRSSet to be dumped. * \param data Arguments to be propagated. */ -static void knot_rrset_dump_binary(const knot_rrset_t *rrset, void *data, +static void knot_rrset_dump_binary(const knot_rrset_t *rrset, int fd, int use_ids, uint8_t **stream, size_t *stream_size, crc_t *crc) { - FILE *f = (FILE *)((arg_t *)data)->arg1; + dbg_zdump_detail("zdump: rrset_dump_binary: Dumping rrset to fd=%d\n", + fd); if (!use_ids) { - dump_dname_with_id(rrset->owner, f, stream, stream_size, crc); + dump_dname_with_id(rrset->owner, fd, stream, stream_size, crc); } - /* \todo check the return value */ - fwrite_wrapper(&rrset->type, sizeof(rrset->type), 1, f, + /*!< \todo #1684 check the return value */ + write_wrapper(&rrset->type, sizeof(rrset->type), 1, fd, stream, stream_size, crc); - fwrite_wrapper(&rrset->rclass, sizeof(rrset->rclass), 1, f, + write_wrapper(&rrset->rclass, sizeof(rrset->rclass), 1, fd, stream, stream_size, crc); - fwrite_wrapper(&rrset->ttl, sizeof(rrset->ttl), 1, f, + write_wrapper(&rrset->ttl, sizeof(rrset->ttl), 1, fd, stream, stream_size, crc); uint32_t rdata_count = 1; @@ -356,26 +359,30 @@ static void knot_rrset_dump_binary(const knot_rrset_t *rrset, void *data, rdata_count++; } - fwrite_wrapper(&rdata_count, sizeof(rdata_count), 1, f, + write_wrapper(&rdata_count, sizeof(rdata_count), 1, fd, stream, stream_size, crc); - fwrite_wrapper(&has_rrsig, sizeof(has_rrsig), 1, f, + write_wrapper(&has_rrsig, sizeof(has_rrsig), 1, fd, stream, stream_size, crc); + + dbg_zdump_detail("zdump: rrset_dump_binary: Static data dumped.\n"); tmp_rdata = rrset->rdata; while (tmp_rdata->next != rrset->rdata) { - knot_rdata_dump_binary(tmp_rdata, rrset->type, data, use_ids, + knot_rdata_dump_binary(tmp_rdata, rrset->type, fd, use_ids, stream, stream_size, crc); tmp_rdata = tmp_rdata->next; } - knot_rdata_dump_binary(tmp_rdata, rrset->type, data, use_ids, + knot_rdata_dump_binary(tmp_rdata, rrset->type, fd, use_ids, stream, stream_size, crc); + + dbg_zdump_detail("zdump: rrset_dump_binary: Rdata dumped.\n"); /* This is now obsolete, although I'd rather not use recursion - that * would probably not work */ if (rrset->rrsigs != NULL) { - knot_rrsig_set_dump_binary(rrset->rrsigs, data, use_ids, + knot_rrsig_set_dump_binary(rrset->rrsigs, fd, use_ids, stream, stream_size, crc); } } @@ -386,38 +393,42 @@ static void knot_rrset_dump_binary(const knot_rrset_t *rrset, void *data, * \param node Node to dumped. * \param data Arguments to be propagated. */ -static void knot_node_dump_binary(knot_node_t *node, void *data, +static void knot_node_dump_binary(knot_node_t *node, int fd, uint8_t **stream, size_t *stream_size, crc_t *crc) { - arg_t *args = (arg_t *)data; - FILE *f = (FILE *)args->arg1; - -// node_count++; + if (node == NULL) { + return; + } + /* first write dname */ assert(node->owner != NULL); /* Write owner ID. */ +dbg_zdump_exec_detail( + char *name = knot_dname_to_str(knot_node_owner(node)); dbg_zdump("Dumping node owned by %s\n", - knot_dname_to_str(node->owner)); + name); + free(name); +); assert(node->owner->id != 0); uint32_t owner_id = node->owner->id; - /* \todo check the return value */ - fwrite_wrapper(&owner_id, sizeof(owner_id), 1, f, stream, stream_size, + /*!< \todo #1684 check the return value */ + write_wrapper(&owner_id, sizeof(owner_id), 1, fd, stream, stream_size, crc); if (knot_node_parent(node) != NULL) { uint32_t parent_id = knot_dname_id( knot_node_owner(knot_node_parent(node))); - fwrite_wrapper(&parent_id, sizeof(parent_id), 1, f, + write_wrapper(&parent_id, sizeof(parent_id), 1, fd, stream, stream_size, crc); } else { uint32_t parent_id = 0; - fwrite_wrapper(&parent_id, sizeof(parent_id), 1, f, + write_wrapper(&parent_id, sizeof(parent_id), 1, fd, stream, stream_size, crc); } - fwrite_wrapper(&(node->flags), sizeof(node->flags), 1, f, + write_wrapper(&(node->flags), sizeof(node->flags), 1, fd, stream, stream_size, crc); dbg_zdump("Written flags: %u\n", node->flags); @@ -425,13 +436,13 @@ static void knot_node_dump_binary(knot_node_t *node, void *data, if (knot_node_nsec3_node(node) != NULL) { uint32_t nsec3_id = knot_node_owner(knot_node_nsec3_node(node))->id; - fwrite_wrapper(&nsec3_id, sizeof(nsec3_id), 1, f, + write_wrapper(&nsec3_id, sizeof(nsec3_id), 1, fd, stream, stream_size, crc); dbg_zdump("Written nsec3 node id: %u\n", knot_node_owner(knot_node_nsec3_node(node))->id); } else { uint32_t nsec3_id = 0; - fwrite_wrapper(&nsec3_id, sizeof(nsec3_id), 1, f, + write_wrapper(&nsec3_id, sizeof(nsec3_id), 1, fd, stream, stream_size, crc); } @@ -439,37 +450,18 @@ static void knot_node_dump_binary(knot_node_t *node, void *data, * but that number is yet unknown */ uint16_t rrset_count = node->rrset_count; - fwrite_wrapper(&rrset_count, sizeof(rrset_count), 1, f, + write_wrapper(&rrset_count, sizeof(rrset_count), 1, fd, stream, stream_size, crc); - /* CLEANUP */ -// const skip_node_t *skip_node = skip_first(node->rrsets); - const knot_rrset_t **node_rrsets = knot_node_rrsets(node); for (int i = 0; i < rrset_count; i++) { - knot_rrset_dump_binary(node_rrsets[i], data, 1, + knot_rrset_dump_binary(node_rrsets[i], fd, 1, stream, stream_size, crc); } - /* CLEANUP */ -// if (skip_node == NULL) { -// /* we can return, count is set to 0 */ -// return; -// } - -// knot_rrset_t *tmp; - -// do { -// tmp = (knot_rrset_t *)skip_node->value; -// knot_rrset_dump_binary(tmp, data, 1); -// } while ((skip_node = skip_next(skip_node)) != NULL); - free(node_rrsets); - dbg_zdump("Position after all rrsets: %ld\n", ftell(f)); - dbg_zdump("Writing here: %ld\n", ftell(f)); - dbg_zdump("Function ends with: %ld\n\n", ftell(f)); } int zone_is_secure(knot_zone_contents_t *zone) @@ -487,50 +479,32 @@ int zone_is_secure(knot_zone_contents_t *zone) } } -/*! - * \brief Safe wrapper around fwrite. - * - * \param dst Destination pointer. - * \param size Size of element to be written. - * \param n Number of elements to be written. - * \param fp File to write to. - * - * \retval > 0 if succesfull. - * \retval 0 if failed. - */ -//static inline int fwrite_wrapper_safe(const void *src, -// size_t size, size_t n, FILE *fp) -//{ -// int rc = fwrite_wrapper(src, size, n, fp); -// if (rc != n) { -// fprintf(stderr, "fwrite_wrapper: invalid write %d (expected %zu)\n", rc, -// n); -// } - -// return rc == n; -//} - static void dump_dname_from_tree(knot_dname_t *dname, void *data) { arg_t *arg = (arg_t *)data; - FILE *f = (FILE *)arg->arg1; + int *fd_pointer = (int *)arg->arg1; + int fd = -1; + if (fd_pointer != NULL) { + fd = *fd_pointer; + } else { + dbg_zdump("zdump: dump_dname_from_tree: Bad fd.\n"); + return; + } + crc_t *crc = (crc_t*)arg->arg2; - dump_dname_with_id(dname, f, NULL, NULL, crc); + dump_dname_with_id(dname, fd, NULL, NULL, crc); } static int knot_dump_dname_table(const knot_dname_table_t *dname_table, - FILE *f, crc_t *crc) + int fd, crc_t *crc) { arg_t arg; - arg.arg1 = f; + arg.arg1 = &fd; arg.arg2 = crc; /* Go through the tree and dump each dname along with its ID. */ knot_dname_table_tree_inorder_apply(dname_table, dump_dname_from_tree, &arg); - /* CLEANUP */ -// TREE_FORWARD_APPLY(dname_table->tree, dname_table_node, avl, -// dump_dname_from_tree, (void *)f); return KNOT_EOK; } @@ -550,10 +524,16 @@ static void save_node_from_tree(knot_node_t *node, void *data) static void dump_node_to_file(knot_node_t *node, void *data) { arg_t *arg = (arg_t *)data; - knot_node_dump_binary(node, data, NULL, NULL, (crc_t *)arg->arg7); + int *fd_pointer = (int *)arg->arg1; + int fd = -1; + if (fd_pointer != NULL) { + fd = *fd_pointer; + } + + knot_node_dump_binary(node, fd, NULL, NULL, (crc_t *)arg->arg7); } -static char *knot_zdump_crc_file(const char* filename) +char *knot_zdump_crc_file(const char* filename) { char *crc_path = malloc(sizeof(char) * (strlen(filename) + @@ -564,31 +544,18 @@ static char *knot_zdump_crc_file(const char* filename) strlen(".crc") + 1)); memcpy(crc_path, filename, sizeof(char) * strlen(filename)); - crc_path = strcat(crc_path, ".crc"); + crc_path = strncat(crc_path, ".crc", strlen(".crc")); return crc_path; } -int knot_zdump_binary(knot_zone_contents_t *zone, const char *filename, - int do_checks, const char *sfilename) +int knot_zdump_binary(knot_zone_contents_t *zone, int fd, + int do_checks, const char *sfilename, + crc_t *crc) { - /* Open .new file. */ - char new_path[strlen(filename) + strlen(".new") + 1]; - memcpy(new_path, filename, strlen(filename) + 1); - strcat(new_path, ".new"); - mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; - int fd = open(new_path, O_WRONLY | O_CREAT | O_TRUNC, mode); - if (fd == -1) { - close(fd); - remove(new_path); - remove(knot_zdump_crc_file(filename)); + if (fd < 0 || sfilename == NULL) { return KNOT_EBADARG; } - FILE *f = fdopen(fd, "wb"); - assert(f); - - /* CLEANUP */ -// skip_list_t *encloser_list = skip_create_list(compare_pointers); arg_t arguments; /* Memory to be derefenced in the save_node_from_tree function. */ uint32_t node_count = 0; @@ -615,7 +582,8 @@ int knot_zdump_binary(knot_zone_contents_t *zone, const char *filename, if (do_checks && zone_is_secure(zone)) { do_checks += zone_is_secure(zone); } - + + /* FIXME(OS): Really descriptive call 1,1,1,1, some #defines here? */ err_handler_t *handler = handler_new(1, 1, 1, 1, 1); if (handler == NULL) { return KNOT_ENOMEM; @@ -640,154 +608,60 @@ int knot_zdump_binary(knot_zone_contents_t *zone, const char *filename, if (ret != KNOT_EOK) { fprintf(stderr, "Zone will not be dumped because of " "fatal semantic errors.\n"); - fclose(f); - close(fd); /* If remove fails, there is nothing we can do. */ - remove(new_path); - remove(knot_zdump_crc_file(filename)); return KNOT_ERROR; } - crc_t crc = crc_init(); + *crc = crc_init(); /* Start writing header - magic bytes. */ static const uint8_t MAGIC[MAGIC_LENGTH] = MAGIC_BYTES; - fwrite_wrapper(&MAGIC, sizeof(uint8_t), MAGIC_LENGTH, f, NULL, NULL, - &crc); + write_wrapper(&MAGIC, sizeof(uint8_t), MAGIC_LENGTH, fd, NULL, NULL, + crc); /* Write source file length. */ - uint32_t sflen = 0; - if (sfilename) { - sflen = strlen(sfilename) + 1; - } - fwrite_wrapper(&sflen, sizeof(uint32_t), 1, f, NULL, NULL, &crc); + uint32_t sflen = strlen(sfilename) + 1; + write_wrapper(&sflen, sizeof(uint32_t), 1, fd, NULL, NULL, crc); /* Write source file. */ - fwrite_wrapper(sfilename, sflen, 1, f, NULL, NULL, &crc); + write_wrapper(sfilename, sflen, 1, fd, NULL, NULL, crc); /* Notice: End of header, */ /* Start writing compiled data. */ - fwrite_wrapper(&normal_node_count, sizeof(normal_node_count), 1, f, - NULL, NULL, &crc); - fwrite_wrapper(&nsec3_node_count, sizeof(nsec3_node_count), 1, f, - NULL, NULL, &crc); + write_wrapper(&normal_node_count, sizeof(normal_node_count), 1, fd, + NULL, NULL, crc); + write_wrapper(&nsec3_node_count, sizeof(nsec3_node_count), 1, fd, + NULL, NULL, crc); uint32_t auth_node_count = zone->node_count; - fwrite_wrapper(&auth_node_count, - sizeof(auth_node_count), 1, f, NULL, NULL, &crc); + write_wrapper(&auth_node_count, + sizeof(auth_node_count), 1, fd, NULL, NULL, crc); /* Write total number of dnames */ assert(zone->dname_table); uint32_t total_dnames = zone->dname_table->id_counter; - fwrite_wrapper(&total_dnames, - sizeof(total_dnames), 1, f, NULL, NULL, &crc); + write_wrapper(&total_dnames, + sizeof(total_dnames), 1, fd, NULL, NULL, crc); /* Write dname table. */ - if (knot_dump_dname_table(zone->dname_table, f, &crc) + if (knot_dump_dname_table(zone->dname_table, fd, crc) != KNOT_EOK) { - fclose(f); - close(fd); - /* If remove fails, there is nothing we can do. */ - remove(new_path); - remove(knot_zdump_crc_file(filename)); return KNOT_ERROR; } - - arguments.arg1 = (void *)f; + + arguments.arg1 = &fd; arguments.arg3 = zone; - arguments.arg7 = &crc; + arguments.arg7 = crc; - /* TODO is there a way how to stop the traversal upon error? */ + /*!< \todo #1685 Stop traversal upon error. */ knot_zone_contents_tree_apply_inorder(zone, dump_node_to_file, (void *)&arguments); knot_zone_contents_nsec3_apply_inorder(zone, dump_node_to_file, (void *)&arguments); - fclose(f); - - crc = crc_finalize(crc); - /* Write CRC to separate .crc file. */ - /*!< \todo There is now function doing this. */ - char *crc_path = - malloc(sizeof(char) * (strlen(filename) + strlen(".crc") + 1)); - if (unlikely(!crc_path)) { - close(fd); - /* If remove fails, there is nothing we can do. */ - remove(new_path); - remove(knot_zdump_crc_file(filename)); - free(crc_path); - return KNOT_ENOMEM; - } - memset(crc_path, 0, - sizeof(char) * (strlen(filename) + strlen(".crc") + 1)); - memcpy(crc_path, filename, sizeof(char) * strlen(filename)); - - crc_path = strcat(crc_path, ".crc"); - FILE *f_crc = fopen(crc_path, "w"); - if (unlikely(!f_crc)) { - dbg_zload("knot_zload_open: failed to open '%s'\n", - crc_path); - close(fd); - /* If remove fails, there is nothing we can do. */ - remove(new_path); - remove(knot_zdump_crc_file(filename)); - free(crc_path); - return ENOENT; - } - free(crc_path); - - fprintf(f_crc, "%lu\n", (unsigned long)crc); - fclose(f_crc); - - close(fd); - mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; - fd = open(filename, O_WRONLY | O_CREAT, mode); - if (fd == -1) { - fprintf(stderr, "%s\n", strerror(errno)); - fprintf(stderr, "Could not open destination file! Use '%s' " - "file instead.\n", new_path); - close(fd); - /* If remove fails, there is nothing we can do. */ - remove(new_path); - remove(knot_zdump_crc_file(filename)); - return KNOT_ERROR; - } - - /* Try to obtain exclusive lock for originally given file. */ - if (fcntl(fd, F_SETLK, knot_file_lock(F_WRLCK, SEEK_SET)) == -1) { - fprintf(stderr, "Could not lock destination file for write! " - "Use '%s' file instead.\n", new_path); - close(fd); - /* If remove fails, there is nothing we can do. */ - remove(new_path); - remove(knot_zdump_crc_file(filename)); - return KNOT_ERROR; - } - - /* Move .new file to original file. */ - if (rename(new_path, filename) != 0) { - fprintf(stderr, "Could not move to originally given file! " - "Use '%s' file instead.\n", new_path); - close(fd); - /* If remove fails, there is nothing we can do. */ - remove(new_path); - remove(knot_zdump_crc_file(filename)); - return KNOT_ERROR; - } - - /* Release the lock. */ - if (fcntl(fd, F_SETLK, knot_file_lock(F_UNLCK, SEEK_SET)) == -1) { - fprintf(stderr, "Could not unlock destination file!\n"); - close(fd); - /* If remove fails, there is nothing we can do. */ - remove(new_path); - remove(knot_zdump_crc_file(filename)); - return KNOT_ERROR; - } - - close(fd); - + *crc = crc_finalize(*crc); + return KNOT_EOK; } @@ -796,74 +670,28 @@ int knot_zdump_rrset_serialize(const knot_rrset_t *rrset, uint8_t **stream, { if (stream == NULL || *stream != NULL || rrset == NULL || size == NULL) { + dbg_zdump("zdump: rrset_serialize: Bad arguments.\n"); return KNOT_EBADARG; } *size = 0; arg_t arguments; memset(&arguments, 0, sizeof(arg_t)); + + /* This fd will signal functions to use streams. */ + int fd = -1; - knot_rrset_dump_binary(rrset, &arguments, 0, stream, size, NULL); + knot_rrset_dump_binary(rrset, fd, 0, stream, size, NULL); return KNOT_EOK; } -int knot_zdump_dump_and_swap(knot_zone_contents_t *zone, - const char *temp_zonedb, - const char *destination_zonedb, - const char *sfilename) +int knot_zdump_dump(knot_zone_contents_t *zone, int fd, const char *sfilename, + crc_t *crc) { - int rc = knot_zdump_binary(zone, temp_zonedb, 0, sfilename); - + int rc = knot_zdump_binary(zone, fd, 0, sfilename, crc); if (rc != KNOT_EOK) { - dbg_zdump("Failed to save the zone to binary zone db %s." - "\n", temp_zonedb); - return KNOT_ERROR; - } - - /*! \todo this would also need locking as well. */ - rc = remove(destination_zonedb); - if (rc == 0 || (rc != 0 && errno == ENOENT)) { - - /* Delete old CRC file. */ - char *destination_zonedb_crc = - knot_zdump_crc_file(destination_zonedb); - if (destination_zonedb_crc == NULL) { - return KNOT_ENOMEM; - } - remove(destination_zonedb_crc); - - /* Move CRC file. */ - char *temp_zonedb_crc = - knot_zdump_crc_file(temp_zonedb); - if (temp_zonedb_crc == NULL) { - return KNOT_ENOMEM; - } - - if (rename(temp_zonedb_crc, destination_zonedb_crc) != 0) { - dbg_zdump("Failed to replace old zonedb CRC %s " - "with new CRC zone file %s.\n", - destination_zonedb_crc, - temp_zonedb_crc); - return KNOT_ERROR; - } - free(temp_zonedb_crc); - free(destination_zonedb_crc); - - /* Rename zonedb. */ - if (rename(temp_zonedb, destination_zonedb) != 0) { - dbg_zdump("Failed to replace old zonedb %s " - "with new zone file %s.\n", - temp_zonedb, - destination_zonedb); - /*! \todo with proper locking, this shouldn't happen, - * revise it later on. - */ - return KNOT_ERROR; - } - } else { - dbg_zdump("Failed to replace old zonedb '%s'', %s.\n", - destination_zonedb, strerror(errno)); + dbg_zdump("Failed to save the zone to binary zone db\n."); return KNOT_ERROR; } diff --git a/src/knot/zone/zone-dump.h b/src/knot/zone/zone-dump.h index 97f1318..77a395c 100644 --- a/src/knot/zone/zone-dump.h +++ b/src/knot/zone/zone-dump.h @@ -44,15 +44,17 @@ enum { * \brief Dumps given zone to binary file. * * \param zone Zone to be saved. - * \param filename Name of file to be created. + * \param fd File descriptor to be written to. * \param do_checks Set to 1 to enable checking the zone for semantic errors. * \param sfilename Source filename of the text zone file. + * \param crc Returns a calculated CRC. * * \retval KNOT_EOK on success. * \retval KNOT_EBADARG if the file cannot be opened for writing. */ -int knot_zdump_binary(knot_zone_contents_t *zone, const char *filename, - int do_checks, const char *sfilename); +int knot_zdump_binary(knot_zone_contents_t *zone, int fd, + int do_checks, const char *sfilename, + crc_t *crc); /*! * \brief Serializes RRSet into binary stream. Expects NULL pointer, memory @@ -95,10 +97,14 @@ int knot_zdump_rrset_serialize(const knot_rrset_t *rrset, uint8_t **stream, */ int zone_is_secure(knot_zone_contents_t *zone); -int knot_zdump_dump_and_swap(knot_zone_contents_t *zone, - const char *temp_zonedb, - const char *destination_zonedb, - const char *sfilename); +/*! \todo Document me (issue #1586). */ +int knot_zdump_dump(knot_zone_contents_t *zone, int fd, const char *sfilename, + crc_t *crc); + +/*! + * \brief Return name of the CRC file associated with filename. + */ +char *knot_zdump_crc_file(const char* filename); #endif /* _KNOT_ZONEDUMP_H_ */ diff --git a/src/knot/zone/zone-load.c b/src/knot/zone/zone-load.c index 5710fe9..f64cfaa 100644 --- a/src/knot/zone/zone-load.c +++ b/src/knot/zone/zone-load.c @@ -235,6 +235,9 @@ static knot_rdata_t *knot_load_rdata(uint16_t type, FILE *f, int use_ids) { knot_rdata_t *rdata = knot_rdata_new(); + if (rdata == NULL) { + return NULL; + } knot_rrtype_descriptor_t *desc = knot_rrtype_descriptor_by_type(type); @@ -246,6 +249,7 @@ static knot_rdata_t *knot_load_rdata(uint16_t type, FILE *f, uint32_t rdata_count = 0; if(!fread_wrapper(&rdata_count, sizeof(rdata_count), 1, f)) { + knot_rdata_free(&rdata); return NULL; } @@ -267,7 +271,9 @@ static knot_rdata_t *knot_load_rdata(uint16_t type, FILE *f, desc->wireformat[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME || desc->wireformat[i] == KNOT_RDATA_WF_LITERAL_DNAME ) { - /* TODO maybe this does not need to be stored this big*/ + /*!< \todo #1686 + * Refactor these variables, some might be too big. + */ uint32_t dname_id = 0; uint8_t has_wildcard = 0; @@ -321,8 +327,9 @@ static knot_rdata_t *knot_load_rdata(uint16_t type, FILE *f, load_rdata_purge(rdata, items, i, desc, type); return NULL; } - - items[i].raw_data = + + /*!< \todo this is not proper fix, see #1678 */ + items[i].raw_data = (uint16_t *) malloc(sizeof(uint8_t) * (raw_data_length + 2)); items[i].raw_data[0] = raw_data_length; @@ -441,35 +448,60 @@ static knot_rrset_t *knot_load_rrset(FILE *f, knot_dname_t **id_array, } if (!fread_wrapper(&rrset_type, sizeof(rrset_type), 1, f)) { + if (!use_ids) { + knot_dname_free(&owner); + } return NULL; } dbg_zload("Zone load: rrset load: type: %u\n", rrset_type); if (!fread_wrapper(&rrset_class, sizeof(rrset_class), 1, f)) { + if (!use_ids) { + knot_dname_free(&owner); + } return NULL; } dbg_zload("Zone load: rrset class: type: %u\n", rrset_class); if (!fread_wrapper(&rrset_ttl, sizeof(rrset_ttl), 1, f)) { + if (!use_ids) { + knot_dname_free(&owner); + } return NULL; } dbg_zload("Zone load: rrset ttl: type: %u\n", rrset_ttl); if (!fread_wrapper(&rdata_count, sizeof(rdata_count), 1, f)) { + if (!use_ids) { + knot_dname_free(&owner); + } return NULL; } dbg_zload("Zone load: rrset load: rdata count: %u\n", rdata_count); if (!fread_wrapper(&rrsig_count, sizeof(rrsig_count), 1, f)) { + if (!use_ids) { + knot_dname_free(&owner); + } return NULL; } dbg_zload("Zone load: rrset load: type: %u\n", rrset_type); +dbg_zload_exec_detail( + char *name = knot_dname_to_str(owner); dbg_zload("Loading RRSet owned by: %s\n", - knot_dname_to_str(owner)); + name); + free(name); +); rrset = knot_rrset_new(owner, rrset_type, rrset_class, rrset_ttl); + + if (rrset == NULL) { + dbg_zload("zload: load_rrset: Could not create rrset."); + knot_dname_free(&owner); + return NULL; + } if (!use_ids) { /* Directly release if allocated locally. */ knot_dname_release(owner); - owner = 0; + owner = NULL; } dbg_zload("RRSet type: %d\n", rrset->type); @@ -581,7 +613,9 @@ static knot_node_t *knot_load_node(FILE *f, knot_dname_t **id_array) for (int i = 0; i < rrset_count; i++) { if ((tmp_rrset = knot_load_rrset(f, id_array, 1)) == NULL) { knot_node_free(&node, 0); - //TODO what else to free? + /*!< \todo #1686 + * Refactor freeing, might not be enough. + */ fprintf(stderr, "zone: Could not load rrset.\n"); return NULL; } @@ -697,11 +731,12 @@ static unsigned long calculate_crc(FILE *f) int knot_zload_open(zloader_t **dst, const char *filename) { - *dst = 0; if (!dst || !filename) { return KNOT_EBADARG; } + *dst = 0; + fread_wrapper = fread_safe_from_file; /* Open file for binary read. */ @@ -727,7 +762,7 @@ int knot_zload_open(zloader_t **dst, const char *filename) memcpy(crc_path, filename, sizeof(char) * strlen(filename)); - crc_path = strcat(crc_path, ".crc"); + crc_path = strncat(crc_path, ".crc", strlen(".crc")); FILE *f_crc = fopen(crc_path, "r"); if (unlikely(!f_crc)) { dbg_zload("knot_zload_open: failed to open '%s'\n", @@ -738,7 +773,7 @@ int knot_zload_open(zloader_t **dst, const char *filename) } unsigned long crc_from_file = 0; - if (fscanf(f_crc, "%lu\n", &crc_from_file) != 1) { + if (fscanf(f_crc, "%64lu\n", &crc_from_file) != 1) { dbg_zload("knot_zload_open: could not read " "CRC from file '%s'\n", crc_path); @@ -893,12 +928,13 @@ static knot_dname_t **create_dname_array(FILE *f, uint max_id) knot_dname_t **array = malloc(sizeof(knot_dname_t *) * ( max_id + 1)); - memset(array, 0, sizeof(knot_dname_t *) * (max_id + 1)); if (array == NULL) { ERR_ALLOC_FAILED; return NULL; } + memset(array, 0, sizeof(knot_dname_t *) * (max_id + 1)); + for (uint i = 0; i < max_id - 1; i++) { knot_dname_t *read_dname = read_dname_with_id(f); if (read_dname == NULL) { @@ -948,14 +984,6 @@ knot_zone_t *knot_zload_load(zloader_t *loader) knot_node_t *tmp_node; - /* Load the dname table. */ - /* CLEANUP */ -// const knot_dname_table_t *dname_table = -// create_dname_table(f, total_dnames); -// if (dname_table == NULL) { -// return NULL; -// } - uint32_t node_count; uint32_t nsec3_node_count; uint32_t auth_node_count; @@ -997,6 +1025,7 @@ knot_zone_t *knot_zload_load(zloader_t *loader) if (dname_table == NULL) { ERR_ALLOC_FAILED; cleanup_id_array(id_array, 1, total_dnames); + free(dname_table); return NULL; } @@ -1007,6 +1036,7 @@ knot_zone_t *knot_zload_load(zloader_t *loader) loader->filename); cleanup_id_array(id_array, 1, node_count + nsec3_node_count + 1); + free(dname_table); return NULL; } @@ -1017,6 +1047,8 @@ knot_zone_t *knot_zload_load(zloader_t *loader) cleanup_id_array(id_array, 1, node_count + nsec3_node_count + 1); dbg_zload("Failed to create new zone from apex!\n"); + knot_node_free(&apex, 0); + free(dname_table); return NULL; } @@ -1026,8 +1058,6 @@ knot_zone_t *knot_zload_load(zloader_t *loader) /* Assign dname table to the new zone. */ contents->dname_table = dname_table; - /* CLEANUP */ -// apex->prev = NULL; knot_node_set_previous(apex, NULL); knot_node_t *last_node = 0; @@ -1049,8 +1079,6 @@ knot_zone_t *knot_zload_load(zloader_t *loader) } knot_node_set_previous(tmp_node, last_node); - /* CLEANUP */ -// tmp_node->prev = last_node; if (tmp_node->rrset_count && (knot_node_is_deleg_point(tmp_node) || @@ -1083,16 +1111,12 @@ knot_zone_t *knot_zload_load(zloader_t *loader) fprintf(stderr, "!! cannot add first nsec3 node, " "exiting.\n"); knot_zone_deep_free(&zone, 0); - free(id_array); - /* TODO this will leak dnames from id_array that were - * not assigned. */ + cleanup_id_array(id_array, node_count + 1, + nsec3_node_count + 1); return NULL; } knot_node_set_previous(nsec3_first, NULL); - /* CLEANUP */ -// nsec3_first->prev = NULL; - last_node = nsec3_first; } @@ -1107,8 +1131,6 @@ knot_zone_t *knot_zload_load(zloader_t *loader) } knot_node_set_previous(tmp_node, last_node); - /* CLEANUP */ -// tmp_node->prev = last_node; last_node = tmp_node; } else { @@ -1120,8 +1142,6 @@ knot_zone_t *knot_zload_load(zloader_t *loader) if (nsec3_node_count) { assert(knot_node_previous(nsec3_first) == NULL); knot_node_set_previous(nsec3_first, last_node); - /* CLEANUP */ -// nsec3_first->prev = last_node; } /* ID array is now useless */ @@ -1133,12 +1153,6 @@ knot_zone_t *knot_zload_load(zloader_t *loader) dbg_zload("zone loaded, returning: %p\n", zone); -// knot_zone_contents_integrity_check(zone->contents); - - //knot_dname_table_dump(zone->contents->dname_table); - - //knot_zone_contents_dump(zone->contents); - return zone; } diff --git a/src/libknot/dname.c b/src/libknot/dname.c index e4b7d5f..0ab3d11 100644 --- a/src/libknot/dname.c +++ b/src/libknot/dname.c @@ -500,8 +500,19 @@ knot_dname_t *knot_dname_parse_from_wire(const uint8_t *wire, if (knot_wire_is_pointer(wire + p)) { // pointer. + // printf("Pointer.\n"); - p = knot_wire_get_pointer(wire + p); + size_t ptr = knot_wire_get_pointer(wire + p); + + /* Check that the pointer points backwards + * otherwise it could result in infinite loop + */ + if (ptr >= p) { + return NULL; + } + + p = ptr; + if (!pointer_used) { *pos += 2; pointer_used = 1; @@ -817,9 +828,9 @@ knot_dname_t *knot_dname_left_chop(const knot_dname_t *dname) void knot_dname_left_chop_no_copy(knot_dname_t *dname) { // copy the name - short first_label_length = dname->labels[1]; - if (dname->label_count > 1) { + short first_label_length = dname->labels[1]; + memmove(dname->name, &dname->name[dname->labels[1]], dname->size - first_label_length); // adjust labels diff --git a/src/libknot/dname.h b/src/libknot/dname.h index bb5e2db..5a182ae 100644 --- a/src/libknot/dname.h +++ b/src/libknot/dname.h @@ -45,15 +45,17 @@ struct knot_node; struct knot_dname { ref_t ref; /*!< Reference counting. */ uint8_t *name; /*!< Wire format of the domain name. */ + uint8_t *labels; + struct knot_node *node; /*!< Zone node the domain name belongs to. */ + unsigned int id; /*!< ID of domain name used in zone dumping. */ + /*! * \brief Size of the domain name in octets. * \todo Is this needed? Every dname should end with \0 or pointer. */ unsigned int size; - uint8_t *labels; + unsigned short label_count; - struct knot_node *node; /*!< Zone node the domain name belongs to. */ - unsigned int id; /*!< ID of domain name used in zone dumping. */ }; typedef struct knot_dname knot_dname_t; diff --git a/src/libknot/edns.c b/src/libknot/edns.c index 435e27c..d12861c 100644 --- a/src/libknot/edns.c +++ b/src/libknot/edns.c @@ -428,9 +428,9 @@ void knot_edns_free_options(knot_opt_rr_t *opt_rr) if (opt_rr->option_count > 0) { /* Free the option data, if any. */ for (int i = 0; i < opt_rr->option_count; i++) { - struct knot_opt_option option = opt_rr->options[i]; - if (option.data != NULL) { - free(option.data); + knot_opt_option_t *option = &(opt_rr->options[i]); + if (option->data != NULL) { + free(option->data); } } free(opt_rr->options); diff --git a/src/libknot/hash/cuckoo-hash-table.c b/src/libknot/hash/cuckoo-hash-table.c index 6688a40..73d1980 100644 --- a/src/libknot/hash/cuckoo-hash-table.c +++ b/src/libknot/hash/cuckoo-hash-table.c @@ -732,6 +732,7 @@ ck_hash_table_t *ck_create_table(uint items) if (table->table_size_exp == 0) { dbg_ck("Failed to count exponent of the hash table.\n"); + free(table); return NULL; } @@ -970,6 +971,8 @@ int ck_insert_item(ck_hash_table_t *table, const char *key, dbg_ck("Table is full, resize needed.\n"); if (ck_resize_table(table) != 0) { dbg_ck("Failed to resize hash table!\n"); + free(new_item); + pthread_mutex_unlock(&table->mtx_table); return -1; } } @@ -994,6 +997,8 @@ int ck_insert_item(ck_hash_table_t *table, const char *key, dbg_ck("Stash is full, resize needed.\n"); if (ck_resize_table(table) != 0) { dbg_ck("Failed to resize hash table!\n"); + /*! \todo Shouldn't 'new_item' be freed? */ + pthread_mutex_unlock(&table->mtx_table); return -1; } } @@ -1332,35 +1337,48 @@ int ck_deep_copy(ck_hash_table_t *from, ck_hash_table_t **to) } dbg_ck("Copying stash item: %p with item %p, ", si, si->item); - dbg_ck("key: %.*s\n", (int)si->item->key_length, si->item->key); +// dbg_ck("key: %.*s\n", (int)si->item->key_length, si->item->key); - si_new->item = (ck_hash_table_item_t *) - malloc(sizeof(ck_hash_table_item_t)); + if (si->item == NULL) { + si_new->item = NULL; + si_new->next = NULL; + } else { + si_new->item = (ck_hash_table_item_t *) + malloc(sizeof(ck_hash_table_item_t)); - if (si_new->item == NULL) { - ERR_ALLOC_FAILED; - ck_deep_copy_cleanup(*to, (*to)->table_count); - return -2; - } + if (si_new->item == NULL) { + ERR_ALLOC_FAILED; + free(si_new); + ck_deep_copy_cleanup(*to, (*to)->table_count); + return -2; + } - memcpy(si_new->item, si->item, sizeof(ck_hash_table_item_t)); + memcpy(si_new->item, si->item, + sizeof(ck_hash_table_item_t)); + si_new->next = NULL; + } *pos = si_new; pos = &si_new->next; si = si->next; - +dbg_ck_exec( dbg_ck("Old stash item: %p with item %p, ", si, ((si == NULL) ? NULL : si->item)); - if (si != NULL) { - dbg_ck("key: %.*s\n", (int)si->item->key_length, si->item->key); + if (si != NULL && si->item != NULL) { + dbg_ck("key: %.*s\n", (int)si->item->key_length, + si->item->key); } else { dbg_ck("\n"); } dbg_ck("New stash item: %p with item %p, ", si_new, - si_new->item); + (si_new) ? si_new->item : NULL); + + assert(si_new != NULL); + assert(si_new->item != NULL); dbg_ck("key: %.*s\n", (int)si_new->item->key_length, si_new->item->key); +); } *pos = NULL; diff --git a/src/libknot/nameserver/name-server.c b/src/libknot/nameserver/name-server.c index 547a629..dea16ec 100644 --- a/src/libknot/nameserver/name-server.c +++ b/src/libknot/nameserver/name-server.c @@ -625,6 +625,8 @@ static void ns_put_authority_ns(const knot_zone_contents_t *zone, static int ns_put_authority_soa(const knot_zone_contents_t *zone, knot_packet_t *resp) { + int ret; + knot_rrset_t *soa_rrset = knot_node_get_rrset( knot_zone_contents_apex(zone), KNOT_RRTYPE_SOA); assert(soa_rrset != NULL); @@ -634,7 +636,12 @@ static int ns_put_authority_soa(const knot_zone_contents_t *zone, uint32_t min = knot_rdata_soa_minimum(knot_rrset_rdata(soa_rrset)); if (min < knot_rrset_ttl(soa_rrset)) { knot_rrset_t *soa_copy = NULL; - knot_rrset_deep_copy(soa_rrset, &soa_copy); + ret = knot_rrset_deep_copy(soa_rrset, &soa_copy); + + if (ret != KNOT_EOK) { + return ret; + } + CHECK_ALLOC_LOG(soa_copy, KNOT_ENOMEM); knot_rrset_set_ttl(soa_copy, min); @@ -643,13 +650,15 @@ static int ns_put_authority_soa(const knot_zone_contents_t *zone, assert(soa_rrset != NULL); - int ret = knot_response_add_rrset_authority(resp, soa_rrset, 0, 0, 0, 1); - if (ret == KNOT_EOK) { - ret = ns_add_rrsigs(soa_rrset, resp, - knot_node_owner(knot_zone_contents_apex(zone)), - knot_response_add_rrset_authority, 1); + ret = knot_response_add_rrset_authority(resp, soa_rrset, 0, 0, 0, 1); + if (ret != KNOT_EOK) { + return ret; } + ret = ns_add_rrsigs(soa_rrset, resp, + knot_node_owner(knot_zone_contents_apex(zone)), + knot_response_add_rrset_authority, 1); + return ret; } @@ -2690,6 +2699,48 @@ knot_nameserver_t *knot_ns_create() /*----------------------------------------------------------------------------*/ +static int knot_ns_replace_nsid(knot_opt_rr_t *opt_rr, const char *nsid, + size_t len) +{ + assert(opt_rr != NULL); + if (nsid == NULL || len == 0) { + return KNOT_EOK; + } + + int found = 0; + int i = 0; + + while (i < opt_rr->option_count && !found) { + if (opt_rr->options[i].code == EDNS_OPTION_NSID) { + found = 1; + } else { + ++i; + } + } + + if (found) { + uint8_t *new_data = (uint8_t *)malloc(len); + if (new_data == NULL) { + return KNOT_ENOMEM; + } + + memcpy(new_data, nsid, len); + uint8_t *old = opt_rr->options[i].data; + + opt_rr->options[i].data = new_data; + opt_rr->options[i].length = len; + + free(old); + + return KNOT_EOK; + } else { + return knot_edns_add_option(opt_rr, EDNS_OPTION_NSID, + len, (const uint8_t *)nsid); + } +} + +/*----------------------------------------------------------------------------*/ + void knot_ns_set_nsid(knot_nameserver_t *nameserver, const char *nsid, size_t len) { if (nameserver == NULL) { @@ -2702,8 +2753,10 @@ void knot_ns_set_nsid(knot_nameserver_t *nameserver, const char *nsid, size_t le return; } - int ret = knot_edns_add_option(nameserver->opt_rr, EDNS_OPTION_NSID, - len, (const uint8_t *)nsid); + int ret = knot_ns_replace_nsid(nameserver->opt_rr, nsid, len); + +// int ret = knot_edns_add_option(nameserver->opt_rr, EDNS_OPTION_NSID, +// len, (const uint8_t *)nsid); if (ret != KNOT_EOK) { dbg_ns("NS: set_nsid: could not add EDNS option.\n"); return; @@ -3326,7 +3379,7 @@ int knot_ns_process_axfrin(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) } // save the zone contents to the xfr->data - xfr->data = zone; + xfr->new_contents = zone; xfr->flags |= XFR_FLAG_AXFR_FINISHED; assert(zone->nsec3_nodes != NULL); @@ -3338,12 +3391,10 @@ int knot_ns_process_axfrin(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) //knot_zone_contents_dump(zone, 0); // check zone integrity -#ifdef KNOT_XFRIN_DEBUG -#ifdef DEBUG_ENABLE_BRIEF +dbg_xfrin_exec( int errs = knot_zone_contents_integrity_check(zone); - dbg_ns("Zone integrity check: %d errors.\n", errs); -#endif -#endif + dbg_xfrin("Zone integrity check: %d errors.\n", errs); +); } /*! @@ -3358,13 +3409,17 @@ int knot_ns_process_axfrin(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) int knot_ns_switch_zone(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) { - if (xfr == NULL || nameserver == NULL || xfr->data == NULL) { + if (xfr == NULL || nameserver == NULL || xfr->new_contents == NULL) { return KNOT_EBADARG; } - knot_zone_contents_t *zone = (knot_zone_contents_t *)xfr->data; + knot_zone_contents_t *zone = (knot_zone_contents_t *)xfr->new_contents; dbg_ns("Replacing zone by new one: %p\n", zone); + if (zone == NULL) { + dbg_ns("No new zone!\n"); + return KNOT_ENOZONE; + } // find the zone in the zone db knot_zone_t *z = knot_zonedb_find_zone(nameserver->zone_db, @@ -3375,32 +3430,17 @@ int knot_ns_switch_zone(knot_nameserver_t *nameserver, dbg_ns("Failed to replace zone %s, old zone " "not found\n", name); free(name); + + return KNOT_ENOZONE; } else { zone->zone = z; } - knot_zone_contents_t *old = rcu_xchg_pointer(&z->contents, zone); - -// knot_zone_t *old = knot_zonedb_replace_zone(nameserver->zone_db, -// zone); - dbg_ns("Old zone: %p\n", old); -// if (old == NULL) { -// char *name = knot_dname_to_str( -// knot_node_owner(knot_zone_apex(zone))); -// dbg_ns("Failed to replace zone %s\n", name); -// free(name); -// } - - // wait for readers to finish - dbg_ns("Waiting for readers to finish...\n"); - synchronize_rcu(); - // destroy the old zone - dbg_ns("Freeing old zone: %p\n", old); - knot_zone_contents_deep_free(&old, 0); + int ret = xfrin_switch_zone(z, zone, xfr->type); dbg_ns_exec( dbg_ns("Zone db contents: (zone count: %zu)\n", - nameserver->zone_db->zone_count); + nameserver->zone_db->zone_count); const knot_zone_t **zones = knot_zonedb_zones(nameserver->zone_db); for (int i = 0; i < knot_zonedb_zone_count @@ -3413,7 +3453,7 @@ dbg_ns_exec( free(zones); ); - return KNOT_EOK; + return ret; } /*----------------------------------------------------------------------------*/ @@ -3654,6 +3694,7 @@ int knot_ns_process_update(knot_nameserver_t *nameserver, knot_packet_t *query, * Maybe only this case will be EOK, other cases some error. */ + knot_ddns_prereqs_free(&prereqs); knot_packet_free(&response); return KNOT_EOK; } diff --git a/src/libknot/nameserver/name-server.h b/src/libknot/nameserver/name-server.h index 3bf9552..8ec3e50 100644 --- a/src/libknot/nameserver/name-server.h +++ b/src/libknot/nameserver/name-server.h @@ -103,6 +103,8 @@ typedef struct knot_ns_xfr { knot_zone_t *zone; char* zname; void *owner; + knot_zone_contents_t *new_contents; + char *msgpref; /*! \note [TSIG] TSIG fields */ /*! \brief Message(s) to sign in wireformat. diff --git a/src/libknot/packet/response.c b/src/libknot/packet/response.c index c9f2ba7..3c7236e 100644 --- a/src/libknot/packet/response.c +++ b/src/libknot/packet/response.c @@ -454,7 +454,6 @@ dbg_response_exec( * It is meaningful only if the found name is the one from QNAME * and thus its parents are not stored yet. */ - assert(compr->wire_pos >= 0); if (knot_response_store_dname_pos(compr->table, dname, not_matched, compr->wire_pos, offset, compr_cs) diff --git a/src/libknot/rdata.c b/src/libknot/rdata.c index 51a1a70..8e9e8c1 100644 --- a/src/libknot/rdata.c +++ b/src/libknot/rdata.c @@ -147,6 +147,47 @@ static const knot_dname_t *knot_rdata_srv_name(const knot_rdata_t *rdata) } /*----------------------------------------------------------------------------*/ + +static void knot_rdata_free_items(knot_rdata_item_t *items, unsigned int count, + uint type, int free_all_dnames) +{ + if (items == NULL) { + return; + } + + knot_rrtype_descriptor_t *desc = knot_rrtype_descriptor_by_type(type); + assert(desc != NULL); + + assert(count <= desc->length); + + for (int i = 0; i < count; i++) { + if (&(items[i]) == NULL) { + continue; + } + if (desc->wireformat[i] == KNOT_RDATA_WF_COMPRESSED_DNAME + || desc->wireformat[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME + || desc->wireformat[i] == KNOT_RDATA_WF_LITERAL_DNAME) { + if ((items[i].dname != NULL)) { + /*! \todo This is hack to prevent memory errors, + * as the rdata_set_items() cannot determine + * items type and so cannot increment + * reference count in case of dname type. + * Free would then release dnames that + * aren't referenced by the rdata. + */ + if (free_all_dnames) { + knot_dname_release(items[i].dname); + } + } + } else { + free(items[i].raw_data); + } + } + + free(items); +} + +/*----------------------------------------------------------------------------*/ /* API functions */ /*----------------------------------------------------------------------------*/ @@ -272,14 +313,17 @@ int knot_rdata_from_wire(knot_rdata_t *rdata, const uint8_t *wire, dname = knot_dname_parse_from_wire( wire, &pos2, total_size, NULL); if (dname == NULL) { + knot_rdata_free_items(items, i, + desc->type, 1); return KNOT_ERROR; } items[i].raw_data = (uint16_t *)malloc( knot_dname_size(dname) + 2); if (items[i].raw_data == NULL) { - /*! \todo This will leak. */ - free(items); + knot_dname_free(&dname); + knot_rdata_free_items(items, i, + desc->type, 1); return KNOT_ENOMEM; } @@ -307,21 +351,23 @@ int knot_rdata_from_wire(knot_rdata_t *rdata, const uint8_t *wire, break; default: + knot_rdata_free_items(items, i, + desc->type, 1); return KNOT_EMALF; } if (item_size != 0) { if (parsed + item_size > rdlength) { - /*! \todo This will leak a lot. */ - free(items); + knot_rdata_free_items(items, i, + desc->type, 1); return KNOT_EFEWDATA; } items[i].raw_data = (uint16_t *)malloc(item_size + 2); if (items[i].raw_data == NULL) { - free(items); - /*! \todo This will also leak a lot. */ + knot_rdata_free_items(items, i, + desc->type, 1); return KNOT_ENOMEM; } memcpy(items[i].raw_data, &item_size, 2); @@ -335,7 +381,8 @@ int knot_rdata_from_wire(knot_rdata_t *rdata, const uint8_t *wire, // and should create an empty RDATA item items[i].raw_data = (uint16_t *)malloc(2); if (items[i].raw_data == NULL) { - free(items); + knot_rdata_free_items(items, i, + desc->type, 1); return KNOT_ENOMEM; } memcpy(items[i].raw_data, &item_size, 2); @@ -494,39 +541,9 @@ void knot_rdata_deep_free(knot_rdata_t **rdata, uint type, return; } - knot_rrtype_descriptor_t *desc = - knot_rrtype_descriptor_by_type(type); - assert(desc != NULL); - - assert((*rdata)->count <= desc->length); - - for (int i = 0; i < (*rdata)->count; i++) { - if (&((*rdata)->items[i]) == NULL) { - continue; - } - if (desc->wireformat[i] == KNOT_RDATA_WF_COMPRESSED_DNAME - || desc->wireformat[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME - || desc->wireformat[i] == KNOT_RDATA_WF_LITERAL_DNAME ) { - if (((*rdata)->items[i].dname != NULL)) { - /*! \todo This is hack to prevent memory errors, - * as the rdata_set_items() cannot determine - * items type and so cannot increment - * reference count in case of dname type. - * Free would then release dnames that - * aren't referenced by the rdata. - */ - if (free_all_dnames) { - knot_dname_release((*rdata)->items[i].dname); - } - } - } else { - free((*rdata)->items[i].raw_data); - } - } + knot_rdata_free_items((*rdata)->items, (*rdata)->count, type, + free_all_dnames); - if ((*rdata)->items) { - free((*rdata)->items); - } free(*rdata); *rdata = NULL; } diff --git a/src/libknot/rrset.c b/src/libknot/rrset.c index d968378..d665c63 100644 --- a/src/libknot/rrset.c +++ b/src/libknot/rrset.c @@ -353,8 +353,8 @@ int knot_rrset_compare_rdata(const knot_rrset_t *r1, const knot_rrset_t *r2) } if (rdata2 == NULL) { - // RDATA from r1 not found in r2 - return 0; + // RDATA from r1 not found in r2 + return 0; } // otherwise it was found, continue with next r1 RDATA @@ -365,14 +365,16 @@ int knot_rrset_compare_rdata(const knot_rrset_t *r1, const knot_rrset_t *r2) rdata2 = knot_rrset_rdata(r2); while (rdata2 != NULL) { rdata1 = knot_rrset_rdata(r1); - while (rdata2 != NULL && knot_rdata_compare(rdata1, rdata2, - desc->wireformat)) { + + while (rdata2 != NULL && rdata1 != NULL + && knot_rdata_compare(rdata1, rdata2, + desc->wireformat)) { rdata1 = knot_rrset_rdata_next(r1, rdata1); } if (rdata1 == NULL) { - // RDATA from r1 not found in r2 - return 0; + // RDATA from r2 not found in r1 + return 0; } // otherwise it was found, continue with next r1 RDATA @@ -630,7 +632,7 @@ int knot_rrset_shallow_copy(const knot_rrset_t *from, knot_rrset_t **to) void knot_rrset_rotate(knot_rrset_t *rrset) { - rrset->rdata = rrset->rdata->next; + //rrset->rdata = rrset->rdata->next; } /*----------------------------------------------------------------------------*/ diff --git a/src/libknot/tsig-op.c b/src/libknot/tsig-op.c index bdaf083..148fc87 100644 --- a/src/libknot/tsig-op.c +++ b/src/libknot/tsig-op.c @@ -19,7 +19,6 @@ #include <openssl/hmac.h> #include <openssl/evp.h> #include <time.h> -#include <ctype.h> #include "common.h" #include "tsig.h" @@ -573,7 +572,6 @@ int knot_tsig_sign(uint8_t *msg, size_t *msg_len, if (ret != KNOT_EOK) { dbg_tsig("TSIG: could not create wire or sign wire: %s\n", knot_strerror(ret)); - free(items); knot_rrset_free(&tmp_tsig); knot_rdata_free(&rdata); @@ -593,7 +591,6 @@ int knot_tsig_sign(uint8_t *msg, size_t *msg_len, if (ret != KNOT_EOK) { dbg_tsig_detail("TSIG: rrset_to_wire = %s\n", knot_strerror(ret)); *digest_len = 0; - free(items); knot_rrset_free(&tmp_tsig); knot_rdata_free(&rdata); return ret; @@ -983,7 +980,7 @@ int knot_tsig_add(uint8_t *msg, size_t *msg_len, size_t msg_max_len, knot_rdata_item_t *items = malloc(sizeof(knot_rdata_item_t) * desc->length); - if (!items) { + if (items == NULL) { dbg_tsig_detail("TSIG: items = NULL\n"); ERR_ALLOC_FAILED; knot_rrset_deep_free(&tmp_tsig, 1, 1, 1); @@ -993,18 +990,19 @@ int knot_tsig_add(uint8_t *msg, size_t *msg_len, size_t msg_max_len, memset(items, 0, sizeof(knot_rdata_item_t) * desc->length); int ret = knot_rdata_set_items(rdata, items, desc->length); + free(items); if (ret != KNOT_EOK) { dbg_tsig_detail("TSIG: rdata_set_items returned %s\n", knot_strerror(ret)); knot_rrset_deep_free(&tmp_tsig, 1, 1, 1); return ret; } - free(items); knot_dname_t *alg_name = knot_dname_deep_copy(tsig_rdata_alg_name(tsig_rr)); if (alg_name == NULL) { dbg_tsig_detail("TSIG: failed to copy alg name\n"); + knot_rrset_deep_free(&tmp_tsig, 1, 1, 1); return KNOT_ERROR; } @@ -1012,6 +1010,7 @@ int knot_tsig_add(uint8_t *msg, size_t *msg_len, size_t msg_max_len, tsig_rdata_set_time_signed(tmp_tsig, tsig_rdata_time_signed(tsig_rr)); tsig_rdata_set_fudge(tmp_tsig, tsig_rdata_fudge(tsig_rr)); tsig_rdata_set_mac(tmp_tsig, 0, NULL); + knot_dname_release(alg_name); /* Already copied in tsig_rdata_set_alg_name() */ /* Set original ID */ tsig_rdata_set_orig_id(tmp_tsig, knot_wire_get_id(msg)); @@ -1036,6 +1035,7 @@ int knot_tsig_add(uint8_t *msg, size_t *msg_len, size_t msg_max_len, } knot_rrset_deep_free(&tmp_tsig, 1, 1, 1); + knot_dname_release(key_name); *msg_len += tsig_wire_len; diff --git a/src/libknot/tsig.c b/src/libknot/tsig.c index 5790b68..e9da295 100644 --- a/src/libknot/tsig.c +++ b/src/libknot/tsig.c @@ -331,16 +331,13 @@ tsig_algorithm_t tsig_rdata_alg(const knot_rrset_t *tsig) } knot_lookup_table_t *item = knot_lookup_by_name(tsig_alg_table, name); + free(name); if (!item) { dbg_tsig_detail("TSIG: rdata: unknown algorithm.\n"); return KNOT_TSIG_ALG_NULL; } - free(name); - - int id = item->id; - - return id; + return item->id; } uint64_t tsig_rdata_time_signed(const knot_rrset_t *tsig) diff --git a/src/libknot/updates/changesets.c b/src/libknot/updates/changesets.c index cf9e6a0..1c3d3b9 100644 --- a/src/libknot/updates/changesets.c +++ b/src/libknot/updates/changesets.c @@ -287,6 +287,8 @@ void knot_free_changesets(knot_changesets_t **changesets) knot_rrset_deep_free(&(*changesets)->first_soa, 1, 1, 1); + assert((*changesets)->changes == NULL); + free(*changesets); *changesets = NULL; } diff --git a/src/libknot/updates/changesets.h b/src/libknot/updates/changesets.h index e8d5e39..0570fc9 100644 --- a/src/libknot/updates/changesets.h +++ b/src/libknot/updates/changesets.h @@ -28,6 +28,7 @@ #define _KNOT_CHANGESETS_H_ #include "rrset.h" +#include "zone/node.h" /*! \todo Changeset must be serializable/deserializable, so * all data and pointers have to be changeset-exclusive, @@ -57,10 +58,58 @@ typedef struct { /*----------------------------------------------------------------------------*/ typedef struct { + /*! + * Deleted (without owners and RDATA) after successful update. + */ + knot_rrset_t **old_rrsets; + int old_rrsets_count; + int old_rrsets_allocated; + + /*! + * Deleted after successful update. + */ + knot_rdata_t **old_rdata; + unsigned *old_rdata_types; + int old_rdata_count; + int old_rdata_allocated; + + /*! + * \brief Copied RRSets (i.e. modified by the update). + * + * Deleted (without owners and RDATA) after failed update. + */ + knot_rrset_t **new_rrsets; + int new_rrsets_count; + int new_rrsets_allocated; + + /*! + * Deleted after failed update. + */ + knot_rdata_t **new_rdata; + unsigned *new_rdata_types; + int new_rdata_count; + int new_rdata_allocated; + +// /*! +// * Deleted (without contents) after successful update. +// */ + knot_node_t **old_nodes; + int old_nodes_count; + int old_nodes_allocated; + + knot_node_t **old_nsec3; + int old_nsec3_count; + int old_nsec3_allocated; +} knot_changes_t; + +/*----------------------------------------------------------------------------*/ + +typedef struct { knot_changeset_t *sets; size_t count; size_t allocated; knot_rrset_t *first_soa; + knot_changes_t *changes; } knot_changesets_t; /*----------------------------------------------------------------------------*/ diff --git a/src/libknot/updates/xfr-in.c b/src/libknot/updates/xfr-in.c index c1ea13d..f411e47 100644 --- a/src/libknot/updates/xfr-in.c +++ b/src/libknot/updates/xfr-in.c @@ -22,13 +22,10 @@ #include "nameserver/name-server.h" #include "util/wire.h" #include "util/debug.h" -// #include "knot/zone/zone-dump.h" -// #include "knot/zone/zone-load.h" #include "packet/packet.h" #include "dname.h" #include "zone/zone.h" #include "packet/query.h" -#include "packet/response.h" #include "util/error.h" #include "updates/changesets.h" #include "tsig.h" @@ -174,6 +171,8 @@ int xfrin_transfer_needed(const knot_zone_contents_t *zone, if (soa_response->parsed < soa_response->size) { ret = knot_packet_parse_rest(soa_response); if (ret != KNOT_EOK) { + dbg_xfrin_verb("knot_packet_parse_rest() returned %s\n", + knot_strerror(ret)); return KNOT_EMALF; } } @@ -403,6 +402,7 @@ static int xfrin_check_tsig(knot_packet_t *packet, knot_ns_xfr_t *xfr, if (ret != KNOT_EOK) { /*! \note [TSIG] No need to check TSIG error * here, propagate and check elsewhere.*/ + knot_rrset_deep_free(&tsig, 1, 1, 1); return ret; } @@ -412,6 +412,7 @@ static int xfrin_check_tsig(knot_packet_t *packet, knot_ns_xfr_t *xfr, // Extract the digest from the TSIG RDATA and store it. if (xfr->digest_max_size < tsig_rdata_mac_length(tsig)) { + knot_rrset_deep_free(&tsig, 1, 1, 1); return KNOT_ESPACE; } memcpy(xfr->digest, tsig_rdata_mac(tsig), @@ -429,6 +430,7 @@ static int xfrin_check_tsig(knot_packet_t *packet, knot_ns_xfr_t *xfr, }*/ } else if (tsig != NULL) { // TSIG where it should not be + knot_rrset_deep_free(&tsig, 1, 1, 1); return KNOT_EMALF; } @@ -630,7 +632,7 @@ dbg_xfrin_exec( while (ret == KNOT_EOK && rr != NULL) { // process the parsed RR - dbg_xfrin("\nNext RR:\n\n"); + dbg_rrset_detail("\nNext RR:\n\n"); knot_rrset_dump(rr, 0); if (node != NULL @@ -834,6 +836,7 @@ dbg_xfrin_exec( ret = knot_zone_contents_add_rrset(zone, rr, &node, KNOT_RRSET_DUPL_MERGE, 1); if (ret < 0) { + knot_packet_free(&packet); dbg_xfrin("Failed to add RRSet to zone:" "%s.\n", knot_strerror(ret)); return KNOT_ERROR; @@ -858,9 +861,12 @@ dbg_xfrin_exec( dbg_xfrin("Could not parse next RR: %s.\n", knot_strerror(ret)); knot_packet_free(&packet); - knot_node_free(&node, 0); + + if (!in_zone) { + knot_node_free(&node, 0); + } + knot_rrset_deep_free(&rr, 1, 1, 1); - /*! \todo Cleanup. */ return KNOT_EMALF; } @@ -903,8 +909,11 @@ dbg_xfrin_exec( static int xfrin_parse_first_rr(knot_packet_t **packet, const uint8_t *pkt, size_t size, knot_rrset_t **rr) { + assert(packet != NULL); + assert(rr != NULL); + *packet = knot_packet_new(KNOT_PACKET_PREALLOC_NONE); - if (packet == NULL) { + if (*packet == NULL) { dbg_xfrin("Could not create packet structure.\n"); return KNOT_ENOMEM; } @@ -1003,6 +1012,7 @@ int xfrin_process_ixfr_packet(knot_ns_xfr_t *xfr) // parse the next one ret = knot_packet_parse_next_rr_answer(packet, &rr); if (ret != KNOT_EOK) { + knot_packet_free(&packet); return ret; } @@ -1035,7 +1045,8 @@ int xfrin_process_ixfr_packet(knot_ns_xfr_t *xfr) } } else { if ((*chs)->first_soa == NULL) { - dbg_xfrin("Changesets don't contain frist SOA!\n"); + dbg_xfrin("Changesets don't contain SOA first!\n"); + knot_rrset_deep_free(&rr, 1, 1, 1); ret = KNOT_EBADARG; goto cleanup; } @@ -1211,8 +1222,9 @@ dbg_xfrin_exec( } } break; - default: - assert(0); + // dead code +// default: +// assert(0); } // parse the next RR @@ -1254,53 +1266,6 @@ cleanup: /* Applying changesets to zone */ /*----------------------------------------------------------------------------*/ -typedef struct { - /*! - * Deleted (without owners and RDATA) after successful update. - */ - knot_rrset_t **old_rrsets; - int old_rrsets_count; - int old_rrsets_allocated; - - /*! - * Deleted after successful update. - */ - knot_rdata_t **old_rdata; - uint *old_rdata_types; - int old_rdata_count; - int old_rdata_allocated; - - /*! - * \brief Copied RRSets (i.e. modified by the update). - * - * Deleted (without owners and RDATA) after failed update. - */ - knot_rrset_t **new_rrsets; - int new_rrsets_count; - int new_rrsets_allocated; - - /*! - * Deleted after failed update. - */ - knot_rdata_t **new_rdata; - uint *new_rdata_types; - int new_rdata_count; - int new_rdata_allocated; - -// /*! -// * Deleted (without contents) after successful update. -// */ - knot_node_t **old_nodes; - int old_nodes_count; - int old_nodes_allocated; - - knot_node_t **old_nsec3; - int old_nsec3_count; - int old_nsec3_allocated; -} xfrin_changes_t; - -/*----------------------------------------------------------------------------*/ - static int xfrin_changes_check_rrsets(knot_rrset_t ***rrsets, int *count, int *allocated, int to_add) { @@ -1383,6 +1348,7 @@ static int xfrin_changes_check_rdata(knot_rdata_t ***rdatas, uint **types, uint *types_new = malloc(new_count * sizeof(uint)); if (types_new == NULL) { + free(rdatas_new); return KNOT_ENOMEM; } @@ -1405,6 +1371,36 @@ static int xfrin_changes_check_rdata(knot_rdata_t ***rdatas, uint **types, /*----------------------------------------------------------------------------*/ +static void xfrin_changes_add_rdata(knot_rdata_t **rdatas, uint *types, + int *count, knot_rdata_t *rdata, uint type) +{ + dbg_xfrin_detail("Adding RDATA to new RDATA list: %p\n", rdata); + +dbg_xfrin_exec_detail( + // try to find the first RDATA in the given list + for (int i = 0; i < *count; ++i) { + knot_rdata_t *r = rdatas[i]; + while (r->next != rdatas[i]) { + if (r == rdata) { + dbg_xfrin_detail("Found same RDATA: %p\n", rdata); + knot_rdata_dump(rdata, type, 0); + } + r = r->next; + } + if (r == rdata) { + dbg_xfrin_detail("Found same RDATA: %p\n", rdata); + knot_rdata_dump(rdata, type, 0); + } + } +); + + rdatas[*count] = rdata; + types[*count] = type; + ++*count; +} + +/*----------------------------------------------------------------------------*/ + static void xfrin_zone_contents_free(knot_zone_contents_t **contents) { /*! \todo This should be all in some API!! */ @@ -1456,7 +1452,7 @@ static knot_rdata_t *xfrin_remove_rdata(knot_rrset_t *from, /*----------------------------------------------------------------------------*/ static int xfrin_copy_old_rrset(knot_rrset_t *old, knot_rrset_t **copy, - xfrin_changes_t *changes) + knot_changes_t *changes) { // create new RRSet by copying the old one // int ret = knot_rrset_shallow_copy(old, copy); @@ -1489,21 +1485,21 @@ static int xfrin_copy_old_rrset(knot_rrset_t *old, knot_rrset_t **copy, } changes->new_rrsets[changes->new_rrsets_count++] = *copy; - changes->new_rdata[changes->new_rdata_count] = - knot_rrset_get_rdata(*copy); - changes->new_rdata_types[changes->new_rdata_count] = - knot_rrset_type(*copy); - ++changes->new_rdata_count; + + xfrin_changes_add_rdata(changes->new_rdata, changes->new_rdata_types, + &changes->new_rdata_count, + knot_rrset_get_rdata(*copy), + knot_rrset_type(*copy)); if ((*copy)->rrsigs != NULL) { assert(old->rrsigs != NULL); changes->new_rrsets[changes->new_rrsets_count++] = (*copy)->rrsigs; - changes->new_rdata[changes->new_rdata_count] = - knot_rrset_get_rdata((*copy)->rrsigs); - changes->new_rdata_types[changes->new_rdata_count] = - KNOT_RRTYPE_RRSIG; - ++changes->new_rdata_count; + xfrin_changes_add_rdata(changes->new_rdata, + changes->new_rdata_types, + &changes->new_rdata_count, + knot_rrset_get_rdata((*copy)->rrsigs), + KNOT_RRTYPE_RRSIG); } // add the old RRSet to the list of old RRSets @@ -1526,19 +1522,20 @@ static int xfrin_copy_old_rrset(knot_rrset_t *old, knot_rrset_t **copy, } changes->old_rrsets[changes->old_rrsets_count++] = old; - changes->old_rdata[changes->old_rdata_count] = old->rdata; - changes->old_rdata_types[changes->old_rdata_count] = - knot_rrset_type(old); - ++changes->old_rdata_count; + + xfrin_changes_add_rdata(changes->old_rdata, changes->old_rdata_types, + &changes->old_rdata_count, old->rdata, + knot_rrset_type(old)); if ((*copy)->rrsigs != NULL) { assert(old->rrsigs != NULL); changes->old_rrsets[changes->old_rrsets_count++] = old->rrsigs; - changes->old_rdata[changes->old_rdata_count] = - old->rrsigs->rdata; - changes->old_rdata_types[changes->old_rdata_count] = - KNOT_RRTYPE_RRSIG; - ++changes->old_rdata_count; + + xfrin_changes_add_rdata(changes->old_rdata, + changes->old_rdata_types, + &changes->old_rdata_count, + old->rrsigs->rdata, + KNOT_RRTYPE_RRSIG); } return KNOT_EOK; @@ -1547,7 +1544,7 @@ static int xfrin_copy_old_rrset(knot_rrset_t *old, knot_rrset_t **copy, /*----------------------------------------------------------------------------*/ static int xfrin_copy_rrset(knot_node_t *node, knot_rr_type_t type, - knot_rrset_t **rrset, xfrin_changes_t *changes) + knot_rrset_t **rrset, knot_changes_t *changes) { knot_rrset_t *old = knot_node_remove_rrset(node, type); @@ -1575,7 +1572,7 @@ static int xfrin_copy_rrset(knot_node_t *node, knot_rr_type_t type, /*----------------------------------------------------------------------------*/ -static int xfrin_apply_remove_rrsigs(xfrin_changes_t *changes, +static int xfrin_apply_remove_rrsigs(knot_changes_t *changes, const knot_rrset_t *remove, knot_node_t *node, knot_rrset_t **rrset) @@ -1662,10 +1659,9 @@ static int xfrin_apply_remove_rrsigs(xfrin_changes_t *changes, return ret; } - changes->old_rdata[changes->old_rdata_count] = rdata; - changes->old_rdata_types[changes->old_rdata_count] = - knot_rrset_type(remove); - ++changes->old_rdata_count; + xfrin_changes_add_rdata(changes->old_rdata, changes->old_rdata_types, + &changes->old_rdata_count, rdata, + knot_rrset_type(remove)); // if the RRSet is empty, remove from node and add to old RRSets // check if there is no RRSIGs; if there are, leave the RRSet @@ -1722,7 +1718,7 @@ static int xfrin_apply_remove_rrsigs(xfrin_changes_t *changes, /*----------------------------------------------------------------------------*/ -static int xfrin_apply_remove_normal(xfrin_changes_t *changes, +static int xfrin_apply_remove_normal(knot_changes_t *changes, const knot_rrset_t *remove, knot_node_t *node, knot_rrset_t **rrset) @@ -1800,10 +1796,9 @@ dbg_xfrin_exec_detail( return ret; } - changes->old_rdata[changes->old_rdata_count] = rdata; - changes->old_rdata_types[changes->old_rdata_count] = - knot_rrset_type(remove); - ++changes->old_rdata_count; + xfrin_changes_add_rdata(changes->old_rdata, changes->old_rdata_types, + &changes->old_rdata_count, rdata, + knot_rrset_type(remove)); // if the RRSet is empty, remove from node and add to old RRSets // check if there is no RRSIGs; if there are, leave the RRSet @@ -1838,7 +1833,7 @@ dbg_xfrin_exec_detail( /*----------------------------------------------------------------------------*/ -static int xfrin_apply_remove_all_rrsets(xfrin_changes_t *changes, +static int xfrin_apply_remove_all_rrsets(knot_changes_t *changes, knot_node_t *node, uint16_t type) { int ret; @@ -1923,7 +1918,7 @@ static knot_node_t *xfrin_add_new_node(knot_zone_contents_t *contents, /*----------------------------------------------------------------------------*/ -static int xfrin_apply_add_normal(xfrin_changes_t *changes, +static int xfrin_apply_add_normal(knot_changes_t *changes, knot_rrset_t *add, knot_node_t *node, knot_rrset_t **rrset, @@ -1994,7 +1989,6 @@ dbg_xfrin_exec( // knot_rrset_dump(*rrset, 1); ret = xfrin_copy_old_rrset(old, rrset, changes); if (ret != KNOT_EOK) { - assert(0); return ret; } @@ -2036,7 +2030,7 @@ dbg_xfrin_exec( /*----------------------------------------------------------------------------*/ -static int xfrin_apply_add_rrsig(xfrin_changes_t *changes, +static int xfrin_apply_add_rrsig(knot_changes_t *changes, knot_rrset_t *add, knot_node_t *node, knot_rrset_t **rrset, @@ -2178,45 +2172,48 @@ dbg_xfrin_exec( /*----------------------------------------------------------------------------*/ -static void xfrin_cleanup_update(xfrin_changes_t *changes) +void xfrin_cleanup_successful_update(knot_changes_t **changes) { - for (int i = 0; i < changes->old_rrsets_count; ++i) { + for (int i = 0; i < (*changes)->old_rrsets_count; ++i) { dbg_xfrin_detail("Deleting old RRSet: %p\n", - changes->old_rrsets[i]); - knot_rrset_dump(changes->old_rrsets[i], 0); - knot_rrset_free(&changes->old_rrsets[i]); + (*changes)->old_rrsets[i]); + knot_rrset_dump((*changes)->old_rrsets[i], 0); + knot_rrset_free(&(*changes)->old_rrsets[i]); } // delete old RDATA - for (int i = 0; i < changes->old_rdata_count; ++i) { + for (int i = 0; i < (*changes)->old_rdata_count; ++i) { dbg_xfrin_detail("Deleting old RDATA: %p, type: %s\n", - changes->old_rdata[i], - knot_rrtype_to_string(changes->old_rdata_types[i])); - knot_rdata_dump(changes->old_rdata[i], - changes->old_rdata_types[i], 0); - knot_rdata_t *rdata = changes->old_rdata[i]; + (*changes)->old_rdata[i], + knot_rrtype_to_string((*changes)->old_rdata_types[i])); + knot_rdata_dump((*changes)->old_rdata[i], + (*changes)->old_rdata_types[i], 0); + knot_rdata_t *rdata = (*changes)->old_rdata[i]; if (rdata != NULL) { do { knot_rdata_t *tmp = rdata->next; knot_rdata_deep_free(&rdata, - changes->old_rdata_types[i], 1); + (*changes)->old_rdata_types[i], 1); rdata = tmp; } while (rdata != NULL - && rdata != changes->old_rdata[i]); + && rdata != (*changes)->old_rdata[i]); } } // free allocated arrays of nodes and rrsets - free(changes->new_rrsets); - free(changes->new_rdata); - free(changes->new_rdata_types); - free(changes->old_nodes); - free(changes->old_nsec3); - free(changes->old_rrsets); - free(changes->old_rdata); - free(changes->old_rdata_types); + free((*changes)->new_rrsets); + free((*changes)->new_rdata); + free((*changes)->new_rdata_types); + free((*changes)->old_nodes); + free((*changes)->old_nsec3); + free((*changes)->old_rrsets); + free((*changes)->old_rdata); + free((*changes)->old_rdata_types); + + free((*changes)); + *changes = NULL; } /*----------------------------------------------------------------------------*/ @@ -2336,62 +2333,108 @@ static void xfrin_cleanup_old_nodes(knot_node_t *node, void *data) /*----------------------------------------------------------------------------*/ -static void xfrin_rollback_update2(knot_zone_contents_t *old_contents, - knot_zone_contents_t *new_contents, - xfrin_changes_t *changes) +static void xfrin_cleanup_failed_update(knot_zone_contents_t *old_contents, + knot_zone_contents_t **new_contents) { - // discard new RRSets - for (int i = 0; i < changes->new_rrsets_count; ++i) { - //knot_rrset_deep_free(&changes->new_rrsets[i], 0, 1, 1); - knot_rrset_free(&changes->new_rrsets[i]); + if (old_contents == NULL && new_contents == NULL) { + return; + } + + if (*new_contents != NULL) { + // destroy the shallow copy of zone + xfrin_zone_contents_free2(new_contents); } - for (int i = 0; i < changes->new_rdata_count; ++i) { - // discard the whole chain of RDATA - knot_rdata_t *rdata = changes->new_rdata[i]; - knot_rdata_t *rdata_next = NULL; + if (old_contents != NULL) { + // cleanup old zone tree - reset pointers to new node to NULL + // also set pointers from dnames to old nodes + knot_zone_contents_tree_apply_inorder(old_contents, + xfrin_cleanup_old_nodes, + NULL); - while (rdata != NULL && rdata->next != changes->new_rdata[i]) { - rdata_next = rdata->next; - knot_rdata_deep_free(&rdata, - changes->new_rdata_types[i], 1); - rdata = rdata_next; + knot_zone_contents_nsec3_apply_inorder(old_contents, + xfrin_cleanup_old_nodes, + NULL); + } +} + +/*----------------------------------------------------------------------------*/ + +void xfrin_rollback_update(knot_zone_contents_t *old_contents, + knot_zone_contents_t **new_contents, + knot_changes_t **changes) +{ + assert(changes != NULL); + + if (*changes != NULL) { + // discard new RRSets + for (int i = 0; i < (*changes)->new_rrsets_count; ++i) { + //knot_rrset_deep_free(&changes->new_rrsets[i], 0, 1, 1); + knot_rrset_free(&(*changes)->new_rrsets[i]); } - assert(rdata == NULL || rdata->next == changes->new_rdata[i]); + for (int i = 0; i < (*changes)->new_rdata_count; ++i) { + fprintf(stderr, "Freeing %d. RDATA chain: %p\n", i, + (*changes)->new_rdata[i]); + + /* + * In some case, the same RDATA may be stored in + * different positions in different RDATA chains, so + * some ivalid reads occur. + * + * More precisely, the same chain is stored multiple + * times, but starting from different RDATA. + * + * We may check every RDATA against every one + * already deleted, but that may be very time-consuming. + */ + + // discard the whole chain of RDATA + knot_rdata_t *rdata = (*changes)->new_rdata[i]; + knot_rdata_t *rdata_next = NULL; + + while (rdata != NULL && rdata->next != + (*changes)->new_rdata[i]) { + assert(rdata->next != rdata); + rdata_next = rdata->next; + fprintf(stderr, " Deleting RDATA: %p\n", rdata); + knot_rdata_deep_free(&rdata, + (*changes)->new_rdata_types[i], 1); + rdata = rdata_next; + } + + assert(rdata == NULL + || rdata->next == (*changes)->new_rdata[i]); + + fprintf(stderr, " Deleting RDATA: %p\n", rdata); + knot_rdata_deep_free(&rdata, + (*changes)->new_rdata_types[i], 1); + + //(*changes)->new_rdata[i] = NULL; + } - knot_rdata_deep_free(&rdata, changes->new_rdata_types[i], 1); + // free allocated arrays of nodes and rrsets + free((*changes)->new_rrsets); + free((*changes)->new_rdata); + free((*changes)->new_rdata_types); + free((*changes)->old_nodes); + free((*changes)->old_nsec3); + free((*changes)->old_rrsets); + free((*changes)->old_rdata); + free((*changes)->old_rdata_types); - changes->new_rdata[i] = NULL; + free(*changes); + *changes = NULL; } - // free allocated arrays of nodes and rrsets - free(changes->new_rrsets); - free(changes->new_rdata); - free(changes->new_rdata_types); - free(changes->old_nodes); - free(changes->old_nsec3); - free(changes->old_rrsets); - free(changes->old_rdata); - free(changes->old_rdata_types); - - // destroy the shallow copy of zone - xfrin_zone_contents_free2(&new_contents); - - // cleanup old zone tree - reset pointers to new node to NULL - // also set pointers from dnames to old nodes - knot_zone_contents_tree_apply_inorder(old_contents, - xfrin_cleanup_old_nodes, NULL); - - knot_zone_contents_nsec3_apply_inorder(old_contents, - xfrin_cleanup_old_nodes, NULL); + xfrin_cleanup_failed_update(old_contents, new_contents); } /*----------------------------------------------------------------------------*/ static int xfrin_apply_remove2(knot_zone_contents_t *contents, knot_changeset_t *chset, - xfrin_changes_t *changes) + knot_changes_t *changes) { /* * Iterate over removed RRSets, and remove them from the new nodes @@ -2472,7 +2515,7 @@ static int xfrin_apply_remove2(knot_zone_contents_t *contents, static int xfrin_apply_add2(knot_zone_contents_t *contents, knot_changeset_t *chset, - xfrin_changes_t *changes) + knot_changes_t *changes) { int ret = 0; knot_node_t *node = NULL; @@ -2540,25 +2583,6 @@ static int xfrin_apply_add2(knot_zone_contents_t *contents, rrset); if (ret > 0) { - // store the new RDATA - // in both cases it must be deleted if the transfer - // fails - - // connect the RDATA to the list of old RDATA - int res = xfrin_changes_check_rdata(&changes->new_rdata, - &changes->new_rdata_types, - changes->new_rdata_count, - &changes->new_rdata_allocated, 1); - if (res != KNOT_EOK) { - return res; - } - - changes->new_rdata[changes->new_rdata_count] = - knot_rrset_get_rdata(chset->add[i]); - changes->new_rdata_types[changes->new_rdata_count] = - knot_rrset_type(chset->add[i]); - ++changes->new_rdata_count; - if (ret == 1) { // the ADD RRSet was used, i.e. it should be // removed from the changeset and saved in the @@ -2576,6 +2600,23 @@ static int xfrin_apply_add2(knot_zone_contents_t *contents, changes->new_rrsets[changes->new_rrsets_count++] = chset->add[i]; + // the same goes for the RDATA + + // connect the RDATA to the list of new RDATA + int res = xfrin_changes_check_rdata(&changes->new_rdata, + &changes->new_rdata_types, + changes->new_rdata_count, + &changes->new_rdata_allocated, 1); + if (res != KNOT_EOK) { + return res; + } + + xfrin_changes_add_rdata(changes->new_rdata, + changes->new_rdata_types, + &changes->new_rdata_count, + knot_rrset_get_rdata(chset->add[i]), + knot_rrset_type(chset->add[i])); + chset->add[i] = NULL; } else if (ret == 2) { // the copy of the RRSet was used, but it was @@ -2583,6 +2624,11 @@ static int xfrin_apply_add2(knot_zone_contents_t *contents, // just delete the add RRSet, but without RDATA // as these were merged to the copied RRSet knot_rrset_free(&chset->add[i]); + + // In this case, the RDATA does not have to be + // stored in the list of new RDATA, because + // it is joined to the copy of RDATA, that is + // already stored there } else { assert(0); } @@ -2598,7 +2644,7 @@ static int xfrin_apply_add2(knot_zone_contents_t *contents, /*----------------------------------------------------------------------------*/ static int xfrin_apply_replace_soa2(knot_zone_contents_t *contents, - xfrin_changes_t *changes, + knot_changes_t *changes, knot_changeset_t *chset) { knot_node_t *node = knot_zone_contents_get_apex(contents); @@ -2658,9 +2704,9 @@ static int xfrin_apply_replace_soa2(knot_zone_contents_t *contents, changes->old_rrsets[changes->old_rrsets_count++] = rrset; /*! \todo Maybe check if the SOA does not have more RDATA? */ - changes->old_rdata[changes->old_rdata_count] = rrset->rdata; - changes->old_rdata_types[changes->old_rdata_count] = KNOT_RRTYPE_SOA; - ++changes->old_rdata_count; + xfrin_changes_add_rdata(changes->old_rdata, changes->old_rdata_types, + &changes->old_rdata_count, rrset->rdata, + KNOT_RRTYPE_SOA); // store RRSIGs from the old SOA to the new SOA knot_rrset_set_rrsigs(chset->soa_to, knot_rrset_get_rrsigs(rrset)); @@ -2678,11 +2724,12 @@ static int xfrin_apply_replace_soa2(knot_zone_contents_t *contents, assert(ret == 0); changes->new_rrsets[changes->new_rrsets_count++] = chset->soa_to; - changes->new_rdata[changes->new_rdata_count] = - knot_rrset_get_rdata(chset->soa_to); - changes->new_rdata_types[changes->new_rdata_count] = - knot_rrset_type(chset->soa_to); - ++changes->new_rdata_count; + + xfrin_changes_add_rdata(changes->new_rdata, + changes->new_rdata_types, + &changes->new_rdata_count, + knot_rrset_get_rdata(chset->soa_to), + knot_rrset_type(chset->soa_to)); // remove the SOA from the changeset, so it will not be deleted after // successful apply @@ -2694,7 +2741,7 @@ static int xfrin_apply_replace_soa2(knot_zone_contents_t *contents, /*----------------------------------------------------------------------------*/ static int xfrin_apply_changeset2(knot_zone_contents_t *contents, - xfrin_changes_t *changes, + knot_changes_t *changes, knot_changeset_t *chset) { /* @@ -2735,7 +2782,7 @@ static void xfrin_mark_empty(knot_node_t *node, void *data) assert(node != NULL); assert(data != NULL); - xfrin_changes_t *changes = (xfrin_changes_t *)data; + knot_changes_t *changes = (knot_changes_t *)data; if (knot_node_rrset_count(node) == 0 && knot_node_children(node) == 0) { @@ -2767,7 +2814,7 @@ static void xfrin_mark_empty_nsec3(knot_node_t *node, void *data) assert(node != NULL); assert(data != NULL); - xfrin_changes_t *changes = (xfrin_changes_t *)data; + knot_changes_t *changes = (knot_changes_t *)data; if (knot_node_rrset_count(node) == 0 && knot_node_children(node) == 0) { @@ -2795,7 +2842,7 @@ static void xfrin_mark_empty_nsec3(knot_node_t *node, void *data) /*----------------------------------------------------------------------------*/ static int xfrin_remove_empty_nodes(knot_zone_contents_t *contents, - xfrin_changes_t *changes) + knot_changes_t *changes) { int ret; @@ -2987,9 +3034,11 @@ static int xfrin_check_contents_copy(knot_zone_contents_t *old_contents) /*----------------------------------------------------------------------------*/ int xfrin_apply_changesets(knot_zone_t *zone, - knot_changesets_t *chsets) + knot_changesets_t *chsets, + knot_zone_contents_t **new_contents) { - if (zone == NULL || chsets == NULL || chsets->count == 0) { + if (zone == NULL || chsets == NULL || chsets->count == 0 + || new_contents == NULL) { return KNOT_EBADARG; } @@ -3033,8 +3082,15 @@ int xfrin_apply_changesets(knot_zone_t *zone, return ret; } - xfrin_changes_t changes; - memset(&changes, 0, sizeof(xfrin_changes_t)); + knot_changes_t *changes = (knot_changes_t *)malloc( + sizeof(knot_changes_t)); + if (changes == NULL) { + dbg_xfrin("Failed to allocate structure for changes!\n"); + xfrin_rollback_update(old_contents, &contents_copy, &changes); + return KNOT_ENOMEM; + } + + memset(changes, 0, sizeof(knot_changes_t)); /*! * \todo Check if all nodes have their copy. @@ -3042,7 +3098,7 @@ int xfrin_apply_changesets(knot_zone_t *zone, ret = xfrin_check_contents_copy(old_contents); if (ret != KNOT_EOK) { dbg_xfrin("Contents copy check failed!\n"); - xfrin_rollback_update2(old_contents, contents_copy, &changes); + xfrin_rollback_update(old_contents, &contents_copy, &changes); return ret; } @@ -3063,11 +3119,11 @@ int xfrin_apply_changesets(knot_zone_t *zone, dbg_xfrin_verb("Old contents apex: %p, new apex: %p\n", old_contents->apex, contents_copy->apex); for (int i = 0; i < chsets->count; ++i) { - if ((ret = xfrin_apply_changeset2(contents_copy, &changes, + if ((ret = xfrin_apply_changeset2(contents_copy, changes, &chsets->sets[i])) != KNOT_EOK) { - xfrin_rollback_update2(old_contents, - contents_copy, &changes); + xfrin_rollback_update(old_contents, + &contents_copy, &changes); dbg_xfrin("Failed to apply changesets to zone: " "%s\n", knot_strerror(ret)); return ret; @@ -3090,11 +3146,11 @@ int xfrin_apply_changesets(knot_zone_t *zone, /* * Select and delete empty nodes. */ - ret = xfrin_remove_empty_nodes(contents_copy, &changes); + ret = xfrin_remove_empty_nodes(contents_copy, changes); if (ret != KNOT_EOK) { dbg_xfrin("Failed to remove empty nodes: %s\n", knot_strerror(ret)); - xfrin_rollback_update2(old_contents, contents_copy, &changes); + xfrin_rollback_update(old_contents, &contents_copy, &changes); return ret; } @@ -3107,7 +3163,7 @@ int xfrin_apply_changesets(knot_zone_t *zone, if (ret != KNOT_EOK) { dbg_xfrin("Failed to finalize zone contents: %s\n", knot_strerror(ret)); - xfrin_rollback_update2(old_contents, contents_copy, &changes); + xfrin_rollback_update(old_contents, &contents_copy, &changes); return ret; } assert(knot_zone_contents_apex(contents_copy) != NULL); @@ -3116,30 +3172,50 @@ int xfrin_apply_changesets(knot_zone_t *zone, ret = knot_zone_contents_check_loops(contents_copy); if (ret != KNOT_EOK) { dbg_xfrin("CNAME loop check failed: %s\n", knot_strerror(ret)); - xfrin_rollback_update2(old_contents, contents_copy, &changes); + xfrin_rollback_update(old_contents, &contents_copy, &changes); return ret; } + //xfrin_cleanup_update(&changes); + chsets->changes = changes; + *new_contents = contents_copy; + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int xfrin_switch_zone(knot_zone_t *zone, + knot_zone_contents_t *new_contents, + int transfer_type) +{ + if (zone == NULL || new_contents == NULL) { + return KNOT_EBADARG; + } + dbg_xfrin("Switching zone contents.\n"); - dbg_xfrin_verb("Old contents apex: %p, new apex: %p\n", - old_contents->apex, contents_copy->apex); + dbg_xfrin_verb("Old contents: %p, apex: %p, new apex: %p\n", + zone->contents, (zone->contents) + ? zone->contents->apex : NULL, new_contents->apex); + knot_zone_contents_t *old = - knot_zone_switch_contents(zone, contents_copy); - assert(old == old_contents); + knot_zone_switch_contents(zone, new_contents); - dbg_xfrin_verb("Old contents apex: %p, new apex: %p\n", - old_contents->apex, contents_copy->apex); - /* - * Wait until all readers finish reading - */ + dbg_xfrin_verb("Old contents: %p, apex: %p, new apex: %p\n", + old, (old) ? old->apex : NULL, new_contents->apex); + + // wait for readers to finish + dbg_xfrin_verb("Waiting for readers to finish...\n"); synchronize_rcu(); + // destroy the old zone + dbg_xfrin_verb("Freeing old zone: %p\n", old); - /* - * Delete all old and unused data. - */ - dbg_xfrin("Cleaning up.\n"); - xfrin_zone_contents_free(&old_contents); - xfrin_cleanup_update(&changes); + if (transfer_type == XFR_TYPE_AIN) { + knot_zone_contents_deep_free(&old, 0); + } else { + assert(old != NULL); + xfrin_zone_contents_free(&old); + } return KNOT_EOK; } diff --git a/src/libknot/updates/xfr-in.h b/src/libknot/updates/xfr-in.h index 233527b..b009152 100644 --- a/src/libknot/updates/xfr-in.h +++ b/src/libknot/updates/xfr-in.h @@ -182,7 +182,21 @@ int xfrin_apply_changesets_to_zone(knot_zone_t *zone, knot_changesets_t *chsets); int xfrin_apply_changesets(knot_zone_t *zone, - knot_changesets_t *chsets); + knot_changesets_t *chsets, + knot_zone_contents_t **new_contents); + +int xfrin_switch_zone(knot_zone_t *zone, + knot_zone_contents_t *new_contents, + int deep_free); + +//void xfrin_cleanup_failed_update(knot_zone_contents_t *old_contents, +// knot_zone_contents_t **new_contents); + +void xfrin_cleanup_successful_update(knot_changes_t **changes); + +void xfrin_rollback_update(knot_zone_contents_t *old_contents, + knot_zone_contents_t **new_contents, + knot_changes_t **changes); #endif /* _KNOTXFR_IN_H_ */ diff --git a/src/libknot/util/debug.c b/src/libknot/util/debug.c index 78cd4a4..f14c3cd 100644 --- a/src/libknot/util/debug.c +++ b/src/libknot/util/debug.c @@ -22,7 +22,6 @@ #include "util/utils.h" #include "util/debug.h" -#include "libknot.h" #include "common/print.h" void knot_rdata_dump(knot_rdata_t *rdata, uint32_t type, char loaded_zone) diff --git a/src/libknot/util/debug.h b/src/libknot/util/debug.h index a7eb86a..e02f988 100644 --- a/src/libknot/util/debug.h +++ b/src/libknot/util/debug.h @@ -34,6 +34,43 @@ #include "config.h" /* autoconf generated */ +/* + * Debug macros + */ +#ifdef KNOT_ZONES_DEBUG + #define KNOT_ZONE_DEBUG + #define KNOT_ZONEDB_DEBUG + #define KNOT_NODE_DEBUG +#endif + +#ifdef KNOT_NS_DEBUG + #define KNOT_EDNS_DEBUG + #define KNOT_NSEC3_DEBUG +#endif + +/* define KNOT_PACKET_DEBUG -- in configure.ac */ +#ifdef KNOT_PACKET_DEBUG + #define KNOT_RESPONSE_DEBUG +#endif + +#ifdef KNOT_RR_DEBUG + #define KNOT_RRSET_DEBUG + #define KNOT_RDATA_DEBUG +#endif + +#ifdef KNOT_HASH_DEBUG + #define CUCKOO_DEBUG + #define CUCKOO_DEBUG_HASH +#endif + +#ifdef KNOT_XFR_DEBUG + #define KNOT_XFRIN_DEBUG + #define KNOT_TSIG_DEBUG +#endif + +/* KNOT_DNAME_DEBUG -- in configure.ac */ +/* #define KNOT_DDNS_DEBUG -- \todo Use this or delete. */ + #include "rdata.h" #include "rrset.h" #include "zone/node.h" @@ -41,27 +78,6 @@ #include "util/utils.h" #include "common/print.h" -/* - * Debug macros - */ -/*! \todo Set these during configure. */ -//#define KNOT_ZONE_DEBUG -//#define KNOT_RESPONSE_DEBUG -//#define KNOT_ZONEDB_DEBUG -//#define KNOT_DNAME_DEBUG -//#define KNOT_NODE_DEBUG -//#define KNOT_PACKET_DEBUG -//#define KNOT_EDNS_DEBUG -//#define KNOT_RRSET_DEBUG -//#define KNOT_RDATA_DEBUG -//#define KNOT_NSEC3_DEBUG -//#define CUCKOO_DEBUG -//#define CUCKOO_DEBUG_HASH -//#define KNOT_NS_DEBUG -//#define KNOT_XFRIN_DEBUG -//#define KNOT_DDNS_DEBUG -//#define KNOT_TSIG_DEBUG - /*! * \brief Dumps RDATA of the given type. * @@ -541,37 +557,46 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); #ifdef DEBUG_ENABLE_BRIEF #define dbg_ck(msg...) fprintf(stderr, msg) #define dbg_ck_hex(data, len) hex_print((data), (len)) +#define dbg_ck_exec(cmds) do { cmds } while (0) #else #define dbg_ck(msg...) #define dbg_ck_hex(data, len) +#define dbg_ck_exec(cmds) #endif /* Verbose messages. */ #ifdef DEBUG_ENABLE_VERBOSE #define dbg_ck_verb(msg...) fprintf(stderr, msg) #define dbg_ck_hex_verb(data, len) hex_print((data), (len)) +#define dbg_ck_exec_verb(cmds) do { cmds } while (0) #else #define dbg_ck_verb(msg...) #define dbg_ck_hex_verb(data, len) +#define dbg_ck_exec_verb(cmds) #endif /* Detail messages. */ #ifdef DEBUG_ENABLE_DETAILS #define dbg_ck_detail(msg...) fprintf(stderr, msg) #define dbg_ck_hex_detail(data, len) hex_print((data), (len)) +#define dbg_ck_exec_detail(cmds) do { cmds } while (0) #else #define dbg_ck_detail(msg...) #define dbg_ck_hex_detail(data, len) +#define dbg_ck_exec_detail(cmds) #endif /* No messages. */ #else #define dbg_ck(msg...) #define dbg_ck_hex(data, len) +#define dbg_ck_exec(cmds) #define dbg_ck_verb(msg...) #define dbg_ck_hex_verb(data, len) +#define dbg_ck_exec_verb(cmds) #define dbg_ck_detail(msg...) #define dbg_ck_hex_detail(data, len) +#define dbg_ck_exec_detail(cmds) #endif /******************************************************************************/ diff --git a/src/libknot/util/libknot_error.c b/src/libknot/util/libknot_error.c index d922afb..a5a9de0 100644 --- a/src/libknot/util/libknot_error.c +++ b/src/libknot/util/libknot_error.c @@ -15,8 +15,6 @@ */ #include "util/error.h" -#include "util/utils.h" - #include "common/errors.h" const error_table_t knot_error_msgs[KNOT_ERROR_COUNT] = { diff --git a/src/libknot/util/utils.h b/src/libknot/util/utils.h index ba7a6d2..fd275b3 100644 --- a/src/libknot/util/utils.h +++ b/src/libknot/util/utils.h @@ -123,8 +123,9 @@ static inline uint32_t knot_wire_read_u32(const uint8_t *pos) */ static inline uint64_t knot_wire_read_u48(const uint8_t *pos) { - return ((uint64_t)(pos[0]) << 40) | ((uint64_t)(pos[1]) << 32) | (pos[2] << 24) | - (pos[3] << 16) | (pos[4] << 8) | pos[5]; + return ((uint64_t)(pos[0]) << 40) | ((uint64_t)(pos[1]) << 32) + | ((uint64_t)(pos[2]) << 24) | ((uint64_t)(pos[3]) << 16) + | ((uint64_t)(pos[4]) << 8) | (uint64_t)pos[5]; } /*! diff --git a/src/libknot/zone/node.h b/src/libknot/zone/node.h index 583f248..11cd0ce 100644 --- a/src/libknot/zone/node.h +++ b/src/libknot/zone/node.h @@ -50,8 +50,6 @@ struct knot_node { /*! \brief Type-ordered list of RRSets belonging to this node. */ general_tree_t *rrset_tree; - unsigned short rrset_count; /*!< Number of RRSets stored in the node. */ - /*! \brief Wildcard node being the direct descendant of this node. */ struct knot_node *wildcard_child; @@ -76,21 +74,14 @@ struct knot_node { struct knot_node *nsec3_referer; - /*! - * \brief Various flags. - * - * Currently only two: - * 0x01 - node is a delegation point - * 0x02 - node is non-authoritative (under a delegation point) - * 0x80 - node is old and will be removed (during update) - * 0x40 - node is new, should not be used while zone is old - */ - uint8_t flags; + struct knot_zone *zone; struct knot_node *new_node; unsigned int children; - + + unsigned short rrset_count; /*!< Number of RRSets stored in the node. */ + /*! * \brief Generation of node to be used. * @@ -100,7 +91,16 @@ struct knot_node { */ // short **generation; - struct knot_zone *zone; + /*! + * \brief Various flags. + * + * Currently only two: + * 0x01 - node is a delegation point + * 0x02 - node is non-authoritative (under a delegation point) + * 0x80 - node is old and will be removed (during update) + * 0x40 - node is new, should not be used while zone is old + */ + uint8_t flags; }; typedef struct knot_node knot_node_t; diff --git a/src/libknot/zone/zone-contents.c b/src/libknot/zone/zone-contents.c index 8a74e23..3764acc 100644 --- a/src/libknot/zone/zone-contents.c +++ b/src/libknot/zone/zone-contents.c @@ -261,21 +261,21 @@ static int knot_zone_contents_dnames_from_node_to_table( * \param zone Current zone. * \param node Node to be used. */ -static void find_and_set_wildcard_child(knot_zone_contents_t *zone, - knot_node_t *node) -{ - knot_dname_t *chopped = knot_dname_left_chop(node->owner); - assert(chopped); - knot_node_t *wildcard_parent; - wildcard_parent = - knot_zone_contents_get_node(zone, chopped); +//static void find_and_set_wildcard_child(knot_zone_contents_t *zone, +// knot_node_t *node) +//{ +// knot_dname_t *chopped = knot_dname_left_chop(node->owner); +// assert(chopped); +// knot_node_t *wildcard_parent; +// wildcard_parent = +// knot_zone_contents_get_node(zone, chopped); - knot_dname_free(&chopped); +// knot_dname_free(&chopped); - assert(wildcard_parent); /* it *has* to be there */ +// assert(wildcard_parent); /* it *has* to be there */ - knot_node_set_wildcard_child(wildcard_parent, node); -} +// knot_node_set_wildcard_child(wildcard_parent, node); +//} /*----------------------------------------------------------------------------*/ /*! @@ -294,54 +294,54 @@ static void find_and_set_wildcard_child(knot_zone_contents_t *zone, * \param zone Zone to which the RDATA belongs. * \param pos Position of the RDATA item in the RDATA. */ -static void knot_zone_contents_adjust_rdata_item(knot_rdata_t *rdata, - knot_zone_contents_t *zone, - knot_node_t *node, - int pos) -{ - return; - const knot_rdata_item_t *dname_item - = knot_rdata_item(rdata, pos); +//static void knot_zone_contents_adjust_rdata_item(knot_rdata_t *rdata, +// knot_zone_contents_t *zone, +// knot_node_t *node, +// int pos) +//{ +// return; +// const knot_rdata_item_t *dname_item +// = knot_rdata_item(rdata, pos); - assert(dname_item); +// assert(dname_item); - if (dname_item != NULL) { - knot_dname_t *dname = dname_item->dname; - const knot_node_t *n = NULL; - const knot_node_t *closest_encloser = NULL; - const knot_node_t *prev = NULL; +// if (dname_item != NULL) { +// knot_dname_t *dname = dname_item->dname; +// const knot_node_t *n = NULL; +// const knot_node_t *closest_encloser = NULL; +// const knot_node_t *prev = NULL; - if (knot_dname_is_wildcard(dname)) { - find_and_set_wildcard_child(zone, node); - } +// if (knot_dname_is_wildcard(dname)) { +// find_and_set_wildcard_child(zone, node); +// } - int ret = knot_zone_contents_find_dname(zone, dname, &n, - &closest_encloser, &prev); +// int ret = knot_zone_contents_find_dname(zone, dname, &n, +// &closest_encloser, &prev); - // n = knot_zone_find_node(zone, dname); +// // n = knot_zone_find_node(zone, dname); - if (ret == KNOT_EBADARG || ret == KNOT_EBADZONE) { - // TODO: do some cleanup if needed - return; - } +// if (ret == KNOT_EBADARG || ret == KNOT_EBADZONE) { +// // TODO: do some cleanup if needed +// return; +// } - assert(ret != KNOT_ZONE_NAME_FOUND - || n == closest_encloser); - - if (ret != KNOT_ZONE_NAME_FOUND - && (closest_encloser != NULL)) { - dbg_zone("Saving closest encloser to RDATA.\n"); - // save pointer to the closest encloser - knot_rdata_item_t *item = - knot_rdata_get_item(rdata, pos); - assert(item->dname != NULL); - assert(item->dname->node == NULL); - //skip_insert(list, (void *)item->dname, - // (void *)closest_encloser->owner, NULL); - item->dname->node = closest_encloser->owner->node; - } - } -} +// assert(ret != KNOT_ZONE_NAME_FOUND +// || n == closest_encloser); + +// if (ret != KNOT_ZONE_NAME_FOUND +// && (closest_encloser != NULL)) { +// dbg_zone("Saving closest encloser to RDATA.\n"); +// // save pointer to the closest encloser +// knot_rdata_item_t *item = +// knot_rdata_get_item(rdata, pos); +// assert(item->dname != NULL); +// assert(item->dname->node == NULL); +// //skip_insert(list, (void *)item->dname, +// // (void *)closest_encloser->owner, NULL); +// item->dname->node = closest_encloser->owner->node; +// } +// } +//} /*----------------------------------------------------------------------------*/ /*! @@ -355,65 +355,65 @@ static void knot_zone_contents_adjust_rdata_item(knot_rdata_t *rdata, * \param rrset RRSet to adjust RDATA in. * \param zone Zone to which the RRSet belongs. */ -static void knot_zone_contents_adjust_rdata_in_rrset(knot_rrset_t *rrset, - knot_zone_contents_t *zone, - knot_node_t *node) -{ - uint16_t type = knot_rrset_type(rrset); +//static void knot_zone_contents_adjust_rdata_in_rrset(knot_rrset_t *rrset, +// knot_zone_contents_t *zone, +// knot_node_t *node) +//{ +// uint16_t type = knot_rrset_type(rrset); - knot_rrtype_descriptor_t *desc = - knot_rrtype_descriptor_by_type(type); - assert(desc); +// knot_rrtype_descriptor_t *desc = +// knot_rrtype_descriptor_by_type(type); +// assert(desc); - knot_rdata_t *rdata_first = knot_rrset_get_rdata(rrset); - knot_rdata_t *rdata = rdata_first; +// knot_rdata_t *rdata_first = knot_rrset_get_rdata(rrset); +// knot_rdata_t *rdata = rdata_first; - if (rdata == NULL) { - return; - } +// if (rdata == NULL) { +// return; +// } - while (rdata->next != rdata_first) { - for (int i = 0; i < rdata->count; ++i) { - if (desc->wireformat[i] - == KNOT_RDATA_WF_COMPRESSED_DNAME - || desc->wireformat[i] - == KNOT_RDATA_WF_UNCOMPRESSED_DNAME - || desc->wireformat[i] - == KNOT_RDATA_WF_LITERAL_DNAME) { - dbg_zone("Adjusting domain name at " - "position %d of RDATA of record with owner " - "%s and type %s.\n", - i, rrset->owner->name, - knot_rrtype_to_string(type)); - - knot_zone_contents_adjust_rdata_item(rdata, - zone, - node, - i); - } - } - rdata = rdata->next; - } +// while (rdata->next != rdata_first) { +// for (int i = 0; i < rdata->count; ++i) { +// if (desc->wireformat[i] +// == KNOT_RDATA_WF_COMPRESSED_DNAME +// || desc->wireformat[i] +// == KNOT_RDATA_WF_UNCOMPRESSED_DNAME +// || desc->wireformat[i] +// == KNOT_RDATA_WF_LITERAL_DNAME) { +// dbg_zone("Adjusting domain name at " +// "position %d of RDATA of record with owner " +// "%s and type %s.\n", +// i, rrset->owner->name, +// knot_rrtype_to_string(type)); + +// knot_zone_contents_adjust_rdata_item(rdata, +// zone, +// node, +// i); +// } +// } +// rdata = rdata->next; +// } - for (int i = 0; i < rdata->count; ++i) { - if (desc->wireformat[i] - == KNOT_RDATA_WF_COMPRESSED_DNAME - || desc->wireformat[i] - == KNOT_RDATA_WF_UNCOMPRESSED_DNAME - || desc->wireformat[i] - == KNOT_RDATA_WF_LITERAL_DNAME) { - dbg_zone("Adjusting domain name at " - "position %d of RDATA of record with owner " - "%s and type %s.\n", - i, rrset->owner->name, - knot_rrtype_to_string(type)); - - knot_zone_contents_adjust_rdata_item(rdata, zone, - node, i); - } - } +// for (int i = 0; i < rdata->count; ++i) { +// if (desc->wireformat[i] +// == KNOT_RDATA_WF_COMPRESSED_DNAME +// || desc->wireformat[i] +// == KNOT_RDATA_WF_UNCOMPRESSED_DNAME +// || desc->wireformat[i] +// == KNOT_RDATA_WF_LITERAL_DNAME) { +// dbg_zone("Adjusting domain name at " +// "position %d of RDATA of record with owner " +// "%s and type %s.\n", +// i, rrset->owner->name, +// knot_rrtype_to_string(type)); + +// knot_zone_contents_adjust_rdata_item(rdata, zone, +// node, i); +// } +// } -} +//} /*----------------------------------------------------------------------------*/ /*! @@ -426,31 +426,31 @@ static void knot_zone_contents_adjust_rdata_in_rrset(knot_rrset_t *rrset, * \param node Zone node to adjust the RRSets in. * \param zone Zone to which the node belongs. */ -static void knot_zone_contents_adjust_rrsets(knot_node_t *node, - knot_zone_contents_t *zone) -{ - //return; - knot_rrset_t **rrsets = knot_node_get_rrsets(node); - short count = knot_node_rrset_count(node); - - assert(count == 0 || rrsets != NULL); - - for (int r = 0; r < count; ++r) { - assert(rrsets[r] != NULL); - dbg_zone("Adjusting next RRSet.\n"); - knot_zone_contents_adjust_rdata_in_rrset(rrsets[r], zone, - node); - knot_rrset_t *rrsigs = rrsets[r]->rrsigs; - if (rrsigs != NULL) { - dbg_zone("Adjusting next RRSIGs.\n"); - knot_zone_contents_adjust_rdata_in_rrset(rrsigs, - zone, - node); - } - } +//static void knot_zone_contents_adjust_rrsets(knot_node_t *node, +// knot_zone_contents_t *zone) +//{ +// //return; +// knot_rrset_t **rrsets = knot_node_get_rrsets(node); +// short count = knot_node_rrset_count(node); + +// assert(count == 0 || rrsets != NULL); + +// for (int r = 0; r < count; ++r) { +// assert(rrsets[r] != NULL); +// dbg_zone("Adjusting next RRSet.\n"); +// knot_zone_contents_adjust_rdata_in_rrset(rrsets[r], zone, +// node); +// knot_rrset_t *rrsigs = rrsets[r]->rrsigs; +// if (rrsigs != NULL) { +// dbg_zone("Adjusting next RRSIGs.\n"); +// knot_zone_contents_adjust_rdata_in_rrset(rrsigs, +// zone, +// node); +// } +// } - free(rrsets); -} +// free(rrsets); +//} /*----------------------------------------------------------------------------*/ /*! @@ -480,7 +480,12 @@ dbg_zone_exec( ); // adjust domain names in RDATA - knot_zone_contents_adjust_rrsets(node, zone); + /*! + * \note This is unnecessary, as the code in adjust_rdata_item() is not + * reachable anyway. However, it's not clear why we disabled the + * code, so this would need further investigation. + */ + //knot_zone_contents_adjust_rrsets(node, zone); dbg_zone_exec( if (knot_node_parent(node)) { @@ -1294,7 +1299,7 @@ int knot_zone_contents_add_node(knot_zone_contents_t *zone, knot_zone_contents_dnames_from_node_to_table( zone->dname_table, next_node); if (ret != KNOT_EOK) { - /*! \todo Will next_node leak? */ + knot_node_free(&next_node, 0); knot_dname_release(chopped); return ret; } @@ -1594,7 +1599,10 @@ int knot_zone_contents_add_nsec3_node(knot_zone_contents_t *zone, // how to know if this is successfull?? // TREE_INSERT(zone->nsec3_nodes, knot_node, avl, node); - knot_zone_tree_insert(zone->nsec3_nodes, node); + ret = knot_zone_tree_insert(zone->nsec3_nodes, node); + if (ret != KNOT_EOK) { + return ret; + } if (use_domain_table) { ret = knot_zone_contents_dnames_from_node_to_table( @@ -2228,45 +2236,51 @@ int knot_zone_contents_adjust(knot_zone_contents_t *zone) adjust_arg.err = KNOT_EOK; // adjust_arg.check_ver = check_ver; - dbg_zone("Adjusting normal nodes.\n"); - int ret = knot_zone_tree_forward_apply_inorder(zone->nodes, - knot_zone_contents_adjust_node_in_tree, + /* + * Adjust the NSEC3 nodes first. + * There are independent on the normal nodes, but the normal nodes are + * dependent on them. + */ + + dbg_zone("Adjusting NSEC3 nodes.\n"); + int ret = knot_zone_tree_forward_apply_inorder( + zone->nsec3_nodes, + knot_zone_contents_adjust_nsec3_node_in_tree, &adjust_arg); assert(ret == KNOT_EOK); if (adjust_arg.err != KNOT_EOK) { - dbg_zone("Failed to adjust normal nodes: %s\n", + dbg_zone("Failed to adjust NSEC3 nodes: %s\n", knot_strerror(adjust_arg.err)); return adjust_arg.err; } - assert(zone->apex == adjust_arg.first_node); - knot_node_set_previous(zone->apex, adjust_arg.previous_node); - + // set the last node as previous of the first node + if (adjust_arg.first_node) { + knot_node_set_previous(adjust_arg.first_node, + adjust_arg.previous_node); + } dbg_zone("Done.\n"); adjust_arg.first_node = NULL; adjust_arg.previous_node = NULL; - dbg_zone("Adjusting NSEC3 nodes.\n"); - ret = knot_zone_tree_forward_apply_inorder( - zone->nsec3_nodes, - knot_zone_contents_adjust_nsec3_node_in_tree, + dbg_zone("Adjusting normal nodes.\n"); + ret = knot_zone_tree_forward_apply_inorder(zone->nodes, + knot_zone_contents_adjust_node_in_tree, &adjust_arg); assert(ret == KNOT_EOK); if (adjust_arg.err != KNOT_EOK) { - dbg_zone("Failed to adjust NSEC3 nodes: %s\n", + dbg_zone("Failed to adjust normal nodes: %s\n", knot_strerror(adjust_arg.err)); return adjust_arg.err; } + assert(zone->apex == adjust_arg.first_node); + knot_node_set_previous(zone->apex, adjust_arg.previous_node); + dbg_zone("Done.\n"); - // set the last node as previous of the first node - if (adjust_arg.first_node) { - knot_node_set_previous(adjust_arg.first_node, - adjust_arg.previous_node); - } return ret; } @@ -2364,7 +2378,8 @@ int knot_zone_contents_load_nsec3param(knot_zone_contents_t *zone) KNOT_RRTYPE_NSEC3PARAM); if (rrset != NULL) { - knot_nsec3_params_from_wire(&zone->nsec3_params, rrset); + int r = knot_nsec3_params_from_wire(&zone->nsec3_params, rrset); + assert(r == KNOT_EOK); } else { memset(&zone->nsec3_params, 0, sizeof(knot_nsec3_params_t)); } @@ -3388,7 +3403,7 @@ int knot_zc_integrity_check_child_count(check_data_t *data) // add count of NSEC3 nodes to the apex' children count // int nsec3_nodes = 0; - dbg_zone(stderr, "Children count of new apex before NSEC3: %d\n", + dbg_zone("Children count of new apex before NSEC3: %d\n", data->contents->apex->new_node->children); knot_zone_tree_forward_apply_inorder(data->contents->nsec3_nodes, count_nsec3_nodes, diff --git a/src/libknot/zone/zone-contents.h b/src/libknot/zone/zone-contents.h index 24fbcac..d31bbbb 100644 --- a/src/libknot/zone/zone-contents.h +++ b/src/libknot/zone/zone-contents.h @@ -49,14 +49,16 @@ typedef struct knot_zone_contents_t { knot_zone_tree_t *nodes; knot_zone_tree_t *nsec3_nodes; - /*! - * \todo Unify the use of this field - authoritative nodes vs. all. - */ - uint node_count; - knot_dname_table_t *dname_table; + struct knot_zone *zone; + knot_nsec3_params_t nsec3_params; + + /*! + * \todo Unify the use of this field - authoritative nodes vs. all. + */ + uint node_count; /*! \brief Generation of the zone during update. * @@ -67,8 +69,6 @@ typedef struct knot_zone_contents_t { * used, no matter their generation. */ short generation; - - struct knot_zone *zone; } knot_zone_contents_t; /*----------------------------------------------------------------------------*/ diff --git a/src/libknot/zone/zone-tree.c b/src/libknot/zone/zone-tree.c index de5df18..2b79f86 100644 --- a/src/libknot/zone/zone-tree.c +++ b/src/libknot/zone/zone-tree.c @@ -318,6 +318,24 @@ int knot_zone_tree_get_less_or_equal(knot_zone_tree_t *tree, *found = (exact_match > 0) ? f->node : NULL; +dbg_zone_exec_detail( + char *name = knot_dname_to_str(owner); + char *name_f = (f != NULL) + ? knot_dname_to_str(knot_node_owner(f->node)) + : "none"; + + dbg_zone_detail("Searched for owner %s in zone tree.\n", + name); + dbg_zone_detail("Exact match: %d\n", exact_match); + dbg_zone_detail("Found node: %p: %s.\n", f, name_f); + dbg_zone_detail("Previous node: %p.\n", prev); + + free(name); + if (f != NULL) { + free(name_f); + } +); + if (exact_match < 0) { // previous is not really previous but should be the leftmost // node in the tree; take it's previous @@ -325,18 +343,6 @@ int knot_zone_tree_get_less_or_equal(knot_zone_tree_t *tree, *previous = knot_node_get_previous(prev->node); exact_match = 0; } else if (prev == NULL) { - if (!exact_match) { - printf("Searched for owner %s in zone tree.\n", - knot_dname_to_str(owner)); - printf("Exact match: %d\n", exact_match); - printf("Found node: %p: %s.\n", f, (f) - ? knot_dname_to_str(knot_node_owner(f->node)) - : "none"); - printf("Previous node: %p: %s.\n", prev, (prev) - ? knot_dname_to_str(knot_node_owner(prev->node)) - : "none"); - } - // either the returned node is the root of the tree, or // it is the leftmost node in the tree; in both cases // node was found set the previous node of the found diff --git a/src/libknot/zone/zone.c b/src/libknot/zone/zone.c index 9de1a53..122b014 100644 --- a/src/libknot/zone/zone.c +++ b/src/libknot/zone/zone.c @@ -25,14 +25,11 @@ #include "zone/zone.h" #include "zone/node.h" #include "dname.h" -#include "consts.h" #include "util/descriptor.h" #include "nsec3.h" #include "util/error.h" #include "util/debug.h" #include "util/utils.h" -#include "common/tree.h" -#include "common/base32hex.h" #include "hash/cuckoo-hash-table.h" #include "zone/zone-contents.h" diff --git a/src/libknot/zone/zonedb.c b/src/libknot/zone/zonedb.c index 7b445dd..a9b6545 100644 --- a/src/libknot/zone/zonedb.c +++ b/src/libknot/zone/zonedb.c @@ -294,16 +294,22 @@ knot_zonedb_t *knot_zonedb_copy(const knot_zonedb_t *db) return db_new; } +/*----------------------------------------------------------------------------*/ + size_t knot_zonedb_zone_count(const knot_zonedb_t *db) { return db->zone_count; } +/*----------------------------------------------------------------------------*/ + struct knot_zone_db_tree_arg { const knot_zone_t **zones; size_t count; }; +/*----------------------------------------------------------------------------*/ + static void save_zone_to_array(void *node, void *data) { knot_zone_t *zone = (knot_zone_t *)node; @@ -313,15 +319,16 @@ static void save_zone_to_array(void *node, void *data) args->zones[args->count++] = zone; } +/*----------------------------------------------------------------------------*/ + const knot_zone_t **knot_zonedb_zones(const knot_zonedb_t *db) { struct knot_zone_db_tree_arg args; - args.zones = malloc(sizeof(knot_zone_t) * db->zone_count); + args.zones = malloc(sizeof(knot_zone_t *) * db->zone_count); args.count = 0; CHECK_ALLOC_LOG(args.zones, NULL); - gen_tree_apply_inorder(db->zone_tree, save_zone_to_array, - &args); + gen_tree_apply_inorder(db->zone_tree, save_zone_to_array, &args); assert(db->zone_count == args.count); return args.zones; diff --git a/src/tests/common/acl_tests.c b/src/tests/common/acl_tests.c index a7613e7..ea7b653 100644 --- a/src/tests/common/acl_tests.c +++ b/src/tests/common/acl_tests.c @@ -34,7 +34,7 @@ unit_api acl_tests_api = { static int acl_tests_count(int argc, char *argv[]) { - return 13; + return 18; } static int acl_tests_run(int argc, char *argv[]) @@ -54,17 +54,17 @@ static int acl_tests_run(int argc, char *argv[]) ok(ret > 0, "acl: new IPv6 address"); // 4. Create simple IPv4 rule - ret = acl_create(acl, &test_v4, ACL_ACCEPT, 0); + ret = acl_create(acl, &test_v4, ACL_ACCEPT, 0, 0); ok(ret == ACL_ACCEPT, "acl: inserted IPv4 rule"); // 5. Create simple IPv6 rule - ret = acl_create(acl, &test_v6, ACL_ACCEPT, 0); + ret = acl_create(acl, &test_v6, ACL_ACCEPT, 0, 0); ok(ret == ACL_ACCEPT, "acl: inserted IPv6 rule"); // 6. Create simple IPv4 'any port' rule sockaddr_t test_v4a; sockaddr_set(&test_v4a, AF_INET, "20.20.20.20", 0); - ret = acl_create(acl, &test_v4a, ACL_ACCEPT, 0); + ret = acl_create(acl, &test_v4a, ACL_ACCEPT, 0, 0); ok(ret == ACL_ACCEPT, "acl: inserted IPv4 'any port' rule"); // 7. Attempt to match unmatching address @@ -94,19 +94,60 @@ static int acl_tests_run(int argc, char *argv[]) ok(ret == ACL_ACCEPT, "acl: matching existing IPv4 'any port' address"); // 12. Attempt to match matching address without matching port + skip(1, 1) { sockaddr_set(&unmatch_v4, AF_INET, "127.0.0.1", 54321); ret = acl_match(acl, &unmatch_v4, 0); ok(ret == ACL_DENY, "acl: matching address without matching port"); + } endskip; // 13. Invalid parameters lives_ok({ acl_delete(0); - acl_create(0, 0, ACL_ERROR, 0); + acl_create(0, 0, ACL_ERROR, 0, 0); acl_match(0, 0, 0); acl_truncate(0); acl_name(0); }, "acl: won't crash with NULL parameters"); + // 14. Attempt to match subnet + sockaddr_t match_pf4, test_pf4; + sockaddr_set(&match_pf4, AF_INET, "192.168.1.0", 0); + sockaddr_setprefix(&match_pf4, 24); + acl_create(acl, &match_pf4, ACL_ACCEPT, 0, 0); + sockaddr_set(&test_pf4, AF_INET, "192.168.1.20", 0); + ret = acl_match(acl, &test_pf4, 0); + ok(ret == ACL_ACCEPT, "acl: searching address in matching prefix /24"); + + // 15. Attempt to search non-matching subnet + sockaddr_set(&test_pf4, AF_INET, "192.168.2.20", 0); + ret = acl_match(acl, &test_pf4, 0); + ok(ret == ACL_DENY, "acl: searching address in non-matching prefix /24"); + + // 16. Attempt to match v6 subnet + sockaddr_t match_pf6, test_pf6; + sockaddr_set(&match_pf6, AF_INET6, "2001:0DB8:0400:000e:0:0:0:AB00", 0); + sockaddr_setprefix(&match_pf6, 120); + acl_create(acl, &match_pf6, ACL_ACCEPT, 0, 0); + sockaddr_set(&test_pf6, AF_INET6, "2001:0DB8:0400:000e:0:0:0:AB03", 0); + ret = acl_match(acl, &test_pf6, 0); + ok(ret == ACL_ACCEPT, "acl: searching v6 address in matching prefix /120"); + + // 17. Attempt to search non-matching subnet + sockaddr_set(&test_pf6, AF_INET6, "2001:0DB8:0400:000e:0:0:0:CCCC", 0); + ret = acl_match(acl, &test_pf6, 0); + ok(ret == ACL_DENY, "acl: searching v6 address in non-matching prefix /120"); + + // 18. Add preferred node + sockaddr_set(&test_pf4, AF_INET, "192.168.1.20", 0); + void *sval = (void*)0x1234; + acl_create(acl, &match_pf4, ACL_ACCEPT, sval, ACL_PREFER); + acl_create(acl, &match_pf4, ACL_ACCEPT, 0, 0); /* Make decoy. */ + acl_key_t *rval = NULL; + ret = acl_match(acl, &test_pf4, &rval); + ok(rval->val == sval, "acl: search for preferred node"); + + acl_delete(&acl); + // Return return 0; } diff --git a/src/tests/knot/journal_tests.c b/src/tests/knot/journal_tests.c index 21c92fe..420300e 100644 --- a/src/tests/knot/journal_tests.c +++ b/src/tests/knot/journal_tests.c @@ -34,7 +34,7 @@ unit_api journal_tests_api = { /* * Unit implementation. */ -static const int JOURNAL_TEST_COUNT = 11; +static const int JOURNAL_TEST_COUNT = 12; /*! \brief Generate random string with given length. */ static int randstr(char* dst, size_t len) @@ -83,8 +83,11 @@ static int journal_tests_run(int argc, char *argv[]) ok(ret == KNOTD_EOK, "journal: create journal '%s'", jfilename); /* Test 3: Open journal. */ - journal_t *j = journal_open(jfilename, fsize, 0); - ok(j != 0, "journal: open"); + journal_t *journal = journal_open(jfilename, fsize, JOURNAL_LAZY, 0); + ok(journal != 0, "journal: open"); + + /* Retain journal. */ + journal_t *j = journal_retain(journal); /* Test 4: Write entry to log. */ const char *sample = "deadbeef"; @@ -124,17 +127,25 @@ static int journal_tests_run(int argc, char *argv[]) ok(ret == 0, "journal: read data integrity check 3 '%s'", _walkbuf); _wbi = 0; + /* Test 9: Attempt to retain and release. */ + journal_t *tmp = journal_retain(j); + ok(tmp == j, "journal: tested journal retaining"); + journal_release(tmp); + + /* Release journal. */ + journal_release(j); + /* Close journal. */ - journal_close(j); + journal_close(journal); - /* Recreate journal. */ + /* Recreate journal = NORMAL mode. */ remove(jfilename); fsize = 8092; jsize = 512; ret = journal_create(jfilename, jsize); - j = journal_open(jfilename, fsize, 0); + j = journal_open(jfilename, fsize, 0, 0); - /* Test 9: Write random data. */ + /* Test 10: Write random data. */ int chk_key = 0; char chk_buf[64] = {'\0'}; ret = 0; @@ -155,16 +166,16 @@ static int journal_tests_run(int argc, char *argv[]) } ok(ret == 0, "journal: sustained looped writes"); - /* Test 10: Check data integrity. */ + /* Test 11: Check data integrity. */ memset(tmpbuf, 0, sizeof(tmpbuf)); journal_read(j, chk_key, 0, tmpbuf); ret = strncmp(chk_buf, tmpbuf, sizeof(chk_buf)); ok(ret == 0, "journal: read data integrity check"); - /* Test 11: Reopen log and re-read value. */ + /* Test 12: Reopen log and re-read value. */ memset(tmpbuf, 0, sizeof(tmpbuf)); journal_close(j); - j = journal_open(jfilename, fsize, 0); + j = journal_open(jfilename, fsize, 0, 0); journal_read(j, chk_key, 0, tmpbuf); ret = strncmp(chk_buf, tmpbuf, sizeof(chk_buf)); ok(ret == 0, "journal: read data integrity check after close/open"); diff --git a/src/tests/libknot/libknot/node_tests.c b/src/tests/libknot/libknot/node_tests.c index d6b1e48..10b01fa 100644 --- a/src/tests/libknot/libknot/node_tests.c +++ b/src/tests/libknot/libknot/node_tests.c @@ -44,13 +44,13 @@ struct test_node { }; static knot_dname_t test_dnames[TEST_NODES] = { - {{}, (uint8_t *)"\3www\7example\3com", 17}, - {{}, (uint8_t *)"\3www\7example\3com", 17} + {{}, (uint8_t *)"\3www\7example\3com", NULL, NULL, 0, 17}, + {{}, (uint8_t *)"\3www\7example\3com", NULL, NULL, 0, 17} }; static struct test_node test_nodes[TEST_NODES] = { - {{{}, (uint8_t *)"\3com", 4}, (knot_node_t *)NULL}, - {{{}, (uint8_t *)"\3www\7example\3com", 17}, (knot_node_t *)NULL} + {{{}, (uint8_t *)"\3com", NULL, NULL, 0, 4}, (knot_node_t *)NULL}, + {{{}, (uint8_t *)"\3www\7example\3com", NULL, NULL, 0, 17}, (knot_node_t *)NULL} }; static knot_rrset_t rrsets[RRSETS] = { diff --git a/src/tests/libknot/libknot/rdata_tests.c b/src/tests/libknot/libknot/rdata_tests.c index 561686a..0c53613 100644 --- a/src/tests/libknot/libknot/rdata_tests.c +++ b/src/tests/libknot/libknot/rdata_tests.c @@ -80,10 +80,10 @@ static uint16_t *RDATA_ITEM_PTR = (uint16_t *)0xDEADBEEF; enum { RDATA_ITEMS_COUNT = 7, TEST_RDATA_COUNT = 4 , RDATA_DNAMES_COUNT = 2 }; static knot_dname_t RDATA_DNAMES[RDATA_DNAMES_COUNT] = { - {{}, (uint8_t *)"\6abcdef\7example\3com", 20, - (uint8_t *)"\x0\x7\xF", 3}, - {{}, (uint8_t *)"\6abcdef\3foo\3com", 16, - (uint8_t *)"\x0\x7\xB", 3} + {{}, (uint8_t *)"\6abcdef\7example\3com", (uint8_t *)"\x0\x7\xF", + NULL, 0, 20, 3}, + {{}, (uint8_t *)"\6abcdef\3foo\3com", (uint8_t *)"\x0\x7\xB", NULL, 0, + 16, 3} }; static knot_rdata_item_t TEST_RDATA_ITEMS[RDATA_ITEMS_COUNT] = { diff --git a/src/tests/libknot/libknot/rrset_tests.c b/src/tests/libknot/libknot/rrset_tests.c index fa75195..41284df 100644 --- a/src/tests/libknot/libknot/rrset_tests.c +++ b/src/tests/libknot/libknot/rrset_tests.c @@ -80,9 +80,9 @@ enum { enum { TEST_DOMAINS_OK = 8 }; static knot_dname_t RR_DNAMES[RR_DNAMES_COUNT] = - { {{}, (uint8_t *)"\7example\3com", 13, NULL}, //0's at the end are added - {{}, (uint8_t *)"\3ns1\7example\3com", 17, NULL}, - {{}, (uint8_t *)"\3ns2\7example\3com", 17, NULL} }; + { {{}, (uint8_t *)"\7example\3com", NULL, NULL, 0, 13, 0}, //0's at the end are added + {{}, (uint8_t *)"\3ns1\7example\3com", NULL, NULL, 0, 17, 0}, + {{}, (uint8_t *)"\3ns2\7example\3com", NULL, NULL, 0, 17, 0} }; /* 192.168.1.1 */ static uint8_t address[4] = {0xc0, 0xa8, 0x01, 0x01}; diff --git a/src/tests/libknot/libknot/tsig_tests.c b/src/tests/libknot/libknot/tsig_tests.c index 31720ec..e0a3d34 100644 --- a/src/tests/libknot/libknot/tsig_tests.c +++ b/src/tests/libknot/libknot/tsig_tests.c @@ -86,7 +86,7 @@ static int test_knot_tsig_sign() int errors = 0; /* Test bad arguments. */ int lived = 0; - lives_ok_silent({ + lives_ok({ int ret = knot_tsig_sign(NULL, NULL, 0, NULL, 0, NULL, NULL, NULL, 0, 0); if (ret != KNOT_EBADARG) { @@ -143,7 +143,7 @@ static int test_knot_tsig_sign() errors++; } lived = 1; - }, NULL); + }, ""); errors += !lived; @@ -301,7 +301,7 @@ static int test_knot_tsig_sign_next() int errors = 0; /* Test bad arguments. */ int lived = 0; - lives_ok_silent({ + lives_ok({ int ret = knot_tsig_sign_next(NULL, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL, 0); /*! \todo FIX */ if (ret != KNOT_EBADARG) { @@ -359,7 +359,7 @@ static int test_knot_tsig_sign_next() errors++; } lived = 1; - }, NULL); + }, ""); errors += !lived; @@ -416,7 +416,7 @@ static int test_knot_tsig_server_check() int errors = 0; /* Test bad arguments. */ int lived = 0; - lives_ok_silent({ + lives_ok({ int ret = knot_tsig_server_check(NULL, NULL, 0, NULL); if (ret != KNOT_EBADARG) { diag("NULL argument did not return KNOT_EBADARG!"); @@ -433,7 +433,7 @@ static int test_knot_tsig_server_check() errors++; } lived = 1; - }, NULL); + }, ""); errors += !lived; @@ -524,7 +524,7 @@ static int test_knot_tsig_client_check() errors++; } lived = 1; - }, NULL); + }, ""); errors += !lived; @@ -632,7 +632,7 @@ static int test_knot_tsig_test_tsig_add() errors++; } lived = 1; - }, NULL); + }, ""); errors += !lived; diff --git a/src/tests/libknot/libknot/zone_tests.c b/src/tests/libknot/libknot/zone_tests.c index 192996c..72aae39 100644 --- a/src/tests/libknot/libknot/zone_tests.c +++ b/src/tests/libknot/libknot/zone_tests.c @@ -46,27 +46,27 @@ struct zone_test_node { }; static struct zone_test_node test_apex = -{{{}, (uint8_t *)"\3com\0", 5, (uint8_t *)"\x0", 1}, (knot_node_t *)NULL}; +{{{}, (uint8_t *)"\3com\0", (uint8_t *)"\x0", NULL, 0, 5, 1}, (knot_node_t *)NULL}; static struct zone_test_node test_nodes_bad[TEST_NODES_BAD] = { - {{{},(uint8_t *)"\5other\6domain\0", 14, (uint8_t *)"\x0\x6", 2}, + {{{},(uint8_t *)"\5other\6domain\0", (uint8_t *)"\x0\x6", NULL, 0, 14, 2}, (knot_node_t *)NULL} }; static struct zone_test_node test_nodes_good[TEST_NODES_GOOD] = { - {{{}, (uint8_t *)"\7example\3com\0", 13, (uint8_t *)"\x0\x8", 2}, + {{{}, (uint8_t *)"\7example\3com\0", (uint8_t *)"\x0\x8", NULL, 0, 13, 2}, (knot_node_t *)NULL}, - {{{}, (uint8_t *)"\3www\7example\3com\0", 17, (uint8_t *)"\x0\x4\xC", 3}, + {{{}, (uint8_t *)"\3www\7example\3com\0", (uint8_t *)"\x0\x4\xC", NULL, 0, 17, 3}, (knot_node_t *)NULL}, - {{{}, (uint8_t *)"\7another\6domain\3com\0", 20, (uint8_t *)"\x0\x8\xF", 3}, + {{{}, (uint8_t *)"\7another\6domain\3com\0", (uint8_t *)"\x0\x8\xF", NULL, 0, 20, 3}, (knot_node_t *)NULL}, - {{{}, (uint8_t *)"\5mail1\7example\3com\0", 19, (uint8_t *)"\x0\x6\xE", 3}, + {{{}, (uint8_t *)"\5mail1\7example\3com\0", (uint8_t *)"\x0\x6\xE", NULL, 0, 19, 3}, (knot_node_t *)NULL}, - {{{}, (uint8_t *)"\5mail2\7example\3com\0", 19, (uint8_t *)"\x0\x6\xE", 3}, + {{{}, (uint8_t *)"\5mail2\7example\3com\0", (uint8_t *)"\x0\x6\xE", NULL, 0, 19, 3}, (knot_node_t *)NULL}, - {{{}, (uint8_t *)"\3smb\7example\3com\0", 17, (uint8_t *)"\x0\x4\xC", 3}, + {{{}, (uint8_t *)"\3smb\7example\3com\0", (uint8_t *)"\x0\x4\xC", NULL, 0, 17, 3}, (knot_node_t *)NULL}, - {{{}, (uint8_t *)"\4smtp\7example\3com\0", 18, (uint8_t *)"\x0\x5\xD", 3}, + {{{}, (uint8_t *)"\4smtp\7example\3com\0", (uint8_t *)"\x0\x5\xD", NULL, 0, 18, 3}, (knot_node_t *)NULL}, }; diff --git a/src/zcompile/parser-util.c b/src/zcompile/parser-util.c index 9e2e999..dde5411 100644 --- a/src/zcompile/parser-util.c +++ b/src/zcompile/parser-util.c @@ -2063,7 +2063,7 @@ uint16_t * zparser_conv_loc(char *str) return NULL; } - if (sscanf(start, "%lf", &d) != 1) { + if (sscanf(start, "%16lf", &d) != 1) { zc_error_prev_line("error parsing seconds"); } @@ -2161,7 +2161,7 @@ uint16_t * zparser_conv_loc(char *str) ++str; } - if (sscanf(start, "%lf", &d) != 1) { + if (sscanf(start, "%16lf", &d) != 1) { zc_error_prev_line("error parsing altitude"); } diff --git a/src/zcompile/zcompile.c b/src/zcompile/zcompile.c index f02fdcf..25de281 100644 --- a/src/zcompile/zcompile.c +++ b/src/zcompile/zcompile.c @@ -33,12 +33,11 @@ #include <string.h> #include <stdlib.h> #include <assert.h> +#include <sys/stat.h> #include "common/base32hex.h" #include "zcompile/zcompile.h" #include "zcompile/parser-util.h" -#include "knot/zone/zone-dump-text.h" -#include "zparser.h" #include "zcompile/zcompile-error.h" #include "knot/zone/zone-dump.h" #include "libknot/libknot.h" @@ -55,9 +54,7 @@ static long int totalrrs = 0; extern FILE *zp_get_in(void *scanner); -//#define ZP_DEBUG - -#ifdef ZP_DEBUG +#ifdef KNOT_COMPILER_DEBUG #define dbg_zp(msg...) fprintf(stderr, msg) #else #define dbg_zp(msg...) @@ -122,23 +119,33 @@ static int find_rrset_for_rrsig_in_zone(knot_zone_contents_t *zone, knot_node_t *tmp_node = NULL; - if (rrsig->type != KNOT_RRTYPE_NSEC3) { + if (knot_rdata_rrsig_type_covered(knot_rrset_rdata(rrsig)) + != KNOT_RRTYPE_NSEC3) { tmp_node = knot_zone_contents_get_node(zone, rrsig->owner); } else { tmp_node = knot_zone_contents_get_nsec3_node(zone, rrsig->owner); } + + dbg_zp("Found this node for RRSIG: %p\n", + tmp_node); if (tmp_node == NULL) { return KNOTDZCOMPILE_EINVAL; } knot_rrset_t *tmp_rrset = - knot_node_get_rrset(tmp_node, rrsig->type); + knot_node_get_rrset(tmp_node, + knot_rdata_rrsig_type_covered( + rrsig->rdata)); + + dbg_zp("Found this rrset for RRSIG: %p\n", + tmp_rrset); if (tmp_rrset == NULL) { return KNOTDZCOMPILE_EINVAL; } + if (tmp_rrset->rrsigs != NULL) { knot_zone_contents_add_rrsigs(zone, rrsig, &tmp_rrset, &tmp_node, @@ -299,7 +306,6 @@ int process_rr(void) } if (current_rrset->type == KNOT_RRTYPE_RRSIG) { - /*!< \todo Still a leak somewhere. */ knot_rrset_t *tmp_rrsig = knot_rrset_new(current_rrset->owner, KNOT_RRTYPE_RRSIG, @@ -310,7 +316,8 @@ int process_rr(void) } if (knot_rrset_add_rdata(tmp_rrsig, - current_rrset->rdata) != 0) { + current_rrset->rdata) != KNOT_EOK) { + knot_rrset_free(&tmp_rrsig); return KNOTDZCOMPILE_EBRDATA; } @@ -325,12 +332,29 @@ int process_rr(void) parser->last_node); rrset_list_delete(&parser->node_rrsigs); } - - if ((parser->last_node = create_node(contents, - current_rrset, node_add_func, - node_get_func)) == NULL) { - knot_rrset_free(&tmp_rrsig); - return KNOTDZCOMPILE_EBADNODE; + + /* The node might however been created previously. */ + parser->last_node = + knot_zone_contents_get_node(contents, + knot_rrset_owner(current_rrset)); + + if (parser->last_node == NULL) { + /* Try NSEC3 tree. */ + parser->last_node = + knot_zone_contents_get_nsec3_node( + contents, + knot_rrset_owner( + current_rrset)); + } + + if (parser->last_node == NULL) { + /* Still NULL, node has to be created. */ + if ((parser->last_node = create_node(contents, + current_rrset, node_add_func, + node_get_func)) == NULL) { + knot_rrset_free(&tmp_rrsig); + return KNOTDZCOMPILE_EBADNODE; + } } } @@ -435,6 +459,10 @@ static uint find_rrsets_orphans(knot_zone_contents_t *zone, rrset_list_t knot_rrtype_to_string(head->data->type)); } else { /* we can throw it away now */ + dbg_zp("RRSet not found for RRSIG: %s (%s)\n", + knot_dname_to_str(head->data->owner), + knot_rrtype_to_string( + knot_rdata_rrsig_type_covered(head->data->rdata))); knot_rrset_free(&head->data); } head = head->next; @@ -442,16 +470,6 @@ static uint find_rrsets_orphans(knot_zone_contents_t *zone, rrset_list_t return found_rrsets; } -/* - * - * Opens a zone file. - * - * Returns: - * - * - pointer to the parser structure - * - NULL on error and errno set - * - */ static int zone_open(const char *filename, uint32_t ttl, uint16_t rclass, knot_node_t *origin, void *scanner, knot_dname_t *origin_from_config) { @@ -470,25 +488,13 @@ static int zone_open(const char *filename, uint32_t ttl, uint16_t rclass, } } -// int fd = fileno(zp_get_in(scanner)); -// if (fd == -1) { -// return 0; -// } - -// if (fcntl(fd, F_SETLK, knot_file_lock(F_RDLCK, SEEK_SET)) == -1) { -// fprintf(stderr, "Could not lock zone file for read!\n"); -// return 0; -// } + /*!< \todo #1676 Implement proper locking. */ zparser_init(filename, ttl, rclass, origin, origin_from_config); return 1; } -/* - * Reads the specified zone into the memory - * - */ int zone_read(const char *name, const char *zonefile, const char *outfile, int semantic_checks) { @@ -507,35 +513,40 @@ int zone_read(const char *name, const char *zonefile, const char *outfile, } fclose(f); - -// char ebuf[256]; - knot_dname_t *dname = knot_dname_new_from_str(name, strlen(name), NULL); if (dname == NULL) { return KNOTDZCOMPILE_ENOMEM; } + if (!knot_dname_is_fqdn(dname)) { + fprintf(stderr, "Error: given zone origin is not FQDN.\n"); + knot_dname_release(dname); + return KNOTDZCOMPILE_EINVAL; + } + knot_node_t *origin_node = knot_node_new(dname, NULL, 0); + if (origin_node == NULL) { + knot_dname_release(dname); + return KNOTDZCOMPILE_ENOMEM; + } + + assert(knot_node_parent(origin_node) == NULL); + /*!< \todo Another copy is probably not needed. */ knot_dname_t *origin_from_config = knot_dname_new_from_str(name, strlen(name), NULL); if (origin_from_config == NULL) { - return KNOTDZCOMPILE_ENOMEM; - } - - //assert(origin_node->next == NULL); - - assert(knot_node_parent(origin_node) == NULL); - if (origin_node == NULL) { - knot_dname_release(dname); + knot_node_free(&origin_node, 0); return KNOTDZCOMPILE_ENOMEM; } void *scanner = NULL; zp_lex_init(&scanner); if (scanner == NULL) { + knot_dname_release(origin_from_config); + knot_node_free(&origin_node, 0); return KNOTDZCOMPILE_ENOMEM; } @@ -544,20 +555,18 @@ int zone_read(const char *name, const char *zonefile, const char *outfile, zc_error_prev_line("Cannot open '%s'\n", zonefile); zparser_free(); + zp_lex_destroy(scanner); + knot_dname_release(origin_from_config); + knot_node_free(&origin_node, 0); return KNOTDZCOMPILE_EZONEINVAL; } if (zp_parse(scanner) != 0) { -// int fd = fileno(zp_get_in(scanner)); -// if (fcntl(fd, F_SETLK, -// knot_file_lock(F_UNLCK, SEEK_SET)) == -1) { -// return KNOTDZCOMPILE_EACCES; -// } - + /*!< \todo #1676 Implement proper locking. */ FILE *in_file = (FILE *)zp_get_in(scanner); fclose(in_file); zp_lex_destroy(scanner); - + knot_node_free(&origin_node, 0); return KNOTDZCOMPILE_ESYNT; } @@ -567,13 +576,8 @@ int zone_read(const char *name, const char *zonefile, const char *outfile, FILE *in_file = (FILE *)zp_get_in(scanner); fclose(in_file); zp_lex_destroy(scanner); - - /* Unlock zone file. */ -// int fd = fileno(zp_get_in(scanner)); -// if (fcntl(fd, F_SETLK, knot_file_lock(F_UNLCK, SEEK_SET)) == -1) { -// fprintf(stderr, "Could not lock zone file for read!\n"); -// return 0; -// } + + /*!< \todo #1676 Implement proper locking. */ dbg_zp("zp complete %p\n", parser->current_zone); @@ -592,6 +596,7 @@ int zone_read(const char *name, const char *zonefile, const char *outfile, zc_error_prev_line("Zone file does not contain SOA record!\n"); knot_zone_deep_free(&parser->current_zone, 1); zparser_free(); + knot_node_free(&origin_node, 0); return KNOTDZCOMPILE_EZONEINVAL; } @@ -604,6 +609,7 @@ int zone_read(const char *name, const char *zonefile, const char *outfile, rrset_list_delete(&parser->rrsig_orphans); if (found_orphans != parser->rrsig_orphan_count) { + /*! \todo This might be desired behaviour. */ fprintf(stderr, "There are unassigned RRSIGs in the zone!\n"); parser->errors++; @@ -618,12 +624,49 @@ int zone_read(const char *name, const char *zonefile, const char *outfile, fprintf(stderr, "Parser finished with error, not dumping the zone!\n"); } else { - if (knot_zdump_binary(contents, - outfile, semantic_checks, - zonefile) != 0) { - fprintf(stderr, "Could not dump zone!\n"); + int fd = open(outfile, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU | S_IRWXG); + if (fd < 0) { + fprintf(stderr, + "Could not open destination file for db: %s.\n", + outfile); totalerrors++; + } else { + crc_t crc; + int ret = knot_zdump_binary(contents, fd, + semantic_checks, + zonefile, &crc); + if (ret != KNOT_EOK) { + fprintf(stderr, "Could not dump zone, reason: " + "%s.\n", knot_strerror(ret)); + remove(outfile); + totalerrors++; + } else { + /* Write CRC file. */ + char *crc_path = knot_zdump_crc_file(outfile); + if (crc_path == NULL) { + fprintf(stderr, + "Could not get crc file path.\n"); + remove(outfile); + totalerrors++; + } else { + FILE *f_crc = fopen(crc_path, "w"); + if (f_crc == NULL) { + fprintf(stderr, + "Could not open crc file \n"); + remove(outfile); + totalerrors++; + } else { + fprintf(f_crc, + "%lu", + (unsigned long)crc); + fclose(f_crc); + } + } + free(crc_path); + } } + + dbg_zp("zone dumped.\n"); } diff --git a/src/zcompile/zcompile.h b/src/zcompile/zcompile.h index 33dd3ee..37b3791 100644 --- a/src/zcompile/zcompile.h +++ b/src/zcompile/zcompile.h @@ -142,6 +142,7 @@ struct zparser { rrset_list_t *node_rrsigs; /*!< List of RRSIGs in current node. */ int rdata_count; /*!< Count of parsed rdata. */ + int origin_directive; /*!< Set to 1 if $ORIGIN directive is present. */ }; typedef struct zparser zparser_type; diff --git a/src/zcompile/zcompile_main.c b/src/zcompile/zcompile_main.c index cb862f8..c02b780 100644 --- a/src/zcompile/zcompile_main.c +++ b/src/zcompile/zcompile_main.c @@ -19,8 +19,6 @@ #include <stdlib.h> #include "zcompile/zcompile.h" -#include "zcompile/zcompile-error.h" -#include "common/errors.h" #include <config.h> static void help(int argc, char **argv) diff --git a/src/zcompile/zparser.y b/src/zcompile/zparser.y index c43b968..59f037d 100644 --- a/src/zcompile/zparser.y +++ b/src/zcompile/zparser.y @@ -307,11 +307,13 @@ ttl_directive: DOLLAR_TTL sp STR trail origin_directive: DOLLAR_ORIGIN sp abs_dname trail { + /*!< \todo this will leak. */ knot_node_t *origin_node = knot_node_new($3 ,NULL, 0); if (parser->origin != NULL) { // knot_node_free(&parser->origin, 1); } parser->origin = origin_node; + parser->origin_directive = 1; } | DOLLAR_ORIGIN sp rel_dname trail { @@ -392,7 +394,6 @@ dname: abs_dname } else { $$ = knot_dname_cat($1, parser->origin->owner); -// printf("leak: %s\n", knot_dname_to_str($$)); } } ; @@ -404,7 +405,12 @@ abs_dname: '.' } | '@' { + if (parser->origin_directive) { $$ = parser->origin->owner; + } else { + zc_error("@ used, but no $ORIGIN specified.\n"); + $$ = parser->origin->owner; + } } | rel_dname '.' { @@ -422,10 +428,7 @@ label: STR zc_error("label exceeds %d character limit", MAXLABELLEN); $$ = error_dname; } else { -// printf("%s\n", $1.str); $$ = knot_dname_new_from_str($1.str, $1.len, NULL); -// printf("Creating new (label): %s %p\n", $1.str, $$); -// printf("new: %p %s\n", $$, $1.str); $$->ref.count = 0; } @@ -1620,6 +1623,8 @@ zparser_init(const char *filename, uint32_t ttl, uint16_t rclass, parser->current_rrset->rclass = parser->default_class; parser->current_rrset->rdata = NULL; + + parser->origin_directive = 0; } |