From 9dea1519eb1ce6a9c3f1e5c53559558064eeafc7 Mon Sep 17 00:00:00 2001 From: Ondřej Surý Date: Wed, 16 May 2012 09:20:01 +0200 Subject: Imported Upstream version 1.0.4 --- KNOWN_ISSUES | 1 - Knot.files | 1 - RELNOTES | 27 +- configure | 142 ++++++++- configure.ac | 9 +- samples/knot.full.conf | 10 + src/Makefile.am | 1 - src/Makefile.in | 13 +- src/common/crc.c | 155 ---------- src/common/crc.h | 91 ++---- src/common/log.c | 18 +- src/config.h.in | 3 + src/knot/conf/cf-lex.l | 1 + src/knot/conf/cf-parse.y | 4 + src/knot/conf/conf.c | 5 + src/knot/conf/conf.h | 2 + src/knot/ctl/knotc_main.c | 124 +++++--- src/knot/main.c | 47 +-- src/knot/server/dthreads.c | 54 +++- src/knot/server/dthreads.h | 33 +- src/knot/server/journal.c | 18 +- src/knot/server/journal.h | 2 +- src/knot/server/notify.c | 13 +- src/knot/server/server.c | 47 ++- src/knot/server/server.h | 10 + src/knot/server/tcp-handler.c | 43 ++- src/knot/server/udp-handler.c | 78 +++-- src/knot/server/xfr-handler.c | 15 +- src/knot/server/zones.c | 571 +++++++++++++++++++++-------------- src/knot/zone/zone-dump-text.c | 4 +- src/knot/zone/zone-dump-text.h | 4 +- src/knot/zone/zone-dump.c | 5 +- src/knot/zone/zone-dump.h | 2 +- src/knot/zone/zone-load.c | 34 ++- src/libknot/dname.c | 13 +- src/libknot/nameserver/name-server.c | 82 +++-- src/libknot/nameserver/name-server.h | 11 +- src/libknot/updates/xfr-in.c | 203 +++++-------- src/libknot/util/descriptor.c | 7 + src/libknot/util/descriptor.h | 1 + src/libknot/zone/node.c | 218 +++++++------ src/libknot/zone/zone-contents.c | 67 ++-- src/libknot/zone/zone-contents.h | 25 +- src/zcompile/parser-descriptor.c | 7 +- src/zcompile/parser-descriptor.h | 1 + src/zcompile/parser-util.c | 6 +- src/zcompile/zcompile.c | 30 +- src/zcompile/zcompile_main.c | 10 +- src/zcompile/zlexer.l | 5 +- src/zcompile/zparser.y | 29 +- 50 files changed, 1366 insertions(+), 936 deletions(-) delete mode 100644 src/common/crc.c diff --git a/KNOWN_ISSUES b/KNOWN_ISSUES index 1d87958..30ced5e 100644 --- a/KNOWN_ISSUES +++ b/KNOWN_ISSUES @@ -10,5 +10,4 @@ current version of Knot. Known bugs ========== -* IXFR may be slow when too much (10 000+) RRSets are transfered at once. * Slow start with too many zones. diff --git a/Knot.files b/Knot.files index d283f32..71a588f 100644 --- a/Knot.files +++ b/Knot.files @@ -98,7 +98,6 @@ src/common/acl.c src/common/acl.h src/common/sockaddr.h src/common/sockaddr.c -src/common/crc.c src/common/crc.h src/common/ref.c src/common/ref.h diff --git a/RELNOTES b/RELNOTES index e0297d6..76c74e2 100644 --- a/RELNOTES +++ b/RELNOTES @@ -1,4 +1,29 @@ -v1.0.3 - Apr 17, 2011 +v1.0.4 - May 16, 2012 +--------------------- + +New features: + * Parallel loading of zones to the server. + * RFC3339-complaint format of log time. + * Support for TLSA (RR type 52). + * knotc checkzone (as a dry-run of zone compile). + * knotc refresh for forcing Knot to update all zones from master + servers. + * Reopening log files upon start (used to truncate them). + +Bugfixes: + * Copying OPCODE and RD bit from query to NOTIMPL responses. + * Corrected response to CNAME queries if the canonical name was also + an alias (was adding the whole CNAME chain to the response). + * Fixed crash when NS or MX points to an alias. + * Fixed problem with early closing of filedescriptors (lead to crash + when compiling and loading or bootstrapping and restarting the server + with a lot of zones). + +Other improvements: + * Significantly sped up IXFR-in and reduced its memory requirements. + + +v1.0.3 - Apr 17, 2012 --------------------- Bugfixes: diff --git a/configure b/configure index 692c858..a6b20e9 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.68 for knot 1.0.3. +# Generated by GNU Autoconf 2.68 for knot 1.0.4. # # Report bugs to . # @@ -570,8 +570,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='knot' PACKAGE_TARNAME='knot' -PACKAGE_VERSION='1.0.3' -PACKAGE_STRING='knot 1.0.3' +PACKAGE_VERSION='1.0.4' +PACKAGE_STRING='knot 1.0.4' PACKAGE_BUGREPORT='knot-dns@labs.nic.cz' PACKAGE_URL='' @@ -1303,7 +1303,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures knot 1.0.3 to adapt to many kinds of systems. +\`configure' configures knot 1.0.4 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1373,7 +1373,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of knot 1.0.3:";; + short | recursive ) echo "Configuration of knot 1.0.4:";; esac cat <<\_ACEOF @@ -1491,7 +1491,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -knot configure 1.0.3 +knot configure 1.0.4 generated by GNU Autoconf 2.68 Copyright (C) 2010 Free Software Foundation, Inc. @@ -2041,7 +2041,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by knot $as_me 1.0.3, which was +It was created by knot $as_me 1.0.4, which was generated by GNU Autoconf 2.68. Invocation command line was $ $0 $@ @@ -2859,7 +2859,7 @@ fi # Define the identity of the package. PACKAGE='knot' - VERSION='1.0.3' + VERSION='1.0.4' cat >>confdefs.h <<_ACEOF @@ -13237,6 +13237,70 @@ $as_echo "#define ENABLE_RECVMMSG 1" >>confdefs.h fi +# Check for link time optimizations support and predictive commoning + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts \"-flto\"" >&5 +$as_echo_n "checking whether C compiler accepts \"-flto\"... " >&6; } +ax_save_FLAGS=$CFLAGS + CFLAGS=""-flto"" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval `$as_echo "ax_cv_c_flags_"-flto"" | $as_tr_sh`=yes +else + eval `$as_echo "ax_cv_c_flags_"-flto"" | $as_tr_sh`=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS=$ax_save_FLAGS +eval ax_check_compiler_flags=$`$as_echo "ax_cv_c_flags_"-flto"" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_check_compiler_flags" >&5 +$as_echo "$ax_check_compiler_flags" >&6; } +if test "x$ax_check_compiler_flags" = xyes; then + CFLAGS="$CFLAGS -flto" +else + : +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts \"-fpredictive-commoning\"" >&5 +$as_echo_n "checking whether C compiler accepts \"-fpredictive-commoning\"... " >&6; } +ax_save_FLAGS=$CFLAGS + CFLAGS=""-fpredictive-commoning"" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval `$as_echo "ax_cv_c_flags_"-fpredictive-commoning"" | $as_tr_sh`=yes +else + eval `$as_echo "ax_cv_c_flags_"-fpredictive-commoning"" | $as_tr_sh`=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS=$ax_save_FLAGS +eval ax_check_compiler_flags=$`$as_echo "ax_cv_c_flags_"-fpredictive-commoning"" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_check_compiler_flags" >&5 +$as_echo "$ax_check_compiler_flags" >&6; } +if test "x$ax_check_compiler_flags" = xyes; then + CFLAGS="$CFLAGS -fpredictive-commoning" +else + : +fi + + # Checks for libraries. # FIXME: Replace `main' with a function in `-lm': # TODO: check if paths exist before appending @@ -13696,6 +13760,62 @@ if test "$ac_res" != no; then : fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing crc32" >&5 +$as_echo_n "checking for library containing crc32... " >&6; } +if ${ac_cv_search_crc32+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char crc32 (); +int +main () +{ +return crc32 (); + ; + return 0; +} +_ACEOF +for ac_lib in '' z; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_crc32=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_crc32+:} false; then : + break +fi +done +if ${ac_cv_search_crc32+:} false; then : + +else + ac_cv_search_crc32=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_crc32" >&5 +$as_echo "$ac_cv_search_crc32" >&6; } +ac_res=$ac_cv_search_crc32 +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + #AC_SEARCH_LIBS([ldns_rr_list_pop_rrset], [ldns], [], [AC_MSG_ERROR([libldns not found])]) # Checks for header files. @@ -14393,7 +14513,7 @@ $as_echo "#define HAVE_MMAP 1" >>confdefs.h fi rm -f conftest.mmap conftest.txt -for ac_func in gethostbyname gettimeofday clock_gettime memalign memmove memset munmap regcomp pselect select socket sqrt strcasecmp strchr strdup strerror strncasecmp strtol strtoul poll epoll_wait kqueue setgroups sendmmsg madvise +for ac_func in gethostbyname gettimeofday clock_gettime memalign memmove memset munmap regcomp pselect select socket sqrt strcasecmp strchr strdup strerror strncasecmp strtol strtoul poll epoll_wait kqueue setgroups sendmmsg madvise pthread_setaffinity_np do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" @@ -14950,7 +15070,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.3, which was +This file was extended by knot $as_me 1.0.4, which was generated by GNU Autoconf 2.68. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -15016,7 +15136,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.3 +knot config.status 1.0.4 configured by $0, generated by GNU Autoconf 2.68, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index c2b498f..1f413cc 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ # -*- Autoconf -*- AC_PREREQ([2.65]) -AC_INIT([knot], [1.0.3], [knot-dns@labs.nic.cz]) +AC_INIT([knot], [1.0.4], [knot-dns@labs.nic.cz]) AM_INIT_AUTOMAKE([gnu -Wall -Werror]) AC_CONFIG_SRCDIR([src/knot/main.c]) AC_CONFIG_HEADERS([src/config.h]) @@ -122,6 +122,10 @@ AC_ARG_ENABLE([recvmmsg], recvmmsg=true ]) +# Check for link time optimizations support and predictive commoning +AX_CHECK_COMPILER_FLAGS("-flto", [CFLAGS="$CFLAGS -flto"], []) +AX_CHECK_COMPILER_FLAGS("-fpredictive-commoning", [CFLAGS="$CFLAGS -fpredictive-commoning"], []) + # Checks for libraries. # FIXME: Replace `main' with a function in `-lm': # TODO: check if paths exist before appending @@ -135,6 +139,7 @@ AC_SEARCH_LIBS([dlopen], [dl]) AC_SEARCH_LIBS([clock_gettime], [rt]) AC_SEARCH_LIBS([OpenSSL_add_all_digests], [crypto],[], [AC_MSG_ERROR([libcrypto not found])]) AC_SEARCH_LIBS([capng_apply], [cap-ng]) +AC_SEARCH_LIBS([crc32], [z]) #AC_SEARCH_LIBS([ldns_rr_list_pop_rrset], [ldns], [], [AC_MSG_ERROR([libldns not found])]) # Checks for header files. @@ -159,7 +164,7 @@ AC_DEFINE([DSFMT_MEXP], [521], [DSFMT parameters.]) # Checks for library functions. AC_FUNC_FORK AC_FUNC_MMAP -AC_CHECK_FUNCS([gethostbyname gettimeofday clock_gettime memalign memmove memset munmap regcomp pselect select socket sqrt strcasecmp strchr strdup strerror strncasecmp strtol strtoul poll epoll_wait kqueue setgroups sendmmsg madvise]) +AC_CHECK_FUNCS([gethostbyname gettimeofday clock_gettime memalign memmove memset munmap regcomp pselect select socket sqrt strcasecmp strchr strdup strerror strncasecmp strtol strtoul poll epoll_wait kqueue setgroups sendmmsg madvise pthread_setaffinity_np]) AC_CONFIG_FILES([Makefile samples/Makefile diff --git a/samples/knot.full.conf b/samples/knot.full.conf index 6ed027e..d9d9de7 100644 --- a/samples/knot.full.conf +++ b/samples/knot.full.conf @@ -123,6 +123,11 @@ zones { # Possible values: on|off # Default value: off semantic-checks off; + + # Disable ANY type queries for authoritative answers (if 'on') + # Possible values: on|off + # Default value: off + disable-any off; # NOTIFY response timeout # Possible values: <1,...> (seconds) @@ -157,6 +162,11 @@ zones { # was started. file "samples/example.com.zone"; + # Disable ANY type queries for authoritative answers (if 'on') + # Possible values: on|off + # Default value: off + disable-any off; + # Enable zone semantic checks # Possible values: on|off # Default value: off diff --git a/src/Makefile.am b/src/Makefile.am index a1bb196..60c51c6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -247,7 +247,6 @@ libknots_la_SOURCES = \ common/sockaddr.h \ common/sockaddr.c \ common/crc.h \ - common/crc.c \ common/ref.h \ common/ref.c \ common/errors.h \ diff --git a/src/Makefile.in b/src/Makefile.in index f35f211..c00450d 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -80,8 +80,8 @@ libknots_la_DEPENDENCIES = @LIBOBJS@ am_libknots_la_OBJECTS = slab.lo tap.lo mempattern.lo lists.lo \ base32.lo print.lo dynamic-array.lo skip-list.lo base32hex.lo \ general-tree.lo evqueue.lo evsched.lo acl.lo sockaddr.lo \ - crc.lo ref.lo errors.lo dSFMT.lo prng.lo fdset.lo \ - fdset_poll.lo fdset_kqueue.lo fdset_epoll.lo log.lo + ref.lo errors.lo dSFMT.lo prng.lo fdset.lo fdset_poll.lo \ + fdset_kqueue.lo fdset_epoll.lo log.lo libknots_la_OBJECTS = $(am_libknots_la_OBJECTS) am__installdirs = "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(sbindir)" \ "$(DESTDIR)$(man8dir)" @@ -570,7 +570,6 @@ libknots_la_SOURCES = \ common/sockaddr.h \ common/sockaddr.c \ common/crc.h \ - common/crc.c \ common/ref.h \ common/ref.c \ common/errors.h \ @@ -849,7 +848,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conf.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conf_tests.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conv.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cuckoo-hash-table.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cuckoo_tests.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dSFMT.Plo@am__quote@ @@ -1420,13 +1418,6 @@ sockaddr.lo: common/sockaddr.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sockaddr.lo `test -f 'common/sockaddr.c' || echo '$(srcdir)/'`common/sockaddr.c -crc.lo: common/crc.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT crc.lo -MD -MP -MF $(DEPDIR)/crc.Tpo -c -o crc.lo `test -f 'common/crc.c' || echo '$(srcdir)/'`common/crc.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/crc.Tpo $(DEPDIR)/crc.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/crc.c' object='crc.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o crc.lo `test -f 'common/crc.c' || echo '$(srcdir)/'`common/crc.c - ref.lo: common/ref.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ref.lo -MD -MP -MF $(DEPDIR)/ref.Tpo -c -o ref.lo `test -f 'common/ref.c' || echo '$(srcdir)/'`common/ref.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ref.Tpo $(DEPDIR)/ref.Plo diff --git a/src/common/crc.c b/src/common/crc.c deleted file mode 100644 index 33bf903..0000000 --- a/src/common/crc.c +++ /dev/null @@ -1,155 +0,0 @@ -/* - Copyright (c) 2006-2011, Thomas Pircher - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - */ - -/** - * \file crc.c - * Functions and types for CRC checks. - * - * Generated on Fri May 6 11:25:47 2011, - * by pycrc v0.7.7, http://www.tty1.net/pycrc/ - * using the configuration: - * Width = 32 - * Poly = 0x04c11db7 - * XorIn = 0xffffffff - * ReflectIn = True - * XorOut = 0xffffffff - * ReflectOut = True - * Algorithm = table-driven - *****************************************************************************/ -#include "crc.h" -#include -#include - -/** - * Static table used for the table_driven implementation. - *****************************************************************************/ -static const crc_t crc_table[256] = { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, - 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, - 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, - 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, - 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, - 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, - 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, - 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, - 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, - 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, - 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, - 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, - 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, - 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, - 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, - 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, - 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, - 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, - 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, - 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, - 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, - 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, - 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, - 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, - 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, - 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, - 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, - 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, - 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, - 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, - 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, - 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, - 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, - 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, - 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, - 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, - 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, - 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, - 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, - 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, - 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, - 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, - 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, - 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, - 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, - 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, - 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, - 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, - 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d -}; - -/** - * Reflect all bits of a \a data word of \a data_len bytes. - * - * \param data The data word to be reflected. - * \param data_len The width of \a data expressed in number of bits. - * \return The reflected data. - *****************************************************************************/ -crc_t crc_reflect(crc_t data, size_t data_len) -{ - unsigned int i; - crc_t ret; - - ret = data & 0x01; - for (i = 1; i < data_len; i++) { - data >>= 1; - ret = (ret << 1) | (data & 0x01); - } - return ret; -} - - -/** - * Update the crc value with new data. - * - * \param crc The current crc value. - * \param data Pointer to a buffer of \a data_len bytes. - * \param data_len Number of bytes in the \a data buffer. - * \return The updated crc value. - *****************************************************************************/ -crc_t crc_update(crc_t crc, const unsigned char *data, size_t data_len) -{ - unsigned int tbl_idx; - - while (data_len--) { - tbl_idx = (crc ^ *data) & 0xff; - crc = (crc_table[tbl_idx] ^ (crc >> 8)) & 0xffffffff; - - data++; - } - return crc & 0xffffffff; -} - - - diff --git a/src/common/crc.h b/src/common/crc.h index 41971a9..cf2e123 100644 --- a/src/common/crc.h +++ b/src/common/crc.h @@ -1,54 +1,34 @@ -/* - Copyright (c) 2006-2011, Thomas Pircher - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. + * + * 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 . */ -/** +/*! * \file crc.h - * Functions and types for CRC checks. * - * Generated on Fri May 6 11:25:43 2011, - * by pycrc v0.7.7, http://www.tty1.net/pycrc/ - * using the configuration: - * Width = 32 - * Poly = 0x04c11db7 - * XorIn = 0xffffffff - * ReflectIn = True - * XorOut = 0xffffffff - * ReflectOut = True - * Algorithm = table-driven - *****************************************************************************/ + * \author UFO + * + * \brief Dummy interface to CRC function of libz library. Should be removed + * + * \addtogroup common_lib + * @{ + */ + #ifndef __CRC_H__ #define __CRC_H__ +#include #include -#include - -#ifdef __cplusplus -extern "C" { -#endif - - -/** - * The definition of the used algorithm. - *****************************************************************************/ -#define CRC_ALGO_TABLE_DRIVEN 1 /** @@ -59,16 +39,6 @@ extern "C" { typedef uint32_t crc_t; -/** - * Reflect all bits of a \a data word of \a data_len bytes. - * - * \param data The data word to be reflected. - * \param data_len The width of \a data expressed in number of bits. - * \return The reflected data. - *****************************************************************************/ -crc_t crc_reflect(crc_t data, size_t data_len); - - /** * Calculate the initial crc value. * @@ -76,7 +46,7 @@ crc_t crc_reflect(crc_t data, size_t data_len); *****************************************************************************/ static inline crc_t crc_init(void) { - return 0xffffffff; + return adler32(0L, NULL, 0); } @@ -88,7 +58,10 @@ static inline crc_t crc_init(void) * \param data_len Number of bytes in the \a data buffer. * \return The updated crc value. *****************************************************************************/ -crc_t crc_update(crc_t crc, const unsigned char *data, size_t data_len); +static inline crc_t crc_update(crc_t crc, const unsigned char *data, size_t data_len) +{ + return adler32(crc, data, data_len); +} /** @@ -99,12 +72,8 @@ crc_t crc_update(crc_t crc, const unsigned char *data, size_t data_len); *****************************************************************************/ static inline crc_t crc_finalize(crc_t crc) { - return crc ^ 0xffffffff; + return crc; } -#ifdef __cplusplus -} /* closing brace for extern "C" */ -#endif - #endif /* __CRC_H__ */ diff --git a/src/common/log.c b/src/common/log.c index 6d77ccb..c70f739 100644 --- a/src/common/log.c +++ b/src/common/log.c @@ -14,11 +14,14 @@ along with this program. If not, see . */ +#define _BSD_SOURCE #include #include #include #include #include +#include +#include #include "common/log.h" #include "common/lists.h" @@ -140,7 +143,7 @@ int log_open_file(const char* filename) } // Open file - LOG_FDS[LOG_FDS_OPEN] = fopen(filename, "w"); + LOG_FDS[LOG_FDS_OPEN] = fopen(filename, "a"); if (!LOG_FDS[LOG_FDS_OPEN]) { return KNOTD_EINVAL; } @@ -212,14 +215,15 @@ static int _log_msg(logsrc_t src, int level, const char *msg) /* Prefix date and time. */ char tstr[128] = {0}; int tlen = 0; - time_t t = time(NULL); - struct tm *lt = localtime(&t); - if (lt != NULL) { + struct tm lt; + struct timeval tv; + gettimeofday(&tv, NULL); + if (localtime_r(&tv.tv_sec, <) != NULL) { tlen = strftime(tstr, sizeof(tstr) - 1, - "%d-%m-%Y %H:%M:%S", lt); + "%Y-%m-%dT%H:%M:%S", <); if (tlen > 0) { - tstr[tlen] = ' '; - tstr[tlen + 1] = '\0'; + char pm = (lt.tm_gmtoff > 0)?'+':'-'; + snprintf(tstr+tlen, 128-tlen-1, ".%.6lu%c%.2u:%.2u ", (unsigned long)tv.tv_usec, pm, (unsigned int)lt.tm_gmtoff/3600, (unsigned int)(lt.tm_gmtoff/60)%60); } } diff --git a/src/config.h.in b/src/config.h.in index 905e327..bd88e96 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -105,6 +105,9 @@ /* Define to 1 if you have the `pselect' function. */ #undef HAVE_PSELECT +/* Define to 1 if you have the `pthread_setaffinity_np' function. */ +#undef HAVE_PTHREAD_SETAFFINITY_NP + /* Define to 1 if you have the `regcomp' function. */ #undef HAVE_REGCOMP diff --git a/src/knot/conf/cf-lex.l b/src/knot/conf/cf-lex.l index dfd0ac7..16b0343 100644 --- a/src/knot/conf/cf-lex.l +++ b/src/knot/conf/cf-lex.l @@ -77,6 +77,7 @@ remotes { lval.t = yytext; return REMOTES; } zones { lval.t = yytext; return ZONES; } file { lval.t = yytext; return FILENAME; } +disable-any { lval.t = yytext; return DISABLE_ANY; } semantic-checks { lval.t = yytext; return SEMANTIC_CHECKS; } notify-retries { lval.t = yytext; return NOTIFY_RETRIES; } notify-timeout { lval.t = yytext; return NOTIFY_TIMEOUT; } diff --git a/src/knot/conf/cf-parse.y b/src/knot/conf/cf-parse.y index 4981606..b415662 100644 --- a/src/knot/conf/cf-parse.y +++ b/src/knot/conf/cf-parse.y @@ -171,6 +171,7 @@ static void conf_zone_start(void *scanner, char *name) { this_zone->notify_retries = 0; // Default policy applies this_zone->ixfr_fslimit = -1; // Default policy applies this_zone->dbsync_timeout = -1; // Default policy applies + this_zone->disable_any = -1; // Default policy applies // Append mising dot to ensure FQDN size_t nlen = strlen(name); @@ -255,6 +256,7 @@ static int conf_mask(void* scanner, int nval, int prefixlen) { %token REMOTES %token ZONES FILENAME +%token DISABLE_ANY %token SEMANTIC_CHECKS %token NOTIFY_RETRIES %token NOTIFY_TIMEOUT @@ -642,6 +644,7 @@ zone: | zone zone_acl_list | zone FILENAME TEXT ';' { this_zone->file = $3.t; } | zone SEMANTIC_CHECKS BOOL ';' { this_zone->enable_checks = $3.i; } + | zone DISABLE_ANY BOOL ';' { this_zone->disable_any = $3.i; } | zone DBSYNC_TIMEOUT NUM ';' { this_zone->dbsync_timeout = $3.i; } | zone DBSYNC_TIMEOUT INTERVAL ';' { this_zone->dbsync_timeout = $3.i; } | zone IXFR_FSLIMIT SIZE ';' { new_config->ixfr_fslimit = $3.l; } @@ -665,6 +668,7 @@ zone: zones: ZONES '{' | zones zone '}' + | zones DISABLE_ANY BOOL ';' { new_config->disable_any = $3.i; } | zones SEMANTIC_CHECKS BOOL ';' { new_config->zone_checks = $3.i; } | zones IXFR_FSLIMIT SIZE ';' { new_config->ixfr_fslimit = $3.l; } | zones IXFR_FSLIMIT NUM ';' { new_config->ixfr_fslimit = $3.i; } diff --git a/src/knot/conf/conf.c b/src/knot/conf/conf.c index 2cb4516..4bbf622 100644 --- a/src/knot/conf/conf.c +++ b/src/knot/conf/conf.c @@ -219,6 +219,11 @@ static int conf_process(conf_t *conf) if (zone->enable_checks < 0) { zone->enable_checks = conf->zone_checks; } + + // Default policy for disabling ANY type queries for AA + if (zone->disable_any < 0) { + zone->disable_any = conf->disable_any; + } // Default policy for NOTIFY retries if (zone->notify_retries <= 0) { diff --git a/src/knot/conf/conf.h b/src/knot/conf/conf.h index 40cd1cc..7e1b61f 100644 --- a/src/knot/conf/conf.h +++ b/src/knot/conf/conf.h @@ -93,6 +93,7 @@ typedef struct conf_zone_t { size_t ixfr_fslimit; /*!< File size limit for IXFR journal. */ int dbsync_timeout; /*!< Interval between syncing to zonefile.*/ int enable_checks; /*!< Semantic checks for parser.*/ + int disable_any; /*!< Disable ANY type queries for AA.*/ int notify_retries; /*!< NOTIFY query retries. */ int notify_timeout; /*!< Timeout for NOTIFY response (s). */ struct { @@ -191,6 +192,7 @@ typedef struct conf_t { list zones; /*!< List of zones. */ int zones_count; /*!< Count of zones. */ int zone_checks; /*!< Semantic checks for parser.*/ + int disable_any; /*!< Disable ANY type queries for AA.*/ int notify_retries; /*!< NOTIFY query retries. */ int notify_timeout; /*!< Timeout for NOTIFY response in seconds. */ int dbsync_timeout; /*!< Default interval between syncing to zonefile.*/ diff --git a/src/knot/ctl/knotc_main.c b/src/knot/ctl/knotc_main.c index 436cc5e..97412dd 100644 --- a/src/knot/ctl/knotc_main.c +++ b/src/knot/ctl/knotc_main.c @@ -54,7 +54,7 @@ static inline unsigned has_flag(unsigned flags, enum knotc_flag_t f) { void help(int argc, char **argv) { printf("Usage: %sc [parameters] start|stop|restart|reload|running|" - "compile\n", PACKAGE_NAME); + "compile [additional]\n", PACKAGE_NAME); printf("Parameters:\n" " -c [file], --config=[file] Select configuration file.\n" " -j [num], --jobs=[num] Number of parallel tasks to run (only for 'compile').\n" @@ -63,7 +63,7 @@ void help(int argc, char **argv) " -V, --version Print %s server version.\n" " -w, --wait Wait for the server to finish start/stop operations.\n" " -i, --interactive Interactive mode (do not daemonize).\n" - " -a, --auto Enable automatic recompilation (start or reload)." + " -a, --auto Enable automatic recompilation (start or reload).\n" " -h, --help Print help and usage.\n", PACKAGE_NAME); printf("Actions:\n" @@ -71,10 +71,13 @@ void help(int argc, char **argv) " stop Stop %s server (no-op if not running).\n" " restart Stops and then starts %s server.\n" " reload Reload %s configuration and compiled zones.\n" + " refresh Refresh all slave zones.\n" " running Check if server is running.\n" " checkconf Check server configuration.\n" "\n" - " compile Compile zone file.\n", + " checkzone Check zones (accepts specific zones, f.e. " + "'knotc checkzone example1.com example2.com').\n" + " compile Compile zones (accepts specific zones, see above).\n", PACKAGE_NAME, PACKAGE_NAME, PACKAGE_NAME, PACKAGE_NAME); } @@ -205,7 +208,7 @@ knotc_zctask_t *zctask_create(int count) } /*! \brief Wait for single task to finish. */ -int zctask_wait(knotc_zctask_t *tasks, int count) +int zctask_wait(knotc_zctask_t *tasks, int count, int is_checkzone) { /* Wait for children to finish. */ int rc = 0; @@ -229,16 +232,18 @@ int zctask_wait(knotc_zctask_t *tasks, int count) /* Evaluate. */ if (!WIFEXITED(rc)) { - log_server_error("Compilation of '%s' " - "failed, process was killed.\n", + log_server_error("%s of '%s' failed, process was killed.\n", + is_checkzone ? "Checking" : "Compilation", z->name); return 1; } else { if (rc < 0 || WEXITSTATUS(rc) != 0) { - log_server_error("Compilation of " - "'%s' failed, knot-zcompile " - "return code was '%d'\n", - z->name, WEXITSTATUS(rc)); + if (!is_checkzone) { + log_zone_error("Compilation of " + "'%s' failed, knot-zcompile " + "return code was '%d'\n", + z->name, WEXITSTATUS(rc)); + } return 1; } } @@ -446,11 +451,7 @@ int execute(const char *action, char **argv, int argc, pid_t pid, log_server_warning("Server PID not found, " "probably not running.\n"); - if (has_flag(flags, F_FORCE)) { - log_server_info("Forcing server stop.\n"); - } else { - return 1; - } + return 1; } // Recompile zones if needed @@ -461,8 +462,27 @@ int execute(const char *action, char **argv, int argc, pid_t pid, // Stop if (kill(pid, SIGHUP) < 0) { - pid_remove(pidfile); rc = 1; + } else { + log_server_info("Server reload queued - OK.\n"); + } + } + if (strcmp(action, "refresh") == 0) { + + // Check PID + valid_cmd = 1; + if (pid <= 0 || !pid_running(pid)) { + log_server_warning("Server PID not found, " + "probably not running.\n"); + + return 1; + } + + // Stop + if (kill(pid, SIGUSR2) < 0) { + rc = 1; + } else { + log_server_info("Zones refresh queued - OK.\n"); } } if (strcmp(action, "running") == 0) { @@ -490,18 +510,22 @@ int execute(const char *action, char **argv, int argc, pid_t pid, rc = 0; valid_cmd = 1; } - if (strcmp(action, "compile") == 0) { + if (strcmp(action, "compile") == 0 || strcmp(action, "checkzone") == 0){ // Print job count - if (jobs > 1) { + if (jobs > 1 && argc == 0) { log_server_warning("Will attempt to compile %d zones " "in parallel, this increases memory " - "consumption for large zones.\n", jobs); + "consumption for large zones.\n", + jobs); } + // Zone checking + int is_checkzone = (strcmp(action, "checkzone") == 0); + // Check zone valid_cmd = 1; - + // Lock configuration conf_read_lock(); @@ -513,57 +537,81 @@ int execute(const char *action, char **argv, int argc, pid_t pid, // Fetch zone conf_zone_t *zone = (conf_zone_t*)n; + + // Specific zone requested + int zone_match = 0; + for (unsigned i = 0; i < argc; ++i) { + size_t len = strlen(zone->name); + if (len > 1) { + len -= 1; + } // All (except root) without final dot + if (strncmp(zone->name, argv[i], len) == 0) { + zone_match = 1; + break; + } + } + if (!zone_match && argc > 0) { + continue; + } // Check source files and mtime int zone_status = check_zone(zone->db, zone->file); - if (zone_status == KNOTD_EOK) { + if (zone_status == KNOTD_EOK && !is_checkzone) { log_zone_info("Zone '%s' is up-to-date.\n", - zone->name); - + zone->name); + if (has_flag(flags, F_FORCE)) { log_zone_info("Forcing zone " - "recompilation.\n"); + "recompilation.\n"); } else { continue; } } - + // Check for not existing source if (zone_status == KNOTD_ENOENT) { continue; } + /* Evaluate space for new task. */ if (running == jobs) { - rc |= zctask_wait(tasks, jobs); + rc |= zctask_wait(tasks, jobs, is_checkzone); --running; } - const char *args[] = { - ZONEPARSER_EXEC, - zone->enable_checks ? "-s" : "", - has_flag(flags, F_VERBOSE) ? "-v" : "", - "-o", - zone->db, - zone->name, - zone->file - }; + int ac = 0; + const char *args[7] = { NULL }; + args[ac++] = ZONEPARSER_EXEC; + if (zone->enable_checks) { + args[ac++] = "-s"; + } + if (has_flag(flags, F_VERBOSE)) { + args[ac++] = "-v"; + } + + if (!is_checkzone) { + args[ac++] = "-o"; + args[ac++] = zone->db; + } + args[ac++] = zone->name; + args[ac++] = zone->file; // Execute command - if (has_flag(flags, F_VERBOSE)) { + if (has_flag(flags, F_VERBOSE) && !is_checkzone) { log_zone_info("Compiling '%s' as '%s'...\n", zone->name, zone->db); } fflush(stdout); fflush(stderr); - pid_t zcpid = start_cmd(args, 7); + pid_t zcpid = start_cmd(args, ac); zctask_add(tasks, jobs, zcpid, zone); ++running; } /* Wait for all running tasks. */ while (running > 0) { - rc |= zctask_wait(tasks, jobs); + rc |= zctask_wait(tasks, jobs, is_checkzone); --running; } free(tasks); diff --git a/src/knot/main.c b/src/knot/main.c index e83551c..99ee1cf 100644 --- a/src/knot/main.c +++ b/src/knot/main.c @@ -19,6 +19,7 @@ #include #include #include +#include #ifdef HAVE_CAP_NG_H #include #endif /* HAVE_CAP_NG_H */ @@ -38,6 +39,7 @@ /* Signal flags. */ static volatile short sig_req_stop = 0; static volatile short sig_req_reload = 0; +static volatile short sig_req_refresh = 0; static volatile short sig_stopping = 0; // SIGINT signal handler @@ -48,7 +50,13 @@ void interrupt_handle(int s) sig_req_reload = 1; return; } - + + // Refresh + if (s == SIGUSR2) { + sig_req_refresh = 1; + return; + } + // Stop server if (s == SIGINT || s == SIGTERM) { if (sig_stopping == 0) { @@ -165,24 +173,15 @@ int main(int argc, char **argv) if (config_fn[0] != '/') { // Get absolute path to cwd - size_t cwbuflen = 64; - char *cwbuf = malloc((cwbuflen + 2) * sizeof(char)); - while (getcwd(cwbuf, cwbuflen) == 0) { - cwbuflen *= 2; - cwbuf = realloc(cwbuf, (cwbuflen + 2) * sizeof(char)); - } - cwbuflen = strlen(cwbuf); - - // Append ending slash - if (cwbuf[cwbuflen - 1] != '/') { - cwbuf = strncat(cwbuf, "/", 1); + char *rpath = realpath(config_fn, NULL); + if (rpath == NULL) { + log_server_error("Couldn't get absolute path for configuration file '%s' - " + "%s.\n", config_fn, strerror(errno)); + return 1; + } else { + free(config_fn); + config_fn = rpath; } - - // Assemble path to config file - char *abs_cfg = strcdup(cwbuf, config_fn); - free(config_fn); - free(cwbuf); - config_fn = abs_cfg; } /* POSIX 1003.1e capabilities. */ @@ -290,6 +289,7 @@ int main(int argc, char **argv) sigaction(SIGTERM, &sa, NULL); sigaction(SIGHUP, &sa, NULL); sigaction(SIGPIPE, &sa, NULL); + sigaction(SIGUSR2, &sa, NULL); sa.sa_flags = 0; pthread_sigmask(SIG_BLOCK, &sa.sa_mask, NULL); @@ -326,6 +326,17 @@ int main(int argc, char **argv) break; } } + if (sig_req_refresh) { + log_server_info("Refreshing slave zones...\n"); + sig_req_reload = 0; + int cf_ret = server_refresh(server); + if (cf_ret != KNOTD_EOK) { + log_server_error("Couldn't refresh " + "slave zones - %s", + knotd_strerror(cf_ret)); + } + + } /* Events. */ if (ret > 0) { diff --git a/src/knot/server/dthreads.c b/src/knot/server/dthreads.c index 4e2b490..e2b45f2 100644 --- a/src/knot/server/dthreads.c +++ b/src/knot/server/dthreads.c @@ -854,6 +854,28 @@ int dt_stop(dt_unit_t *unit) // return KNOTD_EOK; //} +int dt_setaffinity(dthread_t *thread, void *mask, size_t len) +{ + if (thread == NULL || mask == NULL) { + return KNOTD_EINVAL; + } + +#ifdef HAVE_PTHREAD_SETAFFINITY_NP + if (len != sizeof(cpu_set_t)) { + return KNOTD_EINVAL; + } + pthread_t tid = pthread_self(); + int ret = pthread_setaffinity_np(tid, len, (cpu_set_t*)mask); + if (ret < 0) { + return KNOTD_ERROR; + } +#else + return KNOTD_ENOTSUP; +#endif + + return KNOTD_EOK; +} + int dt_repurpose(dthread_t *thread, runnable_t runnable, void *data) { // Check @@ -963,14 +985,22 @@ int dt_compact(dt_unit_t *unit) return KNOTD_EOK; } -int dt_optimal_size() +int dt_online_cpus() { + int ret = -1; #ifdef _SC_NPROCESSORS_ONLN - int ret = (int) sysconf(_SC_NPROCESSORS_ONLN); - if (ret >= 1) { + ret = (int) sysconf(_SC_NPROCESSORS_ONLN); +#endif + return ret; +} + +int dt_optimal_size() +{ + int ret = dt_online_cpus(); + if (ret > 0) { return ret + CPU_ESTIMATE_MAGIC; } -#endif + dbg_dt("dthreads: failed to fetch the number of online CPUs."); return DEFAULT_THR_COUNT; } @@ -993,6 +1023,22 @@ int dt_is_cancelled(dthread_t *thread) return ret; } +unsigned dt_get_id(dthread_t *thread) +{ + if (thread == NULL || thread->unit == NULL) { + return 0; + } + + dt_unit_t *unit = thread->unit; + for(unsigned tid = 0; tid < unit->size; ++tid) { + if (thread == unit->threads[tid]) { + return tid; + } + } + + return 0; +} + int dt_unit_lock(dt_unit_t *unit) { // Check input diff --git a/src/knot/server/dthreads.h b/src/knot/server/dthreads.h index 2347e1d..8ba457b 100644 --- a/src/knot/server/dthreads.h +++ b/src/knot/server/dthreads.h @@ -250,6 +250,17 @@ int dt_stop(dt_unit_t *unit); */ //int dt_setprio(dthread_t *thread, int prio); +/*! + * \brief Set thread affinity to masked CPU's. + * + * \param thread Target thread instance. + * \param mask CPU mask (should be pointer to cpu_set_t). + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL on invalid parameters. + */ +int dt_setaffinity(dthread_t *thread, void *mask, size_t len); + /*! * \brief Set thread to execute another runnable. * @@ -306,10 +317,18 @@ int dt_cancel(dthread_t *thread); */ int dt_compact(dt_unit_t *unit); +/*! + * \brief Return number of online processors. + * + * \retval Number of online CPU's if success. + * \retval <0 on failure. + */ +int dt_online_cpus(); + /*! * \brief Return optimal number of threads for instance. * - * It is estimated as NUM_CPUs + 1. + * It is estimated as NUM_CPUs + CONSTANT. * Fallback is DEFAULT_THR_COUNT (\see common.h). * * \return Number of threads. @@ -328,6 +347,18 @@ int dt_optimal_size(); */ int dt_is_cancelled(dthread_t *thread); + +/*! + * \brief Return thread index in threading unit. + * + * \note Returns 0 when thread doesn't have a unit. + * + * \param thread Target thread instance. + * + * \return Thread index. + */ +unsigned dt_get_id(dthread_t *thread); + /*! * \brief Lock unit to prevent parallel operations which could alter unit * at the same time. diff --git a/src/knot/server/journal.c b/src/knot/server/journal.c index fc8ec5c..9203f79 100644 --- a/src/knot/server/journal.c +++ b/src/knot/server/journal.c @@ -62,6 +62,10 @@ static inline int journal_cmp_eq(uint64_t k1, uint64_t k2) /*! \brief Recover metadata from journal. */ static int journal_recover(journal_t *j) { + if (j == NULL) { + return KNOTD_EINVAL; + } + /* Attempt to recover queue. */ int qstate[2] = { -1, -1 }; unsigned c = 0, p = j->max_nodes - 1; @@ -475,7 +479,8 @@ journal_t* journal_open(const char *fn, size_t fslimit, int mode, uint16_t bflag "it will be flushed.\n", fn); fcntl(fd, F_SETLK, &fl); close(fd); - return NULL; + journal_create(fn, JOURNAL_NCOUNT); + return journal_open(fn, fslimit, mode, bflags); } crc_t crc = 0; if (!sfread(&crc, sizeof(crc_t), fd)) { @@ -501,7 +506,8 @@ journal_t* journal_open(const char *fn, size_t fslimit, int mode, uint16_t bflag "it will be flushed.\n", fn); fcntl(fd, F_SETLK, &fl); close(fd); - return NULL; + journal_create(fn, JOURNAL_NCOUNT); + return journal_open(fn, fslimit, mode, bflags); } /* Check for lazy mode. */ @@ -653,7 +659,7 @@ journal_t* journal_open(const char *fn, size_t fslimit, int mode, uint16_t bflag int journal_fetch(journal_t *journal, uint64_t id, journal_cmp_t cf, journal_node_t** dst) { - if (journal == 0 || dst == 0) { + if (journal == NULL || dst == NULL) { return KNOTD_EINVAL; } @@ -679,7 +685,7 @@ int journal_fetch(journal_t *journal, uint64_t id, int journal_read(journal_t *journal, uint64_t id, journal_cmp_t cf, char *dst) { - if (journal == 0 || dst == 0) { + if (journal == NULL || dst == NULL) { return KNOTD_EINVAL; } @@ -834,7 +840,7 @@ int journal_walk(journal_t *journal, journal_apply_t apply) int journal_update(journal_t *journal, journal_node_t *n) { - if (!journal || !n) { + if (journal == NULL || n == NULL) { return KNOTD_EINVAL; } @@ -941,7 +947,7 @@ int journal_trans_rollback(journal_t *journal) int journal_close(journal_t *journal) { /* Check journal. */ - if (!journal) { + if (journal == NULL) { return KNOTD_EINVAL; } diff --git a/src/knot/server/journal.h b/src/knot/server/journal.h index d874996..322e25d 100644 --- a/src/knot/server/journal.h +++ b/src/knot/server/journal.h @@ -129,7 +129,7 @@ typedef int (*journal_apply_t)(journal_t *j, journal_node_t *n); #define JOURNAL_NCOUNT 1024 /*!< Default node count. */ /* HEADER = magic, crc, max_entries, qhead, qtail */ #define JOURNAL_HSIZE (MAGIC_LENGTH + sizeof(crc_t) + sizeof(uint16_t) * 3) -#define JOURNAL_MAGIC {'k', 'n', 'o', 't', '1', '0', '2'} +#define JOURNAL_MAGIC {'k', 'n', 'o', 't', '1', '0', '4'} /*! * \brief Create new journal. diff --git a/src/knot/server/notify.c b/src/knot/server/notify.c index d12247b..aa0a52b 100644 --- a/src/knot/server/notify.c +++ b/src/knot/server/notify.c @@ -243,8 +243,9 @@ int notify_process_request(knot_nameserver_t *ns, if (knot_packet_parse_rest(notify) != KNOT_EOK) { dbg_notify("notify: failed to parse NOTIFY query\n"); knot_ns_error_response(ns, knot_packet_id(notify), - KNOT_RCODE_FORMERR, buffer, - size); + ¬ify->header.flags1, + KNOT_RCODE_FORMERR, buffer, + size); return KNOTD_EOK; } } @@ -255,8 +256,8 @@ int notify_process_request(knot_nameserver_t *ns, if (ret != KNOTD_EOK) { dbg_notify("notify: failed to create NOTIFY response\n"); knot_ns_error_response(ns, knot_packet_id(notify), - KNOT_RCODE_SERVFAIL, buffer, - size); + ¬ify->header.flags1, + KNOT_RCODE_SERVFAIL, buffer, size); return KNOTD_EOK; } @@ -267,8 +268,8 @@ int notify_process_request(knot_nameserver_t *ns, if (z == NULL) { dbg_notify("notify: failed to find zone by name\n"); knot_ns_error_response(ns, knot_packet_id(notify), - KNOT_RCODE_REFUSED, buffer, - size); + ¬ify->header.flags1, + KNOT_RCODE_REFUSED, buffer, size); return KNOTD_EOK; } diff --git a/src/knot/server/server.c b/src/knot/server/server.c index ba7ccd7..5611a0c 100644 --- a/src/knot/server/server.c +++ b/src/knot/server/server.c @@ -24,17 +24,20 @@ #include #include + +#include "common/prng.h" #include "knot/common.h" #include "knot/other/error.h" #include "knot/server/server.h" #include "knot/server/udp-handler.h" #include "knot/server/tcp-handler.h" #include "knot/server/xfr-handler.h" -#include "libknot/nameserver/name-server.h" +#include "knot/server/zones.h" +#include "knot/conf/conf.h" #include "knot/stat/stat.h" +#include "libknot/nameserver/name-server.h" #include "libknot/zone/zonedb.h" #include "libknot/dname.h" -#include "knot/conf/conf.h" /*! \brief Event scheduler loop. */ static int evsched_run(dthread_t *thread) @@ -124,7 +127,7 @@ static int server_init_iface(iface_t *new_if, conf_iface_t *cfg_if) /* Initialize interface. */ int ret = 0; int sock = 0; - char errbuf[128]; + char errbuf[256] = {0}; int opt = 1024 * 1024; int snd_opt = 1024 * 1024; memset(new_if, 0, sizeof(iface_t)); @@ -153,7 +156,7 @@ static int server_init_iface(iface_t *new_if, conf_iface_t *cfg_if) new_if->type[UDP_ID] = cfg_if->family; /* Set socket options - voluntary. */ - char ebuf[512]; + char ebuf[256] = {0}; if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &snd_opt, sizeof(snd_opt)) < 0) { strerror_r(errno, ebuf, sizeof(ebuf)); // log_server_warning("Failed to configure socket " @@ -610,6 +613,42 @@ int server_wait(server_t *server) return ret; } +int server_refresh(server_t *server) +{ + if (server == NULL || server->nameserver == NULL) { + return KNOTD_EINVAL; + } + + /* Lock RCU and fetch zones. */ + rcu_read_lock(); + knot_nameserver_t *ns = server->nameserver; + evsched_t *sch = ((server_t *)knot_ns_get_data(ns))->sched; + const knot_zone_t **zones = knot_zonedb_zones(ns->zone_db); + if (zones == NULL) { + rcu_read_unlock(); + return KNOTD_ENOMEM; + } + + /* REFRESH zones. */ + for (unsigned i = 0; i < knot_zonedb_zone_count(ns->zone_db); ++i) { + zonedata_t *zd = (zonedata_t *)zones[i]->data; + if (zd == NULL) { + continue; + } + /* Expire REFRESH timer. */ + if (zd->xfr_in.timer) { + evsched_cancel(sch, zd->xfr_in.timer); + evsched_schedule(sch, zd->xfr_in.timer, + tls_rand() * 1000); + } + } + + /* Unlock RCU. */ + rcu_read_unlock(); + free(zones); + return KNOTD_EOK; +} + void server_stop(server_t *server) { dbg_server("server: stopping server\n"); diff --git a/src/knot/server/server.h b/src/knot/server/server.h index b1358cd..79a4729 100644 --- a/src/knot/server/server.h +++ b/src/knot/server/server.h @@ -178,6 +178,16 @@ int server_start(server_t *server); */ int server_wait(server_t *server); +/*! + * \brief Refresh served zones. + * + * \param server Server structure to be used for operation. + * + * \retval 0 On success (EOK). + * \retval <0 If an error occured (EINVAL). + */ +int server_refresh(server_t *server); + /*! * \brief Requests server to stop. * diff --git a/src/knot/server/tcp-handler.c b/src/knot/server/tcp-handler.c index 5f79096..977de0b 100644 --- a/src/knot/server/tcp-handler.c +++ b/src/knot/server/tcp-handler.c @@ -132,6 +132,13 @@ static void tcp_sweep(fdset_t *set, int fd, void* data) * * \param w Associated I/O event. * \param revents Returned events. + * + * \note We do not know if the packet makes sense or if it is + * a bunch of random bytes. There is no way to find out + * without parsing. However, it is irrelevant if we copy + * these random bytes to the response, so we may do it + * and ensure that in case of good packet the response + * is proper. */ static int tcp_handle(tcp_worker_t *w, int fd, uint8_t *qbuf, size_t qbuf_maxlen) { @@ -172,26 +179,31 @@ static int tcp_handle(tcp_worker_t *w, int fd, uint8_t *qbuf, size_t qbuf_maxlen } /* Parse query. */ -// knot_response_t *resp = knot_response_new(qbuf_maxlen); size_t resp_len = qbuf_maxlen; // 64K knot_packet_type_t qtype = KNOT_QUERY_NORMAL; knot_packet_t *packet = knot_packet_new(KNOT_PACKET_PREALLOC_QUERY); if (packet == NULL) { - uint16_t pkt_id = knot_wire_get_id(qbuf); - knot_ns_error_response(ns, pkt_id, KNOT_RCODE_SERVFAIL, - qbuf, &resp_len); - tcp_reply(fd, qbuf, resp_len); + int ret = knot_ns_error_response_from_query(ns, qbuf, n, + KNOT_RCODE_SERVFAIL, + qbuf, &resp_len); + + if (ret == KNOT_EOK) { + tcp_reply(fd, qbuf, resp_len); + } + return KNOTD_EOK; } int parse_res = knot_ns_parse_packet(qbuf, n, packet, &qtype); if (unlikely(parse_res != KNOT_EOK)) { if (parse_res > 0) { /* Returned RCODE */ - uint16_t pkt_id = knot_wire_get_id(qbuf); - knot_ns_error_response(ns, pkt_id, parse_res, - qbuf, &resp_len); - tcp_reply(fd, qbuf, resp_len); + int ret = knot_ns_error_response_from_query(ns, qbuf, n, + parse_res, qbuf, &resp_len); + + if (ret == KNOT_EOK) { + tcp_reply(fd, qbuf, resp_len); + } } knot_packet_free(&packet); return KNOTD_EOK; @@ -224,6 +236,7 @@ static int tcp_handle(tcp_worker_t *w, int fd, uint8_t *qbuf, size_t qbuf_maxlen res = xfr_request_init(&xfr, xfrt, XFR_FLAG_TCP, packet); if (res != KNOTD_EOK) { knot_ns_error_response(ns, knot_packet_id(packet), + &packet->header.flags1, KNOT_RCODE_SERVFAIL, qbuf, &resp_len); res = KNOTD_EOK; @@ -240,8 +253,8 @@ static int tcp_handle(tcp_worker_t *w, int fd, uint8_t *qbuf, size_t qbuf_maxlen case KNOT_QUERY_UPDATE: knot_ns_error_response(ns, knot_packet_id(packet), - KNOT_RCODE_NOTIMPL, qbuf, - &resp_len); + &packet->header.flags1, + KNOT_RCODE_NOTIMPL, qbuf, &resp_len); res = KNOTD_EOK; break; @@ -256,16 +269,16 @@ static int tcp_handle(tcp_worker_t *w, int fd, uint8_t *qbuf, size_t qbuf_maxlen case KNOT_RESPONSE_AXFR: /*!< Processed in XFR handler. */ case KNOT_RESPONSE_IXFR: /*!< Processed in XFR handler. */ knot_ns_error_response(ns, knot_packet_id(packet), - KNOT_RCODE_REFUSED, qbuf, - &resp_len); + &packet->header.flags1, + KNOT_RCODE_REFUSED, qbuf, &resp_len); res = KNOTD_EOK; break; /* Unknown opcodes. */ default: knot_ns_error_response(ns, knot_packet_id(packet), - KNOT_RCODE_FORMERR, qbuf, - &resp_len); + &packet->header.flags1, + KNOT_RCODE_FORMERR, qbuf, &resp_len); res = KNOTD_EOK; break; } diff --git a/src/knot/server/udp-handler.c b/src/knot/server/udp-handler.c index 80bc011..dcb5b1f 100644 --- a/src/knot/server/udp-handler.c +++ b/src/knot/server/udp-handler.c @@ -47,6 +47,7 @@ #include "libknot/packet/packet.h" #include "knot/server/zones.h" #include "knot/server/notify.h" +#include "libknot/util/error.h" /* Check for sendmmsg syscall. */ #ifdef HAVE_SENDMMSG @@ -83,9 +84,15 @@ int udp_handle(int fd, uint8_t *qbuf, size_t qbuflen, size_t *resp_len, knot_packet_new(KNOT_PACKET_PREALLOC_QUERY); if (packet == NULL) { dbg_net("udp: failed to create packet on fd=%d\n", fd); - uint16_t pkt_id = knot_wire_get_id(qbuf); - knot_ns_error_response(ns, pkt_id, KNOT_RCODE_SERVFAIL, - qbuf, resp_len); + + int ret = knot_ns_error_response_from_query(ns, qbuf, qbuflen, + KNOT_RCODE_SERVFAIL, + qbuf, resp_len); + + if (ret != KNOT_EOK) { + return KNOTD_EMALF; + } + return KNOTD_EOK; /* Created error response. */ } @@ -94,9 +101,15 @@ int udp_handle(int fd, uint8_t *qbuf, size_t qbuflen, size_t *resp_len, if (unlikely(res != KNOTD_EOK)) { dbg_net("udp: failed to parse packet on fd=%d\n", fd); if (res > 0) { /* Returned RCODE */ - uint16_t pkt_id = knot_wire_get_id(qbuf); - knot_ns_error_response(ns, pkt_id, res, - qbuf, resp_len); + int ret = knot_ns_error_response_from_query(ns, qbuf, + qbuflen, + res, qbuf, + resp_len); + + if (ret != KNOT_EOK) { + knot_packet_free(&packet); + return KNOTD_EMALF; + } } knot_packet_free(&packet); @@ -111,20 +124,16 @@ int udp_handle(int fd, uint8_t *qbuf, size_t qbuflen, size_t *resp_len, /* Response types. */ case KNOT_RESPONSE_NORMAL: - res = zones_process_response(ns, addr, packet, - qbuf, resp_len); + res = zones_process_response(ns, addr, packet, qbuf, resp_len); break; case KNOT_RESPONSE_NOTIFY: - res = notify_process_response(ns, packet, addr, - qbuf, resp_len); + res = notify_process_response(ns, packet, addr, qbuf, resp_len); break; /* Query types. */ case KNOT_QUERY_NORMAL: res = zones_normal_query_answer(ns, packet, addr, qbuf, resp_len, NS_TRANSPORT_UDP); -// res = knot_ns_answer_normal(ns, packet, qbuf, -// resp_len); break; case KNOT_QUERY_AXFR: /* RFC1034, p.28 requires reliable transfer protocol. @@ -132,8 +141,8 @@ int udp_handle(int fd, uint8_t *qbuf, size_t qbuflen, size_t *resp_len, */ /*! \note Draft exists for AXFR/UDP, but has not been standardized. */ knot_ns_error_response(ns, knot_packet_id(packet), - KNOT_RCODE_FORMERR, qbuf, - resp_len); + &packet->header.flags1, + KNOT_RCODE_FORMERR, qbuf, resp_len); res = KNOTD_EOK; break; case KNOT_QUERY_IXFR: @@ -146,8 +155,6 @@ int udp_handle(int fd, uint8_t *qbuf, size_t qbuflen, size_t *resp_len, res = zones_normal_query_answer(ns, packet, addr, qbuf, resp_len, NS_TRANSPORT_UDP); -// res = knot_ns_answer_normal(ns, packet, qbuf, -// resp_len); break; case KNOT_QUERY_NOTIFY: res = notify_process_request(ns, packet, addr, @@ -157,8 +164,8 @@ int udp_handle(int fd, uint8_t *qbuf, size_t qbuflen, size_t *resp_len, case KNOT_QUERY_UPDATE: dbg_net("udp: UPDATE query on fd=%d not implemented\n", fd); knot_ns_error_response(ns, knot_packet_id(packet), - KNOT_RCODE_NOTIMPL, qbuf, - resp_len); + &packet->header.flags1, + KNOT_RCODE_NOTIMPL, qbuf, resp_len); res = KNOTD_EOK; break; @@ -166,6 +173,7 @@ int udp_handle(int fd, uint8_t *qbuf, size_t qbuflen, size_t *resp_len, case KNOT_RESPONSE_AXFR: /*!< Processed in XFR handler. */ case KNOT_RESPONSE_IXFR: /*!< Processed in XFR handler. */ knot_ns_error_response(ns, knot_packet_id(packet), + &packet->header.flags1, KNOT_RCODE_REFUSED, qbuf, resp_len); res = KNOTD_EOK; @@ -174,8 +182,8 @@ int udp_handle(int fd, uint8_t *qbuf, size_t qbuflen, size_t *resp_len, /* Unknown opcodes */ default: knot_ns_error_response(ns, knot_packet_id(packet), - KNOT_RCODE_FORMERR, qbuf, - resp_len); + &packet->header.flags1, + KNOT_RCODE_FORMERR, qbuf, resp_len); res = KNOTD_EOK; break; } @@ -193,6 +201,21 @@ static inline int udp_master_recvfrom(dthread_t *thread, stat_t *thread_stat) return KNOTD_EINVAL; } + /* Set CPU affinity to improve load distribution on multicore systems. + * Partial overlapping mask to be nice to scheduler. + */ +#ifdef HAVE_PTHREAD_SETAFFINITY_NP + int cpcount = dt_online_cpus(); + if (cpcount > 0) { + unsigned tid = dt_get_id(thread); + cpu_set_t cpus; + CPU_ZERO(&cpus); + CPU_SET(tid % cpcount, &cpus); + CPU_SET((tid + 1) % cpcount, &cpus); + dt_setaffinity(thread, &cpus, sizeof(cpu_set_t)); + } +#endif + knot_nameserver_t *ns = h->server->nameserver; /* Initialize remote party address. */ @@ -380,6 +403,21 @@ static inline int udp_master_recvmmsg(dthread_t *thread, stat_t *thread_stat) msgs[i].msg_hdr.msg_name = addrs[i].ptr; msgs[i].msg_hdr.msg_namelen = addrs[i].len; } + + /* Set CPU affinity to improve load distribution on multicore systems. + * Partial overlapping mask to be nice to scheduler. + */ +#ifdef HAVE_PTHREAD_SETAFFINITY_NP + int cpcount = dt_online_cpus(); + if (cpcount > 0) { + unsigned tid = dt_get_id(thread); + cpu_set_t cpus; + CPU_ZERO(&cpus); + CPU_SET(tid % cpcount, &cpus); + CPU_SET((tid + 1) % cpcount, &cpus); + dt_setaffinity(thread, &cpus, sizeof(cpu_set_t)); + } +#endif /* Loop until all data is read. */ ssize_t n = 0; diff --git a/src/knot/server/xfr-handler.c b/src/knot/server/xfr-handler.c index 2ba2417..f850642 100644 --- a/src/knot/server/xfr-handler.c +++ b/src/knot/server/xfr-handler.c @@ -763,7 +763,14 @@ static int xfr_client_start(xfrworker_t *w, knot_ns_xfr_t *data) } /* Free data updated in this processing. */ - evqueue_write(nextw->q, data, sizeof(knot_ns_xfr_t)); + ret = evqueue_write(nextw->q, data, sizeof(knot_ns_xfr_t)); + if (ret != sizeof(knot_ns_xfr_t)) { + char ebuf[256] = {0}; + strerror_r(errno, ebuf, sizeof(ebuf)); + dbg_xfr("xfr: couldn't write request to evqueue: %s\n", + ebuf); + return KNOTD_ERROR; + } return KNOTD_EOK; } else { zd->xfr_in.wrkr = w; @@ -872,10 +879,10 @@ static int xfr_client_start(xfrworker_t *w, knot_ns_xfr_t *data) /* Start transfer. */ ret = data->send(data->session, &data->addr, data->wire, bufsize); if (ret != bufsize) { - char buf[1024]; - strerror_r(errno, buf, sizeof(buf)); + char ebuf[256] = {0}; + strerror_r(errno, ebuf, sizeof(ebuf)); log_server_info("%s Failed to send query (%s).\n", - data->msgpref, buf); + data->msgpref, ebuf); pthread_mutex_unlock(&zd->xfr_in.lock); close(data->session); data->session = -1; diff --git a/src/knot/server/zones.c b/src/knot/server/zones.c index 3de4a6a..6a710d4 100644 --- a/src/knot/server/zones.c +++ b/src/knot/server/zones.c @@ -167,19 +167,9 @@ 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_LAZY, JOURNAL_DIRTY); - if (!zd->ixfr_db) { - int ret = journal_create(cfg->ixfr_db, JOURNAL_NCOUNT); - if (ret != KNOTD_EOK) { - log_server_warning("Failed to create journal file " - "'%s' (%s)\n", cfg->ixfr_db, - knotd_strerror(ret)); - } - zd->ixfr_db = journal_open(cfg->ixfr_db, cfg->ixfr_fslimit, - JOURNAL_LAZY, JOURNAL_DIRTY); - } if (zd->ixfr_db == NULL) { - char ebuf[128] = {0}; + char ebuf[256] = {0}; strerror_r(errno, ebuf, sizeof(ebuf)); log_server_warning("Couldn't open journal file for zone '%s', " "disabling IXFR/IN. (%s)\n", cfg->name, ebuf); @@ -497,7 +487,7 @@ static int zones_refresh_ev(event_t *e) /* Create query. */ int sock = -1; - char strbuf[512] = "Generic error."; + char strbuf[256] = "Generic error."; const char *errstr = strbuf; sockaddr_t *master = &zd->xfr_in.master; int ret = xfrin_create_soa_query(zone->name, &xfr_req, &buflen); @@ -529,6 +519,7 @@ static int zones_refresh_ev(event_t *e) if (sent == buflen) { ret = KNOTD_EOK; } else { + strbuf[0] = '\0'; strerror_r(errno, strbuf, sizeof(strbuf)); socket_close(sock); sock = -1; @@ -807,7 +798,7 @@ static int zones_set_acl(acl_t **acl, list* acl_list) /*! * \brief Load zone to zone database. * - * \param zonedb Zone database to load the zone into. + * \param dst Loaded zone will be returned in this parameter. * \param zone_name Zone name (owner of the apex node). * \param source Path to zone file source. * \param filename Path to requested compiled zone file. @@ -816,10 +807,14 @@ static int zones_set_acl(acl_t **acl, list* acl_list) * \retval KNOTD_EINVAL * \retval KNOTD_EZONEINVAL */ -static int zones_load_zone(knot_zonedb_t *zonedb, const char *zone_name, +static int zones_load_zone(knot_zone_t **dst, const char *zone_name, const char *source, const char *filename) { - knot_zone_t *zone = NULL; + if (dst == NULL) { + return KNOTD_EINVAL; + } + *dst = NULL; + size_t zlen = strlen(zone_name); char *zname = NULL; if (zlen > 0) { @@ -835,7 +830,7 @@ static int zones_load_zone(knot_zonedb_t *zonedb, const char *zone_name, /* Check if the compiled file still exists. */ struct stat st; if (stat(source, &st) != 0) { - char reason[1024]; + char reason[256] = {0}; strerror_r(errno, reason, sizeof(reason)); log_server_warning("Failed to open zone file '%s' (%s).\n", zname, reason); @@ -893,18 +888,17 @@ static int zones_load_zone(knot_zonedb_t *zonedb, const char *zone_name, zname); } - zone = knot_zload_load(zl); + *dst = knot_zload_load(zl); /* Check loaded name. */ - const knot_dname_t *dname = knot_zone_name(zone); + const knot_dname_t *dname = knot_zone_name(*dst); knot_dname_t *dname_req = 0; dname_req = knot_dname_new_from_str(zone_name, zlen, 0); if (knot_dname_compare(dname, dname_req) != 0) { log_server_warning("Origin of the zone db file is " "different than '%s'\n", zone_name); - knot_zone_deep_free(&zone, 0); - zone = 0; + knot_zone_deep_free(dst, 0); } knot_dname_free(&dname_req); @@ -914,26 +908,21 @@ static int zones_load_zone(knot_zonedb_t *zonedb, const char *zone_name, // int errs = knot_zone_contents_integrity_check(zone->contents); // fprintf(stderr, "INTEGRITY CHECK OF ZONE. ERRORS: %d\n", errs); - if (zone) { + if (*dst != NULL) { /* save the timestamp from the zone db file */ struct stat s; if (stat(filename, &s) < 0) { dbg_zones("zones: failed to stat() zone db, " "something is seriously wrong\n"); - knot_zone_deep_free(&zone, 0); - zone = 0; + knot_zone_deep_free(dst, 0); } else { - knot_zone_set_version(zone, s.st_mtime); - if (knot_zonedb_add_zone(zonedb, zone) != 0){ - knot_zone_deep_free(&zone, 0); - zone = 0; - } + knot_zone_set_version(*dst, s.st_mtime); } } knot_zload_close(zl); - if (!zone) { + if (*dst == NULL) { log_server_error("Failed to load " "db '%s' for zone '%s'.\n", filename, zname); @@ -1146,6 +1135,9 @@ static int zones_load_changesets(const knot_zone_t *zone, /* Retain journal for changeset loading. */ journal_t *j = journal_retain(zd->ixfr_db); + if (j == NULL) { + return KNOTD_EBUSY; + } /* Read entries from starting serial until finished. */ uint32_t found_to = from; @@ -1330,213 +1322,342 @@ static int zones_journal_apply(knot_zone_t *zone) } /*----------------------------------------------------------------------------*/ + /*! - * \brief Fill the new database with zones. + * \brief Insert new zone to the database. * * Zones that should be retained are just added from the old database to the * new. New zones are loaded. * + * \param z Zone configuration. + * \param dst Used for returning new/updated zone. * \param ns Name server instance. - * \param zone_conf Zone configuration. * \param db_old Old zone database. - * \param db_new New zone database. * - * \return Number of inserted zones. + * \retval KNOTD_EOK if successful. + * \retval KNOTD_EINVAL on invalid parameters. + * \retval KNOTD_ENOENT if zone has no contents. + * \retval KNOTD_ERROR on unspecified error. */ -static int zones_insert_zones(knot_nameserver_t *ns, - const list *zone_conf, - const knot_zonedb_t *db_old, - knot_zonedb_t *db_new) +static int zones_insert_zone(conf_zone_t *z, knot_zone_t **dst, + knot_nameserver_t *ns, const knot_zonedb_t *db_old) { - /*! \todo Change to zone contents. */ + if (z == NULL || dst == NULL || ns == NULL || db_old == NULL) { + return KNOTD_EINVAL; + } + + /* Convert the zone name into a domain name. */ + /* Local allocation, will be discarded. */ + knot_dname_t *dname = knot_dname_new_from_str(z->name, strlen(z->name), + NULL); + if (dname == NULL) { + log_server_error("Error creating domain name from zone" + " name\n"); + return KNOTD_EINVAL; + } - node *n = 0; - int inserted = 0; - /* for all zones in the configuration */ - WALK_LIST(n, *zone_conf) { - conf_zone_t *z = (conf_zone_t *)n; - - /* Convert the zone name into a domain name. */ - /* Local allocation, will be discarded. */ - knot_dname_t *zone_name = knot_dname_new_from_str(z->name, - strlen(z->name), NULL); - if (zone_name == NULL) { - log_server_error("Error creating domain name from zone" - " name\n"); - return inserted; - } + /* Try to find the zone in the current zone db. */ + knot_zone_t *zone = knot_zonedb_find_zone(db_old, dname); - dbg_zones_verb("zones: inserting zone %s into the new database.\n", - z->name); + /* Attempt to bootstrap if db or source does not exist. */ + int zone_changed = 0; + struct stat s = {}; + int stat_ret = stat(z->file, &s); + if (zone != NULL && stat_ret == 0) { + /* if found, check timestamp of the file against the + * loaded zone + */ + if (knot_zone_version(zone) < s.st_mtime) { + zone_changed = 1; + } + } else { + zone_changed = 1; + } - /* try to find the zone in the current zone db */ - knot_zone_t *zone = knot_zonedb_find_zone(db_old, - zone_name); - int reload = 0; + /* Reload zone file. */ + int ret = KNOTD_ERROR; + if (zone_changed) { + /* Zone file not exists and has master set. */ + if (stat_ret < 0 && !EMPTY_LIST(z->acl.xfr_in)) { - /* Attempt to bootstrap if db or source does not exist. */ - struct stat s = {}; - int stat_ret = stat(z->file, &s); - if (zone != NULL && stat_ret == 0) { - /* if found, check timestamp of the file against the - * loaded zone - */ - if (knot_zone_version(zone) < s.st_mtime) { - /* the file is newer, reload! */ - reload = 1; + /* Create stub database. */ + dbg_zones_verb("zones: loading stub zone '%s' " + "for bootstrap.\n", + z->name); + knot_dname_t *owner = knot_dname_deep_copy(dname); + zone = knot_zone_new_empty(owner); + if (zone != NULL) { + ret = KNOTD_EOK; + log_server_info("Will attempt to bootstrap zone" + " %s from AXFR master.\n", + z->name); + } else { + dbg_zones("zones: failed to create " + "stub zone '%s'.\n", z->name); + ret = KNOTD_ERROR; } } else { - reload = 1; - } - - /* Reload zone file. */ - int ret = KNOTD_ERROR; - if (reload) { - /* Zone file not exists and has master set. */ - if (stat_ret < 0 && !EMPTY_LIST(z->acl.xfr_in)) { - - /* Create stub database. */ - dbg_zones_verb("zones: loading stub zone '%s' " - "for bootstrap.\n", - z->name); - knot_dname_t *owner = 0; - owner = knot_dname_deep_copy(zone_name); - knot_zone_t* sz = knot_zone_new_empty(owner); - if (sz) { - /* Add stub zone to db_new. */ - ret = knot_zonedb_add_zone(db_new, sz); - if (ret != KNOT_EOK) { - dbg_zones("zones: failed to add " - "stub zone '%s'.\n", - z->name); - knot_zone_deep_free(&sz, 0); - sz = 0; - ret = KNOTD_ERROR; - } else { - log_server_info("Will attempt to " - "bootstrap zone " - "%s from AXFR " - "master.\n", - z->name); - --inserted; - } - - } else { - dbg_zones("zones: failed to create " - "stub zone '%s'.\n", - z->name); - ret = KNOTD_ERROR; - } - - } else { - dbg_zones_verb("zones: loading zone '%s' " - "from '%s'\n", - z->name, - z->db); - ret = zones_load_zone(db_new, z->name, - z->file, z->db); - if (ret == KNOTD_EOK) { - log_server_info("Loaded zone '%s'\n", - z->name); - } + dbg_zones_verb("zones: loading zone '%s' from '%s'\n", + z->name, z->db); + ret = zones_load_zone(&zone, z->name, z->file, z->db); + if (ret == KNOTD_EOK) { + log_server_info("Loaded zone '%s'\n", + z->name); } + } - /* Find zone. */ - if (ret == KNOTD_EOK) { - /* Find the new zone */ - zone = knot_zonedb_find_zone(db_new, - zone_name); - ++inserted; - - dbg_zones_verb("zones: inserted '%s' into " - "database, initializing data\n", - z->name); + /* Evaluate. */ + if (ret == KNOTD_EOK && zone != NULL) { + dbg_zones_verb("zones: inserted '%s' into " + "database, initializing data\n", + z->name); - /* Initialize zone-related data. */ - zonedata_init(z, zone); + /* Initialize zone-related data. */ + zonedata_init(z, zone); + *dst = zone; + } + } else { + dbg_zones_verb("zones: found '%s' in old database, " + "copying to new.\n", z->name); + if (stat_ret == 0) { + log_server_info("Zone '%s' is up-to-date, no need " + "for reload.\n", z->name); + } + *dst = zone; + ret = KNOTD_EOK; + } + + /* Update zone data. */ + if (zone != NULL) { + zonedata_t *zd = (zonedata_t *)knot_zone_data(zone); + assert(zd != NULL); + + /* Update refs. */ + zd->conf = z; + + /* Update ACLs. */ + dbg_zones("Updating zone ACLs.\n"); + zones_set_acl(&zd->xfr_in.acl, &z->acl.xfr_in); + zones_set_acl(&zd->xfr_out, &z->acl.xfr_out); + zones_set_acl(&zd->notify_in, &z->acl.notify_in); + zones_set_acl(&zd->notify_out, &z->acl.notify_out); + + /* Update server pointer. */ + zd->server = (server_t *)knot_ns_get_data(ns); + + /* Update master server address. */ + memset(&zd->xfr_in.tsig_key, 0, sizeof(knot_key_t)); + sockaddr_init(&zd->xfr_in.master, -1); + sockaddr_init(&zd->xfr_in.via, -1); + if (!EMPTY_LIST(z->acl.xfr_in)) { + conf_remote_t *r = HEAD(z->acl.xfr_in); + conf_iface_t *cfg_if = r->remote; + sockaddr_set(&zd->xfr_in.master, + cfg_if->family, + cfg_if->address, + cfg_if->port); + if (sockaddr_isvalid(&cfg_if->via)) { + sockaddr_copy(&zd->xfr_in.via, + &cfg_if->via); } - /* unused return value, if not loaded, just continue */ - } else { - /* just insert the zone into the new zone db */ - dbg_zones_verb("zones: found '%s' in old database, " - "copying to new.\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" - " the new database - %s\n", - z->name, knot_strerror(ret)); - } else { - ++inserted; + + if (cfg_if->key) { + memcpy(&zd->xfr_in.tsig_key, + cfg_if->key, + sizeof(knot_key_t)); } + + dbg_zones("zones: using '%s@%d' as XFR master " + "for '%s'\n", + cfg_if->address, + cfg_if->port, + z->name); } - /* Update zone data. */ - if (zone) { - zonedata_t *zd = (zonedata_t *)knot_zone_data(zone); - - /* Update refs. */ - zd->conf = z; - - /* Update ACLs. */ - dbg_zones("Updating zone ACLs.\n"); - zones_set_acl(&zd->xfr_in.acl, &z->acl.xfr_in); - zones_set_acl(&zd->xfr_out, &z->acl.xfr_out); - zones_set_acl(&zd->notify_in, &z->acl.notify_in); - zones_set_acl(&zd->notify_out, &z->acl.notify_out); - - /* Update server pointer. */ - zd->server = (server_t *)knot_ns_get_data(ns); - - /* Update master server address. */ - memset(&zd->xfr_in.tsig_key, 0, sizeof(knot_key_t)); - sockaddr_init(&zd->xfr_in.master, -1); - sockaddr_init(&zd->xfr_in.via, -1); - if (!EMPTY_LIST(z->acl.xfr_in)) { - conf_remote_t *r = HEAD(z->acl.xfr_in); - conf_iface_t *cfg_if = r->remote; - sockaddr_set(&zd->xfr_in.master, - cfg_if->family, - cfg_if->address, - cfg_if->port); - if (sockaddr_isvalid(&cfg_if->via)) { - sockaddr_copy(&zd->xfr_in.via, - &cfg_if->via); - } + /* Apply changesets from journal. */ + zones_journal_apply(zone); - if (cfg_if->key) { - memcpy(&zd->xfr_in.tsig_key, - cfg_if->key, - sizeof(knot_key_t)); - } + /* Update events scheduled for zone. */ + evsched_t *sch = ((server_t *)knot_ns_get_data(ns))->sched; + zones_timers_update(zone, z, sch); + + /* Schedule IXFR database syncing. */ + /*! \note This has to remain separate as it must not be + * triggered by a zone update or SOA response. + */ + /* Fetch zone data. */ + int sync_tmr = z->dbsync_timeout * 1000; /* s -> ms. */ + if (zd->ixfr_dbsync != NULL) { + evsched_cancel(sch, zd->ixfr_dbsync); + evsched_event_free(sch, zd->ixfr_dbsync); + zd->ixfr_dbsync = NULL; + } + if (zd->ixfr_db != NULL) { + zd->ixfr_dbsync = evsched_schedule_cb( + sch, zones_zonefile_sync_ev, + zone, sync_tmr); + dbg_zones("zone: journal sync of '%s' " + "set to %d\n", z->name, sync_tmr); + } - dbg_zones("zones: using '%s@%d' as XFR master " - "for '%s'\n", - cfg_if->address, - cfg_if->port, - z->name); + /* Update ANY queries policy */ + if (zd->conf->disable_any) { + knot_zone_contents_t *contents = + knot_zone_get_contents(zone); + if (contents) { + knot_zone_contents_disable_any(contents); } - - /* Apply changesets from journal. */ - zones_journal_apply(zone); - - /* Update events scheduled for zone. */ - zones_timers_update(zone, z, - ((server_t *)knot_ns_get_data(ns))->sched); } + } - /* CLEANUP */ + /* CLEANUP */ // knot_zone_contents_dump(knot_zone_get_contents(zone), 1); - /* Directly discard zone. */ - knot_dname_free(&zone_name); + /* Directly discard zone. */ + knot_dname_free(&dname); + return ret; +} + +/*! \brief Structure for multithreaded zone loading. */ +struct zonewalk_t { + knot_nameserver_t *ns; + const knot_zonedb_t *db_old; + knot_zonedb_t *db_new; + pthread_mutex_t lock; + int inserted; + unsigned qhead; + unsigned qtail; + conf_zone_t *q[]; + +}; + +/*! Thread entrypoint for loading zones. */ +static int zonewalker(dthread_t *thread) +{ + if (thread == NULL) { + return KNOTD_ERROR; + } + + struct zonewalk_t *zw = (struct zonewalk_t *)thread->data; + if (zw == NULL) { + return KNOTD_ERROR; } + + unsigned i = 0; + int inserted = 0; + knot_zone_t **zones = NULL; + size_t allocd = 0; + for(;;) { + /* Fetch queue head. */ + pthread_mutex_lock(&zw->lock); + i = zw->qhead++; + pthread_mutex_unlock(&zw->lock); + if (i >= zw->qtail) { + break; + } + + if (mreserve((char **)&zones, sizeof(knot_zone_t*), + inserted + 1, 32, &allocd) < 0) { + dbg_zones("zones: failed to reserve space for " + "loading zones\n"); + continue; + } + + int ret = zones_insert_zone(zw->q[i], zones + inserted, zw->ns, + zw->db_old); + if (ret == KNOTD_EOK) { + ++inserted; + } + } + + /* Collect results. */ + pthread_mutex_lock(&zw->lock); + zw->inserted += inserted; + for (int i = 0; i < inserted; ++i) { + if (knot_zonedb_add_zone(zw->db_new, zones[i]) != KNOT_EOK) { + zonedata_t *zd = (zonedata_t *)knot_zone_data(zones[i]); + log_server_error("Failed to insert zone '%s' " + "into database.\n", zd->conf->name); + knot_zone_deep_free(zones + i, 0); + } + } + pthread_mutex_unlock(&zw->lock); + free(zones); + + return KNOTD_EOK; +} + +/*! + * \brief Fill the new database with zones. + * + * Zones that should be retained are just added from the old database to the + * new. New zones are loaded. + * + * \param ns Name server instance. + * \param zone_conf Zone configuration. + * \param db_old Old zone database. + * \param db_new New zone database. + * + * \return Number of inserted zones. + */ +static int zones_insert_zones(knot_nameserver_t *ns, + const list *zone_conf, + const knot_zonedb_t *db_old, + knot_zonedb_t *db_new) +{ + int inserted = 0; + size_t zcount = 0; + conf_zone_t *z = NULL; + WALK_LIST(z, *zone_conf) { + ++zcount; + } + + /* Initialize zonewalker. */ + size_t zwlen = sizeof(struct zonewalk_t) + zcount * sizeof(conf_zone_t*); + struct zonewalk_t *zw = malloc(zwlen); + if (zw != NULL) { + memset(zw, 0, zwlen); + zw->ns = ns; + zw->db_old = db_old; + zw->db_new = db_new; + zw->inserted = 0; + if (pthread_mutex_init(&zw->lock, NULL) < 0) { + free(zw); + zw = NULL; + } else { + unsigned i = 0; + WALK_LIST(z, *zone_conf) { + zw->q[i++] = z; + } + zw->qhead = 0; + zw->qtail = zcount; + } + } + + /* Initialize threads. */ + dt_unit_t *unit = NULL; + if (zw != NULL) { + unit = dt_create_coherent(dt_optimal_size(), &zonewalker, zw); + } + /* Single-thread fallback. */ + if (unit == NULL) { + log_server_error("Couldn't initialize zone loading - %s\n", + knotd_strerror(KNOTD_ENOMEM)); + return 0; + } + + /* Start loading. */ + dt_start(unit); + + /* Wait for finish. */ + dt_join(unit); + dt_delete(&unit); + + /* Collect counts. */ + inserted = zw->inserted; + pthread_mutex_destroy(&zw->lock); + free(zw); return inserted; } @@ -1838,6 +1959,9 @@ int zones_zonefile_sync(knot_zone_t *zone, journal_t *journal) if (!zone->data) { return KNOTD_EINVAL; } + if (journal == NULL) { + return KNOTD_EINVAL; + } /* Fetch zone data. */ int ret = KNOTD_EOK; @@ -1896,8 +2020,8 @@ int zones_zonefile_sync(knot_zone_t *zone, journal_t *journal) zd->conf->name, serial_to); zd->zonefile_serial = serial_to; } else { - dbg_zones_verb("zones: '%s' zonefile is in sync " - "with differences\n", zd->conf->name); + dbg_zones("zones: '%s' zonefile is in sync " + "with differences\n", zd->conf->name); ret = KNOTD_ERANGE; } @@ -2029,15 +2153,15 @@ int zones_normal_query_answer(knot_nameserver_t *nameserver, dbg_zones_verb("Failed preparing response structure: %s.\n", knot_strerror(rcode)); if (resp == NULL) { - knot_ns_error_response(nameserver, knot_packet_id(query), - rcode, resp_wire, rsize); + knot_ns_error_response(nameserver, + knot_packet_id(query), + &query->header.flags1, + rcode, resp_wire, rsize); rcu_read_unlock(); return KNOT_EOK; } knot_ns_error_response_full(nameserver, resp, rcode, resp_wire, rsize); -// knot_ns_error_response(nameserver, knot_packet_id(query), -// rcode, resp_wire, rsize); } else { /* * Now we have zone. Verify TSIG if it is in the packet. @@ -2416,7 +2540,16 @@ static int zones_dump_zone_text(knot_zone_contents_t *zone, const char *fname) return KNOTD_ERROR; } - if (zone_dump_text(zone, fd) != KNOTD_EOK) { + FILE *f = fdopen(fd, "w"); + if (f == NULL) { + log_zone_warning("Failed to open file descriptor for text zone.\n"); + close(fd); + unlink(new_fname); + free(new_fname); + return KNOTD_ERROR; + } + + if (zone_dump_text(zone, f) != KNOTD_EOK) { log_zone_warning("Failed to save the transferred zone to '%s'.\n", new_fname); close(fd); @@ -2426,7 +2559,7 @@ static int zones_dump_zone_text(knot_zone_contents_t *zone, const char *fname) } /* Swap temporary zonefile and new zonefile. */ - close(fd); + fclose(f); int ret = rename(new_fname, fname); if (ret < 0 && ret != EEXIST) { log_zone_warning("Failed to replace old zone file '%s'' with a new" @@ -3034,20 +3167,6 @@ int zones_timers_update(knot_zone_t *zone, conf_zone_t *cfzone, evsched_t *sch) cfzone->name, refresh_tmr); } - /* Schedule IXFR database syncing. */ - /*! \todo Sync timer should not be reset after each xfr (issue #1348) */ - int sync_timeout = cfzone->dbsync_timeout * 1000; /* Convert to ms. */ - if (zd->ixfr_dbsync) { - evsched_cancel(sch, zd->ixfr_dbsync); - evsched_event_free(sch, zd->ixfr_dbsync); - zd->ixfr_dbsync = 0; - } - if (zd->ixfr_db) { - zd->ixfr_dbsync = evsched_schedule_cb(sch, - zones_zonefile_sync_ev, - zone, sync_timeout); - } - /* Do not issue NOTIFY queries if stub. */ if (!knot_zone_contents(zone)) { conf_read_unlock(); diff --git a/src/knot/zone/zone-dump-text.c b/src/knot/zone/zone-dump-text.c index 2d0b9c0..bc606d3 100644 --- a/src/knot/zone/zone-dump-text.c +++ b/src/knot/zone/zone-dump-text.c @@ -1119,9 +1119,8 @@ void node_dump_text(knot_node_t *node, void *data) free(rrsets); } -int zone_dump_text(knot_zone_contents_t *zone, int fd) +int zone_dump_text(knot_zone_contents_t *zone, FILE *f) { - FILE *f = fdopen(fd, "w"); if (f == NULL) { return KNOT_EBADARG; } @@ -1134,7 +1133,6 @@ int zone_dump_text(knot_zone_contents_t *zone, int fd) param.origin = knot_node_owner(knot_zone_contents_apex(zone)); knot_zone_contents_tree_apply_inorder(zone, node_dump_text, ¶m); knot_zone_contents_nsec3_apply_inorder(zone, node_dump_text, ¶m); - fclose(f); return KNOT_EOK; } diff --git a/src/knot/zone/zone-dump-text.h b/src/knot/zone/zone-dump-text.h index 2a35643..9f9c8dd 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 fd File descriptor to write to. + * \param File file 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, int fd); +int zone_dump_text(knot_zone_contents_t *zone, FILE *f); #endif // _KNOT_ZONE_DUMP_TEXT_H_ diff --git a/src/knot/zone/zone-dump.c b/src/knot/zone/zone-dump.c index 31be9b0..aaf0165 100644 --- a/src/knot/zone/zone-dump.c +++ b/src/knot/zone/zone-dump.c @@ -62,7 +62,7 @@ static inline int write_to_file_crc(const void *src, } ssize_t rc = write(fd, src, size * n); if (rc != size * n) { - fprintf(stderr, "write: invalid write %zu (expected %zu)\n", rc, + fprintf(stderr, "write: invalid write %zd (expected %zu)\n", rc, n); } @@ -1058,11 +1058,10 @@ int knot_zdump_binary(knot_zone_contents_t *zone, int fd, /* Finish the dump. */ if (!write_to_file_crc(buffer, 1, written_bytes, fd, crc)) { - dbg_zdump("zdump: Failed to finalize dump.\n"); + fprintf(stderr, "Failed to finalize zone db!\n"); return KNOT_ERROR; } - *crc = crc_finalize(*crc); dbg_zdump("zdump: Zone %p dumped successfully.\n", zone); diff --git a/src/knot/zone/zone-dump.h b/src/knot/zone/zone-dump.h index 46e760e..fbebae9 100644 --- a/src/knot/zone/zone-dump.h +++ b/src/knot/zone/zone-dump.h @@ -38,7 +38,7 @@ enum { }; /*! \brief Magic identifier: { "knot", maj_ver, min_ver, revision } */ -#define MAGIC_BYTES {'k', 'n', 'o', 't', '1', '0', '0'} +#define MAGIC_BYTES {'k', 'n', 'o', 't', '1', '0', '4'} /*! * \brief Dumps given zone to binary file. diff --git a/src/knot/zone/zone-load.c b/src/knot/zone/zone-load.c index b8c9beb..3a7134e 100644 --- a/src/knot/zone/zone-load.c +++ b/src/knot/zone/zone-load.c @@ -260,9 +260,15 @@ static knot_rdata_t *knot_load_rdata(uint16_t type, FILE *f, knot_rdata_item_t *items = malloc(sizeof(knot_rdata_item_t) * rdata_count); + if (items == NULL) { + ERR_ALLOC_FAILED; + free(items); + return NULL; + } - if (desc->fixed_items) { - assert(desc->length == rdata_count); + if (rdata_count > desc->length) { + dbg_zload("zload: load_rdata: Read wrong count of RDATA.\n"); + return NULL; } uint16_t raw_data_length = 0; @@ -347,8 +353,8 @@ static knot_rdata_t *knot_load_rdata(uint16_t type, FILE *f, } /*!< \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 = + malloc(raw_data_length + 2); if (items[i].raw_data == NULL) { ERR_ALLOC_FAILED; load_rdata_purge(rdata, items, i + 1, desc, @@ -908,16 +914,7 @@ int knot_zload_open(zloader_t **dst, const char *filename) /* Free some value and close the CRC file */ free(crc_path); close(f_crc); - - /* Compare calculated and read CRCs. */ - if (crc_from_file != crc_calculated) { - dbg_zload("knot_zload_open: CRC failed for " - "file '%s'\n", - filename); - fclose(f); - return KNOT_ECRC; - } - + /* Check magic sequence. */ static const uint8_t MAGIC[MAGIC_LENGTH] = MAGIC_BYTES; if (!knot_check_magic(f, MAGIC, MAGIC_LENGTH)) { @@ -929,6 +926,15 @@ int knot_zload_open(zloader_t **dst, const char *filename) return KNOT_EMALF; // Illegal byte sequence (POSIX.1, C99) } + /* Compare calculated and read CRCs. */ + if (crc_from_file != crc_calculated) { + dbg_zload("knot_zload_open: CRC failed for " + "file '%s'\n", + filename); + fclose(f); + return KNOT_ECRC; + } + /* Read source file length. */ uint32_t sflen = 0; if (!fread_wrapper(&sflen, 1, sizeof(uint32_t), f)) { diff --git a/src/libknot/dname.c b/src/libknot/dname.c index 7a6ea5a..80de030 100644 --- a/src/libknot/dname.c +++ b/src/libknot/dname.c @@ -263,16 +263,21 @@ static int knot_dname_find_labels(knot_dname_t *dname, int alloc) uint8_t labels[KNOT_MAX_DNAME_LABELS]; short label_count = 0; - while (pos - name < size && *pos != '\0') { + while (pos - name < size && *pos != '\0' && label_count < KNOT_MAX_DNAME_LABELS ) { labels[label_count++] = pos - name; pos += *pos + 1; } // TODO: how to check if the domain name has right format? - if (pos - name > size || *pos != '\0') { + if (label_count == KNOT_MAX_DNAME_LABELS) { dbg_dname("Wrong wire format of domain name!\n"); - dbg_dname("Position: %d, character: %d, expected" - " size: %d\n", pos - name, *pos, size); + dbg_dname("Too many labels: %s\n", name); + return -1; + } + + if (pos - name > size || *pos != '\0' ) { + dbg_dname("Wrong wire format of domain name!\n"); + dbg_dname("Position: %d, character: %d, expected size: %d\n", pos - name, *pos, size); return -1; } diff --git a/src/libknot/nameserver/name-server.c b/src/libknot/nameserver/name-server.c index 213534c..d938683 100644 --- a/src/libknot/nameserver/name-server.c +++ b/src/libknot/nameserver/name-server.c @@ -1827,7 +1827,8 @@ have_node: goto finalize; } - if (knot_node_rrset(node, KNOT_RRTYPE_CNAME) != NULL) { + if (knot_node_rrset(node, KNOT_RRTYPE_CNAME) != NULL + && qtype != KNOT_RRTYPE_CNAME) { dbg_ns_exec( char *name = knot_dname_to_str(node->owner); dbg_ns("Node %s has CNAME record, resolving...\n", @@ -2841,17 +2842,25 @@ int knot_ns_parse_packet(const uint8_t *query_wire, size_t qsize, /*----------------------------------------------------------------------------*/ -void knot_ns_error_response(const knot_nameserver_t *nameserver, uint16_t query_id, - uint8_t rcode, uint8_t *response_wire, size_t *rsize) +void knot_ns_error_response(const knot_nameserver_t *nameserver, + uint16_t query_id, uint8_t *flags1_query, + uint8_t rcode, uint8_t *response_wire, + size_t *rsize) { - //dbg_ns("Error response: \n"); - //dbg_ns_hex((const char *)nameserver->err_response, - // nameserver->err_resp_size); - memcpy(response_wire, nameserver->err_response, nameserver->err_resp_size); - // copy ID of the query + + // copy only the ID of the query knot_wire_set_id(response_wire, query_id); + + if (flags1_query != NULL) { + if (knot_wire_flags_get_rd(*flags1_query) != 0) { + knot_wire_set_rd(response_wire); + } + knot_wire_set_opcode(response_wire, + knot_wire_flags_get_opcode(*flags1_query)); + } + // set the RCODE knot_wire_set_rcode(response_wire, rcode); *rsize = nameserver->err_resp_size; @@ -2859,6 +2868,33 @@ void knot_ns_error_response(const knot_nameserver_t *nameserver, uint16_t query_ /*----------------------------------------------------------------------------*/ +int knot_ns_error_response_from_query(const knot_nameserver_t *nameserver, + const uint8_t *query, size_t size, + uint8_t rcode, uint8_t *response_wire, + size_t *rsize) +{ + if (size < 2) { + // ignore packet + return KNOT_EFEWDATA; + } + + uint16_t pkt_id = knot_wire_get_id(query); + + uint8_t *flags1_ptr = NULL; + uint8_t flags1; + + if (size > KNOT_WIRE_OFFSET_FLAGS1) { + flags1 = knot_wire_get_flags1(query); + flags1_ptr = &flags1; + } + knot_ns_error_response(nameserver, pkt_id, flags1_ptr, + rcode, response_wire, rsize); + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + void knot_ns_error_response_full(knot_nameserver_t *nameserver, knot_packet_t *response, uint8_t rcode, uint8_t *response_wire, size_t *rsize) @@ -2868,6 +2904,7 @@ void knot_ns_error_response_full(knot_nameserver_t *nameserver, if (ns_error_response_to_wire(response, response_wire, rsize) != 0) { knot_ns_error_response(nameserver, knot_packet_id( knot_packet_query(response)), + &response->header.flags1, KNOT_RCODE_SERVFAIL, response_wire, rsize); } @@ -3039,9 +3076,10 @@ int knot_ns_init_xfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) dbg_ns("Failed to parse rest of the query: %s\n", knot_strerror(ret)); knot_ns_error_response(nameserver, xfr->query->header.id, - (ret == KNOT_EMALF) ? KNOT_RCODE_FORMERR - : KNOT_RCODE_SERVFAIL, - xfr->wire, &xfr->wire_size); + &xfr->query->header.flags1, + (ret == KNOT_EMALF) ? KNOT_RCODE_FORMERR + : KNOT_RCODE_SERVFAIL, + xfr->wire, &xfr->wire_size); ret = xfr->send(xfr->session, &xfr->addr, xfr->wire, xfr->wire_size); return ret; @@ -3057,8 +3095,9 @@ int knot_ns_init_xfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) dbg_ns("Failed to create packet structure.\n"); /*! \todo xfr->wire is not NULL, will fail on assert! */ knot_ns_error_response(nameserver, xfr->query->header.id, - KNOT_RCODE_SERVFAIL, xfr->wire, - &xfr->wire_size); + &xfr->query->header.flags1, + KNOT_RCODE_SERVFAIL, xfr->wire, + &xfr->wire_size); ret = xfr->send(xfr->session, &xfr->addr, xfr->wire, xfr->wire_size); knot_packet_free(&response); @@ -3087,8 +3126,9 @@ int knot_ns_init_xfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) dbg_ns("Failed to init response structure.\n"); /*! \todo xfr->wire is not NULL, will fail on assert! */ knot_ns_error_response(nameserver, xfr->query->header.id, - KNOT_RCODE_SERVFAIL, xfr->wire, - &xfr->wire_size); + &xfr->query->header.flags1, + KNOT_RCODE_SERVFAIL, xfr->wire, + &xfr->wire_size); int res = xfr->send(xfr->session, &xfr->addr, xfr->wire, xfr->wire_size); knot_packet_free(&response); @@ -3205,6 +3245,7 @@ int knot_ns_xfr_send_error(const knot_nameserver_t *nameserver, if ((ret = ns_xfr_send_and_clear(xfr, 1)) != KNOT_EOK) { size_t size = 0; knot_ns_error_response(nameserver, xfr->query->header.id, + &xfr->query->header.flags1, KNOT_RCODE_SERVFAIL, xfr->wire, &size); ret = xfr->send(xfr->session, &xfr->addr, xfr->wire, size); } @@ -3229,8 +3270,9 @@ int knot_ns_answer_axfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) dbg_ns("AXFR failed on stub zone\n"); /*! \todo replace with knot_ns_xfr_send_error() */ knot_ns_error_response(nameserver, xfr->query->header.id, - KNOT_RCODE_SERVFAIL, xfr->wire, - &xfr->wire_size); + &xfr->query->header.flags1, + KNOT_RCODE_SERVFAIL, xfr->wire, + &xfr->wire_size); ret = xfr->send(xfr->session, &xfr->addr, xfr->wire, xfr->wire_size); rcu_read_unlock(); @@ -3263,8 +3305,9 @@ int knot_ns_answer_axfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) /*! \todo xfr->wire is not NULL, will fail on assert! */ /*! \todo replace with knot_ns_xfr_send_error() */ knot_ns_error_response(nameserver, xfr->query->header.id, - KNOT_RCODE_SERVFAIL, xfr->wire, - &xfr->wire_size); + &xfr->query->header.flags1, + KNOT_RCODE_SERVFAIL, xfr->wire, + &xfr->wire_size); ret = xfr->send(xfr->session, &xfr->addr, xfr->wire, xfr->wire_size); } else if (ret > 0) { @@ -3576,6 +3619,7 @@ int knot_ns_process_update(knot_nameserver_t *nameserver, knot_packet_t *query, MAX_UDP_PAYLOAD); if (ret != KNOT_EOK) { knot_ns_error_response(nameserver, knot_packet_id(query), + &query->header.flags1, KNOT_RCODE_SERVFAIL, response_wire, rsize); return KNOT_EOK; diff --git a/src/libknot/nameserver/name-server.h b/src/libknot/nameserver/name-server.h index d40a7d9..da19f49 100644 --- a/src/libknot/nameserver/name-server.h +++ b/src/libknot/nameserver/name-server.h @@ -231,8 +231,15 @@ int knot_ns_parse_packet(const uint8_t *query_wire, size_t qsize, * \param response_wire Place for wire format of the response. * \param rsize Size of the error response will be stored here. */ -void knot_ns_error_response(const knot_nameserver_t *nameserver, uint16_t query_id, - uint8_t rcode, uint8_t *response_wire, size_t *rsize); +void knot_ns_error_response(const knot_nameserver_t *nameserver, + uint16_t query_id, uint8_t *flags1_query, + uint8_t rcode, uint8_t *response_wire, + size_t *rsize); + +int knot_ns_error_response_from_query(const knot_nameserver_t *nameserver, + const uint8_t *query, size_t size, + uint8_t rcode, uint8_t *response_wire, + size_t *rsize); void knot_ns_error_response_full(knot_nameserver_t *nameserver, knot_packet_t *response, uint8_t rcode, diff --git a/src/libknot/updates/xfr-in.c b/src/libknot/updates/xfr-in.c index 4874ccd..ea8178d 100644 --- a/src/libknot/updates/xfr-in.c +++ b/src/libknot/updates/xfr-in.c @@ -730,7 +730,7 @@ dbg_xfrin_exec( return KNOT_ERROR; /*! \todo Other error code. */ } else if (ret == 1) { assert(node != NULL); -dbg_xfrin_exec( +dbg_xfrin_exec_verb( char *name = knot_dname_to_str(node->owner); dbg_xfrin("Found node for the record in " "zone: %s. Merged.\n", name); @@ -744,7 +744,7 @@ dbg_xfrin_exec( // knot_rrset_deep_free(&rr, 1, 1, 1); } else { assert(node != NULL); -dbg_xfrin_exec( +dbg_xfrin_exec_verb( char *name = knot_dname_to_str(node->owner); dbg_xfrin("Found node for the record in " "zone: %s.\n", name); @@ -1113,10 +1113,10 @@ int xfrin_process_ixfr_packet(knot_ns_xfr_t *xfr) /*! \todo This may be implemented with much less IFs! */ while (ret == KNOT_EOK && rr != NULL) { -dbg_xfrin_exec( - dbg_xfrin("Next loop, state: %d\n", state); +dbg_xfrin_exec_verb( + dbg_xfrin_verb("Next loop, state: %d\n", state); char *name = knot_dname_to_str(knot_rrset_owner(rr)); - dbg_xfrin("Actual RR: %s, type %s.\n", name, + dbg_xfrin_verb("Actual RR: %s, type %s.\n", name, knot_rrtype_to_string(knot_rrset_type(rr))); free(name); ); @@ -1228,9 +1228,9 @@ dbg_xfrin_exec( } // parse the next RR - dbg_xfrin("Parsing next RR..\n"); + dbg_xfrin_verb("Parsing next RR..\n"); ret = knot_packet_parse_next_rr_answer(packet, &rr); - dbg_xfrin("Returned %d, %p.\n", ret, rr); + dbg_xfrin_verb("Returned %d, %p.\n", ret, rr); } /*! \note Check TSIG, we're at the end of packet. It may not be @@ -1269,13 +1269,12 @@ cleanup: static int xfrin_changes_check_rrsets(knot_rrset_t ***rrsets, int *count, int *allocated, int to_add) { - /* Ensure at least requested size is allocated. */ - int new_count = (*count + to_add); - assert(new_count >= 0); - if (new_count <= *allocated) { + if (*count + to_add <= *allocated) { return KNOT_EOK; } + int new_count = (*allocated == 0) ? 2 : *allocated * 2; + /* Allocate new memory block. */ knot_rrset_t **rrsets_new = malloc(new_count * sizeof(knot_rrset_t *)); if (rrsets_new == NULL) { @@ -1303,12 +1302,12 @@ static int xfrin_changes_check_nodes(knot_node_t ***nodes, assert(count != NULL); assert(allocated != 0); - /* Ensure at least count and some reserve is allocated. */ - int new_count = *count + 2; - if (new_count <= *allocated) { + if (*count + 2 <= *allocated) { return KNOT_EOK; } + int new_count = (*allocated == 0) ? 2 : *allocated * 2; + /* Allocate new memory block. */ const size_t node_len = sizeof(knot_node_t *); knot_node_t **nodes_new = malloc(new_count * node_len); @@ -1333,13 +1332,12 @@ static int xfrin_changes_check_nodes(knot_node_t ***nodes, static int xfrin_changes_check_rdata(knot_rdata_t ***rdatas, uint **types, int count, int *allocated, int to_add) { - /* Ensure at least requested size is allocated. */ - int new_count = (count + to_add); - assert(new_count >= 0); - if (new_count <= *allocated) { + if (count + to_add <= *allocated) { return KNOT_EOK; } + int new_count = (*allocated == 0) ? 2 : *allocated * 2; + /* Allocate new memory block. */ knot_rdata_t **rdatas_new = malloc(new_count * sizeof(knot_rdata_t *)); if (rdatas_new == NULL) { @@ -1380,26 +1378,26 @@ static void xfrin_changes_add_rdata(knot_rdata_t **rdatas, uint *types, return; } -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]; - if (r == NULL) { - continue; - } - while (r != NULL && 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); - } - } -); +//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]; +// if (r == NULL) { +// continue; +// } +// while (r != NULL && 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; @@ -1461,7 +1459,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, knot_changes_t *changes) { - dbg_xfrin("Copying old RRSet: %p\n", old); + dbg_xfrin_verb("Copying old RRSet: %p\n", old); // create new RRSet by copying the old one // int ret = knot_rrset_shallow_copy(old, copy); int ret = knot_rrset_deep_copy(old, copy); @@ -1573,7 +1571,7 @@ dbg_xfrin_exec_verb( knot_node_rrset(node, type)); if (old == NULL) { - dbg_xfrin("RRSet not found for RR to be removed.\n"); + dbg_xfrin_verb("RRSet not found for RR to be removed.\n"); return 1; } @@ -1784,11 +1782,11 @@ static int xfrin_apply_remove_normal(knot_changes_t *changes, } /*! \todo Does some other case even occur? */ if (*rrset == NULL) { - dbg_xfrin("RRSet not found for RR to be removed.\n"); + dbg_xfrin_verb("RRSet not found for RR to be removed.\n"); return 1; } -dbg_xfrin_exec( +dbg_xfrin_exec_verb( char *name = knot_dname_to_str(knot_rrset_owner(*rrset)); dbg_xfrin("Updating RRSet with owner %s, type %s\n", name, knot_rrtype_to_string(knot_rrset_type(*rrset))); @@ -1961,7 +1959,7 @@ static int xfrin_apply_add_normal(knot_changes_t *changes, int ret; - dbg_xfrin("applying rrset:\n"); + dbg_xfrin_verb("applying rrset:\n"); knot_rrset_dump(add, 0); /*! \note Reusing RRSet from previous function caused it not to be @@ -1981,7 +1979,7 @@ static int xfrin_apply_add_normal(knot_changes_t *changes, *rrset = knot_node_remove_rrset(node, knot_rrset_type(add)); - dbg_xfrin("Removed RRSet: \n"); + dbg_xfrin_verb("Removed RRSet: \n"); knot_rrset_dump(*rrset, 1); if (*rrset == NULL) { @@ -2017,7 +2015,7 @@ dbg_xfrin_exec_verb( knot_rrset_t *old = *rrset; -dbg_xfrin_exec( +dbg_xfrin_exec_verb( char *name = knot_dname_to_str(knot_rrset_owner(*rrset)); dbg_xfrin("Found RRSet with owner %s, type %s\n", name, knot_rrtype_to_string(knot_rrset_type(*rrset))); @@ -2029,7 +2027,7 @@ dbg_xfrin_exec( return ret; } - dbg_xfrin("Copied RRSet: %p\n", *rrset); + dbg_xfrin_verb("Copied RRSet: %p\n", *rrset); // dbg_xfrin("After copy: Found RRSet with owner %s, type %s\n", // knot_dname_to_str((*rrset)->owner), @@ -2046,10 +2044,10 @@ dbg_xfrin_exec( * * TODO: add the 'add' rrset to list of old RRSets? */ - dbg_xfrin("Merging RRSets with owners: %s, %s types: %s, %s\n", - (*rrset)->owner->name, add->owner->name, - knot_rrtype_to_string((*rrset)->type), - knot_rrtype_to_string(add->type)); + dbg_xfrin_verb("Merging RRSets with owners: %s, %s types: %s, %s\n", + (*rrset)->owner->name, add->owner->name, + knot_rrtype_to_string((*rrset)->type), + knot_rrtype_to_string(add->type)); dbg_xfrin_detail("RDATA in RRSet1: %p, RDATA in RRSet2: %p\n", (*rrset)->rdata, add->rdata); @@ -2058,7 +2056,7 @@ dbg_xfrin_exec( dbg_xfrin("Failed to merge changeset RRSet to copy.\n"); return KNOT_ERROR; } - dbg_xfrin("Merge returned: %d\n", ret); + dbg_xfrin_verb("Merge returned: %d\n", ret); knot_rrset_dump(*rrset, 1); ret = knot_node_add_rrset(node, *rrset, 0); @@ -2094,7 +2092,7 @@ static int xfrin_apply_add_rrsig(knot_changes_t *changes, knot_rr_type_t type = knot_rdata_rrsig_type_covered( knot_rrset_rdata(add)); -dbg_xfrin_exec( +dbg_xfrin_exec_verb( char *name = knot_dname_to_str(knot_rrset_owner(add)); const char *typestr = knot_rrtype_to_string(type); dbg_xfrin("Adding RRSIG: Owner %s, type covered %s.\n", @@ -2128,7 +2126,7 @@ dbg_xfrin_exec( } if (*rrset == NULL) { - dbg_xfrin("RRSet to be added not found in zone.\n"); + dbg_xfrin_verb("RRSet to be added not found in zone.\n"); // create a new RRSet to add the RRSIGs into *rrset = knot_rrset_new(knot_node_get_owner(node), type, @@ -2138,7 +2136,7 @@ dbg_xfrin_exec( dbg_xfrin("Failed to create new RRSet for RRSIGs.\n"); return KNOT_ENOMEM; } - dbg_xfrin("Created new RRSet for RRSIG: %p.\n", *rrset); + dbg_xfrin_verb("Created new RRSet for RRSIG: %p.\n", *rrset); // add the RRset to the list of new RRsets ret = xfrin_changes_check_rrsets( @@ -2165,7 +2163,7 @@ dbg_xfrin_exec( changes->new_rrsets[changes->new_rrsets_count++] = *rrset; } -dbg_xfrin_exec( +dbg_xfrin_exec_verb( char *name = knot_dname_to_str(knot_rrset_owner(*rrset)); dbg_xfrin("Found RRSet with owner %s, type %s\n", name, knot_rrtype_to_string(knot_rrset_type(*rrset))); @@ -2174,7 +2172,7 @@ dbg_xfrin_exec( if (knot_rrset_rrsigs(*rrset) == NULL) { - dbg_xfrin("Adding new RRSIGs to RRSet.\n"); + dbg_xfrin_verb("Adding new RRSIGs to RRSet.\n"); ret = knot_zone_contents_add_rrsigs(contents, add, rrset, &node, KNOT_RRSET_DUPL_SKIP, 1); @@ -2205,7 +2203,7 @@ dbg_xfrin_exec( knot_rrset_set_rrsigs(*rrset, rrsig); // merge the changeset RRSet to the copy - dbg_xfrin("Merging RRSIG to the one in the RRSet.\n"); + dbg_xfrin_verb("Merging RRSIG to the one in the RRSet.\n"); ret = knot_rrset_merge((void **)&rrsig, (void **)&add); if (ret != KNOT_EOK) { dbg_xfrin("Failed to merge changeset RRSIG to copy: %s" @@ -2415,6 +2413,8 @@ void xfrin_rollback_update(knot_zone_contents_t *old_contents, { assert(changes != NULL); + dbg_xfrin("Rolling back changeset application.\n"); + if (*changes != NULL) { // discard new RRSets for (int i = 0; i < (*changes)->new_rrsets_count; ++i) { @@ -2533,8 +2533,8 @@ dbg_xfrin_exec_detail( knot_rrset_owner(chset->remove[i])); } if (node == NULL) { - dbg_xfrin("Node not found for RR to be removed" - "!\n"); + dbg_xfrin_verb("Node not found for RR to be " + "removed!\n"); continue; } } @@ -2559,7 +2559,7 @@ dbg_xfrin_exec_detail( node, &rrset); } - dbg_xfrin("xfrin_apply_remove() ret = %d\n", ret); + dbg_xfrin_verb("xfrin_apply_remove() ret = %d\n", ret); if (ret > 0) { continue; @@ -2624,7 +2624,7 @@ dbg_xfrin_exec_detail( if (node == NULL) { // create new node, connect it properly to the // zone nodes - dbg_xfrin("Node not found. Creating new.\n"); + dbg_xfrin_verb("Node not found. Creating new.\n"); node = xfrin_add_new_node(contents, chset->add[i], is_nsec3); @@ -2648,8 +2648,8 @@ dbg_xfrin_exec_detail( assert(ret != KNOT_EOK); - dbg_xfrin("xfrin_apply_..() returned %d, rrset: %p\n", ret, - rrset); + dbg_xfrin_verb("xfrin_apply_..() returned %d, rrset: %p\n", ret, + rrset); if (ret > 0) { if (ret == 1) { @@ -2922,8 +2922,10 @@ static int xfrin_remove_empty_nodes(knot_zone_contents_t *contents, { int ret; - dbg_xfrin("OLD NODES COUNT: %d\n", changes->old_nodes_count); - dbg_xfrin("OLD NSEC3 NODES COUNT: %d\n", changes->old_nsec3_count); + dbg_xfrin("Removing empty nodes from zone.\n"); + + dbg_xfrin_verb("OLD NODES COUNT: %d\n", changes->old_nodes_count); + dbg_xfrin_verb("OLD NSEC3 NODES COUNT: %d\n", changes->old_nsec3_count); // walk through the zone and select nodes to be removed ret = knot_zone_contents_tree_apply_inorder_reverse(contents, @@ -2937,8 +2939,8 @@ static int xfrin_remove_empty_nodes(knot_zone_contents_t *contents, (void *)changes); assert(ret == KNOT_EOK); - dbg_xfrin("OLD NODES COUNT: %d\n", changes->old_nodes_count); - dbg_xfrin("OLD NSEC3 NODES COUNT: %d\n", changes->old_nsec3_count); + dbg_xfrin_verb("OLD NODES COUNT: %d\n", changes->old_nodes_count); + dbg_xfrin_verb("OLD NSEC3 NODES COUNT: %d\n", changes->old_nsec3_count); // remove these nodes from both hash table and the tree ck_hash_table_item_t *hash_item = NULL; @@ -2997,73 +2999,6 @@ static int xfrin_remove_empty_nodes(knot_zone_contents_t *contents, /*----------------------------------------------------------------------------*/ -//static int xfrin_adjust_contents(knot_zone_contents_t *contents, -// xfrin_changes_t *changes) -//{ -// // first, load the NSEC3PARAM record, if there is one -// const knot_node_t *apex = knot_zone_contents_apex(contents); -// assert(apex != NULL); -// const knot_rrset_t *rrset = knot_node_rrset(apex, -// KNOT_RRTYPE_NSEC3PARAM); - -// if (rrset != NULL) { -// knot_nsec3_params_from_wire(&contents->nsec3_params, rrset); -// } else { -// memset(&contents->nsec3_params, 0, sizeof(knot_nsec3_params_t)); -// } - -// // ^ OK - -// xfrin_adjust_data_t data; -//// data.changes = changes; -// data.contents = contents; -// data.err = KNOT_EOK; - -// /* -// * Select and delete empty nodes. -// * -// * TODO: do separately -// */ -// int ret = xfrin_remove_empty_nodes(contents, changes); -// if (ret != KNOT_EOK) { -// dbg_xfrin("Failed to remove empty nodes: %s\n", -// knot_strerror(ret)); -// return ret; -// } - -// /* -// * Walk through the nodes in the zone and do the following: -// * 1) Check node flags (authoritative / non-authoritative / deleg. pt.). -// * 2) For each node without NSEC3 node, try to find the NSEC3 node. -// * 3) Insert all dnames to dname table. -// * -// * We must also set previous nodes, as this cannot be done during -// * node insertion - in that time we do not know, if the node is -// * authoritative or no. -// */ - -// knot_zone_contents_tree_apply_inorder(contents, -// xfrin_adjust_node_in_tree, -// (void *)&data); - -// if (data.err != KNOT_EOK) { -// dbg_xfrin("Failed to adjust nodes after IXFR: %s\n", -// knot_strerror(data.err)); -// return data.err; -// } - -// /* -// * In second walkthrough check CNAME loops, including wildcards. -// */ -// knot_zone_contents_tree_apply_inorder(contents, -// xfrin_check_loops_in_tree, -// (void *)&data); - -// return data.err; -//} - -/*----------------------------------------------------------------------------*/ - static void xfrin_check_contents_copy_node(knot_node_t *node, void *data) { assert(node != NULL); diff --git a/src/libknot/util/descriptor.c b/src/libknot/util/descriptor.c index e6a0377..63e1747 100644 --- a/src/libknot/util/descriptor.c +++ b/src/libknot/util/descriptor.c @@ -373,6 +373,13 @@ static knot_rrtype_descriptor_t { KNOT_RDATA_ZF_BYTE, KNOT_RDATA_ZF_BYTE, KNOT_RDATA_ZF_SHORT, KNOT_RDATA_ZF_HEX_LEN }, true }, /* 52 */ + { KNOT_RRTYPE_TLSA, "TLSA", 4, + { KNOT_RDATA_WF_BYTE, + KNOT_RDATA_WF_BYTE, + KNOT_RDATA_WF_BYTE, + KNOT_RDATA_WF_BINARY }, + { KNOT_RDATA_ZF_BYTE, KNOT_RDATA_ZF_BYTE, + KNOT_RDATA_ZF_BYTE, KNOT_RDATA_ZF_HEX }, true }, /* In NSD they have indices between 52 and 99 filled with diff --git a/src/libknot/util/descriptor.h b/src/libknot/util/descriptor.h index 10d3d20..b7e4a53 100644 --- a/src/libknot/util/descriptor.h +++ b/src/libknot/util/descriptor.h @@ -142,6 +142,7 @@ enum knot_rr_type { * \brief 51 - NSEC3PARAM at zone apex nsec3 parameters */ KNOT_RRTYPE_NSEC3PARAM, + KNOT_RRTYPE_TLSA = 52, /* TODO consider some better way of doing this, indices too high */ diff --git a/src/libknot/zone/node.c b/src/libknot/zone/node.c index 27eb7f2..4ad2a27 100644 --- a/src/libknot/zone/node.c +++ b/src/libknot/zone/node.c @@ -215,6 +215,10 @@ knot_node_t *knot_node_new(knot_dname_t *owner, knot_node_t *parent, int knot_node_add_rrset(knot_node_t *node, knot_rrset_t *rrset, int merge) { + if (node == NULL) { + return KNOT_EBADARG; + } + int ret = 0; if ((ret = (gen_tree_add(node->rrset_tree, rrset, @@ -236,7 +240,10 @@ int knot_node_add_rrset(knot_node_t *node, knot_rrset_t *rrset, const knot_rrset_t *knot_node_rrset(const knot_node_t *node, uint16_t type) { - assert(node != NULL); + if (node == NULL) { + return NULL; + } + assert(node->rrset_tree != NULL); knot_rrset_t rrset; rrset.type = type; @@ -247,6 +254,10 @@ const knot_rrset_t *knot_node_rrset(const knot_node_t *node, knot_rrset_t *knot_node_get_rrset(const knot_node_t *node, uint16_t type) { + if (node == NULL) { + return NULL; + } + knot_rrset_t rrset; rrset.type = type; return (knot_rrset_t *)gen_tree_find(node->rrset_tree, &rrset); @@ -256,6 +267,10 @@ knot_rrset_t *knot_node_get_rrset(const knot_node_t *node, uint16_t type) knot_rrset_t *knot_node_remove_rrset(knot_node_t *node, uint16_t type) { + if (node == NULL) { + return NULL; + } + knot_rrset_t dummy_rrset; dummy_rrset.type = type; knot_rrset_t *rrset = @@ -271,6 +286,10 @@ knot_rrset_t *knot_node_remove_rrset(knot_node_t *node, uint16_t type) void knot_node_remove_all_rrsets(knot_node_t *node) { + if (node == NULL) { + return; + } + // remove RRSets but do not delete them gen_tree_clear(node->rrset_tree); node->rrset_count = 0; @@ -281,6 +300,10 @@ void knot_node_remove_all_rrsets(knot_node_t *node) short knot_node_rrset_count(const knot_node_t *node) { + if (node == NULL) { + return KNOT_EBADARG; + } + return node->rrset_count; } @@ -308,8 +331,7 @@ static void save_rrset_to_array(void *node, void *data) knot_rrset_t **knot_node_get_rrsets(const knot_node_t *node) { -// knot_node_dump(node, 1); - if (node->rrset_count == 0) { + if (node == NULL || node->rrset_count == 0) { return NULL; } knot_rrset_t **rrsets = (knot_rrset_t **)malloc( @@ -331,6 +353,10 @@ knot_rrset_t **knot_node_get_rrsets(const knot_node_t *node) const knot_rrset_t **knot_node_rrsets(const knot_node_t *node) { + if (node == NULL) { + return NULL; + } + return (const knot_rrset_t **)knot_node_get_rrsets(node); } @@ -349,6 +375,10 @@ static void count_rrsets(void *node, void *data) int knot_node_count_rrsets(const knot_node_t *node) { + if (node == NULL) { + return KNOT_EBADARG; + } + int count = 0; gen_tree_apply_inorder(node->rrset_tree, count_rrsets, (void *)&count); @@ -359,6 +389,10 @@ int knot_node_count_rrsets(const knot_node_t *node) const knot_node_t *knot_node_parent(const knot_node_t *node) { + if (node == NULL) { + return NULL; + } + return knot_node_get_parent(node); } @@ -377,7 +411,7 @@ knot_node_t *knot_node_get_parent(const knot_node_t *node) void knot_node_set_parent(knot_node_t *node, knot_node_t *parent) { - if (node->parent == parent) { + if (node == NULL || node->parent == parent) { return; } @@ -398,6 +432,10 @@ void knot_node_set_parent(knot_node_t *node, knot_node_t *parent) unsigned int knot_node_children(const knot_node_t *node) { + if (node == NULL) { + return KNOT_EBADARG; + } + return node->children; } @@ -405,6 +443,10 @@ unsigned int knot_node_children(const knot_node_t *node) const knot_node_t *knot_node_previous(const knot_node_t *node) { + if (node == NULL) { + return NULL; + } + return knot_node_get_previous(node); } @@ -423,6 +465,10 @@ knot_node_t *knot_node_get_previous(const knot_node_t *node) const knot_node_t *knot_node_next(const knot_node_t *node) { + if (node == NULL) { + return NULL; + } + return node->next; } @@ -430,6 +476,10 @@ const knot_node_t *knot_node_next(const knot_node_t *node) void knot_node_set_previous(knot_node_t *node, knot_node_t *prev) { + if (node == NULL) { + return; + } + node->prev = prev; } @@ -448,6 +498,10 @@ knot_node_t *knot_node_get_nsec3_node(const knot_node_t *node) const knot_node_t *knot_node_nsec3_node(const knot_node_t *node) { + if (node == NULL) { + return NULL; + } + return knot_node_get_nsec3_node(node); } @@ -455,6 +509,10 @@ const knot_node_t *knot_node_nsec3_node(const knot_node_t *node) void knot_node_set_nsec3_node(knot_node_t *node, knot_node_t *nsec3_node) { + if (node == NULL) { + return; + } + node->nsec3_node = nsec3_node; if (nsec3_node != NULL) { nsec3_node->nsec3_referer = node; @@ -465,6 +523,10 @@ void knot_node_set_nsec3_node(knot_node_t *node, knot_node_t *nsec3_node) const knot_dname_t *knot_node_owner(const knot_node_t *node) { + if (node == NULL) { + return NULL; + } + return node->owner; } @@ -503,6 +565,10 @@ knot_node_t *knot_node_get_wildcard_child(const knot_node_t *node) void knot_node_set_wildcard_child(knot_node_t *node, knot_node_t *wildcard_child) { + if (node == NULL) { + return; + } + node->wildcard_child = wildcard_child; // assert(wildcard_child->parent == node); } @@ -511,62 +577,21 @@ void knot_node_set_wildcard_child(knot_node_t *node, const knot_node_t *knot_node_wildcard_child(const knot_node_t *node) { + if (node == NULL) { + return NULL; + } + return knot_node_get_wildcard_child(node); } /*----------------------------------------------------------------------------*/ -//const knot_node_t *knot_node_current(const knot_node_t *node) -//{ -// if (node == NULL || node->zone == NULL -// || knot_zone_contents(node->zone) == NULL) { -// return node; -// } - -// int new_gen = knot_node_zone_gen_is_new(node); -// int old_gen = knot_node_zone_gen_is_old(node); -//// short ver = knot_node_zone_generation(node); - -// if (old_gen && knot_node_is_new(node)) { -// return NULL; -// } else if (new_gen && knot_node_is_old(node)) { -// assert(node->new_node != NULL); -// return node->new_node; -// } -// return node; -//} - -/*----------------------------------------------------------------------------*/ - -//knot_node_t *knot_node_get_current(knot_node_t *node) -//{ -// if (node == NULL || node->zone == NULL -// || knot_zone_contents(node->zone) == NULL) { -// return node; -// } - -// int new_gen = knot_node_zone_gen_is_new(node); -// int old_gen = knot_node_zone_gen_is_old(node); -//// short ver = knot_node_zone_generation(node); - -// if (old_gen && knot_node_is_new(node)) { -// return NULL; -// } else if (new_gen && knot_node_is_old(node)) { -// assert(node->new_node != NULL); -// return node->new_node; -// } - -// assert((old_gen && knot_node_is_old(node)) -// || (new_gen && knot_node_is_new(node)) -// || (!old_gen && !new_gen)); - -// return node; -//} - -/*----------------------------------------------------------------------------*/ - const knot_node_t *knot_node_new_node(const knot_node_t *node) { + if (node == NULL) { + return NULL; + } + return node->new_node; } @@ -574,6 +599,10 @@ const knot_node_t *knot_node_new_node(const knot_node_t *node) knot_node_t *knot_node_get_new_node(const knot_node_t *node) { + if (node == NULL) { + return NULL; + } + return node->new_node; } @@ -582,6 +611,10 @@ knot_node_t *knot_node_get_new_node(const knot_node_t *node) void knot_node_set_new_node(knot_node_t *node, knot_node_t *new_node) { + if (node == NULL) { + return; + } + node->new_node = new_node; } @@ -589,6 +622,10 @@ void knot_node_set_new_node(knot_node_t *node, void knot_node_set_zone(knot_node_t *node, knot_zone_t *zone) { + if (node == NULL) { + return; + } + node->zone = zone; } @@ -596,9 +633,6 @@ void knot_node_set_zone(knot_node_t *node, knot_zone_t *zone) void knot_node_update_ref(knot_node_t **ref) { -// if (*ref != NULL && knot_node_is_old(*ref)) { -// *ref = (*ref)->new_node; -// } if (*ref != NULL && (*ref)->new_node != NULL) { *ref = (*ref)->new_node; } @@ -626,6 +660,10 @@ void knot_node_update_refs(knot_node_t *node) void knot_node_set_deleg_point(knot_node_t *node) { + if (node == NULL) { + return; + } + knot_node_flags_set_deleg(&node->flags); } @@ -633,6 +671,10 @@ void knot_node_set_deleg_point(knot_node_t *node) int knot_node_is_deleg_point(const knot_node_t *node) { + if (node == NULL) { + return KNOT_EBADARG; + } + return knot_node_flags_get_deleg(node->flags); } @@ -640,6 +682,10 @@ int knot_node_is_deleg_point(const knot_node_t *node) void knot_node_set_non_auth(knot_node_t *node) { + if (node == NULL) { + return; + } + knot_node_flags_set_nonauth(&node->flags); } @@ -647,6 +693,10 @@ void knot_node_set_non_auth(knot_node_t *node) int knot_node_is_non_auth(const knot_node_t *node) { + if (node == NULL) { + return KNOT_EBADARG; + } + return knot_node_flags_get_nonauth(node->flags); } @@ -654,51 +704,13 @@ int knot_node_is_non_auth(const knot_node_t *node) int knot_node_is_auth(const knot_node_t *node) { + if (node == NULL) { + return KNOT_EBADARG; + } + return (node->flags == 0); } -///*----------------------------------------------------------------------------*/ - -//int knot_node_is_new(const knot_node_t *node) -//{ -// return knot_node_flags_get_new(node->flags); -//} - -///*----------------------------------------------------------------------------*/ - -//int knot_node_is_old(const knot_node_t *node) -//{ -// return knot_node_flags_get_old(node->flags); -//} - -///*----------------------------------------------------------------------------*/ - -//void knot_node_set_new(knot_node_t *node) -//{ -// knot_node_flags_set_new(&node->flags); -//} - -///*----------------------------------------------------------------------------*/ - -//void knot_node_set_old(knot_node_t *node) -//{ -// knot_node_flags_set_old(&node->flags); -//} - -///*----------------------------------------------------------------------------*/ - -//void knot_node_clear_new(knot_node_t *node) -//{ -// knot_node_flags_clear_new(&node->flags); -//} - -///*----------------------------------------------------------------------------*/ - -//void knot_node_clear_old(knot_node_t *node) -//{ -// knot_node_flags_clear_old(&node->flags); -//} - /*----------------------------------------------------------------------------*/ static void knot_node_free_rrsets_from_tree(void *item, void *data) @@ -723,6 +735,10 @@ void knot_node_free_rrsets(knot_node_t *node, int free_rdata_dnames) // free(rrsets); + if (node == NULL) { + return; + } + char *name = knot_dname_to_str(node->owner); free(name); @@ -805,6 +821,8 @@ void knot_node_free(knot_node_t **node, int fix_refs) int knot_node_compare(knot_node_t *node1, knot_node_t *node2) { + assert(node1 != NULL && node2 != NULL); + return knot_dname_compare(node1->owner, node2->owner); } @@ -812,6 +830,10 @@ int knot_node_compare(knot_node_t *node1, knot_node_t *node2) int knot_node_shallow_copy(const knot_node_t *from, knot_node_t **to) { + if (from == NULL || to == NULL) { + return KNOT_EBADARG; + } + // create new node *to = knot_node_new(from->owner, NULL, from->flags); if (*to == NULL) { diff --git a/src/libknot/zone/zone-contents.c b/src/libknot/zone/zone-contents.c index 3764acc..19268c4 100644 --- a/src/libknot/zone/zone-contents.c +++ b/src/libknot/zone/zone-contents.c @@ -40,6 +40,15 @@ typedef struct { /*----------------------------------------------------------------------------*/ +const uint8_t KNOT_ZONE_FLAGS_GEN_OLD = 0; /* xxxxxx00 */ +const uint8_t KNOT_ZONE_FLAGS_GEN_NEW = 1 << 0; /* xxxxxx01 */ +const uint8_t KNOT_ZONE_FLAGS_GEN_FIN = 1 << 2; /* xxxxxx10 */ +const uint8_t KNOT_ZONE_FLAGS_GEN_MASK = 3; /* 00000011 */ +const uint8_t KNOT_ZONE_FLAGS_ANY_MASK = 4; /* 00000100 */ +const uint8_t KNOT_ZONE_FLAGS_ANY = 4; /* 00000100 */ + +/*----------------------------------------------------------------------------*/ + static void knot_zone_tree_apply(knot_zone_tree_node_t *node, void *data) { @@ -1134,58 +1143,72 @@ cleanup: /*----------------------------------------------------------------------------*/ -//short knot_zone_contents_generation(const knot_zone_contents_t *zone) -//{ -// return zone->generation; -//} - -/*----------------------------------------------------------------------------*/ - int knot_zone_contents_gen_is_old(const knot_zone_contents_t *contents) { - return (contents->generation == 0); + return ((contents->flags & KNOT_ZONE_FLAGS_GEN_MASK) + == KNOT_ZONE_FLAGS_GEN_OLD); } /*----------------------------------------------------------------------------*/ int knot_zone_contents_gen_is_new(const knot_zone_contents_t *contents) { - return (contents->generation == 1); + return ((contents->flags & KNOT_ZONE_FLAGS_GEN_MASK) + == KNOT_ZONE_FLAGS_GEN_NEW); } /*----------------------------------------------------------------------------*/ int knot_zone_contents_gen_is_finished(const knot_zone_contents_t *contents) { - return (contents->generation == -1); + return ((contents->flags & KNOT_ZONE_FLAGS_GEN_MASK) + == KNOT_ZONE_FLAGS_GEN_FIN); } /*----------------------------------------------------------------------------*/ -//void knot_zone_contents_switch_generation(knot_zone_contents_t *zone) -//{ -// zone->generation = 1 - zone->generation; -//} - -/*----------------------------------------------------------------------------*/ - void knot_zone_contents_set_gen_old(knot_zone_contents_t *contents) { - contents->generation = 0; + contents->flags &= ~KNOT_ZONE_FLAGS_GEN_MASK; + contents->flags |= KNOT_ZONE_FLAGS_GEN_OLD; } /*----------------------------------------------------------------------------*/ void knot_zone_contents_set_gen_new(knot_zone_contents_t *contents) { - contents->generation = 1; + contents->flags &= ~KNOT_ZONE_FLAGS_GEN_MASK; + contents->flags |= KNOT_ZONE_FLAGS_GEN_NEW; } /*----------------------------------------------------------------------------*/ void knot_zone_contents_set_gen_new_finished(knot_zone_contents_t *contents) { - contents->generation = -1; + contents->flags &= ~KNOT_ZONE_FLAGS_GEN_MASK; + contents->flags |= KNOT_ZONE_FLAGS_GEN_FIN; +} + +/*----------------------------------------------------------------------------*/ + +int knot_zone_contents_any_disabled(const knot_zone_contents_t *contents) +{ + return ((contents->flags & KNOT_ZONE_FLAGS_ANY_MASK) + == KNOT_ZONE_FLAGS_ANY); +} + +/*----------------------------------------------------------------------------*/ + +void knot_zone_contents_disable_any(knot_zone_contents_t *contents) +{ + contents->flags |= KNOT_ZONE_FLAGS_ANY; +} + +/*----------------------------------------------------------------------------*/ + +void knot_zone_contents_enable_any(knot_zone_contents_t *contents) +{ + contents->flags &= ~KNOT_ZONE_FLAGS_ANY_MASK; } /*----------------------------------------------------------------------------*/ @@ -2619,7 +2642,7 @@ int knot_zone_contents_shallow_copy(const knot_zone_contents_t *from, } contents->node_count = from->node_count; - contents->generation = from->generation; + contents->flags = from->flags; contents->zone = from->zone; @@ -2716,7 +2739,7 @@ int knot_zone_contents_shallow_copy2(const knot_zone_contents_t *from, } contents->node_count = from->node_count; - contents->generation = from->generation; + contents->flags = from->flags; contents->zone = from->zone; diff --git a/src/libknot/zone/zone-contents.h b/src/libknot/zone/zone-contents.h index d31bbbb..3143ef9 100644 --- a/src/libknot/zone/zone-contents.h +++ b/src/libknot/zone/zone-contents.h @@ -60,15 +60,21 @@ typedef struct knot_zone_contents_t { */ uint node_count; - /*! \brief Generation of the zone during update. + /*! \brief Various flags * + * Two rightmost bits denote zone contents generation. + * * Possible values: - * - 0 - Original version of the zone. Old nodes should be used. - * - 1 - New (updated) zone. New nodes should be used. - * - -1 - New (updated) zone, but exactly the stored nodes should be + * - 00 - Original version of the zone. Old nodes should be used. + * - 01 - New (updated) zone. New nodes should be used. + * - 10 - New (updated) zone, but exactly the stored nodes should be * used, no matter their generation. + * + * The third bit denotes whether ANY queries are enabled or disabled: + * - 1xx - ANY queries disabled + * - 0xx - ANY queries enabled */ - short generation; + uint8_t flags; } knot_zone_contents_t; /*----------------------------------------------------------------------------*/ @@ -78,11 +84,6 @@ knot_zone_contents_t *knot_zone_contents_new(knot_node_t *apex, int use_domain_table, struct knot_zone *zone); -time_t knot_zone_contents_version(const knot_zone_contents_t *contents); - -void knot_zone_contents_set_version(knot_zone_contents_t *contents, - time_t version); - //short knot_zone_contents_generation(const knot_zone_contents_t *contents); int knot_zone_contents_gen_is_old(const knot_zone_contents_t *contents); @@ -95,6 +96,10 @@ void knot_zone_contents_set_gen_old(knot_zone_contents_t *contents); void knot_zone_contents_set_gen_new(knot_zone_contents_t *contents); void knot_zone_contents_set_gen_new_finished(knot_zone_contents_t *contents); +int knot_zone_contents_any_disabled(const knot_zone_contents_t *contents); +void knot_zone_contents_disable_any(knot_zone_contents_t *contents); +void knot_zone_contents_enable_any(knot_zone_contents_t *contents); + uint16_t knot_zone_contents_class(const knot_zone_contents_t *contents); /*! diff --git a/src/zcompile/parser-descriptor.c b/src/zcompile/parser-descriptor.c index 152781c..b876877 100644 --- a/src/zcompile/parser-descriptor.c +++ b/src/zcompile/parser-descriptor.c @@ -315,7 +315,12 @@ static parser_rrtype_descriptor_t PARSER_RDATA_WF_BYTE, /* flags */ PARSER_RDATA_WF_SHORT, /* iterations */ PARSER_RDATA_WF_BINARYWITHLENGTH /* salt */ }, true }, - /* 52 */ + /* 52 TLSA */ + { PARSER_RRTYPE_TLSA, T_TLSA, "TLSA", 3, + { PARSER_RDATA_WF_BYTE, + PARSER_RDATA_WF_BYTE, + PARSER_RDATA_WF_BYTE, + PARSER_RDATA_WF_BINARY}, true }, /* In NSD they have indices between 52 and 99 filled with diff --git a/src/zcompile/parser-descriptor.h b/src/zcompile/parser-descriptor.h index ba672f1..48c6f02 100644 --- a/src/zcompile/parser-descriptor.h +++ b/src/zcompile/parser-descriptor.h @@ -134,6 +134,7 @@ enum parser_rr_type { * \brief 51 - NSEC3PARAM at zone apex nsec3 parameters */ PARSER_RRTYPE_NSEC3PARAM, + PARSER_RRTYPE_TLSA = 52, /* TODO consider some better way of doing this, indices too high */ diff --git a/src/zcompile/parser-util.c b/src/zcompile/parser-util.c index c225872..cfbc624 100644 --- a/src/zcompile/parser-util.c +++ b/src/zcompile/parser-util.c @@ -2291,9 +2291,9 @@ uint16_t * zparser_conv_apl_rdata(char *str) zc_error_prev_line("invalid address '%s'", colon + 1); return NULL; } else if (rc == -1) { - char ebuf[256]; - zc_error_prev_line("inet_pton failed: %s", - strerror_r(errno, ebuf, sizeof(ebuf))); + char ebuf[256] = {0}; + strerror_r(errno, ebuf, sizeof(ebuf)); + zc_error_prev_line("inet_pton failed: %s", ebuf); return NULL; } diff --git a/src/zcompile/zcompile.c b/src/zcompile/zcompile.c index 263d0d7..c4415d4 100644 --- a/src/zcompile/zcompile.c +++ b/src/zcompile/zcompile.c @@ -549,23 +549,19 @@ static int zone_open(const char *filename, uint32_t ttl, uint16_t rclass, int zone_read(const char *name, const char *zonefile, const char *outfile, int semantic_checks) -{ - if (!outfile) { - zc_error_prev_line("Missing output file for '%s'\n", - zonefile); - return KNOTDZCOMPILE_EINVAL; - } - +{ dbg_zp("zp: zone_read: Reading zone: %s.\n", zonefile); /* Check that we can write to outfile. */ - FILE *f = fopen(outfile, "wb"); - if (f == NULL) { - fprintf(stderr, "Cannot write zone db to file '%s' (%s).\n", - outfile, strerror(errno)); - return KNOTDZCOMPILE_EINVAL; + if (outfile != NULL) { + FILE *f = fopen(outfile, "wb"); + if (f == NULL) { + fprintf(stderr, "Cannot write zone db to file '%s' (%s).\n", + outfile, strerror(errno)); + return KNOTDZCOMPILE_EINVAL; + } + fclose(f); } - fclose(f); knot_dname_t *dname = knot_dname_new_from_str(name, strlen(name), NULL); @@ -675,10 +671,10 @@ int zone_read(const char *name, const char *zonefile, const char *outfile, dbg_zp("zp: zone_read: Zone adjusted.\n"); if (parser->errors != 0) { - log_zone_error("Parser finished with %d error(s), " - "not dumping the zone!\n", - parser->errors); - } else { + log_zone_error("Parser finished with %d error(s)%s\n", + parser->errors, outfile == NULL ? + "." : ", not dumping the zone!"); + } else if (outfile != NULL) { int fd = open(outfile, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU | S_IRWXG); if (fd < 0) { log_zone_error("Could not open destination file for db: %s.\n", diff --git a/src/zcompile/zcompile_main.c b/src/zcompile/zcompile_main.c index 4b631ce..c84515e 100644 --- a/src/zcompile/zcompile_main.c +++ b/src/zcompile/zcompile_main.c @@ -85,8 +85,10 @@ int main(int argc, char **argv) // Initialize log (no syslog) log_init(); log_levels_set(LOGT_SYSLOG, LOG_ANY, 0); - log_zone_info("Parsing file '%s', origin '%s' ...\n", - zonefile, origin); + if (outfile != NULL) { + log_zone_info("Parsing file '%s', origin '%s' ...\n", + zonefile, origin); + } parser = zparser_create(); if (!parser) { @@ -107,8 +109,10 @@ int main(int argc, char **argv) // fprintf(stderr, "Finished with %u errors.\n"); // } return 1; - } else { + } else if (outfile != NULL) { log_zone_info("Compilation of '%s' successful.\n", origin); + } else { + log_zone_info("Zone file for '%s' is OK.\n", origin); } //log_close(); diff --git a/src/zcompile/zlexer.l b/src/zcompile/zlexer.l index c6c01fb..58e6439 100644 --- a/src/zcompile/zlexer.l +++ b/src/zcompile/zlexer.l @@ -243,9 +243,10 @@ ANY [^\"\n\\]|\\. if (strlen(yytext) == 0) { zc_error("missing file name in $INCLUDE directive"); } else if (!(input = fopen(yytext, "r"))) { - char ebuf[256]; + char ebuf[256] = {0}; + strerror_r(errno, ebuf, sizeof(ebuf)); zc_error("cannot open include file '%s': %s", - yytext, strerror_r(errno, ebuf, sizeof(ebuf))); + yytext, ebuf); } else { /* Initialize parser for include file. */ char *filename = strdup(yytext); diff --git a/src/zcompile/zparser.y b/src/zcompile/zparser.y index b353fbe..89af437 100644 --- a/src/zcompile/zparser.y +++ b/src/zcompile/zparser.y @@ -126,7 +126,7 @@ knot_dname_t *error_domain; %token T_GPOS T_EID T_NIMLOC T_ATMA T_NAPTR T_KX T_A6 T_DNAME T_SINK %token T_OPT T_APL T_UINFO T_UID T_GID T_UNSPEC T_TKEY T_TSIG T_IXFR %token T_AXFR T_MAILB T_MAILA T_DS T_DLV T_SSHFP T_RRSIG T_NSEC T_DNSKEY -%token T_SPF T_NSEC3 T_IPSECKEY T_DHCID T_NSEC3PARAM +%token T_SPF T_NSEC3 T_IPSECKEY T_DHCID T_NSEC3PARAM T_TLSA /* other tokens */ %token DOLLAR_TTL DOLLAR_ORIGIN NL SP NO_MEM @@ -566,14 +566,19 @@ str_seq: STR { zadd_rdata_txt_wireformat(zparser_conv_text($1.str, $1.len), 1); - free($1.str); + if(strcmp($1.str, ".") && strcmp($1.str, "@") + && strcmp($1.str, "\\#")) { // Lexer freed that + free($1.str); + } } | str_seq sp STR { zadd_rdata_txt_wireformat(zparser_conv_text($3.str, $3.len), 0); -// zc_warning("multiple TXT entries are currently not supported!"); - free($3.str); + if(strcmp($3.str, ".") && strcmp($3.str, "@") + && strcmp($3.str, "\\#")) { // Lexer freed that + free($3.str); + } } ; @@ -913,6 +918,8 @@ type_and_rdata: | T_NSEC3 sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_NSEC3PARAM sp rdata_nsec3_param | T_NSEC3PARAM sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } + | T_TLSA sp rdata_tlsa + | T_TLSA sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_DNSKEY sp rdata_dnskey | T_DNSKEY sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } | T_UTYPE sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); } @@ -1424,6 +1431,20 @@ rdata_nsec3_param: STR sp STR sp STR sp STR trail free($7.str); } ; + +rdata_tlsa: STR sp STR sp STR sp str_sp_seq trail + { + zadd_rdata_wireformat(zparser_conv_byte($1.str)); + zadd_rdata_wireformat(zparser_conv_byte($3.str)); + zadd_rdata_wireformat(zparser_conv_byte($5.str)); + zadd_rdata_wireformat(zparser_conv_hex($7.str, $7.len)); + + free($1.str); + free($3.str); + free($5.str); + free($7.str); + } + ; rdata_dnskey: STR sp STR sp STR sp str_sp_seq trail { -- cgit v1.2.3