diff options
author | Ondřej Surý <ondrej@sury.org> | 2012-08-31 16:26:55 +0200 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2012-08-31 16:26:55 +0200 |
commit | 9a7b8a090ba4fa50fc023bdea04e83602a2ad0bb (patch) | |
tree | c7fec3e97f0b5e116f35272799d69d802267851f /src | |
parent | 4355eafde2b6a80d2b8feaba30b6a884aff070d9 (diff) | |
download | knot-9a7b8a090ba4fa50fc023bdea04e83602a2ad0bb.tar.gz |
Imported Upstream version 1.1.0upstream/1.1.0
Diffstat (limited to 'src')
277 files changed, 7479 insertions, 5433 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 60c51c6..eece959 100644..100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,8 +1,8 @@ ACLOCAL_AMFLAGS = -I ../m4 libexec_PROGRAMS = knot-zcompile unittests unittests-zcompile unittests-libknot-realdata unittests-libknot unittests-xfr sbin_PROGRAMS = knotc knotd -MANPAGES = knotc.8 knotd.8 -man8_MANS = knotc.8 knotd.8 +MANPAGES = knotc.8 knotd.8 knot.conf.5 +man8_MANS = knotc.8 knotd.8 knot.conf.5 EXTRA_DIST = $(man8_MANS) # $(YACC) will generate header file @@ -58,8 +58,6 @@ knot_zcompile_SOURCES = \ unittests_SOURCES = \ tests/common/acl_tests.c \ tests/common/acl_tests.h \ - tests/common/da_tests.c \ - tests/common/da_tests.h \ tests/common/events_tests.c \ tests/common/events_tests.h \ tests/common/skiplist_tests.c \ @@ -159,8 +157,6 @@ libknot_la_SOURCES = \ libknot/util/debug.c \ libknot/util/debug.h \ libknot/util/utils.h \ - libknot/util/conv.h \ - libknot/util/conv.c \ libknot/util/descriptor.c \ libknot/util/tolower.h \ libknot/util/tolower.c \ @@ -184,6 +180,8 @@ libknot_la_SOURCES = \ libknot/zone/node.c \ libknot/zone/dname-table.h \ libknot/zone/dname-table.c \ + libknot/zone/zone-diff.h \ + libknot/zone/zone-diff.c \ libknot/hash/hash-functions.c \ libknot/hash/cuckoo-hash-table.c \ libknot/hash/universal-system.c \ @@ -225,17 +223,19 @@ libknots_la_SOURCES = \ common/mempattern.c \ common/lists.c \ common/base32.c \ + common/base64.c \ + common/base64.h \ common/lists.h \ + common/heap.h \ + common/heap.c \ common/base32.h \ common/print.c \ common/print.h \ - common/dynamic-array.c \ common/skip-list.c \ common/base32hex.c \ common/skip-list.h \ common/general-tree.h \ common/general-tree.c \ - common/dynamic-array.h \ common/tree.h \ common/base32hex.h \ common/evqueue.h \ diff --git a/src/Makefile.in b/src/Makefile.in index c00450d..d20810f 100644..100755 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -60,13 +60,13 @@ CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libknot_la_LIBADD = -am_libknot_la_OBJECTS = libknot_error.lo utils.lo debug.lo conv.lo \ +am_libknot_la_OBJECTS = libknot_error.lo utils.lo debug.lo \ descriptor.lo tolower.lo query.lo response.lo packet.lo \ zone.lo zone-contents.lo zone-tree.lo zonedb.lo node.lo \ - dname-table.lo hash-functions.lo cuckoo-hash-table.lo \ - universal-system.lo name-server.lo changesets.lo xfr-in.lo \ - ddns.lo edns.lo rrset.lo dname.lo rdata.lo nsec3.lo tsig.lo \ - tsig-op.lo + dname-table.lo zone-diff.lo hash-functions.lo \ + cuckoo-hash-table.lo universal-system.lo name-server.lo \ + changesets.lo xfr-in.lo ddns.lo edns.lo rrset.lo dname.lo \ + rdata.lo nsec3.lo tsig.lo tsig-op.lo libknot_la_OBJECTS = $(am_libknot_la_OBJECTS) libknotd_la_DEPENDENCIES = libknot.la libknots.la @LIBOBJS@ am_libknotd_la_OBJECTS = gatherer.lo stat.lo error.lo \ @@ -78,7 +78,7 @@ am_libknotd_la_OBJECTS = gatherer.lo stat.lo error.lo \ libknotd_la_OBJECTS = $(am_libknotd_la_OBJECTS) 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 \ + base32.lo base64.lo heap.lo print.lo skip-list.lo base32hex.lo \ general-tree.lo evqueue.lo evsched.lo acl.lo sockaddr.lo \ ref.lo errors.lo dSFMT.lo prng.lo fdset.lo fdset_poll.lo \ fdset_kqueue.lo fdset_epoll.lo log.lo @@ -99,12 +99,11 @@ knotc_DEPENDENCIES = libknotd.la libknot.la libknots.la @LIBOBJS@ am_knotd_OBJECTS = main.$(OBJEXT) knotd_OBJECTS = $(am_knotd_OBJECTS) knotd_DEPENDENCIES = libknotd.la libknot.la libknots.la @LIBOBJS@ -am_unittests_OBJECTS = acl_tests.$(OBJEXT) da_tests.$(OBJEXT) \ - events_tests.$(OBJEXT) skiplist_tests.$(OBJEXT) \ - slab_tests.$(OBJEXT) fdset_tests.$(OBJEXT) \ - conf_tests.$(OBJEXT) dthreads_tests.$(OBJEXT) \ - journal_tests.$(OBJEXT) server_tests.$(OBJEXT) \ - unittests_main.$(OBJEXT) +am_unittests_OBJECTS = acl_tests.$(OBJEXT) events_tests.$(OBJEXT) \ + skiplist_tests.$(OBJEXT) slab_tests.$(OBJEXT) \ + fdset_tests.$(OBJEXT) conf_tests.$(OBJEXT) \ + dthreads_tests.$(OBJEXT) journal_tests.$(OBJEXT) \ + server_tests.$(OBJEXT) unittests_main.$(OBJEXT) nodist_unittests_OBJECTS = unittests_OBJECTS = $(am_unittests_OBJECTS) \ $(nodist_unittests_OBJECTS) @@ -326,8 +325,8 @@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ ACLOCAL_AMFLAGS = -I ../m4 -MANPAGES = knotc.8 knotd.8 -man8_MANS = knotc.8 knotd.8 +MANPAGES = knotc.8 knotd.8 knot.conf.5 +man8_MANS = knotc.8 knotd.8 knot.conf.5 EXTRA_DIST = $(man8_MANS) # $(YACC) will generate header file @@ -382,8 +381,6 @@ knot_zcompile_SOURCES = \ unittests_SOURCES = \ tests/common/acl_tests.c \ tests/common/acl_tests.h \ - tests/common/da_tests.c \ - tests/common/da_tests.h \ tests/common/events_tests.c \ tests/common/events_tests.h \ tests/common/skiplist_tests.c \ @@ -482,8 +479,6 @@ libknot_la_SOURCES = \ libknot/util/debug.c \ libknot/util/debug.h \ libknot/util/utils.h \ - libknot/util/conv.h \ - libknot/util/conv.c \ libknot/util/descriptor.c \ libknot/util/tolower.h \ libknot/util/tolower.c \ @@ -507,6 +502,8 @@ libknot_la_SOURCES = \ libknot/zone/node.c \ libknot/zone/dname-table.h \ libknot/zone/dname-table.c \ + libknot/zone/zone-diff.h \ + libknot/zone/zone-diff.c \ libknot/hash/hash-functions.c \ libknot/hash/cuckoo-hash-table.c \ libknot/hash/universal-system.c \ @@ -548,17 +545,19 @@ libknots_la_SOURCES = \ common/mempattern.c \ common/lists.c \ common/base32.c \ + common/base64.c \ + common/base64.h \ common/lists.h \ + common/heap.h \ + common/heap.c \ common/base32.h \ common/print.c \ common/print.h \ - common/dynamic-array.c \ common/skip-list.c \ common/base32hex.c \ common/skip-list.h \ common/general-tree.h \ common/general-tree.c \ - common/dynamic-array.h \ common/tree.h \ common/base32hex.h \ common/evqueue.h \ @@ -844,14 +843,13 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/acl_tests.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/base32.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/base32hex.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/base64.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/changesets.Plo@am__quote@ @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)/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@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/da_tests.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ddns.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/debug.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/descriptor.Plo@am__quote@ @@ -862,7 +860,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dname_tests_realdata.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dthreads.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dthreads_tests.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dynamic-array.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/edns.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/edns_tests.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/edns_tests_realdata.Po@am__quote@ @@ -879,6 +876,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gatherer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/general-tree.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash-functions.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/heap.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/journal.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/journal_tests.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/knotc_main.Po@am__quote@ @@ -949,6 +947,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zcompile_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zlexer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zone-contents.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zone-diff.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zone-dump-text.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zone-dump.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zone-load.Plo@am__quote@ @@ -1005,13 +1004,6 @@ debug.lo: libknot/util/debug.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 debug.lo `test -f 'libknot/util/debug.c' || echo '$(srcdir)/'`libknot/util/debug.c -conv.lo: libknot/util/conv.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT conv.lo -MD -MP -MF $(DEPDIR)/conv.Tpo -c -o conv.lo `test -f 'libknot/util/conv.c' || echo '$(srcdir)/'`libknot/util/conv.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/conv.Tpo $(DEPDIR)/conv.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/util/conv.c' object='conv.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 conv.lo `test -f 'libknot/util/conv.c' || echo '$(srcdir)/'`libknot/util/conv.c - descriptor.lo: libknot/util/descriptor.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT descriptor.lo -MD -MP -MF $(DEPDIR)/descriptor.Tpo -c -o descriptor.lo `test -f 'libknot/util/descriptor.c' || echo '$(srcdir)/'`libknot/util/descriptor.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/descriptor.Tpo $(DEPDIR)/descriptor.Plo @@ -1089,6 +1081,13 @@ dname-table.lo: libknot/zone/dname-table.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 dname-table.lo `test -f 'libknot/zone/dname-table.c' || echo '$(srcdir)/'`libknot/zone/dname-table.c +zone-diff.lo: libknot/zone/zone-diff.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zone-diff.lo -MD -MP -MF $(DEPDIR)/zone-diff.Tpo -c -o zone-diff.lo `test -f 'libknot/zone/zone-diff.c' || echo '$(srcdir)/'`libknot/zone/zone-diff.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zone-diff.Tpo $(DEPDIR)/zone-diff.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='libknot/zone/zone-diff.c' object='zone-diff.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 zone-diff.lo `test -f 'libknot/zone/zone-diff.c' || echo '$(srcdir)/'`libknot/zone/zone-diff.c + hash-functions.lo: libknot/hash/hash-functions.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT hash-functions.lo -MD -MP -MF $(DEPDIR)/hash-functions.Tpo -c -o hash-functions.lo `test -f 'libknot/hash/hash-functions.c' || echo '$(srcdir)/'`libknot/hash/hash-functions.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/hash-functions.Tpo $(DEPDIR)/hash-functions.Plo @@ -1355,6 +1354,20 @@ base32.lo: common/base32.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 base32.lo `test -f 'common/base32.c' || echo '$(srcdir)/'`common/base32.c +base64.lo: common/base64.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT base64.lo -MD -MP -MF $(DEPDIR)/base64.Tpo -c -o base64.lo `test -f 'common/base64.c' || echo '$(srcdir)/'`common/base64.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/base64.Tpo $(DEPDIR)/base64.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/base64.c' object='base64.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 base64.lo `test -f 'common/base64.c' || echo '$(srcdir)/'`common/base64.c + +heap.lo: common/heap.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT heap.lo -MD -MP -MF $(DEPDIR)/heap.Tpo -c -o heap.lo `test -f 'common/heap.c' || echo '$(srcdir)/'`common/heap.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/heap.Tpo $(DEPDIR)/heap.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/heap.c' object='heap.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 heap.lo `test -f 'common/heap.c' || echo '$(srcdir)/'`common/heap.c + print.lo: common/print.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT print.lo -MD -MP -MF $(DEPDIR)/print.Tpo -c -o print.lo `test -f 'common/print.c' || echo '$(srcdir)/'`common/print.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/print.Tpo $(DEPDIR)/print.Plo @@ -1362,13 +1375,6 @@ print.lo: common/print.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 print.lo `test -f 'common/print.c' || echo '$(srcdir)/'`common/print.c -dynamic-array.lo: common/dynamic-array.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dynamic-array.lo -MD -MP -MF $(DEPDIR)/dynamic-array.Tpo -c -o dynamic-array.lo `test -f 'common/dynamic-array.c' || echo '$(srcdir)/'`common/dynamic-array.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/dynamic-array.Tpo $(DEPDIR)/dynamic-array.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/dynamic-array.c' object='dynamic-array.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 dynamic-array.lo `test -f 'common/dynamic-array.c' || echo '$(srcdir)/'`common/dynamic-array.c - skip-list.lo: common/skip-list.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT skip-list.lo -MD -MP -MF $(DEPDIR)/skip-list.Tpo -c -o skip-list.lo `test -f 'common/skip-list.c' || echo '$(srcdir)/'`common/skip-list.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/skip-list.Tpo $(DEPDIR)/skip-list.Plo @@ -1593,20 +1599,6 @@ acl_tests.obj: tests/common/acl_tests.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o acl_tests.obj `if test -f 'tests/common/acl_tests.c'; then $(CYGPATH_W) 'tests/common/acl_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/common/acl_tests.c'; fi` -da_tests.o: tests/common/da_tests.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT da_tests.o -MD -MP -MF $(DEPDIR)/da_tests.Tpo -c -o da_tests.o `test -f 'tests/common/da_tests.c' || echo '$(srcdir)/'`tests/common/da_tests.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/da_tests.Tpo $(DEPDIR)/da_tests.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/common/da_tests.c' object='da_tests.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o da_tests.o `test -f 'tests/common/da_tests.c' || echo '$(srcdir)/'`tests/common/da_tests.c - -da_tests.obj: tests/common/da_tests.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT da_tests.obj -MD -MP -MF $(DEPDIR)/da_tests.Tpo -c -o da_tests.obj `if test -f 'tests/common/da_tests.c'; then $(CYGPATH_W) 'tests/common/da_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/common/da_tests.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/da_tests.Tpo $(DEPDIR)/da_tests.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tests/common/da_tests.c' object='da_tests.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o da_tests.obj `if test -f 'tests/common/da_tests.c'; then $(CYGPATH_W) 'tests/common/da_tests.c'; else $(CYGPATH_W) '$(srcdir)/tests/common/da_tests.c'; fi` - events_tests.o: tests/common/events_tests.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT events_tests.o -MD -MP -MF $(DEPDIR)/events_tests.Tpo -c -o events_tests.o `test -f 'tests/common/events_tests.c' || echo '$(srcdir)/'`tests/common/events_tests.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/events_tests.Tpo $(DEPDIR)/events_tests.Po diff --git a/src/common/LICENSE.txt b/src/common/LICENSE.txt index 15e3bef..15e3bef 100644..100755 --- a/src/common/LICENSE.txt +++ b/src/common/LICENSE.txt diff --git a/src/common/acl.c b/src/common/acl.c index c8e0488..c8e0488 100644..100755 --- a/src/common/acl.c +++ b/src/common/acl.c diff --git a/src/common/acl.h b/src/common/acl.h index 7ce8f26..7ce8f26 100644..100755 --- a/src/common/acl.h +++ b/src/common/acl.h diff --git a/src/common/base32.c b/src/common/base32.c index 43b86c1..43b86c1 100644..100755 --- a/src/common/base32.c +++ b/src/common/base32.c diff --git a/src/common/base32.h b/src/common/base32.h index 45df9fa..45df9fa 100644..100755 --- a/src/common/base32.h +++ b/src/common/base32.h diff --git a/src/common/base32hex.c b/src/common/base32hex.c index cd2d2ce..cd2d2ce 100644..100755 --- a/src/common/base32hex.c +++ b/src/common/base32hex.c diff --git a/src/common/base32hex.h b/src/common/base32hex.h index 9ac4fa8..9ac4fa8 100644..100755 --- a/src/common/base32hex.h +++ b/src/common/base32hex.h diff --git a/src/common/base64.c b/src/common/base64.c new file mode 100755 index 0000000..f1f601c --- /dev/null +++ b/src/common/base64.c @@ -0,0 +1,574 @@ +/* base64.c -- Encode binary data using printable characters. + Copyright (C) 1999-2001, 2004-2006, 2009-2012 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1, 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. */ + +/* Written by Simon Josefsson. Partially adapted from GNU MailUtils + * (mailbox/filter_trans.c, as of 2004-11-28). Improved by review + * from Paul Eggert, Bruno Haible, and Stepan Kasal. + * + * See also RFC 4648 <http://www.ietf.org/rfc/rfc4648.txt>. + * + * Be careful with error checking. Here is how you would typically + * use these functions: + * + * bool ok = base64_decode_alloc (in, inlen, &out, &outlen); + * if (!ok) + * FAIL: input was not valid base64 + * if (out == NULL) + * FAIL: memory allocation error + * OK: data in OUT/OUTLEN + * + * size_t outlen = base64_encode_alloc (in, inlen, &out); + * if (out == NULL && outlen == 0 && inlen != 0) + * FAIL: input too long + * if (out == NULL) + * FAIL: memory allocation error + * OK: data in OUT/OUTLEN. + * + */ + +#include <config.h> + +/* Get prototype. */ +#include "base64.h" + +/* Get malloc. */ +#include <stdlib.h> + +/* Get UCHAR_MAX. */ +#include <limits.h> + +#include <string.h> + +/* C89 compliant way to cast 'char' to 'unsigned char'. */ +static inline unsigned char +to_uchar (char ch) +{ + return ch; +} + +/* Base64 encode IN array of size INLEN into OUT array of size OUTLEN. + If OUTLEN is less than BASE64_LENGTH(INLEN), write as many bytes as + possible. If OUTLEN is larger than BASE64_LENGTH(INLEN), also zero + terminate the output buffer. */ +void +base64_encode (const char *restrict in, size_t inlen, + char *restrict out, size_t outlen) +{ + static const char b64str[64] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + while (inlen && outlen) + { + *out++ = b64str[(to_uchar (in[0]) >> 2) & 0x3f]; + if (!--outlen) + break; + *out++ = b64str[((to_uchar (in[0]) << 4) + + (--inlen ? to_uchar (in[1]) >> 4 : 0)) + & 0x3f]; + if (!--outlen) + break; + *out++ = + (inlen + ? b64str[((to_uchar (in[1]) << 2) + + (--inlen ? to_uchar (in[2]) >> 6 : 0)) + & 0x3f] + : '='); + if (!--outlen) + break; + *out++ = inlen ? b64str[to_uchar (in[2]) & 0x3f] : '='; + if (!--outlen) + break; + if (inlen) + inlen--; + if (inlen) + in += 3; + } + + if (outlen) + *out = '\0'; +} + +/* Allocate a buffer and store zero terminated base64 encoded data + from array IN of size INLEN, returning BASE64_LENGTH(INLEN), i.e., + the length of the encoded data, excluding the terminating zero. On + return, the OUT variable will hold a pointer to newly allocated + memory that must be deallocated by the caller. If output string + length would overflow, 0 is returned and OUT is set to NULL. If + memory allocation failed, OUT is set to NULL, and the return value + indicates length of the requested memory block, i.e., + BASE64_LENGTH(inlen) + 1. */ +size_t +base64_encode_alloc (const char *in, size_t inlen, char **out) +{ + size_t outlen = 1 + BASE64_LENGTH (inlen); + + /* Check for overflow in outlen computation. + * + * If there is no overflow, outlen >= inlen. + * + * If the operation (inlen + 2) overflows then it yields at most +1, so + * outlen is 0. + * + * If the multiplication overflows, we lose at least half of the + * correct value, so the result is < ((inlen + 2) / 3) * 2, which is + * less than (inlen + 2) * 0.66667, which is less than inlen as soon as + * (inlen > 4). + */ + if (inlen > outlen) + { + *out = NULL; + return 0; + } + + *out = malloc (outlen); + if (!*out) + return outlen; + + base64_encode (in, inlen, *out, outlen); + + return outlen - 1; +} + +/* With this approach this file works independent of the charset used + (think EBCDIC). However, it does assume that the characters in the + Base64 alphabet (A-Za-z0-9+/) are encoded in 0..255. POSIX + 1003.1-2001 require that char and unsigned char are 8-bit + quantities, though, taking care of that problem. But this may be a + potential problem on non-POSIX C99 platforms. + + IBM C V6 for AIX mishandles "#define B64(x) ...'x'...", so use "_" + as the formal parameter rather than "x". */ +#define B64(_) \ + ((_) == 'A' ? 0 \ + : (_) == 'B' ? 1 \ + : (_) == 'C' ? 2 \ + : (_) == 'D' ? 3 \ + : (_) == 'E' ? 4 \ + : (_) == 'F' ? 5 \ + : (_) == 'G' ? 6 \ + : (_) == 'H' ? 7 \ + : (_) == 'I' ? 8 \ + : (_) == 'J' ? 9 \ + : (_) == 'K' ? 10 \ + : (_) == 'L' ? 11 \ + : (_) == 'M' ? 12 \ + : (_) == 'N' ? 13 \ + : (_) == 'O' ? 14 \ + : (_) == 'P' ? 15 \ + : (_) == 'Q' ? 16 \ + : (_) == 'R' ? 17 \ + : (_) == 'S' ? 18 \ + : (_) == 'T' ? 19 \ + : (_) == 'U' ? 20 \ + : (_) == 'V' ? 21 \ + : (_) == 'W' ? 22 \ + : (_) == 'X' ? 23 \ + : (_) == 'Y' ? 24 \ + : (_) == 'Z' ? 25 \ + : (_) == 'a' ? 26 \ + : (_) == 'b' ? 27 \ + : (_) == 'c' ? 28 \ + : (_) == 'd' ? 29 \ + : (_) == 'e' ? 30 \ + : (_) == 'f' ? 31 \ + : (_) == 'g' ? 32 \ + : (_) == 'h' ? 33 \ + : (_) == 'i' ? 34 \ + : (_) == 'j' ? 35 \ + : (_) == 'k' ? 36 \ + : (_) == 'l' ? 37 \ + : (_) == 'm' ? 38 \ + : (_) == 'n' ? 39 \ + : (_) == 'o' ? 40 \ + : (_) == 'p' ? 41 \ + : (_) == 'q' ? 42 \ + : (_) == 'r' ? 43 \ + : (_) == 's' ? 44 \ + : (_) == 't' ? 45 \ + : (_) == 'u' ? 46 \ + : (_) == 'v' ? 47 \ + : (_) == 'w' ? 48 \ + : (_) == 'x' ? 49 \ + : (_) == 'y' ? 50 \ + : (_) == 'z' ? 51 \ + : (_) == '0' ? 52 \ + : (_) == '1' ? 53 \ + : (_) == '2' ? 54 \ + : (_) == '3' ? 55 \ + : (_) == '4' ? 56 \ + : (_) == '5' ? 57 \ + : (_) == '6' ? 58 \ + : (_) == '7' ? 59 \ + : (_) == '8' ? 60 \ + : (_) == '9' ? 61 \ + : (_) == '+' ? 62 \ + : (_) == '/' ? 63 \ + : -1) + +static const signed char b64[0x100] = { + B64 (0), B64 (1), B64 (2), B64 (3), + B64 (4), B64 (5), B64 (6), B64 (7), + B64 (8), B64 (9), B64 (10), B64 (11), + B64 (12), B64 (13), B64 (14), B64 (15), + B64 (16), B64 (17), B64 (18), B64 (19), + B64 (20), B64 (21), B64 (22), B64 (23), + B64 (24), B64 (25), B64 (26), B64 (27), + B64 (28), B64 (29), B64 (30), B64 (31), + B64 (32), B64 (33), B64 (34), B64 (35), + B64 (36), B64 (37), B64 (38), B64 (39), + B64 (40), B64 (41), B64 (42), B64 (43), + B64 (44), B64 (45), B64 (46), B64 (47), + B64 (48), B64 (49), B64 (50), B64 (51), + B64 (52), B64 (53), B64 (54), B64 (55), + B64 (56), B64 (57), B64 (58), B64 (59), + B64 (60), B64 (61), B64 (62), B64 (63), + B64 (64), B64 (65), B64 (66), B64 (67), + B64 (68), B64 (69), B64 (70), B64 (71), + B64 (72), B64 (73), B64 (74), B64 (75), + B64 (76), B64 (77), B64 (78), B64 (79), + B64 (80), B64 (81), B64 (82), B64 (83), + B64 (84), B64 (85), B64 (86), B64 (87), + B64 (88), B64 (89), B64 (90), B64 (91), + B64 (92), B64 (93), B64 (94), B64 (95), + B64 (96), B64 (97), B64 (98), B64 (99), + B64 (100), B64 (101), B64 (102), B64 (103), + B64 (104), B64 (105), B64 (106), B64 (107), + B64 (108), B64 (109), B64 (110), B64 (111), + B64 (112), B64 (113), B64 (114), B64 (115), + B64 (116), B64 (117), B64 (118), B64 (119), + B64 (120), B64 (121), B64 (122), B64 (123), + B64 (124), B64 (125), B64 (126), B64 (127), + B64 (128), B64 (129), B64 (130), B64 (131), + B64 (132), B64 (133), B64 (134), B64 (135), + B64 (136), B64 (137), B64 (138), B64 (139), + B64 (140), B64 (141), B64 (142), B64 (143), + B64 (144), B64 (145), B64 (146), B64 (147), + B64 (148), B64 (149), B64 (150), B64 (151), + B64 (152), B64 (153), B64 (154), B64 (155), + B64 (156), B64 (157), B64 (158), B64 (159), + B64 (160), B64 (161), B64 (162), B64 (163), + B64 (164), B64 (165), B64 (166), B64 (167), + B64 (168), B64 (169), B64 (170), B64 (171), + B64 (172), B64 (173), B64 (174), B64 (175), + B64 (176), B64 (177), B64 (178), B64 (179), + B64 (180), B64 (181), B64 (182), B64 (183), + B64 (184), B64 (185), B64 (186), B64 (187), + B64 (188), B64 (189), B64 (190), B64 (191), + B64 (192), B64 (193), B64 (194), B64 (195), + B64 (196), B64 (197), B64 (198), B64 (199), + B64 (200), B64 (201), B64 (202), B64 (203), + B64 (204), B64 (205), B64 (206), B64 (207), + B64 (208), B64 (209), B64 (210), B64 (211), + B64 (212), B64 (213), B64 (214), B64 (215), + B64 (216), B64 (217), B64 (218), B64 (219), + B64 (220), B64 (221), B64 (222), B64 (223), + B64 (224), B64 (225), B64 (226), B64 (227), + B64 (228), B64 (229), B64 (230), B64 (231), + B64 (232), B64 (233), B64 (234), B64 (235), + B64 (236), B64 (237), B64 (238), B64 (239), + B64 (240), B64 (241), B64 (242), B64 (243), + B64 (244), B64 (245), B64 (246), B64 (247), + B64 (248), B64 (249), B64 (250), B64 (251), + B64 (252), B64 (253), B64 (254), B64 (255) +}; + +#if UCHAR_MAX == 255 +# define uchar_in_range(c) true +#else +# define uchar_in_range(c) ((c) <= 255) +#endif + +/* Return true if CH is a character from the Base64 alphabet, and + false otherwise. Note that '=' is padding and not considered to be + part of the alphabet. */ +bool +isbase64 (char ch) +{ + return uchar_in_range (to_uchar (ch)) && 0 <= b64[to_uchar (ch)]; +} + +/* Initialize decode-context buffer, CTX. */ +void +base64_decode_ctx_init (struct base64_decode_context *ctx) +{ + ctx->i = 0; +} + +/* If CTX->i is 0 or 4, there are four or more bytes in [*IN..IN_END), and + none of those four is a newline, then return *IN. Otherwise, copy up to + 4 - CTX->i non-newline bytes from that range into CTX->buf, starting at + index CTX->i and setting CTX->i to reflect the number of bytes copied, + and return CTX->buf. In either case, advance *IN to point to the byte + after the last one processed, and set *N_NON_NEWLINE to the number of + verified non-newline bytes accessible through the returned pointer. */ +static inline char * +get_4 (struct base64_decode_context *ctx, + char const *restrict *in, char const *restrict in_end, + size_t *n_non_newline) +{ + if (ctx->i == 4) + ctx->i = 0; + + if (ctx->i == 0) + { + char const *t = *in; + if (4 <= in_end - *in && memchr (t, '\n', 4) == NULL) + { + /* This is the common case: no newline. */ + *in += 4; + *n_non_newline = 4; + return (char *) t; + } + } + + { + /* Copy non-newline bytes into BUF. */ + char const *p = *in; + while (p < in_end) + { + char c = *p++; + if (c != '\n') + { + ctx->buf[ctx->i++] = c; + if (ctx->i == 4) + break; + } + } + + *in = p; + *n_non_newline = ctx->i; + return ctx->buf; + } +} + +#define return_false \ + do \ + { \ + *outp = out; \ + return false; \ + } \ + while (false) + +/* Decode up to four bytes of base64-encoded data, IN, of length INLEN + into the output buffer, *OUT, of size *OUTLEN bytes. Return true if + decoding is successful, false otherwise. If *OUTLEN is too small, + as many bytes as possible are written to *OUT. On return, advance + *OUT to point to the byte after the last one written, and decrement + *OUTLEN to reflect the number of bytes remaining in *OUT. */ +static inline bool +decode_4 (char const *restrict in, size_t inlen, + char *restrict *outp, size_t *outleft) +{ + char *out = *outp; + if (inlen < 2) + return false; + + if (!isbase64 (in[0]) || !isbase64 (in[1])) + return false; + + if (*outleft) + { + *out++ = ((b64[to_uchar (in[0])] << 2) + | (b64[to_uchar (in[1])] >> 4)); + --*outleft; + } + + if (inlen == 2) + return_false; + + if (in[2] == '=') + { + if (inlen != 4) + return_false; + + if (in[3] != '=') + return_false; + } + else + { + if (!isbase64 (in[2])) + return_false; + + if (*outleft) + { + *out++ = (((b64[to_uchar (in[1])] << 4) & 0xf0) + | (b64[to_uchar (in[2])] >> 2)); + --*outleft; + } + + if (inlen == 3) + return_false; + + if (in[3] == '=') + { + if (inlen != 4) + return_false; + } + else + { + if (!isbase64 (in[3])) + return_false; + + if (*outleft) + { + *out++ = (((b64[to_uchar (in[2])] << 6) & 0xc0) + | b64[to_uchar (in[3])]); + --*outleft; + } + } + } + + *outp = out; + return true; +} + +/* Decode base64-encoded input array IN of length INLEN to output array + OUT that can hold *OUTLEN bytes. The input data may be interspersed + with newlines. Return true if decoding was successful, i.e. if the + input was valid base64 data, false otherwise. If *OUTLEN is too + small, as many bytes as possible will be written to OUT. On return, + *OUTLEN holds the length of decoded bytes in OUT. Note that as soon + as any non-alphabet, non-newline character is encountered, decoding + is stopped and false is returned. If INLEN is zero, then process + only whatever data is stored in CTX. + + Initially, CTX must have been initialized via base64_decode_ctx_init. + Subsequent calls to this function must reuse whatever state is recorded + in that buffer. It is necessary for when a quadruple of base64 input + bytes spans two input buffers. + + If CTX is NULL then newlines are treated as garbage and the input + buffer is processed as a unit. */ + +bool +base64_decode_ctx (struct base64_decode_context *ctx, + const char *restrict in, size_t inlen, + char *restrict out, size_t *outlen) +{ + size_t outleft = *outlen; + bool ignore_newlines = ctx != NULL; + bool flush_ctx = false; + unsigned int ctx_i = 0; + + if (ignore_newlines) + { + ctx_i = ctx->i; + flush_ctx = inlen == 0; + } + + + while (true) + { + size_t outleft_save = outleft; + if (ctx_i == 0 && !flush_ctx) + { + while (true) + { + /* Save a copy of outleft, in case we need to re-parse this + block of four bytes. */ + outleft_save = outleft; + if (!decode_4 (in, inlen, &out, &outleft)) + break; + + in += 4; + inlen -= 4; + } + } + + if (inlen == 0 && !flush_ctx) + break; + + /* Handle the common case of 72-byte wrapped lines. + This also handles any other multiple-of-4-byte wrapping. */ + if (inlen && *in == '\n' && ignore_newlines) + { + ++in; + --inlen; + continue; + } + + /* Restore OUT and OUTLEFT. */ + out -= outleft_save - outleft; + outleft = outleft_save; + + { + char const *in_end = in + inlen; + char const *non_nl; + + if (ignore_newlines) + non_nl = get_4 (ctx, &in, in_end, &inlen); + else + non_nl = in; /* Might have nl in this case. */ + + /* If the input is empty or consists solely of newlines (0 non-newlines), + then we're done. Likewise if there are fewer than 4 bytes when not + flushing context and not treating newlines as garbage. */ + if (inlen == 0 || (inlen < 4 && !flush_ctx && ignore_newlines)) + { + inlen = 0; + break; + } + if (!decode_4 (non_nl, inlen, &out, &outleft)) + break; + + inlen = in_end - in; + } + } + + *outlen -= outleft; + + return inlen == 0; +} + +/* Allocate an output buffer in *OUT, and decode the base64 encoded + data stored in IN of size INLEN to the *OUT buffer. On return, the + size of the decoded data is stored in *OUTLEN. OUTLEN may be NULL, + if the caller is not interested in the decoded length. *OUT may be + NULL to indicate an out of memory error, in which case *OUTLEN + contains the size of the memory block needed. The function returns + true on successful decoding and memory allocation errors. (Use the + *OUT and *OUTLEN parameters to differentiate between successful + decoding and memory error.) The function returns false if the + input was invalid, in which case *OUT is NULL and *OUTLEN is + undefined. */ +bool +base64_decode_alloc_ctx (struct base64_decode_context *ctx, + const char *in, size_t inlen, char **out, + size_t *outlen) +{ + /* This may allocate a few bytes too many, depending on input, + but it's not worth the extra CPU time to compute the exact size. + The exact size is 3 * (inlen + (ctx ? ctx->i : 0)) / 4, minus 1 if the + input ends with "=" and minus another 1 if the input ends with "==". + Dividing before multiplying avoids the possibility of overflow. */ + size_t needlen = 3 * (inlen / 4) + 3; + + *out = malloc (needlen); + if (!*out) + return true; + + if (!base64_decode_ctx (ctx, in, inlen, *out, &needlen)) + { + free (*out); + *out = NULL; + return false; + } + + if (outlen) + *outlen = needlen; + + return true; +} diff --git a/src/common/base64.h b/src/common/base64.h new file mode 100755 index 0000000..aa0b696 --- /dev/null +++ b/src/common/base64.h @@ -0,0 +1,60 @@ +/* base64.h -- Encode binary data using printable characters. + Copyright (C) 2004-2006, 2009-2012 Free Software Foundation, Inc. + Written by Simon Josefsson. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1, 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. */ + +#ifndef BASE64_H +# define BASE64_H + +/* Get size_t. */ +# include <stddef.h> + +/* Get bool. */ +# include <stdbool.h> + +/* This uses that the expression (n+(k-1))/k means the smallest + integer >= n/k, i.e., the ceiling of n/k. */ +# define BASE64_LENGTH(inlen) ((((inlen) + 2) / 3) * 4) + +struct base64_decode_context +{ + unsigned int i; + char buf[4]; +}; + +extern bool isbase64 (char ch); + +extern void base64_encode (const char *restrict in, size_t inlen, + char *restrict out, size_t outlen); + +extern size_t base64_encode_alloc (const char *in, size_t inlen, char **out); + +extern void base64_decode_ctx_init (struct base64_decode_context *ctx); + +extern bool base64_decode_ctx (struct base64_decode_context *ctx, + const char *restrict in, size_t inlen, + char *restrict out, size_t *outlen); + +extern bool base64_decode_alloc_ctx (struct base64_decode_context *ctx, + const char *in, size_t inlen, + char **out, size_t *outlen); + +#define base64_decode(in, inlen, out, outlen) \ + base64_decode_ctx (NULL, in, inlen, out, outlen) + +#define base64_decode_alloc(in, inlen, out, outlen) \ + base64_decode_alloc_ctx (NULL, in, inlen, out, outlen) + +#endif /* BASE64_H */ diff --git a/src/common/crc.h b/src/common/crc.h index cf2e123..7d748be 100644..100755 --- a/src/common/crc.h +++ b/src/common/crc.h @@ -77,3 +77,5 @@ static inline crc_t crc_finalize(crc_t crc) #endif /* __CRC_H__ */ + +/*! @} */ diff --git a/src/common/dSFMT-params.h b/src/common/dSFMT-params.h index c779d8a..c779d8a 100644..100755 --- a/src/common/dSFMT-params.h +++ b/src/common/dSFMT-params.h diff --git a/src/common/dSFMT-params521.h b/src/common/dSFMT-params521.h index f771dc1..f771dc1 100644..100755 --- a/src/common/dSFMT-params521.h +++ b/src/common/dSFMT-params521.h diff --git a/src/common/dSFMT.c b/src/common/dSFMT.c index 090bb80..090bb80 100644..100755 --- a/src/common/dSFMT.c +++ b/src/common/dSFMT.c diff --git a/src/common/dSFMT.h b/src/common/dSFMT.h index f1aa9bd..f1aa9bd 100644..100755 --- a/src/common/dSFMT.h +++ b/src/common/dSFMT.h diff --git a/src/common/dynamic-array.c b/src/common/dynamic-array.c deleted file mode 100644 index 24f2aaa..0000000 --- a/src/common/dynamic-array.c +++ /dev/null @@ -1,225 +0,0 @@ -/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <config.h> -#include <pthread.h> -#include <assert.h> -#include <stdio.h> - -#include <urcu.h> - -//#include "common.h" -#include "common/dynamic-array.h" - -#ifndef ERR_ALLOC_FAILED -#define ERR_ALLOC_FAILED fprintf(stderr, "Allocation failed at %s:%d\n", \ - __FILE__, __LINE__) -#endif - -//#define DA_DEBUG - -#ifndef dbg_da -#ifdef DA_DEBUG -#define dbg_da(msg...) fprintf(stderr, msg) -#else -#define dbg_da(msg...) -#endif -#endif - -/*----------------------------------------------------------------------------*/ -/* Private functions */ -/*----------------------------------------------------------------------------*/ - -enum da_resize_type { - DA_LARGER, DA_SMALLER -}; - -typedef enum da_resize_type da_resize_type_t; - -/*----------------------------------------------------------------------------*/ -/*! - * \retval 1 On success. - * \retval -1 On failure. - */ -static int da_resize(da_array_t *array, da_resize_type_t type) -{ - dbg_da("da_resize(): array pointer: %p, items pointer: %p\n", array, - array->items); - - unsigned new_size = ((type == DA_LARGER) - ? (array->allocated *= 2) - : (array->allocated /= 2)); - - void *new_items = malloc(new_size * array->item_size); - if (new_items == NULL) { - ERR_ALLOC_FAILED; - return -1; - } - - dbg_da("Place for new items: %p\n", new_items); - - // copy the contents from the old array to the new - memcpy(new_items, array->items, array->count * array->item_size); - - // do RCU update - void *old_items = rcu_xchg_pointer(&array->items, new_items); - array->allocated = new_size; - - dbg_da("Old items pointer: %p\n", old_items); - - // wait for readers to finish - //synchronize_rcu(); - // deallocate the old array - dbg_da("RCU synchronized, deallocating old items array at address %p." - "\n", old_items); - free(old_items); - - return 1; -} - -/*----------------------------------------------------------------------------*/ -/* Public functions */ -/*----------------------------------------------------------------------------*/ - -da_array_t *da_create(unsigned count, size_t item_size) -{ - da_array_t *a = (da_array_t *)malloc(sizeof(da_array_t)); - if (a == NULL) { - ERR_ALLOC_FAILED; - return NULL; - } - da_initialize(a, count, item_size); - return a; -} - -/*----------------------------------------------------------------------------*/ - -int da_initialize(da_array_t *array, unsigned count, size_t item_size) -{ - assert(array != NULL); - pthread_mutex_init(&array->mtx, NULL); - pthread_mutex_lock(&array->mtx); - - array->items = malloc(count * item_size); - if (array->items == NULL) { - array->allocated = 0; - array->count = 0; - ERR_ALLOC_FAILED; - pthread_mutex_unlock(&array->mtx); - return -1; - } - - array->allocated = count; - array->count = 0; - array->item_size = item_size; - memset(array->items, 0, count * item_size); - - pthread_mutex_unlock(&array->mtx); - return 0; -} - -/*----------------------------------------------------------------------------*/ - -int da_reserve(da_array_t *array, unsigned count) -{ - pthread_mutex_lock(&array->mtx); - unsigned res = 0; - - assert(array->allocated >= array->count); - if ((array->allocated - array->count) >= count) { - dbg_da("Enough place in the array, no resize needed.\n"); - res = 0; - } else { - dbg_da("Resizing array.\n"); - res = da_resize(array, DA_LARGER); - } - pthread_mutex_unlock(&array->mtx); - - return res; -} - -/*----------------------------------------------------------------------------*/ - -int da_occupy(da_array_t *array, unsigned count) -{ - pthread_mutex_lock(&array->mtx); - unsigned res = 0; - assert(array->allocated >= array->count); - - if ((array->allocated - array->count) < count) { - dbg_da("Not enough place to occupy.\n"); - res = -1; - } else { - array->count += count; - } - - pthread_mutex_unlock(&array->mtx); - return res; -} - -/*----------------------------------------------------------------------------*/ - -unsigned da_try_reserve(const da_array_t *array, unsigned count) -{ - assert(array->allocated >= array->count); - if ((array->allocated - array->count) >= count) { - return 0; - } - - return 1; -} - -/*----------------------------------------------------------------------------*/ - -void da_release(da_array_t *array, unsigned count) -{ - pthread_mutex_lock(&array->mtx); - - assert(array->allocated >= array->count); - assert(array->count >= count); - dbg_da("Decreasing count of items in array.\n"); - array->count -= count; - - pthread_mutex_unlock(&array->mtx); -} - -/*----------------------------------------------------------------------------*/ - -void da_destroy(da_array_t *array) -{ - pthread_mutex_lock(&array->mtx); - void *old_items = rcu_dereference(array->items); - rcu_set_pointer(&array->items, NULL); - pthread_mutex_unlock(&array->mtx); - - //synchronize_rcu(); - free(old_items); - pthread_mutex_destroy(&array->mtx); -} - -/*----------------------------------------------------------------------------*/ - -void *da_get_items(const da_array_t *array) -{ - return array->items; -} - -/*----------------------------------------------------------------------------*/ - -unsigned da_get_count(const da_array_t *array) -{ - return array->count; -} diff --git a/src/common/dynamic-array.h b/src/common/dynamic-array.h deleted file mode 100644 index 77a5d13..0000000 --- a/src/common/dynamic-array.h +++ /dev/null @@ -1,156 +0,0 @@ -/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -/*! - * \file dynamic-array.h - * - * \author Lubos Slovak <lubos.slovak@nic.cz> - * - * \brief Safe dynamic array implementation. - * - * \todo Somehow check if the array is initialized and do not use otherwise. - * Maybe some magic, or so. - * \todo This structure is too slow because of the mutex. - * - * \addtogroup common_lib - * @{ - */ - -#ifndef _KNOTD_COMMON_DYNAMIC_ARRAY_H_ -#define _KNOTD_COMMON_DYNAMIC_ARRAY_H_ - -#include <string.h> -#include <pthread.h> - -/*----------------------------------------------------------------------------*/ -/*! - * \brief Dynamic array structure. - * - * Before using the dynamic array, it must be initialized using da_initialize(). - * When getting individual items always use da_get_items() to obtain pointer to - * the actual array. - * - * Items in the array cannot be dereferenced (it uses void * for storing the - * the items). It is needed to type-cast the item array (obtained by calling - * da_get_items()) to a proper type before dereferencing. - * - * When adding items, first reserve enough space for them by callling - * da_reserve() and subsequently tell the array about the inserted items by - * calling da_occupy(). When removing, the array must be told about the fact - * by calling da_release(). - * - * For getting the actual number of items in array use da_get_count(). - * - * When the array is no more needed, the da_destroy() function must be called - * before deallocating the structure. - */ -struct da_array { - /*! \brief The actual array. The items can't be dereferenced directly.*/ - void *items; - - /*! - * \brief Size of the stored items in bytes (used in counting of space - * needed. - */ - size_t item_size; - - /*! - * \brief Size of allocated space in number of items that can be stored. - */ - unsigned allocated; - - /*! \brief Number of items actually stored in the array. */ - unsigned count; - - /*! \brief Mutex. */ - pthread_mutex_t mtx; -}; - -typedef struct da_array da_array_t; - -/*----------------------------------------------------------------------------*/ -/*! - * \brief Creates and initializes the dynamic array. - * - * Initialization comprises of allocating place for \a count items of size - * \a item_size and setting the items to zeros. - * - * \retval 0 if successful. - * \retval -1 if not successful. - */ -da_array_t *da_create(unsigned count, size_t item_size); - -/*! - * \brief Initializes the dynamic array. - * - * Initialization comprises of allocating place for \a count items of size - * \a item_size and setting the items to zeros. - * - * \retval 0 if successful. - * \retval -1 if not successful. - */ -int da_initialize(da_array_t *array, unsigned count, size_t item_size); - -/*! - * \brief Reserves space for \a count more items. - * - * \retval 0 if successful and resizing was not necessary. - * \retval 1 if successful and the array was enlarged. - * \retval -1 if not successful - resizing was needed but could not be done. - */ -int da_reserve(da_array_t *array, unsigned count); - -/*! - * \brief Increases the number of items in array by \a count. - * - * \retval 0 If successful. - * \retval -1 If not successful (not enough allocated space, i.e. must run - * da_reserve()). - */ -int da_occupy(da_array_t *array, unsigned count); - -/*! - * \brief Tries to reserve space for \a count more items. - * - * \retval 0 if successful and resizing is not necessary. - * \retval 1 if successful but the array will need to be resized. - */ -unsigned da_try_reserve(const da_array_t *array, unsigned count); - -/*! - * \brief Releases space taken by \a count items. - */ -void da_release(da_array_t *array, unsigned count); - -/*! - * \brief Poperly deallocates the array. - */ -void da_destroy(da_array_t *array); - -/*! - * \brief Returns the array of items as a void *. - */ -void *da_get_items(const da_array_t *array); - -/*! - * \brief Returns count of items in the array. - */ -unsigned da_get_count(const da_array_t *array); - -/*----------------------------------------------------------------------------*/ - -#endif /* _KNOTD_COMMON_DYNAMIC_ARRAY_H_ */ - -/*! @} */ diff --git a/src/common/errors.c b/src/common/errors.c index 3b770e9..3b770e9 100644..100755 --- a/src/common/errors.c +++ b/src/common/errors.c diff --git a/src/common/errors.h b/src/common/errors.h index a2773ac..a2773ac 100644..100755 --- a/src/common/errors.h +++ b/src/common/errors.h diff --git a/src/common/evqueue.c b/src/common/evqueue.c index 7614111..240ced6 100644..100755 --- a/src/common/evqueue.c +++ b/src/common/evqueue.c @@ -126,8 +126,11 @@ void evqueue_free(evqueue_t **q) *q = 0; /* Deinitialize. */ - close(eq->fds[EVQUEUE_READFD]); - close(eq->fds[EVQUEUE_WRITEFD]); + for (int i = 0; i < 2; ++i) { + if (eq->fds[i] > -1) { + close(eq->fds[i]); + } + } free(eq); } diff --git a/src/common/evqueue.h b/src/common/evqueue.h index ffb3860..ffb3860 100644..100755 --- a/src/common/evqueue.h +++ b/src/common/evqueue.h diff --git a/src/common/evsched.c b/src/common/evsched.c index cc2cf7c..8b6f721 100644..100755 --- a/src/common/evsched.c +++ b/src/common/evsched.c @@ -26,6 +26,15 @@ #define OPENBSD_SLAB_BROKEN #endif +/* Heap only cares about x<y. */ +static int compare_event_heap_nodes(event_t **e1, event_t **e2) +{ + if (timercmp(&(*e1)->tv, &(*e2)->tv, <)) return -1; + if (timercmp(&(*e1)->tv, &(*e2)->tv, >)) return 1; + return 0; +} + + /*! * \brief Set event timer to T (now) + dt miliseconds. */ @@ -69,7 +78,7 @@ evsched_t *evsched_new() #ifndef OPENBSD_SLAB_BROKEN slab_cache_init(&s->cache.alloc, sizeof(event_t)); #endif - init_list(&s->calendar); + heap_init(&s->heap, sizeof(event_t *), compare_event_heap_nodes, 0, NULL); return s; } @@ -86,10 +95,16 @@ void evsched_delete(evsched_t **s) pthread_mutex_destroy(&(*s)->rl); pthread_mutex_destroy(&(*s)->mx); pthread_cond_destroy(&(*s)->notify); - node *n = 0, *nxt = 0; - WALK_LIST_DELSAFE(n, nxt, (*s)->calendar) { - evsched_event_free((*s), (event_t*)n); + + while (! EMPTY_HEAP(&(*s)->heap)) /* FIXME: Would be faster to simply walk through the array */ + { + event_t *e = *((event_t**)(HHEAD(&(*s)->heap))); + heap_delmin(&(*s)->heap); + evsched_event_free((*s), e); } + + free((*s)->heap.data); + (*s)->heap.data = NULL;; #ifndef OPENBSD_SLAB_BROKEN /* Free allocator. */ @@ -154,25 +169,26 @@ event_t* evsched_next(evsched_t *s) while(1) { /* Check event queue. */ - if (!EMPTY_LIST(s->calendar)) { + if (!EMPTY_HEAP(&s->heap)) { /* Get current time. */ struct timeval dt; gettimeofday(&dt, 0); /* Get next event. */ - event_t *next_ev = HEAD(s->calendar); + event_t *next_ev = *((event_t**)HHEAD(&s->heap)); /* Immediately return. */ if (timercmp(&dt, &next_ev->tv, >=)) { s->current = next_ev; - rem_node(&next_ev->n); + heap_delmin(&s->heap); pthread_mutex_unlock(&s->mx); pthread_mutex_lock(&s->rl); return next_ev; } /* Wait for next event or interrupt. Unlock calendar. */ + /* FIXME: Blocks this the possibility to add any event earlier? */ struct timespec ts; ts.tv_sec = next_ev->tv.tv_sec; ts.tv_nsec = next_ev->tv.tv_usec * 1000L; @@ -214,31 +230,12 @@ int evsched_schedule(evsched_t *s, event_t *ev, uint32_t dt) /* Update event timer. */ evsched_settimer(ev, dt); - + ev->parent = s; + /* Lock calendar. */ pthread_mutex_lock(&s->mx); - - /* Schedule event. */ - node *n = 0, *prev = 0; - if (!EMPTY_LIST(s->calendar)) { - WALK_LIST(n, s->calendar) { - event_t* cur = (event_t *)n; - if (timercmp(&cur->tv, &ev->tv, <)) { - prev = n; - } else { - break; - } - } - } - - /* Append to list. */ - ev->parent = s; - if (prev) { - insert_node(&ev->n, prev); - } else { - add_head(&s->calendar, &ev->n); - } - + + heap_insert(&s->heap, &ev); /* Unlock calendar. */ pthread_cond_signal(&s->notify); @@ -293,6 +290,8 @@ event_t* evsched_schedule_term(evsched_t *s, uint32_t dt) int evsched_cancel(evsched_t *s, event_t *ev) { + int found; + if (!s || !ev) { return -1; } @@ -303,19 +302,8 @@ int evsched_cancel(evsched_t *s, event_t *ev) /* Lock calendar. */ pthread_mutex_lock(&s->mx); - /* Find in list. */ - event_t *n = 0; - int found = 0; - WALK_LIST(n, s->calendar) { - if (n == ev) { - found = 1; - break; - } - } - - /* Remove from list. */ - if (found) { - rem_node(&ev->n); + if ((found = heap_find(&s->heap, &ev))) { + heap_delete(&s->heap, found); } /* Unlock calendar. */ diff --git a/src/common/evsched.h b/src/common/evsched.h index 8ca9c62..47bf672 100644..100755 --- a/src/common/evsched.h +++ b/src/common/evsched.h @@ -68,7 +68,7 @@ #include <pthread.h> #include "common/slab/slab.h" -#include "common/lists.h" +#include "common/heap.h" #include "common/evqueue.h" /*! @@ -92,7 +92,7 @@ typedef struct { event_t *current; /*!< Current running event. */ pthread_mutex_t mx; /*!< Event queue locking. */ pthread_cond_t notify; /*!< Event queue notification. */ - list calendar; /*!< Event calendar. */ + struct heap heap; struct { slab_cache_t alloc; /*!< Events SLAB cache. */ pthread_mutex_t lock; /*!< Events cache spin lock. */ diff --git a/src/common/fdset.c b/src/common/fdset.c index c915e01..c915e01 100644..100755 --- a/src/common/fdset.c +++ b/src/common/fdset.c diff --git a/src/common/fdset.h b/src/common/fdset.h index 4fbd9bc..4038083 100644..100755 --- a/src/common/fdset.h +++ b/src/common/fdset.h @@ -74,7 +74,7 @@ typedef struct fdset_it_t { /*! * \brief File descriptor set implementation backend. - * \notice Functions documentation following. + * \note Functions documentation following. * \internal */ struct fdset_backend_t diff --git a/src/common/fdset_epoll.c b/src/common/fdset_epoll.c index d4481b5..d4481b5 100644..100755 --- a/src/common/fdset_epoll.c +++ b/src/common/fdset_epoll.c diff --git a/src/common/fdset_epoll.h b/src/common/fdset_epoll.h index 58f25f8..58f25f8 100644..100755 --- a/src/common/fdset_epoll.h +++ b/src/common/fdset_epoll.h diff --git a/src/common/fdset_kqueue.c b/src/common/fdset_kqueue.c index 108c572..108c572 100644..100755 --- a/src/common/fdset_kqueue.c +++ b/src/common/fdset_kqueue.c diff --git a/src/common/fdset_kqueue.h b/src/common/fdset_kqueue.h index 4b650a7..4b650a7 100644..100755 --- a/src/common/fdset_kqueue.h +++ b/src/common/fdset_kqueue.h diff --git a/src/common/fdset_poll.c b/src/common/fdset_poll.c index 19804f5..9b1c135 100644..100755 --- a/src/common/fdset_poll.c +++ b/src/common/fdset_poll.c @@ -71,9 +71,10 @@ int fdset_poll_add(fdset_t *fdset, int fd, int events) } /* Append. */ - int nid = fdset->nfds++;; + int nid = fdset->nfds++; fdset->fds[nid].fd = fd; fdset->fds[nid].events = POLLIN; + fdset->fds[nid].revents = 0; return 0; } diff --git a/src/common/fdset_poll.h b/src/common/fdset_poll.h index 68e9e69..68e9e69 100644..100755 --- a/src/common/fdset_poll.h +++ b/src/common/fdset_poll.h diff --git a/src/common/general-tree.c b/src/common/general-tree.c index e1048e7..e1048e7 100644..100755 --- a/src/common/general-tree.c +++ b/src/common/general-tree.c diff --git a/src/common/general-tree.h b/src/common/general-tree.h index 552638a..552638a 100644..100755 --- a/src/common/general-tree.h +++ b/src/common/general-tree.h diff --git a/src/common/heap.c b/src/common/heap.c new file mode 100755 index 0000000..6fefb11 --- /dev/null +++ b/src/common/heap.c @@ -0,0 +1,149 @@ +/* + * Universal Heap Macros + * + * (c) 2012 Ondrej Filip <feela@network.cz> + * + * This software may be freely distributed and used according to the terms + * of the GNU Lesser General Public License. + */ + +/*** + * [[intro]] + * Introduction + * ------------ + * + * Binary heap is a simple data structure, which for example supports efficient insertions, deletions + * and access to the minimal inserted item. We define several macros for such operations. + * Note that because of simplicity of heaps, we have decided to define direct macros instead + * of a <<generic:,macro generator>> as for several other data structures in the Libucw. + * + * A heap is represented by a number of elements and by an array of values. Beware that we + * index this array from one, not from zero as do the standard C arrays. + * + * Most macros use these parameters: + * + * - @type - the type of elements + * - @num - a variable (signed or unsigned integer) with the number of elements + * - @heap - a C array of type @type; the heap is stored in `heap[1] .. heap[num]`; `heap[0]` is unused + * - @less - a callback to compare two element values; `less(x, y)` shall return a non-zero value iff @x is lower than @y + * - @swap - a callback to swap two array elements; `swap(heap, i, j, t)` must swap `heap[i]` with `heap[j]` with possible help of temporary variable @t (type @type). + * + * A valid heap must follow these rules: + * + * - `num >= 0` + * - `heap[i] >= heap[i / 2]` for each `i` in `[2, num]` + * + * The first element `heap[1]` is always lower or equal to all other elements. + * + * [[macros]] + * Macros + * ------ + ***/ + +#include "heap.h" +#include <string.h> +#include <stdlib.h> + +void _def_swap(struct heap *h, void *e1, void *e2) +{ + if (e1 == e2) return; + void *tmp = HTEMPELEMENT(h); + memcpy(tmp, e1, h->elm_size); + memcpy(e1, e2, h->elm_size); + memcpy(e2, tmp, h->elm_size); +} + + +int heap_init(struct heap *h, int elm_size, int (*cmp)(void *, void *), int init_size, void (*swap)(struct heap *, void *, void *)) +{ + int isize = init_size ? init_size : INITIAL_HEAP_SIZE; + + h->num = 0; + h->max_size = isize; + h->cmp = cmp; + h->swap = swap ? swap : _def_swap; + h->data = malloc((isize + 1) * elm_size); + h->elm_size = elm_size; + + return h->data ? 1 : 0; +}; + +static inline void _heap_bubble_down(struct heap *h, int e) +{ + int e1; + for (;;) + { + e1 = 2*e; + if(e1 > h->num) break; + if((h->cmp(HELEMENT(h, e),HELEMENT(h,e1)) < 0) && (e1 == h->num || (h->cmp(HELEMENT(h, e),HELEMENT(h,e1+1)) < 0))) break; + if((e1 != h->num) && (h->cmp(HELEMENT(h, e1+1), HELEMENT(h,e1)) < 0)) e1++; + h->swap(h,HELEMENT(h,e),HELEMENT(h,e1)); + e = e1; + } +} + +static inline void _heap_bubble_up(struct heap *h, int e) +{ + int e1; + while (e > 1) + { + e1 = e/2; + if(h->cmp(HELEMENT(h, e1),HELEMENT(h,e)) < 0) break; + h->swap(h,HELEMENT(h,e),HELEMENT(h,e1)); + e = e1; + } + +} + +void heap_delmin(struct heap *h) +{ + if(h->num == 0) return; + if(h->num > 1) + { + h->swap(h,HHEAD(h),HELEMENT(h,h->num)); + } + --h->num; + _heap_bubble_down(h, 1); +} + +int heap_insert(struct heap *h, void *e) +{ + if(h->num == h->max_size) + { + h->max_size = h->max_size * HEAP_INCREASE_STEP; + h->data = realloc(h->data, (h->max_size + 1) * h->elm_size); + } + + h->num++; + memcpy(HELEMENT(h,h->num),e,h->elm_size); + _heap_bubble_up(h,h->num); + + return h->data ? 1 :0 ; +} + +int heap_find(struct heap *h, void *elm) /* FIXME - very slow */ +{ + int i = h->num; + + while(i > 0) + { + if(h->cmp(HELEMENT(h, i),elm) == 0) break; + --i; + } + return i; +} + +void heap_delete(struct heap *h, int e) +{ + h->swap(h, HELEMENT(h, e), HELEMENT(h, h->num)); + h->num--; + if(h->cmp(HELEMENT(h, e), HELEMENT(h, h->num + 1)) < 0) _heap_bubble_up(h, e); + else _heap_bubble_down(h, e); + + if ((h->num > INITIAL_HEAP_SIZE) && (h->num < h->max_size / HEAP_DECREASE_THRESHOLD)) + { + h->max_size = h->max_size / HEAP_INCREASE_STEP; + h->data = realloc(h->data, (h->max_size + 1) * h->elm_size); + } +} + diff --git a/src/common/heap.h b/src/common/heap.h new file mode 100755 index 0000000..d6f8a0b --- /dev/null +++ b/src/common/heap.h @@ -0,0 +1,57 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file heap.h + * + * \author Ondrej Filip <ondrej.filip@nic.cz> + * + * \brief Universal heap support + * + * + * \addtogroup common_lib + * @{ + */ + +#ifndef _HEAP_H_ +#define _HEAP_H_ + +struct heap { + int num; /* Number of elements */ + int elm_size; /* Size of a single element */ + int max_size; /* Size of allocated memory */ + int (*cmp)(void *, void *); + void (*swap)(struct heap *, void *, void *); + void *data; +}; /* Array follows */ + +#define INITIAL_HEAP_SIZE 512 /* initial heap size */ +#define HEAP_INCREASE_STEP 2 /* multiplier for each inflation, keep conservative */ +#define HEAP_DECREASE_THRESHOLD 2 /* threshold for deflation, keep conservative */ +#define HTEMPELEMENT(h) ((h)->data) /* Pointer to tmp element (for swap) */ +#define HELEMENT(h,num) ((char*)(h)->data + (num) * (h)->elm_size) +#define HHEAD(h) HELEMENT((h),1) +#define EMPTY_HEAP(h) ((h)->num == 0) /* h->num == 0 */ + +int heap_init(struct heap *, int, int (*cmp)(), int, void (*swap)()); +void heap_delmin(struct heap *); +int heap_insert(struct heap *, void *); +int heap_find(struct heap *, void *); +void heap_delete(struct heap *, int); + + +#endif /* _HEAP_H_ */ + +/*! @} */ diff --git a/src/common/latency.c b/src/common/latency.c index a563f58..a563f58 100644..100755 --- a/src/common/latency.c +++ b/src/common/latency.c diff --git a/src/common/latency.h b/src/common/latency.h index d965c56..d965c56 100644..100755 --- a/src/common/latency.h +++ b/src/common/latency.h diff --git a/src/common/libtap/README b/src/common/libtap/README index d57b81d..d57b81d 100644..100755 --- a/src/common/libtap/README +++ b/src/common/libtap/README diff --git a/src/common/libtap/tap.c b/src/common/libtap/tap.c index d6bb995..d6bb995 100644..100755 --- a/src/common/libtap/tap.c +++ b/src/common/libtap/tap.c diff --git a/src/common/libtap/tap.h b/src/common/libtap/tap.h index 89484f4..89484f4 100644..100755 --- a/src/common/libtap/tap.h +++ b/src/common/libtap/tap.h diff --git a/src/common/libtap/tap_unit.h b/src/common/libtap/tap_unit.h index c248fde..c248fde 100644..100755 --- a/src/common/libtap/tap_unit.h +++ b/src/common/libtap/tap_unit.h diff --git a/src/common/lists.c b/src/common/lists.c index 9a93733..9a93733 100644..100755 --- a/src/common/lists.c +++ b/src/common/lists.c diff --git a/src/common/lists.h b/src/common/lists.h index 972ea49..897b1a9 100644..100755 --- a/src/common/lists.h +++ b/src/common/lists.h @@ -71,6 +71,7 @@ typedef struct list { /* In fact two overlayed nodes */ WALK_LIST_DELSAFE(n,nxt,list) { \ free(n); \ } \ + init_list(&list); \ } while(0) void add_tail(list *, node *); diff --git a/src/common/log.c b/src/common/log.c index c70f739..c70f739 100644..100755 --- a/src/common/log.c +++ b/src/common/log.c diff --git a/src/common/log.h b/src/common/log.h index 305020c..305020c 100644..100755 --- a/src/common/log.h +++ b/src/common/log.h diff --git a/src/common/mempattern.c b/src/common/mempattern.c index 5982e18..5982e18 100644..100755 --- a/src/common/mempattern.c +++ b/src/common/mempattern.c diff --git a/src/common/mempattern.h b/src/common/mempattern.h index ae1fa78..ae1fa78 100644..100755 --- a/src/common/mempattern.h +++ b/src/common/mempattern.h diff --git a/src/common/modified_tree.h b/src/common/modified_tree.h index 4c3e325..9ceddd1 100644..100755 --- a/src/common/modified_tree.h +++ b/src/common/modified_tree.h @@ -123,7 +123,7 @@ else if (cmp > 0) \ self->field.avl_right= MOD_TREE_INSERT_##node##_##field(self->field.avl_right, elm, compare, merge, merged); \ else if (merge) { \ - merge(&(elm->data), &(self->data)); \ + merge(&(self->data), &(elm->data)); \ *merged = 1; } \ else \ self->field.avl_right= MOD_TREE_INSERT_##node##_##field(self->field.avl_right, elm, compare, merge, merged); \ diff --git a/src/common/print.c b/src/common/print.c index 9764568..9764568 100644..100755 --- a/src/common/print.c +++ b/src/common/print.c diff --git a/src/common/print.h b/src/common/print.h index 482f55e..482f55e 100644..100755 --- a/src/common/print.h +++ b/src/common/print.h diff --git a/src/common/prng.c b/src/common/prng.c index 250a506..250a506 100644..100755 --- a/src/common/prng.c +++ b/src/common/prng.c diff --git a/src/common/prng.h b/src/common/prng.h index 9f17a78..a64eabb 100644..100755 --- a/src/common/prng.h +++ b/src/common/prng.h @@ -39,3 +39,5 @@ double tls_rand(); #endif //_KNOTD_ACL_H_ + +/*! @} */ diff --git a/src/common/ref.c b/src/common/ref.c index 3b9c033..3b9c033 100644..100755 --- a/src/common/ref.c +++ b/src/common/ref.c diff --git a/src/common/ref.h b/src/common/ref.h index 13a7037..13a7037 100644..100755 --- a/src/common/ref.h +++ b/src/common/ref.h diff --git a/src/common/skip-list.c b/src/common/skip-list.c index cde08d7..cde08d7 100644..100755 --- a/src/common/skip-list.c +++ b/src/common/skip-list.c diff --git a/src/common/skip-list.h b/src/common/skip-list.h index 784f366..784f366 100644..100755 --- a/src/common/skip-list.h +++ b/src/common/skip-list.h diff --git a/src/common/slab/alloc-common.h b/src/common/slab/alloc-common.h index 32878ab..32878ab 100644..100755 --- a/src/common/slab/alloc-common.h +++ b/src/common/slab/alloc-common.h diff --git a/src/common/slab/slab.c b/src/common/slab/slab.c index df30998..9a3e8de 100644..100755 --- a/src/common/slab/slab.c +++ b/src/common/slab/slab.c @@ -231,7 +231,7 @@ void __attribute__ ((destructor)) slab_deinit() * Cache helper functions. */ -/* \notice Not used right now. +/* \note Not used right now. static void slab_dump(slab_t* slab) { printf("%s: buffers (bufsize=%zuB, %u/%u free): \n", diff --git a/src/common/slab/slab.h b/src/common/slab/slab.h index 4ea7e31..4ea7e31 100644..100755 --- a/src/common/slab/slab.h +++ b/src/common/slab/slab.h diff --git a/src/common/sockaddr.c b/src/common/sockaddr.c index b4e75ee..b4e75ee 100644..100755 --- a/src/common/sockaddr.c +++ b/src/common/sockaddr.c diff --git a/src/common/sockaddr.h b/src/common/sockaddr.h index 52e621c..52e621c 100644..100755 --- a/src/common/sockaddr.h +++ b/src/common/sockaddr.h diff --git a/src/common/tree.h b/src/common/tree.h index efea65b..efea65b 100644..100755 --- a/src/common/tree.h +++ b/src/common/tree.h diff --git a/src/config.h.in b/src/config.h.in index bd88e96..b711d4f 100644..100755 --- a/src/config.h.in +++ b/src/config.h.in @@ -27,6 +27,15 @@ /* Define to 1 if you have the `clock_gettime' function. */ #undef HAVE_CLOCK_GETTIME +/* Define if FreeBSD-like cpuset_t exists. */ +#undef HAVE_CPUSET_BSD + +/* Define if Linux-like cpu_set_t exists. */ +#undef HAVE_CPUSET_LINUX + +/* Define if cpuset_t and cpuset(3) exists. */ +#undef HAVE_CPUSET_NETBSD + /* Define to 1 if you have the <dlfcn.h> header file. */ #undef HAVE_DLFCN_H @@ -105,6 +114,9 @@ /* Define to 1 if you have the `pselect' function. */ #undef HAVE_PSELECT +/* Define to 1 if you have the <pthread_np.h> header file. */ +#undef HAVE_PTHREAD_NP_H + /* Define to 1 if you have the `pthread_setaffinity_np' function. */ #undef HAVE_PTHREAD_SETAFFINITY_NP @@ -237,6 +249,9 @@ /* RR debug. */ #undef KNOT_RR_DEBUG +/* Hash table stash debug. */ +#undef KNOT_STASH_DEBUG + /* XFR debug. */ #undef KNOT_XFR_DEBUG diff --git a/src/knot.conf.5 b/src/knot.conf.5 new file mode 100755 index 0000000..d086860 --- /dev/null +++ b/src/knot.conf.5 @@ -0,0 +1,296 @@ +.TH "knot.conf" "5" "August 2012" "CZ.NIC Labs" "Knot DNS, version 1.1" +.SH "NAME" +.LP +.B knot.conf +\- Configuration file manual for Knot DNS server. +.SH "SYNOPSIS" +.LP +.B knot.conf +.SH "DESCRIPTION" +.B knot.conf +serves as an example of the configuration for knotc(8) and knotd(8). +.SH "EXAMPLE" +.LP +# This is a comment. + +# +# There are 4 main sections of this config file: +# system, zones, interfaces and log +# + +# Section 'system' contains general options for the server +system { + + # Identity of the server (see RFC 4892). Not used yet. + identity "I have no mouth and must scream"; + + # Version of the server (see RFC 4892). Not used yet. + version "0.1"; + + # Server identifier + # Use string format "text" + # Or hexstring 0x01ab00 + nsid "myserver0"; + + # Working directory of the server + # Used to store compiled zones and PID file + storage "/tmp/knot-sample"; + + # Custom pidfile path + # default: pidfile is created in 'storage'. + pidfile "/tmp/knot.pid"; + + # Number of workers per interface + # This option is used to force number of threads used per interface + # Default: unset (auto-estimates optimal value from the number of online CPUs) + workers 1; + + # User for running server + # May also specify user.group (f.e. knot.users) + user root; +} + +# Section 'keys' contains list of TSIG keys +keys { + + # TSIG key + # + # format: name key-type "<key>"; + # where key-type may be one of the following: + # hmac-md5 + # hmac-sha1 + # hmac-sha224 + # hmac-sha256 + # hmac-sha384 + # hmac-sha512 + # and <key> is the private key + key0.server0 hmac-md5 "Wg=="; + + # TSIG key for zone + key0.example.com hmac-md5 "==gW"; +} + +# Section 'interfaces' contains definitions of listening interfaces. +interfaces { + + # Interface entry + # + # Format 1: <name> { address <address>; [port <port>;] } + ipv4 { # <name> is an arbitrary symbolic name + address 127.0.0.1; # <address> may be ither IPv4 or IPv6 address + port 53531; # port is required for XFR/IN and NOTIFY/OUT + } + + # Format 2: <name> { address <address>@<port>; } + # shortipv4 { + # address 127.0.0.1@53532; + #} + + # Format 1 (IPv6 interface) + # ipv6 { + # address ::1@53533; + # } + + # Format 2 (IPv6 interface) + # ipv6b { + # address [::1]@53534; + # } + +} + +# Section 'remotes' contains symbolic names for remote servers. +# Syntax for 'remotes' is the same as for 'interfaces'. +remotes { + + # Remote entry + # + # Format 1: <name> { address <address>; [port <port>;] } + server0 { # <name> is an arbitrary symbolic name + address 127.0.0.1; # <address> may be ither IPv4 or IPv6 address + port 53531; # port is optional (default: 53) + key key0.server0; # (optional) specification of TSIG key associated for this remote + via ipv4; # (optional) source interface for queries + via 82.35.64.59; # (optional) source interface for queries, direct IPv4 + via [::cafe]; # (optional) source interface for queries, direct IPv6 + } + + # Format 2: <name> { address <address>@<port>; } + server1 { + address 127.0.0.1@53001; + } +} + +# Section 'zones' contains information about zones to be served. +zones { + + # Shared options for all listed zones + # + + # Build differences from zone file changes + # Possible values: on|off + # Default value: off + ixfr-from-differences off; + + # Enable semantic checks for all zones (if 'on') + # 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) + # Default value: 60 + notify-timeout 60; + + # Number of retries for NOTIFY + # Possible values: <1,...> + # Default value: 5 + notify-retries 5; + + # Timeout for syncing changes from zone database to zonefile + # Possible values: <1..INT_MAX> (seconds) + # Default value: 1h (1 hour) + # It is also possible to suffix with unit size [s/m/h/d] + # f.e. 1s = 1 day, 1m = 1 minute, 1h = 1 hour, 1d = 1 day + zonefile-sync 1h; + + # File size limit for IXFR journal + # Possible values: <1..INT_MAX> + # Default value: N/A (infinite) + # It is also possible to suffix with unit size [k/M/G] + # f.e. 1k, 100M, 2G + ixfr-fslimit 1G; + + # Zone entry + # + # Format: <zone-name> { file "<path-to-zone-file>"; } + example.com { # <zone-name> is the DNS name of the zone (zone root) + # <path-to-zone-file> may be either absolute or relative, in which case + # it is considered relative to the current directory from which the server + # was started. + file "samples/example.com.zone"; + + # Build differences from zone file changes + # Possible values: on|off + # Default value: off + ixfr-from-differences off; + + # 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 + semantic-checks on; + + # NOTIFY response timeout (specific for current zone) + # Possible values: <1,...> (seconds) + # Default value: 60 + notify-timeout 60; + + # Number of retries for NOTIFY (specific for current zone) + # Possible values: <1,...> + # Default value: 5 + notify-retries 5; + + # Timeout for syncing changes from zone database to zonefile + # Possible values: <1..INT_MAX> (seconds) + # Default value: inherited from zones.zonefile-sync + # It is also possible to suffix with unit size [s/m/h/d] + # f.e. 1s = 1 day, 1m = 1 minute, 1h = 1 hour, 1d = 1 day + zonefile-sync 1h; + + # XFR master server + xfr-in server0; + + # ACL list of XFR slaves + xfr-out server0, server1; + + # ACL list of servers allowed to send NOTIFY queries + notify-in server0; + + # List of servers to send NOTIFY to + notify-out server0, server1; + } +} + +# Section 'log' configures logging of server messages. +# +# Logging recognizes 3 symbolic names of log devices: +# stdout - Standard output +# stderr - Standard error output +# syslog - Syslog +# +# In addition, arbitrary number of log files may be specified (see below). +# +# Log messages are characterized by severity and category. +# Supported severities: +# debug - Debug messages. Must be turned on at compile time. +# info - Informational messages. +# notice - Notices and hints. +# warning - Warnings. An action from the operator may be required. +# error - Recoverable error. Some action should be taken. +# fatal - Non-recoverable errors resulting in server shutdown. +# (Not supported yet.) +# all - All severities. +# +# Categories designate the source of the log message and roughly correspond +# to server modules +# Supported categories: +# server - Messages related to general operation of the server. +# zone - Messages related to zones, zone parsing and loading. +# answering - Messages regarding query processing and response creation. +# any - All categories +# +# More severities (separated by commas) may be listed for each category. +# All applicable severities must be listed. +# (I.e. specifying 'error' severity does mean: 'log error messages', +# and NOT 'log all messages of severity error and above'.) +# +# Default settings (in case there are no entries in 'log' section or the section +# is missing at all): +# +# stderr { any error; } +# syslog { any error; } +log { + + # Log entry + # + # Format 1: + # <log> { + # <category1> <severity1> [, <severity2> ...]; + # <category2> <severity1> [, <severity2> ...]; + # ... + # } + syslog { # <log> is a symbolic name of a log device (see above) + # log errors of any category + any error; # for <category> and <severity> see above + # log also warnings and notices from category 'zone' + zone warning, notice; + # log info from server + server info; + } + + # Log fatal, warnings and errors to stderr + stderr { + any error, warning; + } + + # Format 2: + # file <path> { + # <category1> <severity1> [, <severity2> ...]; + # <category2> <severity1> [, <severity2> ...]; + # } + file "/tmp/knot-sample/knotd.debug" { # <path> is absolute or relative path to log file + server debug; + } +} +.SH "SEE ALSO" +.LP +knotd(8), knotc(8) diff --git a/src/knot.service b/src/knot.service index 36864d0..36864d0 100644..100755 --- a/src/knot.service +++ b/src/knot.service diff --git a/src/knot.spec b/src/knot.spec index 5856aab..5856aab 100644..100755 --- a/src/knot.spec +++ b/src/knot.spec diff --git a/src/knot.sysconfig b/src/knot.sysconfig index 99daeba..99daeba 100644..100755 --- a/src/knot.sysconfig +++ b/src/knot.sysconfig diff --git a/src/knot/common.h b/src/knot/common.h index c321b94..ddf24b1 100644..100755 --- a/src/knot/common.h +++ b/src/knot/common.h @@ -85,14 +85,6 @@ typedef unsigned int uint; /*!< \brief Unsigned. */ /*! \brief Eliminate compiler warning with unused parameters. */ #define UNUSED(param) (void)(param) -/*! \brief Type-safe minimum macro. */ -#define MIN(a, b) \ - ({ typeof (a) _a = (a); typeof (b) _b = (b); _a < _b ? _a : _b; }) - -/*! \brief Type-safe maximum macro. */ -#define MAX(a, b) \ - ({ typeof (a) _a = (a); typeof (b) _b = (b); _a > _b ? _a : _b; }) - /* Optimisation macros. */ #ifndef likely /*! \brief Optimize for x to be true value. */ diff --git a/src/knot/conf/cf-lex.l b/src/knot/conf/cf-lex.l index 16b0343..58d1f4b 100644..100755 --- a/src/knot/conf/cf-lex.l +++ b/src/knot/conf/cf-lex.l @@ -90,6 +90,7 @@ notify-out { lval.t = yytext; return NOTIFY_OUT; } workers { lval.t = yytext; return WORKERS; } user { lval.t = yytext; return USER; } pidfile { lval.t = yytext; return PIDFILE; } +ixfr-from-differences { lval.t = yytext; return BUILD_DIFFS; } interfaces { lval.t = yytext; return INTERFACES; } address { lval.t = yytext; return ADDRESS; } diff --git a/src/knot/conf/cf-parse.y b/src/knot/conf/cf-parse.y index b415662..69a5415 100644..100755 --- a/src/knot/conf/cf-parse.y +++ b/src/knot/conf/cf-parse.y @@ -172,6 +172,7 @@ static void conf_zone_start(void *scanner, char *name) { this_zone->ixfr_fslimit = -1; // Default policy applies this_zone->dbsync_timeout = -1; // Default policy applies this_zone->disable_any = -1; // Default policy applies + this_zone->build_diffs = -1; // Default policy applies // Append mising dot to ensure FQDN size_t nlen = strlen(name); @@ -266,6 +267,7 @@ static int conf_mask(void* scanner, int nval, int prefixlen) { %token <tok> XFR_OUT %token <tok> NOTIFY_IN %token <tok> NOTIFY_OUT +%token <tok> BUILD_DIFFS %token <tok> INTERFACES ADDRESS PORT %token <tok> IPA @@ -630,12 +632,31 @@ zone_acl: ; zone_start: - | TEXT { conf_zone_start(scanner, $1.t); } | USER { conf_zone_start(scanner, strdup($1.t)); } | REMOTES { conf_zone_start(scanner, strdup($1.t)); } | LOG_SRC { conf_zone_start(scanner, strdup($1.t)); } | LOG { conf_zone_start(scanner, strdup($1.t)); } | LOG_LEVEL { conf_zone_start(scanner, strdup($1.t)); } + | NUM '/' TEXT { + if ($1.i < 0 || $1.i > 255) { + char buf[256] = ""; + snprintf(buf, sizeof(buf), "rfc2317 origin prefix '%ld' out of bounds", $1.i); + cf_error(scanner, buf); + } + size_t len = 3 + 1 + strlen($3.t) + 1; /* <0,255> '/' rest */ + char *name = malloc(len * sizeof(char)); + if (name == NULL) { + cf_error(scanner, "out of memory"); + } else { + name[0] = '\0'; + if (snprintf(name, len, "%ld/%s", $1.i, $3.t) < 0) { + cf_error(scanner,"failed to convert rfc2317 origin to string"); + } + } + free($3.t); + conf_zone_start(scanner, name); + } + | TEXT { conf_zone_start(scanner, $1.t); } ; zone: @@ -643,6 +664,7 @@ zone: | zone zone_acl '}' | zone zone_acl_list | zone FILENAME TEXT ';' { this_zone->file = $3.t; } + | zone BUILD_DIFFS BOOL ';' { this_zone->build_diffs = $3.i; } | 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; } @@ -669,6 +691,7 @@ zones: ZONES '{' | zones zone '}' | zones DISABLE_ANY BOOL ';' { new_config->disable_any = $3.i; } + | zones BUILD_DIFFS BOOL ';' { new_config->build_diffs = $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 4bbf622..e0bd0ea 100644..100755 --- a/src/knot/conf/conf.c +++ b/src/knot/conf/conf.c @@ -73,74 +73,6 @@ void cf_error(void *scanner, const char *msg) _parser_res = KNOTD_EPARSEFAIL; } -/* - * Config helper functions. - */ - -/*! \brief Free TSIG key. */ -static void key_free(conf_key_t *k) -{ - /* Secure erase. */ - if (k->k.secret) { - memset(k->k.secret, 0, strlen(k->k.secret)); - } - free(k->k.secret); - knot_dname_free(&k->k.name); - free(k); -} - -/*! \brief Free config interfaces. */ -static void iface_free(conf_iface_t *iface) -{ - if (!iface) { - return; - } - - free(iface->name); - free(iface->address); - free(iface); -} - -/*! \brief Free config logs. */ -static void log_free(conf_log_t *log) -{ - if (!log) { - return; - } - - if (log->file) { - free(log->file); - } - - /* Free loglevel mapping. */ - node *n = 0, *nxt = 0; - WALK_LIST_DELSAFE(n, nxt, log->map) { - free((conf_log_map_t*)n); - } - - free(log); -} - -/*! \brief Free config zones. */ -static void zone_free(conf_zone_t *zone) -{ - if (!zone) { - return; - } - - /* Free ACL lists. */ - WALK_LIST_FREE(zone->acl.xfr_in); - WALK_LIST_FREE(zone->acl.xfr_out); - WALK_LIST_FREE(zone->acl.notify_in); - WALK_LIST_FREE(zone->acl.notify_out); - - free(zone->name); - free(zone->file); - free(zone->db); - free(zone->ixfr_db); - free(zone); -} - /*! * \brief Call config hooks that need updating. * @@ -214,6 +146,11 @@ static int conf_process(conf_t *conf) if (zone->dbsync_timeout < 0) { zone->dbsync_timeout = conf->dbsync_timeout; } + + // Default policy for ixfr-from-differences + if (zone->build_diffs < 0) { + zone->build_diffs = conf->build_diffs; + } // Default policy for semantic checks if (zone->enable_checks < 0) { @@ -286,7 +223,12 @@ static int conf_process(conf_t *conf) *dpos = '\0'; } + /* Copy origin and remove bad characters. */ memcpy(dpos, zone->name, zname_len + 1); + for (int i = 0; i < zname_len; ++i) { + if (dpos[i] == '/') dpos[i] = '_'; + } + memcpy(dpos + zname_len, "db", 3); zone->db = dest; @@ -299,16 +241,26 @@ static int conf_process(conf_t *conf) ret = KNOTD_ENOMEM; /* Error report. */ continue; } - strncpy(dest, conf->storage, stor_len + 1); + dpos = dest; + memcpy(dpos, conf->storage, stor_len + 1); + dpos += stor_len; if (conf->storage[stor_len - 1] != '/') { - strncat(dest, "/", 1); + *(dpos++) = '/'; + *dpos = '\0'; } const char *dbext = "diff.db"; - strncat(dest, zone->name, zname_len); - strncat(dest, dbext, strlen(dbext)); + memcpy(dpos, zone->name, zname_len + 1); + for (int i = 0; i < zname_len; ++i) { + if (dpos[i] == '/') dpos[i] = '_'; + } + memcpy(dpos + zname_len, dbext, strlen(dbext) + 1); zone->ixfr_db = dest; } + + /* Update UID and GID. */ + if (conf->uid < 0) conf->uid = getuid(); + if (conf->gid < 0) conf->gid = getgid(); return ret; } @@ -475,6 +427,7 @@ conf_t *conf_new(const char* path) c->ixfr_fslimit = -1; c->uid = -1; c->gid = -1; + c->build_diffs = 0; /* Disable by default. */ return c; } @@ -553,33 +506,33 @@ void conf_truncate(conf_t *conf, int unload_hooks) // Free keys WALK_LIST_DELSAFE(n, nxt, conf->keys) { - key_free((conf_key_t *)n); + conf_free_key((conf_key_t *)n); } // Free interfaces WALK_LIST_DELSAFE(n, nxt, conf->ifaces) { - iface_free((conf_iface_t*)n); + conf_free_iface((conf_iface_t*)n); } conf->ifaces_count = 0; init_list(&conf->ifaces); // Free logs WALK_LIST_DELSAFE(n, nxt, conf->logs) { - log_free((conf_log_t*)n); + conf_free_log((conf_log_t*)n); } conf->logs_count = 0; init_list(&conf->logs); // Free remotes WALK_LIST_DELSAFE(n, nxt, conf->remotes) { - iface_free((conf_iface_t*)n); + conf_free_iface((conf_iface_t*)n); } conf->remotes_count = 0; init_list(&conf->remotes); // Free zones WALK_LIST_DELSAFE(n, nxt, conf->zones) { - zone_free((conf_zone_t*)n); + conf_free_zone((conf_zone_t*)n); } conf->zones_count = 0; init_list(&conf->zones); @@ -784,3 +737,63 @@ char* strcpath(char *path) return path; } +void conf_free_zone(conf_zone_t *zone) +{ + if (!zone) { + return; + } + + /* Free ACL lists. */ + WALK_LIST_FREE(zone->acl.xfr_in); + WALK_LIST_FREE(zone->acl.xfr_out); + WALK_LIST_FREE(zone->acl.notify_in); + WALK_LIST_FREE(zone->acl.notify_out); + + free(zone->name); + free(zone->file); + free(zone->db); + free(zone->ixfr_db); + free(zone); +} + +void conf_free_key(conf_key_t *k) +{ + /* Secure erase. */ + if (k->k.secret) { + memset(k->k.secret, 0, strlen(k->k.secret)); + } + free(k->k.secret); + knot_dname_free(&k->k.name); + free(k); +} + +void conf_free_iface(conf_iface_t *iface) +{ + if (!iface) { + return; + } + + free(iface->name); + free(iface->address); + free(iface); +} + +void conf_free_log(conf_log_t *log) +{ + if (!log) { + return; + } + + if (log->file) { + free(log->file); + } + + /* Free loglevel mapping. */ + node *n = 0, *nxt = 0; + WALK_LIST_DELSAFE(n, nxt, log->map) { + free((conf_log_map_t*)n); + } + + free(log); +} + diff --git a/src/knot/conf/conf.h b/src/knot/conf/conf.h index 7e1b61f..ae41454 100644..100755 --- a/src/knot/conf/conf.h +++ b/src/knot/conf/conf.h @@ -96,6 +96,7 @@ typedef struct conf_zone_t { int disable_any; /*!< Disable ANY type queries for AA.*/ int notify_retries; /*!< NOTIFY query retries. */ int notify_timeout; /*!< Timeout for NOTIFY response (s). */ + int build_diffs; /*!< Calculate differences from changes. */ struct { list xfr_in; /*!< Remotes accepted for for xfr-in.*/ list xfr_out; /*!< Remotes accepted for xfr-out.*/ @@ -197,6 +198,7 @@ typedef struct conf_t { int notify_timeout; /*!< Timeout for NOTIFY response in seconds. */ int dbsync_timeout; /*!< Default interval between syncing to zonefile.*/ size_t ixfr_fslimit; /*!< File size limit for IXFR journal. */ + int build_diffs; /*!< Calculate differences from changes. */ /* * Implementation specifics @@ -323,22 +325,6 @@ static inline conf_t* conf() { return s_config; // Inline for performance reasons. } -/*! - * \brief Lock configuration for reading. - * - * \return Configuration context. - */ -static inline void conf_read_lock() { - rcu_read_lock(); -} - -/*! - * \brief Unlock configuration for reading. - */ -static inline void conf_read_unlock() { - rcu_read_unlock(); -} - /* * Utilities. */ @@ -363,6 +349,18 @@ char* strcdup(const char *s1, const char *s2); */ char* strcpath(char *path); +/*! \brief Free zone config. */ +void conf_free_zone(conf_zone_t *zone); + +/*! \brief Free TSIG key config. */ +void conf_free_key(conf_key_t *k); + +/*! \brief Free interface config. */ +void conf_free_iface(conf_iface_t *iface); + +/*! \brief Free log config. */ +void conf_free_log(conf_log_t *log); + #endif /* _KNOTD_CONF_H_ */ /*! @} */ diff --git a/src/knot/conf/logconf.c b/src/knot/conf/logconf.c index 4d7334f..4d7334f 100644..100755 --- a/src/knot/conf/logconf.c +++ b/src/knot/conf/logconf.c diff --git a/src/knot/conf/logconf.h b/src/knot/conf/logconf.h index 7b9e054..7b9e054 100644..100755 --- a/src/knot/conf/logconf.h +++ b/src/knot/conf/logconf.h diff --git a/src/knot/ctl/knotc_main.c b/src/knot/ctl/knotc_main.c index 97412dd..07a9e38 100644..100755 --- a/src/knot/ctl/knotc_main.c +++ b/src/knot/ctl/knotc_main.c @@ -43,7 +43,8 @@ enum knotc_flag_t { F_VERBOSE = 1 << 1, F_WAIT = 1 << 2, F_INTERACTIVE = 1 << 3, - F_AUTO = 1 << 4 + F_AUTO = 1 << 4, + F_UNPRIVILEGED= 1 << 5 }; static inline unsigned has_flag(unsigned flags, enum knotc_flag_t f) { @@ -55,9 +56,9 @@ void help(int argc, char **argv) { printf("Usage: %sc [parameters] start|stop|restart|reload|running|" "compile [additional]\n", PACKAGE_NAME); - printf("Parameters:\n" + printf("\nParameters:\n" " -c [file], --config=[file] Select configuration file.\n" - " -j [num], --jobs=[num] Number of parallel tasks to run (only for 'compile').\n" + " -j [num], --jobs=[num] Number of parallel tasks to run when compiling.\n" " -f, --force Force operation - override some checks.\n" " -v, --verbose Verbose mode - additional runtime information.\n" " -V, --version Print %s server version.\n" @@ -66,7 +67,7 @@ void help(int argc, char **argv) " -a, --auto Enable automatic recompilation (start or reload).\n" " -h, --help Print help and usage.\n", PACKAGE_NAME); - printf("Actions:\n" + printf("\nActions:\n" " start Start %s server zone (no-op if running).\n" " stop Stop %s server (no-op if not running).\n" " restart Stops and then starts %s server.\n" @@ -75,8 +76,8 @@ void help(int argc, char **argv) " running Check if server is running.\n" " checkconf Check server configuration.\n" "\n" - " checkzone Check zones (accepts specific zones, f.e. " - "'knotc checkzone example1.com example2.com').\n" + " checkzone Check zones (accepts specific zones, \n" + " e.g. 'knotc checkzone example1.com example2.com').\n" " compile Compile zones (accepts specific zones, see above).\n", PACKAGE_NAME, PACKAGE_NAME, PACKAGE_NAME, PACKAGE_NAME); } @@ -142,10 +143,15 @@ pid_t wait_cmd(pid_t proc, int *rc) return proc; } -pid_t start_cmd(const char *argv[], int argc) +pid_t start_cmd(const char *argv[], int argc, int flags) { pid_t chproc = fork(); if (chproc == 0) { + + /* Alter privileges. */ + if (flags & F_UNPRIVILEGED) { + proc_update_privileges(conf()->uid, conf()->gid); + } /* Duplicate, it doesn't run from stack address anyway. */ char **args = malloc((argc + 1) * sizeof(char*)); @@ -180,7 +186,7 @@ pid_t start_cmd(const char *argv[], int argc) int exec_cmd(const char *argv[], int argc) { int ret = 0; - pid_t proc = start_cmd(argv, argc); + pid_t proc = start_cmd(argv, argc, 0); wait_cmd(proc, &ret); return ret; } @@ -292,15 +298,7 @@ int execute(const char *action, char **argv, int argc, pid_t pid, int rc = 0; if (strcmp(action, "start") == 0) { // Check pidfile for w+ - FILE* chkf = fopen(pidfile, "w+"); - if (chkf == NULL) { - log_server_error("PID file '%s' is not writeable, " - "refusing to start\n", pidfile); - return 1; - } else { - fclose(chkf); - chkf = NULL; - } + log_server_info("Starting server...\n"); // Check PID valid_cmd = 1; @@ -332,7 +330,7 @@ int execute(const char *action, char **argv, int argc, pid_t pid, } // Lock configuration - conf_read_lock(); + rcu_read_lock(); // Prepare command const char *cfg = conf()->filename; @@ -346,7 +344,7 @@ int execute(const char *action, char **argv, int argc, pid_t pid, }; // Unlock configuration - conf_read_unlock(); + rcu_read_unlock(); // Execute command if (has_flag(flags, F_INTERACTIVE)) { @@ -381,6 +379,7 @@ int execute(const char *action, char **argv, int argc, pid_t pid, if (strcmp(action, "stop") == 0) { // Check PID + log_server_info("Stopping server...\n"); valid_cmd = 1; rc = 0; if (pid <= 0 || !pid_running(pid)) { @@ -440,7 +439,6 @@ int execute(const char *action, char **argv, int argc, pid_t pid, } } - log_server_info("Restarting server.\n"); rc = execute("start", argv, argc, -1, flags, jobs, pidfile); } if (strcmp(action, "reload") == 0) { @@ -527,7 +525,7 @@ int execute(const char *action, char **argv, int argc, pid_t pid, valid_cmd = 1; // Lock configuration - conf_read_lock(); + rcu_read_lock(); // Generate databases for all zones node *n = 0; @@ -604,7 +602,7 @@ int execute(const char *action, char **argv, int argc, pid_t pid, } fflush(stdout); fflush(stderr); - pid_t zcpid = start_cmd(args, ac); + pid_t zcpid = start_cmd(args, ac, F_UNPRIVILEGED); zctask_add(tasks, jobs, zcpid, zone); ++running; } @@ -617,7 +615,7 @@ int execute(const char *action, char **argv, int argc, pid_t pid, free(tasks); // Unlock configuration - conf_read_unlock(); + rcu_read_unlock(); } if (!valid_cmd) { log_server_error("Invalid command: '%s'\n", action); @@ -707,7 +705,7 @@ int main(int argc, char **argv) log_server_error("Couldn't open configuration file " "'%s'.\n", config_fn); } else { - log_server_error("Failed to parse configuration '%s'.\n", + log_server_error("Failed to load configuration '%s'.\n", config_fn); } free(default_fn); @@ -722,7 +720,7 @@ int main(int argc, char **argv) log_levels_add(LOGT_STDOUT, LOG_ANY, LOG_MASK(LOG_INFO)|LOG_MASK(LOG_DEBUG)); } - + // Fetch PID char* pidfile = pid_filename(); if (!pidfile) { diff --git a/src/knot/ctl/process.c b/src/knot/ctl/process.c index bb61804..d3fa2fc 100644..100755 --- a/src/knot/ctl/process.c +++ b/src/knot/ctl/process.c @@ -21,6 +21,9 @@ #include <errno.h> #include <string.h> #include <signal.h> +#include <grp.h> +#include <unistd.h> +#include <assert.h> #include "knot/common.h" #include "knot/ctl/process.h" @@ -29,7 +32,7 @@ char* pid_filename() { - conf_read_lock(); + rcu_read_lock(); /* Read configuration. */ char* ret = 0; @@ -37,7 +40,7 @@ char* pid_filename() ret = strdup(conf()->pidfile); } - conf_read_unlock(); + rcu_read_unlock(); return ret; } @@ -113,6 +116,7 @@ int pid_write(const char* fn) int pid_remove(const char* fn) { if (unlink(fn) < 0) { + perror("unlink"); return KNOTD_EINVAL; } @@ -124,3 +128,45 @@ int pid_running(pid_t pid) return kill(pid, 0) == 0; } +void proc_update_privileges(int uid, int gid) +{ +#ifdef HAVE_SETGROUPS + /* Drop supplementary groups. */ + if (uid != getuid() || gid != getgid()) { + if (setgroups(0, NULL) < 0) { + log_server_warning("Failed to drop supplementary groups" + " for uid '%d' (%s).\n", + getuid(), strerror(errno)); + } + } +#endif + + /* Watch uid/gid. */ + if (gid != getgid()) { + log_server_info("Changing group id to '%d'.\n", gid); + if (setregid(gid, gid) < 0) { + log_server_error("Failed to change gid to '%d'.\n", + gid); + } + } + if (uid != getuid()) { + log_server_info("Changing user id to '%d'.\n", uid); + if (setreuid(uid, uid) < 0) { + log_server_error("Failed to change uid to '%d'.\n", + uid); + } + } + + /* Check storage writeability. */ + char *lfile = strcdup(conf()->storage, "/knot.lock"); + assert(lfile != NULL); + FILE* fp = fopen(lfile, "w"); + if (fp == NULL) { + log_server_warning("Storage directory '%s' is not writeable.\n", + conf()->storage); + } else { + fclose(fp); + unlink(lfile); + } + free(lfile); +} diff --git a/src/knot/ctl/process.h b/src/knot/ctl/process.h index d8f2f4c..a387add 100644..100755 --- a/src/knot/ctl/process.h +++ b/src/knot/ctl/process.h @@ -83,6 +83,15 @@ int pid_remove(const char* fn); */ int pid_running(pid_t pid); +/*! + * \brief Update process privileges to new UID/GID. + * + * \param uid New user ID. + * \param gid New group ID. + * + */ +void proc_update_privileges(int uid, int gid); + #endif // _KNOTD_PROCESS_H_ /*! @} */ diff --git a/src/knot/main.c b/src/knot/main.c index 99ee1cf..4486a1c 100644..100755 --- a/src/knot/main.c +++ b/src/knot/main.c @@ -20,6 +20,7 @@ #include <unistd.h> #include <getopt.h> #include <limits.h> + #ifdef HAVE_CAP_NG_H #include <cap-ng.h> #endif /* HAVE_CAP_NG_H */ @@ -72,7 +73,7 @@ void help(int argc, char **argv) { printf("Usage: %sd [parameters]\n", PACKAGE_NAME); - printf("Parameters:\n" + printf("\nParameters:\n" " -c, --config [file] Select configuration file.\n" " -d, --daemonize Run server as a daemon.\n" " -v, --verbose Verbose mode - additional runtime information.\n" @@ -138,6 +139,7 @@ int main(int argc, char **argv) emptyset.sa_flags = 0; sigaction(SIGALRM, &emptyset, NULL); // Interrupt sigaction(SIGPIPE, &emptyset, NULL); // Mask + rcu_register_thread(); // Setup event queue evqueue_set(evqueue_new()); @@ -158,11 +160,10 @@ int main(int argc, char **argv) server_t *server = server_create(); // Initialize configuration - conf_read_lock(); + rcu_read_lock(); conf_add_hook(conf(), CONF_LOG, log_conf_hook, 0); conf_add_hook(conf(), CONF_ALL, server_conf_hook, server); - conf_add_hook(conf(), CONF_ALL, zones_ns_conf_hook, server->nameserver); - conf_read_unlock(); + rcu_read_unlock(); // Find implicit configuration file if (!config_fn) { @@ -229,7 +230,7 @@ int main(int argc, char **argv) log_server_error("Couldn't open configuration file " "'%s'.\n", config_fn); } else { - log_server_error("Failed to parse configuration '%s'.\n", + log_server_error("Failed to load configuration '%s'.\n", config_fn); } server_wait(server); @@ -242,21 +243,28 @@ int main(int argc, char **argv) } log_server_info("\n"); - // Create server instance - char* pidfile = pid_filename(); + /* Alter privileges. */ + proc_update_privileges(conf()->uid, conf()->gid); + + /* Load zones and add hook. */ + zones_ns_conf_hook(conf(), server->nameserver); + conf_add_hook(conf(), CONF_ALL, zones_ns_conf_hook, server->nameserver); // Run server int res = 0; + int has_pid = 0; + char* pidfile = pid_filename(); log_server_info("Starting server...\n"); if ((server_start(server)) == KNOTD_EOK) { // Save PID - int has_pid = 1; + has_pid = 1; int rc = pid_write(pidfile); if (rc < 0) { has_pid = 0; log_server_warning("Failed to create " - "PID file '%s'.\n", pidfile); + "PID file '%s' (%s).\n", + pidfile, strerror(errno)); } // Change directory if daemonized @@ -370,7 +378,7 @@ int main(int argc, char **argv) server_destroy(&server); // Remove PID file - if (pid_remove(pidfile) < 0) { + if (has_pid && pid_remove(pidfile) < 0) { log_server_warning("Failed to remove PID file.\n"); } @@ -381,6 +389,8 @@ int main(int argc, char **argv) // Destroy event loop evqueue_t *q = evqueue(); evqueue_free(&q); + + rcu_unregister_thread(); // Free default config filename if exists free(config_fn); diff --git a/src/knot/other/debug.h b/src/knot/other/debug.h index 1a8698e..1a8698e 100644..100755 --- a/src/knot/other/debug.h +++ b/src/knot/other/debug.h diff --git a/src/knot/other/error.c b/src/knot/other/error.c index 70c84a3..7f005e7 100644..100755 --- a/src/knot/other/error.c +++ b/src/knot/other/error.c @@ -41,6 +41,8 @@ const error_table_t knotd_error_msgs[] = { {KNOTD_ENOIPV6, "IPv6 support disabled."}, {KNOTD_EMALF, "Malformed data."}, {KNOTD_ESPACE, "Not enough space provided."}, - {KNOTD_EEXPIRED, "Resource is expired."}, + {KNOTD_EEXPIRED, "Resource is expired."}, + {KNOTD_ENODIFF, "Cannot create zone diff."}, + {KNOTD_EUPTODATE, "Zone is up-to-date."}, {KNOTD_ERROR, 0} }; diff --git a/src/knot/other/error.h b/src/knot/other/error.h index 65c51cf..4b9efee 100644..100755 --- a/src/knot/other/error.h +++ b/src/knot/other/error.h @@ -63,8 +63,10 @@ enum knot_error_t { KNOTD_EMALF, /*!< \brief Malformed data. */ KNOTD_ESPACE, /*!< \brief Not enough space provided. */ KNOTD_EEXPIRED, /*!< \brief Resource is expired. */ + KNOTD_ENODIFF, /*!< \brief Cannot create zone diff. */ + KNOTD_EUPTODATE, /*!< \brief Zone is up-to-date. */ - KNOTD_ERROR_COUNT = 21 + KNOTD_ERROR_COUNT = 23 }; /*! \brief Table linking error messages to error codes. */ diff --git a/src/knot/server/dthreads.c b/src/knot/server/dthreads.c index e2b45f2..0c38cfc 100644..100755 --- a/src/knot/server/dthreads.c +++ b/src/knot/server/dthreads.c @@ -21,15 +21,25 @@ #include <stdio.h> #include <unistd.h> #include <errno.h> +#include <urcu.h> + #ifdef HAVE_CAP_NG_H #include <cap-ng.h> #endif /* HAVE_CAP_NG_H */ +#ifdef HAVE_PTHREAD_NP_H +#include <pthread_np.h> +#endif /* HAVE_PTHREAD_NP_H */ #include "knot/common.h" #include "knot/server/dthreads.h" #include "common/log.h" #include "knot/other/error.h" +/* BSD cpu set compatibility. */ +#if defined(HAVE_CPUSET_BSD) +typedef cpuset_t cpu_set_t; +#endif + /*! \brief Lock thread state for R/W. */ static inline void lock_thread_rw(dthread_t *thread) { @@ -126,6 +136,7 @@ static void *thread_ep(void *data) sigaddset(&ignset, SIGPIPE); sigaddset(&ignset, SIGUSR1); pthread_sigmask(SIG_BLOCK, &ignset, 0); /*! \todo Review under BSD (issue #1441). */ + rcu_register_thread(); dbg_dt("dthreads: [%p] entered ep\n", thread); @@ -207,6 +218,7 @@ static void *thread_ep(void *data) lock_thread_rw(thread); thread->state |= ThreadJoinable; unlock_thread_rw(thread); + rcu_unregister_thread(); // Return return 0; @@ -854,22 +866,44 @@ int dt_stop(dt_unit_t *unit) // return KNOTD_EOK; //} -int dt_setaffinity(dthread_t *thread, void *mask, size_t len) + + +int dt_setaffinity(dthread_t *thread, unsigned* cpu_id, size_t cpu_count) { - if (thread == NULL || mask == NULL) { + if (thread == NULL) { return KNOTD_EINVAL; } #ifdef HAVE_PTHREAD_SETAFFINITY_NP - if (len != sizeof(cpu_set_t)) { - return KNOTD_EINVAL; + int ret = -1; + +/* Linux, FreeBSD interface. */ +#if defined(HAVE_CPUSET_LINUX) || defined(HAVE_CPUSET_BSD) + cpu_set_t set; + CPU_ZERO(&set); + for (unsigned i = 0; i < cpu_count; ++i) { + CPU_SET(cpu_id[i], &set); } - pthread_t tid = pthread_self(); - int ret = pthread_setaffinity_np(tid, len, (cpu_set_t*)mask); + ret = pthread_setaffinity_np(thread->_thr, sizeof(cpu_set_t), &set); +/* NetBSD interface. */ +#elif defined(HAVE_CPUSET_NETBSD) + cpuset_t *set = cpuset_create(); + if (set == NULL) { + return KNOTD_ENOMEM; + } + cpuset_zero(set); + for (unsigned i = 0; i < cpu_count; ++i) { + cpuset_set(cpu_id[i], &set); + } + ret = pthread_setaffinity_np(thread->_thr, cpuset_size(set), set); + cpuset_destroy(set); +#endif /* interface */ + if (ret < 0) { return KNOTD_ERROR; } -#else + +#else /* HAVE_PTHREAD_SETAFFINITY_NP */ return KNOTD_ENOTSUP; #endif @@ -988,8 +1022,17 @@ int dt_compact(dt_unit_t *unit) int dt_online_cpus() { int ret = -1; +/* Linux, Solaris, OS X 10.4+ */ #ifdef _SC_NPROCESSORS_ONLN ret = (int) sysconf(_SC_NPROCESSORS_ONLN); +#else +/* FreeBSD, NetBSD, OpenBSD, OS X < 10.4 */ +#if HAVE_SYSCTLBYNAME + size_t rlen = sizeof(int); + if (sysctlbyname("hw.ncpu", &ret, &rlen, NULL, 0) < 0) { + ret = -1; + } +#endif #endif return ret; } diff --git a/src/knot/server/dthreads.h b/src/knot/server/dthreads.h index 8ba457b..758bc28 100644..100755 --- a/src/knot/server/dthreads.h +++ b/src/knot/server/dthreads.h @@ -254,12 +254,13 @@ int dt_stop(dt_unit_t *unit); * \brief Set thread affinity to masked CPU's. * * \param thread Target thread instance. - * \param mask CPU mask (should be pointer to cpu_set_t). + * \param cpu_id Array of CPU IDs to set affinity to. + * \param cpu_count Number of CPUs in the array, set to 0 for no CPU. * * \retval KNOTD_EOK on success. * \retval KNOTD_EINVAL on invalid parameters. */ -int dt_setaffinity(dthread_t *thread, void *mask, size_t len); +int dt_setaffinity(dthread_t *thread, unsigned* cpu_id, size_t cpu_count); /*! * \brief Set thread to execute another runnable. diff --git a/src/knot/server/journal.c b/src/knot/server/journal.c index f901837..fa84021 100644..100755 --- a/src/knot/server/journal.c +++ b/src/knot/server/journal.c @@ -117,8 +117,8 @@ static int journal_recover(journal_t *j) } /* Write back. */ - lseek(j->fd, JOURNAL_HSIZE - 2 * sizeof(uint16_t), SEEK_SET); - if (!sfwrite(qstate, 2 * sizeof(uint16_t), j->fd)) { + int seek_ret = lseek(j->fd, JOURNAL_HSIZE - 2 * sizeof(uint16_t), SEEK_SET); + if (seek_ret < 0 || !sfwrite(qstate, 2 * sizeof(uint16_t), j->fd)) { dbg_journal("journal: failed to write back queue state\n"); return KNOTD_ERROR; } @@ -146,6 +146,7 @@ int journal_write_in(journal_t *j, journal_node_t **rn, uint64_t id, size_t len) /* Calculate remaining bytes to reach file size limit. */ size_t fs_remaining = j->fslimit - j->fsize; + int seek_ret = 0; /* Increase free segment if on the end of file. */ journal_node_t *n = j->nodes + j->qtail; @@ -193,8 +194,8 @@ int journal_write_in(journal_t *j, journal_node_t **rn, uint64_t id, size_t len) /* Write back evicted node. */ head->flags = JOURNAL_FREE; - lseek(j->fd, JOURNAL_HSIZE + (j->qhead + 1) * node_len, SEEK_SET); - if (!sfwrite(head, node_len, j->fd)) { + seek_ret = lseek(j->fd, JOURNAL_HSIZE + (j->qhead + 1) * node_len, SEEK_SET); + if (seek_ret < 0 || !sfwrite(head, node_len, j->fd)) { return KNOTD_ERROR; } @@ -204,8 +205,8 @@ int journal_write_in(journal_t *j, journal_node_t **rn, uint64_t id, size_t len) /* Write back query state. */ j->qhead = (j->qhead + 1) % j->max_nodes; uint16_t qstate[2] = {j->qhead, j->qtail}; - lseek(j->fd, JOURNAL_HSIZE - 2 * sizeof(uint16_t), SEEK_SET); - if (!sfwrite(qstate, 2 * sizeof(uint16_t), j->fd)) { + seek_ret = lseek(j->fd, JOURNAL_HSIZE - 2 * sizeof(uint16_t), SEEK_SET); + if (seek_ret < 0 || !sfwrite(qstate, 2 * sizeof(uint16_t), j->fd)) { return KNOTD_ERROR; } @@ -260,8 +261,8 @@ int journal_write_out(journal_t *journal, journal_node_t *n) journal->free.pos + journal->free.len); /* Write back free segment state. */ - lseek(journal->fd, JOURNAL_HSIZE, SEEK_SET); - if (!sfwrite(&journal->free, node_len, journal->fd)) { + int seek_ret = lseek(journal->fd, JOURNAL_HSIZE, SEEK_SET); + if (seek_ret < 0 || !sfwrite(&journal->free, node_len, journal->fd)) { /* Node is marked valid and failed to shrink free space, * node will be overwritten on the next write. Return error. */ @@ -278,8 +279,8 @@ int journal_write_out(journal_t *journal, journal_node_t *n) * qtail - highest valid node identifier (most recently used) */ uint16_t qstate[2] = {journal->qhead, journal->qtail}; - lseek(journal->fd, JOURNAL_HSIZE - 2 * sizeof(uint16_t), SEEK_SET); - if (!sfwrite(qstate, 2 * sizeof(uint16_t), journal->fd)) { + seek_ret = lseek(journal->fd, JOURNAL_HSIZE - 2 * sizeof(uint16_t), SEEK_SET); + if (seek_ret < 0 || !sfwrite(qstate, 2 * sizeof(uint16_t), journal->fd)) { dbg_journal("journal: failed to write back queue state\n"); return KNOTD_ERROR; } @@ -297,11 +298,15 @@ int journal_update_crc(int fd) char buf[4096]; ssize_t rb = 0; crc_t crc = crc_init(); - lseek(fd, MAGIC_LENGTH + sizeof(crc_t), SEEK_SET); + if (lseek(fd, MAGIC_LENGTH + sizeof(crc_t), SEEK_SET) < 0) { + return KNOTD_ERROR; + } while((rb = read(fd, buf, sizeof(buf))) > 0) { crc = crc_update(crc, (const unsigned char *)buf, rb); } - lseek(fd, MAGIC_LENGTH, SEEK_SET); + if (lseek(fd, MAGIC_LENGTH, SEEK_SET) < 0) { + return KNOTD_ERROR; + } if (!sfwrite(&crc, sizeof(crc_t), fd)) { dbg_journal("journal: couldn't write CRC to fd=%d\n", fd); return KNOTD_ERROR; @@ -508,7 +513,12 @@ journal_t* journal_open(const char *fn, size_t fslimit, int mode, uint16_t bflag /* Compare */ if (crc == crc_calc) { - lseek(fd, MAGIC_LENGTH + sizeof(crc_t), SEEK_SET); /* Rewind. */ + /* Rewind. */ + if (lseek(fd, MAGIC_LENGTH + sizeof(crc_t), SEEK_SET) < 0) { + fcntl(fd, F_SETLK, &fl); + close(fd); + return NULL; + } } else { log_server_warning("Journal file '%s' CRC error, " "it will be flushed.\n", fn); @@ -717,10 +727,10 @@ int journal_read(journal_t *journal, uint64_t id, journal_cmp_t cf, char *dst) (unsigned long long)id, n->pos, n->pos + n->len, n->flags); /* Seek journal node. */ - lseek(journal->fd, n->pos, SEEK_SET); + int seek_ret = lseek(journal->fd, n->pos, SEEK_SET); /* Read journal node content. */ - if (!sfread(dst, n->len, journal->fd)) { + if (seek_ret < 0 || !sfread(dst, n->len, journal->fd)) { return KNOTD_ERROR; } @@ -741,8 +751,8 @@ int journal_write(journal_t *journal, uint64_t id, const char *src, size_t size) } /* Write data to permanent storage. */ - lseek(journal->fd, n->pos, SEEK_SET); - if (!sfwrite(src, size, journal->fd)) { + int seek_ret = lseek(journal->fd, n->pos, SEEK_SET); + if (seek_ret < 0 || !sfwrite(src, size, journal->fd)) { return KNOTD_ERROR; } @@ -765,7 +775,9 @@ int journal_map(journal_t *journal, uint64_t id, char **dst, size_t size) /* Reserve data in permanent storage. */ /*! \todo This is only needed when inflating journal file. */ - lseek(journal->fd, n->pos, SEEK_SET); + if (lseek(journal->fd, n->pos, SEEK_SET) < 0) { + return KNOTD_ERROR; + } char nbuf[4096] = {0}; size_t wb = sizeof(nbuf); while (size > 0) { @@ -868,8 +880,8 @@ int journal_update(journal_t *journal, journal_node_t *n) i, (unsigned long long)n->id, n->flags); /* Write back. */ - lseek(journal->fd, jn_fpos, SEEK_SET); - if (!sfwrite(n, node_len, journal->fd)) { + int seek_ret = lseek(journal->fd, jn_fpos, SEEK_SET); + if (seek_ret < 0 || !sfwrite(n, node_len, journal->fd)) { dbg_journal("journal: failed to writeback node=%llu to %ld\n", (unsigned long long)n->id, jn_fpos); return KNOTD_ERROR; diff --git a/src/knot/server/journal.h b/src/knot/server/journal.h index 322e25d..fd0e3a6 100644..100755 --- a/src/knot/server/journal.h +++ b/src/knot/server/journal.h @@ -359,3 +359,5 @@ void journal_release(journal_t *journal); int journal_update_crc(int fd); #endif /* _KNOTD_JOURNAL_H_ */ + +/*! @} */ diff --git a/src/knot/server/notify.c b/src/knot/server/notify.c index aa0a52b..d0292e8 100644..100755 --- a/src/knot/server/notify.c +++ b/src/knot/server/notify.c @@ -242,39 +242,49 @@ int notify_process_request(knot_nameserver_t *ns, if (notify->parsed < notify->size) { 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), - ¬ify->header.flags1, - KNOT_RCODE_FORMERR, buffer, - size); + knot_ns_error_response_from_query(ns, notify, + KNOT_RCODE_FORMERR, + buffer, size); return KNOTD_EOK; } } + // check if it makes sense - if the QTYPE is SOA + if (knot_packet_qtype(notify) != KNOT_RRTYPE_SOA) { + // send back FORMERR + knot_ns_error_response_from_query(ns, notify, + KNOT_RCODE_FORMERR, buffer, + size); + return KNOTD_EOK; + } + // create NOTIFY response dbg_notify("notify: creating response\n"); ret = notify_create_response(notify, buffer, size); if (ret != KNOTD_EOK) { dbg_notify("notify: failed to create NOTIFY response\n"); - knot_ns_error_response(ns, knot_packet_id(notify), - ¬ify->header.flags1, - KNOT_RCODE_SERVFAIL, buffer, size); + knot_ns_error_response_from_query(ns, notify, + KNOT_RCODE_SERVFAIL, buffer, + size); return KNOTD_EOK; } // find the zone + rcu_read_lock(); const knot_dname_t *qname = knot_packet_qname(notify); const knot_zone_t *z = knot_zonedb_find_zone_for_name( ns->zone_db, qname); if (z == NULL) { + rcu_read_unlock(); dbg_notify("notify: failed to find zone by name\n"); - knot_ns_error_response(ns, knot_packet_id(notify), - ¬ify->header.flags1, - KNOT_RCODE_REFUSED, buffer, size); + knot_ns_error_response_from_query(ns, notify, + KNOT_RCODE_FORMERR, buffer, + size); return KNOTD_EOK; } notify_check_and_schedule(ns, z, from); - + rcu_read_unlock(); return KNOTD_EOK; } @@ -294,13 +304,16 @@ int notify_process_response(knot_nameserver_t *nameserver, *size = 0; /* Find matching zone. */ + rcu_read_lock(); const knot_dname_t *zone_name = knot_packet_qname(notify); knot_zone_t *zone = knot_zonedb_find_zone(nameserver->zone_db, zone_name); if (!zone) { + rcu_read_unlock(); return KNOTD_ENOENT; } if (!knot_zone_data(zone)) { + rcu_read_unlock(); return KNOTD_ENOENT; } @@ -318,6 +331,7 @@ int notify_process_response(knot_nameserver_t *nameserver, /* Found waiting NOTIFY query? */ if (!match) { + rcu_read_unlock(); pthread_mutex_unlock(&zd->lock); return KNOTD_ERROR; } @@ -327,6 +341,8 @@ int notify_process_response(knot_nameserver_t *nameserver, /* Zone was removed/reloaded. */ pthread_mutex_unlock(&zd->lock); + + rcu_read_unlock(); return KNOTD_EOK; } diff --git a/src/knot/server/notify.h b/src/knot/server/notify.h index a9ba807..a9ba807 100644..100755 --- a/src/knot/server/notify.h +++ b/src/knot/server/notify.h diff --git a/src/knot/server/server.c b/src/knot/server/server.c index 5611a0c..06f89b5 100644..100755 --- a/src/knot/server/server.c +++ b/src/knot/server/server.c @@ -22,8 +22,6 @@ #include <errno.h> #include <openssl/evp.h> #include <assert.h> -#include <grp.h> - #include "common/prng.h" #include "knot/common.h" @@ -219,7 +217,7 @@ static int server_bind_sockets(server_t *server) */ /* Lock configuration. */ - conf_read_lock(); + rcu_read_lock(); /* Prepare helper lists. */ int bound = 0; @@ -290,7 +288,7 @@ static int server_bind_sockets(server_t *server) } /* Unlock configuration. */ - conf_read_unlock(); + rcu_read_unlock(); /* Publish new list. */ list* oldlist = rcu_xchg_pointer(&server->ifaces, newlist); @@ -331,7 +329,7 @@ static int server_bind_handlers(server_t *server) } /* Lock config. */ - conf_read_lock(); + rcu_read_lock(); /* Estimate number of threads/manager. */ int thr_count = 0; @@ -388,7 +386,7 @@ static int server_bind_handlers(server_t *server) } /* Unlock config. */ - conf_read_unlock(); + rcu_read_unlock(); return KNOTD_EOK; } @@ -552,7 +550,7 @@ int server_start(server_t *server) xfr_start(server->xfr_h); /* Lock configuration. */ - conf_read_lock(); + rcu_read_lock(); // Start dispatchers int ret = KNOTD_EOK; @@ -573,7 +571,7 @@ int server_start(server_t *server) } /* Unlock configuration. */ - conf_read_unlock(); + rcu_read_unlock(); dbg_server("server: server started\n"); @@ -653,16 +651,13 @@ void server_stop(server_t *server) { dbg_server("server: stopping server\n"); - /* Wait for XFR master. */ - xfr_stop(server->xfr_h); + /* Send termination event. */ + evsched_schedule_term(server->sched, 0); /* Interrupt XFR handler execution. */ if (server->xfr_h->interrupt) { server->xfr_h->interrupt(server->xfr_h); } - - /* Send termination event. */ - evsched_schedule_term(server->sched, 0); /* Lock RCU. */ rcu_read_lock(); @@ -743,51 +738,9 @@ int server_conf_hook(const struct conf_t *conf, void *data) "configured interfaces.\n"); } } - - /* Lock configuration. */ - conf_read_lock(); - int priv_failed = 0; - -#ifdef HAVE_SETGROUPS - /* Drop supplementary groups. */ - if (conf->gid > -1 || conf->uid > -1) { - ret = setgroups(0, NULL); - - /* Collect results. */ - if (ret < 0) { - log_server_error("Failed to set supplementary groups " - "for uid '%d' (%s).\n", - getuid(), strerror(errno)); - priv_failed = 1; - } - } -#endif - - /* Watch uid/gid. */ - if (conf->gid > -1 && conf->gid != getgid()) { - log_server_info("Changing group id to '%d'.\n", conf->gid); - if (setregid(conf->gid, conf->gid) < 0) { - log_server_error("Failed to change gid to '%d'.\n", - conf->gid); - priv_failed = 1; - } - } - if (conf->uid > -1 && conf->uid != getuid()) { - log_server_info("Changing user id to '%d'.\n", conf->uid); - if (setreuid(conf->uid, conf->uid) < 0) { - log_server_error("Failed to change uid to '%d'.\n", - conf->uid); - priv_failed = 1; - } - } - - if (priv_failed) { - ret = KNOTD_EACCES; - } /* Exit if the server is not running. */ if (ret != KNOTD_EOK || !(server->state & ServerRunning)) { - conf_read_unlock(); return KNOTD_ENOTRUNNING; } @@ -807,9 +760,6 @@ int server_conf_hook(const struct conf_t *conf, void *data) } } - /* Unlock config. */ - conf_read_unlock(); - return ret; } diff --git a/src/knot/server/server.h b/src/knot/server/server.h index 79a4729..79a4729 100644..100755 --- a/src/knot/server/server.h +++ b/src/knot/server/server.h diff --git a/src/knot/server/socket.c b/src/knot/server/socket.c index 4deb862..1e79f89 100644..100755 --- a/src/knot/server/socket.c +++ b/src/knot/server/socket.c @@ -99,6 +99,8 @@ int socket_connect(int fd, const char *addr, unsigned short port) int socket_bind(int socket, int family, const char *addr, unsigned short port) { /* Check address family. */ + int flag = 1; + int ret = 0; struct sockaddr* paddr = 0; socklen_t addrlen = 0; struct sockaddr_in saddr; @@ -150,12 +152,23 @@ int socket_bind(int socket, int family, const char *addr, unsigned short port) addr, buf); } -#endif + + /* Make the socket IPv6 only to allow 'any' for IPv4 and IPv6 at the same time. */ +#ifdef IPV6_V6ONLY + if (family == AF_INET6) { + /* Do not support mapping IPv4 in IPv6 sockets. */ + ret = setsockopt(socket, IPPROTO_IPV6, IPV6_V6ONLY, + &flag, sizeof(flag)); + if (ret < 0) { + return KNOTD_EINVAL; + } + } +#endif /* IPV6_V6ONLY */ +#endif /* DISABLE_IPV6 */ } /* Reuse old address if taken. */ - int flag = 1; - int ret = setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, + ret = setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)); if (ret < 0) { return KNOTD_EINVAL; @@ -164,7 +177,7 @@ int socket_bind(int socket, int family, const char *addr, unsigned short port) /* Bind to specified address. */ int res = bind(socket, paddr, addrlen); if (res < 0) { - log_server_error("Cannot bind to socket (%d).\n", + log_server_error("Cannot bind to socket (errno %d).\n", errno); return knot_map_errno(EADDRINUSE, EINVAL, EACCES, ENOMEM); } diff --git a/src/knot/server/socket.h b/src/knot/server/socket.h index 2185f03..2185f03 100644..100755 --- a/src/knot/server/socket.h +++ b/src/knot/server/socket.h diff --git a/src/knot/server/tcp-handler.c b/src/knot/server/tcp-handler.c index 977de0b..60f4301 100644..100755 --- a/src/knot/server/tcp-handler.c +++ b/src/knot/server/tcp-handler.c @@ -104,7 +104,10 @@ static void tcp_sweep(fdset_t *set, int fd, void* data) int r_port = 0; struct sockaddr_storage addr; socklen_t len = sizeof(addr); - getpeername(fd, (struct sockaddr*)&addr, &len); + if (getpeername(fd, (struct sockaddr*)&addr, &len) < 0) { + dbg_net("tcp: sweep getpeername() on invalid socket=%d\n", fd); + return; + } /* Translate */ if (addr.ss_family == AF_INET) { @@ -158,15 +161,13 @@ static int tcp_handle(tcp_worker_t *w, int fd, uint8_t *qbuf, size_t qbuf_maxlen log_server_error("Socket type %d is not supported, " "IPv6 support is probably disabled.\n", w->ioh->type); - return KNOTD_ECONNREFUSED; + return KNOTD_EINVAL; } /* Receive data. */ int n = tcp_recv(fd, qbuf, qbuf_maxlen, &addr); if (n <= 0) { dbg_net("tcp: client on fd=%d disconnected\n", fd); - fdset_remove(w->fdset, fd); - close(fd); if (n == KNOTD_EAGAIN) { char r_addr[SOCKADDR_STRLEN]; sockaddr_tostr(&addr, r_addr, sizeof(r_addr)); @@ -184,7 +185,7 @@ static int tcp_handle(tcp_worker_t *w, int fd, uint8_t *qbuf, size_t qbuf_maxlen knot_packet_t *packet = knot_packet_new(KNOT_PACKET_PREALLOC_QUERY); if (packet == NULL) { - int ret = knot_ns_error_response_from_query(ns, qbuf, n, + int ret = knot_ns_error_response_from_query_wire(ns, qbuf, n, KNOT_RCODE_SERVFAIL, qbuf, &resp_len); @@ -198,8 +199,8 @@ static int tcp_handle(tcp_worker_t *w, int fd, uint8_t *qbuf, size_t qbuf_maxlen int parse_res = knot_ns_parse_packet(qbuf, n, packet, &qtype); if (unlikely(parse_res != KNOT_EOK)) { if (parse_res > 0) { /* Returned RCODE */ - int ret = knot_ns_error_response_from_query(ns, qbuf, n, - parse_res, qbuf, &resp_len); + int ret = knot_ns_error_response_from_query(ns, packet, + parse_res, qbuf, &resp_len); if (ret == KNOT_EOK) { tcp_reply(fd, qbuf, resp_len); @@ -235,10 +236,9 @@ static int tcp_handle(tcp_worker_t *w, int fd, uint8_t *qbuf, size_t qbuf_maxlen /* Prepare context. */ 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); + knot_ns_error_response_from_query(ns, packet, + KNOT_RCODE_SERVFAIL, + qbuf, &resp_len); res = KNOTD_EOK; break; } @@ -252,9 +252,9 @@ static int tcp_handle(tcp_worker_t *w, int fd, uint8_t *qbuf, size_t qbuf_maxlen return xfr_answer(ns, &xfr); case KNOT_QUERY_UPDATE: - knot_ns_error_response(ns, knot_packet_id(packet), - &packet->header.flags1, - KNOT_RCODE_NOTIMPL, qbuf, &resp_len); + knot_ns_error_response_from_query(ns, packet, + KNOT_RCODE_NOTIMPL, + qbuf, &resp_len); res = KNOTD_EOK; break; @@ -268,17 +268,17 @@ static int tcp_handle(tcp_worker_t *w, int fd, uint8_t *qbuf, size_t qbuf_maxlen case KNOT_RESPONSE_NORMAL: /*!< TCP handler doesn't send queries. */ 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); + knot_ns_error_response_from_query(ns, packet, + KNOT_RCODE_REFUSED, + qbuf, &resp_len); res = KNOTD_EOK; break; /* Unknown opcodes. */ default: - knot_ns_error_response(ns, knot_packet_id(packet), - &packet->header.flags1, - KNOT_RCODE_FORMERR, qbuf, &resp_len); + knot_ns_error_response_from_query(ns, packet, + KNOT_RCODE_FORMERR, + qbuf, &resp_len); res = KNOTD_EOK; break; } @@ -326,7 +326,11 @@ static int tcp_accept(int fd) struct timeval tv; tv.tv_sec = TCP_ACTIVITY_WD; tv.tv_usec = 0; - setsockopt(incoming, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); + if (setsockopt(incoming, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) { + log_server_warning("Couldn't set up TCP connection " + "watchdog timer for fd=%d.\n", + incoming); + } #endif } @@ -389,7 +393,7 @@ int tcp_send(int fd, uint8_t *msg, size_t msglen) */ #ifdef TCP_CORK int cork = 1; - setsockopt(fd, SOL_TCP, TCP_CORK, &cork, sizeof(cork)); + int uncork = setsockopt(fd, SOL_TCP, TCP_CORK, &cork, sizeof(cork)); #endif /* Send message size. */ @@ -406,9 +410,11 @@ int tcp_send(int fd, uint8_t *msg, size_t msglen) } #ifdef TCP_CORK - /* Uncork. */ - cork = 0; - setsockopt(fd, SOL_TCP, TCP_CORK, &cork, sizeof(cork)); + /* Uncork only if corked successfuly. */ + if (uncork == 0) { + cork = 0; + setsockopt(fd, SOL_TCP, TCP_CORK, &cork, sizeof(cork)); + } #endif return sent; } @@ -444,7 +450,9 @@ int tcp_recv(int fd, uint8_t *buf, size_t len, sockaddr_t *addr) /* Get peer name. */ if (addr) { socklen_t alen = addr->len; - getpeername(fd, addr->ptr, &alen); + if (getpeername(fd, addr->ptr, &alen) < 0) { + return KNOTD_EMALF; + } } /* Receive payload. */ @@ -582,6 +590,12 @@ int tcp_loop_worker(dthread_t *thread) "set to %ds\n", it.fd, TCP_ACTIVITY_WD); } + /*! \todo Refactor to allow erase on iterator.*/ + if (ret == KNOTD_ECONNREFUSED) { + fdset_remove(w->fdset, it.fd); + close(it.fd); + break; + } } diff --git a/src/knot/server/tcp-handler.h b/src/knot/server/tcp-handler.h index ab6baab..ab6baab 100644..100755 --- a/src/knot/server/tcp-handler.h +++ b/src/knot/server/tcp-handler.h diff --git a/src/knot/server/udp-handler.c b/src/knot/server/udp-handler.c index dcb5b1f..fc4e9b1 100644..100755 --- a/src/knot/server/udp-handler.c +++ b/src/knot/server/udp-handler.c @@ -85,7 +85,7 @@ int udp_handle(int fd, uint8_t *qbuf, size_t qbuflen, size_t *resp_len, if (packet == NULL) { dbg_net("udp: failed to create packet on fd=%d\n", fd); - int ret = knot_ns_error_response_from_query(ns, qbuf, qbuflen, + int ret = knot_ns_error_response_from_query_wire(ns, qbuf, qbuflen, KNOT_RCODE_SERVFAIL, qbuf, resp_len); @@ -101,15 +101,25 @@ 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 */ - int ret = knot_ns_error_response_from_query(ns, qbuf, - qbuflen, - res, qbuf, - resp_len); +// int ret = knot_ns_error_response_from_query_wire(ns, +// qbuf, qbuflen, res, qbuf, resp_len); + int ret = knot_ns_error_response_from_query(ns, + packet, res, qbuf, resp_len); if (ret != KNOT_EOK) { knot_packet_free(&packet); return KNOTD_EMALF; } + } else { + assert(res < 0); + int ret = knot_ns_error_response_from_query_wire( + ns, qbuf, qbuflen, KNOT_RCODE_SERVFAIL, qbuf, + resp_len); + + if (ret != KNOT_EOK) { + knot_packet_free(&packet); + return ret; + } } knot_packet_free(&packet); @@ -122,14 +132,6 @@ int udp_handle(int fd, uint8_t *qbuf, size_t qbuflen, size_t *resp_len, res = KNOTD_ERROR; switch(qtype) { - /* Response types. */ - case KNOT_RESPONSE_NORMAL: - 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); - break; - /* Query types. */ case KNOT_QUERY_NORMAL: res = zones_normal_query_answer(ns, packet, addr, qbuf, @@ -140,9 +142,9 @@ int udp_handle(int fd, uint8_t *qbuf, size_t qbuflen, size_t *resp_len, * Bind responds with FORMERR. */ /*! \note Draft exists for AXFR/UDP, but has not been standardized. */ - knot_ns_error_response(ns, knot_packet_id(packet), - &packet->header.flags1, - KNOT_RCODE_FORMERR, qbuf, resp_len); + knot_ns_error_response_from_query(ns, packet, + KNOT_RCODE_FORMERR, qbuf, + resp_len); res = KNOTD_EOK; break; case KNOT_QUERY_IXFR: @@ -151,7 +153,7 @@ int udp_handle(int fd, uint8_t *qbuf, size_t qbuflen, size_t *resp_len, * but I have found no tool or slave server to actually attempt * IXFR/UDP. */ - knot_packet_set_qtype(packet, KNOT_RRTYPE_SOA); +// knot_packet_set_qtype(packet, KNOT_RRTYPE_SOA); res = zones_normal_query_answer(ns, packet, addr, qbuf, resp_len, NS_TRANSPORT_UDP); @@ -163,27 +165,26 @@ 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), - &packet->header.flags1, - KNOT_RCODE_NOTIMPL, qbuf, resp_len); + knot_ns_error_response_from_query(ns, packet, + KNOT_RCODE_NOTIMPL, qbuf, + resp_len); res = KNOTD_EOK; break; /* Unhandled opcodes. */ 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); + knot_ns_error_response_from_query(ns, packet, + KNOT_RCODE_REFUSED, qbuf, + resp_len); res = KNOTD_EOK; break; /* Unknown opcodes */ default: - knot_ns_error_response(ns, knot_packet_id(packet), - &packet->header.flags1, - KNOT_RCODE_FORMERR, qbuf, resp_len); + knot_ns_error_response_from_query(ns, packet, + KNOT_RCODE_FORMERR, qbuf, + resp_len); res = KNOTD_EOK; break; } @@ -204,17 +205,14 @@ static inline int udp_master_recvfrom(dthread_t *thread, stat_t *thread_stat) /* 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)); + unsigned cpu[2]; + cpu[0] = dt_get_id(thread); + cpu[1] = (cpu[0] + 1) % cpcount; + cpu[0] = cpu[0] % cpcount; + dt_setaffinity(thread, cpu, 2); } -#endif knot_nameserver_t *ns = h->server->nameserver; @@ -389,6 +387,7 @@ static inline int udp_master_recvmmsg(dthread_t *thread, stat_t *thread_stat) free(addrs); free(iov); free(msgs); + close(sock); return KNOTD_ENOMEM; } @@ -407,17 +406,14 @@ static inline int udp_master_recvmmsg(dthread_t *thread, stat_t *thread_stat) /* 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)); + unsigned cpu[2]; + cpu[0] = dt_get_id(thread); + cpu[1] = (cpu[0] + 1) % cpcount; + cpu[0] = cpu[0] % cpcount; + dt_setaffinity(thread, cpu, 2); } -#endif /* Loop until all data is read. */ ssize_t n = 0; @@ -433,7 +429,9 @@ static inline int udp_master_recvmmsg(dthread_t *thread, stat_t *thread_stat) /* Error and interrupt handling. */ if (unlikely(n <= 0)) { - if (errno != EINTR && errno != 0) { + if (errno != EINTR && errno != 0 && n < 0) { + log_server_error("I/O failure in UDP - errno %d " + "(Linux/recvmmsg)", errno); dbg_net("udp: recvmmsg() failed: %d\n", errno); } @@ -493,7 +491,10 @@ void __attribute__ ((constructor)) udp_master_init() #ifdef MSG_WAITFORONE /* Check for recvmmsg() support. */ if (dlsym(RTLD_DEFAULT, "recvmmsg") != 0) { - _udp_master = udp_master_recvmmsg; + int r = recvmmsg(0, NULL, 0, 0, 0); + if (errno != ENOSYS) { + _udp_master = udp_master_recvmmsg; + } } /* Check for sendmmsg() support. */ diff --git a/src/knot/server/udp-handler.h b/src/knot/server/udp-handler.h index f5fcd04..f5fcd04 100644..100755 --- a/src/knot/server/udp-handler.h +++ b/src/knot/server/udp-handler.h diff --git a/src/knot/server/xfr-handler.c b/src/knot/server/xfr-handler.c index a77f1f1..7863c9a 100644..100755 --- a/src/knot/server/xfr-handler.c +++ b/src/knot/server/xfr-handler.c @@ -45,12 +45,19 @@ #define XFR_QUERY_WD 10 /*!< SOA/NOTIFY query timeout [s]. */ #define XFR_SWEEP_INTERVAL 2 /*! [seconds] between sweeps. */ #define XFR_BUFFER_SIZE 65535 /*! Do not change this - maximum value for UDP packet length. */ +#define XFR_MSG_DLTTR 9 /*! Index of letter differentiating IXFR/AXFR in log msg. */ /*! \brief Send interrupt to all workers. */ void xfr_interrupt(xfrhandler_t *h) { for(unsigned i = 0; i < h->unit->size; ++i) { - evqueue_write(h->workers[i]->q, "", 1); + evqueue_t *q = h->workers[i]->q; + if (evqueue_write(q, "", 1) == 1) { + close(q->fds[EVQUEUE_WRITEFD]); + q->fds[EVQUEUE_WRITEFD] = -1; + } else { + dt_stop_id(h->unit->threads[i]); + } } } @@ -63,6 +70,55 @@ static void xfr_request_deinit(knot_ns_xfr_t *r) } } +/*! + * \brief Clean pending transfer data. + */ +static int xfr_xfrin_cleanup(xfrworker_t *w, knot_ns_xfr_t *data) +{ + int ret = KNOTD_EOK; + knot_changesets_t *chs = 0; + + dbg_xfr_verb("Cleaning up after XFR-in.\n"); + + switch(data->type) { + case XFR_TYPE_AIN: + if (data->flags & XFR_FLAG_AXFR_FINISHED) { + knot_zone_contents_deep_free( + &data->new_contents, 1); + } else { + if (data->data) { + xfrin_constructed_zone_t *constr_zone = + (xfrin_constructed_zone_t *)data->data; + knot_zone_contents_deep_free( + &(constr_zone->contents), 0); + xfrin_free_orphan_rrsigs(&(constr_zone->rrsigs)); + free(data->data); + data->data = 0; + } + } + break; + case XFR_TYPE_IIN: + if (data->data) { + chs = (knot_changesets_t *)data->data; + knot_free_changesets(&chs); + data->data = NULL; + } + + // this function is called before new contents are created + assert(data->new_contents == NULL); + + break; + } + + /* Cleanup other data - so that the structure may be reused. */ + data->packet_nr = 0; + data->tsig_data_size = 0; + + dbg_xfr_detail("Done.\n"); + + return ret; +} + /*! \brief Free allocated xfer descriptor (also deinitializes). */ static void xfr_free_task(knot_ns_xfr_t *task) { @@ -83,7 +139,8 @@ static void xfr_free_task(knot_ns_xfr_t *task) } /* Unlock if XFR/IN.*/ - if (task->type == XFR_TYPE_AIN || task->type == XFR_TYPE_IIN) { + int is_xfer = task->type == XFR_TYPE_AIN || task->type == XFR_TYPE_IIN; + if (is_xfer) { knot_zone_t *zone = task->zone; zonedata_t *zd = (zonedata_t *)knot_zone_data(zone); if (zd) { @@ -92,9 +149,24 @@ static void xfr_free_task(knot_ns_xfr_t *task) } } - /* Deinitialize */ - xfr_request_deinit(task); + /* Free TSIG buffers. */ + if (task->digest) { + free(task->digest); + task->digest = NULL; + task->digest_size = 0; + } + if (task->tsig_data) { + free(task->tsig_data); + task->tsig_data = NULL; + task->tsig_data_size = 0; + } + if (!task->session_closed) { + /* Cleanup pending request. */ + if (is_xfer) { + xfr_xfrin_cleanup(w, task); + } + /* Remove fd-related data. */ xfrhandler_t *h = w->master; pthread_mutex_lock(&h->tasks_mx); @@ -102,6 +174,12 @@ static void xfr_free_task(knot_ns_xfr_t *task) pthread_mutex_unlock(&h->tasks_mx); close(task->session); } + + /* No further access to zone. */ + knot_zone_release(task->zone); + + /* Deinitialize */ + xfr_request_deinit(task); free(task); } @@ -139,11 +217,15 @@ static knot_ns_xfr_t *xfr_handler_task(xfrworker_t *w, int fd) static int xfr_udp_timeout(knot_ns_xfr_t *data) { /* Close socket. */ + rcu_read_lock(); knot_zone_t *z = data->zone; if (z && knot_zone_get_contents(z) && knot_zone_data(z)) { - log_zone_info("%s Failed, timeout exceeded.\n", - data->msgpref); + if (!(knot_zone_flags(z) & KNOT_ZONE_DISCARDED)) { + log_zone_info("%s Failed, timeout exceeded.\n", + data->msgpref); + } } + rcu_read_unlock(); /* Invalidate pending query. */ xfr_free_task(data); @@ -161,15 +243,93 @@ static int xfr_udp_timeout(knot_ns_xfr_t *data) */ static int xfr_process_udp_resp(xfrworker_t *w, int fd, knot_ns_xfr_t *data) { + /* Check if zone is valid. */ + int ret = KNOTD_ECONNREFUSED; + rcu_read_lock(); + if (knot_zone_flags(data->zone) & KNOT_ZONE_DISCARDED) { + rcu_read_unlock(); + return ret; + } + rcu_read_unlock(); + /* Receive msg. */ - ssize_t n = recvfrom(data->session, data->wire, data->wire_size, 0, data->addr.ptr, &data->addr.len); + ssize_t n = recvfrom(data->session, data->wire, data->wire_size, + 0, data->addr.ptr, &data->addr.len); size_t resp_len = data->wire_size; - if (n > 0) { - udp_handle(fd, data->wire, n, &resp_len, &data->addr, w->ns); + if (n <= 0) { + return ret; + } + + // parse packet + knot_packet_t *re = knot_packet_new(KNOT_PACKET_PREALLOC_RESPONSE); + if (re == NULL) { + return KNOTD_ENOMEM; + } + + knot_packet_type_t rt = KNOT_RESPONSE_NORMAL; + ret = knot_ns_parse_packet(data->wire, n, re, &rt); + if (ret != KNOTD_EOK) { + knot_packet_free(&re); + return KNOTD_EOK; /* Ignore */ + } + + /* Ignore other packets. */ + if (rt != KNOT_RESPONSE_NORMAL && rt != KNOT_RESPONSE_NOTIFY) { + knot_packet_free(&re); + return KNOTD_EOK; /* Ignore */ + } + ret = knot_packet_parse_rest(re); + if (ret != KNOT_EOK) { + knot_packet_free(&re); + return KNOTD_EOK; /* Ignore */ + } + + // check TSIG + const knot_rrset_t * tsig_rr = knot_packet_tsig(re); + if (data->tsig_key != NULL) { + /*! \todo Not sure about prev_time_signed, but this is the first + * reply and we should pass query sign time as the time + * may be different. Leaving to 0. + */ + ret = knot_tsig_client_check(tsig_rr, data->wire, n, + data->digest, data->digest_size, + data->tsig_key, 0); + if (ret != KNOT_EOK) { + log_server_error("%s %s\n", + data->msgpref, knot_strerror(ret)); + knot_packet_free(&re); + return KNOTD_ECONNREFUSED; + } + + } + + // process response + switch(rt) { + case KNOT_RESPONSE_NORMAL: + ret = zones_process_response(w->ns, &data->addr, re, + data->wire, &resp_len); + break; + case KNOT_RESPONSE_NOTIFY: + ret = notify_process_response(w->ns, re, &data->addr, + data->wire, &resp_len); + break; + default: + break; } + knot_packet_free(&re); + + /* Check up-to-date zone. */ + if (ret == KNOTD_EUPTODATE) { + log_server_info("%s %s\n", data->msgpref, knotd_strerror(ret)); + ret = KNOTD_ECONNREFUSED; + } + /* Invalidate pending query. */ - return KNOTD_ECONNREFUSED; + if (ret == KNOTD_EOK) { + ret = KNOTD_ECONNREFUSED; + } + return ret; } /*! \brief Sweep non-replied connection. */ @@ -250,46 +410,6 @@ static knot_ns_xfr_t *xfr_register_task(xfrworker_t *w, const knot_ns_xfr_t *req } /*! - * \brief Clean pending transfer data. - */ -static int xfr_xfrin_cleanup(xfrworker_t *w, knot_ns_xfr_t *data) -{ - int ret = KNOTD_EOK; - knot_changesets_t *chs = 0; - - switch(data->type) { - case XFR_TYPE_AIN: - if (data->flags & XFR_FLAG_AXFR_FINISHED) { - knot_zone_contents_deep_free( - &data->new_contents, 1); - } else { - if (data->data) { - xfrin_constructed_zone_t *constr_zone = - (xfrin_constructed_zone_t *)data->data; - knot_zone_contents_deep_free( - &(constr_zone->contents), 0); - xfrin_free_orphan_rrsigs(&(constr_zone->rrsigs)); - free(data->data); - data->data = 0; - } - } - break; - case XFR_TYPE_IIN: - if (data->data) { - chs = (knot_changesets_t *)data->data; - knot_free_changesets(&chs); - } - - // this function is called before new contents are created - assert(data->new_contents == NULL); - - break; - } - - return ret; -} - -/*! * \brief Finalize XFR/IN transfer. * * \param w XFR worker. @@ -382,7 +502,7 @@ static int xfr_xfrin_finalize(xfrworker_t *w, knot_ns_xfr_t *data) /* Switch zone contents. */ switch_ret = xfrin_switch_zone(data->zone, data->new_contents, - data->type); + data->type); if (switch_ret != KNOT_EOK) { log_zone_error("%s Failed to replace " @@ -401,7 +521,7 @@ static int xfr_xfrin_finalize(xfrworker_t *w, knot_ns_xfr_t *data) break; } - xfrin_cleanup_successful_update( &chs->changes); + xfrin_cleanup_successful_update(&chs->changes); /* Free changesets, but not the data. */ knot_free_changesets(&chs); @@ -418,24 +538,6 @@ static int xfr_xfrin_finalize(xfrworker_t *w, knot_ns_xfr_t *data) } /*! - * \brief Prepare TSIG for XFR. - */ -static int xfr_prepare_tsig(knot_ns_xfr_t *xfr, knot_key_t *key) -{ - int ret = KNOT_EOK; - xfr->tsig_key = key; - xfr->tsig_size = tsig_wire_maxsize(key); - xfr->digest_max_size = tsig_alg_digest_length( - key->algorithm); - xfr->digest = malloc(xfr->digest_max_size); - memset(xfr->digest, 0 , xfr->digest_max_size); - dbg_xfr("xfr: found TSIG key (MAC len=%zu), adding to transfer\n", - xfr->digest_max_size); - - return ret; -} - -/*! * \brief Check TSIG if exists. */ static int xfr_check_tsig(knot_ns_xfr_t *xfr, knot_rcode_t *rcode, char **tag) @@ -473,15 +575,11 @@ static int xfr_check_tsig(knot_ns_xfr_t *xfr, knot_rcode_t *rcode, char **tag) // return REFUSED xfr->tsig_key = 0; *rcode = KNOT_RCODE_REFUSED; - return KNOT_EXFRREFUSED; + return KNOT_EXFRDENIED; } if (tsig_rr) { tsig_algorithm_t alg = tsig_rdata_alg(tsig_rr); if (tsig_alg_digest_length(alg) == 0) { - log_server_info("%s Unsupported digest algorithm " - "requested, treating as " - "bad key.\n", - xfr->msgpref); *rcode = KNOT_RCODE_NOTAUTH; xfr->tsig_key = NULL; xfr->tsig_rcode = KNOT_TSIG_RCODE_BADKEY; @@ -598,8 +696,14 @@ int xfr_process_event(xfrworker_t *w, int fd, knot_ns_xfr_t *data, uint8_t *buf, /* Read DNS/TCP packet. */ int ret = 0; int rcvd = tcp_recv(fd, buf, buflen, 0); + + /* Raise read-lock and check if zone is still valid. */ + rcu_read_lock(); + int zone_discarded = (knot_zone_flags(zone) & KNOT_ZONE_DISCARDED); + + /* Handle incoming packet. */ data->wire_size = rcvd; - if (rcvd <= 0) { + if (rcvd <= 0 || zone_discarded) { data->wire_size = 0; ret = KNOT_ECONN; } else { @@ -621,14 +725,15 @@ int xfr_process_event(xfrworker_t *w, int fd, knot_ns_xfr_t *data, uint8_t *buf, /* AXFR-style IXFR. */ if (ret == KNOT_ENOIXFR) { assert(data->type == XFR_TYPE_IIN); - log_server_notice("%s Fallback to AXFR/IN.\n", data->msgpref); + log_server_notice("%s Fallback to AXFR.\n", data->msgpref); data->type = XFR_TYPE_AIN; - data->msgpref[0] = 'A'; + data->msgpref[XFR_MSG_DLTTR] = 'A'; ret = knot_ns_process_axfrin(w->ns, data); } /* Check return code for errors. */ - dbg_xfr_verb("xfr: processed incoming XFR packet (res = %d)\n", ret); + dbg_xfr_verb("xfr: processed incoming XFR packet (%s)\n", + knot_strerror(ret)); /* Finished xfers. */ int xfer_finished = 0; @@ -637,8 +742,8 @@ int xfr_process_event(xfrworker_t *w, int fd, knot_ns_xfr_t *data, uint8_t *buf, } /* IXFR refused, try again with AXFR. */ - if (zone && data->type == XFR_TYPE_IIN && ret == KNOT_EXFRREFUSED) { - log_server_notice("%s Transfer failed, fallback to AXFR/IN.\n", + if (data->type == XFR_TYPE_IIN && ret == KNOT_EXFRREFUSED) { + log_server_notice("%s Transfer failed, fallback to AXFR.\n", data->msgpref); size_t bufsize = buflen; data->wire_size = buflen; /* Reset maximum bufsize */ @@ -650,20 +755,26 @@ int xfr_process_event(xfrworker_t *w, int fd, knot_ns_xfr_t *data, uint8_t *buf, data->wire, bufsize); /* Switch to AIN type XFR and return now. */ if (ret == bufsize) { + rcu_read_unlock(); + xfr_xfrin_cleanup(w, data); data->type = XFR_TYPE_AIN; - data->msgpref[0] = 'A'; + data->msgpref[XFR_MSG_DLTTR] = 'A'; return KNOTD_EOK; } } } + + rcu_read_unlock(); /* Handle errors. */ - if (ret == KNOT_ENOXFR) { - log_server_warning("%s Finished, %s\n", - data->msgpref, knot_strerror(ret)); - } else if (ret < 0) { - log_server_error("%s %s\n", - data->msgpref, knot_strerror(ret)); + if (!zone_discarded) { + if (ret == KNOT_ENOXFR) { + log_server_warning("%s Finished, %s\n", + data->msgpref, knot_strerror(ret)); + } else if (ret < 0) { + log_server_error("%s %s\n", + data->msgpref, knot_strerror(ret)); + } } /* Check finished zone. */ @@ -683,12 +794,11 @@ int xfr_process_event(xfrworker_t *w, int fd, knot_ns_xfr_t *data, uint8_t *buf, knot_zone_t *zone = (knot_zone_t *)data->zone; zonedata_t *zd = (zonedata_t *)knot_zone_data(zone); - /* Only for successful xfers. */ - if (ret > 0) { + /* Only for successful xfers on non-discarded zones. */ + if (ret > 0 && !zone_discarded) { ret = xfr_xfrin_finalize(w, data); /* AXFR bootstrap timeout. */ - rcu_read_lock(); if (ret != KNOTD_EOK && !knot_zone_contents(zone)) { /* Schedule request (60 - 90s random delay). */ int tmr_s = AXFR_BOOTSTRAP_RETRY; @@ -702,25 +812,11 @@ int xfr_process_event(xfrworker_t *w, int fd, knot_ns_xfr_t *data, uint8_t *buf, /* Update timers. */ server_t *server = (server_t *)knot_ns_get_data(w->ns); zones_timers_update(zone, zd->conf, server->sched); - rcu_read_unlock(); - } else { /* Cleanup */ xfr_xfrin_cleanup(w, data); } - /* Free TSIG buffers. */ - if (data->digest) { - free(data->digest); - data->digest = 0; - data->digest_size = 0; - } - if (data->tsig_data) { - free(data->tsig_data); - data->tsig_data = 0; - data->tsig_data_size = 0; - } - /* Disconnect. */ result = KNOTD_ECONNREFUSED; /* Make it disconnect. */ } @@ -753,6 +849,7 @@ static int xfr_client_start(xfrworker_t *w, knot_ns_xfr_t *data) /* Enqueue to worker that has zone locked for XFR/IN. */ int ret = pthread_mutex_trylock(&zd->xfr_in.lock); + rcu_read_lock(); if (ret != 0) { dbg_xfr_verb("xfr: XFR/IN switching to another thread, " "zone '%s' is already in transfer\n", @@ -769,8 +866,11 @@ static int xfr_client_start(xfrworker_t *w, knot_ns_xfr_t *data) strerror_r(errno, ebuf, sizeof(ebuf)); dbg_xfr("xfr: couldn't write request to evqueue: %s\n", ebuf); + rcu_read_unlock(); return KNOTD_ERROR; } + + rcu_read_unlock(); return KNOTD_EOK; } else { zd->xfr_in.wrkr = w; @@ -798,6 +898,7 @@ static int xfr_client_start(xfrworker_t *w, knot_ns_xfr_t *data) } if (ret < 0) { + rcu_read_unlock(); pthread_mutex_unlock(&zd->xfr_in.lock); if (fd >= 0) { close(fd); @@ -811,6 +912,7 @@ static int xfr_client_start(xfrworker_t *w, knot_ns_xfr_t *data) /* Duplicate existing socket descriptor. */ data->session = dup(data->session); if (data->session < 0) { + rcu_read_unlock(); pthread_mutex_unlock(&zd->xfr_in.lock); log_server_warning("Not enough memory to duplicate \n" "sockets.\n"); @@ -819,12 +921,11 @@ static int xfr_client_start(xfrworker_t *w, knot_ns_xfr_t *data) } /* Fetch zone contents. */ - rcu_read_lock(); const knot_zone_contents_t *contents = knot_zone_contents(zone); if (!contents && data->type == XFR_TYPE_IIN) { pthread_mutex_unlock(&zd->xfr_in.lock); rcu_read_unlock(); - log_server_warning("%s Refusing to start IXFR/IN on zone with no " + log_server_warning("%s Refusing to start IXFR on zone with no " "contents.\n", data->msgpref); close(data->session); data->session = -1; @@ -958,7 +1059,7 @@ static int xfr_answer_ixfr(knot_nameserver_t *ns, knot_ns_xfr_t *xfr) "Fallback to AXFR.\n", xfr->msgpref); xfr->type = XFR_TYPE_AOUT; - xfr->msgpref[0] = 'A'; + xfr->msgpref[XFR_MSG_DLTTR] = 'A'; return xfr_answer_axfr(ns, xfr); } else if (chsload == KNOTD_EMALF) { xfr->rcode = KNOT_RCODE_FORMERR; @@ -973,7 +1074,7 @@ static int xfr_answer_ixfr(knot_nameserver_t *ns, knot_ns_xfr_t *xfr) /* Finally, answer. */ if (chsload == KNOTD_EOK) { ret = knot_ns_answer_ixfr(ns, xfr); - dbg_xfr("xfr: ns_answer_ixfr() = %d.\n", ret); + dbg_xfr("xfr: ns_answer_ixfr() = %s.\n", knot_strerror(ret)); } return ret; @@ -987,6 +1088,7 @@ static int xfr_update_msgpref(knot_ns_xfr_t *req, const char *keytag) return KNOTD_EINVAL; } + rcu_read_lock(); char r_addr[SOCKADDR_STRLEN]; char *r_key = NULL; int r_port = sockaddr_portnum(&req->addr); @@ -1013,13 +1115,12 @@ static int xfr_update_msgpref(knot_ns_xfr_t *req, const char *keytag) } /* Prepare log message. */ - conf_read_lock(); const char *zname = req->zname; if (zname == NULL && req->zone != NULL) { zonedata_t *zd = (zonedata_t *)knot_zone_data(req->zone); if (zd == NULL) { free(r_key); - conf_read_unlock(); + rcu_read_unlock(); return KNOTD_EINVAL; } else { zname = zd->conf->name; @@ -1028,16 +1129,16 @@ static int xfr_update_msgpref(knot_ns_xfr_t *req, const char *keytag) const char *pformat = NULL; switch (req->type) { case XFR_TYPE_AIN: - pformat = "AXFR transfer of '%s/IN' with '%s@%d'%s:"; + pformat = "Incoming AXFR transfer of '%s' with '%s@%d'%s:"; break; case XFR_TYPE_IIN: - pformat = "IXFR transfer of '%s/IN' with '%s@%d'%s:"; + pformat = "Incoming IXFR transfer of '%s' with '%s@%d'%s:"; break; case XFR_TYPE_AOUT: - pformat = "AXFR transfer of '%s/OUT' to '%s@%d'%s:"; + pformat = "Outgoing AXFR transfer of '%s' to '%s@%d'%s:"; break; case XFR_TYPE_IOUT: - pformat = "IXFR transfer of '%s/OUT' to '%s@%d'%s:"; + pformat = "Outgoing IXFR transfer of '%s' to '%s@%d'%s:"; break; case XFR_TYPE_NOTIFY: pformat = "NOTIFY query of '%s' to '%s@%d'%s:"; @@ -1065,7 +1166,7 @@ static int xfr_update_msgpref(knot_ns_xfr_t *req, const char *keytag) req->msgpref = msg; } - conf_read_unlock(); + rcu_read_unlock(); free(r_key); return KNOTD_EOK; } @@ -1277,9 +1378,11 @@ int xfr_answer(knot_nameserver_t *ns, knot_ns_xfr_t *xfr) return KNOTD_EINVAL; } + rcu_read_lock(); int ret = knot_ns_init_xfr(ns, xfr); + int xfr_failed = (ret != KNOT_EOK); - const char * errstr = knot_strerror(ret); + const char *errstr = knot_strerror(ret); // use the QNAME as the zone name to get names also for // zones that are not in the server @@ -1310,6 +1413,23 @@ int xfr_answer(knot_nameserver_t *ns, knot_ns_xfr_t *xfr) } free(keytag); + /* Announce. */ + log_server_info("%s Started.\n", xfr->msgpref); + switch (ret) { + case KNOT_EXFRDENIED: + log_server_info("%s TSIG required, but not found in query.\n", + xfr->msgpref); + break; + case KNOT_TSIG_EBADKEY: + log_server_info("%s Unsupported digest " + "algorithm requested, " + "treating as bad key.\n", + xfr->msgpref); + break; + default: + break; + } + /* Prepare place for TSIG data */ xfr->tsig_data = malloc(KNOT_NS_TSIG_DATA_MAX_SIZE); if (xfr->tsig_data) { @@ -1356,6 +1476,7 @@ int xfr_answer(knot_nameserver_t *ns, knot_ns_xfr_t *xfr) free(xfr->tsig_data); xfr->tsig_data = NULL; xfr_request_deinit(xfr); + rcu_read_unlock(); /* Cleanup. */ free(xfr->digest); @@ -1381,6 +1502,8 @@ static int xfr_process_request(xfrworker_t *w, uint8_t *buf, size_t buflen) return KNOTD_ENOTRUNNING; } + rcu_read_lock(); + /* Update request. */ xfr.wire = buf; xfr.wire_size = buflen; @@ -1389,12 +1512,15 @@ static int xfr_process_request(xfrworker_t *w, uint8_t *buf, size_t buflen) xfr_update_msgpref(&xfr, NULL); /* Check if not already processing. */ - zonedata_t *zd = NULL; - if (xfr.zone != NULL) { - zd = (zonedata_t *)knot_zone_data(xfr.zone); - } + zonedata_t *zd = (zonedata_t *)knot_zone_data(xfr.zone); - conf_read_lock(); + /* Check if the zone is not discarded. */ + if (knot_zone_flags(xfr.zone) & KNOT_ZONE_DISCARDED) { + xfr_request_deinit(&xfr); + knot_zone_release(xfr.zone); + rcu_read_unlock(); + return KNOTD_EOK; + } /* Handle request. */ knot_ns_xfr_t *task = NULL; @@ -1423,6 +1549,7 @@ static int xfr_process_request(xfrworker_t *w, uint8_t *buf, size_t buflen) log_server_error("%s %s\n", xfr.msgpref, knotd_strerror(ret)); } + knot_zone_release(xfr.zone); /* No further access to zone. */ } break; @@ -1431,21 +1558,21 @@ static int xfr_process_request(xfrworker_t *w, uint8_t *buf, size_t buflen) /* Register task. */ task = xfr_register_task(w, &xfr); if (!task) { + knot_zone_release(xfr.zone); /* No further access to zone. */ ret = KNOTD_ENOMEM; - break; + } else { + /* Add timeout. */ + fdset_set_watchdog(w->fdset, task->session, XFR_QUERY_WD); + log_server_info("%s Query issued.\n", xfr.msgpref); + ret = KNOTD_EOK; } - - /* Add timeout. */ - fdset_set_watchdog(w->fdset, task->session, XFR_QUERY_WD); - log_server_info("%s Query issued.\n", xfr.msgpref); - ret = KNOTD_EOK; break; default: log_server_error("Unknown XFR request type (%d).\n", xfr.type); break; } - conf_read_unlock(); + rcu_read_unlock(); /* Deinitialize (it is already registered, or discarded). * Right now, this only frees temporary msgpref. @@ -1506,7 +1633,6 @@ int xfr_worker(dthread_t *thread) fdset_begin(w->fdset, &it); int rfd_event = 0; while(nfds > 0) { - /* Check if it request. */ if (it.fd == rfd) { rfd_event = 1; /* Delay new tasks after processing. */ @@ -1527,6 +1653,8 @@ int xfr_worker(dthread_t *thread) ret = xfr_process_event(w, it.fd, data, buf, buflen); if (ret != KNOTD_EOK) { xfr_free_task(data); + /*! \todo Refactor to allow erase on iterator.*/ + break; } } @@ -1551,6 +1679,11 @@ int xfr_worker(dthread_t *thread) next_sweep.tv_sec += XFR_SWEEP_INTERVAL; } } + + /* Check for interrupt request. */ + if (ret == KNOTD_ENOTRUNNING) { + break; + } } /* Stop whole unit. */ @@ -1559,3 +1692,28 @@ int xfr_worker(dthread_t *thread) thread->data = 0; return KNOTD_EOK; } + +int xfr_prepare_tsig(knot_ns_xfr_t *xfr, knot_key_t *key) +{ + if (xfr == NULL || key == NULL) { + return KNOTD_EINVAL; + } + + int ret = KNOT_EOK; + xfr->tsig_key = key; + xfr->tsig_size = tsig_wire_maxsize(key); + xfr->digest_max_size = tsig_alg_digest_length( + key->algorithm); + xfr->digest = malloc(xfr->digest_max_size); + if (xfr->digest == NULL) { + xfr->tsig_key = NULL; + xfr->tsig_size = 0; + xfr->digest_max_size = 0; + return KNOTD_ENOMEM; + } + memset(xfr->digest, 0 , xfr->digest_max_size); + dbg_xfr("xfr: found TSIG key (MAC len=%zu), adding to transfer\n", + xfr->digest_max_size); + + return ret; +} diff --git a/src/knot/server/xfr-handler.h b/src/knot/server/xfr-handler.h index 02eb189..e2f5643 100644..100755 --- a/src/knot/server/xfr-handler.h +++ b/src/knot/server/xfr-handler.h @@ -170,6 +170,17 @@ int xfr_answer(knot_nameserver_t *ns, knot_ns_xfr_t *req); */ int xfr_worker(dthread_t *thread); +/*! + * \brief Prepare TSIG for XFR. + * \param xfr XFR request. + * \param key Used TSIG key. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL on NULL parameters. + * \retval KNOTD_ENOMEM when out of memory. + */ +int xfr_prepare_tsig(knot_ns_xfr_t *xfr, knot_key_t *key); + #endif // _KNOTD_XFRHANDLER_H_ /*! @} */ diff --git a/src/knot/server/zones.c b/src/knot/server/zones.c index 37c1316..95ab2b1 100644..100755 --- a/src/knot/server/zones.c +++ b/src/knot/server/zones.c @@ -39,6 +39,7 @@ #include "libknot/updates/changesets.h" #include "libknot/tsig-op.h" #include "libknot/packet/response.h" +#include "libknot/zone/zone-diff.h" static const size_t XFRIN_CHANGESET_BINARY_SIZE = 100; static const size_t XFRIN_CHANGESET_BINARY_STEP = 100; @@ -46,7 +47,9 @@ static const size_t XFRIN_BOOTSTRAP_DELAY = 60; /*!< AXFR bootstrap avg. delay * /* Forward declarations. */ static int zones_dump_zone_text(knot_zone_contents_t *zone, const char *zf); - +static int zones_dump_zone_binary(knot_zone_contents_t *zone, + const char *zonedb, + const char *zonefile); /*----------------------------------------------------------------------------*/ /*! @@ -117,11 +120,13 @@ static int zonedata_destroy(knot_zone_t *zone) /* Close IXFR db. */ journal_release(zd->ixfr_db); + + /* Free assigned config. */ + conf_free_zone(zd->conf); free(zd); /* Invalidate. */ - zone->dtor = 0; zone->data = 0; return KNOTD_EOK; @@ -172,7 +177,7 @@ static int zonedata_init(conf_zone_t *cfg, knot_zone_t *zone) 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); + "disabling incoming IXFR. (%s)\n", cfg->name, ebuf); } /* Initialize IXFR database syncing event. */ @@ -180,7 +185,7 @@ static int zonedata_init(conf_zone_t *cfg, knot_zone_t *zone) /* Set and install destructor. */ zone->data = zd; - zone->dtor = zonedata_destroy; + knot_zone_set_dtor(zone, zonedata_destroy); /* Set zonefile SOA serial. */ const knot_rrset_t *soa_rrs = 0; @@ -305,6 +310,12 @@ static int zones_expire_ev(event_t *e) zonedata_t *zd = (zonedata_t *)zone->data; rcu_read_lock(); + /* Check if zone is not discarded. */ + if (knot_zone_flags(zone) & KNOT_ZONE_DISCARDED) { + rcu_read_unlock(); + return KNOTD_EOK; + } + /* Do not issue SOA query if transfer is pending. */ int locked = pthread_mutex_trylock(&zd->xfr_in.lock); if (locked != 0) { @@ -336,10 +347,12 @@ static int zones_expire_ev(event_t *e) pthread_mutex_unlock(&zd->xfr_in.lock); log_server_warning("Non-existent zone expired. Ignoring.\n"); rcu_read_unlock(); - return 0; + return KNOTD_EOK; } /* Publish expired zone. */ + /* Need to keep a reference in case zone get's deleted in meantime. */ + knot_zone_retain(zone); rcu_read_unlock(); synchronize_rcu(); rcu_read_lock(); @@ -368,7 +381,10 @@ static int zones_expire_ev(event_t *e) pthread_mutex_unlock(&zd->xfr_in.lock); rcu_read_unlock(); - return 0; + /* Release holding reference. */ + knot_zone_release(zone); + + return KNOTD_EOK; } /*! @@ -377,16 +393,23 @@ static int zones_expire_ev(event_t *e) static int zones_refresh_ev(event_t *e) { dbg_zones("zones: REFRESH or RETRY timer event\n"); + rcu_read_lock(); knot_zone_t *zone = (knot_zone_t *)e->data; if (zone == NULL || zone->data == NULL) { + rcu_read_unlock(); return KNOTD_EINVAL; } /* Cancel pending timers. */ zonedata_t *zd = (zonedata_t *)knot_zone_data(zone); + + /* Check if zone is not discarded. */ + if (knot_zone_flags(zone) & KNOT_ZONE_DISCARDED) { + rcu_read_unlock(); + return KNOTD_EOK; + } /* Check for contents. */ - rcu_read_lock(); if (!knot_zone_contents(zone)) { /* Bootstrap from XFR master. */ @@ -429,13 +452,20 @@ static int zones_refresh_ev(event_t *e) ++zd->xfr_in.scheduled; pthread_mutex_unlock(&zd->xfr_in.lock); + /* Retain pointer to zone for processing. */ + knot_zone_retain(xfr_req.zone); + /* Unlock zone contents. */ rcu_read_unlock(); /* Mark as finished to prevent stalling. */ evsched_event_finished(e->parent); + int ret = xfr_request(zd->server->xfr_h, &xfr_req); + if (ret != KNOTD_EOK) { + knot_zone_release(xfr_req.zone); /* Discard */ + } + return ret; - return xfr_request(zd->server->xfr_h, &xfr_req); } /* Do not issue SOA query if transfer is pending. */ @@ -485,17 +515,21 @@ static int zones_refresh_ev(event_t *e) size_t buflen = SOCKET_MTU_SZ; - /*! \todo [TSIG] CHANGE!!! only for compatibility now. */ - knot_ns_xfr_t xfr_req; - memset(&xfr_req, 0, sizeof(knot_ns_xfr_t)); - xfr_req.wire = qbuf; + knot_ns_xfr_t req; + memset(&req, 0, sizeof(knot_ns_xfr_t)); + req.wire = qbuf; + + /* Select TSIG key. */ + if (zd->xfr_in.tsig_key.name) { + xfr_prepare_tsig(&req, &zd->xfr_in.tsig_key); + } /* Create query. */ int sock = -1; 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); + int ret = xfrin_create_soa_query(zone->name, &req, &buflen); if (ret == KNOT_EOK) { /* Create socket on random port. */ @@ -548,26 +582,30 @@ static int zones_refresh_ev(event_t *e) evsched_event_finished(e->parent); /* Watch socket. */ - knot_ns_xfr_t req; - memset(&req, 0, sizeof(req)); req.session = sock; req.type = XFR_TYPE_SOA; req.flags |= XFR_FLAG_UDP; req.zone = zone; + req.wire = NULL; memcpy(&req.addr, master, sizeof(sockaddr_t)); memcpy(&req.saddr, &zd->xfr_in.via, sizeof(sockaddr_t)); sockaddr_update(&req.addr); sockaddr_update(&req.saddr); + + /* Retain pointer to zone and issue. */ + knot_zone_retain(req.zone); if (ret == KNOTD_EOK) { ret = xfr_request(zd->server->xfr_h, &req); } if (ret != KNOTD_EOK) { + free(req.digest); + knot_zone_release(req.zone); /* Discard */ log_server_warning("Failed to issue SOA query for zone '%s' (%s).\n", zd->conf->name, errstr); } free(qbuf); - + /* Unlock RCU. */ rcu_read_unlock(); @@ -580,21 +618,28 @@ static int zones_refresh_ev(event_t *e) static int zones_notify_send(event_t *e) { dbg_notify("notify: NOTIFY timer event\n"); - + rcu_read_lock(); notify_ev_t *ev = (notify_ev_t *)e->data; if (ev == NULL) { + rcu_read_unlock(); log_zone_error("NOTIFY invalid event received\n"); return KNOTD_EINVAL; } + knot_zone_t *zone = ev->zone; if (zone == NULL || zone->data == NULL) { + rcu_read_unlock(); log_zone_error("NOTIFY invalid event data received\n"); evsched_event_free(e->parent, e); free(ev); return KNOTD_EINVAL; } - - rcu_read_lock(); + + /* Check if zone is not discarded. */ + if (knot_zone_flags(zone) & KNOT_ZONE_DISCARDED) { + rcu_read_unlock(); /* Event will be freed on zonedata_destroy.*/ + return KNOTD_EOK; + } /* Check for answered/cancelled query. */ zonedata_t *zd = (zonedata_t *)knot_zone_data(zone); @@ -675,7 +720,13 @@ static int zones_notify_send(event_t *e) req.zone = zone; memcpy(&req.addr, &ev->addr, sizeof(sockaddr_t)); memcpy(&req.saddr, &ev->saddr, sizeof(sockaddr_t)); - xfr_request(zd->server->xfr_h, &req); + + /* Retain pointer to zone and issue request. */ + knot_zone_retain(req.zone); + ret = xfr_request(zd->server->xfr_h, &req); + if (ret != KNOTD_EOK) { + knot_zone_release(req.zone); /* Discard */ + } } free(qbuf); @@ -724,6 +775,8 @@ static int zones_zonefile_sync_ev(event_t *e) journal_t *j = journal_retain(zd->ixfr_db); int ret = zones_zonefile_sync(zone, j); journal_release(j); + + rcu_read_lock(); if (ret == KNOTD_EOK) { log_zone_info("Applied differences of '%s' to zonefile.\n", zd->conf->name); @@ -732,13 +785,14 @@ static int zones_zonefile_sync_ev(event_t *e) "to zonefile.\n", zd->conf->name); } + rcu_read_unlock(); /* Reschedule. */ - conf_read_lock(); + rcu_read_lock(); evsched_schedule(e->parent, e, zd->conf->dbsync_timeout * 1000); dbg_zones("zones: next IXFR database SYNC of '%s' in %d seconds\n", zd->conf->name, zd->conf->dbsync_timeout); - conf_read_unlock(); + rcu_read_unlock(); return ret; } @@ -813,11 +867,12 @@ static int zones_set_acl(acl_t **acl, list* acl_list) static int zones_load_zone(knot_zone_t **dst, const char *zone_name, const char *source, const char *filename) { - if (dst == NULL) { + if (dst == NULL || zone_name == NULL || source == NULL) { return KNOTD_EINVAL; } *dst = NULL; + /* Duplicate zone name. */ size_t zlen = strlen(zone_name); char *zname = NULL; if (zlen > 0) { @@ -827,8 +882,13 @@ static int zones_load_zone(knot_zone_t **dst, const char *zone_name, } else { return KNOTD_EINVAL; } - zname[zlen - 1] = '\0'; /* Trim last dot */ + if (filename == NULL) { + log_server_error("No file name for zone '%s'.\n", zname); + free(zname); + return KNOTD_EINVAL; + } + /* Check if the compiled file still exists. */ struct stat st; @@ -841,109 +901,90 @@ static int zones_load_zone(knot_zone_t **dst, const char *zone_name, return KNOTD_EZONEINVAL; } - /* Check path */ - if (filename) { - dbg_zones("zones: parsing zone database '%s'\n", filename); - zloader_t *zl = 0; - int ret = knot_zload_open(&zl, filename); - switch(ret) { - case KNOT_EOK: - /* OK */ - break; - case KNOT_EACCES: - log_server_error("Failed to open compiled zone '%s' " - "(Permission denied).\n", filename); - free(zname); - return KNOTD_EZONEINVAL; - case KNOT_ENOENT: - log_server_error("Couldn't find compiled zone. " - "Please recompile '%s'.\n", zname); - free(zname); - return KNOTD_EZONEINVAL; - case KNOT_ECRC: - log_server_error("Compiled zone db CRC mismatch, " - "db is corrupted or .crc file is " - "deleted. Please recompile '%s'.\n", - zname); - free(zname); - return KNOTD_EZONEINVAL; - case KNOT_EMALF: - log_server_error("Compiled db '%s' is too old. " - "Please recompile '%s'.\n", - filename, zname); - free(zname); - return KNOTD_EZONEINVAL; - case KNOT_EFEWDATA: - case KNOT_ERROR: - case KNOT_ENOMEM: - default: - log_server_error("Failed to load compiled zone file " - "'%s'.\n", filename); - free(zname); - return KNOTD_EZONEINVAL; - } - - /* Check the source file */ - int src_changed = strcmp(source, zl->source) != 0; - if (src_changed || knot_zload_needs_update(zl)) { - log_server_warning("Database for zone '%s' is not " - "up-to-date. Please recompile.\n", - zname); - } - - *dst = knot_zload_load(zl); - - /* Check loaded name. */ - 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(dst, 0); - - } - knot_dname_free(&dname_req); - - /* CLEANUP */ -// knot_zone_contents_dump(zone->contents, 1); -// int errs = knot_zone_contents_integrity_check(zone->contents); -// fprintf(stderr, "INTEGRITY CHECK OF ZONE. ERRORS: %d\n", errs); - - 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(dst, 0); - } else { - knot_zone_set_version(*dst, s.st_mtime); - } - } - + /* Attempt to open compiled zone for loading. */ + int ret = KNOTD_EOK; + zloader_t *zl = NULL; + dbg_zones("zones: parsing zone database '%s'\n", filename); + switch(knot_zload_open(&zl, filename)) { + case KNOT_EOK: + /* OK */ + break; + case KNOT_EACCES: + log_server_error("Failed to open compiled zone '%s' " + "(Permission denied).\n", filename); + free(zname); + return KNOTD_EZONEINVAL; + case KNOT_ENOENT: + log_server_error("Couldn't find compiled zone. " + "Please recompile '%s'.\n", zname); + free(zname); + return KNOTD_EZONEINVAL; + case KNOT_ECRC: + log_server_error("Compiled zone db CRC mismatch, " + "db is corrupted or .crc file is " + "deleted. Please recompile '%s'.\n", + zname); + free(zname); + return KNOTD_EZONEINVAL; + case KNOT_EMALF: + log_server_error("Compiled db '%s' is too old. " + "Please recompile '%s'.\n", + filename, zname); + free(zname); + return KNOTD_EZONEINVAL; + case KNOT_EFEWDATA: + case KNOT_ERROR: + case KNOT_ENOMEM: + default: + log_server_error("Failed to load compiled zone file " + "'%s'.\n", filename); + free(zname); + return KNOTD_EZONEINVAL; + } + + /* Check the source file */ + assert(zl != NULL); + int src_changed = strcmp(source, zl->source) != 0; + if (src_changed || knot_zload_needs_update(zl)) { + log_server_warning("Database for zone '%s' is not " + "up-to-date. Please recompile.\n", + zname); + } + + *dst = knot_zload_load(zl); + if (*dst == NULL) { + log_server_error("Failed to load db '%s' for zone '%s'.\n", + filename, zname); knot_zload_close(zl); - - if (*dst == NULL) { - log_server_error("Failed to load " - "db '%s' for zone '%s'.\n", - filename, zname); - free(zname); - return KNOTD_EZONEINVAL; - } - } else { - /* db is null. */ - log_server_error("No file name for zone '%s'.\n", zname); free(zname); - return KNOTD_EINVAL; + return KNOTD_EZONEINVAL; } - - /* CLEANUP */ -// knot_zone_dump(zone, 1); + + /* Check if loaded origin matches. */ + const knot_dname_t *dname = knot_zone_name(*dst); + knot_dname_t *dname_req = NULL; + dname_req = knot_dname_new_from_str(zone_name, zlen, 0); + if (knot_dname_compare(dname, dname_req) != 0) { + log_server_error("Origin of the zone db file is " + "different than '%s'\n", + zone_name); + knot_zone_deep_free(dst, 0); + ret = KNOTD_EZONEINVAL; + } else { + /* Save the timestamp from the zone db file. */ + if (stat(filename, &st) < 0) { + dbg_zones("zones: failed to stat() zone db, " + "something is seriously wrong\n"); + knot_zone_deep_free(dst, 0); + ret = KNOTD_EZONEINVAL; + } else { + knot_zone_set_version(*dst, st.st_mtime); + } + } + knot_dname_free(&dname_req); + knot_zload_close(zl); free(zname); - - return KNOTD_EOK; + return ret; } /*----------------------------------------------------------------------------*/ @@ -1130,11 +1171,11 @@ static int zones_load_changesets(const knot_zone_t *zone, dbg_zones_detail("Bad arguments: zd->ixfr_db=%p\n", zone->data); return KNOTD_EINVAL; } - - conf_read_lock(); + + rcu_read_lock(); dbg_xfr("xfr: loading changesets for zone '%s' from serial %u to %u\n", zd->conf->name, from, to); - conf_read_unlock(); + rcu_read_unlock(); /* Retain journal for changeset loading. */ journal_t *j = journal_retain(zd->ixfr_db); @@ -1167,7 +1208,7 @@ static int zones_load_changesets(const knot_zone_t *zone, ret = knot_changesets_check_size(dst); --dst->count; if (ret != KNOT_EOK) { - --dst->count; + //--dst->count; dbg_xfr("xfr: failed to check changesets size: %s\n", knot_strerror(ret)); journal_release(j); @@ -1211,10 +1252,10 @@ static int zones_load_changesets(const knot_zone_t *zone, /* Unpack binary data. */ int unpack_ret = zones_changesets_from_binary(dst); - if (unpack_ret != KNOT_EOK) { + if (unpack_ret != KNOTD_EOK) { dbg_xfr("xfr: failed to unpack changesets " - "from binary, %s\n", knot_strerror(unpack_ret)); - return KNOTD_ERROR; + "from binary, %s\n", knotd_strerror(unpack_ret)); + return unpack_ret; } /* Check for complete history. */ @@ -1288,7 +1329,7 @@ static int zones_journal_apply(knot_zone_t *zone) &contents); if (apply_ret != KNOT_EOK) { log_server_error("Failed to apply changesets to" - "'%s' - Apply failed: %s\n", + " '%s' - Apply failed: %s\n", zd->conf->name, knot_strerror(apply_ret)); ret = KNOTD_ERROR; @@ -1297,27 +1338,27 @@ static int zones_journal_apply(knot_zone_t *zone) xfrin_rollback_update(zone->contents, &contents, &chsets->changes); - } - - /* Switch zone immediately. */ - rcu_read_unlock(); - apply_ret = xfrin_switch_zone(zone, contents, - XFR_TYPE_IIN); - rcu_read_lock(); - if (apply_ret == KNOT_EOK) { - xfrin_cleanup_successful_update( - &chsets->changes); } else { - log_server_error("Failed to apply changesets to" - " '%s' - Switch failed: %s\n", - zd->conf->name, - knot_strerror(apply_ret)); - ret = KNOTD_ERROR; - - // Cleanup old and new contents - xfrin_rollback_update(zone->contents, - &contents, - &chsets->changes); + /* Switch zone immediately. */ + rcu_read_unlock(); + apply_ret = xfrin_switch_zone(zone, contents, + XFR_TYPE_IIN); + rcu_read_lock(); + if (apply_ret == KNOT_EOK) { + xfrin_cleanup_successful_update( + &chsets->changes); + } else { + log_server_error("Failed to apply " + "changesets to '%s' - Switch failed: " + "%s\n", zd->conf->name, + knot_strerror(apply_ret)); + ret = KNOTD_ERROR; + + // Cleanup old and new contents + xfrin_rollback_update(zone->contents, + &contents, + &chsets->changes); + } } } } else { @@ -1350,9 +1391,9 @@ static int zones_journal_apply(knot_zone_t *zone) * \retval KNOTD_ERROR on unspecified error. */ static int zones_insert_zone(conf_zone_t *z, knot_zone_t **dst, - knot_nameserver_t *ns, const knot_zonedb_t *db_old) + knot_nameserver_t *ns) { - if (z == NULL || dst == NULL || ns == NULL || db_old == NULL) { + if (z == NULL || dst == NULL || ns == NULL) { return KNOTD_EINVAL; } @@ -1367,17 +1408,19 @@ static int zones_insert_zone(conf_zone_t *z, knot_zone_t **dst, } /* Try to find the zone in the current zone db. */ - knot_zone_t *zone = knot_zonedb_find_zone(db_old, dname); + rcu_read_lock(); + knot_zone_t *zone = knot_zonedb_find_zone(ns->zone_db, dname); + rcu_read_unlock(); /* 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 (zone != NULL) { /* if found, check timestamp of the file against the * loaded zone */ - if (knot_zone_version(zone) < s.st_mtime) { + if (stat_ret == 0 && knot_zone_version(zone) < s.st_mtime) { zone_changed = 1; } } else { @@ -1385,6 +1428,7 @@ static int zones_insert_zone(conf_zone_t *z, knot_zone_t **dst, } /* Reload zone file. */ + int is_bootstrapped = 0; int ret = KNOTD_ERROR; if (zone_changed) { /* Zone file not exists and has master set. */ @@ -1398,9 +1442,7 @@ static int zones_insert_zone(conf_zone_t *z, knot_zone_t **dst, 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); + is_bootstrapped = 1; } else { dbg_zones("zones: failed to create " "stub zone '%s'.\n", z->name); @@ -1410,9 +1452,21 @@ static int zones_insert_zone(conf_zone_t *z, knot_zone_t **dst, 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); + const knot_node_t *apex = NULL; + const knot_rrset_t *soa = NULL; if (ret == KNOTD_EOK) { - log_server_info("Loaded zone '%s'\n", - z->name); + apex = knot_zone_contents_apex( + knot_zone_contents(zone)); + soa = knot_node_rrset(apex, + KNOT_RRTYPE_SOA); + int64_t sn = 0; + if (apex && soa) { + sn = knot_rdata_soa_serial( + knot_rrset_rdata(soa)); + if (sn < 0) sn = 0; + } + log_server_info("Loaded zone '%s' serial %u\n", + z->name, (uint32_t)sn); } } @@ -1425,7 +1479,6 @@ static int zones_insert_zone(conf_zone_t *z, knot_zone_t **dst, /* Initialize zone-related data. */ zonedata_init(z, zone); *dst = zone; - } } else { dbg_zones_verb("zones: found '%s' in old database, " @@ -1442,9 +1495,20 @@ static int zones_insert_zone(conf_zone_t *z, knot_zone_t **dst, if (zone != NULL) { zonedata_t *zd = (zonedata_t *)knot_zone_data(zone); assert(zd != NULL); + + /* Log bootstrapped zone. */ + if (is_bootstrapped) { + log_server_info("Will attempt to bootstrap zone" + " %s from AXFR master in %us.\n", + z->name, + zd->xfr_in.bootstrap_retry / 1000); + } /* Update refs. */ - zd->conf = z; + if (zd->conf != z) { + conf_free_zone(zd->conf); + zd->conf = z; + } /* Update ACLs. */ dbg_zones("Updating zone ACLs.\n"); @@ -1486,7 +1550,13 @@ static int zones_insert_zone(conf_zone_t *z, knot_zone_t **dst, } /* Apply changesets from journal. */ - zones_journal_apply(zone); + int ar = zones_journal_apply(zone); + if (ar != KNOTD_EOK && ar != KNOTD_ERANGE && ar != KNOTD_ENOENT) { + log_server_warning("Failed to apply changesets " + "for zone '%s': %s\n", + z->name, knotd_strerror(ar)); + } + /* Update events scheduled for zone. */ evsched_t *sch = ((server_t *)knot_ns_get_data(ns))->sched; @@ -1526,10 +1596,32 @@ static int zones_insert_zone(conf_zone_t *z, knot_zone_t **dst, rcu_read_unlock(); } + + /* Calculate differences. */ + rcu_read_lock(); + knot_zone_t *z_old = knot_zonedb_find_zone(ns->zone_db, + dname); + /* Ensure both new and old have zone contents. */ + knot_zone_contents_t *zc = knot_zone_get_contents(zone); + knot_zone_contents_t *zc_old = knot_zone_get_contents(z_old); + if (z->build_diffs && zc != NULL && zc_old != NULL && zone_changed) { + int bd = zones_create_and_save_changesets(z_old, zone); + if (bd == KNOTD_ENODIFF) { + log_zone_warning("Zone file for '%s' changed, " + "but serial didn't - " + "won't create changesets.\n", + z->name); + } else if (bd != KNOTD_EOK) { + log_zone_warning("Failed to calculate differences" + " from the zone file update: " + "%s\n", knotd_strerror(bd)); + } + } + rcu_read_unlock(); } /* CLEANUP */ -// knot_zone_contents_dump(knot_zone_get_contents(zone), 1); +// knot_zone_contents_dump(knot_zone_get_contents(zone), 1); /* Directly discard zone. */ knot_dname_free(&dname); @@ -1539,8 +1631,7 @@ static int zones_insert_zone(conf_zone_t *z, knot_zone_t **dst, /*! \brief Structure for multithreaded zone loading. */ struct zonewalk_t { knot_nameserver_t *ns; - const knot_zonedb_t *db_old; - knot_zonedb_t *db_new; + knot_zonedb_t *db_new; pthread_mutex_t lock; int inserted; unsigned qhead; @@ -1581,8 +1672,7 @@ static int zonewalker(dthread_t *thread) continue; } - int ret = zones_insert_zone(zw->q[i], zones + inserted, zw->ns, - zw->db_old); + int ret = zones_insert_zone(zw->q[i], zones + inserted, zw->ns); if (ret == KNOTD_EOK) { ++inserted; } @@ -1592,11 +1682,15 @@ static int zonewalker(dthread_t *thread) pthread_mutex_lock(&zw->lock); zw->inserted += inserted; for (int i = 0; i < inserted; ++i) { + zonedata_t *zd = (zonedata_t *)knot_zone_data(zones[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); + } else { + /* Unlink zone config from conf(), + * transferring ownership to zonedata. */ + rem_node(&zd->conf->n); } } pthread_mutex_unlock(&zw->lock); @@ -1613,14 +1707,12 @@ static int zonewalker(dthread_t *thread) * * \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; @@ -1636,7 +1728,6 @@ static int zones_insert_zones(knot_nameserver_t *ns, 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) { @@ -1713,6 +1804,18 @@ dbg_zones_exec( "from database.\n", name); free(name); ); + /* Invalidate ACLs - since we would need to copy each + * remote data and keep ownership, I think it's no harm + * to drop all ACLs for the discarded zone. + * refs #1976 */ + zonedata_t *zd = (zonedata_t*)knot_zone_data(old_zone); + conf_zone_t *zconf = zd->conf; + WALK_LIST_FREE(zconf->acl.xfr_in); + WALK_LIST_FREE(zconf->acl.xfr_out); + WALK_LIST_FREE(zconf->acl.notify_in); + WALK_LIST_FREE(zconf->acl.notify_out); + + /* Remove from zone db. */ knot_zone_t * rm = knot_zonedb_remove_zone(db_old, knot_zone_name(old_zone)); assert(rm == old_zone); @@ -1758,8 +1861,10 @@ static int zones_verify_tsig_query(const knot_packet_t *query, /* * 2) Find the particular key used by the TSIG. + * Check not only name, but also the algorithm. */ - if (key && kname && knot_dname_compare(key->name, kname) == 0) { + if (key && kname && knot_dname_compare(key->name, kname) == 0 + && key->algorithm == alg) { dbg_zones_verb("Found claimed TSIG key for comparison\n"); } else { *rcode = KNOT_RCODE_NOTAUTH; @@ -1848,18 +1953,19 @@ static int zones_check_tsig_query(const knot_zone_t *zone, assert(rcode != NULL); assert(tsig_key_zone != NULL); - const knot_rrset_t *tsig = NULL; + const knot_rrset_t *tsig = knot_packet_tsig(query); - if (knot_packet_additional_rrset_count(query) > 0) { - /*! \todo warning */ - tsig = knot_packet_additional_rrset(query, - knot_packet_additional_rrset_count(query) - 1); - if (knot_rrset_type(tsig) == KNOT_RRTYPE_TSIG) { - dbg_zones_verb("found TSIG in normal query\n"); - } else { - tsig = NULL; /* Invalidate if not TSIG RRTYPE. */ - } - } + // not required, TSIG is already found +// if (knot_packet_additional_rrset_count(query) > 0) { +// /*! \todo warning */ +// tsig = knot_packet_additional_rrset(query, +// knot_packet_additional_rrset_count(query) - 1); +// if (knot_rrset_type(tsig) == KNOT_RRTYPE_TSIG) { +// dbg_zones_verb("found TSIG in normal query\n"); +// } else { +// tsig = NULL; /* Invalidate if not TSIG RRTYPE. */ +// } +// } if (tsig == NULL) { // no TSIG, this is completely valid @@ -1894,7 +2000,7 @@ static int zones_check_tsig_query(const knot_zone_t *zone, } // save TSIG RR to query structure - knot_packet_set_tsig(query, tsig); +// knot_packet_set_tsig(query, tsig); return ret; } @@ -1913,34 +2019,39 @@ int zones_update_db_from_config(const conf_t *conf, knot_nameserver_t *ns, /* Lock RCU to ensure none will deallocate any data under our hands. */ rcu_read_lock(); - + /* Grab a pointer to the old database */ - *db_old = ns->zone_db; - if (*db_old == NULL) { + if (ns->zone_db == NULL) { + rcu_read_unlock(); log_server_error("Missing zone database in nameserver structure" ".\n"); - rcu_read_unlock(); return KNOTD_ERROR; } + rcu_read_unlock(); /* Create new zone DB */ knot_zonedb_t *db_new = knot_zonedb_new(); if (db_new == NULL) { - rcu_read_unlock(); return KNOTD_ERROR; } log_server_info("Loading %d compiled zones...\n", conf->zones_count); /* Insert all required zones to the new zone DB. */ - int inserted = zones_insert_zones(ns, &conf->zones, *db_old, db_new); - + /*! \warning RCU must not be locked as some contents switching will + be required. */ + int inserted = zones_insert_zones(ns, &conf->zones, db_new); + log_server_info("Loaded %d out of %d zones.\n", inserted, conf->zones_count); if (inserted != conf->zones_count) { log_server_warning("Not all the zones were loaded.\n"); } + + /* Lock RCU to ensure none will deallocate any data under our hands. */ + rcu_read_lock(); + *db_old = ns->zone_db; dbg_zones_detail("zones: old db in nameserver: %p, old db stored: %p, " "new db: %p\n", ns->zone_db, *db_old, db_new); @@ -2020,19 +2131,29 @@ int zones_zonefile_sync(knot_zone_t *zone, journal_t *journal) if (zd->zonefile_serial != serial_to) { /* Save zone to zonefile. */ - conf_read_lock(); dbg_zones("zones: syncing '%s' differences to '%s' " "(SOA serial %u)\n", zd->conf->name, zd->conf->file, serial_to); ret = zones_dump_zone_text(contents, zd->conf->file); if (ret != KNOTD_EOK) { - dbg_zones("zones: failed to sync '%s' to '%s'\n", - zd->conf->name, zd->conf->file); + log_zone_warning("Failed to apply differences " + "'%s' to '%s'\n", + zd->conf->name, zd->conf->file); pthread_mutex_unlock(&zd->lock); rcu_read_unlock(); return ret; } - conf_read_unlock(); + + /* Save zone to binary db file. */ + ret = zones_dump_zone_binary(contents, zd->conf->db, zd->conf->file); + if (ret != KNOTD_EOK) { + log_zone_warning("Failed to apply differences " + "'%s' to '%s'\n", + zd->conf->name, zd->conf->db); + pthread_mutex_unlock(&zd->lock); + rcu_read_unlock(); + return KNOTD_ERROR; + } /* Update journal entries. */ dbg_zones_verb("zones: unmarking all dirty nodes " @@ -2144,15 +2265,16 @@ int zones_normal_query_answer(knot_nameserver_t *nameserver, ? *rsize : 0); // check for TSIG in the query - if (knot_packet_additional_rrset_count(query) > 0) { - /*! \todo warning */ - const knot_rrset_t *tsig = knot_packet_additional_rrset(query, - knot_packet_additional_rrset_count(query) - 1); - if (knot_rrset_type(tsig) == KNOT_RRTYPE_TSIG) { - dbg_zones_verb("found TSIG in normal query\n"); - knot_packet_set_tsig(query, tsig); - } - } + // not required, TSIG is already found if it is there +// if (knot_packet_additional_rrset_count(query) > 0) { +// /*! \todo warning */ +// const knot_rrset_t *tsig = knot_packet_additional_rrset(query, +// knot_packet_additional_rrset_count(query) - 1); +// if (knot_rrset_type(tsig) == KNOT_RRTYPE_TSIG) { +// dbg_zones_verb("found TSIG in normal query\n"); +// knot_packet_set_tsig(query, tsig); +// } +// } knot_rcode_t rcode = 0; @@ -2170,7 +2292,10 @@ int zones_normal_query_answer(knot_nameserver_t *nameserver, break; } - if (zone == NULL && knot_packet_tsig(query) == NULL) { + if (rcode == KNOT_RCODE_NOERROR + && ((zone == NULL && knot_packet_tsig(query) == NULL) + || (knot_packet_qclass(query) != KNOT_CLASS_IN + && knot_packet_qclass(query) != KNOT_CLASS_ANY))) { /*! \todo If there is TSIG, this should be probably handled * as a key error. */ @@ -2181,10 +2306,9 @@ 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), - &query->header.flags1, - rcode, resp_wire, rsize); + knot_ns_error_response_from_query(nameserver, query, + rcode, resp_wire, + rsize); rcu_read_unlock(); return KNOT_EOK; } @@ -2198,7 +2322,8 @@ int zones_normal_query_answer(knot_nameserver_t *nameserver, assert(rcode == KNOT_RCODE_NOERROR); uint16_t tsig_rcode = 0; knot_key_t *tsig_key_zone = NULL; - uint64_t tsig_prev_time_signed = 0; /*! \todo Verify, as it was uninitialized! */ + uint64_t tsig_prev_time_signed = 0; + /*! \todo Verify, as it was uninitialized! */ size_t answer_size = *rsize; int ret = KNOT_EOK; @@ -2206,6 +2331,7 @@ int zones_normal_query_answer(knot_nameserver_t *nameserver, if (zone == NULL) { assert(knot_packet_tsig(query) != NULL); // treat as BADKEY error + /*! \todo Is this OK?? */ rcode = KNOT_RCODE_NOTAUTH; tsig_rcode = KNOT_TSIG_RCODE_BADKEY; ret = KNOT_TSIG_EBADKEY; @@ -2228,8 +2354,20 @@ int zones_normal_query_answer(knot_nameserver_t *nameserver, tsig_wire_maxsize(tsig_key_zone); knot_packet_set_tsig_size(resp, tsig_max_size); } - ret = knot_ns_answer_normal(nameserver, zone, resp, - resp_wire, &answer_size); + + // handle IXFR queries + if (knot_packet_qtype(query) == KNOT_RRTYPE_IXFR) { + assert(transport == NS_TRANSPORT_UDP); + ret = knot_ns_answer_ixfr_udp(nameserver, zone, + resp, resp_wire, + &answer_size); + } else { + ret = knot_ns_answer_normal(nameserver, zone, + resp, resp_wire, + &answer_size, + transport == + NS_TRANSPORT_UDP); + } dbg_zones_detail("rsize = %zu\n", *rsize); dbg_zones_detail("answer_size = %zu\n", answer_size); @@ -2334,6 +2472,9 @@ int zones_normal_query_answer(knot_nameserver_t *nameserver, tsig_rdata_mac_length(tsig), digest, &digest_size, tsig_key_zone, tsig_rcode, tsig_prev_time_signed); + + // no need to keep the digest + free(digest); *rsize = answer_size; } else { @@ -2385,6 +2526,7 @@ int zones_process_response(knot_nameserver_t *nameserver, } /* Find matching zone and ID. */ + rcu_read_lock(); const knot_dname_t *zone_name = knot_packet_qname(packet); /*! \todo Change the access to the zone db. */ knot_zone_t *zone = knot_zonedb_find_zone( @@ -2392,7 +2534,6 @@ int zones_process_response(knot_nameserver_t *nameserver, zone_name); /* Get zone contents. */ - rcu_read_lock(); const knot_zone_contents_t *contents = knot_zone_contents(zone); @@ -2423,17 +2564,10 @@ int zones_process_response(knot_nameserver_t *nameserver, evsched_t *sched = ((server_t *)knot_ns_get_data(nameserver))->sched; if (ret == 0) { - char r_addr[SOCKADDR_STRLEN]; - int r_port = sockaddr_portnum(from); - sockaddr_tostr(from, r_addr, sizeof(r_addr)); - log_zone_info("SOA query of '%s' to '%s@%d': Answered, no " - "transfer needed.\n", - zd->conf->name, r_addr, r_port); - /* Reinstall timers. */ zones_timers_update(zone, zd->conf, sched); rcu_read_unlock(); - return KNOTD_EOK; + return KNOTD_EUPTODATE; } assert(ret > 0); @@ -2471,9 +2605,13 @@ int zones_process_response(knot_nameserver_t *nameserver, /* Unlock zone contents. */ rcu_read_unlock(); - /* Enqueue XFR request. */ - return xfr_request(((server_t *)knot_ns_get_data( - nameserver))->xfr_h, &xfr_req); + /* Retain pointer to zone for processing. */ + knot_zone_retain(xfr_req.zone); + ret = xfr_request(((server_t *)knot_ns_get_data( + nameserver))->xfr_h, &xfr_req); + if (ret != KNOTD_EOK) { + knot_zone_release(xfr_req.zone); /* Discard */ + } } return KNOTD_EOK; @@ -2492,45 +2630,6 @@ knot_ns_xfr_type_t zones_transfer_to_use(zonedata_t *data) /*----------------------------------------------------------------------------*/ -static int zones_find_zone_for_xfr(const knot_zone_contents_t *zone, - const char **zonefile, const char **zonedb) -{ - /* find the zone file name and zone db file name for the zone */ - conf_t *cnf = conf(); - node *n = NULL; - WALK_LIST(n, cnf->zones) { - conf_zone_t *zone_conf = (conf_zone_t *)n; - knot_dname_t *zone_name = knot_dname_new_from_str( - zone_conf->name, strlen(zone_conf->name), NULL); - if (zone_name == NULL) { - return KNOTD_ENOMEM; - } - - int r = knot_dname_compare(zone_name, knot_node_owner( - knot_zone_contents_apex(zone))); - - /* Directly discard dname, won't be needed. */ - knot_dname_free(&zone_name); - - if (r == 0) { - /* found the right zone */ - *zonefile = zone_conf->file; - *zonedb = zone_conf->db; - return KNOTD_EOK; - } - } - - char *name = knot_dname_to_str(knot_node_owner( - knot_zone_contents_apex(zone))); - dbg_zones("zones: no zone found for the zone received by transfer " - "(%s).\n", name); - free(name); - - return KNOTD_ENOENT; -} - -/*----------------------------------------------------------------------------*/ - static int zones_open_free_filename(const char *old_name, char **new_name) { /* find zone name not present on the disk */ @@ -2571,7 +2670,6 @@ static int zones_dump_zone_text(knot_zone_contents_t *zone, const char *fname) 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; @@ -2580,11 +2678,14 @@ static int zones_dump_zone_text(knot_zone_contents_t *zone, const char *fname) if (zone_dump_text(zone, f) != KNOTD_EOK) { log_zone_warning("Failed to save the transferred zone to '%s'.\n", new_fname); - close(fd); + fclose(f); unlink(new_fname); free(new_fname); return KNOTD_ERROR; } + + /* Set zone file rights to 0640. */ + fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); /* Swap temporary zonefile and new zonefile. */ fclose(f); @@ -2596,8 +2697,7 @@ static int zones_dump_zone_text(knot_zone_contents_t *zone, const char *fname) free(new_fname); return KNOTD_ERROR; } - - + free(new_fname); return KNOTD_EOK; } @@ -2619,18 +2719,23 @@ static int zones_dump_zone_binary(knot_zone_contents_t *zone, return KNOTD_ERROR; } - crc_t crc_value; + crc_t crc_value = 0; if (knot_zdump_dump(zone, fd, zonefile, &crc_value) != KNOT_EOK) { close(fd); unlink(new_zonedb); free(new_zonedb); return KNOTD_ERROR; } + + /* Set compiled zone rights to 0640. */ + fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); + + /* Close compiled zone. */ + close(fd); /* Delete old CRC file. */ char *zonedb_crc = knot_zdump_crc_file(zonedb); if (zonedb_crc == NULL) { - close(fd); unlink(new_zonedb); free(new_zonedb); return KNOTD_ENOMEM; @@ -2643,7 +2748,6 @@ static int zones_dump_zone_binary(knot_zone_contents_t *zone, dbg_zdump("Failed to create CRC file path from %s.\n", new_zonedb); free(zonedb_crc); - close(fd); unlink(new_zonedb); free(new_zonedb); return KNOTD_ENOMEM; @@ -2654,13 +2758,18 @@ static int zones_dump_zone_binary(knot_zone_contents_t *zone, if (f_crc == NULL) { dbg_zdump("Cannot open CRC file %s!\n", zonedb_crc); + free(zonedb_crc); unlink(new_zonedb); + free(new_zonedb); return KNOTD_ERROR; } else { fprintf(f_crc, "%lu\n", (unsigned long)crc_value); fclose(f_crc); } + + /* Set CRC file rights to 0640. */ + chmod(new_zonedb_crc, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); /* Swap CRC files. */ int ret = KNOTD_EOK; @@ -2689,7 +2798,6 @@ static int zones_dump_zone_binary(knot_zone_contents_t *zone, free(new_zonedb_crc); free(zonedb_crc); - close(fd); free(new_zonedb); @@ -2700,33 +2808,48 @@ static int zones_dump_zone_binary(knot_zone_contents_t *zone, int zones_save_zone(const knot_ns_xfr_t *xfr) { - if (xfr == NULL || xfr->new_contents == NULL) { + if (xfr == NULL || xfr->new_contents == NULL || xfr->zone == NULL) { return KNOTD_EINVAL; } - knot_zone_contents_t *zone = xfr->new_contents; - - const char *zonefile = NULL; - const char *zonedb = NULL; + rcu_read_lock(); - int ret = zones_find_zone_for_xfr(zone, &zonefile, &zonedb); - if (ret != KNOTD_EOK) { - return ret; + zonedata_t *zd = (zonedata_t *)knot_zone_data(xfr->zone); + knot_zone_contents_t *new_zone = xfr->new_contents; + + const char *zonefile = zd->conf->file; + const char *zonedb = zd->conf->db; + + /* Check if the new zone apex dname matches zone name. */ + knot_dname_t *cur_name = knot_dname_new_from_str(zd->conf->name, + strlen(zd->conf->name), + NULL); + const knot_dname_t *new_name = NULL; + new_name = knot_node_owner(knot_zone_contents_apex(new_zone)); + int r = knot_dname_compare(cur_name, new_name); + knot_dname_free(&cur_name); + if (r != 0) { + rcu_read_unlock(); + return KNOTD_EINVAL; } assert(zonefile != NULL && zonedb != NULL); /* dump the zone into text zone file */ - ret = zones_dump_zone_text(zone, zonefile); + int ret = zones_dump_zone_text(new_zone, zonefile); if (ret != KNOTD_EOK) { + rcu_read_unlock(); return KNOTD_ERROR; } /* dump the zone into binary db file */ - ret = zones_dump_zone_binary(zone, zonedb, zonefile); + ret = zones_dump_zone_binary(new_zone, zonedb, zonefile); if (ret != KNOTD_EOK) { + rcu_read_unlock(); return KNOTD_ERROR; } + rcu_read_unlock(); + return KNOTD_EOK; } @@ -2970,10 +3093,10 @@ static int zones_store_changeset(const knot_changeset_t *chs, journal_t *j, /* Reschedule sync timer. */ if (tmr) { /* Fetch sync timeout. */ - conf_read_lock(); + rcu_read_lock(); int timeout = zd->conf->dbsync_timeout; timeout *= 1000; /* Convert to ms. */ - conf_read_unlock(); + rcu_read_unlock(); /* Reschedule. */ dbg_xfr_verb("xfr: resuming SYNC " @@ -3145,6 +3268,79 @@ int zones_xfr_load_changesets(knot_ns_xfr_t *xfr, uint32_t serial_from, /*----------------------------------------------------------------------------*/ +int zones_create_and_save_changesets(const knot_zone_t *old_zone, + const knot_zone_t *new_zone) +{ + if (old_zone == NULL || old_zone->contents == NULL + || new_zone == NULL || new_zone->contents == NULL) { + dbg_zones("zones: create_changesets: " + "NULL arguments.\n"); + return KNOTD_EINVAL; + } + + knot_ns_xfr_t xfr; + memset(&xfr, 0, sizeof(xfr)); + xfr.zone = (knot_zone_t *)old_zone; + knot_changesets_t *changesets; + int ret = knot_zone_diff_create_changesets(old_zone->contents, + new_zone->contents, + &changesets); + if (ret != KNOT_EOK) { + if (ret == KNOT_ERANGE) { + dbg_zones_detail("zones: create_changesets: " + "New serial was lower than the old " + "one.\n"); + knot_free_changesets(&changesets); + return KNOTD_ERANGE; + } else if (ret == KNOT_ENODIFF) { + dbg_zones_detail("zones: create_changesets: " + "New serial was the same as the old " + "one.\n"); + knot_free_changesets(&changesets); + return KNOTD_ENODIFF; + } else { + dbg_zones("zones: create_changesets: " + "Could not create changesets. Reason: %s\n", + knot_strerror(ret)); + knot_free_changesets(&changesets); + return KNOTD_ERROR; + } + } + + xfr.data = changesets; + journal_t *journal = zones_store_changesets_begin(&xfr); + if (journal == NULL) { + dbg_zones("zones: create_changesets: " + "Could not start journal operation.\n"); + return KNOTD_ERROR; + } + + ret = zones_store_changesets(&xfr); + if (ret != KNOTD_EOK) { + zones_store_changesets_rollback(journal); + dbg_zones("zones: create_changesets: " + "Could not store in the journal. Reason: %s.\n", + knotd_strerror(ret)); + + return ret; + } + + ret = zones_store_changesets_commit(journal); + if (ret != KNOTD_EOK) { + dbg_zones("zones: create_changesets: " + "Could not commit to journal. Reason: %s.\n", + knotd_strerror(ret)); + + return ret; + } + + knot_free_changesets(&changesets); + + return KNOTD_EOK; +} + +/*----------------------------------------------------------------------------*/ + int zones_timers_update(knot_zone_t *zone, conf_zone_t *cfzone, evsched_t *sch) { if (!sch || !zone) { @@ -3180,7 +3376,7 @@ int zones_timers_update(knot_zone_t *zone, conf_zone_t *cfzone, evsched_t *sch) pthread_mutex_unlock(&zd->lock); /* Check XFR/IN master server. */ - conf_read_lock(); + rcu_read_lock(); if (zd->xfr_in.master.ptr) { /* Schedule REFRESH timer. */ @@ -3198,13 +3394,12 @@ int zones_timers_update(knot_zone_t *zone, conf_zone_t *cfzone, evsched_t *sch) /* Do not issue NOTIFY queries if stub. */ if (!knot_zone_contents(zone)) { - conf_read_unlock(); + rcu_read_unlock(); return KNOTD_EOK; } /* Schedule NOTIFY to slaves. */ conf_remote_t *r = 0; - conf_read_lock(); WALK_LIST(r, cfzone->acl.notify_out) { /* Fetch remote. */ @@ -3257,7 +3452,7 @@ int zones_timers_update(knot_zone_t *zone, conf_zone_t *cfzone, evsched_t *sch) tmr_s, cfg_if->address, cfg_if->port); } - conf_read_unlock(); + rcu_read_unlock(); return KNOTD_EOK; } @@ -3275,7 +3470,10 @@ int zones_cancel_notify(zonedata_t *zd, notify_ev_t *ev) event_t *tmr = ev->timer; ev->timer = 0; pthread_mutex_unlock(&zd->lock); - evsched_cancel(tmr->parent, tmr); + if (evsched_cancel(tmr->parent, tmr) == 0) { + dbg_notify("notify: NOTIFY event %p designated for cancellation " + "not found\n", tmr); + } /* Re-lock and find again (if not deleted). */ pthread_mutex_lock(&zd->lock); diff --git a/src/knot/server/zones.h b/src/knot/server/zones.h index bb95b93..65e5a61 100644..100755 --- a/src/knot/server/zones.h +++ b/src/knot/server/zones.h @@ -59,7 +59,7 @@ typedef struct zonedata_t /*! \brief Zone data lock for exclusive access. */ pthread_mutex_t lock; - + /*! \brief Access control lists. */ acl_t *xfr_out; /*!< ACL for xfr-out.*/ acl_t *notify_in; /*!< ACL for notify-in.*/ @@ -272,6 +272,23 @@ int zones_xfr_load_changesets(knot_ns_xfr_t *xfr, uint32_t serial_from, uint32_t serial_to); /*! + * \brief Creates changesets from zones difference. + * + * Also saves changesets to journal, which is taken from old zone. + * + * \param old_zone Old zone, previously served by server. + * \param new_zone New zone, to be served by server, after creating changesets. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL on invalid arguments. + * \retval KNOTD_ERANGE when new serial is lower than the old one. + * \retval KNOTD_ENODIFF when new zone's serial are equal. + * \retval KNOTD_ERROR when there was error creating changesets. + */ +int zones_create_and_save_changesets(const knot_zone_t *old_zone, + const knot_zone_t *new_zone); + +/*! * \brief Update zone timers. * * REFRESH/RETRY/EXPIRE timers are updated according to SOA. diff --git a/src/knot/stat/gatherer.c b/src/knot/stat/gatherer.c index 5b8eab6..5b8eab6 100644..100755 --- a/src/knot/stat/gatherer.c +++ b/src/knot/stat/gatherer.c diff --git a/src/knot/stat/gatherer.h b/src/knot/stat/gatherer.h index 62b3939..62b3939 100644..100755 --- a/src/knot/stat/gatherer.h +++ b/src/knot/stat/gatherer.h diff --git a/src/knot/stat/stat-common.h b/src/knot/stat/stat-common.h index 032e32b..032e32b 100644..100755 --- a/src/knot/stat/stat-common.h +++ b/src/knot/stat/stat-common.h diff --git a/src/knot/stat/stat.c b/src/knot/stat/stat.c index a473085..a473085 100644..100755 --- a/src/knot/stat/stat.c +++ b/src/knot/stat/stat.c diff --git a/src/knot/stat/stat.h b/src/knot/stat/stat.h index 0cf1454..0cf1454 100644..100755 --- a/src/knot/stat/stat.h +++ b/src/knot/stat/stat.h diff --git a/src/knot/zone/semantic-check.c b/src/knot/zone/semantic-check.c index fc20c29..20043df 100644..100755 --- a/src/knot/zone/semantic-check.c +++ b/src/knot/zone/semantic-check.c @@ -16,8 +16,7 @@ static char *error_messages[(-ZC_ERR_ALLOC) + 1] = { [-ZC_ERR_ALLOC] = "Memory allocation error!\n", [-ZC_ERR_MISSING_SOA] = "SOA record missing in zone!\n", - [-ZC_ERR_MISSING_NS_DEL_POINT] = "NS record missing in zone apex or in " - "delegation point!\n", + [-ZC_ERR_MISSING_NS_DEL_POINT] = "NS record missing in zone apex!\n", [-ZC_ERR_RRSIG_RDATA_TYPE_COVERED] = "RRSIG: Type covered rdata field is wrong!\n", @@ -169,7 +168,7 @@ int err_handler_handle_error(err_handler_t *handler, return KNOT_EBADARG; } - /*!< \todo this is so wrong! This should not even return anything. */ + /*!< \todo #1886 this is so wrong! Should not even return anything. */ if (error == ZC_ERR_ALLOC || error == 0) { return KNOT_EBADARG; } @@ -262,9 +261,11 @@ static int check_cname_cycles_in_zone(knot_zone_contents_t *zone, const knot_node_t *next_node = NULL; uint i = 0; - - assert(tmp_rdata); - + + if (tmp_rdata == NULL) { + return KNOT_EOK; + } + const knot_dname_t *next_dname = knot_rdata_cname_name(tmp_rdata); /* (cname_name == dname_target) */ @@ -330,6 +331,7 @@ static int check_cname_cycles_in_zone(knot_zone_contents_t *zone, } else if ((knot_dname_is_fqdn(next_dname_copy) && knot_dname_label_count(next_dname_copy) == 0)) { knot_dname_free(&next_dname_copy); + knot_dname_free(&tmp_chopped); /* Root domain, end of search. */ break; } @@ -367,7 +369,7 @@ static int check_cname_cycles_in_zone(knot_zone_contents_t *zone, next_dname); } -/*!< \todo this might replace some of the code above. */ +/*!< \todo #1887 this might replace some of the code above. */ // /* Still NULL, try wildcards. */ // if (next_node == NULL && knot_dname_is_wildcard(next_dname)) { // /* We can only use the wildcard so many times. */ @@ -390,7 +392,6 @@ static int check_cname_cycles_in_zone(knot_zone_contents_t *zone, knot_dname_t *chopped_next = knot_dname_left_chop(next_dname); if (chopped_next == NULL) { - /*!< \todo check. */ return KNOT_ERROR; } while (next_node == NULL && chopped_next != NULL) { @@ -422,7 +423,7 @@ static int check_cname_cycles_in_zone(knot_zone_contents_t *zone, if (next_node != NULL) { next_rrset = knot_node_rrset(next_node, rrset->type); - if (next_rrset != NULL) { + if (next_rrset != NULL && next_rrset->rdata != NULL) { next_dname = knot_rdata_cname_name(next_rrset->rdata); } else { @@ -477,7 +478,6 @@ uint16_t type_covered_from_rdata(const knot_rdata_t *rdata) static int check_dnskey_rdata(const knot_rdata_t *rdata) { /* check that Zone key bit it set - position 7 in net order */ - /*! \todo FIXME: endian? I swear I've fixed this already, it was 7 i guesss*/ uint16_t mask = 1 << 8; //0b0000000100000000; uint16_t flags = @@ -570,7 +570,6 @@ static int dnskey_to_wire(const knot_rdata_t *rdata, uint8_t **wire, /* copy the wire octet by octet */ - /* TODO check if we really have that many items */ if (rdata->count < 4) { free(*wire); *wire = NULL; @@ -754,28 +753,34 @@ static int check_rrsig_in_rrset(const knot_rrset_t *rrset, return ZC_ERR_RRSIG_TTL; } - /* Check whether all rrsets have their rrsigs */ const knot_rdata_t *tmp_rdata = knot_rrset_rdata(rrset); const knot_rdata_t *tmp_rrsig_rdata = knot_rrset_rdata(rrsigs); - - assert(tmp_rdata); - assert(tmp_rrsig_rdata); + + assert(tmp_rrsig_rdata != NULL); + if (tmp_rdata == NULL) { + /* Only RRSIG, valid, but we can't check anything. */ + return KNOT_EOK; + } + int ret = 0; - char all_signed = tmp_rdata && tmp_rrsig_rdata; do { if ((ret = check_rrsig_rdata(tmp_rrsig_rdata, rrset, dnskey_rrset)) != 0) { + /*!< \todo This should go to handler. */ return ret; } - - all_signed = tmp_rdata && tmp_rrsig_rdata; - } while (((tmp_rdata = knot_rrset_rdata_next(rrset, tmp_rdata)) - != NULL) && - ((tmp_rrsig_rdata = - knot_rrset_rdata_next(rrsigs, tmp_rrsig_rdata)) - != NULL)); - + tmp_rdata = knot_rrset_rdata_next(rrset, tmp_rdata); + tmp_rrsig_rdata = knot_rrset_rdata_next(rrsigs, + tmp_rrsig_rdata); + } while (tmp_rdata != NULL && tmp_rrsig_rdata != NULL); + + /*!< \todo JK 03-08-2012 #1972 + * This check is not very informative, its output + * does not contain any info about which RRSet is not completely signed. + * A rewrite is needed. + */ + char all_signed = tmp_rdata == NULL && tmp_rrsig_rdata == NULL; if (!all_signed) { return ZC_ERR_RRSIG_NOT_ALL; } @@ -992,10 +997,6 @@ static int check_nsec3_node_in_zone(knot_zone_contents_t *zone, knot_node_t *nod /* Directly discard. */ knot_dname_free(&next_dname); - /*!< \todo These comments are not accurate anymore. */ - /* This is probably not sufficient, but again, it is covered in - * zone load time */ - uint count; uint16_t *array = NULL; if (rdata_nsec_to_type_array( @@ -1104,8 +1105,9 @@ static int semantic_checks_plain(knot_zone_contents_t *zone, } } - if (knot_rrset_rdata(cname_rrset)->next != - knot_rrset_rdata(cname_rrset)) { + if (knot_rrset_rdata(cname_rrset) && + knot_rrset_rdata(cname_rrset)->next != + knot_rrset_rdata(cname_rrset)) { *fatal_error = 1; err_handler_handle_error(handler, node, ZC_ERR_CNAME_MULTIPLE); @@ -1169,7 +1171,7 @@ static int semantic_checks_plain(knot_zone_contents_t *zone, return KNOT_EOK; } - /*!< \todo Good Lord, move this to ist own function. */ + /*!< \todo #1887 Good Lord, move this to ist own function. */ /* check for glue records at zone cuts and in apex. */ if (knot_node_is_deleg_point(node) || knot_zone_contents_apex(zone) == @@ -1184,10 +1186,12 @@ static int semantic_checks_plain(knot_zone_contents_t *zone, //FIXME this should be an error as well ! (i guess) knot_dname_t *ns_dname = + knot_dname_deep_copy( knot_rdata_get_item(knot_rrset_rdata - (ns_rrset), 0)->dname; - - assert(ns_dname); + (ns_rrset), 0)->dname); + if (ns_dname == NULL) { + return KNOT_ENOMEM; + } const knot_node_t *glue_node = knot_zone_contents_find_node(zone, ns_dname); @@ -1199,6 +1203,7 @@ static int semantic_checks_plain(knot_zone_contents_t *zone, knot_dname_t *wildcard = knot_dname_new_from_str("*", 1, NULL); if (wildcard == NULL) { + knot_dname_free(&ns_dname); return KNOT_ENOMEM; } @@ -1206,6 +1211,7 @@ static int semantic_checks_plain(knot_zone_contents_t *zone, if (knot_dname_cat(wildcard, ns_dname) == NULL) { + knot_dname_free(&ns_dname); knot_dname_free(&wildcard); return KNOT_ENOMEM; } @@ -1236,6 +1242,7 @@ static int semantic_checks_plain(knot_zone_contents_t *zone, } } } + knot_dname_free(&ns_dname); } return KNOT_EOK; } @@ -1512,7 +1519,7 @@ void log_cyclic_errors_in_zone(err_handler_t *handler, free(next_dname_decoded); - /*! \todo Free result and dname! */ + /*! \todo #1887 Free result and dname! */ if (knot_dname_cat(next_dname, knot_node_owner(knot_zone_contents_apex(zone))) == NULL) { diff --git a/src/knot/zone/semantic-check.h b/src/knot/zone/semantic-check.h index 17b774f..2f6dad7 100644..100755 --- a/src/knot/zone/semantic-check.h +++ b/src/knot/zone/semantic-check.h @@ -20,7 +20,7 @@ * * \brief DNS zone semantic checks. * - * \addtogroup dnslib + * \addtogroup zoneparser * @{ */ @@ -200,3 +200,5 @@ int zone_do_sem_checks(knot_zone_contents_t *zone, char do_checks, knot_node_t **last_node); #endif // _KNOT_SEMANTIC_CHECK_H_ + +/*! @} */ diff --git a/src/knot/zone/zone-dump-text.c b/src/knot/zone/zone-dump-text.c index bc606d3..8f428a5 100644..100755 --- a/src/knot/zone/zone-dump-text.c +++ b/src/knot/zone/zone-dump-text.c @@ -305,12 +305,12 @@ static inline uint16_t rdata_item_size(knot_rdata_item_t item) return item.raw_data[0]; } -char *rdata_dname_to_string(knot_rdata_item_t item) +static char *rdata_dname_to_string(knot_rdata_item_t item) { return knot_dname_to_str(item.dname); } -char *rdata_binary_dname_to_string(knot_rdata_item_t item) +static char *rdata_binary_dname_to_string(knot_rdata_item_t item) { if (item.raw_data == NULL) { return NULL; @@ -334,7 +334,7 @@ char *rdata_binary_dname_to_string(knot_rdata_item_t item) return str; } -char *rdata_dns_name_to_string(knot_rdata_item_t item) +static char *rdata_dns_name_to_string(knot_rdata_item_t item) { return knot_dname_to_str(item.dname); } @@ -342,8 +342,7 @@ char *rdata_dns_name_to_string(knot_rdata_item_t item) static char *rdata_txt_data_to_string(const uint8_t *data) { uint8_t length = data[0]; - size_t i; - + size_t i = 0; if (length == 0) { return NULL; } @@ -360,38 +359,41 @@ static char *rdata_txt_data_to_string(const uint8_t *data) } memset(ret, 0, current_length); - strncat(ret, "\"", 3); + strncat(ret, "\"", 2); for (i = 1; i <= length; i++) { char ch = (char) data[i]; if (isprint((int)ch)) { if (ch == '"' || ch == '\\') { - strncat(ret, "\"", 3); + strncat(ret, "\"", 2); } - /* for the love of god, how to this better, - but w/o obscure self-made functions */ char tmp_str[2]; tmp_str[0] = ch; - tmp_str[1] = 0; + tmp_str[1] = '\0'; strncat(ret, tmp_str, 2); } else { - strncat(ret, "\\", 3); + strncat(ret, "\\", 2); char tmp_str[2]; tmp_str[0] = ch - '0'; - tmp_str[1] = 0; - + tmp_str[1] = '\0'; strncat(ret, tmp_str, 2); } } - strncat(ret, "\"", 3); + strncat(ret, "\"", 2); return ret; } -char *rdata_text_to_string(knot_rdata_item_t item) +static char *rdata_text_to_string(knot_rdata_item_t item) { uint16_t size = item.raw_data[0]; - char *ret = malloc(sizeof(char) * size * 2 + 1) ; + /* + * Times two because they can all be one char long + * and then it would be as much chars as spaces (and one final space). + */ + size_t txt_size = size * 2 + 1; + /* + 1 ... space for (hypothetical) last \0. */ + char *ret = malloc(txt_size + 1); if (ret == NULL) { ERR_ALLOC_FAILED; return NULL; @@ -399,6 +401,7 @@ char *rdata_text_to_string(knot_rdata_item_t item) memset(ret, 0, sizeof(char) * size); const uint8_t *data = (uint8_t *)(item.raw_data + 1); size_t read_count = 0; + size_t tmp_str_current_length = 0; // Will be used with strncat. while (read_count < size) { assert(read_count <= size); char *txt = rdata_txt_data_to_string(data + read_count); @@ -406,20 +409,30 @@ char *rdata_text_to_string(knot_rdata_item_t item) free(ret); return NULL; } + /* + * We can trust this strlen, as + * it is created in internal function. + */ read_count += strlen(txt) - 1; /* Create delimiter. */ char del[2]; del[0] = ' '; del[1] = '\0'; - strncat(ret, txt, strlen(txt)); - strncat(ret, del, 2); + + /* We can only write to the remainder of string. */ + strncat(ret, txt, txt_size - tmp_str_current_length); + /* Increase length of tmp string. */ + tmp_str_current_length += strlen(txt); + strncat(ret, del, txt_size - tmp_str_current_length); + /* Increase length of tmp string by 1 ... space. */ + tmp_str_current_length += + 1; free(txt); } return ret; } -char *rdata_byte_to_string(knot_rdata_item_t item) +static char *rdata_byte_to_string(knot_rdata_item_t item) { assert(item.raw_data[0] == 1); uint8_t data = *((uint8_t *)(item.raw_data + 1)); @@ -428,7 +441,7 @@ char *rdata_byte_to_string(knot_rdata_item_t item) return ret; } -char *rdata_short_to_string(knot_rdata_item_t item) +static char *rdata_short_to_string(knot_rdata_item_t item) { uint16_t data = knot_wire_read_u16(rdata_item_data(item)); char *ret = malloc(sizeof(char) * U16_MAX_STR_LEN); @@ -438,7 +451,7 @@ char *rdata_short_to_string(knot_rdata_item_t item) return ret; } -char *rdata_long_to_string(knot_rdata_item_t item) +static char *rdata_long_to_string(knot_rdata_item_t item) { uint32_t data = knot_wire_read_u32(rdata_item_data(item)); char *ret = malloc(sizeof(char) * U32_MAX_STR_LEN); @@ -447,7 +460,7 @@ char *rdata_long_to_string(knot_rdata_item_t item) return ret; } -char *rdata_a_to_string(knot_rdata_item_t item) +static char *rdata_a_to_string(knot_rdata_item_t item) { /* 200 seems like a little too much */ char *ret = malloc(sizeof(char) * 200); @@ -458,7 +471,7 @@ char *rdata_a_to_string(knot_rdata_item_t item) } } -char *rdata_aaaa_to_string(knot_rdata_item_t item) +static char *rdata_aaaa_to_string(knot_rdata_item_t item) { char *ret = malloc(sizeof(char) * 200); if (inet_ntop(AF_INET6, rdata_item_data(item), ret, 200)) { @@ -468,7 +481,7 @@ char *rdata_aaaa_to_string(knot_rdata_item_t item) } } -char *rdata_rrtype_to_string(knot_rdata_item_t item) +static char *rdata_rrtype_to_string(knot_rdata_item_t item) { uint16_t type = knot_wire_read_u16(rdata_item_data(item)); const char *tmp = knot_rrtype_to_string(type); @@ -477,7 +490,7 @@ char *rdata_rrtype_to_string(knot_rdata_item_t item) return ret; } -char *rdata_algorithm_to_string(knot_rdata_item_t item) +static char *rdata_algorithm_to_string(knot_rdata_item_t item) { uint8_t id = *rdata_item_data(item); char *ret = malloc(sizeof(char) * MAX_RR_TYPE_LEN); @@ -492,7 +505,7 @@ char *rdata_algorithm_to_string(knot_rdata_item_t item) return ret; } -char *rdata_certificate_type_to_string(knot_rdata_item_t item) +static char *rdata_certificate_type_to_string(knot_rdata_item_t item) { uint16_t id = knot_wire_read_u16(rdata_item_data(item)); char *ret = malloc(sizeof(char) * MAX_RR_TYPE_LEN); @@ -507,7 +520,7 @@ char *rdata_certificate_type_to_string(knot_rdata_item_t item) return ret; } -char *rdata_period_to_string(knot_rdata_item_t item) +static char *rdata_period_to_string(knot_rdata_item_t item) { /* uint32 but read 16 XXX */ uint32_t period = knot_wire_read_u32(rdata_item_data(item)); @@ -516,7 +529,7 @@ char *rdata_period_to_string(knot_rdata_item_t item) return ret; } -char *rdata_time_to_string(knot_rdata_item_t item) +static char *rdata_time_to_string(knot_rdata_item_t item) { time_t time = (time_t) knot_wire_read_u32(rdata_item_data(item)); struct tm tm_conv; @@ -532,7 +545,7 @@ char *rdata_time_to_string(knot_rdata_item_t item) } } -char *rdata_base32_to_string(knot_rdata_item_t item) +static char *rdata_base32_to_string(knot_rdata_item_t item) { int length; size_t size = rdata_item_size(item); @@ -555,7 +568,8 @@ char *rdata_base32_to_string(knot_rdata_item_t item) } } -char *rdata_base64_to_string(knot_rdata_item_t item) +/*!< \todo Replace with function from .../common after release. */ +static char *rdata_base64_to_string(knot_rdata_item_t item) { int length; size_t size = rdata_item_size(item); @@ -570,7 +584,7 @@ char *rdata_base64_to_string(knot_rdata_item_t item) } } -char *hex_to_string(const uint8_t *data, size_t size) +static char *knot_hex_to_string(const uint8_t *data, size_t size) { static const char hexdigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', @@ -593,7 +607,7 @@ char *hex_to_string(const uint8_t *data, size_t size) char *rdata_hex_to_string(knot_rdata_item_t item) { - return hex_to_string(rdata_item_data(item), rdata_item_size(item)); + return knot_hex_to_string(rdata_item_data(item), rdata_item_size(item)); } char *rdata_hexlen_to_string(knot_rdata_item_t item) @@ -605,8 +619,8 @@ char *rdata_hexlen_to_string(knot_rdata_item_t item) ret[1] = '\0'; return ret; } else { - return hex_to_string(rdata_item_data(item) + 1, - rdata_item_size(item) - 1); + return knot_hex_to_string(rdata_item_data(item) + 1, + rdata_item_size(item) - 1); } } @@ -622,8 +636,8 @@ char *rdata_nsap_to_string(knot_rdata_item_t item) /* String is already terminated. */ memcpy(ret, "0x", strlen("0x")); - char *converted = hex_to_string(rdata_item_data(item), - rdata_item_size(item)); + char *converted = knot_hex_to_string(rdata_item_data(item), + rdata_item_size(item)); if (converted == NULL) { return NULL; } @@ -707,9 +721,7 @@ char *rdata_services_to_string(knot_rdata_item_t item) if (proto) { int i; - /*!< \todo #1863 see below, but we can trust getprotobynumber... */ strncpy(ret, proto->p_name, strlen(proto->p_name)); - strncat(ret, " ", 2); for (i = 0; i < bitmap_size * 8; ++i) { @@ -718,12 +730,6 @@ char *rdata_services_to_string(knot_rdata_item_t item) getservbyport((int)htons(i), proto->p_name); if (service) { - /*!< \todo #1863 - * using strncat with strlen - * does not make a whole lot of sense. - * At least it will crash wil - * Use max length of service name! - */ strncat(ret, service->s_name, strlen(service->s_name)); strncat(ret, " ", 2); @@ -738,37 +744,6 @@ char *rdata_services_to_string(knot_rdata_item_t item) } return ret; - - /* - int result = 0; - uint8_t protocol_number = buffer_read_u8(&packet); - ssize_t bitmap_size = buffer_remaining(&packet); - uint8_t *bitmap = buffer_current(&packet); - struct protoent *proto = getprotobynumber(protocol_number); - - - if (proto) { - int i; - - strcpy(ret, proto->p_name); - - for (i = 0; i < bitmap_size * 8; ++i) { - if (get_bit(bitmap, i)) { - struct servent *service = - getservbyport((int)htons(i), - proto->p_name); - if (service) { - buffer_printf(output, " %s", - service->s_name); - } else { - buffer_printf(output, " %d", i); - } - } - } - result = 1; - } - return ret; - */ } char *rdata_ipsecgateway_to_string(knot_rdata_item_t item, @@ -830,17 +805,15 @@ char *rdata_nxt_to_string(knot_rdata_item_t item) char *rdata_nsec_to_string(knot_rdata_item_t item) { - /* CLEANUP */ -// int insert_space = 0; - char *ret = malloc(sizeof(char) * MAX_NSEC_BIT_STR_LEN); - + if (ret == NULL) { + ERR_ALLOC_FAILED; + return NULL; + } memset(ret, 0, MAX_NSEC_BIT_STR_LEN); - uint8_t *data = rdata_item_data(item); int increment = 0; - for (int i = 0; i < rdata_item_size(item); i += increment) { increment = 0; uint8_t window = data[i]; @@ -870,33 +843,6 @@ char *rdata_nsec_to_string(knot_rdata_item_t item) } return ret; - - /* CLEANUP */ -/* while (buffer_available(&packet, 2)) { - uint8_t window = buffer_read_u8(&packet); - uint8_t bitmap_size = buffer_read_u8(&packet); - uint8_t *bitmap = buffer_current(&packet); - int i; - - if (!buffer_available(&packet, bitmap_size)) { - buffer_set_position(output, saved_position); - return 0; - } - - for (i = 0; i < bitmap_size * 8; ++i) { - if (get_bit(bitmap, i)) { - buffer_printf(output, - "%s%s", - insert_space ? " " : "", - rrtype_to_string( - window * 256 + i)); - insert_space = 1; - } - } - buffer_skip(&packet, bitmap_size); - } - - return 1; */ } char *rdata_unknown_to_string(knot_rdata_item_t item) @@ -912,7 +858,7 @@ char *rdata_unknown_to_string(knot_rdata_item_t item) snprintf(ret + strlen("\\# "), strlen("\\# ") + U16_MAX_STR_LEN + 1, "%lu ", (unsigned long) size); - char *converted = hex_to_string(rdata_item_data(item), size); + char *converted = knot_hex_to_string(rdata_item_data(item), size); strncat(ret, converted, size * 2 + 1); free(converted); return ret; @@ -959,14 +905,13 @@ char *rdata_item_to_string(knot_rdata_zoneformat_t type, return item_to_string_table[type](item); } -/* CLEANUP */ -/*void knot_zone_tree_apply_inorder(knot_zone_t *zone, - void (*function)(knot_node_t *node, void *data), - void *data); */ - int rdata_dump_text(const knot_rdata_t *rdata, uint16_t type, FILE *f, const knot_rrset_t *rrset) { + if (rdata == NULL || rrset == NULL) { + return KNOT_EBADARG; + } + knot_rrtype_descriptor_t *desc = knot_rrtype_descriptor_by_type(type); char *item_str = NULL; @@ -1040,19 +985,23 @@ int rrsig_set_dump_text(knot_rrset_t *rrsig, FILE *f) int rrset_dump_text(const knot_rrset_t *rrset, FILE *f) { - dump_rrset_header(rrset, f); - knot_rdata_t *tmp = rrset->rdata; + if (rrset->rdata != NULL) { // No sense in dumping empty RR + dump_rrset_header(rrset, f); - while (tmp->next != rrset->rdata) { - int ret = rdata_dump_text(tmp, rrset->type, f, rrset); - if (ret != KNOTD_EOK) { - return ret; + knot_rdata_t *tmp = rrset->rdata; + + while (tmp->next != rrset->rdata) { + int ret = rdata_dump_text(tmp, rrset->type, f, rrset); + if (ret != KNOTD_EOK) { + return ret; + } + dump_rrset_header(rrset, f); + tmp = tmp->next; } - dump_rrset_header(rrset, f); - tmp = tmp->next; + + rdata_dump_text(tmp, rrset->type, f, rrset); } - rdata_dump_text(tmp, rrset->type, f, rrset); knot_rrset_t *rrsig_set = rrset->rrsigs; if (rrsig_set != NULL) { rrsig_set_dump_text(rrsig_set, f); diff --git a/src/knot/zone/zone-dump-text.h b/src/knot/zone/zone-dump-text.h index 9f9c8dd..c55f712 100644..100755 --- a/src/knot/zone/zone-dump-text.h +++ b/src/knot/zone/zone-dump-text.h @@ -20,7 +20,7 @@ * * \brief Functions for dumping zone to text file. * - * \addtogroup dnslib + * \addtogroup zone-load-dump * @{ */ diff --git a/src/knot/zone/zone-dump.c b/src/knot/zone/zone-dump.c index aaf0165..708cd2b 100644..100755 --- a/src/knot/zone/zone-dump.c +++ b/src/knot/zone/zone-dump.c @@ -360,6 +360,11 @@ static int knot_rdata_dump_binary(knot_rdata_t *rdata, rdata->items[i].dname) { wildcard = rdata->items[i].dname->node->owner; } + + dbg_zdump_detail("zdump: dump_rdata: " + "Writing dname: %s.\n", + knot_dname_to_str( + rdata->items[i].dname)); if (use_ids) { /* Write ID. */ @@ -392,6 +397,8 @@ static int knot_rdata_dump_binary(knot_rdata_t *rdata, /*! \todo Does not have to be so complex. * Create extra variable. */ if (rdata->items[i].dname->node != NULL && !wildcard) { + dbg_zdump("zdump: dump_rdata: " + "This dname is in the zone.\n"); if (!write_wrapper((uint8_t *)"\1", sizeof(uint8_t), 1, fd, stream, max_size, @@ -401,6 +408,8 @@ static int knot_rdata_dump_binary(knot_rdata_t *rdata, return KNOT_ERROR; } } else { + dbg_zdump("zdump: dump_rdata: " + "This dname is not in the zone.\n"); if (!write_wrapper((uint8_t *)"\0", sizeof(uint8_t), 1, fd, @@ -423,6 +432,9 @@ static int knot_rdata_dump_binary(knot_rdata_t *rdata, } uint32_t wildcard_id = wildcard->id; + dbg_zdump("zdump: dump_rdata: " + "This dname is covered by wc (%s).\n", + knot_dname_to_str(wildcard)); if (!write_wrapper(&wildcard_id, sizeof(wildcard_id), 1, fd, stream, max_size, @@ -567,7 +579,11 @@ static int knot_rrset_dump_binary(const knot_rrset_t *rrset, int fd, "Dumping RRSet \\w owner: %s.\n", name); free(name); - ); + ); + + if (!use_ids) { + assert(rrset->rrsigs == NULL); + } if (!use_ids) { /*!< \todo IDs in changeset do no good. Change loading too. */ @@ -602,10 +618,14 @@ static int knot_rrset_dump_binary(const knot_rrset_t *rrset, int fd, /* Calculate rrset rdata count. */ knot_rdata_t *tmp_rdata = rrset->rdata; - while(tmp_rdata->next != rrset->rdata) { + while(tmp_rdata && (tmp_rdata->next != rrset->rdata)) { tmp_rdata = tmp_rdata->next; rdata_count++; } + + if (rrset->rdata == NULL) { + rdata_count = 0; + } if (!write_wrapper(&rdata_count, sizeof(rdata_count), 1, fd, stream, max_size, written_bytes, crc)) { @@ -619,29 +639,35 @@ static int knot_rrset_dump_binary(const knot_rrset_t *rrset, int fd, } dbg_zdump_verb("zdump: rrset_dump_binary: Static data dumped.\n"); + + if (rdata_count != 0) { + + tmp_rdata = rrset->rdata; - tmp_rdata = rrset->rdata; - - while (tmp_rdata->next != rrset->rdata) { + while (tmp_rdata->next != rrset->rdata) { + int ret = knot_rdata_dump_binary(tmp_rdata, rrset->type, + fd, use_ids, + stream, max_size, + written_bytes, crc); + if (ret != KNOT_EOK) { + dbg_zdump("zdump: rrset_to_binary: Could not " + "dump " + "rdata. Reason: %s.\n", + knot_strerror(ret)); + return ret; + } + tmp_rdata = tmp_rdata->next; + } + int ret = knot_rdata_dump_binary(tmp_rdata, rrset->type, fd, use_ids, - stream, max_size, - written_bytes, crc); + stream, + max_size, written_bytes, crc); if (ret != KNOT_EOK) { dbg_zdump("zdump: rrset_to_binary: Could not dump " "rdata. Reason: %s.\n", knot_strerror(ret)); return ret; } - tmp_rdata = tmp_rdata->next; - } - - int ret = knot_rdata_dump_binary(tmp_rdata, rrset->type, fd, use_ids, - stream, - max_size, written_bytes, crc); - if (ret != KNOT_EOK) { - dbg_zdump("zdump: rrset_to_binary: Could not dump " - "rdata. Reason: %s.\n", knot_strerror(ret)); - return ret; } dbg_zdump_verb("zdump: rrset_dump_binary: Rdata dumped.\n"); @@ -894,6 +920,7 @@ int knot_zdump_binary(knot_zone_contents_t *zone, int fd, int do_checks, const char *sfilename, crc_t *crc) { + if (fd < 0 || sfilename == NULL) { dbg_zdump("zdump: Bad arguments.\n"); return KNOT_EBADARG; diff --git a/src/knot/zone/zone-dump.h b/src/knot/zone/zone-dump.h index fbebae9..02d0298 100644..100755 --- a/src/knot/zone/zone-dump.h +++ b/src/knot/zone/zone-dump.h @@ -20,7 +20,7 @@ * * \brief Functions for dumping zone to binary file. * - * \addtogroup dnslib + * \addtogroup zone-load-dump * @{ */ @@ -38,7 +38,7 @@ enum { }; /*! \brief Magic identifier: { "knot", maj_ver, min_ver, revision } */ -#define MAGIC_BYTES {'k', 'n', 'o', 't', '1', '0', '4'} +#define MAGIC_BYTES {'k', 'n', 'o', 't', '1', '1', '0'} /*! * \brief Dumps given zone to binary file. diff --git a/src/knot/zone/zone-load.c b/src/knot/zone/zone-load.c index 3a7134e..fedd38b 100644..100755 --- a/src/knot/zone/zone-load.c +++ b/src/knot/zone/zone-load.c @@ -62,39 +62,57 @@ static int timet_cmp(time_t x, time_t y) * \retval 0 if failed. */ static inline int fread_safe_from_file(void *dst, - size_t size, size_t n, FILE *fp) + size_t size, size_t n, void *source) { + if (dst == NULL || source == NULL) { + dbg_zload("zload: fread_safe_from_file: NULL arguments.\n"); + return 0; + } + FILE *fp = (FILE *)source; int rc = fread(dst, size, n, fp); if (rc != n) { - fprintf(stderr, "fread: invalid read %d (expected %zu)\n", rc, - n); + dbg_zload("zload: fread_safe_from_file: " + "invalid read %d (exp. %zu)\n", + rc, n); } return rc == n; } -static uint8_t *knot_zload_stream = NULL; -static size_t knot_zload_stream_remaining = 0; -static size_t knot_zload_stream_size = 0; +struct load_stream { + uint8_t *stream; + size_t stream_remaining; + size_t stream_size; +}; + +typedef struct load_stream load_stream_t; static inline int read_from_stream(void *dst, - size_t size, size_t n, FILE *fp) + size_t size, size_t n, void *source) { - if (knot_zload_stream_remaining < (size * n)) { + if (dst == NULL || source == NULL) { + dbg_zload("zload: read_from_stream: NULL arguments.\n"); + return 0; + } + + /* Extract information from source data. */ + load_stream_t *data = (load_stream_t *)source; + + + if (data->stream_remaining < (size * n)) { + dbg_zload("zload: read_from_stream: Buffer depleted.\n"); return 0; } memcpy(dst, - knot_zload_stream + - (knot_zload_stream_size - knot_zload_stream_remaining), + data->stream + + (data->stream_size - data->stream_remaining), size * n); - knot_zload_stream_remaining -= size * n; + data->stream_remaining -= size * n; return 1; } -static int (*fread_wrapper)(void *dst, size_t size, size_t n, FILE *fp); - /*! \note Contents of dump file: * MAGIC(knotxx) NUMBER_OF_NORMAL_NODES NUMBER_OF_NSEC3_NODES * [normal_nodes] [nsec3_nodes] @@ -136,23 +154,31 @@ static void load_rdata_purge(knot_rdata_t *rdata, knot_dname_retain(items[i].dname); break; default: + /*!< \todo This would leak wire data! */ break; } } /* Copy items to rdata and free the temporary rdata. */ knot_rdata_set_items(rdata, items, count); - knot_rdata_deep_free(&rdata, type, 1); + knot_rdata_deep_free(&rdata, type, 0); free(items); } -static knot_dname_t *read_dname_with_id(FILE *f) +static knot_dname_t *read_dname_with_id(FILE *f, int use_ids) { if (f == NULL) { dbg_zload("zload: read_dname_id: NULL file.\n"); } knot_dname_t *ret = knot_dname_new(); CHECK_ALLOC_LOG(ret, NULL); + + int (*fread_wrapper)(void *dst, size_t size, size_t n, void *source); + if (use_ids) { + fread_wrapper = fread_safe_from_file; + } else { + fread_wrapper = read_from_stream; + } /* Read ID. */ uint32_t dname_id = 0; @@ -173,9 +199,12 @@ static knot_dname_t *read_dname_with_id(FILE *f) return NULL; } ret->size = dname_size; - dbg_zload("loaded: dname length: %u\n", ret->size); - - assert(ret->size <= DNAME_MAX_WIRE_LENGTH); + dbg_zload_detail("loaded: dname length: %u\n", ret->size); + if (ret->size > DNAME_MAX_WIRE_LENGTH) { + dbg_zload("zload: read_dname_id: Name too long.\n"); + knot_dname_release(ret); + return NULL; + } /* Read wireformat of dname. */ ret->name = malloc(sizeof(uint8_t) * ret->size); @@ -238,6 +267,18 @@ static knot_rdata_t *knot_load_rdata(uint16_t type, FILE *f, knot_dname_t **id_array, int use_ids) { + if (f == NULL) { + dbg_zload("zload: load_rdata: NULL arguments.\n"); + return NULL; + } + + int (*fread_wrapper)(void *dst, size_t size, size_t n, void *source); + if (use_ids) { + fread_wrapper = fread_safe_from_file; + } else { + fread_wrapper = read_from_stream; + } + knot_rdata_t *rdata = knot_rdata_new(); if (rdata == NULL) { dbg_zload("zload: load_rdata: Cannot create new rdata.\n"); @@ -262,12 +303,14 @@ static knot_rdata_t *knot_load_rdata(uint16_t type, FILE *f, malloc(sizeof(knot_rdata_item_t) * rdata_count); if (items == NULL) { ERR_ALLOC_FAILED; - free(items); + free(rdata); return NULL; } if (rdata_count > desc->length) { dbg_zload("zload: load_rdata: Read wrong count of RDATA.\n"); + free(items); + free(rdata); return NULL; } @@ -285,6 +328,7 @@ static knot_rdata_t *knot_load_rdata(uint16_t type, FILE *f, /*!< \todo #1686 * Refactor these variables, some might be too big. */ + uint32_t dname_id = 0; uint8_t has_wildcard = 0; @@ -304,8 +348,13 @@ static knot_rdata_t *knot_load_rdata(uint16_t type, FILE *f, knot_dname_retain(id_array[dname_id]); items[i].dname = id_array[dname_id]; } else { - items[i].dname = read_dname_with_id(f); + items[i].dname = read_dname_with_id(f, use_ids); } + + dbg_zload_detail("zload: load_rdata: " + "Loading dname: %s.\n", + knot_dname_to_str(items[i].dname)); + if(!fread_wrapper(&in_the_zone, sizeof(in_the_zone), 1, f)) { @@ -322,6 +371,27 @@ static knot_rdata_t *knot_load_rdata(uint16_t type, FILE *f, "Cannot read wildcard bit.\n"); return NULL; } + + dbg_zload_detail("zload: load_rdata: Has wildcard: " + "%d\n", has_wildcard); + + if (use_ids && !in_the_zone) { + dbg_zload_detail("zload: load_rdata: " + "Freeing node owned by: %s.\n", + knot_dname_to_str(items[i].dname)); + /* Destroy the node */ + assert(!in_the_zone); + if (items[i].dname->node != NULL && + /* + * This check is here to prevent freeing + * of previously set wildcard node. + */ + (items[i].dname->node->owner == + items[i].dname)) { + knot_node_free(&items[i].dname->node); + assert(items[i].dname->node == NULL); + } + } if (use_ids && has_wildcard) { if(!fread_wrapper(&dname_id, sizeof(dname_id), @@ -332,16 +402,14 @@ static knot_rdata_t *knot_load_rdata(uint16_t type, FILE *f, "Cannot read wc ID.\n"); return NULL; } + dbg_zload_detail("zload: load_rdata: " + "Wildcard: %s\n", + knot_dname_to_str( + id_array[dname_id])); items[i].dname->node = id_array[dname_id]->node; - } else if (use_ids && !in_the_zone) { - /* destroy the node */ - if (id_array[dname_id]->node != NULL) { - knot_node_free(&id_array[dname_id]-> - node, 0); - } - /* Also sets node to NULL! */ } + assert(items[i].dname); } else { if (!fread_wrapper(&raw_data_length, @@ -379,10 +447,12 @@ static knot_rdata_t *knot_load_rdata(uint16_t type, FILE *f, } /* Each item has refcount already incremented for saving in rdata. */ - if (knot_rdata_set_items(rdata, items, rdata_count) != 0) { - fprintf(stderr, "zload: read_rdata: Could not set items " - "when loading rdata.\n"); - knot_rdata_deep_free(&rdata, type, 0); + int ret = knot_rdata_set_items(rdata, items, rdata_count); + if (ret != KNOT_EOK) { + dbg_zload("zload: read_rdata: Could not set items " + "when loading rdata. Reason: %\n.", + knot_strerror(ret)); + load_rdata_purge(rdata, items, desc->length, desc, type); return NULL; } @@ -403,7 +473,7 @@ static knot_rdata_t *knot_load_rdata(uint16_t type, FILE *f, * * \return pointer to created and read RRSIG on success, NULL otherwise. */ -static knot_rrset_t *knot_load_rrsig(FILE *f, knot_dname_t **id_array, +static knot_rrset_t *knot_load_rrsig(void *f, knot_dname_t **id_array, int use_ids) { if (f == NULL || id_array == NULL) { @@ -411,6 +481,13 @@ static knot_rrset_t *knot_load_rrsig(FILE *f, knot_dname_t **id_array, return NULL; } + int (*fread_wrapper)(void *dst, size_t size, size_t n, void *source); + if (use_ids) { + fread_wrapper = fread_safe_from_file; + } else { + fread_wrapper = read_from_stream; + } + knot_rrset_t *rrsig = NULL; uint16_t rrset_type = 0; @@ -487,9 +564,21 @@ static knot_rrset_t *knot_load_rrsig(FILE *f, knot_dname_t **id_array, * * \return pointer to created and read RRSet on success, NULL otherwise. */ -static knot_rrset_t *knot_load_rrset(FILE *f, knot_dname_t **id_array, +static knot_rrset_t *knot_load_rrset(void *f, knot_dname_t **id_array, int use_ids) { + if (f == NULL) { + dbg_zload("zload: load_rrset: NULL arguments.\n"); + return NULL; + } + + int (*fread_wrapper)(void *dst, size_t size, size_t n, void *source); + if (use_ids) { + fread_wrapper = fread_safe_from_file; + } else { + fread_wrapper = read_from_stream; + } + knot_rrset_t *rrset = NULL; uint16_t rrset_type = 0; @@ -504,7 +593,7 @@ static knot_rrset_t *knot_load_rrset(FILE *f, knot_dname_t **id_array, if (!use_ids) { dbg_zload_detail("zload: load_rrset: " "Loading owner of new RRSet from wire.\n"); - owner = read_dname_with_id(f); + owner = read_dname_with_id(f, use_ids); if (owner == NULL) { dbg_zload("zload: load_rrset: Cannot load owner.\n"); return NULL; @@ -587,6 +676,7 @@ dbg_zload_exec_detail( return NULL; } } else { + dbg_zload("zload: load_rrset: Cannot load rdata.\n"); knot_rrset_deep_free(&rrset, 0, 1, 1); return NULL; } @@ -628,6 +718,10 @@ static knot_node_t *knot_load_node(FILE *f, knot_dname_t **id_array) dbg_zload("zload: load_node: Wrong parameters.\n"); return NULL; } + + int (*fread_wrapper)(void *dst, size_t size, size_t n, void *source); + fread_wrapper = fread_safe_from_file; + uint8_t flags = 0; knot_node_t *node = NULL; uint32_t parent_id = 0; @@ -661,6 +755,10 @@ static knot_node_t *knot_load_node(FILE *f, knot_dname_t **id_array) return NULL; } knot_dname_t *owner = id_array[dname_id]; + if (owner == NULL) { + dbg_zload("zload: load_node: Wrong dname ID, cannot load.\n"); + return NULL; + } dbg_zload_detail("zload: load_node: Node owner id: %d.\n", dname_id); dbg_zload_exec_detail( @@ -701,7 +799,7 @@ dbg_zload_exec_detail( for (int i = 0; i < rrset_count; i++) { if ((tmp_rrset = knot_load_rrset(f, id_array, 1)) == NULL) { - knot_node_free(&node, 0); + knot_node_free(&node); /*!< \todo #1686 * Refactor freeing, might not be enough. */ @@ -770,6 +868,9 @@ static void find_and_set_wildcard_child(knot_zone_contents_t *zone, static int knot_check_magic(FILE *f, const uint8_t* MAGIC, uint MAGIC_LENGTH) { uint8_t tmp_magic[MAGIC_LENGTH]; + + int (*fread_wrapper)(void *dst, size_t size, size_t n, void *source); + fread_wrapper = fread_safe_from_file; if (!fread_wrapper(&tmp_magic, sizeof(uint8_t), MAGIC_LENGTH, f)) { return 0; @@ -791,6 +892,9 @@ static unsigned long calculate_crc(FILE *f) fseek(f, 0L, SEEK_END); size_t file_size = ftell(f); fseek(f, 0L, SEEK_SET); + + int (*fread_wrapper)(void *dst, size_t size, size_t n, void *source); + fread_wrapper = fread_safe_from_file; const size_t chunk_size = 4096; /* read chunks of 4 kB */ @@ -836,11 +940,12 @@ int knot_zload_open(zloader_t **dst, const char *filename) dbg_zload("zload: open: Bad arguments.\n"); return KNOT_EBADARG; } + + int (*fread_wrapper)(void *dst, size_t size, size_t n, void *source); + fread_wrapper = fread_safe_from_file; *dst = 0; - fread_wrapper = fread_safe_from_file; - /* Open file for binary read. */ FILE *f = fopen(filename, "rb"); if (unlikely(!f)) { @@ -856,6 +961,15 @@ int knot_zload_open(zloader_t **dst, const char *filename) return KNOT_EFEWDATA; // No such file or directory (POSIX.1) } + + /* Calculate file size. */ + fseek(f, 0L, SEEK_END); + size_t file_size = ftell(f); + fseek(f, 0L, SEEK_SET); + if (file_size < MAGIC_LENGTH) { + fclose(f); + return KNOT_EFEWDATA; + } /* Calculate CRC and compare with filename.crc file */ unsigned long crc_calculated = calculate_crc(f); @@ -983,8 +1097,14 @@ int knot_zload_open(zloader_t **dst, const char *filename) static void cleanup_id_array(knot_dname_t **id_array, const uint from, const uint to) { + if (id_array == NULL) { + dbg_zload("zload: cleanup_id_array: NULL arguments.\n"); + } + for (uint i = from; i < to; i++) { - knot_dname_release(id_array[i]); + if (id_array[i] != NULL) { + knot_dname_release(id_array[i]); + } } free(id_array); @@ -1044,7 +1164,7 @@ static knot_dname_t **create_dname_array(FILE *f, uint max_id) memset(array, 0, sizeof(knot_dname_t *) * (max_id + 1)); for (uint i = 0; i < max_id - 1; i++) { - knot_dname_t *read_dname = read_dname_with_id(f); + knot_dname_t *read_dname = read_dname_with_id(f, 1); if (read_dname == NULL) { dbg_zload("zload: create_dname_array: " "Cannot read dname.\n" ); @@ -1090,8 +1210,6 @@ knot_zone_t *knot_zload_load(zloader_t *loader) return NULL; } - fread_wrapper = fread_safe_from_file; - FILE *f = loader->fp; knot_node_t *tmp_node; @@ -1099,7 +1217,10 @@ knot_zone_t *knot_zload_load(zloader_t *loader) uint32_t node_count; uint32_t nsec3_node_count; uint32_t auth_node_count; - + + int (*fread_wrapper)(void *dst, size_t size, size_t n, void *source); + fread_wrapper = fread_safe_from_file; + if (!fread_wrapper(&node_count, sizeof(node_count), 1, f)) { dbg_zload("zload: load: Cannot read node count!\n"); return NULL; @@ -1147,7 +1268,7 @@ knot_zone_t *knot_zload_load(zloader_t *loader) knot_node_t *apex = knot_load_node(f, id_array); if (!apex) { - fprintf(stderr, "zone: Could not load apex node (in %s)\n", + dbg_zload("zone: Could not load apex node (in %s)\n", loader->filename); cleanup_id_array(id_array, 1, node_count + nsec3_node_count + 1); @@ -1163,7 +1284,7 @@ knot_zone_t *knot_zload_load(zloader_t *loader) node_count + nsec3_node_count + 1); dbg_zload("zload: load: Failed to create new " "zone from apex!\n"); - knot_node_free(&apex, 0); + knot_node_free(&apex); free(dname_table); return NULL; } @@ -1178,19 +1299,26 @@ knot_zone_t *knot_zload_load(zloader_t *loader) knot_node_t *last_node = 0; last_node = apex; + int ret = 0; + for (uint i = 1; i < node_count; i++) { tmp_node = knot_load_node(f, id_array); if (tmp_node != NULL) { - if (knot_zone_contents_add_node(contents, tmp_node, - 0, 0, 0) != 0) { + dbg_zload_detail("zload: load: Adding node owned by: " + "%s\n.", + knot_dname_to_str(tmp_node->owner)); + if ((ret = knot_zone_contents_add_node(contents, + tmp_node, + 0, 0, 0)) != 0) { cleanup_id_array(id_array, 1, node_count + nsec3_node_count + 1); knot_zone_deep_free(&zone, 0); dbg_zload("zload: load: Failed to add node " - "to zone.\n"); + "to zone: %s.\n", knot_strerror(ret)); return NULL; } + if (knot_dname_is_wildcard(tmp_node->owner)) { find_and_set_wildcard_child(contents, tmp_node, 0); @@ -1229,12 +1357,12 @@ knot_zone_t *knot_zload_load(zloader_t *loader) assert(nsec3_first != NULL); - if (knot_zone_contents_add_nsec3_node(contents, nsec3_first, - 0, 0, 0) - != 0) { + if ((ret = knot_zone_contents_add_nsec3_node(contents, + nsec3_first, + 0, 0, 0)) != 0) { dbg_zload("zload: load: " "cannot add first nsec3 node, " - "exiting.\n"); + "exiting: %s.\n", knot_strerror(ret)); knot_zone_deep_free(&zone, 0); cleanup_id_array(id_array, node_count + 1, nsec3_node_count + 1); @@ -1249,10 +1377,11 @@ knot_zone_t *knot_zload_load(zloader_t *loader) tmp_node = knot_load_node(f, id_array); if (tmp_node != NULL) { - if (knot_zone_contents_add_nsec3_node(contents, - tmp_node, 0, 0, 0) != 0) { + if ((ret = knot_zone_contents_add_nsec3_node(contents, + tmp_node, 0, 0, 0)) != 0) { dbg_zload("zload: load: Cannot add " - "NSEC3 node.\n"); + "NSEC3 node: %s.\n", + knot_strerror(ret)); knot_zone_deep_free(&zone, 0); cleanup_id_array(id_array, node_count + 1, nsec3_node_count + 1); @@ -1265,6 +1394,10 @@ knot_zone_t *knot_zload_load(zloader_t *loader) } else { fprintf(stderr, "zone: Node error (in %s).\n", loader->filename); + knot_zone_deep_free(&zone, 0); + cleanup_id_array(id_array, node_count + 1, + nsec3_node_count + 1); + return NULL; } } @@ -1332,27 +1465,20 @@ int knot_zload_rrset_deserialize(knot_rrset_t **rrset, return KNOT_EBADARG; } - fread_wrapper = read_from_stream; + load_stream_t data; + data.stream = stream; + data.stream_remaining = *size; + data.stream_size = *size; - knot_zload_stream = stream; - knot_zload_stream_remaining = knot_zload_stream_size = *size; - - knot_rrset_t *ret = knot_load_rrset(NULL, NULL, 0); + knot_rrset_t *ret = knot_load_rrset(&data, NULL, 0); if (ret == NULL) { dbg_zload("zload: rrset_deserialize: Cannot load RRSet.\n"); - knot_zload_stream = NULL; - knot_zload_stream_remaining = 0; - knot_zload_stream_size = 0; return KNOT_EMALF; } - *size = knot_zload_stream_remaining; + *size = data.stream_remaining; *rrset = ret; - knot_zload_stream = NULL; - knot_zload_stream_remaining = 0; - knot_zload_stream_size = 0; - dbg_zload_detail("zload: rrset_deserialize: RRSet deserialized " "successfully.\n"); return KNOT_EOK; diff --git a/src/knot/zone/zone-load.h b/src/knot/zone/zone-load.h index 2fe318f..837d5f2 100644..100755 --- a/src/knot/zone/zone-load.h +++ b/src/knot/zone/zone-load.h @@ -20,7 +20,7 @@ * * \brief Loader of previously parsed zone * - * \addtogroup dnslib + * \addtogroup zone-load-dump * @{ */ diff --git a/src/knotc.8 b/src/knotc.8 index b61bfd3..9cd3f08 100644..100755 --- a/src/knotc.8 +++ b/src/knotc.8 @@ -1,6 +1,6 @@ -.TH knotc "8" "November 2011" "CZ.NIC Labs" "Knot DNS, version 0.8" +.TH knotc "8" "August 2012" "CZ.NIC Labs" "Knot DNS, version 1.1" .SH NAME -.B knot +.B knotc \- Knot DNS control utility .SH SYNOPSIS .B knotc @@ -28,27 +28,39 @@ Wait for the server to finish start/stop operations. \fB\-i\fR, \fB\-\-interactive\fR Interactive mode (do not daemonize). .TP +\fB\-a\fR, \fB\-\-auto\fR +Enable automatic recompilation (start or reload). +.TP \fB\-h\fR, \fB\-\-help\fR Print help and usage. .SS "Actions:" .TP start -Start knot server zone (no\-op if running). +Start knot server daemon (no\-op if running). .TP stop -Stop knot server (no\-op if not running). +Stop knot server daemon (no\-op if not running). .TP restart -Stops and then starts knot server. +Stops and then starts knot server daemon. .TP reload Reload knot configuration and compiled zones. .TP running -check if server is running. +Check if server is running. .TP compile Compile zone file. +.TP +refresh +Refresh all slave zones. +.TP +checkconf +Check server configuration. +.TP +checkzone +Check zones before compiling (accepts specific zones, f.e. 'knotc checkzone example1.com example2.com'). .SH "SEE ALSO" The full documentation for .B Knot diff --git a/src/knotd.8 b/src/knotd.8 index df4b264..cdc450a 100644..100755 --- a/src/knotd.8 +++ b/src/knotd.8 @@ -1,4 +1,4 @@ -.TH "knotd" "8" "November 2011" "CZ.NIC Labs" "Knot DNS, version 0.8" +.TH "knotd" "8" "August 2012" "CZ.NIC Labs" "Knot DNS, version 1.1" .SH NAME .B knotd \- Knot DNS daemon diff --git a/src/libknot/common.h b/src/libknot/common.h index 9b2d8ae..9b2d8ae 100644..100755 --- a/src/libknot/common.h +++ b/src/libknot/common.h diff --git a/src/libknot/consts.h b/src/libknot/consts.h index 4249763..4249763 100644..100755 --- a/src/libknot/consts.h +++ b/src/libknot/consts.h diff --git a/src/libknot/dname.c b/src/libknot/dname.c index 80de030..7d59b6b 100644..100755 --- a/src/libknot/dname.c +++ b/src/libknot/dname.c @@ -163,7 +163,7 @@ static int knot_dname_str_to_wire(const char *name, uint size, return -1; } - dbg_dname("Allocated space for wire format of dname: %p\n", wire); + dbg_dname_verb("Allocated space for wire format of dname: %p\n", wire); if (root) { *wire = '\0'; @@ -181,18 +181,18 @@ static int knot_dname_str_to_wire(const char *name, uint size, assert(w - wire - 1 == ch - (const uint8_t *)name); if (*ch == '.') { - dbg_dname("Position %zd (%p): " - "label length: %u\n", - label_start - wire, - label_start, label_length); + dbg_dname_detail("Position %zd (%p): " + "label length: %u\n", + label_start - wire, + label_start, label_length); *label_start = label_length; labels[label_count++] = label_start - wire; label_start = w; label_length = 0; } else { assert(w - wire < wire_size); - dbg_dname("Position %zd (%p): character: %c\n", - w - wire, w, *ch); + dbg_dname_detail("Position %zd (%p): character: %c\n", + w - wire, w, *ch); *w = *ch; ++label_length; } @@ -205,14 +205,13 @@ static int knot_dname_str_to_wire(const char *name, uint size, --ch; if (*ch == '.') { // put 0 for root label if the name ended with . --w; - dbg_dname("Position %zd (%p): character: (null)\n", - w - wire, w); + dbg_dname_detail("Position %zd (%p): character: (null)\n", + w - wire, w); *w = 0; } else { // otherwise we did not save the last label length - dbg_dname("Position %zd (%p): " - "label length: %u\n", - label_start - wire, - label_start, label_length); + dbg_dname_detail("Position %zd (%p): label length: %u\n", + label_start - wire, + label_start, label_length); *label_start = label_length; labels[label_count++] = label_start - wire; } @@ -277,7 +276,8 @@ static int knot_dname_find_labels(knot_dname_t *dname, int alloc) 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); + dbg_dname("Position: %d, character: %d, expected size: %d\n", + pos - name, *pos, size); return -1; } @@ -298,12 +298,11 @@ static int knot_dname_find_labels(knot_dname_t *dname, int alloc) static int knot_dname_cmp(const knot_dname_t *d1, const knot_dname_t *d2, int cs) { -dbg_dname_exec( +dbg_dname_exec_verb( char *name1 = knot_dname_to_str(d1); char *name2 = knot_dname_to_str(d2); - dbg_dname("Comparing dnames %s and %s\n", - name1, name2); + dbg_dname_verb("Comparing dnames %s and %s\n", name1, name2); for (int i = 0; i < strlen(name1); ++i) { name1[i] = knot_tolower(name1[i]); @@ -312,8 +311,7 @@ dbg_dname_exec( name2[i] = knot_tolower(name2[i]); } - dbg_dname("After to lower: %s and %s\n", - name1, name2); + dbg_dname_detail("After to lower: %s and %s\n", name1, name2); free(name1); free(name2); @@ -325,16 +323,16 @@ dbg_dname_exec( int l1 = d1->label_count; int l2 = d2->label_count; - dbg_dname("Label counts: %d and %d\n", l1, l2); + dbg_dname_detail("Label counts: %d and %d\n", l1, l2); assert(l1 >= 0); assert(l2 >= 0); // compare labels from last to first while (l1 > 0 && l2 > 0) { - dbg_dname("Comparing labels %d and %d\n", - l1 - 1, l2 - 1); - dbg_dname(" at offsets: %d and %d\n", - d1->labels[l1 - 1], d2->labels[l2 - 1]); + dbg_dname_detail("Comparing labels %d and %d\n", + l1 - 1, l2 - 1); + dbg_dname_detail(" at offsets: %d and %d\n", + d1->labels[l1 - 1], d2->labels[l2 - 1]); int res = knot_dname_compare_labels( &d1->name[d1->labels[--l1]], &d2->name[d2->labels[--l2]], @@ -434,26 +432,6 @@ dbg_dname_exec_verb( /*----------------------------------------------------------------------------*/ -//int knot_dname_from_wire(knot_dname_t *dname, const uint8_t *name, -// uint size) -//{ -// int i = 0; -// uint8_t labels[KNOT_MAX_DNAME_LABELS]; -// int label_i = 0; - -// while (name[i] != 0) { -// labels[label_i++] = i; -// uint8_t label_length = name[i]; -// if (i + label_length >= size) { -// return -2; -// } -// for (int j = 1; j <= label_length; ++j) { -// } -// } -//} - -/*----------------------------------------------------------------------------*/ - knot_dname_t *knot_dname_new_from_wire(const uint8_t *name, uint size, struct knot_node *node) { @@ -510,12 +488,10 @@ knot_dname_t *knot_dname_parse_from_wire(const uint8_t *wire, return NULL; } labels[l] = i; - dbg_dname("Next label (%d.) position: %zu\n", l, i); + dbg_dname_detail("Next label (%d.) position: %zu\n", l, i); if (knot_wire_is_pointer(wire + p)) { // pointer. - -// printf("Pointer.\n"); size_t ptr = knot_wire_get_pointer(wire + p); /* Check that the pointer points backwards @@ -622,6 +598,10 @@ knot_dname_t *knot_dname_deep_copy(const knot_dname_t *dname) /* dname_new_from_wire() does not accept non-FQDN dnames, so we * do the copy by hand. It's faster anyway */ + if (dname == NULL) { + return NULL; + } + knot_dname_t *copy = knot_dname_new(); CHECK_ALLOC(copy, NULL); @@ -771,7 +751,44 @@ struct knot_node *knot_dname_get_node(const knot_dname_t *dname) if (dname == NULL) { return NULL; } - return dname->node; + + knot_node_t *node = dname->node; + + /* + * If the zone contains new zone contents (during an update), we should + * return new node. Check if the node has the new node set. If it does + * not, it means this is already the new node. If it has, return the + * new node. If the new node is empty, return NULL, as the node will be + * deleted later. + */ +dbg_dname_exec_detail( + dbg_dname_detail("Getting node from dname: node: %p, zone: %p\n", node, + knot_node_zone(node)); + if (node != NULL && knot_node_zone(node) != NULL + && knot_zone_contents(knot_node_zone(node)) != NULL) { + dbg_dname_detail("zone contents gen: %d, new node of the node: " + "%p, is empty: %d\n", + knot_zone_contents_gen_is_new(knot_zone_contents( + knot_node_zone(node))), + knot_node_new_node(node), + knot_node_new_node(node) + ? knot_node_is_empty(knot_node_new_node(node)) + : -1); + } +); + + if (node && knot_node_zone(node) + && knot_zone_contents(knot_node_zone(node)) + && knot_zone_contents_gen_is_new(knot_zone_contents( + knot_node_zone(node))) + && knot_node_new_node(node) != NULL) { + node = knot_node_get_new_node(node); + if (knot_node_is_empty(node)) { + node = NULL; + } + } + + return node; } /*----------------------------------------------------------------------------*/ @@ -785,7 +802,20 @@ void knot_dname_set_node(knot_dname_t *dname, knot_node_t *node) void knot_dname_update_node(knot_dname_t *dname) { +dbg_dname_exec_detail( + char *name = knot_dname_to_str(dname); + dbg_dname_detail("Updating node pointer in dname %p: %s. Before: %p\n", + dname, name, dname->node); + free(name); +); + knot_node_update_ref(&dname->node); + dbg_dname_detail("After: %p\n", dname->node); + + if (knot_node_is_empty(dname->node)) { + dbg_dname_detail("Node is empty, setting to NULL.\n"); + dname->node = NULL; + } } /*----------------------------------------------------------------------------*/ @@ -829,12 +859,6 @@ knot_dname_t *knot_dname_left_chop(const knot_dname_t *dname) return parent; } - -// if (dname->label_count <= 1) { -// /* Nothing to chop. */ -// return NULL; -// } - parent->size = dname->size - dname->name[0] - 1; parent->name = (uint8_t *)malloc(parent->size); @@ -894,12 +918,11 @@ void knot_dname_left_chop_no_copy(knot_dname_t *dname) int knot_dname_is_subdomain(const knot_dname_t *sub, const knot_dname_t *domain) { -dbg_dname_exec( +dbg_dname_exec_verb( char *name1 = knot_dname_to_str(sub); char *name2 = knot_dname_to_str(domain); - dbg_dname("Checking if %s is subdomain of %s\n", - name1, name2); + dbg_dname_verb("Checking if %s is subdomain of %s\n", name1, name2); free(name1); free(name2); ); @@ -919,7 +942,7 @@ dbg_dname_exec( int l1 = sub->label_count; int l2 = domain->label_count; - dbg_dname("Label counts: %d and %d\n", l1, l2); + dbg_dname_detail("Label counts: %d and %d\n", l1, l2); if (l1 <= l2) { // if sub does not have more labes than domain return 0; // it is not its subdomain @@ -927,10 +950,10 @@ dbg_dname_exec( // compare labels from last to first while (l1 > 0 && l2 > 0) { - dbg_dname("Comparing labels %d and %d\n", - l1 - 1, l2 - 1); - dbg_dname(" at offsets: %d and %d\n", - sub->labels[l1 - 1], domain->labels[l2 - 1]); + dbg_dname_detail("Comparing labels %d and %d\n", + l1 - 1, l2 - 1); + dbg_dname_detail(" at offsets: %d and %d\n", + sub->labels[l1 - 1], domain->labels[l2 - 1]); // if some labels do not match if (knot_dname_compare_labels(&sub->name[sub->labels[--l1]], &domain->name[domain->labels[--l2]], 0) @@ -989,15 +1012,6 @@ int knot_dname_label_count(const knot_dname_t *dname) uint8_t knot_dname_label_size(const knot_dname_t *dname, int i) { -// printf("Returning size of %d. label starting on %d\n", -// i, dname->labels[i]); -// printf("Label count: %d, size of %d. label: %d, size of %d.label: %d\n", -// dname->label_count, i, dname->labels[i], i + 1, -// dname->labels[i+1]); -// printf("Size from the name: %u\n", dname->name[dname->labels[i]]); -// printf("Size from label offsets: %u\n", -// dname->labels[i + 1] - dname->labels[i]); - assert(i >= 0); assert(dname->size == 1 || i + 1 == dname->label_count || dname->labels[i + 1] - dname->labels[i] - 1 @@ -1007,17 +1021,16 @@ uint8_t knot_dname_label_size(const knot_dname_t *dname, int i) /*----------------------------------------------------------------------------*/ -knot_dname_t *knot_dname_replace_suffix(const knot_dname_t *dname, - int size, - const knot_dname_t *suffix) +knot_dname_t *knot_dname_replace_suffix(const knot_dname_t *dname, int size, + const knot_dname_t *suffix) { -dbg_dname_exec( +dbg_dname_exec_verb( char *name = knot_dname_to_str(dname); - dbg_dname("Replacing suffix of name %s, size %d with ", name, - size); + dbg_dname_verb("Replacing suffix of name %s, size %d with ", name, + size); free(name); name = knot_dname_to_str(suffix); - dbg_dname("%s (size %d)\n", name, suffix->size); + dbg_dname_verb("%s (size %d)\n", name, suffix->size); free(name); ); knot_dname_t *res = knot_dname_new(); @@ -1025,7 +1038,7 @@ dbg_dname_exec( res->size = dname->size - size + suffix->size; - dbg_dname("Allocating %d bytes...\n", res->size); + dbg_dname_detail("Allocating %d bytes...\n", res->size); res->name = (uint8_t *)malloc(res->size); if (res->name == NULL) { knot_dname_free(&res); @@ -1034,12 +1047,12 @@ dbg_dname_exec( dbg_dname_hex((char *)res->name, res->size); - dbg_dname("Copying %d bytes from the original name.\n", - dname->size - size); + dbg_dname_detail("Copying %d bytes from the original name.\n", + dname->size - size); memcpy(res->name, dname->name, dname->size - size); dbg_dname_hex((char *)res->name, res->size); - dbg_dname("Copying %d bytes from the suffix.\n", suffix->size); + dbg_dname_detail("Copying %d bytes from the suffix.\n", suffix->size); memcpy(res->name + dname->size - size, suffix->name, suffix->size); dbg_dname_hex((char *)res->name, res->size); @@ -1057,13 +1070,6 @@ void knot_dname_free(knot_dname_t **dname) return; } -// char *name = knot_dname_to_str((*dname)); - -// printf("freeing in dname: %s %p\n", name, *dname); - -// free(name); - - if ((*dname)->name != NULL) { free((*dname)->name); } @@ -1116,13 +1122,13 @@ knot_dname_t *knot_dname_cat(knot_dname_t *d1, const knot_dname_t *d2) return NULL; } - dbg_dname("1: copying %d bytes from adress %p to %p\n", - d1->size, d1->name, new_dname); + dbg_dname_detail("1: copying %d bytes from adress %p to %p\n", + d1->size, d1->name, new_dname); memcpy(new_dname, d1->name, d1->size); - dbg_dname("2: copying %d bytes from adress %p to %p\n", - d2->size, d2->name, new_dname + d1->size); + dbg_dname_detail("2: copying %d bytes from adress %p to %p\n", + d2->size, d2->name, new_dname + d1->size); memcpy(new_dname + d1->size, d2->name, d2->size); diff --git a/src/libknot/dname.h b/src/libknot/dname.h index 473bca7..43bc4d2 100644..100755 --- a/src/libknot/dname.h +++ b/src/libknot/dname.h @@ -224,8 +224,6 @@ const struct knot_node *knot_dname_node(const knot_dname_t *dname); struct knot_node *knot_dname_get_node(const knot_dname_t *dname); -void knot_dname_set_node(knot_dname_t *dname, struct knot_node *node); - void knot_dname_update_node(knot_dname_t *dname); void knot_dname_set_node(knot_dname_t *dname, struct knot_node *node); diff --git a/src/libknot/edns.c b/src/libknot/edns.c index ea630dd..8e1efcc 100644..100755 --- a/src/libknot/edns.c +++ b/src/libknot/edns.c @@ -71,21 +71,20 @@ int knot_edns_new_from_wire(knot_opt_rr_t *opt_rr, const uint8_t *wire, // owner of EDNS OPT RR must be root (0) if (*pos != 0) { dbg_edns("EDNS packet malformed (expected root " - "domain as owner).\n"); + "domain as owner).\n"); return KNOT_EMALF; } pos += 1; // check the type of the record (must be OPT) if (knot_wire_read_u16(pos) != KNOT_RRTYPE_OPT) { - dbg_edns("EDNS packet malformed (expected OPT type" - ".\n"); + dbg_edns("EDNS packet malformed (expected OPT type.\n"); return KNOT_EMALF; } pos += 2; opt_rr->payload = knot_wire_read_u16(pos); - dbg_edns("Parsed payload: %u\n", opt_rr->payload); + dbg_edns_verb("Parsed payload: %u\n", opt_rr->payload); pos += 2; opt_rr->ext_rcode = *(pos++); @@ -107,18 +106,18 @@ int knot_edns_new_from_wire(knot_opt_rr_t *opt_rr, const uint8_t *wire, while (parsed < rdlength + KNOT_EDNS_MIN_SIZE) { if (max_size - parsed < 4) { dbg_edns("Not enough data to parse OPT RR" - " OPTION header.\n"); + " OPTION header.\n"); return KNOT_EFEWDATA; } uint16_t code = knot_wire_read_u16(pos); pos += 2; uint16_t length = knot_wire_read_u16(pos); pos += 2; - dbg_edns("EDNS OPTION: Code: %u, Length: %u\n", - code, length); + dbg_edns_verb("EDNS OPTION: Code: %u, Length: %u\n", + code, length); if (max_size - parsed - 4 < length) { dbg_edns("Not enough data to parse OPT RR" - " OPTION data.\n"); + " OPTION data.\n"); return KNOT_EFEWDATA; } int ret; @@ -144,28 +143,28 @@ int knot_edns_new_from_rr(knot_opt_rr_t *opt_rr, return KNOT_EBADARG; } - dbg_edns("Parsing payload.\n"); + dbg_edns_verb("Parsing payload.\n"); opt_rr->payload = knot_rrset_class(rrset); // the TTL has switched bytes uint32_t ttl; - dbg_edns("TTL: %u\n", knot_rrset_ttl(rrset)); + dbg_edns_detail("TTL: %u\n", knot_rrset_ttl(rrset)); knot_wire_write_u32((uint8_t *)&ttl, knot_rrset_ttl(rrset)); // first byte of TTL is extended RCODE - dbg_edns("TTL: %u\n", ttl); + dbg_edns_detail("TTL: %u\n", ttl); memcpy(&opt_rr->ext_rcode, &ttl, 1); - dbg_edns("Parsed extended RCODE: %u.\n", opt_rr->ext_rcode); + dbg_edns_detail("Parsed extended RCODE: %u.\n", opt_rr->ext_rcode); // second is the version memcpy(&opt_rr->version, (const uint8_t *)(&ttl) + 1, 1); - dbg_edns("Parsed version: %u.\n", opt_rr->version); + dbg_edns_detail("Parsed version: %u.\n", opt_rr->version); // third and fourth are flags opt_rr->flags = knot_wire_read_u16((const uint8_t *)(&ttl) + 2); - dbg_edns("Parsed flags: %u.\n", opt_rr->flags); + dbg_edns_detail("Parsed flags: %u.\n", opt_rr->flags); // size of the header, options are counted elsewhere opt_rr->size = 11; int rc = 0; - dbg_edns("Parsing options.\n"); + dbg_edns_verb("Parsing options.\n"); const knot_rdata_t *rdata = knot_rrset_rdata(rrset); // in OPT RR, all RDATA are in one RDATA item stored as BINARY data, @@ -206,7 +205,7 @@ int knot_edns_new_from_rr(knot_opt_rr_t *opt_rr, } - dbg_edns("EDNS created.\n"); + dbg_edns_verb("EDNS created.\n"); return KNOT_EOK; } @@ -316,10 +315,10 @@ int knot_edns_add_option(knot_opt_rr_t *opt_rr, uint16_t code, free(old_options); } - dbg_edns("Adding option.\n"); - dbg_edns("Code: %u.\n", code); - dbg_edns("Length: %u.\n", length); - dbg_edns("Data: %p.\n", data); + dbg_edns_verb("Adding option.\n"); + dbg_edns_verb("Code: %u.\n", code); + dbg_edns_verb("Length: %u.\n", length); + dbg_edns_verb("Data: %p.\n", data); opt_rr->options[opt_rr->option_count].data = (uint8_t *)malloc(length); CHECK_ALLOC_LOG(opt_rr->options[opt_rr->option_count].data, KNOT_ENOMEM); @@ -370,9 +369,9 @@ short knot_edns_to_wire(const knot_opt_rr_t *opt_rr, uint8_t *wire, uint8_t *pos = wire; - dbg_edns_detail("Putting OPT RR to the wire format. Size: %d, " - "position: %zu\n", - opt_rr->size, (size_t)(pos - wire)); + dbg_edns_verb("Putting OPT RR to the wire format. Size: %d, " + "position: %zu\n", + opt_rr->size, (size_t)(pos - wire)); *(pos++) = 0; knot_wire_write_u16(pos, KNOT_RRTYPE_OPT); diff --git a/src/libknot/edns.h b/src/libknot/edns.h index 022ac36..022ac36 100644..100755 --- a/src/libknot/edns.h +++ b/src/libknot/edns.h diff --git a/src/libknot/hash/cuckoo-hash-table.c b/src/libknot/hash/cuckoo-hash-table.c index 9db32bf..7358e14 100644..100755 --- a/src/libknot/hash/cuckoo-hash-table.c +++ b/src/libknot/hash/cuckoo-hash-table.c @@ -30,7 +30,6 @@ #include "util/debug.h" #include "hash/cuckoo-hash-table.h" #include "hash/hash-functions.h" -#include "common/dynamic-array.h" /*----------------------------------------------------------------------------*/ /* Macros and inline functions */ @@ -283,6 +282,8 @@ static int ck_stash_is_full(const ck_hash_table_t *table) */ static inline void ck_clear_item(ck_hash_table_item_t **item) { + dbg_stash("[EMPTY STASH] [CREATE] setting item %p (%p) to NULL.\n", + item, *item); *item = NULL; } @@ -320,49 +321,11 @@ static inline void ck_swap_items(ck_hash_table_item_t **item1, static inline void ck_put_item(ck_hash_table_item_t **to, ck_hash_table_item_t *item) { - *to = item; -} - -/*----------------------------------------------------------------------------*/ -/*! - * \brief Checks if the hash was already used twice. - * - * If yes, it means we entered a loop in the hashing process, so we must stop. - * Otherwise it remembers that we used the hash. - * - * \note According to Kirsch, et al. a check that at most one hash was used - * twice should be sufficient. We will retain our version for now. - * - * \param used Array of used table indices (hashes). - * \param hash Hash to check. - * - * \retval -1 if the hash was already used twice. - * \retval -2 if an error occured. - * \retval 0 if the hash was not used twice yet. - */ -static uint ck_check_used_twice(da_array_t *used, uint32_t hash) -{ - uint i = 0, found = 0; - while (i < da_get_count(used) && found < 2) { - if (((uint *)(da_get_items(used)))[i] == hash) { - ++found; - } - ++i; - } - - if (found == 2) { - dbg_ck_hash("Hashing entered infinite loop.\n"); - return -1; - } else { - if (da_reserve(used, 1) < 0) { - ERR_ALLOC_FAILED; - return -2; - } - ((uint *)da_get_items(used))[da_get_count(used)] = hash; - da_occupy(used, 1); - assert(da_get_count(used) < RELOCATIONS_MAX); - return 0; + if (item == NULL) { + dbg_stash("[EMPTY STASH] [CREATE] Putting NULL to item %p.\n", + to); } + *to = item; } /*----------------------------------------------------------------------------*/ @@ -419,12 +382,14 @@ static ck_hash_table_item_t **ck_find_in_stash(const ck_hash_table_t *table, * non-NULL. */ if (item->item && ck_items_match(item->item, key, length)) { - dbg_ck("Comparing item in stash (key: %.*s (size %zu))" - "with searched item (key %.*s (size %u)).\n", - (int)item->item->key_length, item->item->key, - item->item->key_length, (int)length, key, - length); + dbg_ck_detail("Comparing item in stash (key: %.*s (size" + " %zu)) with searched item (key %.*s (size %u)).\n", + (int)item->item->key_length, item->item->key, + item->item->key_length, (int)length, key, length); return &item->item; + } else if (item->item == NULL) { + dbg_stash("[EMPTY STASH] [FIND] STASH ITEM IS EMPTY: " + "%p (%p)\n", item, item->item); } item = item->next; } @@ -448,18 +413,18 @@ static ck_hash_table_item_t **ck_find_gen(const ck_hash_table_t *table, size_t length, uint8_t generation) { uint32_t hash; - dbg_ck("Finding item in generation: %u\n", generation); + dbg_ck_verb("Finding item in generation: %u\n", generation); // check hash tables for (uint t = 0; t < table->table_count; ++t) { hash = HASH(&table->hash_system, key, length, table->table_size_exp, generation, t); - dbg_ck("Hash: %u, key: %.*s\n", hash, (int)length, key); - dbg_ck("Table %d, hash: %u, item: %p\n", t + 1, hash, - table->tables[t][hash]); + dbg_ck_detail("Hash: %u, key: %.*s\n", hash, (int)length, key); + dbg_ck_detail("Table %d, hash: %u, item: %p\n", t + 1, hash, + table->tables[t][hash]); if (table->tables[t][hash] != NULL) { - dbg_ck("Table %u, key: %.*s, value: %p, key " + dbg_ck_detail("Table %u, key: %.*s, value: %p, key " "length: %zu\n", t + 1, (int)table->tables[t][hash]->key_length, table->tables[t][hash]->key, @@ -475,16 +440,16 @@ static ck_hash_table_item_t **ck_find_gen(const ck_hash_table_t *table, } // try to find in stash - dbg_ck("Searching in stash...\n"); + dbg_ck_verb("Searching in stash...\n"); ck_hash_table_item_t **found = ck_find_in_stash(table, key, length); - dbg_ck("Found pointer: %p\n", found); + dbg_ck_verb("Found pointer: %p\n", found); if (found != NULL) { - dbg_ck("Stash, key: %.*s, value: %p, key length: %zu\n", - (int)(*found)->key_length, (*found)->key, - (*found)->value, (*found)->key_length); + dbg_ck_verb("Stash, key: %.*s, value: %p, key length: %zu\n", + (int)(*found)->key_length, (*found)->key, + (*found)->value, (*found)->key_length); } // ck_find_in_buffer returns NULL if not found, otherwise pointer to @@ -520,6 +485,136 @@ static ck_hash_table_item_t **ck_find_item_nc(const ck_hash_table_t *table, } /*----------------------------------------------------------------------------*/ +/* Lightweight dynamic array for keeping track of used items. */ +/*----------------------------------------------------------------------------*/ + +typedef struct ck_used { + uint32_t *items; + uint array_count; + size_t *counts; + size_t allocated; +} ck_used_t; + +/*----------------------------------------------------------------------------*/ + +static int ck_used_create(ck_used_t *used, uint table_count) +{ + // all tables in one array + used->items = malloc(table_count * RELOCATIONS_DEFAULT + * sizeof(uint32_t)); + if (used->items == NULL) { + return -1; + } + + used->counts = malloc(table_count * sizeof(size_t)); + if (used->counts == NULL) { + free(used->items); + return -1; + } + + used->array_count = table_count; + used->allocated = RELOCATIONS_DEFAULT; + + for (int i = 0; i < table_count; ++i) { + used->counts[i] = 0; + } + + memset(used->items, 0, + used->array_count * used->allocated * sizeof(uint32_t)); + + return 0; +} + +/*----------------------------------------------------------------------------*/ + +static void ck_used_free(ck_used_t *used) +{ + free(used->items); + free(used->counts); + used->allocated = 0; +} + +/*----------------------------------------------------------------------------*/ + +static int ck_used_add(ck_used_t *used, uint table_nr, uint32_t to_add) +{ + dbg_ck_hash_verb("1) Table nr: %u, count: %zu, allocated: %zu\n", + table_nr, used->counts[table_nr], used->allocated); + + if (used->counts[table_nr] == used->allocated) { + dbg_ck_hash_verb("Reallocating...\n"); + size_t allocated_new = used->allocated * 2; + uint32_t *items_new = malloc(used->array_count * allocated_new + * sizeof(uint32_t)); + if (items_new == NULL) { + return -1; + } + + memcpy(items_new, used->items, + used->allocated * used->array_count); + + uint32_t *old_items = used->items; + + used->items = items_new; + used->allocated = allocated_new; + + free(old_items); + } + + dbg_ck_hash_verb("2) Table nr: %u, count: %zu, allocated: %zu\n", + table_nr, used->counts[table_nr], used->allocated); + + assert(used->counts[table_nr] < used->allocated); + used->items[table_nr * used->allocated + used->counts[table_nr]] + = to_add; + ++used->counts[table_nr]; + + dbg_ck_hash_verb("3)Table nr: %u, count: %zu, allocated: %zu\n", + table_nr, used->counts[table_nr], used->allocated); + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Checks if the hash was already used twice. + * + * If yes, it means we entered a loop in the hashing process, so we must stop. + * Otherwise it remembers that we used the hash. + * + * \note According to Kirsch, et al. a check that at most one hash was used + * twice should be sufficient. We will retain our version for now. + * + * \param used Array of used table indices (hashes). + * \param hash Hash to check. + * + * \retval -1 if the hash was already used twice. + * \retval -2 if an error occured. + * \retval 0 if the hash was not used twice yet. + */ +static int ck_check_used_twice(ck_used_t *used, uint table_nr, + uint32_t hash) +{ + uint i = 0, found = 0; + + while (i < used->counts[table_nr] && found < 2) { + if (used->items[table_nr * used->allocated + i] == hash) { + ++found; + } + ++i; + } + + if (found == 2) { + dbg_ck_hash("Hashing entered infinite loop.\n"); + return -1; + } else { + return ck_used_add(used, table_nr, hash); + } +} + +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ /*! * \brief Hashes the given item using the given generation. * @@ -532,20 +627,26 @@ static ck_hash_table_item_t **ck_find_item_nc(const ck_hash_table_t *table, * * \retval 0 if successful and no loop occured. * \retval 1 if a loop occured and the item was inserted to the \a free place. + * \retval < 0 if an error occured. */ static int ck_hash_item(ck_hash_table_t *table, ck_hash_table_item_t **to_hash, ck_hash_table_item_t **free, uint8_t generation) { - da_array_t used[table->table_count]; - for (uint i = 0; i < table->table_count; ++i) { - da_initialize(&used[i], RELOCATIONS_DEFAULT, sizeof(uint)); +// da_array_t used[table->table_count]; +// for (uint i = 0; i < table->table_count; ++i) { +// da_initialize(&used[i], RELOCATIONS_DEFAULT, sizeof(uint)); +// } + ck_used_t used; + int ret = ck_used_create(&used, table->table_count); + if (ret != 0) { + return -1; } // hash until empty cell is encountered or until loop appears - dbg_ck_hash("Hashing key: %.*s of size %zu.\n", - (int)(*to_hash)->key_length, (*to_hash)->key, - (*to_hash)->key_length); + dbg_ck_hash_verb("Hashing key: %.*s of size %zu.\n", + (int)(*to_hash)->key_length, (*to_hash)->key, + (*to_hash)->key_length); uint next_table = 0; @@ -553,21 +654,24 @@ static int ck_hash_item(ck_hash_table_t *table, ck_hash_table_item_t **to_hash, (*to_hash)->key_length, table->table_size_exp, generation, next_table); - dbg_ck_hash("New hash: %u.\n", hash); + dbg_ck_hash_detail("New hash: %u.\n", hash); assert(hash < hashsize(table->table_size_exp)); - ((uint *)da_get_items(&used[next_table])) - [da_get_count(&used[next_table])] = hash; + ret = ck_used_add(&used, next_table, hash); + if (ret != 0) { + return -2; + } + ck_hash_table_item_t **next = &table->tables[next_table][hash]; - dbg_ck_hash("Item to be moved: %p, place in table: %p\n", - *next, next); + dbg_ck_hash_detail("Item to be moved: %p, place in table: %p\n", + *next, next); ck_hash_table_item_t **moving = to_hash; int loop = 0; while (*next != NULL) { - dbg_ck_hash("Swapping items to hash: %p and Moving: %p\n", - to_hash, moving); + dbg_ck_hash_detail("Swapping items: To hash: %p, Moving: %p\n", + to_hash, moving); ck_swap_items(to_hash, moving); // first time it's unnecessary // set the generation of the inserted item to the next @@ -575,9 +679,10 @@ static int ck_hash_item(ck_hash_table_t *table, ck_hash_table_item_t **to_hash, moving = next; - dbg_ck_hash("Moving item from table %u, key: %.*s, hash %u ", - next_table + 1, (int)(*moving)->key_length, - (*moving)->key, hash); + dbg_ck_hash_detail("Moving item from table %u, key: %.*s, hash " + "%u \n", next_table + 1, + (int)(*moving)->key_length, + (*moving)->key, hash); // if rehashing and the 'next' item is from the old generation, // start from table 1 @@ -594,31 +699,31 @@ static int ck_hash_item(ck_hash_table_t *table, ck_hash_table_item_t **to_hash, next = &table->tables[next_table][hash]; - dbg_ck_hash("to table %u, hash %u, item: %p, place: %p\n", - next_table + 1, hash, *next, next); + dbg_ck_hash_detail("To table %u, hash %u, item: %p, place: %p" + "\n", next_table + 1, hash, *next, next); if ((*next) != NULL) { - dbg_ck_hash("Table %u, hash: %u, key: %.*s\n", - next_table + 1, hash, - (int)(*next)->key_length, (*next)->key); + dbg_ck_hash_detail("Table %u, hash: %u, key: %.*s\n", + next_table + 1, hash, + (int)(*next)->key_length, (*next)->key); } // check if this cell wasn't already used in this item's hashing - if (ck_check_used_twice(&used[next_table], hash) != 0) { + if (ck_check_used_twice(&used, next_table, hash) != 0) { next = free; loop = -1; break; } } - dbg_ck_hash("Putting pointer %p (*moving) to item %p (next).\n", - *moving, next); + dbg_ck_hash_detail("Putting pointer %p (*moving) to item %p (next).\n", + *moving, next); ck_put_item(next, *moving); // set the new generation for the inserted item SET_GENERATION(&(*next)->timestamp, generation); - dbg_ck_hash("Putting pointer %p (*old) to item %p (moving).\n", - *to_hash, moving); + dbg_ck_hash_detail("Putting pointer %p (*old) to item %p (moving).\n", + *to_hash, moving); ck_put_item(moving, *to_hash); @@ -626,9 +731,7 @@ static int ck_hash_item(ck_hash_table_t *table, ck_hash_table_item_t **to_hash, SET_GENERATION(&(*moving)->timestamp, generation); *to_hash = NULL; - for (uint i = 0; i < table->table_count; ++i) { - da_destroy(&used[i]); - } + ck_used_free(&used); return loop; } @@ -670,6 +773,10 @@ static void ck_rollback_rehash(ck_hash_table_t *table) */ int ck_add_to_stash(ck_hash_table_t *table, ck_hash_table_item_t *item) { + if (item == NULL) { + dbg_stash("[EMPTY STASH] [CREATE] ADDING NULL ITEM TO STASH\n"); + } + ck_stash_item_t *new_item = (ck_stash_item_t *)malloc(sizeof(ck_stash_item_t)); if (new_item == NULL) { @@ -681,8 +788,8 @@ int ck_add_to_stash(ck_hash_table_t *table, ck_hash_table_item_t *item) new_item->next = table->stash; table->stash = new_item; - dbg_ck_hash("First item in stash (now inserted): key: %.*s (size %zu)" - ", value: %p\n", (int)table->stash->item->key_length, + dbg_ck_hash_verb("First item in stash (now inserted): key: %.*s (size" + " %zu), value: %p\n", (int)table->stash->item->key_length, table->stash->item->key, table->stash->item->key_length, table->stash->item->value); @@ -739,12 +846,12 @@ ck_hash_table_t *ck_create_table(uint items) dbg_ck("Creating hash table for %u items.\n", items); dbg_ck("Exponent: %u, number of tables: %u\n ", - table->table_size_exp, table->table_count); + table->table_size_exp, table->table_count); dbg_ck("Table size: %u items, each %zu bytes, total %zu bytes\n", - hashsize(table->table_size_exp), - sizeof(ck_hash_table_item_t *), - hashsize(table->table_size_exp) - * sizeof(ck_hash_table_item_t *)); + hashsize(table->table_size_exp), + sizeof(ck_hash_table_item_t *), + hashsize(table->table_size_exp) + * sizeof(ck_hash_table_item_t *)); // create tables for (uint t = 0; t < table->table_count; ++t) { @@ -805,18 +912,6 @@ void ck_destroy_table(ck_hash_table_t **table, void (*dtor_value)(void *value), } // destroy items in stash -// ck_hash_table_item_t **stash = -// ((ck_hash_table_item_t **)(da_get_items(&(*table)->stash))); -// for (uint i = 0; i < da_get_count(&(*table)->stash); ++i) { -// assert(stash[i] != NULL); -// if (dtor_value) { -// dtor_value(stash[i]->value); -// } -// if (delete_key != 0) { -// free((void *)stash[i]->key); -// } -// free((void *)stash[i]); -// } ck_stash_item_t *item = (*table)->stash; while (item != NULL) { // disconnect the item @@ -842,8 +937,6 @@ void ck_destroy_table(ck_hash_table_t **table, void (*dtor_value)(void *value), for (uint t = 0; t < (*table)->table_count; ++t) { free((*table)->tables[t]); } - // destroy stash -// da_destroy(&(*table)->stash); pthread_mutex_unlock(&(*table)->mtx_table); // destroy mutex, assuming that here noone will lock the mutex again @@ -884,7 +977,7 @@ void ck_table_free(ck_hash_table_t **table) int ck_resize_table(ck_hash_table_t *table) { dbg_ck("Resizing hash table.\n"); - + /* * Easiest is just to increment the exponent, resulting in doubling * the table sizes. This is not very memory-effective, but should do @@ -900,7 +993,7 @@ int ck_resize_table(ck_hash_table_t *table) ck_hash_table_item_t **tables_old[MAX_TABLES]; int exp_new = table->table_size_exp + 1; - dbg_ck("New tables exponent: %d\n", exp_new); + dbg_ck_verb("New tables exponent: %d\n", exp_new); for (int t = 0; t < table->table_count; ++t) { if (ck_new_table(&tables_new[t], exp_new) != 0) { @@ -919,14 +1012,14 @@ int ck_resize_table(ck_hash_table_t *table) * sizeof(ck_hash_table_item_t *); // copy the old table items - dbg_ck("Copying to: %p, from %p, size: %zu\n", - tables_new[t], table->tables[t], old_size); + dbg_ck_verb("Copying to: %p, from %p, size: %zu\n", + tables_new[t], table->tables[t], old_size); memcpy(tables_new[t], table->tables[t], old_size); // set the rest to 0 - dbg_ck("Setting to 0 from %p, size %zu\n", - tables_new[t] + hashsize(table->table_size_exp), - (hashsize(exp_new) * sizeof(ck_hash_table_item_t *)) - - old_size); + dbg_ck_verb("Setting to 0 from %p, size %zu\n", + tables_new[t] + hashsize(table->table_size_exp), + (hashsize(exp_new) * sizeof(ck_hash_table_item_t *)) + - old_size); memset(tables_new[t] + hashsize(table->table_size_exp), 0, (hashsize(exp_new) * sizeof(ck_hash_table_item_t *)) - old_size); @@ -948,7 +1041,6 @@ int ck_resize_table(ck_hash_table_t *table) } return ck_rehash(table); - //return 0; } int ck_insert_item(ck_hash_table_t *table, const char *key, @@ -980,9 +1072,6 @@ int ck_insert_item(ck_hash_table_t *table, const char *key, } } - // there should be at least 2 free places - //assert(da_try_reserve(&table->stash, 2) == 0); - //da_reserve(&table->stash, 1); ck_hash_table_item_t *free_place = NULL; if (ck_hash_item(table, &new_item, &free_place, table->generation) != 0) { @@ -1104,6 +1193,8 @@ ck_hash_table_item_t *ck_remove_item(ck_hash_table_t *table, const char *key, int ck_shallow_copy(const ck_hash_table_t *from, ck_hash_table_t **to) { + dbg_ck("ck_shallow_copy()\n"); + if (from == NULL || to == NULL) { return -1; } @@ -1176,26 +1267,27 @@ int ck_shallow_copy(const ck_hash_table_t *from, ck_hash_table_t **to) return -2; } - dbg_ck("Copying stash item: %p with item %p, ", si, si->item); - dbg_ck("key: %.*s\n", (int)si->item->key_length, si->item->key); + dbg_ck_detail("Copying stash item: %p with item %p, key: %.*s" + "\n", si, si->item, (int)si->item->key_length, + si->item->key); si_new->item = si->item; *pos = si_new; pos = &si_new->next; si = si->next; - - dbg_ck("Old stash item: %p with item %p, ", si, - ((si == NULL) ? NULL : si->item)); +dbg_ck_exec_detail( + dbg_ck_detail("Old stash item: %p with item %p, \n", si, + ((si == NULL) ? NULL : si->item)); if (si != NULL) { - dbg_ck("key: %.*s\n", (int)si->item->key_length, si->item->key); - } else { - dbg_ck("\n"); + dbg_ck_detail("key: %.*s\n", (int)si->item->key_length, + si->item->key); } - dbg_ck("New stash item: %p with item %p, ", si_new, - si_new->item); - dbg_ck("key: %.*s\n", (int)si_new->item->key_length, - si_new->item->key); + dbg_ck_detail("New stash item: %p with item %p, ", si_new, + si_new->item); + dbg_ck_detail("key: %.*s\n", (int)si_new->item->key_length, + si_new->item->key); +); } *pos = NULL; @@ -1273,11 +1365,12 @@ void ck_deep_copy_cleanup(ck_hash_table_t *table, int table_count) int ck_deep_copy(ck_hash_table_t *from, ck_hash_table_t **to) { + dbg_ck("ck_deep_copy()\n"); + if (from == NULL || to == NULL) { return -1; } - dbg_ck("Allocating new table...\n"); *to = (ck_hash_table_t *)malloc(sizeof(ck_hash_table_t)); if (*to == NULL) { @@ -1341,10 +1434,12 @@ int ck_deep_copy(ck_hash_table_t *from, ck_hash_table_t **to) return -2; } - dbg_ck("Copying stash item: %p with item %p, ", si, si->item); -// dbg_ck("key: %.*s\n", (int)si->item->key_length, si->item->key); + dbg_ck_detail("Copying stash item: %p with item %p, ", si, + si->item); if (si->item == NULL) { + dbg_stash("[EMPTY STASH] [FIND] STASH ITEM IS EMPTY: " + "%p (%p)\n", si, si->item); si_new->item = NULL; si_new->next = NULL; } else { @@ -1367,22 +1462,20 @@ int ck_deep_copy(ck_hash_table_t *from, ck_hash_table_t **to) pos = &si_new->next; si = si->next; -dbg_ck_exec( - dbg_ck("Old stash item: %p with item %p, ", si, - ((si == NULL) ? NULL : si->item)); +dbg_ck_exec_detail( + dbg_ck_detail("Old stash item: %p with item %p, \n", si, + ((si == NULL) ? NULL : si->item)); if (si != NULL && si->item != NULL) { - dbg_ck("key: %.*s\n", (int)si->item->key_length, - si->item->key); - } else { - dbg_ck("\n"); + dbg_ck_detail("key: %.*s\n", (int)si->item->key_length, + si->item->key); } - dbg_ck("New stash item: %p with item %p, ", si_new, - (si_new) ? si_new->item : NULL); + dbg_ck_detail("New stash item: %p with item %p, ", si_new, + (si_new) ? si_new->item : NULL); assert(si_new != NULL); assert(si_new->item != NULL); - dbg_ck("key: %.*s\n", (int)si_new->item->key_length, - si_new->item->key); + dbg_ck_detail("key: %.*s\n", (int)si_new->item->key_length, + si_new->item->key); ); } @@ -1446,13 +1539,13 @@ int ck_rehash(ck_hash_table_t *table) do { // 1) Rehash items from stash - dbg_ck_rehash("Rehashing items from stash.\n"); + dbg_ck_hash_verb("Rehashing items from stash.\n"); ck_stash_item_t *item = table->stash; ck_stash_item_t **item_place = &table->stash; // terminate when at the end; this way the newly added items // (added to the beginning) will be properly ignored while (item != NULL) { - dbg_ck_rehash("Rehashing item with " + dbg_ck_hash_detail("Rehashing item with " "key (length %zu): %.*s, generation: %hu, " "table generation: %hu.\n", item->item->key_length, (int)item->item->key_length, item->item->key, @@ -1481,6 +1574,8 @@ int ck_rehash(ck_hash_table_t *table) assert(item->item == NULL); // and the item should be hashed too // assert(table->hashed == NULL); + dbg_stash("[EMPTY STASH] [CREATE] Created empty" + " item: %p (%p)\n", item, item->item); // fix the pointer from the previous hash item *item_place = item->next; @@ -1501,12 +1596,11 @@ int ck_rehash(ck_hash_table_t *table) // which will be put to the stash ck_hash_table_item_t *free = NULL; assert(table->hashed == NULL); -// ck_hash_table_item_t *old = table->hashed; for (uint t = 0; t < table->table_count; ++t) { uint rehashed = 0; - dbg_ck_rehash("Rehashing table %d.\n", t); + dbg_ck_hash_verb("Rehashing table %d.\n", t); while (rehashed < hashsize(table->table_size_exp)) { @@ -1516,13 +1610,13 @@ int ck_rehash(ck_hash_table_t *table) || !(EQUAL_GENERATIONS( table->tables[t][rehashed]->timestamp, table->generation))) { - dbg_ck_rehash("Skipping item.\n"); + dbg_ck_hash_detail("Skipping item.\n"); ++rehashed; continue; } - dbg_ck_rehash("Rehashing item with hash %u, " - "key (length %zu): %.*s, generation: %hu, " + dbg_ck_hash_detail("Rehashing item with hash %u" + ", key (length %zu): %.*s, generation: %hu, " "table generation: %hu.\n", rehashed, table->tables[t][rehashed]->key_length, (int)(table->tables[t][rehashed]->key_length), @@ -1537,8 +1631,8 @@ int ck_rehash(ck_hash_table_t *table) // get rehashed again ck_clear_item(&table->tables[t][rehashed]); - dbg_ck_rehash("Table generation: %hu, next " - "generation: %hu.\n", + dbg_ck_hash_detail("Table generation: %hu, next" + " generation: %hu.\n", GET_GENERATION(table->generation), NEXT_GENERATION(table->generation)); @@ -1546,8 +1640,8 @@ int ck_rehash(ck_hash_table_t *table) NEXT_GENERATION(table->generation)) != 0) { // loop occured dbg_ck_hash("Hashing entered a loop." - "\n"); - dbg_ck_rehash("Item with key %.*s " + "\n"); + dbg_ck_hash_verb("Item with key %.*s " "inserted into the free slot.\n", free->key_length, free->key); @@ -1561,6 +1655,12 @@ int ck_rehash(ck_hash_table_t *table) free_stash_items; free_stash_items = item->next; + if (free == NULL) { + dbg_stash("[EMPTY STASH] " + "[CREATE] STORING NULL" + " in the stash\n"); + } + item->item = free; item->next = table->stash; table->stash = item; @@ -1579,15 +1679,15 @@ int ck_rehash(ck_hash_table_t *table) } } - dbg_ck_rehash("Old table generation: %u\n", - GET_GENERATION(table->generation)); + dbg_ck_hash("Old table generation: %u\n", + GET_GENERATION(table->generation)); // rehashing completed, switch generation of the table SET_NEXT_GENERATION(&table->generation); - dbg_ck_rehash("New table generation: %u\n", - GET_GENERATION(table->generation)); + dbg_ck_hash("New table generation: %u\n", + GET_GENERATION(table->generation)); // generate new hash functions for the old generation - dbg_ck_rehash("Generating coeficients for generation: %u\n", - NEXT_GENERATION(table->generation)); + dbg_ck_hash("Generating coeficients for generation: %u\n", + NEXT_GENERATION(table->generation)); us_next(&table->hash_system, NEXT_GENERATION(table->generation)); @@ -1609,248 +1709,6 @@ int ck_rehash(ck_hash_table_t *table) } /*----------------------------------------------------------------------------*/ -/*! - * \brief Rehashes the whole table. - * - * \param table Hash table to be rehashed. - * - * \note While rehashing no item should be inserted as it will result in a - * deadlock. - * - * \retval 0 No error. - * \retval -1 Rehashing failed. Some items may have been already moved and the - * rehashing flag remains set. - * - * \todo What if the stash is reallocated during ck_hash_item()? We'd be using - * the old stash for saving items! The old stash would not get deallocated - * (due to RCU - maybe put some rcu_read_lock() here), but the item - * would not be saved into the new stash! - * Maybe add a function for getting a pointer to particular item from - * the dynamic array and protect it using rcu_read_lock(). - * Other option: Do not use pointer to an item in stash in the call to - * ck_hash_item(). Use some new place & put the item to the stash - * afterwards, protecting it using rcu_read_lock() and rcu_assign_pointer. - */ -//int ck_rehash(ck_hash_table_t *table) -//{ -// dbg_ck_rehash("Rehashing items in table.\n"); -// SET_REHASHING_ON(&table->generation); - -// // we already have functions for the next generation, begin rehashing -// // we wil use the last item in the buffer as free cell for hashing -// assert(da_try_reserve(&table->stash, 1) == 0); -// ck_hash_table_item_t *old = (ck_hash_table_item_t *) -// (malloc(sizeof(ck_hash_table_item_t))); - -// do { -// dbg_ck_hash("Rehash!\n"); - -// if (da_get_count(&table->stash) > STASH_SIZE) { -// dbg_ck_hash("STASH RESIZED!!! (new stash size: %d)\n", -// da_get_count(&table->stash)); -// } - -// // rehash items from stash, starting from the last old item -// int stash_i = da_get_count(&table->stash) - 1; -// while (stash_i >= 0) { -// // if item's generation is the new generation, skip -// if (STASH_ITEMS(&table->stash)[stash_i] == NULL -// || !(EQUAL_GENERATIONS(STASH_ITEMS(&table->stash) -// [stash_i]->timestamp, -// table->generation))) { -// dbg_ck_rehash("Skipping item.\n"); -// --stash_i; -// continue; -// } - -// dbg_ck_rehash("Rehashing item from buffer position %u" -// ", key (length %u): %.*s, generation: " -// "%hu, table generation: %hu.\n", -// stash_i, -// STASH_ITEMS(&table->stash)[stash_i]->key_length, -// (int)STASH_ITEMS(&table->stash)[stash_i]->key_length, -// STASH_ITEMS(&table->stash)[stash_i]->key, -// GET_GENERATION( -// STASH_ITEMS(&table->stash)[stash_i]->timestamp), -// GET_GENERATION(table->generation)); - -// // otherwise copy the item for rehashing -// ck_put_item(&old, STASH_ITEMS(&table->stash)[stash_i]); -// // clear the place so that this item will not get -// // rehashed again -// ck_clear_item(&STASH_ITEMS(&table->stash)[stash_i]); -// da_release(&table->stash, 1); - -// // there should be at least one place in the stash -// assert(da_try_reserve(&table->stash, 1) == 0); -// da_reserve(&table->stash, 1); - -// assert(STASH_ITEMS(&table->stash)[stash_i] == NULL); - -// // and start rehashing -// if (ck_hash_item(table, &old, -// &STASH_ITEMS(&table->stash)[stash_i], -// NEXT_GENERATION(table->generation)) != 0) { -// // loop occured -// dbg_ck_hash("Hashing entered a loop.\n"); - -// dbg_ck_rehash("Item with key %.*s inserted " -// "into the stash on position %d.\n", -// STASH_ITEMS(&table->stash) -// [stash_i]->key_length, -// STASH_ITEMS(&table->stash) -// [stash_i]->key, -// da_get_count(&table->stash)); - -// // hashing unsuccessful, the item was inserted -// // into the stash -// da_occupy(&table->stash, 1); -// assert(STASH_ITEMS(&table->stash)[stash_i] -// != NULL); - -// // if only one place left, resize the stash -// // TODO: Why??? -// if (da_reserve(&table->stash, 2) < 0) { -// // stash could not be resized => !!! -// dbg_ck_hash("Failed to rehash items " -// "from " -// "table, no other rehash possible!\n"); -// // so rollback -// ck_rollback_rehash(table); -// // clear the 'old' item -// ck_clear_item(&old); -// return -1; -// } -// } - -// // clear the 'old' item -// ck_clear_item(&old); -// // decrement the index -// --stash_i; -// } - -// uint i = 0; -// while (i < da_get_count(&table->stash)) { -// assert(STASH_ITEMS(&table->stash)[i] != NULL); -// ++i; -// } -// dbg_ck_hash("OK\n"); -// assert(da_try_reserve(&table->stash, 1) == 0); -// assert(STASH_ITEMS(&table->stash)[da_get_count(&table->stash)] -// == NULL); - -// // rehash items from hash tables -// for (uint t = TABLE_FIRST; -// t <= TABLE_LAST(table->table_count); ++t) { -// dbg_ck_rehash("Rehashing items from table %d.\n", -// t + 1); -// uint rehashed = 0; - -// while (rehashed < hashsize(table->table_size_exp)) { - -// // if item's generation is the new generation, -// // skip -// if (table->tables[t][rehashed] == NULL -// || !(EQUAL_GENERATIONS( -// table->tables[t][rehashed]->timestamp, -// table->generation))) { -// dbg_ck_rehash("Skipping item.\n"); -// ++rehashed; -// continue; -// } - -// dbg_ck_rehash("Rehashing item with hash %u, " -// "key (length %u): %.*s, generation: %hu, " -// "table generation: %hu.\n", rehashed, -// table->tables[t][rehashed]->key_length, -// (int)(table->tables[t][rehashed]->key_length), -// table->tables[t][rehashed]->key, -// GET_GENERATION( -// table->tables[t][rehashed]->timestamp), -// GET_GENERATION(table->generation)); - -// // otherwise copy the item for rehashing -// ck_put_item(&old, table->tables[t][rehashed]); -// // clear the place so that this item will not -// // get rehashed again -// ck_clear_item(&table->tables[t][rehashed]); - -// dbg_ck_rehash("Table generation: %hu, next " -// "generation: %hu.\n", -// GET_GENERATION(table->generation), -// NEXT_GENERATION(table->generation)); - -// // and start rehashing -// assert(&old != &STASH_ITEMS(&table->stash)[ -// da_get_count(&table->stash)]); -// assert(da_try_reserve(&table->stash, 1) == 0); -// da_reserve(&table->stash, 1); - -// if (ck_hash_item(table, &old, -// &STASH_ITEMS(&table->stash)[ -// da_get_count(&table->stash)], -// NEXT_GENERATION(table->generation)) != 0) { -// // loop occured -// dbg_ck_hash("Hashing entered a loop." -// "\n"); -// dbg_ck_rehash("Item with key %.*s " -// "inserted into the stash on position " -// "%d.\n", STASH_ITEMS(&table->stash)[ -// da_get_count(&table->stash)] -// ->key_length, -// STASH_ITEMS(&table->stash)[ -// da_get_count(&table->stash)]->key, -// da_get_count(&table->stash)); - -// assert(STASH_ITEMS(&table->stash)[ -// da_get_count(&table->stash)] != NULL); -// // loop occured, the item is already at -// // its new place in the buffer, so just -// // increment the index -// da_occupy(&table->stash, 1); - -// // if only one place left, resize the -// // stash TODO: Why? -// if (da_reserve(&table->stash, 2) < 0) { -// // stash could not be resized -// dbg_ck_hash("Failed to rehash" -// " items from table, no other " -// "rehash possible!\n"); -// // so rollback -// ck_rollback_rehash(table); -// // clear the 'old' item -// ck_clear_item(&old); -// return -1; -// } -// } -// ++rehashed; -// } -// } - -// dbg_ck_rehash("Old table generation: %u\n", -// GET_GENERATION(table->generation)); -// // rehashing completed, switch generation of the table -// SET_NEXT_GENERATION(&table->generation); -// dbg_ck_rehash("New table generation: %u\n", -// GET_GENERATION(table->generation)); -// // generate new hash functions for the old generation -// dbg_ck_rehash("Generating coeficients for generation: %u\n", -// NEXT_GENERATION(table->generation)); -// us_next(NEXT_GENERATION(table->generation)); - -// // repeat rehashing while there are more items in the stash than -// // its initial size -// if (da_get_count(&table->stash) > STASH_SIZE) { -// dbg_ck_rehash("Rehashing again!\n"); -// } -// } while (da_get_count(&table->stash) > STASH_SIZE); - -// SET_REHASHING_OFF(&table->generation); - -// return 0; -//} - -/*----------------------------------------------------------------------------*/ void ck_dump_table(const ck_hash_table_t *table) { @@ -1872,15 +1730,6 @@ void ck_dump_table(const ck_hash_table_t *table) } dbg_ck("Stash:\n"); -// for (i = 0; i < da_get_count(&table->stash); ++i) { -// dbg_ck("Index: %u, Key: %.*s Value: %p.\n", i, -// ((ck_hash_table_item_t **) -// da_get_items(&table->stash))[i]->key_length, -// ((ck_hash_table_item_t **) -// da_get_items(&table->stash))[i]->key, -// ((ck_hash_table_item_t **) -// da_get_items(&table->stash))[i]->value); -// } ck_stash_item_t *item = table->stash; while (item != NULL) { dbg_ck("Hash: %u, Key: %.*s, Value: %p.\n", i, diff --git a/src/libknot/hash/cuckoo-hash-table.h b/src/libknot/hash/cuckoo-hash-table.h index eaa6a89..c0fe9cc 100644..100755 --- a/src/libknot/hash/cuckoo-hash-table.h +++ b/src/libknot/hash/cuckoo-hash-table.h @@ -42,7 +42,6 @@ #include <pthread.h> #include "hash/universal-system.h" -#include "common/dynamic-array.h" /*----------------------------------------------------------------------------*/ diff --git a/src/libknot/hash/hash-functions.c b/src/libknot/hash/hash-functions.c index a33dd6b..a33dd6b 100644..100755 --- a/src/libknot/hash/hash-functions.c +++ b/src/libknot/hash/hash-functions.c diff --git a/src/libknot/hash/hash-functions.h b/src/libknot/hash/hash-functions.h index f23730b..f23730b 100644..100755 --- a/src/libknot/hash/hash-functions.h +++ b/src/libknot/hash/hash-functions.h diff --git a/src/libknot/hash/universal-system.c b/src/libknot/hash/universal-system.c index 096974c..096974c 100644..100755 --- a/src/libknot/hash/universal-system.c +++ b/src/libknot/hash/universal-system.c diff --git a/src/libknot/hash/universal-system.h b/src/libknot/hash/universal-system.h index 25330de..25330de 100644..100755 --- a/src/libknot/hash/universal-system.h +++ b/src/libknot/hash/universal-system.h diff --git a/src/libknot/libknot.h b/src/libknot/libknot.h index a401be7..a401be7 100644..100755 --- a/src/libknot/libknot.h +++ b/src/libknot/libknot.h diff --git a/src/libknot/nameserver/name-server.c b/src/libknot/nameserver/name-server.c index 7a6bc4d..6924f44 100644..100755 --- a/src/libknot/nameserver/name-server.c +++ b/src/libknot/nameserver/name-server.c @@ -126,10 +126,9 @@ static const knot_zone_t *ns_get_zone_for_qname(knot_zonedb_t *zdb, static knot_rrset_t *ns_synth_from_wildcard( const knot_rrset_t *wildcard_rrset, const knot_dname_t *qname) { - dbg_ns("Synthetizing RRSet from wildcard...\n"); + dbg_ns_verb("Synthetizing RRSet from wildcard...\n"); knot_dname_t *owner = knot_dname_deep_copy(qname); -// printf("Copied owner ptr: %p\n", owner); knot_rrset_t *synth_rrset = knot_rrset_new( owner, knot_rrset_type(wildcard_rrset), @@ -143,7 +142,7 @@ static knot_rrset_t *ns_synth_from_wildcard( return NULL; } - dbg_ns("Created RRSet header:\n"); + dbg_ns_verb("Created RRSet header:\n"); knot_rrset_dump(synth_rrset, 1); // copy all RDATA @@ -159,15 +158,15 @@ static knot_rrset_t *ns_synth_from_wildcard( return NULL; } - dbg_ns("Copied RDATA:\n"); + dbg_ns_verb("Copied RDATA:\n"); knot_rdata_dump(rdata_copy, knot_rrset_type(synth_rrset), 1); - knot_rrset_add_rdata(synth_rrset, rdata_copy); + int ret = knot_rrset_add_rdata(synth_rrset, rdata_copy); + assert(ret == KNOT_EOK); rdata = knot_rrset_rdata_next(wildcard_rrset, rdata); } -// printf("Synthetized RRSet pointer: %p\n", synth_rrset); return synth_rrset; } @@ -182,8 +181,8 @@ static knot_rrset_t *ns_synth_from_wildcard( * temporary RRSet). * \param rrset RRSet to check (and possibly replace). */ -static void ns_check_wildcard(const knot_dname_t *name, knot_packet_t *resp, - knot_rrset_t **rrset) +static int ns_check_wildcard(const knot_dname_t *name, knot_packet_t *resp, + knot_rrset_t **rrset) { assert(name != NULL); assert(resp != NULL); @@ -193,11 +192,26 @@ static void ns_check_wildcard(const knot_dname_t *name, knot_packet_t *resp, if (knot_dname_is_wildcard((*rrset)->owner)) { knot_rrset_t *synth_rrset = ns_synth_from_wildcard(*rrset, name); - dbg_ns("Synthetized RRSet:\n"); + if (synth_rrset == NULL) { + dbg_ns("Failed to synthetize RRSet from wildcard.\n"); + return KNOT_ERROR; + } + +dbg_ns_exec_verb( + dbg_ns_verb("Synthetized RRSet:\n"); knot_rrset_dump(synth_rrset, 1); - knot_packet_add_tmp_rrset(resp, synth_rrset); +); + + int ret = knot_packet_add_tmp_rrset(resp, synth_rrset); + if (ret != KNOT_EOK) { + dbg_ns("Failed to add sythetized RRSet to tmp list.\n"); + knot_rrset_deep_free(&synth_rrset, 1, 1, 1); + return ret; + } *rrset = synth_rrset; } + + return KNOT_EOK; } /*----------------------------------------------------------------------------*/ @@ -230,23 +244,28 @@ static int ns_add_rrsigs(knot_rrset_t *rrset, knot_packet_t *resp, { knot_rrset_t *rrsigs; - dbg_ns("Adding RRSIGs for RRSet, type: %s.\n", - knot_rrtype_to_string(knot_rrset_type(rrset))); + dbg_ns_verb("Adding RRSIGs for RRSet, type: %s.\n", + knot_rrtype_to_string(knot_rrset_type(rrset))); assert(resp != NULL); assert(add_rrset_to_resp != NULL); - dbg_ns("DNSSEC requested: %d\n", - knot_query_dnssec_requested(knot_packet_query(resp))); - dbg_ns("RRSIGS: %p\n", knot_rrset_rrsigs(rrset)); + dbg_ns_detail("DNSSEC requested: %d\n", + knot_query_dnssec_requested(knot_packet_query(resp))); + dbg_ns_detail("RRSIGS: %p\n", knot_rrset_rrsigs(rrset)); if (DNSSEC_ENABLED && knot_query_dnssec_requested(knot_packet_query(resp)) && (rrsigs = knot_rrset_get_rrsigs(rrset)) != NULL) { if (name != NULL) { - ns_check_wildcard(name, resp, &rrsigs); + int ret = ns_check_wildcard(name, resp, &rrsigs); + if (ret != KNOT_EOK) { + dbg_ns("Failed to process wildcard: %s\n", + knot_strerror(ret)); + return ret; + } } - return add_rrset_to_resp(resp, rrsigs, tc, 0, 0, 1); + return add_rrset_to_resp(resp, rrsigs, tc, 1, 0, 1); } return KNOT_EOK; @@ -265,7 +284,7 @@ static int ns_add_rrsigs(knot_rrset_t *rrset, knot_packet_t *resp, * \param tc Set to 1 if omitting the RRSIG RRSet should result in setting the * TC bit in the response. */ -static void ns_follow_cname(const knot_node_t **node, +static int ns_follow_cname(const knot_node_t **node, const knot_dname_t **qname, knot_packet_t *resp, int (*add_rrset_to_resp)(knot_packet_t *, @@ -273,19 +292,22 @@ static void ns_follow_cname(const knot_node_t **node, int, int, int, int), int tc) { - dbg_ns("Resolving CNAME chain...\n"); + dbg_ns_verb("Resolving CNAME chain...\n"); knot_rrset_t *cname_rrset; + int ret = 0; + while (*node != NULL && (cname_rrset = knot_node_get_rrset(*node, KNOT_RRTYPE_CNAME)) - != NULL) { + != NULL + && (knot_rrset_rdata(cname_rrset) != NULL)) { /* put the CNAME record to answer, but replace the possible wildcard name with qname */ assert(cname_rrset != NULL); - dbg_ns("CNAME RRSet: %p, owner: %p\n", cname_rrset, - cname_rrset->owner); + dbg_ns_detail("CNAME RRSet: %p, owner: %p\n", cname_rrset, + cname_rrset->owner); knot_rrset_t *rrset = cname_rrset; @@ -294,27 +316,67 @@ static void ns_follow_cname(const knot_node_t **node, /* if wildcard node, we must copy the RRSet and replace its owner */ rrset = ns_synth_from_wildcard(cname_rrset, *qname); - knot_packet_add_tmp_rrset(resp, rrset); - add_rrset_to_resp(resp, rrset, tc, 0, 0, 1); - ns_add_rrsigs(cname_rrset, resp, *qname, - add_rrset_to_resp, tc); + if (rrset == NULL) { + dbg_ns("Failed to synthetize RRSet from " + "wildcard RRSet followed from CNAME.\n"); + return KNOT_ERROR; /*! \todo Better error. */ + } + + ret = knot_packet_add_tmp_rrset(resp, rrset); + if (ret != KNOT_EOK) { + dbg_ns("Failed to add synthetized RRSet (CNAME " + "follow) to the tmp RRSets in response." + "\n"); + knot_rrset_deep_free(&rrset, 1, 1, 1); + return ret; + } + + ret = add_rrset_to_resp(resp, rrset, tc, 0, 0, 1); + if (ret != KNOT_EOK) { + dbg_ns("Failed to add synthetized RRSet (CNAME " + "follow) to the response.\n"); + return ret; + } + + ret = ns_add_rrsigs(cname_rrset, resp, *qname, + add_rrset_to_resp, tc); + if (ret != KNOT_EOK) { + dbg_ns("Failed to add RRSIG for the synthetized" + "RRSet (CNAME follow) to the response." + "\n"); + return ret; + } int ret = knot_response_add_wildcard_node( resp, *node, *qname); - - /*! \todo Fix when return values are handled! */ if (ret != KNOT_EOK) { - assert(0); + dbg_ns("Failed to add wildcard node for later " + "processing.\n"); + return ret; } } else { - add_rrset_to_resp(resp, rrset, tc, 0, 0, 1); - ns_add_rrsigs(rrset, resp, *qname, add_rrset_to_resp, - tc); + ret = add_rrset_to_resp(resp, rrset, tc, 0, 0, 1); + + if (ret != KNOT_EOK) { + dbg_ns("Failed to add followed RRSet into" + "the response.\n"); + return ret; + } + + ret = ns_add_rrsigs(rrset, resp, *qname, + add_rrset_to_resp, tc); + + if (ret != KNOT_EOK) { + dbg_ns("Failed to add RRSIG for followed RRSet " + "into the response.\n"); + return ret; + } } - dbg_ns("Using RRSet: %p, owner: %p\n", rrset, rrset->owner); + dbg_ns_detail("Using RRSet: %p, owner: %p\n", rrset, + rrset->owner); -dbg_ns_exec( +dbg_ns_exec_verb( char *name = knot_dname_to_str(knot_rrset_owner(rrset)); dbg_ns("CNAME record for owner %s put to response.\n", name); free(name); @@ -323,18 +385,16 @@ dbg_ns_exec( // get the name from the CNAME RDATA const knot_dname_t *cname = knot_rdata_cname_name( knot_rrset_rdata(cname_rrset)); - dbg_ns("CNAME name from RDATA: %p\n", cname); + dbg_ns_detail("CNAME name from RDATA: %p\n", cname); // change the node to the node of that name *node = knot_dname_node(cname); - dbg_ns("This name's node: %p\n", *node); -// // it is not an old node and if yes, skip it -// if (knot_node_is_old(*node)) { -// *node = knot_node_new_node(*node); -// } + dbg_ns_detail("This name's node: %p\n", *node); // save the new name which should be used for replacing wildcard *qname = cname; - }; + } + + return KNOT_EOK; } /*----------------------------------------------------------------------------*/ @@ -350,47 +410,70 @@ dbg_ns_exec( * * \return Number of RRSets added. */ -static int ns_put_answer(const knot_node_t *node, const knot_dname_t *name, - uint16_t type, knot_packet_t *resp) +static int ns_put_answer(const knot_node_t *node, + const knot_zone_contents_t *zone, + const knot_dname_t *name, + uint16_t type, knot_packet_t *resp, int *added, + int check_any) { - int added = 0; -dbg_ns_exec( + *added = 0; +dbg_ns_exec_verb( char *name_str = knot_dname_to_str(node->owner); - dbg_ns("Putting answers from node %s.\n", name_str); + dbg_ns_verb("Putting answers from node %s.\n", name_str); free(name_str); ); + int ret = KNOT_EOK; + switch (type) { case KNOT_RRTYPE_ANY: { - dbg_ns("Returning all RRTYPES.\n"); + dbg_ns_verb("Returning all RRTYPES.\n"); + + // if ANY not allowed, set TC bit + if (check_any && knot_zone_contents_any_disabled(zone)) { + knot_response_set_tc(resp); + break; + } + knot_rrset_t **rrsets = knot_node_get_rrsets(node); if (rrsets == NULL) { break; } int i = 0; - int ret = 0; knot_rrset_t *rrset; while (i < knot_node_rrset_count(node)) { assert(rrsets[i] != NULL); rrset = rrsets[i]; - dbg_ns(" Type: %s\n", + dbg_ns_detail(" Type: %s\n", knot_rrtype_to_string(knot_rrset_type(rrset))); - ns_check_wildcard(name, resp, &rrset); + ret = ns_check_wildcard(name, resp, &rrset); + if (ret != KNOT_EOK) { + dbg_ns("Failed to process wildcard.\n"); + break; + } + ret = knot_response_add_rrset_answer(resp, rrset, 1, 0, 0, 1); - if (ret >= 0 && (added += 1) - && (ret = ns_add_rrsigs(rrset, resp, name, - knot_response_add_rrset_answer, 1)) - >=0 ) { - added += 1; - } else { - free(rrsets); - rrsets = NULL; + if (ret != KNOT_EOK) { + dbg_ns("Failed add Answer RRSet: %s\n", + knot_strerror(ret)); + break; + } + + *added += 1; + + ret = ns_add_rrsigs(rrset, resp, name, + knot_response_add_rrset_answer, 1); + if (ret != KNOT_EOK) { + dbg_ns("Failed add RRSIGs for Answer RRSet: %s" + "\n", knot_strerror(ret)); break; } + *added += 1; + ++i; } if (rrsets != NULL) { @@ -399,7 +482,7 @@ dbg_ns_exec( break; } case KNOT_RRTYPE_RRSIG: { - dbg_ns("Returning all RRSIGs.\n"); + dbg_ns_verb("Returning all RRSIGs.\n"); knot_rrset_t **rrsets = knot_node_get_rrsets(node); if (rrsets == NULL) { break; @@ -416,15 +499,21 @@ dbg_ns_exec( continue; } - ns_check_wildcard(name, resp, &rrset); + ret = ns_check_wildcard(name, resp, &rrset); + if (ret != KNOT_EOK) { + dbg_ns("Failed to process wildcard.\n"); + break; + } + ret = knot_response_add_rrset_answer(resp, rrset, 1, 0, 0, 1); - - if (ret < 0) { + if (ret != KNOT_EOK) { + dbg_ns("Failed add Answer RRSet: %s\n", + knot_strerror(ret)); break; } - added += 1; + *added += 1; ++i; } free(rrsets); @@ -434,23 +523,41 @@ dbg_ns_exec( int ret = 0; knot_rrset_t *rrset = knot_node_get_rrset(node, type); knot_rrset_t *rrset2 = rrset; - if (rrset != NULL) { - dbg_ns("Found RRSet of type %s\n", - knot_rrtype_to_string(type)); - ns_check_wildcard(name, resp, &rrset2); + if (rrset != NULL && knot_rrset_rdata(rrset) != NULL) { + dbg_ns_verb("Found RRSet of type %s\n", + knot_rrtype_to_string(type)); + + ret = ns_check_wildcard(name, resp, &rrset2); + if (ret != KNOT_EOK) { + dbg_ns("Failed to process wildcard.\n"); + break; + } + ret = knot_response_add_rrset_answer(resp, rrset2, 1, 0, 0, 1); - if (ret >= 0 && (added += 1) - && (ret = ns_add_rrsigs(rrset, resp, name, - knot_response_add_rrset_answer, 1)) > 0) { - added += 1; + if (ret != KNOT_EOK) { + dbg_ns("Failed add Answer RRSet: %s\n", + knot_strerror(ret)); + break; } + + *added += 1; + + ret = ns_add_rrsigs(rrset, resp, name, + knot_response_add_rrset_answer, 1); + + if (ret != KNOT_EOK) { + dbg_ns("Failed add RRSIGs for Answer RRSet: %s" + "\n", knot_strerror(ret)); + break; + } + + *added += 1; } } } - knot_response_set_rcode(resp, KNOT_RCODE_NOERROR); - return added; + return ret; } /*----------------------------------------------------------------------------*/ @@ -471,34 +578,36 @@ dbg_ns_exec( * \param resp Response where to add the Additional data. * \param rrset RRSet to get the Additional data for. */ -static void ns_put_additional_for_rrset(knot_packet_t *resp, - const knot_rrset_t *rrset) +static int ns_put_additional_for_rrset(knot_packet_t *resp, + const knot_rrset_t *rrset) { const knot_node_t *node = NULL; const knot_rdata_t *rdata = NULL; const knot_dname_t *dname = NULL; + int ret = 0; + // for all RRs in the RRset rdata = knot_rrset_rdata(rrset); while (rdata != NULL) { - dbg_ns("Getting name from RDATA, type %s..\n", - knot_rrtype_to_string(knot_rrset_type(rrset))); + dbg_ns_verb("Getting name from RDATA, type %s..\n", + knot_rrtype_to_string(knot_rrset_type(rrset))); dname = knot_rdata_get_name(rdata, knot_rrset_type(rrset)); + +dbg_ns_exec_detail( + char *name = knot_dname_to_str(dname); + dbg_ns_detail("Name: %s\n", name); + free(name); +); assert(dname != NULL); node = knot_dname_node(dname); -// dbg_ns_detail("Node saved in RDATA dname: %p\n", node); -// char *name = knot_dname_to_str(dname); -// dbg_ns_detail("Owner of the node: %p, dname: %p (%s)\n", -// node->owner, dname, name); -// free(name); -// knot_node_dump((knot_node_t *)node, (void *)1); - + dbg_ns_detail("Node saved in RDATA dname: %p\n", node); if (node != NULL && node->owner != dname) { - // the stored node should be the closest encloser - assert(knot_dname_is_subdomain(dname, node->owner)); - // try the wildcard child, if any - node = knot_node_wildcard_child(node); + // the stored node should be the wildcard covering the + // name + dbg_ns_detail("Node is wildcard.\n"); + assert(knot_dname_is_wildcard(knot_node_owner(node))); } knot_rrset_t *rrset_add; @@ -506,43 +615,90 @@ static void ns_put_additional_for_rrset(knot_packet_t *resp, if (node != NULL) { dbg_ns_exec( char *name = knot_dname_to_str(node->owner); - dbg_ns("Putting additional from node %s\n", name); + dbg_ns_verb("Putting additional from node %s\n", name); free(name); ); - dbg_ns("Checking CNAMEs...\n"); - if (knot_node_rrset(node, KNOT_RRTYPE_CNAME) - != NULL) { - dbg_ns("Found CNAME in node, following...\n"); + dbg_ns_detail("Checking CNAMEs...\n"); + if (knot_node_rrset(node, KNOT_RRTYPE_CNAME) != NULL) { + dbg_ns_detail("Found CNAME in node.\n"); const knot_dname_t *dname = knot_node_owner(node); - ns_follow_cname(&node, &dname, resp, + ret = ns_follow_cname(&node, &dname, resp, knot_response_add_rrset_additional, 0); + if (ret != KNOT_EOK) { + dbg_ns("Failed to follow CNAME.\n"); + return ret; + } } // A RRSet - dbg_ns("A RRSets...\n"); + dbg_ns_detail("A RRSets...\n"); rrset_add = knot_node_get_rrset(node, KNOT_RRTYPE_A); if (rrset_add != NULL) { - dbg_ns("Found A RRsets.\n"); + dbg_ns_detail("Found A RRsets.\n"); knot_rrset_t *rrset_add2 = rrset_add; - ns_check_wildcard(dname, resp, &rrset_add2); - knot_response_add_rrset_additional( + ret = ns_check_wildcard(dname, resp, + &rrset_add2); + if (ret != KNOT_EOK) { + dbg_ns("Failed to process wildcard for" + "Additional section: %s.\n", + knot_strerror(ret)); + return ret; + } + + ret = knot_response_add_rrset_additional( resp, rrset_add2, 0, 1, 0, 1); - ns_add_rrsigs(rrset_add, resp, dname, + + if (ret != KNOT_EOK) { + dbg_ns("Failed to add A RRSet to " + "Additional section: %s.\n", + knot_strerror(ret)); + return ret; + } + + ret = ns_add_rrsigs(rrset_add, resp, dname, knot_response_add_rrset_additional, 0); + + if (ret != KNOT_EOK) { + dbg_ns("Failed to add RRSIGs for A RR" + "Set to Additional section: %s." + "\n", knot_strerror(ret)); + return ret; + } } // AAAA RRSet - dbg_ns("AAAA RRSets...\n"); + dbg_ns_detail("AAAA RRSets...\n"); rrset_add = knot_node_get_rrset(node, KNOT_RRTYPE_AAAA); if (rrset_add != NULL) { - dbg_ns("Found AAAA RRsets.\n"); + dbg_ns_detail("Found AAAA RRsets.\n"); knot_rrset_t *rrset_add2 = rrset_add; - ns_check_wildcard(dname, resp, &rrset_add2); - knot_response_add_rrset_additional( + ret = ns_check_wildcard(dname, resp, + &rrset_add2); + if (ret != KNOT_EOK) { + dbg_ns("Failed to process wildcard for" + "Additional section: %s.\n", + knot_strerror(ret)); + return ret; + } + + ret = knot_response_add_rrset_additional( resp, rrset_add2, 0, 1, 0, 1); - ns_add_rrsigs(rrset_add, resp, dname, + + if (ret != KNOT_EOK) { + dbg_ns("Failed to add AAAA RRSet to " + "Additional section.\n"); + return ret; + } + + ret = ns_add_rrsigs(rrset_add, resp, dname, knot_response_add_rrset_additional, 0); + + if (ret != KNOT_EOK) { + dbg_ns("Failed to add RRSIG for AAAA RR" + "Set to Additional section.\n"); + return ret; + } } } @@ -550,6 +706,8 @@ dbg_ns_exec( assert(rdata != NULL); rdata = knot_rrset_rdata_next(rrset, rdata); } + + return KNOT_EOK; } /*----------------------------------------------------------------------------*/ @@ -580,26 +738,37 @@ static int ns_additional_needed(uint16_t qtype) * * \param resp Response to process. */ -static void ns_put_additional(knot_packet_t *resp) +static int ns_put_additional(knot_packet_t *resp) { - dbg_ns("ADDITIONAL SECTION PROCESSING\n"); + dbg_ns_verb("ADDITIONAL SECTION PROCESSING\n"); const knot_rrset_t *rrset = NULL; + int ret = 0; for (int i = 0; i < knot_packet_answer_rrset_count(resp); ++i) { rrset = knot_packet_answer_rrset(resp, i); assert(rrset != NULL); if (ns_additional_needed(knot_rrset_type(rrset))) { - ns_put_additional_for_rrset(resp, rrset); + ret = ns_put_additional_for_rrset(resp, rrset); + if (ret != KNOT_EOK) { + // if error, do not try to add other RRSets + return ret; + } } } for (int i = 0; i < knot_packet_authority_rrset_count(resp); ++i) { rrset = knot_packet_authority_rrset(resp, i); if (ns_additional_needed(knot_rrset_type(rrset))) { - ns_put_additional_for_rrset(resp, rrset); + ret = ns_put_additional_for_rrset(resp, rrset); + if (ret != KNOT_EOK) { + // if error, do not try to add other RRSets + return ret; + } } } + + return KNOT_EOK; } /*----------------------------------------------------------------------------*/ @@ -609,18 +778,35 @@ static void ns_put_additional(knot_packet_t *resp) * \param zone Zone to take the authority NS RRSet from. * \param resp Response where to add the RRSet. */ -static void ns_put_authority_ns(const knot_zone_contents_t *zone, +static int ns_put_authority_ns(const knot_zone_contents_t *zone, knot_packet_t *resp) { + dbg_ns_verb("PUTTING AUTHORITY NS\n"); + knot_rrset_t *ns_rrset = knot_node_get_rrset( knot_zone_contents_apex(zone), KNOT_RRTYPE_NS); if (ns_rrset != NULL) { - knot_response_add_rrset_authority(resp, ns_rrset, 0, 1, 0, 1); - ns_add_rrsigs(ns_rrset, resp, knot_node_owner( + int ret = knot_response_add_rrset_authority(resp, ns_rrset, 0, + 1, 0, 1); + + if (ret != KNOT_EOK) { + dbg_ns("Failed to add Authority NSs to response.\n"); + return ret; + } + + ret = ns_add_rrsigs(ns_rrset, resp, knot_node_owner( knot_zone_contents_apex(zone)), - knot_response_add_rrset_authority, 1); + knot_response_add_rrset_authority, 1); + + if (ret != KNOT_EOK) { + dbg_ns("Failed to add RRSIGs for Authority NSs to " + "response.\n"); + return ret; + } } + + return KNOT_EOK; } /*----------------------------------------------------------------------------*/ @@ -633,6 +819,8 @@ static void ns_put_authority_ns(const knot_zone_contents_t *zone, static int ns_put_authority_soa(const knot_zone_contents_t *zone, knot_packet_t *resp) { + dbg_ns_verb("PUTTING AUTHORITY SOA\n"); + int ret; knot_rrset_t *soa_rrset = knot_node_get_rrset( @@ -644,7 +832,7 @@ static int ns_put_authority_soa(const knot_zone_contents_t *zone, uint32_t min = knot_rdata_soa_minimum(knot_rrset_rdata(soa_rrset)); if (min < knot_rrset_ttl(soa_rrset)) { knot_rrset_t *soa_copy = NULL; - ret = knot_rrset_deep_copy(soa_rrset, &soa_copy); + ret = knot_rrset_deep_copy(soa_rrset, &soa_copy, 0); if (ret != KNOT_EOK) { return ret; @@ -655,7 +843,11 @@ static int ns_put_authority_soa(const knot_zone_contents_t *zone, knot_rrset_set_ttl(soa_copy, min); soa_rrset = soa_copy; /* Need to add it as temporary, so it get's freed. */ - knot_packet_add_tmp_rrset(resp, soa_copy); + ret = knot_packet_add_tmp_rrset(resp, soa_copy); + if (ret != KNOT_EOK) { + knot_rrset_deep_free(&soa_copy, 1, 1, 1); + return ret; + } } assert(soa_rrset != NULL); @@ -717,20 +909,36 @@ static knot_dname_t *ns_next_closer(const knot_dname_t *closest_encloser, * \param node Node to get the NSEC3 RRSet from. * \param resp Response where to add the RRSets. */ -static void ns_put_nsec3_from_node(const knot_node_t *node, +static int ns_put_nsec3_from_node(const knot_node_t *node, knot_packet_t *resp) { assert(DNSSEC_ENABLED && knot_query_dnssec_requested(knot_packet_query(resp))); - knot_rrset_t *rrset = knot_node_get_rrset(node, KNOT_RRTYPE_NSEC3); - assert(rrset != NULL); + knot_rrset_t *rrset = knot_node_get_rrset(node, KNOT_RRTYPE_NSEC3); + //assert(rrset != NULL); - int res = knot_response_add_rrset_authority(resp, rrset, 1, 1, 0, 1); + if (rrset == NULL) { + // bad zone, ignore + return KNOT_EOK; + } + + int res = KNOT_EOK; + if (knot_rrset_rdata(rrset) != NULL) { + res = knot_response_add_rrset_authority(resp, rrset, 1, 1, 0, + 1); + } // add RRSIG for the RRSet - if (res == 0 && (rrset = knot_rrset_get_rrsigs(rrset)) != NULL) { - knot_response_add_rrset_authority(resp, rrset, 1, 0, 0, 1); + if (res == KNOT_EOK && (rrset = knot_rrset_get_rrsigs(rrset)) != NULL + && knot_rrset_rdata(rrset) != NULL) { + res = knot_response_add_rrset_authority(resp, rrset, 1, 0, 0, + 1); } + + /*! \note TC bit is already set, if something went wrong. */ + + // return the error code, so that other code may be skipped + return res; } /*----------------------------------------------------------------------------*/ @@ -753,31 +961,25 @@ static int ns_put_covering_nsec3(const knot_zone_contents_t *zone, const knot_node_t *prev, *node; /*! \todo Check version. */ int match = knot_zone_contents_find_nsec3_for_name(zone, name, - &node, &prev); - assert(match >= 0); -// node = knot_node_current(node); -// prev = knot_node_current(prev); + &node, &prev); + //assert(match >= 0); + if (match < 0) { + // ignoring, what can we do anyway? + return KNOT_EOK; + } - if (match == KNOT_ZONE_NAME_FOUND){ - // run-time collision => SERVFAIL + if (match == KNOT_ZONE_NAME_FOUND || prev == NULL){ + // if run-time collision => SERVFAIL return KNOT_EOK; } -// // check if the prev node is not old and if yes, take the new one -// if (knot_node_is_old(prev)) { -// prev = knot_node_new_node(prev); -// assert(prev != NULL); -// } - -dbg_ns_exec( +dbg_ns_exec_verb( char *name = knot_dname_to_str(prev->owner); - dbg_ns("Covering NSEC3 node: %s\n", name); + dbg_ns_verb("Covering NSEC3 node: %s\n", name); free(name); ); - ns_put_nsec3_from_node(prev, resp); - - return KNOT_EOK; + return ns_put_nsec3_from_node(prev, resp); } /*----------------------------------------------------------------------------*/ @@ -812,19 +1014,24 @@ static int ns_put_nsec3_closest_encloser_proof( assert(qname != NULL); assert(resp != NULL); + // this function should be called only if NSEC3 is enabled in the zone + assert(knot_zone_contents_nsec3params(zone) != NULL); + + dbg_ns_verb("Adding closest encloser proof\n"); + if (knot_zone_contents_nsec3params(zone) == NULL) { -dbg_ns_exec( +dbg_ns_exec_verb( char *name = knot_dname_to_str(knot_node_owner( knot_zone_contents_apex(zone))); - dbg_ns("No NSEC3PARAM found in zone %s.\n", name); + dbg_ns_verb("No NSEC3PARAM found in zone %s.\n", name); free(name); ); return KNOT_EOK; } -dbg_ns_exec( +dbg_ns_exec_detail( char *name = knot_dname_to_str(knot_node_owner(*closest_encloser)); - dbg_ns("Closest encloser: %s\n", name); + dbg_ns_detail("Closest encloser: %s\n", name); free(name); ); @@ -845,28 +1052,30 @@ dbg_ns_exec( assert(nsec3_node != NULL); -dbg_ns_exec( +dbg_ns_exec_verb( char *name = knot_dname_to_str(nsec3_node->owner); - dbg_ns("NSEC3 node: %s\n", name); + dbg_ns_verb("NSEC3 node: %s\n", name); free(name); name = knot_dname_to_str((*closest_encloser)->owner); - dbg_ns("Closest provable encloser: %s\n", name); + dbg_ns_verb("Closest provable encloser: %s\n", name); free(name); if (next_closer != NULL) { name = knot_dname_to_str(next_closer); - dbg_ns("Next closer name: %s\n", name); + dbg_ns_verb("Next closer name: %s\n", name); free(name); } else { - dbg_ns("Next closer name: none\n"); + dbg_ns_verb("Next closer name: none\n"); } ); - ns_put_nsec3_from_node(nsec3_node, resp); + int ret = ns_put_nsec3_from_node(nsec3_node, resp); + if (ret != KNOT_EOK) { + return ret; + } /* * 2) NSEC3 that covers the "next closer" name. */ - int ret = 0; if (next_closer == NULL) { // create the "next closer" name by appending from qname next_closer = ns_next_closer( @@ -875,9 +1084,9 @@ dbg_ns_exec( if (next_closer == NULL) { return NS_ERR_SERVFAIL; } -dbg_ns_exec( +dbg_ns_exec_verb( char *name = knot_dname_to_str(next_closer); - dbg_ns("Next closer name: %s\n", name); + dbg_ns_verb("Next closer name: %s\n", name); free(name); ); ret = ns_put_covering_nsec3(zone, next_closer, resp); @@ -914,9 +1123,9 @@ static knot_dname_t *ns_wildcard_child_name(const knot_dname_t *name) return NULL; } -dbg_ns_exec( +dbg_ns_exec_verb( char *name = knot_dname_to_str(wildcard); - dbg_ns("Wildcard: %s\n", name); + dbg_ns_verb("Wildcard: %s\n", name); free(name); ); return wildcard; @@ -971,26 +1180,55 @@ static int ns_put_nsec3_no_wildcard_child(const knot_zone_contents_t *zone, * RRSets of the requested type). * \param resp Response where to add the NSECs or NSEC3s. */ -static void ns_put_nsec_nsec3_nodata(const knot_node_t *node, - knot_packet_t *resp) +static int ns_put_nsec_nsec3_nodata(const knot_zone_contents_t *zone, + const knot_node_t *node, + knot_packet_t *resp) { if (!DNSSEC_ENABLED || !knot_query_dnssec_requested(knot_packet_query(resp))) { - return; + return KNOT_EOK; } - knot_node_t *nsec3_node = knot_node_get_nsec3_node(node); + /*! \todo Maybe distinguish different errors. */ + int ret = KNOT_ERROR; + knot_rrset_t *rrset = NULL; - if ((rrset = knot_node_get_rrset(node, KNOT_RRTYPE_NSEC)) != NULL - || (nsec3_node != NULL && (rrset = - knot_node_get_rrset(nsec3_node, KNOT_RRTYPE_NSEC3)) != NULL)) { - knot_response_add_rrset_authority(resp, rrset, 1, 0, 0, 1); - // add RRSIG for the RRSet - if ((rrset = knot_rrset_get_rrsigs(rrset)) != NULL) { - knot_response_add_rrset_authority(resp, rrset, 1, - 0, 0, 1); + + if (knot_zone_contents_nsec3_enabled(zone)) { + knot_node_t *nsec3_node = knot_node_get_nsec3_node(node); + dbg_ns_verb("Adding NSEC3 for NODATA, NSEC3 node: %p\n", + nsec3_node); + + if (nsec3_node != NULL + && (rrset = knot_node_get_rrset(nsec3_node, + KNOT_RRTYPE_NSEC3)) != NULL + && knot_rrset_rdata(rrset) != NULL) { + dbg_ns_detail("Putting the RRSet to Authority\n"); + ret = knot_response_add_rrset_authority(resp, rrset, 1, + 0, 0, 1); } + } else { + dbg_ns_verb("Adding NSEC for NODATA\n"); + if ((rrset = knot_node_get_rrset(node, KNOT_RRTYPE_NSEC)) + != NULL + && knot_rrset_rdata(rrset) != NULL) { + dbg_ns_detail("Putting the RRSet to Authority\n"); + ret = knot_response_add_rrset_authority(resp, rrset, 1, + 0, 0, 1); + } + } + + if (ret != KNOT_EOK) { + return ret; } + + dbg_ns_detail("Putting RRSet's RRSIGs to Authority\n"); + if (rrset != NULL && (rrset = knot_rrset_get_rrsigs(rrset)) != NULL) { + ret = knot_response_add_rrset_authority(resp, rrset, 1, + 0, 0, 1); + } + + return ret; } /*----------------------------------------------------------------------------*/ @@ -1030,9 +1268,11 @@ static int ns_put_nsec_nxdomain(const knot_dname_t *qname, } } +dbg_ns_exec_verb( char *name = knot_dname_to_str(previous->owner); - dbg_ns("Previous node: %s\n", name); + dbg_ns_verb("Previous node: %s\n", name); free(name); +); // 1) NSEC proving that there is no node with the searched name rrset = knot_node_get_rrset(previous, KNOT_RRTYPE_NSEC); @@ -1043,11 +1283,21 @@ static int ns_put_nsec_nxdomain(const knot_dname_t *qname, } - knot_response_add_rrset_authority(resp, rrset, 1, 0, 0, 1); + int ret = knot_response_add_rrset_authority(resp, rrset, 1, 0, 0, 1); + if (ret != KNOT_EOK) { + dbg_ns("Failed to add NSEC for NXDOMAIN to response: %s\n", + knot_strerror(ret)); + return ret; + } + rrset = knot_rrset_get_rrsigs(rrset); assert(rrset != NULL); - knot_response_add_rrset_authority(resp, rrset, 1, 0, 0, 1); - + ret = knot_response_add_rrset_authority(resp, rrset, 1, 0, 0, 1); + if (ret != KNOT_EOK) { + dbg_ns("Failed to add RRSIGs for NSEC for NXDOMAIN to response:" + "%s\n", knot_strerror(ret)); + return ret; + } // 2) NSEC proving that there is no wildcard covering the name // this is only different from 1) if the wildcard would be // before 'previous' in canonical order, i.e. we can @@ -1064,9 +1314,9 @@ static int ns_put_nsec_nxdomain(const knot_dname_t *qname, while (knot_dname_compare(knot_node_owner(prev_new), wildcard) > 0) { -dbg_ns_exec( +dbg_ns_exec_verb( char *name = knot_dname_to_str(knot_node_owner(prev_new)); - dbg_ns("Previous node: %s\n", name); + dbg_ns_verb("Previous node: %s\n", name); free(name); ); assert(prev_new != knot_zone_contents_apex(zone)); @@ -1075,9 +1325,9 @@ dbg_ns_exec( assert(knot_dname_compare(knot_node_owner(prev_new), wildcard) < 0); -dbg_ns_exec( +dbg_ns_exec_verb( char *name = knot_dname_to_str(knot_node_owner(prev_new)); - dbg_ns("Previous node: %s\n", name); + dbg_ns_verb("Previous node: %s\n", name); free(name); ); @@ -1086,11 +1336,27 @@ dbg_ns_exec( if (prev_new != previous) { rrset = knot_node_get_rrset(prev_new, KNOT_RRTYPE_NSEC); - assert(rrset != NULL); - knot_response_add_rrset_authority(resp, rrset, 1, 0, 0, 1); + if (rrset == NULL || knot_rrset_rdata(rrset) == NULL) { + // bad zone, ignore + return KNOT_EOK; + } + ret = knot_response_add_rrset_authority(resp, rrset, 1, 0, 0, 1); + if (ret != KNOT_EOK) { + dbg_ns("Failed to add second NSEC for NXDOMAIN to " + "response: %s\n", knot_strerror(ret)); + return ret; + } rrset = knot_rrset_get_rrsigs(rrset); - assert(rrset != NULL); - knot_response_add_rrset_authority(resp, rrset, 1, 0, 0, 1); + if (rrset == NULL || knot_rrset_rdata(rrset) == NULL) { + // bad zone, ignore + return KNOT_EOK; + } + ret = knot_response_add_rrset_authority(resp, rrset, 1, 0, 0, 1); + if (ret != KNOT_EOK) { + dbg_ns("Failed to add RRSIGs for second NSEC for " + "NXDOMAIN to response: %s\n", knot_strerror(ret)); + return ret; + } } return KNOT_EOK; @@ -1118,13 +1384,12 @@ static int ns_put_nsec3_nxdomain(const knot_zone_contents_t *zone, knot_packet_t *resp) { // 1) Closest encloser proof - dbg_ns("Putting closest encloser proof.\n"); int ret = ns_put_nsec3_closest_encloser_proof(zone, &closest_encloser, qname, resp); // 2) NSEC3 covering non-existent wildcard if (ret == KNOT_EOK && closest_encloser != NULL) { - dbg_ns("Putting NSEC3 for no wildcard child of closest " - "encloser.\n"); + dbg_ns_verb("Putting NSEC3 for no wildcard child of closest " + "encloser.\n"); ret = ns_put_nsec3_no_wildcard_child(zone, closest_encloser, resp); } @@ -1207,16 +1472,16 @@ static int ns_put_nsec3_wildcard(const knot_zone_contents_t *zone, * NSEC3 that covers the "next closer" name. */ // create the "next closer" name by appending from qname - dbg_ns("Finding next closer name for wildcard NSEC3.\n"); + dbg_ns_verb("Finding next closer name for wildcard NSEC3.\n"); knot_dname_t *next_closer = ns_next_closer(closest_encloser->owner, qname); if (next_closer == NULL) { return NS_ERR_SERVFAIL; } -dbg_ns_exec( +dbg_ns_exec_verb( char *name = knot_dname_to_str(next_closer); - dbg_ns("Next closer name: %s\n", name); + dbg_ns_verb("Next closer name: %s\n", name); free(name); ); int ret = ns_put_covering_nsec3(zone, next_closer, resp); @@ -1241,10 +1506,10 @@ dbg_ns_exec( * \param previous Previous node of \a qname in canonical order. * \param resp Response to put the NSEC3s into. */ -static void ns_put_nsec_wildcard(const knot_zone_contents_t *zone, - const knot_dname_t *qname, - const knot_node_t *previous, - knot_packet_t *resp) +static int ns_put_nsec_wildcard(const knot_zone_contents_t *zone, + const knot_dname_t *qname, + const knot_node_t *previous, + knot_packet_t *resp) { assert(DNSSEC_ENABLED && knot_query_dnssec_requested(knot_packet_query(resp))); @@ -1261,13 +1526,22 @@ static void ns_put_nsec_wildcard(const knot_zone_contents_t *zone, knot_rrset_t *rrset = knot_node_get_rrset(previous, KNOT_RRTYPE_NSEC); - if (rrset != NULL) { + + int ret = KNOT_EOK; + + if (rrset != NULL && knot_rrset_rdata(rrset) != NULL) { // NSEC proving that there is no node with the searched name - knot_response_add_rrset_authority(resp, rrset, 1, 0, 0, 1); - rrset = knot_rrset_get_rrsigs(rrset); - assert(rrset != NULL); - knot_response_add_rrset_authority(resp, rrset, 1, 0, 0, 1); + ret = knot_response_add_rrset_authority(resp, rrset, 1, 0, + 0, 1); + if (ret == KNOT_EOK) { + rrset = knot_rrset_get_rrsigs(rrset); + assert(rrset != NULL); + ret = knot_response_add_rrset_authority(resp, rrset, 1, + 0, 0, 1); + } } + + return ret; } /*----------------------------------------------------------------------------*/ @@ -1306,10 +1580,10 @@ static int ns_put_nsec_nsec3_wildcard_nodata(const knot_node_t *node, if (ret == KNOT_EOK && (nsec3_node = knot_node_nsec3_node(node)) != NULL) { - ns_put_nsec3_from_node(nsec3_node, resp); + ret = ns_put_nsec3_from_node(nsec3_node, resp); } } else { - ns_put_nsec_wildcard(zone, qname, previous, resp); + ret = ns_put_nsec_wildcard(zone, qname, previous, resp); } } return ret; @@ -1339,18 +1613,18 @@ static int ns_put_nsec_nsec3_wildcard_answer(const knot_node_t *node, const knot_dname_t *qname, knot_packet_t *resp) { - int r = KNOT_EOK; + int ret = KNOT_EOK; if (DNSSEC_ENABLED && knot_query_dnssec_requested(knot_packet_query(resp)) && knot_dname_is_wildcard(knot_node_owner(node))) { if (knot_zone_contents_nsec3_enabled(zone)) { - r = ns_put_nsec3_wildcard(zone, closest_encloser, qname, - resp); + ret = ns_put_nsec3_wildcard(zone, closest_encloser, + qname, resp); } else { - ns_put_nsec_wildcard(zone, qname, previous, resp); + ret = ns_put_nsec_wildcard(zone, qname, previous, resp); } } - return r; + return ret; } /*----------------------------------------------------------------------------*/ @@ -1403,26 +1677,27 @@ static inline int ns_referral(const knot_node_t *node, knot_packet_t *resp, uint16_t qtype) { - dbg_ns("Referral response.\n"); + dbg_ns_verb("Referral response.\n"); while (!knot_node_is_deleg_point(node)) { assert(knot_node_parent(node) != NULL); node = knot_node_parent(node); } + int ret = KNOT_EOK; + // Special handling of DS queries if (qtype == KNOT_RRTYPE_DS) { knot_rrset_t *ds_rrset = knot_node_get_rrset(node, KNOT_RRTYPE_DS); - int ret = KNOT_EOK; if (ds_rrset) { - knot_response_add_rrset_answer(resp, ds_rrset, 1, 0, - 0, 1); - if (DNSSEC_ENABLED + ret = knot_response_add_rrset_answer(resp, ds_rrset, 1, + 0, 0, 1); + if (ret == KNOT_EOK && DNSSEC_ENABLED && knot_query_dnssec_requested( knot_packet_query(resp))) { - ns_add_rrsigs(ds_rrset, resp, node->owner, + ret = ns_add_rrsigs(ds_rrset, resp, node->owner, knot_response_add_rrset_authority, 1); } @@ -1430,18 +1705,13 @@ static inline int ns_referral(const knot_node_t *node, // normal NODATA response /*! \todo Handle in some generic way. */ - dbg_ns("Adding NSEC/NSEC3 for NODATA.\n"); - ns_put_nsec_nsec3_nodata(node, resp); + dbg_ns_verb("Adding NSEC/NSEC3 for NODATA.\n"); + ret = ns_put_nsec_nsec3_nodata(zone, node, resp); + if (ret != KNOT_EOK) { + return ret; + } - // wildcard delegations not supported! -// if (knot_dname_is_wildcard(node->owner)) { -// dbg_ns("Putting NSEC/NSEC3 for wildcard" -// " NODATA\n"); -// ret = ns_put_nsec_nsec3_wildcard_nodata(node, -// closest_encloser, previous, zone, qname, -// resp); -// } - ns_put_authority_soa(zone, resp); + ret = ns_put_authority_soa(zone, resp); } return ret; @@ -1449,39 +1719,42 @@ static inline int ns_referral(const knot_node_t *node, knot_rrset_t *rrset = knot_node_get_rrset(node, KNOT_RRTYPE_NS); assert(rrset != NULL); - - // TODO: wildcards?? - //ns_check_wildcard(name, resp, &rrset); - knot_response_add_rrset_authority(resp, rrset, 1, 0, 0, 1); - ns_add_rrsigs(rrset, resp, node->owner, - knot_response_add_rrset_authority, 1); + ret = knot_response_add_rrset_authority(resp, rrset, 1, 0, 0, 1); + if (ret == KNOT_EOK) { + ret = ns_add_rrsigs(rrset, resp, node->owner, + knot_response_add_rrset_authority, 1); + } - int ret = KNOT_EOK; // add DS records - dbg_ns("DNSSEC requested: %d\n", + dbg_ns_verb("DNSSEC requested: %d\n", knot_query_dnssec_requested(knot_packet_query(resp))); - dbg_ns("DS records: %p\n", knot_node_rrset(node, KNOT_RRTYPE_DS)); - if (DNSSEC_ENABLED + dbg_ns_verb("DS records: %p\n", knot_node_rrset(node, KNOT_RRTYPE_DS)); + if (ret == KNOT_EOK && DNSSEC_ENABLED && knot_query_dnssec_requested(knot_packet_query(resp))) { rrset = knot_node_get_rrset(node, KNOT_RRTYPE_DS); if (rrset != NULL) { - knot_response_add_rrset_authority(resp, rrset, 1, 0, - 0, 1); - ns_add_rrsigs(rrset, resp, node->owner, - knot_response_add_rrset_authority, 1); + ret = knot_response_add_rrset_authority(resp, rrset, 1, + 0, 0, 1); + if (ret == KNOT_EOK) { + ret = ns_add_rrsigs(rrset, resp, node->owner, + knot_response_add_rrset_authority, 1); + } } else { // no DS, add NSEC3 or NSEC // if NSEC3 enabled, search for NSEC3 if (knot_zone_contents_nsec3_enabled(zone)) { const knot_node_t *nsec3_node = knot_node_nsec3_node(node); - dbg_ns("There is no DS, putting NSEC3s...\n"); + dbg_ns_detail("There is no DS, putting NSEC3s." + "\n"); if (nsec3_node != NULL) { - dbg_ns("Putting NSEC3s from the node.\n"); - ns_put_nsec3_from_node(nsec3_node, resp); + dbg_ns_detail("Putting NSEC3s from the node.\n"); + ret = ns_put_nsec3_from_node(nsec3_node, + resp); } else { - dbg_ns("Putting Opt-Out NSEC3s.\n"); + dbg_ns_detail("Putting Opt-Out NSEC3s." + "\n"); // no NSEC3 (probably Opt-Out) // TODO: check if the zone is Opt-Out ret = ns_put_nsec3_closest_encloser_proof(zone, @@ -1492,10 +1765,11 @@ static inline int ns_referral(const knot_node_t *node, node, KNOT_RRTYPE_NSEC); if (nsec) { /*! \todo Check return value? */ - knot_response_add_rrset_authority( + ret = knot_response_add_rrset_authority( resp, nsec, 1, 1, 0, 1); - if ((nsec = knot_rrset_get_rrsigs(nsec)) != NULL) { - knot_response_add_rrset_authority( + if (ret == KNOT_EOK && + (nsec = knot_rrset_get_rrsigs(nsec)) != NULL) { + ret = knot_response_add_rrset_authority( resp, nsec, 1, 1, 0, 1); } } @@ -1503,10 +1777,13 @@ static inline int ns_referral(const knot_node_t *node, } } - if (ret == KNOT_EOK) { -// ns_put_additional(resp); + if (ret == KNOT_ESPACE) { + knot_response_set_rcode(resp, KNOT_RCODE_NOERROR); + ret = KNOT_EOK; + } else if (ret == KNOT_EOK) { knot_response_set_rcode(resp, KNOT_RCODE_NOERROR); } + return ret; } @@ -1540,65 +1817,65 @@ static int ns_answer_from_node(const knot_node_t *node, const knot_node_t *previous, const knot_zone_contents_t *zone, const knot_dname_t *qname, uint16_t qtype, - knot_packet_t *resp) + knot_packet_t *resp, int check_any) { - dbg_ns("Putting answers from found node to the response...\n"); - int answers = ns_put_answer(node, qname, qtype, resp); + dbg_ns_verb("Putting answers from found node to the response...\n"); + int answers = 0; + + int ret = ns_put_answer(node, zone, qname, qtype, resp, &answers, + check_any); + if (ret != KNOT_EOK) { + return ret; + } + + assert(ret == KNOT_EOK); - int ret = KNOT_EOK; if (answers == 0) { // if NODATA response, put SOA + ret = ns_put_authority_soa(zone, resp); if (knot_node_rrset_count(node) == 0 && !knot_zone_contents_nsec3_enabled(zone)) { // node is an empty non-terminal => NSEC for NXDOMAIN //assert(knot_node_rrset_count(closest_encloser) > 0); - dbg_ns("Adding NSEC/NSEC3 for NXDOMAIN.\n"); + dbg_ns_verb("Adding NSEC/NSEC3 for NXDOMAIN.\n"); ret = ns_put_nsec_nsec3_nxdomain(zone, knot_node_previous(node), closest_encloser, qname, resp); } else { - dbg_ns("Adding NSEC/NSEC3 for NODATA.\n"); - ns_put_nsec_nsec3_nodata(node, resp); + dbg_ns_verb("Adding NSEC/NSEC3 for NODATA.\n"); + ret = ns_put_nsec_nsec3_nodata(zone, node, resp); + if (ret != KNOT_EOK) { + dbg_ns("Failed adding NSEC/NSEC3 for NODATA: %s" + "\n", knot_strerror(ret)); + return ret; + } + if (knot_dname_is_wildcard(node->owner)) { - dbg_ns("Putting NSEC/NSEC3 for wildcard" - " NODATA\n"); + dbg_ns_verb("Putting NSEC/NSEC3 for wildcard" + " NODATA\n"); ret = ns_put_nsec_nsec3_wildcard_nodata(node, closest_encloser, previous, zone, qname, resp); + if (ret != KNOT_EOK) { + return ret; + } } } - ns_put_authority_soa(zone, resp); } else { // else put authority NS // if wildcard answer, add NSEC / NSEC3 - dbg_ns("Adding NSEC/NSEC3 for wildcard answer.\n"); - -// char *n = knot_dname_to_str(knot_node_owner(node)); -// char *ce = (closest_encloser) -// ? knot_dname_to_str(knot_node_owner(closest_encloser)) -// : "(nil)"; -// char *prev = (previous) -// ? knot_dname_to_str(knot_node_owner(previous)) -// : "(nil)"; -// printf("Node: %s, closest encloser: %s, previous: %s\n", -// n, ce, prev); -// free(n); -// if (closest_encloser) { -// free(ce); -// } -// if (previous) { -// free(prev); -// } + dbg_ns_verb("Adding NSEC/NSEC3 for wildcard answer.\n"); + assert(previous == NULL); assert(closest_encloser == knot_node_parent(node) || !knot_dname_is_wildcard(knot_node_owner(node))); ret = ns_put_nsec_nsec3_wildcard_answer(node, closest_encloser, previous, zone, qname, resp); - ns_put_authority_ns(zone, resp); + + if (ret == KNOT_EOK) { + ret = ns_put_authority_ns(zone, resp); + } } -// if (ret == KNOT_EOK) { -// ns_put_additional(resp); -// } return ret; } @@ -1617,7 +1894,7 @@ static int ns_answer_from_node(const knot_node_t *node, static knot_rrset_t *ns_cname_from_dname(const knot_rrset_t *dname_rrset, const knot_dname_t *qname) { - dbg_ns("Synthetizing CNAME from DNAME...\n"); + dbg_ns_verb("Synthetizing CNAME from DNAME...\n"); // create new CNAME RRSet @@ -1642,15 +1919,25 @@ static knot_rrset_t *ns_cname_from_dname(const knot_rrset_t *dname_rrset, knot_rdata_get_item(knot_rrset_rdata(dname_rrset), 0)->dname); dbg_ns_exec( char *name = knot_dname_to_str(cname); - dbg_ns("CNAME canonical name: %s.\n", name); + dbg_ns_verb("CNAME canonical name: %s.\n", name); free(name); ); knot_rdata_t *cname_rdata = knot_rdata_new(); knot_rdata_item_t cname_rdata_item; cname_rdata_item.dname = cname; - knot_rdata_set_items(cname_rdata, &cname_rdata_item, 1); + int ret = knot_rdata_set_items(cname_rdata, &cname_rdata_item, 1); + if (ret != KNOT_EOK) { + knot_rrset_deep_free(&cname_rrset, 1, 1, 1); + knot_rdata_deep_free(&cname_rdata, KNOT_RRTYPE_CNAME, 1); + return NULL; + } - knot_rrset_add_rdata(cname_rrset, cname_rdata); + ret = knot_rrset_add_rdata(cname_rrset, cname_rdata); + if (ret != KNOT_EOK) { + knot_rrset_deep_free(&cname_rrset, 1, 1, 1); + knot_rdata_deep_free(&cname_rdata, KNOT_RRTYPE_CNAME, 1); + return NULL; + } return cname_rrset; } @@ -1694,38 +1981,59 @@ static int ns_dname_is_too_long(const knot_rrset_t *dname_rrset, * \param qname Searched name. * \param resp Response. */ -static void ns_process_dname(knot_rrset_t *dname_rrset, - const knot_dname_t *qname, +static int ns_process_dname(knot_rrset_t *dname_rrset, + const knot_dname_t **qname, knot_packet_t *resp) { -dbg_ns_exec( +dbg_ns_exec_verb( char *name = knot_dname_to_str(knot_rrset_owner(dname_rrset)); - dbg_ns("Processing DNAME for owner %s...\n", name); + dbg_ns_verb("Processing DNAME for owner %s...\n", name); free(name); ); // TODO: check the number of RRs in the RRSet?? // put the DNAME RRSet into the answer - knot_response_add_rrset_answer(resp, dname_rrset, 1, 0, 0, 1); - ns_add_rrsigs(dname_rrset, resp, qname, - knot_response_add_rrset_answer, 1); + int ret = knot_response_add_rrset_answer(resp, dname_rrset, 1, 0, 0, 1); + if (ret != KNOT_EOK) { + return ret; + } - if (ns_dname_is_too_long(dname_rrset, qname)) { + ret = ns_add_rrsigs(dname_rrset, resp, *qname, + knot_response_add_rrset_answer, 1); + if (ret != KNOT_EOK) { + return ret; + } + + if (ns_dname_is_too_long(dname_rrset, *qname)) { knot_response_set_rcode(resp, KNOT_RCODE_YXDOMAIN); - return; + return KNOT_EOK; } // synthetize CNAME (no way to tell that client supports DNAME) - knot_rrset_t *synth_cname = ns_cname_from_dname(dname_rrset, qname); + knot_rrset_t *synth_cname = ns_cname_from_dname(dname_rrset, *qname); // add the synthetized RRSet to the Answer - knot_response_add_rrset_answer(resp, synth_cname, 1, 0, 0, 1); + ret = knot_response_add_rrset_answer(resp, synth_cname, 1, 0, 0, 1); + if (ret != KNOT_EOK) { + return ret; + } // no RRSIGs for this RRSet // add the synthetized RRSet into list of temporary RRSets of response - knot_packet_add_tmp_rrset(resp, synth_cname); + ret = knot_packet_add_tmp_rrset(resp, synth_cname); + if (ret != KNOT_EOK) { + return ret; + } + + // get the next SNAME from the CNAME RDATA + const knot_dname_t *cname = knot_rdata_cname_name( + knot_rrset_rdata(synth_cname)); + dbg_ns_verb("CNAME name from RDATA: %p\n", cname); - // do not search for the name in new zone (out-of-bailiwick) + // save the new name which should be used for replacing wildcard + *qname = cname; + + return KNOT_EOK; } /*----------------------------------------------------------------------------*/ @@ -1735,15 +2043,23 @@ dbg_ns_exec( * \param apex Zone apex node. * \param resp Response. */ -static void ns_add_dnskey(const knot_node_t *apex, knot_packet_t *resp) +static int ns_add_dnskey(const knot_node_t *apex, knot_packet_t *resp) { knot_rrset_t *rrset = knot_node_get_rrset(apex, KNOT_RRTYPE_DNSKEY); + + int ret = KNOT_EOK; + if (rrset != NULL) { - knot_response_add_rrset_additional(resp, rrset, 0, 0, 0, 1); - ns_add_rrsigs(rrset, resp, apex->owner, - knot_response_add_rrset_additional, 0); + ret = knot_response_add_rrset_additional(resp, rrset, 0, 0, + 0, 1); + if (ret == KNOT_EOK) { + ret = ns_add_rrsigs(rrset, resp, apex->owner, + knot_response_add_rrset_additional, 0); + } } + + return ret; } /*----------------------------------------------------------------------------*/ @@ -1763,7 +2079,7 @@ static void ns_add_dnskey(const knot_node_t *apex, knot_packet_t *resp) * \todo Describe the answering logic in detail. */ static int ns_answer_from_zone(const knot_zone_contents_t *zone, - knot_packet_t *resp) + knot_packet_t *resp, int check_any) { const knot_node_t *node = NULL, *closest_encloser = NULL, *previous = NULL; @@ -1774,13 +2090,9 @@ static int ns_answer_from_zone(const knot_zone_contents_t *zone, search: #ifdef USE_HASH_TABLE - /*! \todo Check version. */ find_ret = knot_zone_contents_find_dname_hash(zone, qname, &node, &closest_encloser); -// node = knot_node_current(node); -// closest_encloser = knot_node_current(closest_encloser); #else - /*! \todo Check version. */ find_ret = knot_zone_contents_find_dname(zone, qname, &node, &closest_encloser, &previous); node = knot_node_current(node); @@ -1791,33 +2103,33 @@ search: return NS_ERR_SERVFAIL; } -dbg_ns_exec( +dbg_ns_exec_verb( char *name; if (node) { name = knot_dname_to_str(node->owner); - dbg_ns("zone_find_dname() returned node %s \n", name); + dbg_ns_verb("zone_find_dname() returned node %s \n", name); free(name); } else { - dbg_ns("zone_find_dname() returned no node,\n"); + dbg_ns_verb("zone_find_dname() returned no node,\n"); } if (closest_encloser != NULL) { name = knot_dname_to_str(closest_encloser->owner); - dbg_ns(" closest encloser %s.\n", name); + dbg_ns_verb(" closest encloser %s.\n", name); free(name); } else { - dbg_ns(" closest encloser (nil).\n"); + dbg_ns_verb(" closest encloser (nil).\n"); } if (previous != NULL) { name = knot_dname_to_str(previous->owner); - dbg_ns(" and previous node: %s.\n", name); + dbg_ns_verb(" and previous node: %s.\n", name); free(name); } else { - dbg_ns(" and previous node: (nil).\n"); + dbg_ns_verb(" and previous node: (nil).\n"); } ); if (find_ret == KNOT_EBADZONE) { - // possible only if we followed cname + // possible only if we followed CNAME or DNAME assert(cname != 0); knot_response_set_rcode(resp, KNOT_RCODE_NOERROR); auth_soa = 1; @@ -1826,10 +2138,10 @@ dbg_ns_exec( } have_node: - dbg_ns("Closest encloser is deleg. point? %s\n", + dbg_ns_verb("Closest encloser is deleg. point? %s\n", (knot_node_is_deleg_point(closest_encloser)) ? "yes" : "no"); - dbg_ns("Closest encloser is non authoritative? %s\n", + dbg_ns_verb("Closest encloser is non authoritative? %s\n", (knot_node_is_non_auth(closest_encloser)) ? "yes" : "no"); if (knot_node_is_deleg_point(closest_encloser) @@ -1843,21 +2155,31 @@ have_node: knot_rrset_t *dname_rrset = knot_node_get_rrset( closest_encloser, KNOT_RRTYPE_DNAME); if (dname_rrset != NULL) { - ns_process_dname(dname_rrset, qname, resp); - auth_soa = 1; + ret = ns_process_dname(dname_rrset, &qname, resp); + knot_response_set_aa(resp); - goto finalize; + + if (ret != KNOT_EOK) { + goto finalize; + } + + // do not search for the name in new zone + // (out-of-bailiwick), just in the current zone if it + // belongs there + + cname = 1; + goto search; } // else check for a wildcard child const knot_node_t *wildcard_node = knot_node_wildcard_child(closest_encloser); if (wildcard_node == NULL) { - dbg_ns("No wildcard node. (cname: %d)\n", - cname); + dbg_ns_verb("No wildcard node. (cname: %d)\n", + cname); auth_soa = 1; if (cname == 0) { - dbg_ns("Setting NXDOMAIN RCODE.\n"); + dbg_ns_detail("Setting NXDOMAIN RCODE.\n"); // return NXDOMAIN knot_response_set_rcode(resp, KNOT_RCODE_NXDOMAIN); @@ -1884,24 +2206,31 @@ have_node: } if (knot_node_rrset(node, KNOT_RRTYPE_CNAME) != NULL - && qtype != KNOT_RRTYPE_CNAME) { + && qtype != KNOT_RRTYPE_CNAME && qtype != KNOT_RRTYPE_RRSIG) { dbg_ns_exec( char *name = knot_dname_to_str(node->owner); - dbg_ns("Node %s has CNAME record, resolving...\n", - name); + dbg_ns_verb("Node %s has CNAME record, resolving...\n", name); free(name); ); const knot_dname_t *act_name = qname; - ns_follow_cname(&node, &act_name, resp, - knot_response_add_rrset_answer, 1); -dbg_ns_exec( + ret = ns_follow_cname(&node, &act_name, resp, + knot_response_add_rrset_answer, 1); + + /*! \todo IS OK??? */ + knot_response_set_aa(resp); + + if (ret != KNOT_EOK) { + // KNOT_ESPACE case is handled there + goto finalize; + } +dbg_ns_exec_verb( char *name = (node != NULL) ? knot_dname_to_str(node->owner) : "(nil)"; char *name2 = knot_dname_to_str(act_name); - dbg_ns("Canonical name: %s (%p), node found: %p\n", - name2, act_name, node); - dbg_ns("The node's owner: %s (%p)\n", name, (node != NULL) - ? node->owner : NULL); + dbg_ns_verb("Canonical name: %s (%p), node found: %p\n", + name2, act_name, node); + dbg_ns_verb("The node's owner: %s (%p)\n", name, (node != NULL) + ? node->owner : NULL); if (node != NULL) { free(name); } @@ -1913,25 +2242,33 @@ dbg_ns_exec( // otherwise search for the new name if (node == NULL) { goto search; - } else if (node->owner != act_name) { - // the stored node is closest encloser - find_ret = KNOT_ZONE_NAME_NOT_FOUND; - closest_encloser = node; - node = NULL; - goto have_node; - } // else do nothing, just continue + } else if (knot_node_owner(node) != act_name) { + if(knot_dname_is_wildcard(knot_node_owner(node))) { + // we must set the closest encloser to the + // parent of the node, to be right + closest_encloser = knot_node_parent(node); + assert(closest_encloser != NULL); + } else { + // the stored node is closest encloser + find_ret = KNOT_ZONE_NAME_NOT_FOUND; + closest_encloser = node; + node = NULL; + goto have_node; + } + } } ret = ns_answer_from_node(node, closest_encloser, previous, zone, qname, - qtype, resp); + qtype, resp, check_any); if (ret == NS_ERR_SERVFAIL) { // in this case we should drop the response and send an error // for now, just send the error code with a non-complete answer -// knot_response_set_rcode(resp, KNOT_RCODE_SERVFAIL); -// goto finalize; return ret; } else if (ret != KNOT_EOK) { /*! \todo Handle RCODE return values!!! */ + // In case ret == KNOT_ESPACE, this is later converted to EOK + // so it does not cause error response + knot_response_set_aa(resp); goto finalize; } knot_response_set_aa(resp); @@ -1940,16 +2277,21 @@ dbg_ns_exec( // this is the only case when the servers answers from // particular node, i.e. the only case when it may return SOA // or NS records in Answer section - if (DNSSEC_ENABLED + if (knot_packet_tc(resp) == 0 && DNSSEC_ENABLED && knot_query_dnssec_requested(knot_packet_query(resp)) && node == knot_zone_contents_apex(zone) && (qtype == KNOT_RRTYPE_SOA || qtype == KNOT_RRTYPE_NS)) { - ns_add_dnskey(node, resp); + ret = ns_add_dnskey(node, resp); } finalize: - if (ret == KNOT_EOK && auth_soa) { - ns_put_authority_soa(zone, resp); + if (ret == KNOT_EOK && knot_packet_tc(resp) == 0 && auth_soa) { + ret = ns_put_authority_soa(zone, resp); + } + + if (ret == KNOT_ESPACE) { + knot_response_set_rcode(resp, KNOT_RCODE_NOERROR); + ret = KNOT_EOK; } // add all missing NSECs/NSEC3s for wildcard nodes @@ -1976,20 +2318,9 @@ finalize: * \retval KNOT_EOK * \retval NS_ERR_SERVFAIL */ -static int ns_answer(const knot_zone_t *zone, knot_packet_t *resp) -{ -// const knot_dname_t *qname = knot_packet_qname(resp); -// assert(qname != NULL); - -// uint16_t qtype = knot_packet_qtype(resp); -//dbg_ns_exec( -// char *name_str = knot_dname_to_str(qname); -// dbg_ns("Trying to find zone for QNAME %s\n", name_str); -// free(name_str); -//); -// // find zone in which to search for the name -// const knot_zone_t *zone = -// ns_get_zone_for_qname(db, qname, qtype); +static int ns_answer(const knot_zone_t *zone, knot_packet_t *resp, + int check_any) +{ const knot_zone_contents_t *contents = knot_zone_contents(zone); // if no zone found, return REFUSED @@ -2012,9 +2343,7 @@ dbg_ns_exec( // take the zone contents and use only them for answering - return ns_answer_from_zone(contents, resp); - - //knot_dname_free(&qname); + return ns_answer_from_zone(contents, resp, check_any); } /*----------------------------------------------------------------------------*/ @@ -2026,10 +2355,9 @@ int ns_response_to_wire(knot_packet_t *resp, uint8_t *wire, size_t rsize = 0; int ret = 0; - if ((ret = knot_packet_to_wire(resp, &rwire, &rsize)) - != KNOT_EOK) { + if ((ret = knot_packet_to_wire(resp, &rwire, &rsize)) != KNOT_EOK) { dbg_ns("Error converting response packet " - "to wire format (error %d).\n", ret); + "to wire format (error %d).\n", ret); return NS_ERR_SERVFAIL; } @@ -2041,14 +2369,13 @@ int ns_response_to_wire(knot_packet_t *resp, uint8_t *wire, if (rwire != wire) { dbg_ns("Wire format reallocated, copying to place for " - "wire.\n"); + "wire.\n"); memcpy(wire, rwire, rsize); } else { dbg_ns("Using the same space or wire format.\n"); } *wire_size = rsize; - //free(rwire); return KNOT_EOK; } @@ -2073,17 +2400,17 @@ static int ns_error_response_to_wire(knot_packet_t *resp, uint8_t *wire, * wire format is assembled, but COUNTs in header are not set. * This is ideal, we just truncate the packet after the question. */ - dbg_ns("Creating error response.\n"); + dbg_ns_verb("Creating error response.\n"); size_t rsize = knot_packet_question_size(knot_packet_query(resp)); - dbg_ns("Error response (~ query) size: %zu\n", rsize); + dbg_ns_detail("Error response (~ query) size: %zu\n", rsize); // take 'qsize' from the current wireformat of the response // it is already assembled - Header and Question section are copied const uint8_t *rwire = knot_packet_wireformat(resp); if (rsize > *wire_size) { dbg_ns("Reponse size (%zu) larger than allowed wire size" - " (%zu).\n", rsize, *wire_size); + " (%zu).\n", rsize, *wire_size); return NS_ERR_SERVFAIL; } @@ -2116,8 +2443,8 @@ typedef struct ns_axfr_params { int knot_ns_tsig_required(int packet_nr) { - dbg_ns_detail("ns_tsig_required(%d): %d\n", packet_nr, - (packet_nr % KNOT_NS_TSIG_FREQ == 0)); + dbg_ns_verb("ns_tsig_required(%d): %d\n", packet_nr, + (packet_nr % KNOT_NS_TSIG_FREQ == 0)); return (packet_nr % KNOT_NS_TSIG_FREQ == 0); } @@ -2132,7 +2459,7 @@ static int ns_xfr_send_and_clear(knot_ns_xfr_t *xfr, int add_tsig) assert(xfr->send != NULL); // Transform the packet into wire format - dbg_ns("Converting response to wire format..\n"); + dbg_ns_verb("Converting response to wire format..\n"); size_t real_size = xfr->wire_size; if (ns_response_to_wire(xfr->response, xfr->wire, &real_size) != 0) { return NS_ERR_SERVFAIL; @@ -2154,15 +2481,14 @@ static int ns_xfr_send_and_clear(knot_ns_xfr_t *xfr, int add_tsig) xfr->tsig_data_size += real_size; } - /*! \note [TSIG] Generate TSIG if required (during XFR/IN). */ if (xfr->tsig_key && add_tsig) { if (xfr->packet_nr == 0) { /* Add key, digest and digest length. */ dbg_ns_detail("Calling tsig_sign(): %p, %zu, %zu, " - "%p, %zu, %p, %zu, %p\n", - xfr->wire, real_size, xfr->wire_size, - xfr->digest, xfr->digest_size, xfr->digest, - digest_real_size, xfr->tsig_key); + "%p, %zu, %p, %zu, %p\n", + xfr->wire, real_size, xfr->wire_size, + xfr->digest, xfr->digest_size, xfr->digest, + digest_real_size, xfr->tsig_key); res = knot_tsig_sign(xfr->wire, &real_size, xfr->wire_size, xfr->digest, xfr->digest_size, xfr->digest, @@ -2182,8 +2508,7 @@ static int ns_xfr_send_and_clear(knot_ns_xfr_t *xfr, int add_tsig) xfr->tsig_data_size); } - dbg_ns_detail("Sign function returned: %s\n", - knot_strerror(res)); + dbg_ns_verb("Sign function returned: %s\n", knot_strerror(res)); dbg_ns_detail("Real size of digest: %zu\n", digest_real_size); if (res != KNOT_EOK) { @@ -2198,8 +2523,8 @@ static int ns_xfr_send_and_clear(knot_ns_xfr_t *xfr, int add_tsig) xfr->tsig_data_size = 0; } else if (xfr->tsig_rcode != 0) { - dbg_ns_detail("Adding TSIG without signing, TSIG RCODE: %d.\n", - xfr->tsig_rcode); + dbg_ns_verb("Adding TSIG without signing, TSIG RCODE: %d.\n", + xfr->tsig_rcode); assert(xfr->tsig_rcode != KNOT_TSIG_RCODE_BADTIME); // add TSIG without signing assert(xfr->query != NULL); @@ -2225,12 +2550,11 @@ static int ns_xfr_send_and_clear(knot_ns_xfr_t *xfr, int add_tsig) return res; } else if (res != real_size) { dbg_ns("AXFR did not send right amount of bytes." - " Transfer size: %zu, sent: %d\n", - real_size, res); + " Transfer size: %zu, sent: %d\n", real_size, res); } // Clean the response structure - dbg_ns("Clearing response structure..\n"); + dbg_ns_verb("Clearing response structure..\n"); knot_response_clear(xfr->response, 0); // increment the packet number @@ -2243,8 +2567,10 @@ static int ns_xfr_send_and_clear(knot_ns_xfr_t *xfr, int add_tsig) knot_packet_set_tsig_size(xfr->response, 0); } - dbg_ns("Response structure after clearing:\n"); +dbg_ns_exec_verb( + dbg_ns_verb("Response structure after clearing:\n"); knot_packet_dump(xfr->response); +); return KNOT_EOK; } @@ -2260,15 +2586,15 @@ static void ns_axfr_from_node(knot_node_t *node, void *data) if (params->ret != KNOT_EOK) { // just skip (will be called on next node with the same params - dbg_ns("Params contain error: %s, skipping node...\n", + dbg_ns_detail("Params contain error: %s, skipping node...\n", knot_strerror(params->ret)); return; } - dbg_ns("Params OK, answering AXFR from node %p.\n", node); -dbg_ns_exec( + dbg_ns_detail("Params OK, answering AXFR from node %p.\n", node); +dbg_ns_exec_verb( char *name = knot_dname_to_str(knot_node_owner(node)); - dbg_ns("Node ownerr: %s\n", name); + dbg_ns_verb("Node owner: %s\n", name); free(name); ); @@ -2289,8 +2615,8 @@ dbg_ns_exec( assert(rrsets[i] != NULL); rrset = rrsets[i]; rrset: - dbg_ns(" Type: %s\n", - knot_rrtype_to_string(knot_rrset_type(rrset))); + dbg_ns_verb(" Type: %s\n", + knot_rrtype_to_string(knot_rrset_type(rrset))); // do not add SOA if (knot_rrset_type(rrset) == KNOT_RRTYPE_SOA) { @@ -2477,9 +2803,7 @@ static int ns_ixfr_put_rrset(knot_ns_xfr_t *xfr, knot_rrset_t *rrset) /*! \todo Probably send back AXFR instead. */ knot_response_set_rcode(xfr->response, KNOT_RCODE_SERVFAIL); - /*! \todo Probably rename the function. */ ns_xfr_send_and_clear(xfr, 1); - //socket_close(xfr->session); /*! \todo Remove for UDP.*/ return res; } @@ -2546,12 +2870,10 @@ static int ns_ixfr_from_zone(knot_ns_xfr_t *xfr) 0, 0, 0); if (res != KNOT_EOK) { dbg_ns("IXFR query cannot be answered: %s.\n", - knot_strerror(res)); + knot_strerror(res)); knot_response_set_rcode(xfr->response, KNOT_RCODE_SERVFAIL); - /*! \todo Probably rename the function. */ ns_xfr_send_and_clear(xfr, 1); -// socket_close(xfr->session); /*! \todo Remove for UDP.*/ rcu_read_unlock(); return res; } @@ -2571,10 +2893,7 @@ static int ns_ixfr_from_zone(knot_ns_xfr_t *xfr) } if (res == KNOT_EOK) { - /*! \todo Probably rename the function. */ ns_xfr_send_and_clear(xfr, 1); - //socket_close(xfr->session); /*! \todo Remove for UDP.*/ -// return 1; } rcu_read_unlock(); @@ -2596,7 +2915,6 @@ static int ns_ixfr(knot_ns_xfr_t *xfr) // malformed packet dbg_ns("IXFR query does not contain authority record.\n"); knot_response_set_rcode(xfr->response, KNOT_RCODE_FORMERR); - /*! \todo Probably rename the function. */ if (ns_xfr_send_and_clear(xfr, 1) == KNOT_ECONN) { return KNOT_ECONN; } @@ -2614,11 +2932,9 @@ static int ns_ixfr(knot_ns_xfr_t *xfr) // malformed packet dbg_ns("IXFR query is malformed.\n"); knot_response_set_rcode(xfr->response, KNOT_RCODE_FORMERR); - /*! \todo Probably rename the function. */ if (ns_xfr_send_and_clear(xfr, 1) == KNOT_ECONN) { return KNOT_ECONN; } - //socket_close(xfr->session); /*! \todo Remove for UDP. */ return KNOT_EMALF; } @@ -2627,8 +2943,7 @@ static int ns_ixfr(knot_ns_xfr_t *xfr) /*----------------------------------------------------------------------------*/ -static int knot_ns_prepare_response(knot_nameserver_t *nameserver, - knot_packet_t *query, knot_packet_t **resp, +static int knot_ns_prepare_response(knot_packet_t *query, knot_packet_t **resp, size_t max_size) { assert(max_size >= 500); @@ -2641,8 +2956,6 @@ static int knot_ns_prepare_response(knot_nameserver_t *nameserver, } int ret = knot_packet_set_max_size(*resp, max_size); - //(*resp)->wireformat = response_wire;; - //(*resp)->max_size = max_size; if (ret != KNOT_EOK) { dbg_ns("Failed to init response structure.\n"); @@ -2827,14 +3140,12 @@ void knot_ns_set_nsid(knot_nameserver_t *nameserver, const char *nsid, size_t le int ret = knot_ns_replace_nsid(nameserver->opt_rr, nsid, len); -// int ret = knot_edns_add_option(nameserver->opt_rr, EDNS_OPTION_NSID, -// len, (const uint8_t *)nsid); if (ret != KNOT_EOK) { dbg_ns("NS: set_nsid: could not add EDNS option.\n"); return; } - dbg_ns("NS: set_nsid: added successfully.\n"); + dbg_ns_verb("NS: set_nsid: added successfully.\n"); } /*----------------------------------------------------------------------------*/ @@ -2847,28 +3158,21 @@ int knot_ns_parse_packet(const uint8_t *query_wire, size_t qsize, return KNOT_EBADARG; } - dbg_ns("ns_parse_packet() called with query size %zu.\n", qsize); - //dbg_ns_hex((char *)query_wire, qsize); - - if (qsize < 2) { - return KNOT_EMALF; - } + dbg_ns_verb("ns_parse_packet() called with query size %zu.\n", qsize); // 1) create empty response - dbg_ns("Parsing packet...\n"); - //parsed = knot_response_new_empty(NULL); + dbg_ns_verb("Parsing packet...\n"); int ret = 0; if ((ret = knot_packet_parse_from_wire(packet, query_wire, qsize, 1)) != 0) { dbg_ns("Error while parsing packet, " - "libknot error '%s'.\n", knot_strerror(ret)); -// knot_response_free(&parsed); + "libknot error '%s'.\n", knot_strerror(ret)); return KNOT_RCODE_FORMERR; } - dbg_ns("Parsed packet header and Question:\n"); + dbg_ns_verb("Parsed packet header and Question:\n"); knot_packet_dump(packet); // 3) determine the query type @@ -2904,17 +3208,15 @@ int knot_ns_parse_packet(const uint8_t *query_wire, size_t qsize, return KNOT_RCODE_NOTIMPL; } -// knot_packet_free(&packet); - return KNOT_EOK; } /*----------------------------------------------------------------------------*/ -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) +static 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) { memcpy(response_wire, nameserver->err_response, nameserver->err_resp_size); @@ -2927,7 +3229,7 @@ void knot_ns_error_response(const knot_nameserver_t *nameserver, knot_wire_set_rd(response_wire); } knot_wire_set_opcode(response_wire, - knot_wire_flags_get_opcode(*flags1_query)); + knot_wire_flags_get_opcode(*flags1_query)); } // set the RCODE @@ -2937,10 +3239,10 @@ void knot_ns_error_response(const knot_nameserver_t *nameserver, /*----------------------------------------------------------------------------*/ -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) +int knot_ns_error_response_from_query_wire(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 @@ -2964,6 +3266,63 @@ int knot_ns_error_response_from_query(const knot_nameserver_t *nameserver, /*----------------------------------------------------------------------------*/ +int knot_ns_error_response_from_query(const knot_nameserver_t *nameserver, + const knot_packet_t *query, + uint8_t rcode, uint8_t *response_wire, + size_t *rsize) +{ + if (query->parsed < 2) { + // ignore packet + return KNOT_EFEWDATA; + } + + if (query->parsed < KNOT_WIRE_HEADER_SIZE) { + return knot_ns_error_response_from_query_wire(nameserver, + query->wireformat, query->size, rcode, response_wire, + rsize); + } + + size_t max_size = *rsize; + uint8_t flags1 = knot_wire_get_flags1(knot_packet_wireformat(query)); + + // prepare the generic error response + knot_ns_error_response(nameserver, knot_packet_id(query), + &flags1, rcode, response_wire, + rsize); + + if (query->parsed > KNOT_WIRE_HEADER_SIZE + + KNOT_WIRE_QUESTION_MIN_SIZE) { + // in this case the whole question was parsed, append it + size_t question_size = 4 + knot_dname_size( + knot_packet_qname(query)); + + if (max_size > KNOT_WIRE_HEADER_SIZE + question_size) { + /* + * At this point, the wireformat of query may be in the + * same place where the response is assembled. This does + * not matter before this point, although the query + * wireformat is rewritten. Now we just need to copy + * the original Question section. So if the pointers are + * the same, we may just leave it and increase the + * response wire size. Otherwise we must copy the data. + */ + if (response_wire != knot_packet_wireformat(query)) { + memcpy(response_wire + KNOT_WIRE_HEADER_SIZE, + knot_packet_wireformat(query) + + KNOT_WIRE_HEADER_SIZE, question_size); + } + *rsize += question_size; + + // adjust QDCOUNT + knot_wire_set_qdcount(response_wire, 1); + } + } + + 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) @@ -2971,11 +3330,10 @@ void knot_ns_error_response_full(knot_nameserver_t *nameserver, knot_response_set_rcode(response, rcode); 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); + knot_ns_error_response_from_query(nameserver, + knot_packet_query(response), + KNOT_RCODE_SERVFAIL, + response_wire, rsize); } } @@ -2985,7 +3343,7 @@ int knot_ns_prep_normal_response(knot_nameserver_t *nameserver, knot_packet_t *query, knot_packet_t **resp, const knot_zone_t **zone, size_t max_size) { - dbg_ns("knot_ns_prep_normal_response()\n"); + dbg_ns_verb("knot_ns_prep_normal_response()\n"); if (nameserver == NULL || query == NULL || resp == NULL || zone == NULL) { @@ -2994,8 +3352,8 @@ int knot_ns_prep_normal_response(knot_nameserver_t *nameserver, // first, parse the rest of the packet assert(knot_packet_is_query(query)); - dbg_ns("Query - parsed: %zu, total wire size: %zu\n", - knot_packet_parsed(query), knot_packet_size(query)); + dbg_ns_verb("Query - parsed: %zu, total wire size: %zu\n", + knot_packet_parsed(query), knot_packet_size(query)); int ret; ret = knot_packet_parse_rest(query); @@ -3017,10 +3375,38 @@ int knot_ns_prep_normal_response(knot_nameserver_t *nameserver, if (knot_packet_ancount(query) > 0 || knot_packet_nscount(query) > 0 || knot_packet_qdcount(query) != 1) { - dbg_ns("ANCOUNT or NSCOUNT not 0 in query, reply FORMERR.\n"); + dbg_ns("ANCOUNT or NSCOUNT not 0 in query, " + "or QDCOUNT != 1. Reply FORMERR.\n"); return KNOT_EMALF; } + /* + * Check what is in the Additional section. Only OPT and TSIG are + * allowed. TSIG must be the last record if present. + */ + if (knot_packet_arcount(query) > 0) { + int ok = 0; + const knot_rrset_t *add1 = + knot_packet_additional_rrset(query, 0); + if (knot_packet_additional_rrset_count(query) == 1 + && (knot_rrset_type(add1) == KNOT_RRTYPE_OPT + || knot_rrset_type(add1) == KNOT_RRTYPE_TSIG)) { + ok = 1; + } else if (knot_packet_additional_rrset_count(query) == 2) { + const knot_rrset_t *add2 = + knot_packet_additional_rrset(query, 1); + if (knot_rrset_type(add1) == KNOT_RRTYPE_OPT + && knot_rrset_type(add2) == KNOT_RRTYPE_TSIG) { + ok = 1; + } + } + + if (!ok) { + dbg_ns("Additional section malformed. Reply FORMERR\n"); + return KNOT_EMALF; + } + } + size_t resp_max_size = 0; knot_packet_dump(query); @@ -3044,22 +3430,21 @@ int knot_ns_prep_normal_response(knot_nameserver_t *nameserver, resp_max_size = MAX_UDP_PAYLOAD; } - ret = knot_ns_prepare_response(nameserver, query, resp, - resp_max_size); + ret = knot_ns_prepare_response(query, resp, resp_max_size); if (ret != KNOT_EOK) { return KNOT_ERROR; } - dbg_ns("Query - parsed: %zu, total wire size: %zu\n", - query->parsed, query->size); - dbg_ns("Opt RR: version: %d, payload: %d\n", + dbg_ns_verb("Query - parsed: %zu, total wire size: %zu\n", + query->parsed, query->size); + dbg_ns_detail("Opt RR: version: %d, payload: %d\n", query->opt_rr.version, query->opt_rr.payload); // get the answer for the query knot_zonedb_t *zonedb = rcu_dereference(nameserver->zone_db); - dbg_ns("EDNS supported in query: %d\n", - knot_query_edns_supported(query)); + dbg_ns_detail("EDNS supported in query: %d\n", + knot_query_edns_supported(query)); // set the OPT RR to the response if (knot_query_edns_supported(query)) { @@ -3067,25 +3452,24 @@ int knot_ns_prep_normal_response(knot_nameserver_t *nameserver, knot_query_nsid_requested(query)); if (ret != KNOT_EOK) { dbg_ns("Failed to set OPT RR to the response" - ": %s\n", knot_strerror(ret)); + ": %s\n", knot_strerror(ret)); } else { // copy the DO bit from the query if (knot_query_dnssec_requested(query)) { - /*! \todo API for this. */ knot_edns_set_do(&(*resp)->opt_rr); } } } - dbg_ns("Response max size: %zu\n", (*resp)->max_size); + dbg_ns_verb("Response max size: %zu\n", (*resp)->max_size); const knot_dname_t *qname = knot_packet_qname(*resp); assert(qname != NULL); uint16_t qtype = knot_packet_qtype(*resp); -dbg_ns_exec( +dbg_ns_exec_verb( char *name_str = knot_dname_to_str(qname); - dbg_ns("Trying to find zone for QNAME %s\n", name_str); + dbg_ns_verb("Trying to find zone for QNAME %s\n", name_str); free(name_str); ); // find zone in which to search for the name @@ -3098,11 +3482,11 @@ dbg_ns_exec( int knot_ns_answer_normal(knot_nameserver_t *nameserver, const knot_zone_t *zone, knot_packet_t *resp, - uint8_t *response_wire, size_t *rsize) + uint8_t *response_wire, size_t *rsize, int check_any) { - dbg_ns("ns_answer_normal()\n"); + dbg_ns_verb("ns_answer_normal()\n"); - int ret = ns_answer(zone, resp); + int ret = ns_answer(zone, resp, check_any); if (ret != 0) { // now only one type of error (SERVFAIL), later maybe more @@ -3110,7 +3494,7 @@ int knot_ns_answer_normal(knot_nameserver_t *nameserver, KNOT_RCODE_SERVFAIL, response_wire, rsize); } else { - dbg_ns("Created response packet.\n"); + dbg_ns_verb("Created response packet.\n"); //knot_response_dump(resp); knot_packet_dump(resp); @@ -3123,6 +3507,55 @@ int knot_ns_answer_normal(knot_nameserver_t *nameserver, } } + dbg_ns_verb("Returning response with wire size %zu\n", *rsize); + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_ns_answer_ixfr_udp(knot_nameserver_t *nameserver, + const knot_zone_t *zone, knot_packet_t *resp, + uint8_t *response_wire, size_t *rsize) +{ + dbg_ns("ns_answer_ixfr_udp()\n"); + + const knot_zone_contents_t *contents = knot_zone_contents(zone); + + // if no zone found, return REFUSED + if (zone == NULL) { + dbg_ns("No zone found.\n"); + knot_response_set_rcode(resp, KNOT_RCODE_REFUSED); + return KNOT_EOK; + } else if (contents == NULL) { + dbg_ns("Zone expired or not bootstrapped. Reply SERVFAIL.\n"); + knot_response_set_rcode(resp, KNOT_RCODE_SERVFAIL); + return KNOT_EOK; + } + + const knot_node_t *apex = knot_zone_contents_apex(contents); + assert(apex != NULL); + knot_rrset_t *soa = knot_node_get_rrset(apex, KNOT_RRTYPE_SOA); + + // just put the SOA to the Answer section of the response and send back + int ret = knot_response_add_rrset_answer(resp, soa, 1, 0, 0, 0); + if (ret != KNOT_EOK) { + knot_ns_error_response_full(nameserver, resp, + KNOT_RCODE_SERVFAIL, + response_wire, rsize); + } + + dbg_ns("Created response packet.\n"); + knot_packet_dump(resp); + + // Transform the packet into wire format + if (ns_response_to_wire(resp, response_wire, rsize) != 0) { + // send back SERVFAIL (as this is our problem) + knot_ns_error_response_full(nameserver, resp, + KNOT_RCODE_SERVFAIL, + response_wire, rsize); + } + dbg_ns("Returning response with wire size %zu\n", *rsize); return KNOT_EOK; @@ -3134,18 +3567,21 @@ int knot_ns_init_xfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) { dbg_ns("knot_ns_init_xfr()\n"); + int ret = 0; + if (nameserver == NULL || xfr == NULL) { - return KNOT_EBADARG; + dbg_ns("Wrong parameters given to function ns_init_xfr()\n"); + /* Sending error was totally wrong. If nameserver or xfr were + * NULL, the ns_error_response() function would crash. + */ + return ret; } - // no need to parse rest of the packet - /*! \todo Parse rest of packet because of EDNS. */ - int ret = knot_packet_parse_rest(xfr->query); + ret = knot_packet_parse_rest(xfr->query); if (ret != KNOT_EOK) { dbg_ns("Failed to parse rest of the query: %s\n", knot_strerror(ret)); - knot_ns_error_response(nameserver, xfr->query->header.id, - &xfr->query->header.flags1, + knot_ns_error_response_from_query(nameserver, xfr->query, (ret == KNOT_EMALF) ? KNOT_RCODE_FORMERR : KNOT_RCODE_SERVFAIL, xfr->wire, &xfr->wire_size); @@ -3154,8 +3590,10 @@ int knot_ns_init_xfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) return ret; } - dbg_packet("Parsed XFR query:\n"); +dbg_ns_exec_verb( + dbg_ns_verb("Parsed XFR query:\n"); knot_packet_dump(xfr->query); +); // initialize response packet structure knot_packet_t *response = knot_packet_new( @@ -3163,41 +3601,25 @@ int knot_ns_init_xfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) if (response == NULL) { 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, - &xfr->query->header.flags1, - KNOT_RCODE_SERVFAIL, xfr->wire, - &xfr->wire_size); + knot_ns_error_response_from_query(nameserver, xfr->query, + KNOT_RCODE_SERVFAIL, + xfr->wire, &xfr->wire_size); ret = xfr->send(xfr->session, &xfr->addr, xfr->wire, xfr->wire_size); - knot_packet_free(&response); return ret; } - //int ret = knot_packet_set_max_size(response, xfr->wire_size); response->wireformat = xfr->wire; response->max_size = xfr->wire_size; -// if (ret != KNOT_EOK) { -// 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); -// int res = xfr->send(xfr->session, &xfr->addr, xfr->wire, -// xfr->wire_size); -// knot_packet_free(&response); -// return res; -// } - ret = knot_response_init_from_query(response, xfr->query); if (ret != KNOT_EOK) { 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, - &xfr->query->header.flags1, - KNOT_RCODE_SERVFAIL, xfr->wire, - &xfr->wire_size); + knot_ns_error_response_from_query(nameserver, xfr->query, + 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); @@ -3213,9 +3635,9 @@ int knot_ns_init_xfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) assert(knot_packet_qtype(xfr->response) == KNOT_RRTYPE_AXFR || knot_packet_qtype(xfr->response) == KNOT_RRTYPE_IXFR); -dbg_ns_exec( +dbg_ns_exec_verb( char *name_str = knot_dname_to_str(qname); - dbg_ns("Trying to find zone with name %s\n", name_str); + dbg_ns_verb("Trying to find zone with name %s\n", name_str); free(name_str); ); // find zone in which to search for the name @@ -3258,20 +3680,20 @@ int ns_ixfr_load_serials(const knot_ns_xfr_t *xfr, uint32_t *serial_from, { if (xfr == NULL || xfr->zone == NULL || serial_from == NULL || serial_to == NULL) { - dbg_ns_detail("Wrong parameters: xfr=%p," - " xfr->zone = %p\n", xfr, xfr->zone); + dbg_ns("Wrong parameters: xfr=%p," + " xfr->zone = %p\n", xfr, xfr->zone); return KNOT_EBADARG; } const knot_zone_t *zone = xfr->zone; const knot_zone_contents_t *contents = knot_zone_contents(zone); if (!contents) { - dbg_ns_detail("Missing contents\n"); + dbg_ns("Missing contents\n"); return KNOT_EBADARG; } if (knot_zone_contents_apex(contents) == NULL) { - dbg_ns_detail("No apex.\n"); + dbg_ns("No apex.\n"); return KNOT_EBADARG; } @@ -3279,17 +3701,17 @@ int ns_ixfr_load_serials(const knot_ns_xfr_t *xfr, uint32_t *serial_from, knot_node_rrset(knot_zone_contents_apex(contents), KNOT_RRTYPE_SOA); if (zone_soa == NULL) { - dbg_ns_verb("No SOA.\n"); + dbg_ns("No SOA.\n"); return KNOT_EBADARG; } if (knot_packet_nscount(xfr->query) < 1) { - dbg_ns_verb("No Authority record.\n"); + dbg_ns("No Authority record.\n"); return KNOT_EMALF; } if (knot_packet_authority_rrset(xfr->query, 0) == NULL) { - dbg_ns_verb("Authority record missing.\n"); + dbg_ns("Authority record missing.\n"); return KNOT_ERROR; } @@ -3309,13 +3731,13 @@ int knot_ns_xfr_send_error(const knot_nameserver_t *nameserver, /*! \todo Handle TSIG errors differently. */ knot_response_set_rcode(xfr->response, rcode); - /*! \todo Probably rename the function. */ int ret = 0; - if ((ret = ns_xfr_send_and_clear(xfr, 1)) != KNOT_EOK) { + if ((ret = ns_xfr_send_and_clear(xfr, 1)) != KNOT_EOK + || xfr->response == NULL) { size_t size = 0; - knot_ns_error_response(nameserver, xfr->query->header.id, - &xfr->query->header.flags1, - KNOT_RCODE_SERVFAIL, xfr->wire, &size); + knot_ns_error_response_from_query(nameserver, xfr->query, + KNOT_RCODE_SERVFAIL, + xfr->wire, &size); ret = xfr->send(xfr->session, &xfr->addr, xfr->wire, size); } @@ -3337,11 +3759,7 @@ int knot_ns_answer_axfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) knot_zone_contents_t *contents = knot_zone_get_contents(xfr->zone); if (!contents) { 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, - &xfr->query->header.flags1, - KNOT_RCODE_SERVFAIL, xfr->wire, - &xfr->wire_size); + knot_ns_xfr_send_error(nameserver, xfr, KNOT_RCODE_SERVFAIL); ret = xfr->send(xfr->session, &xfr->addr, xfr->wire, xfr->wire_size); rcu_read_unlock(); @@ -3349,16 +3767,16 @@ int knot_ns_answer_axfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) return ret; } - /*! - * \todo [TSIG] The TSIG data should already be stored in 'xfr'. - * Now just count the expected size of the TSIG RR and save it - * to the response structure. + /* + * The TSIG data should already be stored in 'xfr'. + * Now just count the expected size of the TSIG RR and save it + * to the response structure. */ /*! \todo [TSIG] Get the TSIG size from some API function. */ if (xfr->tsig_size > 0) { - dbg_ns_detail("Setting TSIG size in packet: %zu\n", - xfr->tsig_size); + dbg_ns_verb("Setting TSIG size in packet: %zu\n", + xfr->tsig_size); knot_packet_set_tsig_size(xfr->response, xfr->tsig_size); } @@ -3372,11 +3790,7 @@ int knot_ns_answer_axfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) dbg_ns("AXFR failed, sending SERVFAIL.\n"); // now only one type of error (SERVFAIL), later maybe more /*! \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, - &xfr->query->header.flags1, - KNOT_RCODE_SERVFAIL, xfr->wire, - &xfr->wire_size); + knot_ns_xfr_send_error(nameserver, xfr, KNOT_RCODE_SERVFAIL); ret = xfr->send(xfr->session, &xfr->addr, xfr->wire, xfr->wire_size); } else if (ret > 0) { @@ -3398,14 +3812,12 @@ int knot_ns_answer_ixfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) || xfr->response == NULL) { return KNOT_EBADARG; } - - //uint8_t *wire = NULL; - //size_t size = xfr->wire_size; // parse rest of the packet (we need the Authority record) int ret = knot_packet_parse_rest(xfr->query); if (ret != KNOT_EOK) { - dbg_ns("Failed to parse rest of the packet. Reply FORMERR.\n"); + dbg_ns("Failed to parse rest of the packet: %s. " + "Reply FORMERR.\n", knot_strerror(ret)); knot_ns_xfr_send_error(nameserver, xfr, KNOT_RCODE_FORMERR); knot_packet_free(&xfr->response); return ret; @@ -3419,11 +3831,11 @@ int knot_ns_answer_ixfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) return ret; } - /*! - * \todo [TSIG] The TSIG data should already be stored in 'xfr'. - * Now just count the expected size of the TSIG RR and save it - * to the response structure. This should be optional, only if - * the request contained TSIG, i.e. if there is the data in 'xfr'. + /* + * The TSIG data should already be stored in 'xfr'. + * Now just count the expected size of the TSIG RR and save it + * to the response structure. This should be optional, only if + * the request contained TSIG, i.e. if there is the data in 'xfr'. */ /*! \todo [TSIG] Get the TSIG size from some API function. */ @@ -3433,16 +3845,6 @@ int knot_ns_answer_ixfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) ret = ns_ixfr(xfr); -// /*! \todo Somehow distinguish when it makes sense to send the SERVFAIL -// * and when it does not. E.g. if there was problem in sending -// * packet, it will probably fail when sending the SERVFAIL also. -// */ -// if (ret < 0) { -// dbg_ns("IXFR failed, sending SERVFAIL.\n"); -// // now only one type of error (SERVFAIL), later maybe more -// knot_ns_xfr_send_error(nameserver, xfr, KNOT_RCODE_SERVFAIL); -// } - knot_packet_free(&xfr->response); return ret; @@ -3452,18 +3854,16 @@ int knot_ns_answer_ixfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) int knot_ns_process_axfrin(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) { - /*! - * \todo [TSIG] Here we assume that 'xfr' contains TSIG information - * and the digest of the query sent to the master or the previous - * digest. + /* + * Here we assume that 'xfr' contains TSIG information + * and the digest of the query sent to the master or the previous + * digest. */ dbg_ns("ns_process_axfrin: incoming packet, wire size: %zu\n", - xfr->wire_size); + xfr->wire_size); - int ret = xfrin_process_axfr_packet(/*xfr->wire, xfr->wire_size,*/ - /*(xfrin_constructed_zone_t **)(&xfr->data)*/ - xfr); + int ret = xfrin_process_axfr_packet(xfr); if (ret > 0) { // transfer finished dbg_ns("ns_process_axfrin: AXFR finished, zone created.\n"); @@ -3477,19 +3877,19 @@ int knot_ns_process_axfrin(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) assert(zone != NULL); /* Create and fill hash table */ - dbg_ns("ns_process_axfrin: filling hash table.\n"); + dbg_ns_verb("ns_process_axfrin: filling hash table.\n"); int rc = knot_zone_contents_create_and_fill_hash_table(zone); if (rc != KNOT_EOK) { return KNOT_ERROR; // TODO: change error code } - dbg_ns("ns_process_axfrin: adjusting zone.\n"); + dbg_ns_verb("ns_process_axfrin: adjusting zone.\n"); rc = knot_zone_contents_adjust(zone); if (rc != KNOT_EOK) { return rc; } - dbg_ns("ns_process_axfrin: checking loops.\n"); + dbg_ns_verb("ns_process_axfrin: checking loops.\n"); rc = knot_zone_contents_check_loops(zone); if (rc != KNOT_EOK) { return rc; @@ -3508,15 +3908,13 @@ int knot_ns_process_axfrin(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) //knot_zone_contents_dump(zone, 0); // check zone integrity -dbg_xfrin_exec( +dbg_ns_exec_verb( int errs = knot_zone_contents_integrity_check(zone); - dbg_xfrin("Zone integrity check: %d errors.\n", errs); + dbg_ns_verb("Zone integrity check: %d errors.\n", errs); ); } - /*! - * \todo In case of error, shouldn't the zone be destroyed here? - */ + /*! \todo In case of error, shouldn't the zone be destroyed here? */ return ret; } @@ -3538,14 +3936,14 @@ int knot_ns_switch_zone(knot_nameserver_t *nameserver, return KNOT_ENOZONE; } - // find the zone in the zone db - knot_zone_t *z = knot_zonedb_find_zone(nameserver->zone_db, - knot_node_owner(knot_zone_contents_apex(zone))); + /* Zone must not be looked-up from server, as it may be a different zone if + * a reload occurs when transfer is pending. */ + knot_zone_t *z = xfr->zone; if (z == NULL) { char *name = knot_dname_to_str(knot_node_owner( knot_zone_contents_apex(zone))); dbg_ns("Failed to replace zone %s, old zone " - "not found\n", name); + "not found\n", name); free(name); return KNOT_ENOZONE; @@ -3555,16 +3953,18 @@ int knot_ns_switch_zone(knot_nameserver_t *nameserver, int ret = xfrin_switch_zone(z, zone, xfr->type); -dbg_ns_exec( - dbg_ns("Zone db contents: (zone count: %zu)\n", - nameserver->zone_db->zone_count); +dbg_ns_exec_verb( + dbg_ns_verb("Zone db contents: (zone count: %zu)\n", + nameserver->zone_db->zone_count); + /* Warning: may not show updated zone if updated zone that is already + * discarded from zone db (reload with pending transfer). */ const knot_zone_t **zones = knot_zonedb_zones(nameserver->zone_db); for (int i = 0; i < knot_zonedb_zone_count (nameserver->zone_db); i++) { - dbg_ns("%d. zone: %p", i, zones[i]); + dbg_ns_verb("%d. zone: %p\n", i, zones[i]); char *name = knot_dname_to_str(zones[i]->name); - dbg_ns(" zone name: %s\n", name); + dbg_ns_verb(" zone name: %s\n", name); free(name); } free(zones); @@ -3574,18 +3974,16 @@ dbg_ns_exec( } /*----------------------------------------------------------------------------*/ -/*! \todo In this function, xfr->zone is properly set. If this is so, we do not - * have to search for the zone after the transfer has finished. - */ + int knot_ns_process_ixfrin(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) { dbg_ns("ns_process_ixfrin: incoming packet\n"); - /*! - * \todo [TSIG] Here we assume that 'xfr' contains TSIG information - * and the digest of the query sent to the master or the previous - * digest. + /* + * [TSIG] Here we assume that 'xfr' contains TSIG information + * and the digest of the query sent to the master or the previous + * digest. */ int ret = xfrin_process_ixfr_packet(xfr); @@ -3608,19 +4006,18 @@ int knot_ns_process_ixfrin(knot_nameserver_t *nameserver, } // find zone associated with the changesets - knot_zone_t *zone = knot_zonedb_find_zone( - nameserver->zone_db, - knot_rrset_owner(chgsets->first_soa)); + /* Must not search for the zone in zonedb as it may fetch a + * different zone than the one the transfer started on. */ + knot_zone_t *zone = xfr->zone; if (zone == NULL) { dbg_ns("No zone found for incoming IXFR!\n"); knot_free_changesets( (knot_changesets_t **)(&xfr->data)); - return KNOT_ENOZONE; /*! \todo Other error code? */ + return KNOT_ENOZONE; } switch (ret) { case XFRIN_RES_COMPLETE: - xfr->zone = zone; break; case XFRIN_RES_SOA_ONLY: { // compare the SERIAL from the changeset with the zone's @@ -3666,9 +4063,7 @@ int knot_ns_process_ixfrin(knot_nameserver_t *nameserver, } } - /*! - * \todo In case of error, shouldn't the zone be destroyed here? - */ + /*! \todo In case of error, shouldn't the zone be destroyed here? */ return ret; } @@ -3684,26 +4079,24 @@ int knot_ns_process_update(knot_nameserver_t *nameserver, knot_packet_t *query, knot_packet_t *response; assert(*rsize >= MAX_UDP_PAYLOAD); - int ret = knot_ns_prepare_response(nameserver, query, &response, - MAX_UDP_PAYLOAD); + int ret = knot_ns_prepare_response(query, &response, 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); + knot_ns_error_response_from_query(nameserver, query, + KNOT_RCODE_SERVFAIL, + response_wire, rsize); return KNOT_EOK; } assert(response != NULL); - dbg_ns("Query - parsed: %zu, total wire size: %zu\n", - query->parsed, query->size); + dbg_ns_verb("Query - parsed: %zu, total wire size: %zu\n", + query->parsed, query->size); if (knot_packet_parsed(query) < knot_packet_size(query)) { ret = knot_packet_parse_rest(query); if (ret != KNOT_EOK) { dbg_ns("Failed to parse rest of the query: " - "%s.\n", knot_strerror(ret)); + "%s.\n", knot_strerror(ret)); knot_ns_error_response_full(nameserver, response, (ret == KNOT_EMALF) ? KNOT_RCODE_FORMERR @@ -3714,17 +4107,16 @@ int knot_ns_process_update(knot_nameserver_t *nameserver, knot_packet_t *query, } } - dbg_ns("Query - parsed: %zu, total wire size: %zu\n", - knot_packet_parsed(query), knot_packet_size(query)); + dbg_ns_verb("Query - parsed: %zu, total wire size: %zu\n", + knot_packet_parsed(query), knot_packet_size(query)); /*! \todo API for EDNS values. */ - dbg_ns("Opt RR: version: %d, payload: %d\n", - query->opt_rr.version, query->opt_rr.payload); + dbg_ns_verb("Opt RR: version: %d, payload: %d\n", + query->opt_rr.version, query->opt_rr.payload); // 2) Find zone for the query // we do not check if there is only one entry in the Question section // because the packet structure does not allow it - /*! \todo Check number of Question entries while parsing. */ if (knot_packet_qtype(query) != KNOT_RRTYPE_SOA) { dbg_ns("Question is not of type SOA.\n"); knot_ns_error_response_full(nameserver, response, @@ -3754,7 +4146,7 @@ int knot_ns_process_update(knot_nameserver_t *nameserver, knot_packet_t *query, return KNOT_EBADZONE; } else if (ret != KNOT_EOK) { dbg_ns("Failed to check zone for update: " - "%s.\n", knot_strerror(ret)); + "%s.\n", knot_strerror(ret)); knot_ns_error_response_full(nameserver, response, rcode, response_wire, rsize); knot_packet_free(&response); @@ -3766,7 +4158,7 @@ int knot_ns_process_update(knot_nameserver_t *nameserver, knot_packet_t *query, ret = knot_ddns_process_prereqs(query, &prereqs, &rcode); if (ret != KNOT_EOK) { dbg_ns("Failed to check zone for update: " - "%s.\n", knot_strerror(ret)); + "%s.\n", knot_strerror(ret)); knot_ns_error_response_full(nameserver, response, rcode, response_wire, rsize); knot_packet_free(&response); @@ -3783,7 +4175,7 @@ int knot_ns_process_update(knot_nameserver_t *nameserver, knot_packet_t *query, &rcode); if (ret != KNOT_EOK) { dbg_ns("Failed to check zone for update: " - "%s.\n", knot_strerror(ret)); + "%s.\n", knot_strerror(ret)); knot_ns_error_response_full(nameserver, response, rcode, response_wire, rsize); knot_ddns_prereqs_free(&prereqs); @@ -3795,7 +4187,7 @@ int knot_ns_process_update(knot_nameserver_t *nameserver, knot_packet_t *query, ret = knot_ddns_process_update(query, changeset, &rcode); if (ret != KNOT_EOK) { dbg_ns("Failed to check zone for update: " - "%s.\n", knot_strerror(ret)); + "%s.\n", knot_strerror(ret)); knot_ns_error_response_full(nameserver, response, rcode, response_wire, rsize); knot_ddns_prereqs_free(&prereqs); diff --git a/src/libknot/nameserver/name-server.h b/src/libknot/nameserver/name-server.h index da19f49..3fe1210 100644..100755 --- a/src/libknot/nameserver/name-server.h +++ b/src/libknot/nameserver/name-server.h @@ -115,8 +115,6 @@ typedef struct knot_ns_xfr { */ uint8_t *tsig_data; size_t tsig_data_size; /*!< Size of the message(s) in bytes */ -// const knot_rrset_t *tsig; /*!< Response TSIG. -// \todo [TSIG] Replace with separate data. */ size_t tsig_size; /*!< Size of the TSIG RR wireformat in bytes.*/ knot_key_t *tsig_key; /*!< Associated TSIG key for signing. */ @@ -127,13 +125,6 @@ typedef struct knot_ns_xfr { uint16_t tsig_rcode; uint64_t tsig_prev_time_signed; - /*! \brief Previous digest or request digest. - * - * Should be allocated before the transfer (known size). - */ -// uint8_t *prev_digest; -// size_t prev_digest_size; /*!< Size of previous digest in bytes. */ - /*! * \brief Number of the packet currently assembled. * @@ -154,7 +145,7 @@ static const size_t KNOT_NS_TSIG_DATA_MAX_SIZE = 100 * 64 * 1024; enum knot_ns_xfr_flag_t { XFR_FLAG_TCP = 1 << 0, /*!< XFR request is on TCP. */ XFR_FLAG_UDP = 1 << 1, /*!< XFR request is on UDP. */ - XFR_FLAG_AXFR_FINISHED = 1 << 2 + XFR_FLAG_AXFR_FINISHED = 1 << 2 /*!< Transfer is finished. */ }; typedef enum knot_ns_transport { @@ -218,26 +209,13 @@ void knot_ns_set_nsid(knot_nameserver_t *nameserver, const char *nsid, int knot_ns_parse_packet(const uint8_t *query_wire, size_t qsize, knot_packet_t *packet, knot_packet_type_t *type); -/*! - * \brief Prepares wire format of an error response using generic error template - * stored in the nameserver structure. - * - * The error response will not contain the Question section from the query, just - * a header with ID copied from the query and the given RCODE. - * - * \param nameserver Nameserver structure containing the error template. - * \param query_id ID of the query. - * \param rcode RCODE to set in the response. - * \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 *flags1_query, - uint8_t rcode, uint8_t *response_wire, - size_t *rsize); +int knot_ns_error_response_from_query_wire(const knot_nameserver_t *nameserver, + const uint8_t *query, size_t size, + 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, + const knot_packet_t *query, uint8_t rcode, uint8_t *response_wire, size_t *rsize); @@ -264,7 +242,11 @@ int knot_ns_prep_normal_response(knot_nameserver_t *nameserver, */ int knot_ns_answer_normal(knot_nameserver_t *nameserver, const knot_zone_t *zone, knot_packet_t *resp, - uint8_t *response_wire, size_t *rsize); + uint8_t *response_wire, size_t *rsize, int check_any); + +int knot_ns_answer_ixfr_udp(knot_nameserver_t *nameserver, + const knot_zone_t *zone, knot_packet_t *resp, + uint8_t *response_wire, size_t *rsize); int knot_ns_init_xfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr); @@ -322,11 +304,11 @@ int knot_ns_answer_ixfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr); * \param nameserver Name server structure to provide the data for answering. * \param xfr Persistent transfer-specific data. * - * \todo Document me. */ int knot_ns_process_axfrin(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr); +/*! \todo Document me. */ int knot_ns_switch_zone(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr); diff --git a/src/libknot/nsec3.c b/src/libknot/nsec3.c index 1414e7e..9cab4be 100644..100755 --- a/src/libknot/nsec3.c +++ b/src/libknot/nsec3.c @@ -74,7 +74,7 @@ int knot_nsec3_params_from_wire(knot_nsec3_params_t *params, dbg_nsec3("Flags: %hu\n", params->flags); dbg_nsec3("Iterations: %hu\n", params->iterations); dbg_nsec3("Salt length: %hu\n", params->salt_length); - dbg_nsec3("Salt: "); + dbg_nsec3("Salt: \n"); if (params->salt != NULL) { dbg_nsec3_hex((char *)params->salt, params->salt_length); @@ -171,8 +171,8 @@ int knot_nsec3_sha1(const knot_nsec3_params_t *params, EVP_MD_CTX_cleanup(&mdctx); - dbg_nsec3("NSEC3 hashing: calls: %lu, avg time per call: %f." - "\n", calls, (double)(total_time) / calls); + dbg_nsec3_verb("NSEC3 hashing: calls: %lu, avg time per call: %f." + "\n", calls, (double)(total_time) / calls); free(data_low); return 0; @@ -194,17 +194,17 @@ int knot_nsec3_sha1(const knot_nsec3_params_t *params, uint8_t salt_length = params->salt_length; uint16_t iterations = params->iterations; - dbg_nsec3("Hashing: \n"); - dbg_nsec3(" Data: %.*s \n", size, data); - dbg_nsec3_hex((const char *)data, size); - dbg_nsec3(" (size %d)\n Iterations: %u\n", (int)size, iterations); - dbg_nsec3(" Salt length: %u\n", salt_length); - dbg_nsec3(" Salt: "); + dbg_nsec3_verb("Hashing: \n"); + dbg_nsec3_verb(" Data: %.*s \n", size, data); + dbg_nsec3_hex_verb((const char *)data, size); + dbg_nsec3_verb(" (size %d)\n Iterations: %u\n", (int)size, iterations); + dbg_nsec3_verb(" Salt length: %u\n", salt_length); + dbg_nsec3_verb(" Salt: \n"); if (salt_length > 0) { - dbg_nsec3_hex((char *)salt, salt_length); - dbg_nsec3("\n"); + dbg_nsec3_hex_verb((char *)salt, salt_length); + dbg_nsec3_verb("\n"); } else { - dbg_nsec3("none\n"); + dbg_nsec3_verb("none\n"); } SHA_CTX ctx; @@ -251,9 +251,9 @@ int knot_nsec3_sha1(const knot_nsec3_params_t *params, *digest_size = SHA_DIGEST_LENGTH; - dbg_nsec3("Hash: %.*s\n", *digest_size, *digest); - dbg_nsec3_hex((const char *)*digest, *digest_size); - dbg_nsec3("\n"); + dbg_nsec3_verb("Hash: %.*s\n", *digest_size, *digest); + dbg_nsec3_hex_verb((const char *)*digest, *digest_size); + dbg_nsec3_verb("\n"); free(data_low); return KNOT_EOK; diff --git a/src/libknot/nsec3.h b/src/libknot/nsec3.h index 0ce6899..0ce6899 100644..100755 --- a/src/libknot/nsec3.h +++ b/src/libknot/nsec3.h diff --git a/src/libknot/packet/packet.c b/src/libknot/packet/packet.c index 82b65c6..6c7fd02 100644..100755 --- a/src/libknot/packet/packet.c +++ b/src/libknot/packet/packet.c @@ -22,6 +22,7 @@ #include "common.h" #include "util/descriptor.h" #include "util/wire.h" +#include "tsig.h" /*----------------------------------------------------------------------------*/ @@ -51,7 +52,7 @@ typedef enum { */ static void knot_packet_init_pointers_response(knot_packet_t *pkt) { - dbg_packet("Packet pointer: %p\n", pkt); + dbg_packet_detail("Packet pointer: %p\n", pkt); char *pos = (char *)pkt + PREALLOC_PACKET; @@ -59,7 +60,7 @@ static void knot_packet_init_pointers_response(knot_packet_t *pkt) pkt->question.qname = (knot_dname_t *)pos; pos += PREALLOC_QNAME_DNAME; - dbg_packet("QNAME: %p\n", pkt->question.qname); + dbg_packet_detail("QNAME: %p\n", pkt->question.qname); pkt->question.qname->name = (uint8_t *)pos; pos += PREALLOC_QNAME_NAME; @@ -67,7 +68,7 @@ static void knot_packet_init_pointers_response(knot_packet_t *pkt) pos += PREALLOC_QNAME_LABELS; pkt->owner_tmp = (uint8_t *)pos; - dbg_packet("Tmp owner: %p\n", pkt->owner_tmp); + dbg_packet_detail("Tmp owner: %p\n", pkt->owner_tmp); pos += PREALLOC_RR_OWNER; // then answer, authority and additional sections @@ -92,9 +93,9 @@ static void knot_packet_init_pointers_response(knot_packet_t *pkt) pos += DEFAULT_ARCOUNT * sizeof(const knot_rrset_t *); } - dbg_packet("Answer section: %p\n", pkt->answer); - dbg_packet("Authority section: %p\n", pkt->authority); - dbg_packet("Additional section: %p\n", pkt->additional); + dbg_packet_detail("Answer section: %p\n", pkt->answer); + dbg_packet_detail("Authority section: %p\n", pkt->authority); + dbg_packet_detail("Additional section: %p\n", pkt->additional); pkt->max_an_rrsets = DEFAULT_ANCOUNT; pkt->max_ns_rrsets = DEFAULT_NSCOUNT; @@ -106,8 +107,8 @@ static void knot_packet_init_pointers_response(knot_packet_t *pkt) pkt->compression.offsets = (size_t *)pos; pos += DEFAULT_DOMAINS_IN_RESPONSE * sizeof(size_t); - dbg_packet("Compression dnames: %p\n", pkt->compression.dnames); - dbg_packet("Compression offsets: %p\n", pkt->compression.offsets); + dbg_packet_detail("Compression dnames: %p\n", pkt->compression.dnames); + dbg_packet_detail("Compression offsets: %p\n", pkt->compression.offsets); pkt->compression.max = DEFAULT_DOMAINS_IN_RESPONSE; pkt->compression.default_count = DEFAULT_DOMAINS_IN_RESPONSE; @@ -118,8 +119,8 @@ static void knot_packet_init_pointers_response(knot_packet_t *pkt) pkt->wildcard_nodes.snames = (const knot_dname_t **)pos; pos += DEFAULT_WILDCARD_NODES * sizeof(knot_dname_t *); - dbg_packet("Wildcard nodes: %p\n", pkt->wildcard_nodes.nodes); - dbg_packet("Wildcard SNAMEs: %p\n", pkt->wildcard_nodes.snames); + dbg_packet_detail("Wildcard nodes: %p\n", pkt->wildcard_nodes.nodes); + dbg_packet_detail("Wildcard SNAMEs: %p\n", pkt->wildcard_nodes.snames); pkt->wildcard_nodes.default_count = DEFAULT_WILDCARD_NODES; pkt->wildcard_nodes.max = DEFAULT_WILDCARD_NODES; @@ -127,7 +128,7 @@ static void knot_packet_init_pointers_response(knot_packet_t *pkt) pkt->tmp_rrsets = (const knot_rrset_t **)pos; pos += DEFAULT_TMP_RRSETS * sizeof(const knot_rrset_t *); - dbg_packet("Tmp rrsets: %p\n", pkt->tmp_rrsets); + dbg_packet_detail("Tmp rrsets: %p\n", pkt->tmp_rrsets); pkt->tmp_rrsets_max = DEFAULT_TMP_RRSETS; @@ -141,7 +142,7 @@ static void knot_packet_init_pointers_response(knot_packet_t *pkt) */ static void knot_packet_init_pointers_query(knot_packet_t *pkt) { - dbg_packet("Packet pointer: %p\n", pkt); + dbg_packet_detail("Packet pointer: %p\n", pkt); char *pos = (char *)pkt + PREALLOC_PACKET; @@ -149,17 +150,15 @@ static void knot_packet_init_pointers_query(knot_packet_t *pkt) pkt->question.qname = (knot_dname_t *)pos; pos += PREALLOC_QNAME_DNAME; - dbg_packet("QNAME: %p (%zu after start of packet)\n", - pkt->question.qname, - (void *)pkt->question.qname - (void *)pkt); + dbg_packet_detail("QNAME: %p (%zu after start of packet)\n", + pkt->question.qname, + (void *)pkt->question.qname - (void *)pkt); pkt->question.qname->name = (uint8_t *)pos; pos += PREALLOC_QNAME_NAME; pkt->question.qname->labels = (uint8_t *)pos; pos += PREALLOC_QNAME_LABELS; -// pkt->owner_tmp = (uint8_t *)((char *)pkt->question.qname->labels -// + PREALLOC_QNAME_LABELS); // then answer, authority and additional sections if (DEFAULT_ANCOUNT_QUERY == 0) { @@ -183,9 +182,9 @@ static void knot_packet_init_pointers_query(knot_packet_t *pkt) pos += DEFAULT_ARCOUNT_QUERY * sizeof(const knot_rrset_t *); } - dbg_packet("Answer section: %p\n", pkt->answer); - dbg_packet("Authority section: %p\n", pkt->authority); - dbg_packet("Additional section: %p\n", pkt->additional); + dbg_packet_detail("Answer section: %p\n", pkt->answer); + dbg_packet_detail("Authority section: %p\n", pkt->authority); + dbg_packet_detail("Additional section: %p\n", pkt->additional); pkt->max_an_rrsets = DEFAULT_ANCOUNT_QUERY; pkt->max_ns_rrsets = DEFAULT_NSCOUNT_QUERY; @@ -194,15 +193,11 @@ static void knot_packet_init_pointers_query(knot_packet_t *pkt) pkt->tmp_rrsets = (const knot_rrset_t **)pos; pos += DEFAULT_TMP_RRSETS_QUERY * sizeof(const knot_rrset_t *); - dbg_packet("Tmp rrsets: %p\n", pkt->tmp_rrsets); + dbg_packet_detail("Tmp rrsets: %p\n", pkt->tmp_rrsets); pkt->tmp_rrsets_max = DEFAULT_TMP_RRSETS_QUERY; -// dbg_packet("End of data: %p (%zu after start of packet)\n", -// pkt->tmp_rrsets + DEFAULT_TMP_RRSETS_QUERY, -// (void *)(pkt->tmp_rrsets + DEFAULT_TMP_RRSETS_QUERY) -// - (void *)pkt); - dbg_packet("Allocated total: %u\n", PREALLOC_QUERY); + dbg_packet_detail("Allocated total: %u\n", PREALLOC_QUERY); assert(pos == (char *)pkt + PREALLOC_QUERY); } @@ -230,7 +225,7 @@ static int knot_packet_parse_header(const uint8_t *wire, size_t *pos, assert(header != NULL); if (size - *pos < KNOT_WIRE_HEADER_SIZE) { - dbg_response("Not enough data to parse header.\n"); + dbg_packet("Not enough data to parse header.\n"); return KNOT_EFEWDATA; } @@ -238,10 +233,8 @@ static int knot_packet_parse_header(const uint8_t *wire, size_t *pos, // copy some of the flags: OPCODE and RD // do this by copying flags1 and setting QR to 1, AA to 0 and TC to 0 header->flags1 = knot_wire_get_flags1(wire); -// knot_wire_flags_set_qr(&header->flags1); -// knot_wire_flags_clear_aa(&header->flags1); -// knot_wire_flags_clear_tc(&header->flags1); // do not copy flags2 (all set by server) + header->qdcount = knot_wire_get_qdcount(wire); header->ancount = knot_wire_get_ancount(wire); header->nscount = knot_wire_get_nscount(wire); @@ -276,12 +269,11 @@ static int knot_packet_parse_question(const uint8_t *wire, size_t *pos, assert(question != NULL); if (size - *pos < KNOT_WIRE_QUESTION_MIN_SIZE) { - dbg_response("Not enough data to parse question.\n"); + dbg_packet("Not enough data to parse question.\n"); return KNOT_EFEWDATA; // malformed } - dbg_response("Parsing Question starting on position %zu.\n", - *pos); + dbg_packet("Parsing Question starting on position %zu.\n", *pos); // domain name must end with 0, so just search for 0 int i = *pos; @@ -290,13 +282,13 @@ static int knot_packet_parse_question(const uint8_t *wire, size_t *pos, } if (size - i - 1 < 4) { - dbg_response("Not enough data to parse question.\n"); + dbg_packet("Not enough data to parse question.\n"); return KNOT_EFEWDATA; // no 0 found or not enough data left } - dbg_response("Parsing dname starting on position %zu and " + dbg_packet_verb("Parsing dname starting on position %zu and " "%zu bytes long.\n", *pos, i - *pos + 1); - dbg_response("Alloc: %d\n", alloc); + dbg_packet_verb("Alloc: %d\n", alloc); if (alloc) { question->qname = knot_dname_new_from_wire( wire + *pos, i - *pos + 1, NULL); @@ -314,10 +306,7 @@ static int knot_packet_parse_question(const uint8_t *wire, size_t *pos, *pos = i + 1; question->qtype = knot_wire_read_u16(wire + i + 1); - //*pos += 2; question->qclass = knot_wire_read_u16(wire + i + 3); - //*pos += 2; - *pos += 4; return KNOT_EOK; @@ -340,7 +329,7 @@ static int knot_packet_realloc_rrsets(const knot_rrset_t ***rrsets, short *max_count, short default_max_count, short step) { - dbg_packet("Max count: %d, default max count: %d\n", + dbg_packet_verb("Max count: %d, default max count: %d\n", *max_count, default_max_count); int free_old = (*max_count) != default_max_count; const knot_rrset_t **old = *rrsets; @@ -368,11 +357,6 @@ static knot_rdata_t *knot_packet_parse_rdata(const uint8_t *wire, size_t *pos, size_t total_size, size_t rdlength, const knot_rrtype_descriptor_t *desc) { -// if (desc->type == 0) { -// dbg_packet("Unknown RR type.\n"); -// return NULL; -// } - knot_rdata_t *rdata = knot_rdata_new(); if (rdata == NULL) { return NULL; @@ -383,7 +367,7 @@ static knot_rdata_t *knot_packet_parse_rdata(const uint8_t *wire, if (rc != KNOT_EOK) { dbg_packet("rdata_from_wire() returned: %s\n", - knot_strerror(rc)); + knot_strerror(rc)); knot_rdata_free(&rdata); return NULL; } @@ -396,38 +380,32 @@ static knot_rdata_t *knot_packet_parse_rdata(const uint8_t *wire, static knot_rrset_t *knot_packet_parse_rr(const uint8_t *wire, size_t *pos, size_t size) { -// knot_rrset_t *rrset = -// (knot_rrset_t *)malloc(sizeof(knot_rrset_t)); -// CHECK_ALLOC_LOG(rrset, NULL); - dbg_packet("Parsing RR from position: %zu, total size: %zu\n", - *pos, size); + *pos, size); knot_dname_t *owner = knot_dname_parse_from_wire(wire, pos, size, NULL); - dbg_packet("Created owner: %p, actual position: %zu\n", owner, + dbg_packet_detail("Created owner: %p, actual position: %zu\n", owner, *pos); if (owner == NULL) { return NULL; } -dbg_packet_exec( +dbg_packet_exec_verb( char *name = knot_dname_to_str(owner); - dbg_packet("Parsed name: %s\n", name); + dbg_packet_verb("Parsed name: %s\n", name); free(name); ); - //*remaining -= knot_dname_size(rrset->owner); - /*! @todo Get rid of the numerical constant. */ if (size - *pos < 10) { dbg_packet("Malformed RR: Not enough data to parse RR" - " header.\n"); + " header.\n"); knot_dname_release(owner); return NULL; } - dbg_packet("Reading type from position %zu\n", *pos); + dbg_packet_detail("Reading type from position %zu\n", *pos); uint16_t type = knot_wire_read_u16(wire + *pos); uint16_t rclass = knot_wire_read_u16(wire + *pos + 2); @@ -445,7 +423,7 @@ dbg_packet_exec( uint16_t rdlength = knot_wire_read_u16(wire + *pos + 8); - dbg_packet("Read RR header: type %u, class %u, ttl %u, " + dbg_packet_detail("Read RR header: type %u, class %u, ttl %u, " "rdlength %u\n", rrset->type, rrset->rclass, rrset->ttl, rdlength); @@ -453,10 +431,8 @@ dbg_packet_exec( if (size - *pos < rdlength) { dbg_packet("Malformed RR: Not enough data to parse RR" - " RDATA (size: %zu, position: %zu).\n", - size, *pos); + " RDATA (size: %zu, position: %zu).\n", size, *pos); knot_rrset_deep_free(&rrset, 1, 1, 0); -// free(rrset); return NULL; } @@ -473,16 +449,13 @@ dbg_packet_exec( if (rdata == NULL) { dbg_packet("Malformed RR: Could not parse RDATA.\n"); knot_rrset_deep_free(&rrset, 1, 1, 0); -// free(rrset); return NULL; } if (knot_rrset_add_rdata(rrset, rdata) != KNOT_EOK) { - dbg_packet("Malformed RR: Could not add RDATA to RRSet" - ".\n"); + dbg_packet("Malformed RR: Could not add RDATA to RRSet.\n"); knot_rdata_free(&rdata); knot_rrset_deep_free(&rrset, 1, 1, 0); -// free(rrset); return NULL; } @@ -492,23 +465,22 @@ dbg_packet_exec( /*----------------------------------------------------------------------------*/ static int knot_packet_add_rrset(knot_rrset_t *rrset, - const knot_rrset_t ***rrsets, - short *rrset_count, - short *max_rrsets, - short default_rrsets, - const knot_packet_t *packet, - knot_packet_duplicate_handling_t dupl) + const knot_rrset_t ***rrsets, + short *rrset_count, + short *max_rrsets, + short default_rrsets, + const knot_packet_t *packet, + knot_packet_duplicate_handling_t dupl) { - assert(rrset != NULL); assert(rrsets != NULL); assert(rrset_count != NULL); assert(max_rrsets != NULL); -dbg_packet_exec( +dbg_packet_exec_verb( char *name = knot_dname_to_str(rrset->owner); - dbg_packet("packet_add_rrset(), owner: %s, type: %s\n", - name, knot_rrtype_to_string(rrset->type)); + dbg_packet_verb("packet_add_rrset(), owner: %s, type: %s\n", + name, knot_rrtype_to_string(rrset->type)); free(name); ); @@ -529,19 +501,20 @@ dbg_packet_exec( // try to find the RRSet in this array of RRSets for (int i = 0; i < *rrset_count; ++i) { -dbg_packet_exec( +dbg_packet_exec_detail( char *name = knot_dname_to_str((*rrsets)[i]->owner); - dbg_packet("Comparing to RRSet: owner: %s, " - "type: %s\n", name, - knot_rrtype_to_string( - (*rrsets)[i]->type)); + dbg_packet_detail("Comparing to RRSet: owner: %s, " + "type: %s\n", name, + knot_rrtype_to_string( + (*rrsets)[i]->type)); free(name); ); if (knot_rrset_compare((*rrsets)[i], rrset, KNOT_RRSET_COMPARE_HEADER)) { - //const knot_rrset_t *r = (*rrsets) /*! \todo Test this!!! */ + // no duplicate checking here, the packet should + // look exactly as it came from wire int rc = knot_rrset_merge( (void **)((*rrsets) + i), (void **)&rrset); if (rc != KNOT_EOK) { @@ -561,11 +534,12 @@ dbg_packet_exec( /*----------------------------------------------------------------------------*/ static int knot_packet_parse_rrs(const uint8_t *wire, size_t *pos, - size_t size, uint16_t rr_count, - const knot_rrset_t ***rrsets, - short *rrset_count, short *max_rrsets, - short default_rrsets, - knot_packet_t *packet) + size_t size, uint16_t rr_count, + uint16_t *parsed_rrs, + const knot_rrset_t ***rrsets, + short *rrset_count, short *max_rrsets, + short default_rrsets, + knot_packet_t *packet) { assert(pos != NULL); assert(wire != NULL); @@ -574,12 +548,7 @@ static int knot_packet_parse_rrs(const uint8_t *wire, size_t *pos, assert(max_rrsets != NULL); assert(packet != NULL); - dbg_packet("Parsing RRSets starting on position: %zu\n", - *pos); - -// if (*rrsets == NULL) { -// knot_packet_realloc_rrsets(rrsets, max_rrsets, 0, 1); -// } + dbg_packet("Parsing RRSets starting on position: %zu\n", *pos); /* * The RRs from one RRSet may be scattered in the current section. @@ -589,7 +558,8 @@ static int knot_packet_parse_rrs(const uint8_t *wire, size_t *pos, int err = KNOT_EOK; knot_rrset_t *rrset = NULL; - for (int i = 0; i < rr_count; ++i) { + /* Start parsing from the first RR not parsed. */ + for (int i = *parsed_rrs; i < rr_count; ++i) { rrset = knot_packet_parse_rr(wire, pos, size); if (rrset == NULL) { dbg_packet("Failed to parse RR!\n"); @@ -597,13 +567,15 @@ static int knot_packet_parse_rrs(const uint8_t *wire, size_t *pos, break; } + ++(*parsed_rrs); + err = knot_packet_add_rrset(rrset, rrsets, rrset_count, - max_rrsets, default_rrsets, packet, - KNOT_PACKET_DUPL_MERGE); + max_rrsets, default_rrsets, packet, + KNOT_PACKET_DUPL_MERGE); if (err < 0) { break; } else if (err > 0) { // merged - dbg_packet("RRSet merged, freeing.\n"); + dbg_packet_detail("RRSet merged, freeing.\n"); knot_rrset_deep_free(&rrset, 1, 0, 0); // TODO: ok?? continue; } @@ -616,6 +588,23 @@ static int knot_packet_parse_rrs(const uint8_t *wire, size_t *pos, knot_rrset_deep_free(&rrset, 1, 1, 1); break; } + + if (knot_rrset_type(rrset) == KNOT_RRTYPE_TSIG) { + // if there is some TSIG already, treat as malformed + if (knot_packet_tsig(packet) != NULL) { + err = KNOT_EMALF; + break; + } + + // First check the format of the TSIG RR + if (!tsig_rdata_is_ok(rrset)) { + err = KNOT_EMALF; + break; + } + + // store the TSIG into the packet + knot_packet_set_tsig(packet, rrset); + } } return (err < 0) ? err : KNOT_EOK; @@ -630,9 +619,9 @@ static int knot_packet_parse_rrs(const uint8_t *wire, size_t *pos, */ static void knot_packet_free_allocated_space(knot_packet_t *pkt) { - dbg_packet("Freeing additional space in packet.\n"); + dbg_packet_verb("Freeing additional space in packet.\n"); if (pkt->prealloc_type == KNOT_PACKET_PREALLOC_NONE) { - dbg_packet("Freeing QNAME.\n"); + dbg_packet_detail("Freeing QNAME.\n"); knot_dname_release(pkt->question.qname); } @@ -674,37 +663,55 @@ static int knot_packet_parse_rr_sections(knot_packet_t *packet, int err; - dbg_packet("Parsing Answer RRs...\n"); + assert(packet->tsig_rr == NULL); + + dbg_packet_verb("Parsing Answer RRs...\n"); if ((err = knot_packet_parse_rrs(packet->wireformat, pos, - packet->size, packet->header.ancount, &packet->answer, - &packet->an_rrsets, &packet->max_an_rrsets, + packet->size, packet->header.ancount, &packet->parsed_an, + &packet->answer, &packet->an_rrsets, &packet->max_an_rrsets, DEFAULT_RRSET_COUNT(ANCOUNT, packet), packet)) != KNOT_EOK) { return err; } - dbg_packet("Parsing Authority RRs...\n"); + if (packet->tsig_rr != NULL) { + dbg_packet("TSIG in Answer section.\n"); + return KNOT_EMALF; + } + + dbg_packet_verb("Parsing Authority RRs...\n"); if ((err = knot_packet_parse_rrs(packet->wireformat, pos, - packet->size, packet->header.nscount, &packet->authority, - &packet->ns_rrsets, &packet->max_ns_rrsets, + packet->size, packet->header.nscount, &packet->parsed_ns, + &packet->authority, &packet->ns_rrsets, &packet->max_ns_rrsets, DEFAULT_RRSET_COUNT(NSCOUNT, packet), packet)) != KNOT_EOK) { return err; } - dbg_packet("Parsing Additional RRs...\n"); + if (packet->tsig_rr != NULL) { + dbg_packet("TSIG in Authority section.\n"); + return KNOT_EMALF; + } + + dbg_packet_verb("Parsing Additional RRs...\n"); if ((err = knot_packet_parse_rrs(packet->wireformat, pos, - packet->size, packet->header.arcount, &packet->additional, - &packet->ar_rrsets, &packet->max_ar_rrsets, + packet->size, packet->header.arcount, &packet->parsed_ar, + &packet->additional, &packet->ar_rrsets, &packet->max_ar_rrsets, DEFAULT_RRSET_COUNT(ARCOUNT, packet), packet)) != KNOT_EOK) { return err; } - dbg_packet("Trying to find OPT RR in the packet.\n"); + // If TSIG is not the last record + if (packet->tsig_rr != NULL + && packet->ar_rrsets[packet->additional - 1] != packet->tsig_rr) { + dbg_packet("TSIG in Additonal section but not last.\n"); + return KNOT_EMALF; + } + + dbg_packet_verb("Trying to find OPT RR in the packet.\n"); for (int i = 0; i < packet->ar_rrsets; ++i) { assert(packet->additional[i] != NULL); - if (knot_rrset_type(packet->additional[i]) - == KNOT_RRTYPE_OPT) { - dbg_packet("Found OPT RR, filling.\n"); + if (knot_rrset_type(packet->additional[i]) == KNOT_RRTYPE_OPT) { + dbg_packet_detail("Found OPT RR, filling.\n"); err = knot_edns_new_from_rr(&packet->opt_rr, packet->additional[i]); if (err != KNOT_EOK) { @@ -717,9 +724,10 @@ static int knot_packet_parse_rr_sections(knot_packet_t *packet, packet->parsed = *pos; if (*pos < packet->size) { - // some trailing garbage; ignore, but log - dbg_response("Packet: %zu bytes of trailing garbage " - "in packet.\n", packet->size - (*pos)); + // If there is some trailing garbage, treat the packet as + // malformed + dbg_packet_verb("Packet: %zu bytes of trailing garbage " + "in packet.\n", packet->size - (*pos)); return KNOT_EMALF; } @@ -784,12 +792,14 @@ int knot_packet_parse_from_wire(knot_packet_t *packet, packet->size = size; packet->free_wireformat = 0; - //uint8_t *pos = wireformat; + if (size < 2) { + return KNOT_EMALF; + } + size_t pos = 0; - //size_t remaining = size; - dbg_packet("Parsing wire format of packet (size %zu).\nHeader\n", - size); + dbg_packet_verb("Parsing wire format of packet (size %zu).\nHeader\n", + size); if ((err = knot_packet_parse_header(wireformat, &pos, size, &packet->header)) != KNOT_EOK) { return err; @@ -797,15 +807,14 @@ int knot_packet_parse_from_wire(knot_packet_t *packet, packet->parsed = pos; - dbg_packet("Question (prealloc type: %d)...\n", packet->prealloc_type); + dbg_packet_verb("Question (prealloc type: %d)...\n", + packet->prealloc_type); if (packet->header.qdcount > 1) { dbg_packet("QDCOUNT larger than 1, FORMERR.\n"); return KNOT_EMALF; } - knot_packet_dump(packet); - if (packet->header.qdcount == 1) { if ((err = knot_packet_parse_question(wireformat, &pos, size, &packet->question, packet->prealloc_type @@ -816,18 +825,20 @@ int knot_packet_parse_from_wire(knot_packet_t *packet, packet->parsed = pos; } +dbg_packet_exec_detail( knot_packet_dump(packet); +); if (question_only) { return KNOT_EOK; } /*! \todo Replace by call to parse_rest()? */ - err = knot_packet_parse_rr_sections(packet, &pos); + err = knot_packet_parse_rest(packet); -#ifdef KNOT_PACKET_DEBUG +dbg_packet_exec_detail( knot_packet_dump(packet); -#endif /* KNOT_RESPONSE_DEBUG */ +); return err; } @@ -840,16 +851,21 @@ int knot_packet_parse_rest(knot_packet_t *packet) return KNOT_EBADARG; } -// if (packet->parsed >= packet->size) { -// return KNOT_EOK; -// } - - if (packet->parsed == packet->size) { + if (packet->header.ancount == packet->parsed_an + && packet->header.nscount == packet->parsed_ns + && packet->header.arcount == packet->parsed_ar + && packet->parsed == packet->size) { return KNOT_EOK; } + + // If there is less data then required, the next function will find out. + // If there is more data than required, it also returns EMALF. size_t pos = packet->parsed; + /*! \todo If we already parsed some part of the packet, it is not ok + * to begin parsing from the Answer section. + */ return knot_packet_parse_rr_sections(packet, &pos); } @@ -866,16 +882,16 @@ int knot_packet_parse_next_rr_answer(knot_packet_t *packet, if (packet->parsed >= packet->size) { assert(packet->an_rrsets <= packet->header.ancount); - if (packet->an_rrsets != packet->header.ancount) { + if (packet->parsed_an != packet->header.ancount) { dbg_packet("Parsed less RRs than expected.\n"); return KNOT_EMALF; } else { - dbg_packet("Whole packet parsed\n"); + dbg_packet_detail("Whole packet parsed\n"); return KNOT_EOK; } } - if (packet->an_rrsets == packet->header.ancount) { + if (packet->parsed_an == packet->header.ancount) { assert(packet->parsed < packet->size); //dbg_packet("Trailing garbage, ignoring...\n"); // there may be other data in the packet @@ -885,19 +901,20 @@ int knot_packet_parse_next_rr_answer(knot_packet_t *packet, size_t pos = packet->parsed; - dbg_packet("Parsing next Answer RR (pos: %zu)...\n", pos); + dbg_packet_verb("Parsing next Answer RR (pos: %zu)...\n", pos); *rr = knot_packet_parse_rr(packet->wireformat, &pos, packet->size); if (*rr == NULL) { - dbg_packet("Failed to parse RR!\n"); + dbg_packet_verb("Failed to parse RR!\n"); return KNOT_EMALF; } - dbg_packet("Parsed. Pos: %zu.\n", pos); + dbg_packet_detail("Parsed. Pos: %zu.\n", pos); packet->parsed = pos; // increment the number of answer RRSets, though there are no saved // in the packet; it is OK, because packet->answer is NULL ++packet->an_rrsets; + ++packet->parsed_an; return KNOT_EOK; } @@ -916,37 +933,37 @@ int knot_packet_parse_next_rr_additional(knot_packet_t *packet, if (packet->parsed >= packet->size) { assert(packet->ar_rrsets <= packet->header.arcount); - if (packet->ar_rrsets != packet->header.arcount) { + if (packet->parsed_ar != packet->header.arcount) { dbg_packet("Parsed less RRs than expected.\n"); return KNOT_EMALF; } else { - dbg_packet("Whole packet parsed\n"); + dbg_packet_detail("Whole packet parsed\n"); return KNOT_EOK; } } - if (packet->ar_rrsets == packet->header.arcount) { + if (packet->parsed_ar == packet->header.arcount) { assert(packet->parsed < packet->size); - dbg_packet("Trailing garbage, ignoring...\n"); - /*! \todo Do not ignore. */ - return KNOT_EOK; + dbg_packet_verb("Trailing garbage, treating as malformed...\n"); + return KNOT_EMALF; } size_t pos = packet->parsed; - dbg_packet("Parsing next Additional RR (pos: %zu)...\n", pos); + dbg_packet_verb("Parsing next Additional RR (pos: %zu)...\n", pos); *rr = knot_packet_parse_rr(packet->wireformat, &pos, packet->size); if (*rr == NULL) { - dbg_packet("Failed to parse RR!\n"); + dbg_packet_verb("Failed to parse RR!\n"); return KNOT_EMALF; } - dbg_packet("Parsed. Pos: %zu.\n", pos); + dbg_packet_detail("Parsed. Pos: %zu.\n", pos); packet->parsed = pos; // increment the number of answer RRSets, though there are no saved // in the packet; it is OK, because packet->answer is NULL ++packet->ar_rrsets; + ++packet->parsed_ar; return KNOT_EOK; } @@ -1186,7 +1203,7 @@ const knot_rrset_t *knot_packet_tsig(const knot_packet_t *packet) void knot_packet_set_tsig(knot_packet_t *packet, const knot_rrset_t *tsig_rr) { - packet->tsig_rr = (knot_rrset_t *)tsig_rr; + packet->tsig_rr = (knot_rrset_t *)tsig_rr; } /*----------------------------------------------------------------------------*/ @@ -1268,19 +1285,19 @@ int knot_packet_contains(const knot_packet_t *packet, return KNOT_EBADARG; } - for (int i = 0; i < packet->header.ancount; ++i) { + for (int i = 0; i < packet->an_rrsets; ++i) { if (knot_rrset_compare(packet->answer[i], rrset, cmp)) { return 1; } } - for (int i = 0; i < packet->header.nscount; ++i) { + for (int i = 0; i < packet->ns_rrsets; ++i) { if (knot_rrset_compare(packet->authority[i], rrset, cmp)) { return 1; } } - for (int i = 0; i < packet->header.arcount; ++i) { + for (int i = 0; i < packet->ar_rrsets; ++i) { if (knot_rrset_compare(packet->additional[i], rrset, cmp)) { return 1; } @@ -1307,8 +1324,8 @@ int knot_packet_add_tmp_rrset(knot_packet_t *packet, } packet->tmp_rrsets[packet->tmp_rrsets_count++] = tmp_rrset; - dbg_packet("Current tmp RRSets count: %d, max count: %d\n", - packet->tmp_rrsets_count, packet->tmp_rrsets_max); + dbg_packet_detail("Current tmp RRSets count: %d, max count: %d\n", + packet->tmp_rrsets_count, packet->tmp_rrsets_max); return KNOT_EOK; } @@ -1329,7 +1346,7 @@ void knot_packet_free_tmp_rrsets(knot_packet_t *pkt) dbg_packet_exec( char *name = knot_dname_to_str( (((knot_rrset_t **)(pkt->tmp_rrsets))[i])->owner); - dbg_packet("Freeing tmp RRSet on ptr: %p (ptr to ptr:" + dbg_packet_verb("Freeing tmp RRSet on ptr: %p (ptr to ptr:" " %p, type: %s, owner: %s)\n", (((knot_rrset_t **)(pkt->tmp_rrsets))[i]), &(((knot_rrset_t **)(pkt->tmp_rrsets))[i]), @@ -1394,14 +1411,6 @@ int knot_packet_question_to_wire(knot_packet_t *packet) pos += 2; knot_wire_write_u16(pos, packet->question.qclass); -// int err = 0; - // TODO: put the qname into the compression table -// // TODO: get rid of the numeric constants -// if ((err = knot_response_store_dname_pos(&packet->compression, -// packet->question.qname,0, 12, 12)) != KNOT_EOK) { -// return err; -// } - packet->size += knot_dname_size(packet->question.qname) + 4; return KNOT_EOK; @@ -1486,8 +1495,6 @@ void knot_packet_free(knot_packet_t **packet) knot_packet_free_allocated_space(*packet); // free the space for wireformat -// assert((*packet)->wireformat != NULL); -// free((*packet)->wireformat); if ((*packet)->wireformat != NULL && (*packet)->free_wireformat) { free((*packet)->wireformat); } diff --git a/src/libknot/packet/packet.h b/src/libknot/packet/packet.h index 9e37c12..d76209a 100644..100755 --- a/src/libknot/packet/packet.h +++ b/src/libknot/packet/packet.h @@ -138,6 +138,9 @@ struct knot_packet { short free_wireformat; size_t parsed; + uint16_t parsed_an; + uint16_t parsed_ns; + uint16_t parsed_ar; size_t size; /*!< Current wire size of the packet. */ size_t max_size; /*!< Maximum allowed size of the packet. */ diff --git a/src/libknot/packet/query.c b/src/libknot/packet/query.c index b76059b..bc3a4db 100644..100755 --- a/src/libknot/packet/query.c +++ b/src/libknot/packet/query.c @@ -209,7 +209,7 @@ int knot_query_add_rrset_authority(knot_packet_t *query, // reserve space for OPT RR /*! \todo Why here??? */ endp -= query->opt_rr.size; - /*! \note [TSIG] reserve space for TSIG RR */ + /* Reserve space for TSIG RR */ endp -= query->tsig_size; uint8_t *pos = startp; diff --git a/src/libknot/packet/query.h b/src/libknot/packet/query.h index a979641..cda72b9 100644..100755 --- a/src/libknot/packet/query.h +++ b/src/libknot/packet/query.h @@ -61,12 +61,6 @@ int knot_query_nsid_requested(const knot_packet_t *query); int knot_query_edns_supported(const knot_packet_t *query); -//int knot_query_set_qname(knot_packet_t *query, const knot_dname_t *qname); - -//int knot_query_set_qtype(knot_packet_t *query, uint16_t qtype); - -//int knot_query_set_qclass(knot_packet_t *query, uint16_t qclass); - int knot_query_init(knot_packet_t *query); int knot_query_set_question(knot_packet_t *query, diff --git a/src/libknot/packet/response.c b/src/libknot/packet/response.c index 9f6277c..bb4d0f2 100644..100755 --- a/src/libknot/packet/response.c +++ b/src/libknot/packet/response.c @@ -164,15 +164,14 @@ static int knot_response_store_dname_pos(knot_compressed_dnames_t *table, { dbg_response_exec( char *name = knot_dname_to_str(dname); - dbg_response("Putting dname %s into compression table." - " Labels not matched: %d, position: %zu," - ", pointer: %p, unmatched off: %zu\n", name, - not_matched, pos, dname, unmatched_offset); + dbg_response_detail("Putting dname %s into compression table." + " Labels not matched: %d, position: %zu," + ", pointer: %p, unmatched off: %zu\n", name, + not_matched, pos, dname, unmatched_offset); free(name); ); if (pos > KNOT_RESPONSE_MAX_PTR) { - dbg_response("Pointer larger than it can be, not" - " saving\n"); + dbg_response("Pointer larger than it can be, not saving\n"); return KNOT_EDNAMEPTR; } @@ -181,11 +180,6 @@ dbg_response_exec( return KNOT_ENOMEM; } - // store the position of the name -// table->dnames[table->count] = dname; -// table->offsets[table->count] = pos; -// ++table->count; - /* * Store positions of ancestors if more than 1 label was not matched. * @@ -210,11 +204,11 @@ dbg_response_exec( parent_pos = unmatched_offset; } -dbg_response_exec( +dbg_response_exec_detail( char *name = knot_dname_to_str(to_save); - dbg_response("Putting dname %s into compression table." - " Position: %zu, pointer: %p\n", - name, parent_pos, to_save); + dbg_response_detail("Putting dname %s into compression table." + " Position: %zu, pointer: %p\n", + name, parent_pos, to_save); free(name); ); @@ -224,7 +218,6 @@ dbg_response_exec( return KNOT_ENOMEM; } -// dbg_response("Saving..\n"); knot_response_compr_save(table, to_save, parent_pos); /*! \todo Remove '!compr_cs'. */ @@ -234,16 +227,23 @@ dbg_response_exec( // If case-sensitive search is in place, we should not save the // node's parent's positions. - to_save = !compr_cs && (knot_dname_node(to_save) != NULL - && knot_node_parent(knot_dname_node(to_save)) - != NULL) ? knot_node_owner(knot_node_parent( + // Added check to rule out wildcard-covered dnames + // (in such case the offset is not right) + + /*! \todo The whole compression requires a serious refactoring. + * Or better - a rewrite! + */ + to_save = (!compr_cs && knot_dname_node(to_save) != NULL + && knot_node_owner(knot_dname_node(to_save)) + != to_save + && knot_node_parent(knot_dname_node(to_save)) + != NULL) + ? knot_node_owner(knot_node_parent( knot_dname_node(to_save))) - : NULL; + : NULL; dbg_response("i: %d\n", i); parent_pos += knot_dname_label_size(dname, i) + 1; -// parent_pos += (i > 0) -// ? knot_dname_label_size(dname, i - 1) + 1 : 0; ++i; } @@ -267,22 +267,12 @@ static size_t knot_response_find_dname_pos( const knot_dname_t *dname, int compr_cs) { for (int i = 0; i < table->count; ++i) { -// dbg_response("Comparing dnames %p and %p\n", -// dname, table->dnames[i]); -//dbg_response_exec( -// char *name = knot_dname_to_str(dname); -// dbg_response("(%s and ", name); -// name = knot_dname_to_str(table->dnames[i]); -// dbg_response("%s)\n", name); -// free(name); -//); - //if (table->dnames[i] == dname) { int ret = (compr_cs) ? knot_dname_compare_cs(table->dnames[i], dname) : knot_dname_compare(table->dnames[i], dname); if (ret == 0) { - dbg_response("Found offset: %zu\n", - table->offsets[i]); + dbg_response_detail("Found offset: %zu\n", + table->offsets[i]); return table->offsets[i]; } } @@ -319,7 +309,7 @@ static int knot_response_put_dname_ptr(const knot_dname_t *dname, memcpy(wire, knot_dname_name(dname), size); knot_wire_put_pointer(wire + size, offset); - dbg_response("Size of the dname with ptr: %d\n", size + 2); + dbg_response_detail("Size of the dname with ptr: %d\n", size + 2); return size + 2; } @@ -343,15 +333,9 @@ static int knot_response_compress_dname(const knot_dname_t *dname, knot_compr_t *compr, uint8_t *dname_wire, size_t max, int compr_cs) { int size = 0; - /*! - * \todo Compress!! - * - * if pos == 0, do not store the position! - */ // try to find the name or one of its ancestors in the compr. table #ifdef COMPRESSION_PEDANTIC - //knot_dname_t *to_find = knot_dname_copy(dname); knot_dname_t *to_find = (knot_dname_t *)dname; int copied = 0; #else @@ -361,11 +345,11 @@ static int knot_response_compress_dname(const knot_dname_t *dname, int not_matched = 0; while (to_find != NULL && knot_dname_label_count(to_find) != 0) { -dbg_response_exec( +dbg_response_exec_detail( char *name = knot_dname_to_str(to_find); - dbg_response("Searching for name %s in the compression" - " table, not matched labels: %d\n", name, - not_matched); + dbg_response_detail("Searching for name %s in the compression" + " table, not matched labels: %d\n", name, + not_matched); free(name); ); offset = knot_response_find_dname_pos(compr->table, to_find, @@ -396,17 +380,17 @@ dbg_response_exec( || knot_node_owner(knot_dname_node(to_find)) != to_find || knot_node_parent(knot_dname_node(to_find)) == NULL) { - dbg_response("compr_cs: %d\n", compr_cs); - dbg_response("knot_dname_node(to_find, 1) == %p" + dbg_response_detail("compr_cs: %d\n", compr_cs); + dbg_response_detail("knot_dname_node(to_find, 1) == %p" "\n", knot_dname_node(to_find)); if (knot_dname_node(to_find) != NULL) { - dbg_response("knot_node_owner(knot_dname_node(" - "to_find, 1)) = %p, to_find = %p\n", - knot_node_owner(knot_dname_node(to_find)), - to_find); - dbg_response("knot_node_parent(knot_dname_node(" - "to_find, 1), 1) = %p\n", + dbg_response_detail("knot_node_owner(knot_dname_node(" + "to_find, 1)) = %p, to_find = %p\n", + knot_node_owner(knot_dname_node(to_find)), + to_find); + dbg_response_detail("knot_node_parent(knot_dname_node(" + "to_find, 1), 1) = %p\n", knot_node_parent(knot_dname_node(to_find))); } break; @@ -417,7 +401,7 @@ dbg_response_exec( knot_node_parent(knot_dname_node(to_find)))); to_find = knot_node_owner( knot_node_parent(knot_dname_node(to_find))); - dbg_response("New to_find: %p\n", to_find); + dbg_response_detail("New to_find: %p\n", to_find); } #endif } @@ -428,10 +412,10 @@ dbg_response_exec( } #endif - dbg_response("Max size available for domain name: %zu\n", max); + dbg_response_detail("Max size available for domain name: %zu\n", max); if (offset > 0) { // found such dname somewhere in the packet - dbg_response("Found name in the compression table.\n"); + dbg_response_detail("Found name in the compression table.\n"); assert(offset >= KNOT_WIRE_HEADER_SIZE); size = knot_response_put_dname_ptr(dname, not_matched, offset, dname_wire, max); @@ -439,7 +423,7 @@ dbg_response_exec( return KNOT_ESPACE; } } else { - dbg_response("Not found, putting whole name.\n"); + dbg_response_detail("Not found, putting whole name.\n"); // now just copy the dname without compressing if (dname->size > max) { return KNOT_ESPACE; @@ -458,8 +442,7 @@ dbg_response_exec( if (knot_response_store_dname_pos(compr->table, dname, not_matched, compr->wire_pos, offset, compr_cs) != 0) { - dbg_response("Compression info could not be stored." - "\n"); + dbg_response_detail("Compression info could not be stored.\n"); } return size; @@ -488,7 +471,7 @@ static int knot_response_rr_to_wire(const knot_rrset_t *rrset, { int size = 0; - dbg_response("Max size: %zu, owner pos: %zu, owner size: %d\n", + dbg_response_detail("Max size: %zu, owner pos: %zu, owner size: %d\n", max_size, compr->owner.pos, compr->owner.size); if (size + ((compr->owner.pos == 0 @@ -498,7 +481,7 @@ static int knot_response_rr_to_wire(const knot_rrset_t *rrset, return KNOT_ESPACE; } - dbg_response("Owner position: %zu\n", compr->owner.pos); + dbg_response_detail("Owner position: %zu\n", compr->owner.pos); // put owner if needed (already compressed) if (compr->owner.pos == 0 || compr->owner.pos > KNOT_RESPONSE_MAX_PTR) { @@ -507,28 +490,28 @@ static int knot_response_rr_to_wire(const knot_rrset_t *rrset, *rrset_wire += compr->owner.size; size += compr->owner.size; } else { - dbg_response("Putting pointer: %zu\n", - compr->owner.pos); + dbg_response_detail("Putting pointer: %zu\n", + compr->owner.pos); knot_wire_put_pointer(*rrset_wire, compr->owner.pos); *rrset_wire += 2; size += 2; } - dbg_response("Max size: %zu, size: %d\n", max_size, size); + dbg_response_detail("Max size: %zu, size: %d\n", max_size, size); - dbg_response("Wire format:\n"); + dbg_response_detail("Wire format:\n"); // put rest of RR 'header' knot_wire_write_u16(*rrset_wire, rrset->type); - dbg_response(" Type: %u\n", rrset->type); + dbg_response_detail(" Type: %u\n", rrset->type); *rrset_wire += 2; knot_wire_write_u16(*rrset_wire, rrset->rclass); - dbg_response(" Class: %u\n", rrset->rclass); + dbg_response_detail(" Class: %u\n", rrset->rclass); *rrset_wire += 2; knot_wire_write_u32(*rrset_wire, rrset->ttl); - dbg_response(" TTL: %u\n", rrset->ttl); + dbg_response_detail(" TTL: %u\n", rrset->ttl); *rrset_wire += 4; // save space for RDLENGTH @@ -538,7 +521,7 @@ static int knot_response_rr_to_wire(const knot_rrset_t *rrset, size += 10; compr->wire_pos += size; - dbg_response("Max size: %zu, size: %d\n", max_size, size); + dbg_response_detail("Max size: %zu, size: %d\n", max_size, size); knot_rrtype_descriptor_t *desc = knot_rrtype_descriptor_by_type(rrset->type); @@ -561,8 +544,7 @@ static int knot_response_rr_to_wire(const knot_rrset_t *rrset, return KNOT_ESPACE; } - dbg_response("Compressed dname size: %d\n", - ret); + dbg_response_detail("Compressed dname size: %d\n", ret); *rrset_wire += ret; rdlength += ret; compr->wire_pos += ret; @@ -579,8 +561,8 @@ static int knot_response_rr_to_wire(const knot_rrset_t *rrset, // save whole domain name memcpy(*rrset_wire, dname->name, dname->size); - dbg_response("Uncompressed dname size: %d\n", - dname->size); + dbg_response_detail("Uncompressed dname size: %d\n", + dname->size); *rrset_wire += dname->size; rdlength += dname->size; compr->wire_pos += dname->size; @@ -596,8 +578,8 @@ static int knot_response_rr_to_wire(const knot_rrset_t *rrset, // copy just the rdata item data (without size) memcpy(*rrset_wire, raw_data + 1, raw_data[0]); - dbg_response("Raw data size: %d\n", - raw_data[0]); + dbg_response_detail("Raw data size: %d\n", + raw_data[0]); *rrset_wire += raw_data[0]; rdlength += raw_data[0]; compr->wire_pos += raw_data[0]; @@ -606,7 +588,7 @@ static int knot_response_rr_to_wire(const knot_rrset_t *rrset, } } - dbg_response("Max size: %zu, size: %d\n", max_size, size); + dbg_response_detail("Max size: %zu, size: %d\n", max_size, size); assert(size + rdlength <= max_size); size += rdlength; @@ -639,12 +621,12 @@ static int knot_response_rrset_to_wire(const knot_rrset_t *rrset, knot_compressed_dnames_t *compr, int compr_cs) { -dbg_response_exec( +dbg_response_exec_verb( char *name = knot_dname_to_str(rrset->owner); - dbg_response("Converting RRSet with owner %s, type %s\n", - name, knot_rrtype_to_string(rrset->type)); + dbg_response_verb("Converting RRSet with owner %s, type %s\n", + name, knot_rrtype_to_string(rrset->type)); free(name); - dbg_response(" Size before: %zu\n", *size); + dbg_response_verb(" Size before: %zu\n", *size); ); // if no RDATA in RRSet, return @@ -652,10 +634,6 @@ dbg_response_exec( return KNOT_EOK; } - //uint8_t *rrset_wire = (uint8_t *)malloc(PREALLOC_RRSET_WIRE); - //short rrset_size = 0; - - //uint8_t *owner_wire = (uint8_t *)malloc(rrset->owner->size); /* * We may pass the current position to the compression function * because if the owner will be put somewhere, it will be on the @@ -665,7 +643,6 @@ dbg_response_exec( */ knot_compr_t compr_info; - //compr_info.new_entries = 0; compr_info.table = compr; compr_info.wire_pos = wire_pos; compr_info.owner.pos = 0; @@ -674,8 +651,8 @@ dbg_response_exec( knot_response_compress_dname(rrset->owner, &compr_info, owner_tmp, max_size, compr_cs); - dbg_response(" Owner size: %d, position: %zu\n", - compr_info.owner.size, compr_info.owner.pos); + dbg_response_detail(" Owner size: %d, position: %zu\n", + compr_info.owner.size, compr_info.owner.pos); if (compr_info.owner.size < 0) { return KNOT_ESPACE; } @@ -698,20 +675,17 @@ dbg_response_exec( return KNOT_ESPACE; } - dbg_response("RR of size %d added.\n", ret); + dbg_response_verb("RR of size %d added.\n", ret); rrset_size += ret; ++rrs; } while ((rdata = knot_rrset_rdata_next(rrset, rdata)) != NULL); - //memcpy(*pos, rrset_wire, rrset_size); - //*size += rrset_size; - //*pos += rrset_size; // the whole RRSet did fit in assert (rrset_size <= max_size); *size += rrset_size; - dbg_response(" Size after: %zu\n", *size); + dbg_response_verb(" Size after: %zu\n", *size); return rrs; } @@ -750,8 +724,8 @@ static int knot_response_try_add_rrset(const knot_rrset_t **rrsets, dbg_response_exec( char *name = knot_dname_to_str(rrset->owner); - dbg_response("\nAdding RRSet with owner %s and type %s: \n", - name, knot_rrtype_to_string(rrset->type)); + dbg_response_verb("\nAdding RRSet with owner %s and type %s: \n", + name, knot_rrtype_to_string(rrset->type)); free(name); ); @@ -764,11 +738,11 @@ dbg_response_exec( if (rrs >= 0) { rrsets[(*rrset_count)++] = rrset; resp->size += size; - dbg_response("RRset added, size: %zu, RRs: %d, total " - "size of response: %zu\n\n", size, rrs, - resp->size); + dbg_response_verb("RRset added, size: %zu, RRs: %d, total " + "size of response: %zu\n\n", size, rrs, + resp->size); } else if (tc) { - dbg_response("Setting TC bit.\n"); + dbg_response_verb("Setting TC bit.\n"); knot_wire_flags_set_tc(&resp->header.flags1); knot_wire_set_tc(resp->wireformat); } @@ -825,8 +799,8 @@ static int knot_response_realloc_wc_nodes(const knot_node_t ***nodes, short *max_count, short default_max_count, short step) { - dbg_packet("Max count: %d, default max count: %d\n", - *max_count, default_max_count); + dbg_packet_detail("Max count: %d, default max count: %d\n", + *max_count, default_max_count); int free_old = (*max_count) != default_max_count; const knot_node_t **old_nodes = *nodes; @@ -896,13 +870,10 @@ int knot_response_init_from_query(knot_packet_t *response, // copy the header from the query memcpy(&response->header, &query->header, sizeof(knot_header_t)); -// memmove(&response->header, &query->header, sizeof(knot_header_t)); // copy the Question section (but do not copy the QNAME) memcpy(&response->question, &query->question, sizeof(knot_question_t)); -// memmove(&response->question, &query->question, -// sizeof(knot_question_t)); int err = 0; // put the qname into the compression table @@ -917,18 +888,16 @@ int knot_response_init_from_query(knot_packet_t *response, size_t to_copy = 12 + 4 + knot_dname_size(response->question.qname); assert(response->max_size >= to_copy); -// printf("Resp init from query: Copying from: %p to: %p size: %d\n", -// response->wireformat, query->wireformat, -// to_copy); -// printf("Resp init from query: Question name size: %d Query name size: %d\n", -// knot_dname_size(response->question.qname), -// knot_dname_size(query->question.qname)); memcpy(response->wireformat, query->wireformat, to_copy); response->size = to_copy; // set the qr bit to 1 knot_wire_flags_set_qr(&response->header.flags1); knot_wire_set_qr(response->wireformat); + + // clear TC flag + knot_wire_flags_clear_tc(&response->header.flags1); + knot_wire_clear_tc(response->wireformat); // clear AD flag knot_wire_flags_clear_ad(&response->header.flags2); @@ -940,8 +909,11 @@ int knot_response_init_from_query(knot_packet_t *response, // set counts to 0 response->header.ancount = 0; + knot_wire_set_ancount(response->wireformat, 0); response->header.nscount = 0; + knot_wire_set_nscount(response->wireformat, 0); response->header.arcount = 0; + knot_wire_set_arcount(response->wireformat, 0); response->query = query; @@ -1039,16 +1011,14 @@ int knot_response_add_opt(knot_packet_t *resp, if (override_max_size && resp->max_size > 0 && resp->max_size < opt_rr->payload) { -// return KNOT_EPAYLOAD; return KNOT_EOK; } // set max size (less is OK) if (override_max_size) { dbg_response("Overriding max size to: %u\n", - resp->opt_rr.payload); + resp->opt_rr.payload); return knot_packet_set_max_size(resp, resp->opt_rr.payload); - //resp->max_size = resp->opt_rr.payload; } return KNOT_EOK; @@ -1065,7 +1035,7 @@ int knot_response_add_rrset_answer(knot_packet_t *response, return KNOT_EBADARG; } - dbg_response("add_rrset_answer()\n"); + dbg_response_verb("add_rrset_answer()\n"); assert(response->header.arcount == 0); assert(response->header.nscount == 0); @@ -1081,9 +1051,9 @@ int knot_response_add_rrset_answer(knot_packet_t *response, return KNOT_EOK; } - dbg_response("Trying to add RRSet to Answer section.\n"); - dbg_response("RRset: %p\n", rrset); - dbg_response("Owner: %p\n", rrset->owner); + dbg_response_verb("Trying to add RRSet to Answer section.\n"); + dbg_response_detail("RRset: %p\n", rrset); + dbg_response_detail("Owner: %p\n", rrset->owner); int rrs = knot_response_try_add_rrset(response->answer, &response->an_rrsets, response, @@ -1132,7 +1102,7 @@ int knot_response_add_rrset_authority(knot_packet_t *response, return KNOT_EOK; } - dbg_response("Trying to add RRSet to Authority section.\n"); + dbg_response_verb("Trying to add RRSet to Authority section.\n"); int rrs = knot_response_try_add_rrset(response->authority, &response->ns_rrsets, response, @@ -1188,7 +1158,7 @@ int knot_response_add_rrset_additional(knot_packet_t *response, return KNOT_EOK; } - dbg_response("Trying to add RRSet to Additional section.\n"); + dbg_response_verb("Trying to add RRSet to Additional section.\n"); int rrs = knot_response_try_add_rrset(response->additional, &response->ar_rrsets, response, @@ -1283,7 +1253,7 @@ int knot_response_add_wildcard_node(knot_packet_t *response, response->wildcard_nodes.snames[response->wildcard_nodes.count] = sname; ++response->wildcard_nodes.count; - dbg_response("Current wildcard nodes count: %d, max count: %d\n", + dbg_response_verb("Current wildcard nodes count: %d, max count: %d\n", response->wildcard_nodes.count, response->wildcard_nodes.max); diff --git a/src/libknot/packet/response.h b/src/libknot/packet/response.h index d3e66f3..d3e66f3 100644..100755 --- a/src/libknot/packet/response.h +++ b/src/libknot/packet/response.h diff --git a/src/libknot/rdata.c b/src/libknot/rdata.c index 8e9e8c1..1cdd339 100644..100755 --- a/src/libknot/rdata.c +++ b/src/libknot/rdata.c @@ -210,8 +210,8 @@ knot_rdata_t *knot_rdata_new() /*----------------------------------------------------------------------------*/ int knot_rdata_from_wire(knot_rdata_t *rdata, const uint8_t *wire, - size_t *pos, size_t total_size, size_t rdlength, - const knot_rrtype_descriptor_t *desc) + size_t *pos, size_t total_size, size_t rdlength, + const knot_rrtype_descriptor_t *desc) { int i = 0; uint8_t item_type; @@ -249,7 +249,6 @@ int knot_rdata_from_wire(knot_rdata_t *rdata, const uint8_t *wire, return KNOT_ERROR; } items[i].dname = dname; - //*pos += dname->size; parsed += pos2 - *pos; *pos = pos2; dname = 0; @@ -309,7 +308,6 @@ int knot_rdata_from_wire(knot_rdata_t *rdata, const uint8_t *wire, break; case 3: pos2 = *pos; - //fprintf(stderr, "reading dname from pos: %zu\n", pos2); dname = knot_dname_parse_from_wire( wire, &pos2, total_size, NULL); if (dname == NULL) { @@ -331,12 +329,9 @@ int knot_rdata_from_wire(knot_rdata_t *rdata, const uint8_t *wire, memcpy((uint8_t *)(items[i].raw_data + 1), knot_dname_name(dname), knot_dname_size(dname)); - -// items[i].dname = dname; - //*pos += dname->size; + parsed += pos2 - *pos; - - //fprintf(stderr, "read %zu bytes.\n", parsed); + *pos = pos2; knot_dname_free(&dname); @@ -374,9 +369,7 @@ int knot_rdata_from_wire(knot_rdata_t *rdata, const uint8_t *wire, memcpy(items[i].raw_data + 1, wire + *pos, item_size); *pos += item_size; parsed += item_size; - } else if (item_type == KNOT_RDATA_WF_BINARY/* - || item_type == KNOT_RDATA_WF_IPSECGATEWAY*/) { -// fprintf(stderr, "item_size was 0, creating empty rdata item.\n"); + } else if (item_type == KNOT_RDATA_WF_BINARY) { // in this case we are at the end of the RDATA // and should create an empty RDATA item items[i].raw_data = (uint16_t *)malloc(2); @@ -389,8 +382,6 @@ int knot_rdata_from_wire(knot_rdata_t *rdata, const uint8_t *wire, } else if (item_type != KNOT_RDATA_WF_COMPRESSED_DNAME && item_type != KNOT_RDATA_WF_UNCOMPRESSED_DNAME && item_type != KNOT_RDATA_WF_LITERAL_DNAME) { -// fprintf(stderr, "RDATA item not set (i: %d), type: %u" -// " RDATA item type: %d\n", i, desc->type ,item_type); assert(0); } @@ -519,6 +510,25 @@ int knot_rdata_item_set_raw_data(knot_rdata_t *rdata, uint pos, /*----------------------------------------------------------------------------*/ +int knot_rdata_count(const knot_rdata_t *rdata) +{ + if (rdata == NULL) { + return 0; + } + + int count = 1; + const knot_rdata_t *r = rdata; + + while (r->next != NULL && r->next != rdata) { + r = r->next; + ++count; + } + + return count; +} + +/*----------------------------------------------------------------------------*/ + void knot_rdata_free(knot_rdata_t **rdata) { if (rdata == NULL || *rdata == NULL) { @@ -541,134 +551,16 @@ void knot_rdata_deep_free(knot_rdata_t **rdata, uint type, return; } - knot_rdata_free_items((*rdata)->items, (*rdata)->count, type, - free_all_dnames); + if ((*rdata)->items != NULL) { + knot_rdata_free_items((*rdata)->items, (*rdata)->count, type, + free_all_dnames); + } free(*rdata); *rdata = NULL; } /*----------------------------------------------------------------------------*/ -/* CLEANUP */ -//uint knot_rdata_wire_size(const knot_rdata_t *rdata, -// const uint8_t *format) -//{ -// uint size = 0; - -// for (int i = 0; i < rdata->count; ++i) { -// switch (format[i]) { -// case KNOT_RDATA_WF_COMPRESSED_DNAME: -// case KNOT_RDATA_WF_UNCOMPRESSED_DNAME: -// case KNOT_RDATA_WF_LITERAL_DNAME: -// size += knot_dname_size(rdata->items[i].dname); -// break; -// case KNOT_RDATA_WF_BYTE: -// size += 1; -// break; -// case KNOT_RDATA_WF_SHORT: -// size += 2; -// break; -// case KNOT_RDATA_WF_LONG: -// size += 4; -// break; -// case KNOT_RDATA_WF_A: -// size += 4; -// break; -// case KNOT_RDATA_WF_AAAA: -// size += 16; -// break; -// case KNOT_RDATA_WF_BINARY: -// case KNOT_RDATA_WF_APL: // saved as binary -// case KNOT_RDATA_WF_IPSECGATEWAY: // saved as binary -// size += rdata->items[i].raw_data[0]; -// break; -// case KNOT_RDATA_WF_TEXT: -// case KNOT_RDATA_WF_BINARYWITHLENGTH: -// size += rdata->items[i].raw_data[0] + 1; -// break; -// default: -// assert(0); -// } -// } -// return size; -//} - -/*----------------------------------------------------------------------------*/ - -//int knot_rdata_to_wire(const knot_rdata_t *rdata, const uint8_t *format, -// uint8_t *buffer, uint buf_size) -//{ -// uint copied = 0; -// uint8_t tmp[KNOT_MAX_RDATA_WIRE_SIZE]; -// uint8_t *to = tmp; - -// for (int i = 0; i < rdata->count; ++i) { -// assert(copied < KNOT_MAX_RDATA_WIRE_SIZE); - -// const uint8_t *from = (uint8_t *)rdata->items[i].raw_data; -// uint size = 0; - -// switch (format[i]) { -// case KNOT_RDATA_WF_COMPRESSED_DNAME: -// case KNOT_RDATA_WF_UNCOMPRESSED_DNAME: -// case KNOT_RDATA_WF_LITERAL_DNAME: -// size = knot_dname_size(rdata->items[i].dname); -// from = knot_dname_name(rdata->items[i].dname); - -// break; -// case KNOT_RDATA_WF_BYTE: -// size = 1; -// break; -// case KNOT_RDATA_WF_SHORT: -// size = 2; -// break; -// case KNOT_RDATA_WF_LONG: -// size = 4; -// break; -// case KNOT_RDATA_WF_A: -// size = 4; -// break; -// case KNOT_RDATA_WF_AAAA: -// size = 16; -// break; -// case KNOT_RDATA_WF_TEXT: -// case KNOT_RDATA_WF_BINARYWITHLENGTH: -// // size stored in the first two bytes, but in little -// // endian and we need only the lower byte from it -// *to = *from; // lower byte is the first in little endian -// to += 1; -// case KNOT_RDATA_WF_BINARY: -// case KNOT_RDATA_WF_APL: // saved as binary -// case KNOT_RDATA_WF_IPSECGATEWAY: // saved as binary -// // size stored in the first two bytes, those bytes -// // must not be copied -// size = rdata->items[i].raw_data[0]; -// from += 2; // skip the first two bytes -// break; -// default: -// assert(0); -// } - -// assert(size != 0); -// assert(copied + size < KNOT_MAX_RDATA_WIRE_SIZE); - -// memcpy(to, from, size); -// to += size; -// copied += size; -// } - -// if (copied > buf_size) { -// dbg_rdata("Not enough place allocated for function " -// "knot_rdata_to_wire(). Allocated %u, need %u\n", -// buf_size, copied); -// return -1; -// } - -// memcpy(buffer, tmp, copied); -// return 0; -//} - -/*----------------------------------------------------------------------------*/ knot_rdata_t *knot_rdata_deep_copy(const knot_rdata_t *rdata, uint16_t type, int copy_dnames) @@ -728,33 +620,19 @@ int knot_rdata_compare(const knot_rdata_t *r1, const knot_rdata_t *r2, int cmp = 0; for (int i = 0; i < count; ++i) { - /* CLEANUP */ -// const uint8_t *data1, *data2; -// int size1, size2; - if (format[i] == KNOT_RDATA_WF_COMPRESSED_DNAME || format[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME || format[i] == KNOT_RDATA_WF_LITERAL_DNAME) { cmp = knot_dname_compare(r1->items[i].dname, r2->items[i].dname); -// data1 = knot_dname_name(r1->items[i].dname); -// data2 = knot_dname_name(r2->items[i].dname); -// size1 = knot_dname_size(r2->items[i].dname); -// size2 = knot_dname_size(r2->items[i].dname); } else { cmp = knot_rdata_compare_binary( (uint8_t *)(r1->items[i].raw_data + 1), (uint8_t *)(r2->items[i].raw_data + 1), r1->items[i].raw_data[0], r1->items[i].raw_data[0]); -// data1 = (uint8_t *)(r1->items[i].raw_data + 1); -// data2 = (uint8_t *)(r2->items[i].raw_data + 1); -// size1 = r1->items[i].raw_data[0]; -// size2 = r1->items[i].raw_data[0]; } -// cmp = - if (cmp != 0) { return cmp; } @@ -894,3 +772,48 @@ uint16_t knot_rdata_rrsig_type_covered(const knot_rdata_t *rdata) return knot_wire_read_u16((uint8_t *)(rdata->items[0].raw_data + 1)); } + +/*---------------------------------------------------------------------------*/ + +uint8_t knot_rdata_nsec3_algorithm(const knot_rdata_t *rdata) +{ + if (rdata->count < 1) { + return 0; + } + + return *((uint8_t *)(rdata->items[0].raw_data + 1)); +} + +/*---------------------------------------------------------------------------*/ + +uint16_t knot_rdata_nsec3_iterations(const knot_rdata_t *rdata) +{ + if (rdata->count < 3) { + // this is actually valid value...what to return?? + return 0; + } + + return knot_wire_read_u16((uint8_t *)(rdata->items[2].raw_data + 1)); +} + +/*---------------------------------------------------------------------------*/ + +uint8_t knot_rdata_nsec3_salt_length(const knot_rdata_t *rdata) +{ + if (rdata->count < 4) { + return 0; + } + + return *((uint8_t *)(rdata->items[3].raw_data + 1)); +} + +/*---------------------------------------------------------------------------*/ + +const uint8_t *knot_rdata_nsec3_salt(const knot_rdata_t *rdata) +{ + if (rdata->count < 4) { + return NULL; + } + + return ((uint8_t *)(rdata->items[3].raw_data + 1)) + 1; +} diff --git a/src/libknot/rdata.h b/src/libknot/rdata.h index bb45f50..acd678f 100644..100755 --- a/src/libknot/rdata.h +++ b/src/libknot/rdata.h @@ -220,6 +220,8 @@ int knot_rdata_item_set_dname(knot_rdata_t *rdata, unsigned int pos, int knot_rdata_item_set_raw_data(knot_rdata_t *rdata, unsigned int pos, uint16_t *raw_data); +int knot_rdata_count(const knot_rdata_t *rdata); + /*! * \brief Copies the given RDATA. * @@ -335,6 +337,11 @@ uint32_t knot_rdata_soa_minimum(const knot_rdata_t *rdata); uint16_t knot_rdata_rrsig_type_covered(const knot_rdata_t *rdata); +uint8_t knot_rdata_nsec3_algorithm(const knot_rdata_t *rdata); +uint16_t knot_rdata_nsec3_iterations(const knot_rdata_t *rdata); +uint8_t knot_rdata_nsec3_salt_length(const knot_rdata_t *rdata); +const uint8_t *knot_rdata_nsec3_salt(const knot_rdata_t *rdata); + #endif /* _KNOT_RDATA_H */ /*! @} */ diff --git a/src/libknot/rrset.c b/src/libknot/rrset.c index d665c63..ef7fce8 100644..100755 --- a/src/libknot/rrset.c +++ b/src/libknot/rrset.c @@ -32,7 +32,7 @@ /*----------------------------------------------------------------------------*/ static void knot_rrset_disconnect_rdata(knot_rrset_t *rrset, - knot_rdata_t *prev, knot_rdata_t *rdata) + knot_rdata_t *prev, knot_rdata_t *rdata) { if (prev == NULL) { // find the previous RDATA in the series, as its pointer must @@ -113,6 +113,53 @@ int knot_rrset_add_rdata(knot_rrset_t *rrset, knot_rdata_t *rdata) /*----------------------------------------------------------------------------*/ +int knot_rrset_add_rdata_order(knot_rrset_t *rrset, knot_rdata_t *rdata) +{ + if (rrset == NULL || rdata == NULL) { + dbg_rrset("rrset: add_rdata_order: NULL arguments.\n"); + return KNOT_EBADARG; + } + + if (rrset->rdata == NULL) { + /* Easy peasy, just insert the first item. */ + rrset->rdata = rdata; + rrset->rdata->next = rrset->rdata; + } else { + knot_rdata_t *walk = NULL; + char found = 0; + knot_rdata_t *insert_after = rrset->rdata; + while (((walk = knot_rrset_rdata_get_next(rrset, + walk)) != NULL) && + (!found)) { + const knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type(rrset->type); + assert(desc); + int cmp = knot_rdata_compare(rdata, walk, + desc->wireformat); + if (cmp < 1) { + /* We've found place for this item. */ + } else if (cmp == 0) { + /* This item will not be inserted. */ + found = 1; + insert_after = NULL; + } + assert(cmp > 1); + /* Continue the search. */ + insert_after = walk; + } + if (insert_after != NULL) { + rdata->next = insert_after->next; + insert_after->next = rdata; + } else { + ; + /* Consider returning something different than EOK. */ + } + } + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + knot_rdata_t *knot_rrset_remove_rdata(knot_rrset_t *rrset, const knot_rdata_t *rdata) { @@ -167,19 +214,30 @@ int knot_rrset_add_rrsigs(knot_rrset_t *rrset, knot_rrset_t *rrsigs, int rc; if (rrset->rrsigs != NULL) { if (dupl == KNOT_RRSET_DUPL_MERGE) { - rc = knot_rrset_merge((void **)&rrset->rrsigs, - (void **)&rrsigs); + rc = knot_rrset_merge_no_dupl((void **)&rrset->rrsigs, + (void **)&rrsigs); if (rc != KNOT_EOK) { return rc; } else { return 1; } } else if (dupl == KNOT_RRSET_DUPL_SKIP) { +// rc = knot_rrset_merge_no_dupl((void **)&rrset->rrsigs, +// (void **)&rrsigs); +// if (rc != KNOT_EOK) { +// return rc; +// } else { +// return 1; +// } return 2; } else if (dupl == KNOT_RRSET_DUPL_REPLACE) { rrset->rrsigs = rrsigs; } } else { + if (rrset->ttl != rrsigs->ttl) { + rrsigs->ttl = rrset->ttl; + } + rrset->rrsigs = rrsigs; } @@ -291,6 +349,10 @@ knot_rdata_t *knot_rrset_rdata_get_next(knot_rrset_t *rrset, int knot_rrset_rdata_rr_count(const knot_rrset_t *rrset) { + if (rrset == NULL) { + return 0; + } + int count = 0; const knot_rdata_t *rdata = rrset->rdata; @@ -341,7 +403,7 @@ int knot_rrset_compare_rdata(const knot_rrset_t *r1, const knot_rrset_t *r2) } // compare RDATA sets (order is not significant) - const knot_rdata_t *rdata1= knot_rrset_rdata(r1); + const knot_rdata_t *rdata1 = knot_rrset_rdata(r1); const knot_rdata_t *rdata2; // find all RDATA from r1 in r2 @@ -434,7 +496,6 @@ static int knot_rrset_rr_to_wire(const knot_rrset_t *rrset, *pos += 2; size += 10; -// compr->wire_pos += size; dbg_rrset_detail("Max size: %zu, size: %d\n", max_size, size); @@ -465,7 +526,6 @@ static int knot_rrset_rr_to_wire(const knot_rrset_t *rrset, knot_dname_size(dname)); *pos += knot_dname_size(dname); rdlength += knot_dname_size(dname); -// compr->wire_pos += dname->size; break; } default: { @@ -481,7 +541,6 @@ static int knot_rrset_rr_to_wire(const knot_rrset_t *rrset, dbg_rrset_detail("Raw data size: %d\n", raw_data[0]); *pos += raw_data[0]; rdlength += raw_data[0]; -// compr->wire_pos += raw_data[0]; break; } } @@ -523,11 +582,11 @@ int knot_rrset_to_wire(const knot_rrset_t *rrset, uint8_t *wire, size_t *size, if (ret < 0) { // some RR didn't fit in, so no RRs should be used // TODO: remove last entries from compression table - dbg_rrset_detail("Some RR didn't fit in.\n"); + dbg_rrset_verb("Some RR didn't fit in.\n"); return KNOT_ESPACE; } - dbg_rrset_detail("RR of size %d added.\n", ret); + dbg_rrset_verb("RR of size %d added.\n", ret); rrset_size += ret; ++rrs; } while ((rdata = knot_rrset_rdata_next(rrset, rdata)) != NULL); @@ -556,7 +615,7 @@ int knot_rrset_compare(const knot_rrset_t *r1, int res = ((r1->rclass == r2->rclass) && (r1->type == r2->type) - && (r1->ttl == r2->ttl) +// && (r1->ttl == r2->ttl) && knot_dname_compare(r1->owner, r2->owner) == 0); if (cmp == KNOT_RRSET_COMPARE_WHOLE && res) { @@ -571,7 +630,8 @@ int knot_rrset_compare(const knot_rrset_t *r1, /*----------------------------------------------------------------------------*/ -int knot_rrset_deep_copy(const knot_rrset_t *from, knot_rrset_t **to) +int knot_rrset_deep_copy(const knot_rrset_t *from, knot_rrset_t **to, + int copy_rdata_dnames) { if (from == NULL || to == NULL) { return KNOT_EBADARG; @@ -582,14 +642,14 @@ int knot_rrset_deep_copy(const knot_rrset_t *from, knot_rrset_t **to) *to = (knot_rrset_t *)calloc(1, sizeof(knot_rrset_t)); CHECK_ALLOC_LOG(*to, KNOT_ENOMEM); - //(*to)->owner = knot_dname_deep_copy(from->owner); (*to)->owner = from->owner; knot_dname_retain((*to)->owner); (*to)->rclass = from->rclass; (*to)->ttl = from->ttl; (*to)->type = from->type; if (from->rrsigs != NULL) { - ret = knot_rrset_deep_copy(from->rrsigs, &(*to)->rrsigs); + ret = knot_rrset_deep_copy(from->rrsigs, &(*to)->rrsigs, + copy_rdata_dnames); if (ret != KNOT_EOK) { knot_rrset_deep_free(to, 1, 0, 0); return ret; @@ -601,8 +661,19 @@ int knot_rrset_deep_copy(const knot_rrset_t *from, knot_rrset_t **to) /*! \note Order of RDATA will be reversed. */ while (rdata != NULL) { - ret = knot_rrset_add_rdata(*to, knot_rdata_deep_copy(rdata, - knot_rrset_type(from), 1)); + knot_rdata_t *rdata_copy = knot_rdata_deep_copy(rdata, + knot_rrset_type(from), + copy_rdata_dnames); +dbg_rrset_exec_detail( + char *name = knot_dname_to_str(knot_rrset_owner(from)); + dbg_rrset_detail("Copying RDATA from RRSet with owner: %s, type" + ": %s. Old RDATA ptr: %p, new RDATA ptr: %p\n", + name, + knot_rrtype_to_string(knot_rrset_type(from)), + rdata, rdata_copy); + free(name); +); + ret = knot_rrset_add_rdata(*to, rdata_copy); if (ret != KNOT_EOK) { knot_rrset_deep_free(to, 1, 1, 1); return ret; @@ -632,6 +703,7 @@ int knot_rrset_shallow_copy(const knot_rrset_t *from, knot_rrset_t **to) void knot_rrset_rotate(knot_rrset_t *rrset) { + /*! \todo Maybe implement properly one day. */ //rrset->rdata = rrset->rdata->next; } @@ -659,12 +731,6 @@ void knot_rrset_deep_free(knot_rrset_t **rrset, int free_owner, return; } -// char *name = knot_dname_to_str(knot_rrset_owner(*rrset)); -// char *type = knot_rrtype_to_string(knot_rrset_type(*rrset)); -// fprintf(stderr, "Deleting RRSet (%p) %s, type %s, rdata: %p\n", -// *rrset, name, type, (*rrset)->rdata); -// free(name); - if (free_rdata) { knot_rdata_t *tmp_rdata; knot_rdata_t *next_rdata; @@ -679,7 +745,6 @@ void knot_rrset_deep_free(knot_rrset_t **rrset, int free_owner, tmp_rdata = next_rdata; } -// printf("test: %p\n", tmp_rdata->next->next); assert(tmp_rdata == NULL || tmp_rdata->next == (*rrset)->rdata); @@ -693,10 +758,7 @@ void knot_rrset_deep_free(knot_rrset_t **rrset, int free_owner, free_rdata_dnames); } - /*! \todo Release owner every time? */ - //if (free_owner) { - knot_dname_release((*rrset)->owner); - //} + knot_dname_release((*rrset)->owner); free(*rrset); *rrset = NULL; @@ -711,8 +773,7 @@ int knot_rrset_merge(void **r1, void **r2) if ((knot_dname_compare(rrset1->owner, rrset2->owner) != 0) || rrset1->rclass != rrset2->rclass - || rrset1->type != rrset2->type - || rrset1->ttl != rrset2->ttl) { + || rrset1->type != rrset2->type) { return KNOT_EBADARG; } @@ -744,6 +805,155 @@ int knot_rrset_merge(void **r1, void **r2) } tmp_rdata->next = rrset1->rdata; + rrset2->rdata = rrset1->rdata; + + return KNOT_EOK; +} + +int knot_rrset_merge_no_dupl(void **r1, void **r2) +{ + if (r1 == NULL || r2 == NULL) { + dbg_rrset("rrset: merge_no_dupl: NULL arguments."); + return KNOT_EBADARG; + } + + knot_rrset_t *rrset1 = (knot_rrset_t *)(*r1); + knot_rrset_t *rrset2 = (knot_rrset_t *)(*r2); + if (rrset1 == NULL || rrset2 == NULL) { + dbg_rrset("rrset: merge_no_dupl: NULL arguments."); + return KNOT_EBADARG; + } + +dbg_rrset_exec_detail( + char *name = knot_dname_to_str(rrset1->owner); + dbg_rrset_detail("rrset: merge_no_dupl: Merging %s.\n", name); + free(name); +); + + if ((knot_dname_compare(rrset1->owner, rrset2->owner) != 0) + || rrset1->rclass != rrset2->rclass + || rrset1->type != rrset2->type) { + dbg_rrset("rrset: merge_no_dupl: Trying to merge " + "different RRs.\n"); + return KNOT_EBADARG; + } + + knot_rdata_t *walk2 = rrset2->rdata; + + // no RDATA in RRSet 1 + if (rrset1->rdata == NULL && rrset2->rdata != NULL) { + /* + * This function has to assure that there are no duplicates in + * second RRSet's list. This can be done by putting a first + * item from the second list as a first item of the first list + * and then simply continuing with inserting items from second + * list to the first one. + * + * However, we must store pointer to second item in the second + * list, as the 'next' pointer of the first item will be altered + */ + + // Store pointer to the second item in RRSet2 RDATA so that + // we later start from this item. + walk2 = knot_rrset_rdata_get_next(rrset2, walk2); + assert(walk2 == rrset2->rdata->next || walk2 == NULL); + + // Connect the first item from second list to the first list. + rrset1->rdata = rrset2->rdata; + // Close the cyclic list (by pointing to itself). + rrset1->rdata->next = rrset1->rdata; + } else if (rrset2->rdata == NULL) { + return KNOT_EOK; + } + + /* + * Check that rrset1 does not contain any rdata from rrset2, if so + * such RDATA shall not be inserted. + */ + + /* Get last RDATA from first rrset, we'll need it for insertion. */ + knot_rdata_t *insert_after = rrset1->rdata; + while (insert_after->next != rrset1->rdata) { + dbg_rrset_detail("rrset: merge_dupl: first rrset rdata: %p.\n", + insert_after); + insert_after = insert_after->next; + } + assert(insert_after->next == rrset1->rdata); + + while (walk2 != NULL) { + knot_rdata_t *walk1 = rrset1->rdata; + char dupl = 0; + while ((walk1 != NULL) && + !dupl) { + const knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type(rrset1->type); + assert(desc); + /* If walk1 and walk2 are equal, do not insert. */ + dupl = !knot_rdata_compare(walk1, walk2, + desc->wireformat); + walk1 = knot_rrset_rdata_get_next(rrset1, walk1); + dbg_rrset_detail("rrset: merge_dupl: next item: %p.\n", + walk1); + } + if (!dupl) { + dbg_rrset_detail("rrset: merge_dupl: Inserting " + "unique item (%p).\n", + walk2); + knot_rdata_t *tmp = walk2; + /* + * We need to move this, insertion + * will corrupt pointers. + */ + walk2 = knot_rrset_rdata_get_next(rrset2, walk2); + /* Insert this item at the end of first list. */ + tmp->next = insert_after->next; + insert_after->next = tmp; + insert_after = tmp; + /*!< \todo This message has to be removed after bugfix. */ + dbg_rrset_detail("rrset: merge_no_dupl: Insert after=%p" + ", tmp=%p, tmp->next=%p, " + " rrset1->rdata=%p" + "\n", + insert_after, tmp, tmp->next, + rrset1->rdata); + assert(tmp->next == rrset1->rdata); + } else { + dbg_rrset_detail("rrset: merge_dupl: Skipping and " + "freeing duplicated item " + "of type: %s (%p).\n", + knot_rrtype_to_string(rrset1->type), + walk2); + /* + * Not freeing this item will result in a leak. + * Since this operation destroys the second + * list, we have to free the item here. + */ + knot_rdata_t *tmp = walk2; + dbg_rrset_detail("rrset: merge_dupl: freeing: %p.\n", + tmp); + walk2 = knot_rrset_rdata_get_next(rrset2, walk2); + knot_rdata_deep_free(&tmp, rrset1->type, 1); + assert(tmp == NULL); + /* Maybe caller should be warned about this. */ + } + } + + assert(walk2 == NULL); +dbg_rrset_exec_detail( + dbg_rrset_detail("rrset: merge_dupl: RDATA after merge:\n "); + knot_rdata_t *walk1 = rrset1->rdata; + while (walk1 != NULL) { + dbg_rrset_detail("%p ->\n", walk1); + walk1 = knot_rrset_rdata_get_next(rrset1, walk1); + } + dbg_rrset_detail("rrset: merge_dupl: RDATA after merge: r1:%p r2: %p\n", + rrset1->rdata, rrset2->rdata); +); + /* + * Since there is a possibility of corrupted list for second RRSet, it + * is safer to set its list to NULL, so that it cannot be used. + */ + rrset2->rdata = NULL; return KNOT_EOK; } diff --git a/src/libknot/rrset.h b/src/libknot/rrset.h index b5c11dc..36d8da5 100644..100755 --- a/src/libknot/rrset.h +++ b/src/libknot/rrset.h @@ -105,6 +105,21 @@ knot_rrset_t *knot_rrset_new(knot_dname_t *owner, uint16_t type, */ int knot_rrset_add_rdata(knot_rrset_t *rrset, knot_rdata_t *rdata); +/*! + * \brief Adds the given RDATA to the RRSet but will not insert duplicated data. + * + * \warning Should be only used to insert one RDATA. (NO lists) + * + * \param rrset RRSet to add the RDATA to. + * \param rdata RDATA to add to the RRSet. + * + * \retval KNOT_EOK + * \retval KNOT_EBADARG + * + * \todo Provide some function for comparing RDATAs. + */ +int knot_rrset_add_rdata_order(knot_rrset_t *rrset, knot_rdata_t *rdata); + knot_rdata_t * knot_rrset_remove_rdata(knot_rrset_t *rrset, const knot_rdata_t *rdata); @@ -249,7 +264,8 @@ int knot_rrset_compare(const knot_rrset_t *r1, knot_rrset_compare_type_t cmp); /*! \todo Add unit test. */ -int knot_rrset_deep_copy(const knot_rrset_t *from, knot_rrset_t **to); +int knot_rrset_deep_copy(const knot_rrset_t *from, knot_rrset_t **to, + int copy_rdata_dnames); /*! \todo Add unit test. */ int knot_rrset_shallow_copy(const knot_rrset_t *from, knot_rrset_t **to); @@ -296,9 +312,9 @@ void knot_rrset_deep_free(knot_rrset_t **rrset, int free_owner, * \brief Merges two RRSets. * * Merges \a r1 into \a r2 by concatenating the list of RDATAs in \a r2 after - * the list of RDATAs in \a r1. \a r2 is unaffected by this, though you must not - * destroy the RDATAs in \a r2 as they are now also in \a r1. (You may use - * function knot_rrset_free() though, as it does not touch RDATAs). + * the list of RDATAs in \a r1. You must not + * destroy the RDATAs in \a r2 as they are now identical to RDATAs in \a r1. + * (You may use function knot_rrset_free() though, as it does not touch RDATAs). * * \note Member \a rrsigs is preserved from the first RRSet. * @@ -311,6 +327,26 @@ void knot_rrset_deep_free(knot_rrset_t **rrset, int free_owner, */ int knot_rrset_merge(void **r1, void **r2); + +/*! + * \brief Merges two RRSets, but will discard and free any duplicates in \a r2. + * + * Merges \a r1 into \a r2 by concatenating the list of RDATAs in \a r2 after + * the list of RDATAs in \a r1. You must not + * destroy the RDATAs in \a r2 as they are now identical to RDATAs in \a r1. + * (You may use function knot_rrset_free() though, as it does not touch RDATAs). + * + * \note Member \a rrsigs is preserved from the first RRSet. + * + * \param r1 Pointer to RRSet to be merged into. + * \param r2 Poitner to RRSet to be merged. + * + * \retval KNOT_EOK + * \retval KNOT_EBADARG if the RRSets could not be merged, because their + * Owner, Type, Class or TTL does not match. + */ +int knot_rrset_merge_no_dupl(void **r1, void **r2); + #endif /* _KNOT_RRSET_H_ */ /*! @} */ diff --git a/src/libknot/tsig-op.c b/src/libknot/tsig-op.c index 148fc87..173538c 100644..100755 --- a/src/libknot/tsig-op.c +++ b/src/libknot/tsig-op.c @@ -21,20 +21,27 @@ #include <time.h> #include "common.h" +#include "common/base64.h" #include "tsig.h" #include "tsig-op.h" #include "util/wire.h" -#include "libknot/util/conv.h" #include "util/error.h" #include "util/debug.h" #include "consts.h" const int KNOT_TSIG_MAX_DIGEST_SIZE = 64; // size of HMAC-SHA512 digest - +const uint16_t KNOT_TSIG_FUDGE_DEFAULT = 300; // default Fudge value +enum b64_const { + B64BUFSIZE = 65535 +}; static int knot_tsig_check_algorithm(const knot_rrset_t *tsig_rr) { + if (tsig_rr == NULL) { + return KNOT_EBADARG; + } + const knot_dname_t *alg_name = tsig_rdata_alg_name(tsig_rr); if (!alg_name) { return KNOT_EMALF; @@ -53,6 +60,10 @@ static int knot_tsig_check_algorithm(const knot_rrset_t *tsig_rr) static int knot_tsig_check_key(const knot_rrset_t *tsig_rr, const knot_key_t *tsig_key) { + if (tsig_rr == NULL || tsig_key == NULL) { + return KNOT_EBADARG; + } + const knot_dname_t *tsig_name = knot_rrset_owner(tsig_rr); if (!tsig_name) { return KNOT_EMALF; @@ -94,28 +105,25 @@ static int knot_tsig_compute_digest(const uint8_t *wire, size_t wire_len, return KNOT_TSIG_EBADSIG; } - /* Create digest, using length of the algorithm. */ -// *digest = malloc(sizeof(uint8_t) * tsig_alg_digest_length(tsig_alg)); -// if (!digest) { -// ERR_ALLOC_FAILED; -// return KNOT_ENOMEM; -// } - /* Decode key from Base64. */ char decoded_key[B64BUFSIZE]; - - int decoded_key_size = b64_pton(key->secret, (uint8_t *)decoded_key, - B64BUFSIZE); + + size_t decoded_key_size = B64BUFSIZE; + int ret = base64_decode(key->secret, strlen(key->secret), + decoded_key, + &decoded_key_size); + if (ret != 1) { + dbg_tsig("TSIG: New decode function failed! (%d)\n", ret); + return KNOT_ERROR; + } + if (decoded_key_size < 0) { dbg_tsig("TSIG: Could not decode Base64\n"); return KNOT_ERROR; } - + dbg_tsig_detail("TSIG: decoded key size: %d\n", decoded_key_size); dbg_tsig_detail("TSIG: decoded key: '%*s'\n", decoded_key_size, decoded_key); - -// dbg_tsig_detail("TSIG: using this wire for digest calculation\n"); -// dbg_tsig_hex_detail(wire, wire_len); dbg_tsig_detail("Wire for signing is %zu bytes long.\n", wire_len); /* Compute digest. */ @@ -152,6 +160,7 @@ static int knot_tsig_check_time_signed(const knot_rrset_t *tsig_rr, uint64_t prev_time_signed) { if (!tsig_rr) { + dbg_tsig("TSIG: check_time_signed: NULL argument.\n"); return KNOT_EBADARG; } @@ -184,21 +193,14 @@ static int knot_tsig_check_time_signed(const knot_rrset_t *tsig_rr, return KNOT_EOK; } -static int knot_tsig_write_tsig_timers(uint8_t *wire, - const knot_rrset_t *tsig_rr) -{ - // put time signed - knot_wire_write_u48(wire, tsig_rdata_time_signed(tsig_rr)); - - // put fudge - knot_wire_write_u16(wire + 6, tsig_rdata_fudge(tsig_rr)); - - return KNOT_EOK; -} - static int knot_tsig_write_tsig_variables(uint8_t *wire, const knot_rrset_t *tsig_rr) { + if (wire == NULL || tsig_rr == NULL) { + dbg_tsig("TSIG: write tsig variables: NULL arguments.\n"); + return KNOT_EBADARG; + } + /* Copy TSIG variables - starting with key name. */ const knot_dname_t *tsig_owner = knot_rrset_owner(tsig_rr); if (!tsig_owner) { @@ -210,24 +212,23 @@ static int knot_tsig_write_tsig_variables(uint8_t *wire, memcpy(wire + offset, knot_dname_name(tsig_owner), sizeof(uint8_t) * knot_dname_size(tsig_owner)); - dbg_tsig("TSIG: write variables: written owner (tsig alg): \n"); - /*knot_rrset_class(tsig_rr));*/ - dbg_tsig_hex_detail(wire + offset, knot_dname_size(tsig_owner)); + dbg_tsig_verb("TSIG: write variables: written owner (tsig alg): \n"); + dbg_tsig_hex_verb(wire + offset, knot_dname_size(tsig_owner)); offset += knot_dname_size(tsig_owner); /*!< \todo which order? */ /* Copy class. */ knot_wire_write_u16(wire + offset, knot_rrset_class(tsig_rr)); - dbg_tsig("TSIG: write variables: written CLASS: %u - ", - knot_rrset_class(tsig_rr)); + dbg_tsig_verb("TSIG: write variables: written CLASS: %u - ", + knot_rrset_class(tsig_rr)); dbg_tsig_hex_detail(wire + offset, sizeof(uint16_t)); offset += sizeof(uint16_t); /* Copy TTL - always 0. */ knot_wire_write_u32(wire + offset, knot_rrset_ttl(tsig_rr)); - dbg_tsig("TSIG: write variables: written TTL: %u - ", - knot_rrset_ttl(tsig_rr)); + dbg_tsig_verb("TSIG: write variables: written TTL: %u - ", + knot_rrset_ttl(tsig_rr)); dbg_tsig_hex_detail(wire + offset, sizeof(uint32_t)); offset += sizeof(uint32_t); @@ -237,28 +238,25 @@ static int knot_tsig_write_tsig_variables(uint8_t *wire, dbg_tsig("TSIG: write variables: no algorithm name.\n"); return KNOT_EBADARG; } -// alg_name = knot_dname_new_from_str("HMAC-MD5.SIG-ALG.REG.INT.", - //strlen("HMAC-MD5.SIG-ALG.REG.INT."), - //NULL); memcpy(wire + offset, knot_dname_name(alg_name), sizeof(uint8_t) * knot_dname_size(alg_name)); offset += knot_dname_size(alg_name); - dbg_tsig_detail("TSIG: write variables: written alg name: %s\n", - knot_dname_to_str(alg_name)); + dbg_tsig_verb("TSIG: write variables: written alg name: %s\n", + knot_dname_to_str(alg_name)); /* Following data are written in network order. */ /* Time signed. */ knot_wire_write_u48(wire + offset, tsig_rdata_time_signed(tsig_rr)); offset += 6; - dbg_tsig_detail("TSIG: write variables: time signed: %llu - ", - tsig_rdata_time_signed(tsig_rr)); + dbg_tsig_verb("TSIG: write variables: time signed: %llu - ", + tsig_rdata_time_signed(tsig_rr)); dbg_tsig_hex_detail(wire + offset - 6, 6); /* Fudge. */ knot_wire_write_u16(wire + offset, tsig_rdata_fudge(tsig_rr)); offset += sizeof(uint16_t); - dbg_tsig_detail("TSIG: write variables: fudge: %hu\n", - tsig_rdata_fudge(tsig_rr)); + dbg_tsig_verb("TSIG: write variables: fudge: %hu\n", + tsig_rdata_fudge(tsig_rr)); /* TSIG error. */ knot_wire_write_u16(wire + offset, tsig_rdata_error(tsig_rr)); offset += sizeof(uint16_t); @@ -279,7 +277,7 @@ static int knot_tsig_write_tsig_variables(uint8_t *wire, offset += sizeof(uint16_t); /* Skip the length. */ - dbg_tsig_detail("Copying other data.\n"); + dbg_tsig_verb("Copying other data.\n"); memcpy(wire + offset, other_data, other_data_length); return KNOT_EOK; @@ -288,7 +286,14 @@ static int knot_tsig_write_tsig_variables(uint8_t *wire, static int knot_tsig_wire_write_timers(uint8_t *wire, const knot_rrset_t *tsig_rr) { + if (wire == NULL || tsig_rr == NULL) { + dbg_tsig("TSIG: write timers: NULL arguments.\n"); + return KNOT_EBADARG; + } + + //write time signed knot_wire_write_u48(wire, tsig_rdata_time_signed(tsig_rr)); + //write fudge knot_wire_write_u16(wire + 6, tsig_rdata_fudge(tsig_rr)); return KNOT_EOK; @@ -308,21 +313,14 @@ static int knot_tsig_create_sign_wire(const uint8_t *msg, size_t msg_len, /* Create tmp TSIG. */ int ret = KNOT_EOK; -// knot_rrset_t *tmp_tsig = -// knot_rrset_new(key->name, KNOT_RRTYPE_TSIG, KNOT_CLASS_ANY, 0); -// if (!tmp_tsig) { -// return KNOT_ENOMEM; -// } - -// tsig_rdata_store_current_time(tmp_tsig); /* * Create tmp wire, it should contain message * plus request mac plus tsig varibles. */ - dbg_tsig("Counting wire size: %zu, %zu, %zu.\n", - msg_len, request_mac_len, - tsig_rdata_tsig_variables_length(tmp_tsig)); + dbg_tsig_verb("Counting wire size: %zu, %zu, %zu.\n", + msg_len, request_mac_len, + tsig_rdata_tsig_variables_length(tmp_tsig)); size_t wire_len = sizeof(uint8_t) * (msg_len + request_mac_len + ((request_mac_len > 0) ? 2 : 0) + @@ -339,23 +337,21 @@ static int knot_tsig_create_sign_wire(const uint8_t *msg, size_t msg_len, /* Copy the request MAC - should work even if NULL. */ if (request_mac_len > 0) { - dbg_tsig_detail("Copying request MAC size\n"); + dbg_tsig_verb("Copying request MAC size\n"); knot_wire_write_u16(pos, request_mac_len); pos += 2; } - dbg_tsig("Copying request mac.\n"); + dbg_tsig_verb("Copying request mac.\n"); memcpy(pos, request_mac, sizeof(uint8_t) * request_mac_len); dbg_tsig_detail("TSIG: create wire: request mac: "); dbg_tsig_hex_detail(pos, request_mac_len); pos += request_mac_len; /* Copy the original message. */ - dbg_tsig("Copying original message.\n"); + dbg_tsig_verb("Copying original message.\n"); memcpy(pos, msg, msg_len); - dbg_tsig_detail("TSIG: create wire: original message: \n"); - //dbg_tsig_hex_detail(pos, msg_len); pos += msg_len; /* Copy TSIG variables. */ - dbg_tsig("Writing TSIG variables.\n"); + dbg_tsig_verb("Writing TSIG variables.\n"); ret = knot_tsig_write_tsig_variables(pos, tmp_tsig); if (ret != KNOT_EOK) { dbg_tsig("TSIG: create wire: failed to write TSIG " @@ -375,20 +371,8 @@ static int knot_tsig_create_sign_wire(const uint8_t *msg, size_t msg_len, return ret; } -// assert(digest_tmp_len > 0); free(wire); -// if (digest_tmp_len > *digest_len) { -// *digest_len = 0; -// return KNOT_ESPACE; -// } - -// knot_rrset_deep_free(&tmp_tsig, 1, 1, 1); - - // everything went ok, save the digest to the output parameter -// memcpy(digest, digest_tmp, digest_tmp_len); -// *digest_len = digest_tmp_len; - return KNOT_EOK; } @@ -411,9 +395,9 @@ static int knot_tsig_create_sign_wire_next(const uint8_t *msg, size_t msg_len, * Create tmp wire, it should contain message * plus request mac plus tsig varibles. */ - dbg_tsig("Counting wire size: %zu, %zu, %zu.\n", - msg_len, prev_mac_len, - tsig_rdata_tsig_timers_length()); + dbg_tsig_verb("Counting wire size: %zu, %zu, %zu.\n", + msg_len, prev_mac_len, + tsig_rdata_tsig_timers_length()); size_t wire_len = sizeof(uint8_t) * (msg_len + prev_mac_len + tsig_rdata_tsig_timers_length() + 2); @@ -426,27 +410,24 @@ static int knot_tsig_create_sign_wire_next(const uint8_t *msg, size_t msg_len, memset(wire, 0, wire_len); /* Copy the request MAC - should work even if NULL. */ - dbg_tsig("Copying request mac size.\n"); + dbg_tsig_verb("Copying request mac size.\n"); knot_wire_write_u16(wire, prev_mac_len); - dbg_tsig("Copying request mac.\n"); + dbg_tsig_verb("Copying request mac.\n"); memcpy(wire + 2, prev_mac, sizeof(uint8_t) * prev_mac_len); dbg_tsig_detail("TSIG: create wire: request mac: "); dbg_tsig_hex_detail(wire + 2, prev_mac_len); /* Copy the original message. */ - dbg_tsig("Copying original message.\n"); + dbg_tsig_verb("Copying original message.\n"); memcpy(wire + prev_mac_len + 2, msg, msg_len); - dbg_tsig_detail("TSIG: create wire: original message: \n"); - //dbg_tsig_hex_detail(wire + prev_mac_len, msg_len); /* Copy TSIG variables. */ - dbg_tsig("Writing TSIG timers.\n"); - ret = knot_tsig_write_tsig_timers(wire + prev_mac_len + msg_len + 2, + dbg_tsig_verb("Writing TSIG timers.\n"); + ret = knot_tsig_wire_write_timers(wire + prev_mac_len + msg_len + 2, tmp_tsig); -// ret = knot_tsig_write_tsig_variables(wire + prev_mac_len + msg_len, -// tmp_tsig); if (ret != KNOT_EOK) { dbg_tsig("TSIG: create wire: failed to write TSIG " "timers: %s\n", knot_strerror(ret)); + free(wire); return ret; } @@ -457,6 +438,7 @@ static int knot_tsig_create_sign_wire_next(const uint8_t *msg, size_t msg_len, dbg_tsig("TSIG: create wire: failed to compute digest: %s\n", knot_strerror(ret)); *digest_len = 0; + free(wire); return ret; } @@ -478,7 +460,7 @@ int knot_tsig_sign(uint8_t *msg, size_t *msg_len, knot_dname_t *key_name_copy = knot_dname_deep_copy(key->name); if (!key_name_copy) { - dbg_tsig_detail("TSIG: key_name_copy = NULL\n"); + dbg_tsig("TSIG: key_name_copy = NULL\n"); return KNOT_ENOMEM; } @@ -488,14 +470,14 @@ int knot_tsig_sign(uint8_t *msg, size_t *msg_len, /* Should be retained by rrsig or freed, release. */ knot_dname_release(key_name_copy); if (!tmp_tsig) { - dbg_tsig_detail("TSIG: tmp_tsig = NULL\n"); + dbg_tsig("TSIG: tmp_tsig = NULL\n"); return KNOT_ENOMEM; } /* Create rdata for TSIG RR. */ knot_rdata_t *rdata = knot_rdata_new(); if (!rdata) { - dbg_tsig_detail("TSIG: rdata = NULL\n"); + dbg_tsig("TSIG: rdata = NULL\n"); knot_rrset_free(&tmp_tsig); return KNOT_ENOMEM; } @@ -510,7 +492,7 @@ int knot_tsig_sign(uint8_t *msg, size_t *msg_len, knot_rdata_item_t *items = malloc(sizeof(knot_rdata_item_t) * desc->length); if (!items) { - dbg_tsig_detail("TSIG: items = NULL\n"); + dbg_tsig("TSIG: items = NULL\n"); ERR_ALLOC_FAILED; knot_rrset_free(&tmp_tsig); knot_rdata_free(&rdata); @@ -521,7 +503,8 @@ int knot_tsig_sign(uint8_t *msg, size_t *msg_len, int ret = knot_rdata_set_items(rdata, items, desc->length); if (ret != KNOT_EOK) { - dbg_tsig_detail("TSIG: rdata_set_items returned %s\n", knot_strerror(ret)); + dbg_tsig("TSIG: rdata_set_items returned %s\n", + knot_strerror(ret)); free(items); knot_rrset_free(&tmp_tsig); knot_rdata_free(&rdata); @@ -554,7 +537,7 @@ int knot_tsig_sign(uint8_t *msg, size_t *msg_len, tsig_rdata_set_other_data(tmp_tsig, 0, 0); } - tsig_rdata_set_fudge(tmp_tsig, 300); /*! \todo Bleeding eyes :-) */ + tsig_rdata_set_fudge(tmp_tsig, KNOT_TSIG_FUDGE_DEFAULT); /* Set original ID */ tsig_rdata_set_orig_id(tmp_tsig, knot_wire_get_id(msg)); @@ -583,13 +566,11 @@ int knot_tsig_sign(uint8_t *msg, size_t *msg_len, int rr_count = 0; tsig_rdata_set_mac(tmp_tsig, digest_tmp_len, digest_tmp); - //knot_rrset_dump(tmp_tsig, 1); - /* Write RRSet to wire */ ret = knot_rrset_to_wire(tmp_tsig, msg + *msg_len, &tsig_wire_len, &rr_count); if (ret != KNOT_EOK) { - dbg_tsig_detail("TSIG: rrset_to_wire = %s\n", knot_strerror(ret)); + dbg_tsig("TSIG: rrset_to_wire = %s\n", knot_strerror(ret)); *digest_len = 0; knot_rrset_free(&tmp_tsig); knot_rdata_free(&rdata); @@ -633,7 +614,7 @@ int knot_tsig_sign_next(uint8_t *msg, size_t *msg_len, size_t msg_max_len, /* Create rdata for TSIG RR. */ knot_rdata_t *rdata = knot_rdata_new(); if (!rdata) { - dbg_tsig_detail("TSIG: rdata = NULL\n"); + dbg_tsig("TSIG: rdata = NULL\n"); knot_rrset_free(&tmp_tsig); return KNOT_ENOMEM; } @@ -642,7 +623,7 @@ int knot_tsig_sign_next(uint8_t *msg, size_t *msg_len, size_t msg_max_len, ret = knot_rrset_add_rdata(tmp_tsig, rdata); if (ret != KNOT_EOK) { - dbg_tsig_detail("TSIG: could not add rdata\n"); + dbg_tsig("TSIG: could not add rdata\n"); knot_rrset_free(&tmp_tsig); knot_rdata_free(&rdata); return ret; @@ -656,7 +637,7 @@ int knot_tsig_sign_next(uint8_t *msg, size_t *msg_len, size_t msg_max_len, knot_rdata_item_t *items = malloc(sizeof(knot_rdata_item_t) * desc->length); if (!items) { - dbg_tsig_detail("TSIG: items = NULL\n"); + dbg_tsig("TSIG: items = NULL\n"); ERR_ALLOC_FAILED; knot_rrset_free(&tmp_tsig); knot_rdata_free(&rdata); @@ -667,7 +648,8 @@ int knot_tsig_sign_next(uint8_t *msg, size_t *msg_len, size_t msg_max_len, ret = knot_rdata_set_items(rdata, items, desc->length); if (ret != KNOT_EOK) { - dbg_tsig_detail("TSIG: rdata_set_items returned %s\n", knot_strerror(ret)); + dbg_tsig("TSIG: rdata_set_items returned %s\n", + knot_strerror(ret)); knot_rrset_free(&tmp_tsig); knot_rdata_free(&rdata); free(items); @@ -676,7 +658,7 @@ int knot_tsig_sign_next(uint8_t *msg, size_t *msg_len, size_t msg_max_len, free(items); tsig_rdata_store_current_time(tmp_tsig); - tsig_rdata_set_fudge(tmp_tsig, 300); + tsig_rdata_set_fudge(tmp_tsig, KNOT_TSIG_FUDGE_DEFAULT); /* Create wire to be signed. */ size_t wire_len = prev_digest_len + to_sign_len @@ -739,8 +721,8 @@ int knot_tsig_sign_next(uint8_t *msg, size_t *msg_len, size_t msg_max_len, /* Set other data. */ tsig_rdata_set_other_data(tmp_tsig, 0, NULL); - dbg_tsig_detail("Message max length: %zu, message length: %zu\n", - msg_max_len, *msg_len); + dbg_tsig_verb("Message max length: %zu, message length: %zu\n", + msg_max_len, *msg_len); size_t tsig_wire_size = msg_max_len - *msg_len; int rr_count = 0; @@ -788,7 +770,7 @@ static int knot_tsig_check_digest(const knot_rrset_t *tsig_rr, return ret; } - dbg_tsig("TSIG: time checked.\n"); + dbg_tsig_verb("TSIG: time checked.\n"); /* Check that libknot knows the algorithm. */ ret = knot_tsig_check_algorithm(tsig_rr); @@ -796,7 +778,7 @@ static int knot_tsig_check_digest(const knot_rrset_t *tsig_rr, return ret; } - dbg_tsig("TSIG: algorithm checked.\n"); + dbg_tsig_verb("TSIG: algorithm checked.\n"); /* Check that key is valid, ie. the same as given in args. */ ret = knot_tsig_check_key(tsig_rr, tsig_key); @@ -804,22 +786,15 @@ static int knot_tsig_check_digest(const knot_rrset_t *tsig_rr, return ret; } - dbg_tsig("TSIG: key validity checked.\n"); + dbg_tsig_verb("TSIG: key validity checked.\n"); /* Time OK algorithm OK, key name OK - do digest. */ /* Calculate the size of TSIG RR. */ size_t tsig_len = tsig_wire_actsize(tsig_rr); - dbg_tsig_detail("TSIG: check digest: wire before strip: \n"); - //dbg_tsig_hex_detail(wire, size); - /* Strip the TSIG. */ size -= tsig_len; - dbg_tsig_detail("TSIG: check digest: wire after strip (stripped %zu):\n", - tsig_len); - //dbg_tsig_hex_detail(wire, size); - uint8_t *wire_to_sign = malloc(sizeof(uint8_t) * size); if (!wire_to_sign) { ERR_ALLOC_FAILED; @@ -858,16 +833,7 @@ static int knot_tsig_check_digest(const knot_rrset_t *tsig_rr, return ret; } -// uint8_t digest_tmp[KNOT_TSIG_MAX_DIGEST_SIZE]; -// size_t digest_tmp_len = 0; -// ret = knot_tsig_compute_digest(wire, size, digest_tmp, -// &digest_tmp_len, tsig_key); -// if (ret != KNOT_EOK) { -// dbg_tsig("TSIG: digest could not be calculated\n"); -// return ret; -// } - - dbg_tsig("TSIG: digest calculated\n"); + dbg_tsig_verb("TSIG: digest calculated\n"); /* Compare MAC from TSIG RR RDATA with just computed digest. */ @@ -880,17 +846,16 @@ static int knot_tsig_check_digest(const knot_rrset_t *tsig_rr, const uint8_t *tsig_mac = tsig_rdata_mac(tsig_rr); if (mac_length != tsig_alg_digest_length(alg)) { - dbg_tsig("TSIG: calculated digest length and given length do not match!\n"); + dbg_tsig("TSIG: calculated digest length and given length do " + "not match!\n"); return KNOT_TSIG_EBADSIG; } -// assert(tsig_alg_digest_length(alg) == mac_length); - - dbg_tsig("TSIG: calc digest : "); - dbg_tsig_hex(digest_tmp, digest_tmp_len); + dbg_tsig_verb("TSIG: calc digest : "); + dbg_tsig_hex_verb(digest_tmp, digest_tmp_len); - dbg_tsig("TSIG: given digest: "); - dbg_tsig_hex(tsig_mac, mac_length); + dbg_tsig_verb("TSIG: given digest: "); + dbg_tsig_hex_verb(tsig_mac, mac_length); if (strncasecmp((char *)(tsig_mac), (char *)digest_tmp, mac_length) != 0) { @@ -904,7 +869,7 @@ int knot_tsig_server_check(const knot_rrset_t *tsig_rr, const uint8_t *wire, size_t size, const knot_key_t *tsig_key) { - dbg_tsig_verb("tsig_server_check()\n"); + dbg_tsig("tsig_server_check()\n"); return knot_tsig_check_digest(tsig_rr, wire, size, NULL, 0, tsig_key, 0, 0); } @@ -915,7 +880,7 @@ int knot_tsig_client_check(const knot_rrset_t *tsig_rr, const knot_key_t *tsig_key, uint64_t prev_time_signed) { - dbg_tsig_verb("tsig_client_check()\n"); + dbg_tsig("tsig_client_check()\n"); return knot_tsig_check_digest(tsig_rr, wire, size, request_mac, request_mac_len, tsig_key, prev_time_signed, 0); @@ -928,9 +893,7 @@ int knot_tsig_client_check_next(const knot_rrset_t *tsig_rr, const knot_key_t *tsig_key, uint64_t prev_time_signed) { -// return knot_tsig_client_check(tsig_rr, wire, size, prev_digest, -// prev_digest_len, tsig_key); - dbg_tsig_verb("tsig_client_check_next()\n"); + dbg_tsig("tsig_client_check_next()\n"); return knot_tsig_check_digest(tsig_rr, wire, size, prev_digest, prev_digest_len, tsig_key, prev_time_signed, 1); @@ -950,15 +913,14 @@ int knot_tsig_add(uint8_t *msg, size_t *msg_len, size_t msg_max_len, knot_dname_t *key_name = knot_dname_deep_copy(knot_rrset_owner(tsig_rr)); if (key_name == NULL) { - dbg_tsig_detail("TSIG: failed to copy owner\n"); + dbg_tsig("TSIG: failed to copy owner\n"); return KNOT_ERROR; } knot_rrset_t *tmp_tsig = - knot_rrset_new(key_name, - KNOT_RRTYPE_TSIG, KNOT_CLASS_ANY, 0); + knot_rrset_new(key_name, KNOT_RRTYPE_TSIG, KNOT_CLASS_ANY, 0); if (!tmp_tsig) { - dbg_tsig_detail("TSIG: tmp_tsig = NULL\n"); + dbg_tsig("TSIG: tmp_tsig = NULL\n"); knot_dname_free(&key_name); return KNOT_ENOMEM; } @@ -966,7 +928,7 @@ int knot_tsig_add(uint8_t *msg, size_t *msg_len, size_t msg_max_len, /* Create rdata for TSIG RR. */ knot_rdata_t *rdata = knot_rdata_new(); if (!rdata) { - dbg_tsig_detail("TSIG: rdata = NULL\n"); + dbg_tsig("TSIG: rdata = NULL\n"); knot_rrset_deep_free(&tmp_tsig, 1, 1, 1); return KNOT_ENOMEM; } @@ -981,7 +943,7 @@ int knot_tsig_add(uint8_t *msg, size_t *msg_len, size_t msg_max_len, knot_rdata_item_t *items = malloc(sizeof(knot_rdata_item_t) * desc->length); if (items == NULL) { - dbg_tsig_detail("TSIG: items = NULL\n"); + dbg_tsig("TSIG: items = NULL\n"); ERR_ALLOC_FAILED; knot_rrset_deep_free(&tmp_tsig, 1, 1, 1); return KNOT_ENOMEM; @@ -992,8 +954,8 @@ int knot_tsig_add(uint8_t *msg, size_t *msg_len, size_t msg_max_len, int ret = knot_rdata_set_items(rdata, items, desc->length); free(items); if (ret != KNOT_EOK) { - dbg_tsig_detail("TSIG: rdata_set_items returned %s\n", - knot_strerror(ret)); + dbg_tsig("TSIG: rdata_set_items returned %s\n", + knot_strerror(ret)); knot_rrset_deep_free(&tmp_tsig, 1, 1, 1); return ret; } @@ -1001,14 +963,18 @@ int knot_tsig_add(uint8_t *msg, size_t *msg_len, size_t msg_max_len, knot_dname_t *alg_name = knot_dname_deep_copy(tsig_rdata_alg_name(tsig_rr)); if (alg_name == NULL) { - dbg_tsig_detail("TSIG: failed to copy alg name\n"); + dbg_tsig("TSIG: failed to copy alg name\n"); knot_rrset_deep_free(&tmp_tsig, 1, 1, 1); return KNOT_ERROR; } tsig_rdata_set_alg_name(tmp_tsig, alg_name); tsig_rdata_set_time_signed(tmp_tsig, tsig_rdata_time_signed(tsig_rr)); - tsig_rdata_set_fudge(tmp_tsig, tsig_rdata_fudge(tsig_rr)); + + /* Comparing to BIND it was found out that the Fudge should always be + * set to the server's value. + */ + tsig_rdata_set_fudge(tmp_tsig, KNOT_TSIG_FUDGE_DEFAULT); tsig_rdata_set_mac(tmp_tsig, 0, NULL); knot_dname_release(alg_name); /* Already copied in tsig_rdata_set_alg_name() */ @@ -1029,7 +995,7 @@ int knot_tsig_add(uint8_t *msg, size_t *msg_len, size_t msg_max_len, ret = knot_rrset_to_wire(tmp_tsig, msg + *msg_len, &tsig_wire_len, &rr_count); if (ret != KNOT_EOK) { - dbg_tsig_detail("TSIG: rrset_to_wire = %s\n", knot_strerror(ret)); + dbg_tsig("TSIG: rrset_to_wire = %s\n", knot_strerror(ret)); knot_rrset_deep_free(&tmp_tsig, 1, 1, 1); return ret; } diff --git a/src/libknot/tsig-op.h b/src/libknot/tsig-op.h index 07a84a8..07a84a8 100644..100755 --- a/src/libknot/tsig-op.h +++ b/src/libknot/tsig-op.h diff --git a/src/libknot/tsig.c b/src/libknot/tsig.c index e8df92e..86b7f9d 100644..100755 --- a/src/libknot/tsig.c +++ b/src/libknot/tsig.c @@ -319,21 +319,21 @@ tsig_algorithm_t tsig_rdata_alg(const knot_rrset_t *tsig) /* Get the algorithm name. */ const knot_dname_t *alg_name = tsig_rdata_alg_name(tsig); if (!alg_name) { - dbg_tsig_detail("TSIG: rdata: cannot get algorithm name.\n"); + dbg_tsig("TSIG: rdata: cannot get algorithm name.\n"); return KNOT_TSIG_ALG_NULL; } /* Convert alg name to string. */ char *name = knot_dname_to_str(alg_name); if (!name) { - dbg_tsig_detail("TSIG: rdata: cannot convert alg name.\n"); + dbg_tsig("TSIG: rdata: cannot convert alg name.\n"); return KNOT_TSIG_ALG_NULL; } knot_lookup_table_t *item = knot_lookup_by_name(tsig_alg_table, name); free(name); if (!item) { - dbg_tsig_detail("TSIG: rdata: unknown algorithm.\n"); + dbg_tsig("TSIG: rdata: unknown algorithm.\n"); return KNOT_TSIG_ALG_NULL; } @@ -342,7 +342,7 @@ tsig_algorithm_t tsig_rdata_alg(const knot_rrset_t *tsig) uint64_t tsig_rdata_time_signed(const knot_rrset_t *tsig) { - /*!< \note How about assert. Or maybe change API??? */ + /*! \note How about assert. Or maybe change API??? */ if (!tsig) { return 0; } @@ -366,7 +366,7 @@ uint64_t tsig_rdata_time_signed(const knot_rrset_t *tsig) uint16_t tsig_rdata_fudge(const knot_rrset_t *tsig) { - /*!< \note How about assert. Or maybe change API??? */ + /*! \note How about assert. Or maybe change API??? */ if (!tsig) { return 0; } @@ -390,7 +390,7 @@ uint16_t tsig_rdata_fudge(const knot_rrset_t *tsig) const uint8_t *tsig_rdata_mac(const knot_rrset_t *tsig) { - /*!< \note How about assert. Or maybe change API??? */ + /*! \note How about assert. Or maybe change API??? */ if (!tsig) { return 0; } @@ -424,7 +424,7 @@ size_t tsig_rdata_mac_length(const knot_rrset_t *tsig) uint16_t tsig_rdata_orig_id(const knot_rrset_t *tsig) { - /*!< \note How about assert. Or maybe change API??? */ + /*! \note How about assert. Or maybe change API??? */ if (!tsig) { return 0; } @@ -448,7 +448,7 @@ uint16_t tsig_rdata_orig_id(const knot_rrset_t *tsig) uint16_t tsig_rdata_error(const knot_rrset_t *tsig) { - /*!< \note How about assert. Or maybe change API??? */ + /*! \note How about assert. Or maybe change API??? */ if (!tsig) { return 0; } @@ -472,7 +472,7 @@ uint16_t tsig_rdata_error(const knot_rrset_t *tsig) const uint8_t *tsig_rdata_other_data(const knot_rrset_t *tsig) { - /*!< \note How about assert. Or maybe change API??? */ + /*! \note How about assert. Or maybe change API??? */ if (!tsig) { return 0; } @@ -491,7 +491,7 @@ const uint8_t *tsig_rdata_other_data(const knot_rrset_t *tsig) uint16_t tsig_rdata_other_data_length(const knot_rrset_t *tsig) { - /*!< \note How about assert. Or maybe change API??? */ + /*! \note How about assert. Or maybe change API??? */ if (!tsig) { return 0; } @@ -558,6 +558,9 @@ uint16_t tsig_alg_digest_length(tsig_algorithm_t alg) size_t tsig_rdata_tsig_variables_length(const knot_rrset_t *tsig) { + if (tsig == NULL) { + return 0; + } /* Key name, Algorithm name and Other data have variable lengths. */ const knot_dname_t *key_name = knot_rrset_owner(tsig); if (!key_name) { @@ -569,13 +572,6 @@ size_t tsig_rdata_tsig_variables_length(const knot_rrset_t *tsig) return 0; } -// dbg_tsig_detail("key_name: %.*s (size: %u) alg_name: %.*s (size: %u)\n", knot_dname_size(key_name), -// key_name->name, alg_name->size, alg_name->name, -// key_name->size, alg_name->size); - -// dbg_tsig_hex_detail(key_name->name, key_name->size); -// dbg_tsig_hex_detail(alg_name->name, alg_name->size); - uint16_t other_data_length = tsig_rdata_other_data_length(tsig); return knot_dname_size(key_name) + knot_dname_size(alg_name) + @@ -594,7 +590,7 @@ int tsig_rdata_store_current_time(knot_rrset_t *tsig) return KNOT_EBADARG; } time_t curr_time = time(NULL); - /*!< \todo bleeding eyes. */ + /*! \todo bleeding eyes. */ tsig_rdata_set_time_signed(tsig, (uint64_t)curr_time); return KNOT_EOK; } @@ -612,6 +608,10 @@ const char* tsig_alg_to_str(tsig_algorithm_t alg) size_t tsig_wire_maxsize(const knot_key_t* key) { + if (key == NULL) { + return 0; + } + size_t alg_name_size = strlen(tsig_alg_to_str(key->algorithm)) + 1; return knot_dname_size(key->name) + @@ -632,6 +632,10 @@ size_t tsig_wire_maxsize(const knot_key_t* key) size_t tsig_wire_actsize(const knot_rrset_t *tsig) { + if (tsig == NULL) { + return 0; + } + return knot_dname_size(knot_rrset_owner(tsig)) + sizeof(uint16_t) + /* TYPE */ sizeof(uint16_t) + /* CLASS */ @@ -648,3 +652,12 @@ size_t tsig_wire_actsize(const knot_rrset_t *tsig) tsig_rdata_other_data_length(tsig); } +int tsig_rdata_is_ok(const knot_rrset_t *tsig) +{ + return (tsig + && knot_rrset_rdata(tsig) != NULL + && knot_rdata_item_count(knot_rrset_rdata(tsig)) >= 7 + && tsig_rdata_alg_name(tsig) != NULL + && tsig_rdata_time_signed(tsig) != 0); +} + diff --git a/src/libknot/tsig.h b/src/libknot/tsig.h index 73fa832..249184d 100644..100755 --- a/src/libknot/tsig.h +++ b/src/libknot/tsig.h @@ -140,6 +140,8 @@ uint16_t tsig_alg_digest_length(tsig_algorithm_t alg); size_t tsig_wire_maxsize(const knot_key_t *key); size_t tsig_wire_actsize(const knot_rrset_t *tsig); +int tsig_rdata_is_ok(const knot_rrset_t *tsig); + #endif /* _KNOT_TSIG_H_ */ /*! @} */ diff --git a/src/libknot/updates/changesets.c b/src/libknot/updates/changesets.c index 1c3d3b9..502a858 100644..100755 --- a/src/libknot/updates/changesets.c +++ b/src/libknot/updates/changesets.c @@ -115,23 +115,20 @@ int knot_changeset_add_rr(knot_rrset_t ***rrsets, size_t *count, // try to find the RRSet in the list of RRSets, but search backwards // as it is probable that the last RRSet is the one to which the RR // belongs - int i = *count - 1; - - while (i >= 0 && !knot_changeset_rrsets_match((*rrsets)[i], rr)) { - --i; - } - if (i >= 0) { - // found RRSet to merge the new one into - if (knot_rrset_merge((void **)&(*rrsets)[i], - (void **)&rr) != KNOT_EOK) { + // Just check the last RRSet. If the RR belongs to it, merge it, + // otherwise just add the RR to the end of the list + + if (*count > 0 + && knot_changeset_rrsets_match((*rrsets)[*count - 1], rr)) { + // Create changesets exactly as they came, with possibly + // duplicate records + if (knot_rrset_merge((void **)&(*rrsets)[*count - 1], + (void **)&rr) != KNOT_EOK) { return KNOT_ERROR; } - // remove the RR - /*! \todo does this make sense? */ - knot_rrset_free(&rr); // used to be deep free with all 1's - + knot_rrset_free(&rr); return KNOT_EOK; } else { return knot_changeset_add_rrset(rrsets, count, allocated, rr); @@ -211,7 +208,7 @@ int knot_changeset_add_soa(knot_changeset_t *changeset, knot_rrset_t *soa, int knot_changesets_check_size(knot_changesets_t *changesets) { /* Check if allocated is sufficient. */ - if (changesets->count <= changesets->allocated) { + if (changesets->count < changesets->allocated) { return KNOT_EOK; } @@ -243,7 +240,6 @@ int knot_changesets_check_size(knot_changesets_t *changesets) void knot_free_changeset(knot_changeset_t **changeset) { - /* XXX XXX investigate wrong frees. */ assert((*changeset)->add_allocated >= (*changeset)->add_count); assert((*changeset)->remove_allocated >= (*changeset)->remove_count); assert((*changeset)->allocated >= (*changeset)->size); @@ -292,7 +288,3 @@ void knot_free_changesets(knot_changesets_t **changesets) free(*changesets); *changesets = NULL; } - -/*---------------------------------------------------------------------------*/ - - diff --git a/src/libknot/updates/changesets.h b/src/libknot/updates/changesets.h index 0570fc9..642b155 100644..100755 --- a/src/libknot/updates/changesets.h +++ b/src/libknot/updates/changesets.h @@ -5,7 +5,7 @@ * * \brief Structure for representing IXFR/DDNS changeset and its API. * - * \addtogroup libknot + * \addtogroup xfr * @{ */ /* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> @@ -90,9 +90,9 @@ typedef struct { int new_rdata_count; int new_rdata_allocated; -// /*! -// * Deleted (without contents) after successful update. -// */ + /*! + * Deleted (without contents) after successful update. + */ knot_node_t **old_nodes; int old_nodes_count; int old_nodes_allocated; diff --git a/src/libknot/updates/ddns.c b/src/libknot/updates/ddns.c index 025cd6b..905c44b 100644..100755 --- a/src/libknot/updates/ddns.c +++ b/src/libknot/updates/ddns.c @@ -97,7 +97,7 @@ static int knot_ddns_add_prereq_rrset(const knot_rrset_t *rrset, } knot_rrset_t *new_rrset = NULL; - ret = knot_rrset_deep_copy(rrset, &new_rrset); + ret = knot_rrset_deep_copy(rrset, &new_rrset, 0); if (ret != KNOT_EOK) { return ret; } @@ -202,7 +202,7 @@ static int knot_ddns_add_update(knot_changeset_t *changeset, * copy. */ knot_rrset_t *rrset_copy; - ret = knot_rrset_deep_copy(rrset, &rrset_copy); + ret = knot_rrset_deep_copy(rrset, &rrset_copy, 0); if (ret != KNOT_EOK) { return ret; } diff --git a/src/libknot/updates/ddns.h b/src/libknot/updates/ddns.h index dceebed..35dfcb7 100644..100755 --- a/src/libknot/updates/ddns.h +++ b/src/libknot/updates/ddns.h @@ -5,7 +5,7 @@ * * \brief Dynamic updates processing. * - * \addtogroup query_processing + * \addtogroup ddns * @{ */ /* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> diff --git a/src/libknot/updates/xfr-in.c b/src/libknot/updates/xfr-in.c index ea8178d..c870ece 100644..100755 --- a/src/libknot/updates/xfr-in.c +++ b/src/libknot/updates/xfr-in.c @@ -102,7 +102,7 @@ static int xfrin_create_query(knot_dname_t *qname, uint16_t qtype, if (wire_size > *size) { dbg_xfrin("Not enough space provided for the wire " - "format of the query.\n"); + "format of the query.\n"); knot_packet_free(&pkt); return KNOT_ESPACE; } @@ -112,7 +112,7 @@ static int xfrin_create_query(knot_dname_t *qname, uint16_t qtype, char *name = knot_dname_to_str(xfr->tsig_key->name); dbg_xfrin_detail("Signing XFR query with key (name %s): \n", name); - free(name); + free(name); dbg_xfrin_hex_detail(xfr->tsig_key->secret, xfr->tsig_key->secret_size); @@ -152,9 +152,9 @@ static int xfrin_create_query(knot_dname_t *qname, uint16_t qtype, int xfrin_create_soa_query(knot_dname_t *owner, knot_ns_xfr_t *xfr, size_t *size) { - /*! \todo [TSIG] Should TSIG apply for SOA query too? */ return xfrin_create_query(owner, KNOT_RRTYPE_SOA, - KNOT_CLASS_IN, xfr, size, 0, 0); + KNOT_CLASS_IN, xfr, size, 0, + xfr->tsig_key != NULL); } /*----------------------------------------------------------------------------*/ @@ -164,8 +164,8 @@ int xfrin_transfer_needed(const knot_zone_contents_t *zone, { // first, parse the rest of the packet assert(!knot_packet_is_query(soa_response)); - dbg_xfrin("Response - parsed: %zu, total wire size: %zu\n", - soa_response->parsed, soa_response->size); + dbg_xfrin_verb("Response - parsed: %zu, total wire size: %zu\n", + soa_response->parsed, soa_response->size); int ret; if (soa_response->parsed < soa_response->size) { @@ -199,7 +199,7 @@ dbg_xfrin_exec( dbg_xfrin("Malformed data in SOA of zone %s\n", name); free(name); ); - return KNOT_EMALF; // maybe some other error + return KNOT_EMALF; // maybe some other error } /* @@ -273,8 +273,8 @@ static int xfrin_add_orphan_rrsig(xfrin_orphan_rrsig_t **rrsigs, && knot_rdata_rrsig_type_covered(knot_rrset_rdata( last->rrsig)) == knot_rdata_rrsig_type_covered(knot_rrset_rdata(rr))) { - ret = knot_rrset_merge((void **)&last->rrsig, - (void **)&rr); + ret = knot_rrset_merge_no_dupl((void **)&last->rrsig, + (void **)&rr); if (ret != KNOT_EOK) { return ret; } else { @@ -341,7 +341,7 @@ void xfrin_free_orphan_rrsigs(xfrin_orphan_rrsig_t **rrsigs) } /*----------------------------------------------------------------------------*/ -/*! \note [TSIG] */ + static int xfrin_check_tsig(knot_packet_t *packet, knot_ns_xfr_t *xfr, int tsig_req) { @@ -400,8 +400,8 @@ static int xfrin_check_tsig(knot_packet_t *packet, knot_ns_xfr_t *xfr, } if (ret != KNOT_EOK) { - /*! \note [TSIG] No need to check TSIG error - * here, propagate and check elsewhere.*/ + /* No need to check TSIG error + * here, propagate and check elsewhere.*/ knot_rrset_deep_free(&tsig, 1, 1, 1); return ret; } @@ -425,9 +425,7 @@ static int xfrin_check_tsig(knot_packet_t *packet, knot_ns_xfr_t *xfr, tsig_rdata_time_signed(tsig); - }/* else { // TSIG not required and not there - - }*/ + } } else if (tsig != NULL) { // TSIG where it should not be knot_rrset_deep_free(&tsig, 1, 1, 1); @@ -441,9 +439,7 @@ static int xfrin_check_tsig(knot_packet_t *packet, knot_ns_xfr_t *xfr, /*----------------------------------------------------------------------------*/ -int xfrin_process_axfr_packet(/*const uint8_t *pkt, size_t size, - xfrin_constructed_zone_t **constr*/ - knot_ns_xfr_t *xfr) +int xfrin_process_axfr_packet(knot_ns_xfr_t *xfr) { const uint8_t *pkt = xfr->wire; size_t size = xfr->wire_size; @@ -451,11 +447,10 @@ int xfrin_process_axfr_packet(/*const uint8_t *pkt, size_t size, (xfrin_constructed_zone_t **)(&xfr->data); if (pkt == NULL || constr == NULL) { - dbg_xfrin("Wrong parameters supported.\n"); return KNOT_EBADARG; } - dbg_xfrin("Processing AXFR packet of size %zu.\n", size); + dbg_xfrin_verb("Processing AXFR packet of size %zu.\n", size); // check if the response is OK if (knot_wire_get_rcode(pkt) != KNOT_RCODE_NOERROR) { @@ -473,8 +468,7 @@ int xfrin_process_axfr_packet(/*const uint8_t *pkt, size_t size, int ret = knot_packet_parse_from_wire(packet, pkt, size, 1); if (ret != KNOT_EOK) { - dbg_xfrin("Could not parse packet: %s.\n", - knot_strerror(ret)); + dbg_xfrin("Could not parse packet: %s.\n", knot_strerror(ret)); knot_packet_free(&packet); /*! \todo Cleanup. */ return KNOT_EMALF; @@ -510,18 +504,16 @@ int xfrin_process_axfr_packet(/*const uint8_t *pkt, size_t size, if (*constr == NULL) { // this should be the first packet - /*! \note [TSIG] Packet number for checking TSIG validation. */ + /*! Packet number for checking TSIG validation. */ xfr->packet_nr = 0; -// /*! \note [TSIG] Storing total size of data for TSIG digest. */ -// xfr->tsig_data_size = 0; // create new zone /*! \todo Ensure that the packet is the first one. */ if (knot_rrset_type(rr) != KNOT_RRTYPE_SOA) { dbg_xfrin("No zone created, but the first RR in " - "Answer is not a SOA RR.\n"); + "Answer is not a SOA RR.\n"); knot_packet_free(&packet); - knot_node_free(&node, 0); + knot_node_free(&node); knot_rrset_deep_free(&rr, 1, 1, 1); /*! \todo Cleanup. */ return KNOT_EMALF; @@ -543,7 +535,7 @@ dbg_xfrin_exec( ); /*! \todo Cleanup. */ knot_packet_free(&packet); - knot_node_free(&node, 0); + knot_node_free(&node); knot_rrset_deep_free(&rr, 1, 1, 1); return KNOT_EMALF; } @@ -564,19 +556,20 @@ dbg_xfrin_exec( if (*constr == NULL) { dbg_xfrin("Failed to create new constr. zone.\n"); knot_packet_free(&packet); - knot_node_free(&node, 0); + knot_node_free(&node); knot_rrset_deep_free(&rr, 1, 1, 1); return KNOT_ENOMEM; } memset(*constr, 0, sizeof(xfrin_constructed_zone_t)); - (*constr)->contents = knot_zone_contents_new(node, 0, 1, NULL); -// assert(0); + dbg_xfrin_verb("Creating new zone contents.\n"); + (*constr)->contents = knot_zone_contents_new(node, 0, 1, + xfr->zone); if ((*constr)->contents== NULL) { dbg_xfrin("Failed to create new zone.\n"); knot_packet_free(&packet); - knot_node_free(&node, 0); + knot_node_free(&node); knot_rrset_deep_free(&rr, 1, 1, 1); /*! \todo Cleanup. */ return KNOT_ENOMEM; @@ -588,21 +581,19 @@ dbg_xfrin_exec( assert(zone->apex == node); assert(zone->apex->owner == rr->owner); // add the RRSet to the node - //ret = knot_node_add_rrset(node, rr, 0); ret = knot_zone_contents_add_rrset(zone, rr, &node, KNOT_RRSET_DUPL_MERGE, 1); if (ret < 0) { dbg_xfrin("Failed to add RRSet to zone node: %s.\n", knot_strerror(ret)); knot_packet_free(&packet); - knot_node_free(&node, 0); + knot_node_free(&node); knot_rrset_deep_free(&rr, 1, 1, 1); /*! \todo Cleanup. */ return KNOT_ERROR; } else if (ret > 0) { dbg_xfrin("Merged SOA RRSet.\n"); // merged, free the RRSet - //knot_rrset_deep_free(&rr, 1, 0, 0); knot_rrset_free(&rr); } @@ -613,20 +604,6 @@ dbg_xfrin_exec( ++xfr->packet_nr; } - /*! \note [TSIG] add the packet wire size to the data to be verified by - * TSIG - */ -// if (xfr->tsig_key) { -// dbg_xfrin("Adding packet wire to TSIG data (size till now: %zu," -// " adding: %zu).\n", xfr->tsig_data_size, -// xfr->wire_size); -// assert(KNOT_NS_TSIG_DATA_MAX_SIZE - xfr->tsig_data_size -// >= xfr->wire_size); -// memcpy(xfr->tsig_data + xfr->tsig_data_size, xfr->wire, -// xfr->wire_size); -// xfr->tsig_data_size += xfr->wire_size; -// } - assert(zone != NULL); while (ret == KNOT_EOK && rr != NULL) { @@ -637,9 +614,9 @@ dbg_xfrin_exec( if (node != NULL && knot_dname_compare(rr->owner, node->owner) != 0) { -dbg_xfrin_exec( +dbg_xfrin_exec_detail( char *name = knot_dname_to_str(node->owner); - dbg_xfrin("Node owner: %s\n", name); + dbg_xfrin_detail("Node owner: %s\n", name); free(name); ); if (!in_zone) { @@ -659,16 +636,15 @@ dbg_xfrin_exec( assert(knot_zone_contents_apex((zone)) != NULL); assert(knot_node_rrset(knot_zone_contents_apex((zone)), KNOT_RRTYPE_SOA) != NULL); - dbg_xfrin("Found last SOA, transfer finished.\n"); + dbg_xfrin_verb("Found last SOA, transfer finished.\n"); - dbg_xfrin("Verifying TSIG...\n"); + dbg_xfrin_verb("Verifying TSIG...\n"); /*! \note [TSIG] Now check if there is not a TSIG record * at the end of the packet. */ ret = xfrin_check_tsig(packet, xfr, 1); - dbg_xfrin_detail("xfrin_check_tsig() returned %d\n", - ret); + dbg_xfrin_verb("xfrin_check_tsig() returned %d\n", ret); knot_packet_free(&packet); knot_rrset_deep_free(&rr, 1, 1, 1); @@ -682,8 +658,7 @@ dbg_xfrin_exec( ret = xfrin_process_orphan_rrsigs(zone, (*constr)->rrsigs); if (ret != KNOT_EOK) { - dbg_xfrin("Failed to process orphan " - "RRSIGs\n"); + dbg_xfrin("Failed to process orphan RRSIGs\n"); /*! \todo Cleanup?? */ return ret; } @@ -700,8 +675,8 @@ dbg_xfrin_exec( ret = knot_zone_contents_add_rrsigs(zone, rr, &tmp_rrset, &node, KNOT_RRSET_DUPL_MERGE, 1); if (ret == KNOT_ENONODE || ret == KNOT_ENORRSET) { - dbg_xfrin("No node or RRSet for RRSIGs\n"); - dbg_xfrin("Saving for later insertion.\n"); + dbg_xfrin_verb("No node or RRSet for RRSIGs\n"); + dbg_xfrin_verb("Saving for later insertion.\n"); if (ret == KNOT_ENORRSET) { in_zone = 1; @@ -711,13 +686,13 @@ dbg_xfrin_exec( rr); if (ret > 0) { - dbg_xfrin("Merged RRSIGs.\n"); + dbg_xfrin_detail("Merged RRSIGs.\n"); knot_rrset_free(&rr); } else if (ret != KNOT_EOK) { dbg_xfrin("Failed to save orphan" - " RRSIGs.\n"); + " RRSIGs.\n"); knot_packet_free(&packet); - knot_node_free(&node, 0); // ??? + knot_node_free(&node); // ??? knot_rrset_deep_free(&rr, 1, 1, 1); return ret; } @@ -725,15 +700,15 @@ dbg_xfrin_exec( dbg_xfrin("Failed to add RRSIGs (%s).\n", knot_strerror(ret)); knot_packet_free(&packet); - knot_node_free(&node, 0); // ??? + knot_node_free(&node); // ??? knot_rrset_deep_free(&rr, 1, 1, 1); return KNOT_ERROR; /*! \todo Other error code. */ } else if (ret == 1) { assert(node != NULL); 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); + dbg_xfrin_detail("Found node for the record in " + "zone: %s. Merged.\n", name); free(name); ); in_zone = 1; @@ -741,13 +716,12 @@ dbg_xfrin_exec_verb( } else if (ret == 2) { // should not happen assert(0); -// knot_rrset_deep_free(&rr, 1, 1, 1); } else { assert(node != NULL); dbg_xfrin_exec_verb( char *name = knot_dname_to_str(node->owner); - dbg_xfrin("Found node for the record in " - "zone: %s.\n", name); + dbg_xfrin_detail("Found node for the record in " + "zone: %s.\n", name); free(name); ); in_zone = 1; @@ -760,12 +734,12 @@ dbg_xfrin_exec_verb( continue; } - /*! \note [TSIG] TSIG where it should not be - in Answer section.*/ + /* TSIG where it should not be - in Answer section.*/ if (knot_rrset_type(rr) == KNOT_RRTYPE_TSIG) { // not allowed here - dbg_xfrin(" in Answer section.\n"); + dbg_xfrin("TSIG in Answer section.\n"); knot_packet_free(&packet); - knot_node_free(&node, 0); // ??? + knot_node_free(&node); // ??? knot_rrset_deep_free(&rr, 1, 1, 1); return KNOT_EMALF; } @@ -786,7 +760,7 @@ dbg_xfrin_exec_verb( if (node == NULL && (node = get_node(zone, knot_rrset_owner(rr))) != NULL) { // the node for this RR was found in the zone - dbg_xfrin("Found node for the record in zone.\n"); + dbg_xfrin_detail("Found node for the record in zone\n"); in_zone = 1; } @@ -800,31 +774,30 @@ dbg_xfrin_exec_verb( knot_rrset_deep_free(&rr, 1, 1, 1); return KNOT_ENOMEM; } - dbg_xfrin("Created new node for the record.\n"); + dbg_xfrin_detail("Created new node for the record.\n"); // insert the RRSet to the node - ret = knot_node_add_rrset(node, rr, 1); + ret = knot_node_add_rrset_no_dupl(node, rr); if (ret < 0) { - dbg_xfrin("Failed to add RRSet to node (%s" - ")\n", knot_strerror(ret)); + dbg_xfrin("Failed to add RRSet to node (%s)\n", + knot_strerror(ret)); knot_packet_free(&packet); - knot_node_free(&node, 0); // ??? + knot_node_free(&node); // ??? knot_rrset_deep_free(&rr, 1, 1, 1); return KNOT_ERROR; } else if (ret > 0) { // should not happen, this is new node assert(0); -// knot_rrset_deep_free(&rr, 1, 0, 0); } // insert the node into the zone ret = add_node(zone, node, 1, 0, 1); assert(node != NULL); if (ret != KNOT_EOK) { - dbg_xfrin("Failed to add node to zone (%s)" - ".\n", knot_strerror(ret)); + dbg_xfrin("Failed to add node to zone (%s).\n", + knot_strerror(ret)); knot_packet_free(&packet); - knot_node_free(&node, 0); // ??? + knot_node_free(&node); // ??? knot_rrset_deep_free(&rr, 1, 1, 1); return KNOT_ERROR; } @@ -837,12 +810,11 @@ dbg_xfrin_exec_verb( KNOT_RRSET_DUPL_MERGE, 1); if (ret < 0) { knot_packet_free(&packet); - dbg_xfrin("Failed to add RRSet to zone:" - "%s.\n", knot_strerror(ret)); + dbg_xfrin("Failed to add RRSet to zone :%s.\n", + knot_strerror(ret)); return KNOT_ERROR; } else if (ret > 0) { // merged, free the RRSet -// knot_rrset_deep_free(&rr, 1, 0, 0); knot_rrset_free(&rr); } @@ -858,12 +830,11 @@ dbg_xfrin_exec_verb( if (ret < 0) { // some error in parsing - dbg_xfrin("Could not parse next RR: %s.\n", - knot_strerror(ret)); + dbg_xfrin("Could not parse next RR: %s.\n", knot_strerror(ret)); knot_packet_free(&packet); if (!in_zone) { - knot_node_free(&node, 0); + knot_node_free(&node); } knot_rrset_deep_free(&rr, 1, 1, 1); @@ -878,25 +849,23 @@ dbg_xfrin_exec_verb( assert(node != NULL); ret = knot_zone_contents_add_node(zone, node, 1, 0, 1); if (ret != KNOT_EOK) { - dbg_xfrin("Failed to add last node into zone (%s)" - ".\n", knot_strerror(ret)); + dbg_xfrin("Failed to add last node into zone (%s).\n", + knot_strerror(ret)); knot_packet_free(&packet); - knot_node_free(&node, 0); + knot_node_free(&node); return KNOT_ERROR; /*! \todo Other error */ } } - /*! \note [TSIG] Now check if there is not a TSIG record at the end of - * the packet. - */ + /* Now check if there is not a TSIG record at the end of the packet. */ ret = xfrin_check_tsig(packet, xfr, knot_ns_tsig_required(xfr->packet_nr)); ++xfr->packet_nr; knot_packet_free(&packet); - dbg_xfrin("Processed one AXFR packet successfully.\n"); + dbg_xfrin_verb("Processed one AXFR packet successfully.\n"); - /*! \note [TSIG] TSIG errors are propagated and reported in a standard + /* TSIG errors are propagated and reported in a standard * manner, as we're in response processing, no further error response * should be sent. */ @@ -920,8 +889,7 @@ static int xfrin_parse_first_rr(knot_packet_t **packet, const uint8_t *pkt, int ret = knot_packet_parse_from_wire(*packet, pkt, size, 1); if (ret != KNOT_EOK) { - dbg_xfrin("Could not parse packet: %s.\n", - knot_strerror(ret)); + dbg_xfrin("Could not parse packet: %s.\n", knot_strerror(ret)); knot_packet_free(packet); return KNOT_EMALF; } @@ -986,7 +954,7 @@ int xfrin_process_ixfr_packet(knot_ns_xfr_t *xfr) } if (*chs == NULL) { - dbg_xfrin("Changesets empty, creating new.\n"); + dbg_xfrin_verb("Changesets empty, creating new.\n"); ret = knot_changeset_allocate(chs); if (ret != KNOT_EOK) { @@ -1007,7 +975,7 @@ int xfrin_process_ixfr_packet(knot_ns_xfr_t *xfr) (*chs)->first_soa = rr; state = -1; - dbg_xfrin("First SOA of IXFR saved, state set to -1.\n"); + dbg_xfrin_verb("First SOA of IXFR saved, state set to -1.\n"); // parse the next one ret = knot_packet_parse_next_rr_answer(packet, &rr); @@ -1050,7 +1018,7 @@ int xfrin_process_ixfr_packet(knot_ns_xfr_t *xfr) ret = KNOT_EBADARG; goto cleanup; } - dbg_xfrin("Changesets present.\n"); + dbg_xfrin_detail("Changesets present.\n"); } /* @@ -1090,7 +1058,7 @@ int xfrin_process_ixfr_packet(knot_ns_xfr_t *xfr) * calls to this function. */ if (state != -1) { - dbg_xfrin("State is not -1, deciding...\n"); + dbg_xfrin_detail("State is not -1, deciding...\n"); // there should be at least one started changeset right now if ((*chs)->count <= 0) { knot_rrset_deep_free(&rr, 1, 1, 1); @@ -1108,15 +1076,15 @@ int xfrin_process_ixfr_packet(knot_ns_xfr_t *xfr) } } - dbg_xfrin("State before the loop: %d\n", state); + dbg_xfrin_detail("State before the loop: %d\n", state); /*! \todo This may be implemented with much less IFs! */ while (ret == KNOT_EOK && rr != NULL) { dbg_xfrin_exec_verb( - dbg_xfrin_verb("Next loop, state: %d\n", state); + dbg_xfrin_detail("Next loop, state: %d\n", state); char *name = knot_dname_to_str(knot_rrset_owner(rr)); - dbg_xfrin_verb("Actual RR: %s, type %s.\n", name, + dbg_xfrin_detail("Actual RR: %s, type %s.\n", name, knot_rrtype_to_string(knot_rrset_type(rr))); free(name); ); @@ -1128,7 +1096,7 @@ dbg_xfrin_exec_verb( // is quite weird in fact if (knot_rrset_type(rr) != KNOT_RRTYPE_SOA) { dbg_xfrin("First RR is not a SOA RR!\n"); - dbg_xfrin("RR type: %s\n", + dbg_xfrin_verb("RR type: %s\n", knot_rrtype_to_string(knot_rrset_type(rr))); ret = KNOT_EMALF; knot_rrset_deep_free(&rr, 1, 1, 1); @@ -1222,15 +1190,12 @@ dbg_xfrin_exec_verb( } } break; - // dead code -// default: -// assert(0); } // parse the next RR - dbg_xfrin_verb("Parsing next RR..\n"); + dbg_xfrin_detail("Parsing next RR..\n"); ret = knot_packet_parse_next_rr_answer(packet, &rr); - dbg_xfrin_verb("Returned %d, %p.\n", ret, rr); + dbg_xfrin_detail("Returned %d, %p.\n", ret, rr); } /*! \note Check TSIG, we're at the end of packet. It may not be @@ -1238,7 +1203,7 @@ dbg_xfrin_exec_verb( */ ret = xfrin_check_tsig(packet, xfr, knot_ns_tsig_required(xfr->packet_nr)); - dbg_xfrin_detail("xfrin_check_tsig() returned %d\n", ret); + dbg_xfrin_verb("xfrin_check_tsig() returned %d\n", ret); ++xfr->packet_nr; /*! \note [TSIG] Cleanup and propagate error if TSIG validation fails.*/ @@ -1255,7 +1220,7 @@ cleanup: /* We should go here only if some error occured. */ assert(ret < 0); - dbg_xfrin("Cleanup after processing IXFR/IN packet.\n"); + dbg_xfrin_detail("Cleanup after processing IXFR/IN packet.\n"); knot_free_changesets(chs); knot_packet_free(&packet); xfr->data = 0; @@ -1337,6 +1302,9 @@ static int xfrin_changes_check_rdata(knot_rdata_t ***rdatas, uint **types, } int new_count = (*allocated == 0) ? 2 : *allocated * 2; + while (new_count < count + to_add) { + new_count *= 2; + } /* Allocate new memory block. */ knot_rdata_t **rdatas_new = malloc(new_count * sizeof(knot_rdata_t *)); @@ -1372,36 +1340,21 @@ static int xfrin_changes_check_rdata(knot_rdata_t ***rdatas, uint **types, static void xfrin_changes_add_rdata(knot_rdata_t **rdatas, uint *types, int *count, knot_rdata_t *rdata, uint type) { - dbg_xfrin_detail("Adding RDATA to RDATA list: %p\n", rdata); - if (rdata == NULL) { 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); -// } -// } -//); + // Add all RDATAs from the chain!! - rdatas[*count] = rdata; - types[*count] = type; - ++*count; + knot_rdata_t *r = rdata; + do { + dbg_xfrin_detail("Adding RDATA to RDATA list: %p\n", r); + rdatas[*count] = r; + types[*count] = type; + ++*count; + + r = r->next; + } while (r != NULL && r != rdata); } /*----------------------------------------------------------------------------*/ @@ -1412,7 +1365,6 @@ static void xfrin_zone_contents_free(knot_zone_contents_t **contents) if ((*contents)->table != NULL) { ck_destroy_table(&(*contents)->table, NULL, 0); -// ck_table_free(&(*contents)->table); } // free the zone tree with nodes @@ -1459,10 +1411,9 @@ 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_verb("Copying old RRSet: %p\n", old); + dbg_xfrin_detail("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); + int ret = knot_rrset_deep_copy(old, copy, 0); if (ret != KNOT_EOK) { dbg_xfrin("Failed to create RRSet copy.\n"); return KNOT_ENOMEM; @@ -1479,11 +1430,14 @@ static int xfrin_copy_old_rrset(knot_rrset_t *old, knot_rrset_t **copy, return ret; } + int count = knot_rrset_rdata_rr_count(*copy); + count += knot_rrset_rdata_rr_count((*copy)->rrsigs); + // add the copied RDATA to the list of new RDATA ret = xfrin_changes_check_rdata(&changes->new_rdata, &changes->new_rdata_types, changes->new_rdata_count, - &changes->new_rdata_allocated, 2); + &changes->new_rdata_allocated, count); if (ret != KNOT_EOK) { dbg_xfrin("Failed to add new RRSet to list.\n"); knot_rrset_deep_free(copy, 1, 1, 1); @@ -1492,7 +1446,8 @@ static int xfrin_copy_old_rrset(knot_rrset_t *old, knot_rrset_t **copy, changes->new_rrsets[changes->new_rrsets_count++] = *copy; - dbg_xfrin_verb("Adding RDATA from the RRSet copy to new RDATA list.\n"); + dbg_xfrin_detail("Adding RDATA from the RRSet copy to new RDATA list." + "\n"); xfrin_changes_add_rdata(changes->new_rdata, changes->new_rdata_types, &changes->new_rdata_count, knot_rrset_get_rdata(*copy), @@ -1502,8 +1457,9 @@ static int xfrin_copy_old_rrset(knot_rrset_t *old, knot_rrset_t **copy, assert(old->rrsigs != NULL); changes->new_rrsets[changes->new_rrsets_count++] = (*copy)->rrsigs; - dbg_xfrin_verb("Adding RDATA from RRSIG of the RRSet copy to " - "new RDATA list.\n"); + + dbg_xfrin_detail("Adding RDATA from RRSIG of the RRSet copy to " + "new RDATA list.\n"); xfrin_changes_add_rdata(changes->new_rdata, changes->new_rdata_types, &changes->new_rdata_count, @@ -1520,11 +1476,14 @@ static int xfrin_copy_old_rrset(knot_rrset_t *old, knot_rrset_t **copy, return ret; } + count = knot_rrset_rdata_rr_count(old); + count += knot_rrset_rdata_rr_count(old->rrsigs); + // and old RDATA to the list of old RDATA ret = xfrin_changes_check_rdata(&changes->old_rdata, &changes->old_rdata_types, changes->old_rdata_count, - &changes->old_rdata_allocated, 2); + &changes->old_rdata_allocated, count); if (ret != KNOT_EOK) { dbg_xfrin("Failed to add old RRSet to list.\n"); return ret; @@ -1532,7 +1491,7 @@ static int xfrin_copy_old_rrset(knot_rrset_t *old, knot_rrset_t **copy, changes->old_rrsets[changes->old_rrsets_count++] = old; - dbg_xfrin_verb("Adding RDATA from old RRSet to old RDATA list.\n"); + dbg_xfrin_detail("Adding RDATA from old RRSet to old RDATA list.\n"); xfrin_changes_add_rdata(changes->old_rdata, changes->old_rdata_types, &changes->old_rdata_count, old->rdata, knot_rrset_type(old)); @@ -1541,8 +1500,8 @@ static int xfrin_copy_old_rrset(knot_rrset_t *old, knot_rrset_t **copy, assert(old->rrsigs != NULL); changes->old_rrsets[changes->old_rrsets_count++] = old->rrsigs; - dbg_xfrin_verb("Adding RDATA from RRSIG of the old RRSet to " - "old RDATA list.\n"); + dbg_xfrin_detail("Adding RDATA from RRSIG of the old RRSet to " + "old RDATA list.\n"); xfrin_changes_add_rdata(changes->old_rdata, changes->old_rdata_types, &changes->old_rdata_count, @@ -1558,15 +1517,15 @@ static int xfrin_copy_old_rrset(knot_rrset_t *old, knot_rrset_t **copy, static int xfrin_copy_rrset(knot_node_t *node, knot_rr_type_t type, knot_rrset_t **rrset, knot_changes_t *changes) { -dbg_xfrin_exec_verb( +dbg_xfrin_exec_detail( char *name = knot_dname_to_str(knot_node_owner(node)); - dbg_xfrin_verb("Removing RRSet of type %s from node %s (%p)\n", + dbg_xfrin_detail("Removing RRSet of type %s from node %s (%p)\n", knot_rrtype_to_string(type), name, node); free(name); ); knot_rrset_t *old = knot_node_remove_rrset(node, type); - dbg_xfrin_verb("Removed RRSet: %p\n", old); + dbg_xfrin_detail("Removed RRSet: %p\n", old); dbg_xfrin_detail("Other RRSet of the same type in the node: %p\n", knot_node_rrset(node, type)); @@ -1580,7 +1539,7 @@ dbg_xfrin_exec_verb( return ret; } - dbg_xfrin_verb("Copied old rrset %p to new %p.\n", old, *rrset); + dbg_xfrin_detail("Copied old rrset %p to new %p.\n", old, *rrset); // replace the RRSet in the node copy by the new one ret = knot_node_add_rrset(node, *rrset, 0); @@ -1597,7 +1556,8 @@ dbg_xfrin_exec_verb( static int xfrin_apply_remove_rrsigs(knot_changes_t *changes, const knot_rrset_t *remove, knot_node_t *node, - knot_rrset_t **rrset) + knot_rrset_t **rrset, + knot_rrset_t **rrsigs_old) { assert(changes != NULL); assert(remove != NULL); @@ -1613,37 +1573,35 @@ static int xfrin_apply_remove_rrsigs(knot_changes_t *changes, int copied = 0; - if (!*rrset - || knot_dname_compare(knot_rrset_owner(*rrset), - knot_node_owner(node)) != 0 - || knot_rrset_type(*rrset) != knot_rdata_rrsig_type_covered( - knot_rrset_rdata(remove))) { + if (*rrset + && knot_dname_compare(knot_rrset_owner(*rrset), + knot_node_owner(node)) == 0 + && knot_rrset_type(*rrset) == knot_rdata_rrsig_type_covered( + knot_rrset_rdata(remove))) { + // this RRSet should be the already copied RRSet so we may + // update it right away + /*! \todo Does this case even occur? */ + dbg_xfrin_verb("Using RRSet from previous iteration.\n"); + } else { // find RRSet based on the Type Covered knot_rr_type_t type = knot_rdata_rrsig_type_covered( knot_rrset_rdata(remove)); // copy the rrset - dbg_xfrin_verb("Copying RRSet that carries the RRSIGs.\n"); + dbg_xfrin_detail("Copying RRSet that carries the RRSIGs.\n"); ret = xfrin_copy_rrset(node, type, rrset, changes); if (ret != KNOT_EOK) { dbg_xfrin("Failed to copy rrset from changeset.\n"); return ret; } + dbg_xfrin_detail("Copied RRSet:\n"); + knot_rrset_dump(*rrset, 0); copied = 1; - } else { - // we should have the right RRSIG RRSet in *rrset - assert(knot_rrset_type(*rrset) - == knot_rdata_rrsig_type_covered( - knot_rrset_rdata(remove))); - // this RRSet should be the already copied RRSet so we may - // update it right away - /*! \todo Does this case even occur? */ - dbg_xfrin_verb("Using RRSet from previous iteration.\n"); } - + // get the old rrsigs knot_rrset_t *old = knot_rrset_get_rrsigs(*rrset); - dbg_xfrin_verb("Old RRSIGs from RRSet: %p\n", old); + dbg_xfrin_detail("Old RRSIGs from RRSet: %p\n", old); if (old == NULL) { return 1; } @@ -1651,14 +1609,22 @@ static int xfrin_apply_remove_rrsigs(knot_changes_t *changes, // copy the RRSIGs knot_rrset_t *rrsigs = NULL; if (!copied) { - ret = xfrin_copy_old_rrset(old, &rrsigs, changes); - if (ret != KNOT_EOK) { - return ret; + // check if the stored RRSIGs are not the right ones + if (*rrsigs_old && *rrsigs_old == (*rrset)->rrsigs) { + dbg_xfrin_verb("Using RRSIG from previous iteration\n"); + rrsigs = *rrsigs_old; + } else { + ret = xfrin_copy_old_rrset(old, &rrsigs, changes); + if (ret != KNOT_EOK) { + return ret; + } + dbg_xfrin_detail("Copied RRSIGs: %p\n", rrsigs); + dbg_xfrin_detail("Copied RRSet:\n"); + knot_rrset_dump(rrsigs, 0); } - dbg_xfrin_verb("Copied RRSIGs: %p\n", rrsigs); } else { rrsigs = old; - dbg_xfrin_verb("Using old RRSIGs: %p\n", rrsigs); + dbg_xfrin_detail("Using old RRSIGs: %p\n", rrsigs); } // set the RRSIGs to the new RRSet copy @@ -1667,21 +1633,25 @@ static int xfrin_apply_remove_rrsigs(knot_changes_t *changes, return KNOT_ERROR; } + *rrsigs_old = rrsigs; + // now in '*rrset' we have a copy of the RRSet which holds the RRSIGs // and in 'rrsigs' we have the copy of the RRSIGs knot_rdata_t *rdata = xfrin_remove_rdata(rrsigs, remove); if (rdata == NULL) { dbg_xfrin("Failed to remove RDATA from RRSet: %s.\n", - knot_strerror(ret)); + knot_strerror(ret)); return 1; } + + int count = knot_rdata_count(rdata); // connect the RDATA to the list of old RDATA ret = xfrin_changes_check_rdata(&changes->old_rdata, &changes->old_rdata_types, changes->old_rdata_count, - &changes->old_rdata_allocated, 1); + &changes->old_rdata_allocated, count); if (ret != KNOT_EOK) { return ret; } @@ -1704,7 +1674,7 @@ static int xfrin_apply_remove_rrsigs(knot_changes_t *changes, 1); if (ret != KNOT_EOK) { dbg_xfrin("Failed to add empty RRSet to the " - "list of old RRSets."); + "list of old RRSets."); // delete the RRSet right away knot_rrset_free(&rrsigs); return ret; @@ -1729,7 +1699,7 @@ static int xfrin_apply_remove_rrsigs(knot_changes_t *changes, 1); if (ret != KNOT_EOK) { dbg_xfrin("Failed to add empty RRSet to " - "the list of old RRSets."); + "the list of old RRSets."); // delete the RRSet right away knot_rrset_free(rrset); return ret; @@ -1762,10 +1732,13 @@ static int xfrin_apply_remove_normal(knot_changes_t *changes, // now we have the copy of the node, so lets get the right RRSet // check if we do not already have it - if (!*rrset - || knot_dname_compare(knot_rrset_owner(*rrset), - knot_node_owner(node)) != 0 - || knot_rrset_type(*rrset) != knot_rrset_type(remove)) { + if (*rrset + && knot_dname_compare(knot_rrset_owner(*rrset), + knot_node_owner(node)) == 0 + && knot_rrset_type(*rrset) == knot_rrset_type(remove)) { + /*! \todo Does some other case even occur? */ + dbg_xfrin_verb("Using RRSet from previous loop.\n"); + } else { /*! * \todo This may happen also with already * copied RRSet. In that case it would be @@ -1774,30 +1747,29 @@ static int xfrin_apply_remove_normal(knot_changes_t *changes, */ ret = xfrin_copy_rrset(node, knot_rrset_type(remove), rrset, changes); - dbg_xfrin_detail("Copied RRSet:\n"); - knot_rrset_dump(*rrset, 0); if (ret != KNOT_EOK) { return ret; } - } /*! \todo Does some other case even occur? */ + dbg_xfrin_detail("Copied RRSet:\n"); + knot_rrset_dump(*rrset, 0); + } if (*rrset == NULL) { dbg_xfrin_verb("RRSet not found for RR to be removed.\n"); return 1; } -dbg_xfrin_exec_verb( +dbg_xfrin_exec_detail( 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))); + dbg_xfrin_detail("Updating RRSet with owner %s, type %s\n", name, + knot_rrtype_to_string(knot_rrset_type(*rrset))); free(name); ); - // remove the specified RRs from the RRSet (de facto difference of - // sets) + // remove the specified RRs from the RRSet (de facto difference of sets) knot_rdata_t *rdata = xfrin_remove_rdata(*rrset, remove); if (rdata == NULL) { - dbg_xfrin("Failed to remove RDATA from RRSet\n"); + dbg_xfrin_verb("Failed to remove RDATA from RRSet\n"); // In this case, the RDATA was not found in the RRSet return 1; } @@ -1814,11 +1786,12 @@ dbg_xfrin_exec_detail( } ); + int count = knot_rdata_count(rdata); // connect the RDATA to the list of old RDATA ret = xfrin_changes_check_rdata(&changes->old_rdata, &changes->old_rdata_types, changes->old_rdata_count, - &changes->old_rdata_allocated, 1); + &changes->old_rdata_allocated, count); if (ret != KNOT_EOK) { return ret; } @@ -1859,7 +1832,7 @@ dbg_xfrin_exec_detail( } /*----------------------------------------------------------------------------*/ - +/*! \todo Needs review - RRs may not be merged into RRSets. */ static int xfrin_apply_remove_all_rrsets(knot_changes_t *changes, knot_node_t *node, uint16_t type) { @@ -1918,9 +1891,6 @@ static knot_node_t *xfrin_add_new_node(knot_zone_contents_t *contents, // insert the node into zone structures and create parents if // necessary -// dbg_xfrin("Adding new node to zone. From owner: %s type %s\n", -// knot_dname_to_str(node->owner), -// knot_rrtype_to_string(rrset->type)); if (is_nsec3) { ret = knot_zone_contents_add_nsec3_node(contents, node, 1, 0, 1); @@ -1959,35 +1929,53 @@ static int xfrin_apply_add_normal(knot_changes_t *changes, int ret; - dbg_xfrin_verb("applying rrset:\n"); +dbg_xfrin_exec_detail( + dbg_xfrin_detail("applying rrset:\n"); knot_rrset_dump(add, 0); +); + int copied = 0; /*! \note Reusing RRSet from previous function caused it not to be * removed from the node. * Maybe modification of the code would allow reusing the RRSet * as in apply_add_rrsigs() - the RRSet should not be copied * in such case. */ -// if (!*rrset -// || knot_dname_compare(knot_rrset_owner(*rrset), -// knot_node_owner(node)) != 0 -// || knot_rrset_type(*rrset) -// != knot_rrset_type(add)) { -// dbg_xfrin("Removing rrset!\n"); -// *rrset = knot_node_remove_rrset(node, knot_rrset_type(add)); -// } - - *rrset = knot_node_remove_rrset(node, knot_rrset_type(add)); - - dbg_xfrin_verb("Removed RRSet: \n"); + if (*rrset + && knot_dname_compare(knot_rrset_owner(*rrset), + knot_node_owner(node)) == 0 + && knot_rrset_type(*rrset) == knot_rrset_type(add)) { + dbg_xfrin_verb("Using RRSet from previous iteration.\n"); + } else { + dbg_xfrin_detail("Removing rrset!\n"); + *rrset = knot_node_remove_rrset(node, knot_rrset_type(add)); + + knot_rrset_t *old = *rrset; + + if (*rrset != NULL) { + ret = xfrin_copy_old_rrset(old, rrset, changes); + if (ret != KNOT_EOK) { + return ret; + } + + dbg_xfrin_detail("Copied RRSet: %p\n", *rrset); + dbg_xfrin_detail("Copied RRSet:\n"); + knot_rrset_dump(*rrset, 0); + copied = 1; + } + } + +dbg_xfrin_exec_detail( + dbg_xfrin_detail("Removed RRSet: \n"); knot_rrset_dump(*rrset, 1); +); if (*rrset == NULL) { -dbg_xfrin_exec_verb( +dbg_xfrin_exec_detail( char *name = knot_dname_to_str(add->owner); - dbg_xfrin_verb("RRSet to be added not found in zone.\n"); - dbg_xfrin_verb("owner: %s type: %s\n", name, - knot_rrtype_to_string(add->type)); + dbg_xfrin_detail("RRSet to be added not found in zone.\n"); + dbg_xfrin_detail("owner: %s type: %s\n", name, + knot_rrtype_to_string(add->type)); free(name); ); // add the RRSet from the changeset to the node @@ -2013,25 +2001,12 @@ dbg_xfrin_exec_verb( return 1; // return 1 to indicate the add RRSet was used } - knot_rrset_t *old = *rrset; - -dbg_xfrin_exec_verb( +dbg_xfrin_exec_detail( 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))); + dbg_xfrin_detail("Found RRSet with owner %s, type %s\n", name, + knot_rrtype_to_string(knot_rrset_type(*rrset))); free(name); ); -// knot_rrset_dump(*rrset, 1); - ret = xfrin_copy_old_rrset(old, rrset, changes); - if (ret != KNOT_EOK) { - return ret; - } - - 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), -// knot_rrtype_to_string(knot_rrset_type(*rrset))); // merge the changeset RRSet to the copy /* What if the update fails? @@ -2044,25 +2019,38 @@ dbg_xfrin_exec_verb( * * TODO: add the 'add' rrset to list of old RRSets? */ - 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("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); - ret = knot_rrset_merge((void **)rrset, (void **)&add); + /* In case the RRSet is empty (and only remained there because of the + * RRSIGs) it may happen that the TTL may be different than that of + * the new RRs. Update the TTL according to the first RR. + */ + + if (knot_rrset_rdata(*rrset) == NULL + && knot_rrset_ttl(*rrset) != knot_rrset_ttl(add)) { + knot_rrset_set_ttl(*rrset, knot_rrset_ttl(add)); + } + + ret = knot_rrset_merge_no_dupl((void **)rrset, (void **)&add); if (ret != KNOT_EOK) { - dbg_xfrin("Failed to merge changeset RRSet to copy.\n"); - return KNOT_ERROR; + dbg_xfrin("Failed to merge changeset RRSet.\n"); + return ret; } - dbg_xfrin_verb("Merge returned: %d\n", ret); + dbg_xfrin_detail("Merge returned: %d\n", ret); knot_rrset_dump(*rrset, 1); - ret = knot_node_add_rrset(node, *rrset, 0); - if (ret < 0) { - dbg_xfrin("Failed to add merged RRSet to the node.\n"); - return ret; + if (copied) { + ret = knot_node_add_rrset(node, *rrset, 0); + + if (ret < 0) { + dbg_xfrin("Failed to add merged RRSet to the node.\n"); + return ret; + } } // return 2 so that the add RRSet is removed from @@ -2078,6 +2066,7 @@ static int xfrin_apply_add_rrsig(knot_changes_t *changes, knot_rrset_t *add, knot_node_t *node, knot_rrset_t **rrset, + knot_rrset_t **rrsigs_old, knot_zone_contents_t *contents) { assert(changes != NULL); @@ -2095,8 +2084,8 @@ static int xfrin_apply_add_rrsig(knot_changes_t *changes, 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", - name, typestr); + dbg_xfrin_verb("Adding RRSIG: Owner %s, type covered %s.\n", + name, typestr); free(name); ); @@ -2105,11 +2094,12 @@ dbg_xfrin_exec_verb( /*! \note Here the check is OK, because if we aready have the RRSet, * it's a copied one, so it is OK to modify it right away. */ - if (!*rrset - || knot_dname_compare(knot_rrset_owner(*rrset), - knot_node_owner(node)) != 0 - || knot_rrset_type(*rrset) != knot_rdata_rrsig_type_covered( - knot_rrset_rdata(add))) { + if (*rrset + && knot_dname_compare(knot_rrset_owner(*rrset), + knot_node_owner(node)) == 0 + && knot_rrset_type(*rrset) == type) { + dbg_xfrin_verb("Using RRSet from previous iteration.\n"); + } else { // copy the rrset ret = xfrin_copy_rrset(node, type, rrset, changes); if (ret < 0) { @@ -2118,15 +2108,12 @@ dbg_xfrin_exec_verb( *rrset = NULL; } copied = 1; - } else { - // we should have the right RRSIG RRSet in *rrset - assert(knot_rrset_type(*rrset) == type); - // this RRSet should be the already copied RRSet so we may - // update it right away + dbg_xfrin_detail("Copied RRSet:\n"); + knot_rrset_dump(*rrset, 0); } if (*rrset == NULL) { - dbg_xfrin_verb("RRSet to be added not found in zone.\n"); + dbg_xfrin_detail("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, @@ -2136,7 +2123,7 @@ dbg_xfrin_exec_verb( dbg_xfrin("Failed to create new RRSet for RRSIGs.\n"); return KNOT_ENOMEM; } - dbg_xfrin_verb("Created new RRSet for RRSIG: %p.\n", *rrset); + dbg_xfrin_detail("Created new RRSet for RRSIG: %p.\n", *rrset); // add the RRset to the list of new RRsets ret = xfrin_changes_check_rrsets( @@ -2144,8 +2131,7 @@ dbg_xfrin_exec_verb( &changes->new_rrsets_count, &changes->new_rrsets_allocated, 1); if (ret != KNOT_EOK) { - dbg_xfrin("Failed to add old RRSet to " - "list.\n"); + dbg_xfrin("Failed to add old RRSet to list.\n"); knot_rrset_free(rrset); return ret; } @@ -2163,20 +2149,19 @@ dbg_xfrin_exec_verb( changes->new_rrsets[changes->new_rrsets_count++] = *rrset; } -dbg_xfrin_exec_verb( +dbg_xfrin_exec_detail( 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))); + dbg_xfrin_detail("Found RRSet with owner %s, type %s\n", name, + knot_rrtype_to_string(knot_rrset_type(*rrset))); free(name); ); if (knot_rrset_rrsigs(*rrset) == NULL) { - dbg_xfrin_verb("Adding new RRSIGs to RRSet.\n"); + dbg_xfrin_detail("Adding new RRSIGs to RRSet.\n"); ret = knot_zone_contents_add_rrsigs(contents, add, rrset, &node, KNOT_RRSET_DUPL_SKIP, 1); -// ret = knot_rrset_set_rrsigs(*rrset, add); if (ret < 0) { dbg_xfrin("Failed to add RRSIGs to the RRSet.\n"); return KNOT_ERROR; @@ -2191,20 +2176,30 @@ dbg_xfrin_exec_verb( knot_rrset_t *rrsig; if (!copied) { - ret = xfrin_copy_old_rrset(old, &rrsig, changes); - if (ret != KNOT_EOK) { - return ret; + // check if the stored RRSIGs are not the right ones + if (*rrsigs_old && *rrsigs_old == old) { + dbg_xfrin_verb("Using RRSIG from previous iteration\n"); + rrsig = *rrsigs_old; + } else { + ret = xfrin_copy_old_rrset(old, &rrsig, changes); + if (ret != KNOT_EOK) { + return ret; + } + dbg_xfrin_detail("Copied RRSIGs: %p\n", rrsig); + dbg_xfrin_detail("Copied RRSet:\n"); + knot_rrset_dump(rrsig, 0); } } else { rrsig = old; + dbg_xfrin_verb("Using old RRSIGs: %p\n", rrsig); } // replace the old RRSIGs with the new ones knot_rrset_set_rrsigs(*rrset, rrsig); // merge the changeset RRSet to the copy - dbg_xfrin_verb("Merging RRSIG to the one in the RRSet.\n"); - ret = knot_rrset_merge((void **)&rrsig, (void **)&add); + dbg_xfrin_detail("Merging RRSIG to the one in the RRSet.\n"); + ret = knot_rrset_merge_no_dupl((void **)&rrsig, (void **)&add); if (ret != KNOT_EOK) { dbg_xfrin("Failed to merge changeset RRSIG to copy: %s" ".\n", knot_strerror(ret)); @@ -2232,23 +2227,50 @@ void xfrin_cleanup_successful_update(knot_changes_t **changes) // delete old RDATA for (int i = 0; i < (*changes)->old_rdata_count; ++i) { dbg_xfrin_detail("Deleting old RDATA: %p, type: %s\n", - (*changes)->old_rdata[i], - knot_rrtype_to_string((*changes)->old_rdata_types[i])); + (*changes)->old_rdata[i], + knot_rrtype_to_string((*changes)->old_rdata_types[i])); knot_rdata_dump((*changes)->old_rdata[i], (*changes)->old_rdata_types[i], 0); - knot_rdata_t *rdata = (*changes)->old_rdata[i]; - if (rdata != NULL) { - do { - knot_rdata_t *tmp = rdata->next; - knot_rdata_deep_free(&rdata, - (*changes)->old_rdata_types[i], 1); - rdata = tmp; - } while (rdata != NULL - && rdata != (*changes)->old_rdata[i]); - } + // RDATA are stored separately so do not delete the whole chain + knot_rdata_deep_free(&(*changes)->old_rdata[i], + (*changes)->old_rdata_types[i], 1); +// knot_rdata_t *rdata = (*changes)->old_rdata[i]; +// if (rdata != NULL) { +// do { +// knot_rdata_t *tmp = rdata->next; +// knot_rdata_deep_free(&rdata, +// (*changes)->old_rdata_types[i], 1); +// rdata = tmp; +// } while (rdata != NULL +// && rdata != (*changes)->old_rdata[i]); +// } } + // free the empty nodes + for (int i = 0; i < (*changes)->old_nodes_count; ++i) { +dbg_xfrin_exec_detail( + char *name = knot_dname_to_str( + knot_node_owner((*changes)->old_nodes[i])); + dbg_xfrin_detail("Deleting old empty node: %p, owner: %s\n", + (*changes)->old_nodes[i], name); + free(name); +); + knot_node_free(&(*changes)->old_nodes[i]); + } + + // free empty NSEC3 nodes + for (int i = 0; i < (*changes)->old_nsec3_count; ++i) { +dbg_xfrin_exec_detail( + char *name = knot_dname_to_str( + knot_node_owner((*changes)->old_nsec3[i])); + dbg_xfrin_detail("Deleting old empty node: %p, owner: %s\n", + (*changes)->old_nsec3[i], name); + free(name); +); + knot_node_free(&(*changes)->old_nsec3[i]); + } + // free allocated arrays of nodes and rrsets free((*changes)->new_rrsets); free((*changes)->new_rdata); @@ -2304,13 +2326,21 @@ static void xfrin_switch_node_in_dname_table(knot_dname_t *dname, void *data) { UNUSED(data); - if (knot_dname_node(dname) == NULL) { +dbg_xfrin_exec_detail( + char *name = knot_dname_to_str(dname); + dbg_xfrin_detail("Switching node in dname %s (%p)\n", name, dname->node); + free(name); +); + /* dname is not checked here (for NULL value), which resulted in crash + * on howl recently. However, dname should not be NULL here at all, + * it is a sign of some other error. + */ + + if (dname->node == NULL) { return; } - assert(knot_node_new_node(knot_dname_node(dname)) != NULL); - knot_dname_set_node(dname, knot_node_get_new_node( - knot_dname_get_node(dname))); + knot_dname_update_node(dname); } /*----------------------------------------------------------------------------*/ @@ -2333,10 +2363,10 @@ static int xfrin_switch_nodes(knot_zone_contents_t *contents_copy) xfrin_switch_node_in_hash_table, NULL); assert(ret == 0); - // Traverse also the dname table and change the node pointers in dnames - knot_zone_contents_dname_table_apply(contents_copy, - xfrin_switch_node_in_dname_table, - NULL); +// // Traverse also the dname table and change the node pointers in dnames +// knot_zone_contents_dname_table_apply(contents_copy, +// xfrin_switch_node_in_dname_table, +// NULL); return KNOT_EOK; } @@ -2349,7 +2379,6 @@ static void xfrin_zone_contents_free2(knot_zone_contents_t **contents) if ((*contents)->table != NULL) { ck_destroy_table(&(*contents)->table, NULL, 0); -// ck_table_free(&(*contents)->table); } // free the zone tree, but only the structure @@ -2423,8 +2452,8 @@ void xfrin_rollback_update(knot_zone_contents_t *old_contents, } for (int i = 0; i < (*changes)->new_rdata_count; ++i) { - dbg_xfrin("Freeing %d. RDATA chain: %p\n", i, - (*changes)->new_rdata[i]); + dbg_xfrin_detail("Freeing %d. RDATA: %p\n", i, + (*changes)->new_rdata[i]); /* * In some case, the same RDATA may be stored in @@ -2438,28 +2467,14 @@ void xfrin_rollback_update(knot_zone_contents_t *old_contents, * already deleted, but that may be very time-consuming. */ - // discard the whole chain of RDATA - knot_rdata_t *rdata = (*changes)->new_rdata[i]; - knot_rdata_t *rdata_next = NULL; - - while (rdata != NULL && rdata->next != - (*changes)->new_rdata[i]) { - assert(rdata->next != rdata); - rdata_next = rdata->next; - dbg_xfrin(" Deleting RDATA: %p\n", rdata); - knot_rdata_deep_free(&rdata, - (*changes)->new_rdata_types[i], 1); - rdata = rdata_next; - } - - assert(rdata == NULL - || rdata->next == (*changes)->new_rdata[i]); + /* + * Every RDATA from a chain is stored separately. + * We thus do not follow the RDATA chains and free only + * the first RDATA in each. + */ - dbg_xfrin(" Deleting RDATA: %p\n", rdata); - knot_rdata_deep_free(&rdata, + knot_rdata_deep_free(&(*changes)->new_rdata[i], (*changes)->new_rdata_types[i], 1); - - //(*changes)->new_rdata[i] = NULL; } // free allocated arrays of nodes and rrsets @@ -2481,9 +2496,9 @@ void xfrin_rollback_update(knot_zone_contents_t *old_contents, /*----------------------------------------------------------------------------*/ -static int xfrin_apply_remove2(knot_zone_contents_t *contents, - knot_changeset_t *chset, - knot_changes_t *changes) +static int xfrin_apply_remove(knot_zone_contents_t *contents, + knot_changeset_t *chset, + knot_changes_t *changes) { /* * Iterate over removed RRSets, and remove them from the new nodes @@ -2492,7 +2507,7 @@ static int xfrin_apply_remove2(knot_zone_contents_t *contents, */ int ret = 0; knot_node_t *node = NULL; - knot_rrset_t *rrset = NULL; + knot_rrset_t *rrset = NULL, *rrsigs = NULL; int is_nsec3 = 0; @@ -2501,8 +2516,8 @@ dbg_xfrin_exec_verb( char *name = knot_dname_to_str( knot_rrset_owner(chset->remove[i])); dbg_xfrin_verb("Removing RRSet: %s, type %s\n", name, - knot_rrtype_to_string( - knot_rrset_type(chset->remove[i]))); + knot_rrtype_to_string( + knot_rrset_type(chset->remove[i]))); free(name); ); dbg_xfrin_exec_detail( @@ -2551,7 +2566,7 @@ dbg_xfrin_exec_detail( // this should work also for UPDATE ret = xfrin_apply_remove_rrsigs(changes, chset->remove[i], - node, &rrset); + node, &rrset, &rrsigs); } else { // this should work also for UPDATE ret = xfrin_apply_remove_normal(changes, @@ -2559,7 +2574,7 @@ dbg_xfrin_exec_detail( node, &rrset); } - dbg_xfrin_verb("xfrin_apply_remove() ret = %d\n", ret); + dbg_xfrin_detail("xfrin_apply_remove() ret = %d\n", ret); if (ret > 0) { continue; @@ -2573,13 +2588,14 @@ dbg_xfrin_exec_detail( /*----------------------------------------------------------------------------*/ -static int xfrin_apply_add2(knot_zone_contents_t *contents, - knot_changeset_t *chset, - knot_changes_t *changes) +static int xfrin_apply_add(knot_zone_contents_t *contents, + knot_changeset_t *chset, + knot_changes_t *changes) { int ret = 0; knot_node_t *node = NULL; knot_rrset_t *rrset = NULL; + knot_rrset_t *rrsigs = NULL; int is_nsec3 = 0; @@ -2588,8 +2604,8 @@ dbg_xfrin_exec_verb( char *name = knot_dname_to_str( knot_rrset_owner(chset->add[i])); dbg_xfrin_verb("Adding RRSet: %s, type: %s\n", name, - knot_rrtype_to_string( - knot_rrset_type(chset->add[i]))); + knot_rrtype_to_string( + knot_rrset_type(chset->add[i]))); free(name); ); dbg_xfrin_exec_detail( @@ -2605,14 +2621,14 @@ dbg_xfrin_exec_detail( knot_rrset_rdata(chset->add[i])) == KNOT_RRTYPE_NSEC3)) { - dbg_xfrin_verb("This is NSEC3-related RRSet.\n"); + dbg_xfrin_detail("This is NSEC3-related RRSet.\n"); is_nsec3 = 1; } // check if the old node is not the one we should use if (!node || knot_rrset_owner(chset->add[i]) != knot_node_owner(node)) { - dbg_xfrin_verb("Searching for node...\n"); + dbg_xfrin_detail("Searching for node...\n"); if (is_nsec3) { node = knot_zone_contents_get_nsec3_node( contents, @@ -2624,7 +2640,8 @@ dbg_xfrin_exec_detail( if (node == NULL) { // create new node, connect it properly to the // zone nodes - dbg_xfrin_verb("Node not found. Creating new.\n"); + dbg_xfrin_detail("Node not found. Creating new." + "\n"); node = xfrin_add_new_node(contents, chset->add[i], is_nsec3); @@ -2640,7 +2657,8 @@ dbg_xfrin_exec_detail( if (knot_rrset_type(chset->add[i]) == KNOT_RRTYPE_RRSIG) { ret = xfrin_apply_add_rrsig(changes, chset->add[i], - node, &rrset, contents); + node, &rrset, &rrsigs, + contents); } else { ret = xfrin_apply_add_normal(changes, chset->add[i], node, &rrset, contents); @@ -2648,8 +2666,8 @@ dbg_xfrin_exec_detail( assert(ret != KNOT_EOK); - dbg_xfrin_verb("xfrin_apply_..() returned %d, rrset: %p\n", ret, - rrset); + dbg_xfrin_detail("xfrin_apply_..() returned %s, rrset: %p\n", + knot_strerror(ret), rrset); if (ret > 0) { if (ret == 1) { @@ -2670,21 +2688,24 @@ dbg_xfrin_exec_detail( = chset->add[i]; // the same goes for the RDATA + int count = knot_rrset_rdata_rr_count( + chset->add[i]); // connect the RDATA to the list of new RDATA - int res = xfrin_changes_check_rdata(&changes->new_rdata, + int res = xfrin_changes_check_rdata( + &changes->new_rdata, &changes->new_rdata_types, changes->new_rdata_count, - &changes->new_rdata_allocated, 1); + &changes->new_rdata_allocated, count); if (res != KNOT_EOK) { return res; } xfrin_changes_add_rdata(changes->new_rdata, - changes->new_rdata_types, - &changes->new_rdata_count, - knot_rrset_get_rdata(chset->add[i]), - knot_rrset_type(chset->add[i])); + changes->new_rdata_types, + &changes->new_rdata_count, + knot_rrset_get_rdata(chset->add[i]), + knot_rrset_type(chset->add[i])); chset->add[i] = NULL; } else if (ret == 2) { @@ -2712,9 +2733,9 @@ dbg_xfrin_exec_detail( /*----------------------------------------------------------------------------*/ -static int xfrin_apply_replace_soa2(knot_zone_contents_t *contents, - knot_changes_t *changes, - knot_changeset_t *chset) +static int xfrin_apply_replace_soa(knot_zone_contents_t *contents, + knot_changes_t *changes, + knot_changeset_t *chset) { dbg_xfrin("Replacing SOA record.\n"); knot_node_t *node = knot_zone_contents_get_apex(contents); @@ -2762,11 +2783,13 @@ static int xfrin_apply_replace_soa2(knot_zone_contents_t *contents, return ret; } + int count = knot_rrset_rdata_rr_count(rrset); + count += knot_rrset_rdata_rr_count(chset->soa_to); // save the new SOA RDATA ret = xfrin_changes_check_rdata(&changes->new_rdata, &changes->new_rdata_types, changes->new_rdata_count, - &changes->new_rdata_allocated, 1); + &changes->new_rdata_allocated, count); if (ret != KNOT_EOK) { dbg_xfrin("Failed to add new RDATA to list.\n"); return ret; @@ -2813,9 +2836,9 @@ static int xfrin_apply_replace_soa2(knot_zone_contents_t *contents, /*----------------------------------------------------------------------------*/ -static int xfrin_apply_changeset2(knot_zone_contents_t *contents, - knot_changes_t *changes, - knot_changeset_t *chset) +static int xfrin_apply_changeset(knot_zone_contents_t *contents, + knot_changes_t *changes, + knot_changeset_t *chset) { /* * Applies one changeset to the zone. Checks if the changeset may be @@ -2836,19 +2859,17 @@ static int xfrin_apply_changeset2(knot_zone_contents_t *contents, return KNOT_ERROR; } - int ret = xfrin_apply_remove2(contents, chset, changes); + int ret = xfrin_apply_remove(contents, chset, changes); if (ret != KNOT_EOK) { -// xfrin_clean_changes_after_fail2(changes); return ret; } - ret = xfrin_apply_add2(contents, chset, changes); + ret = xfrin_apply_add(contents, chset, changes); if (ret != KNOT_EOK) { -// xfrin_clean_changes_after_fail(changes); return ret; } - return xfrin_apply_replace_soa2(contents, changes, chset); + return xfrin_apply_replace_soa(contents, changes, chset); } /*----------------------------------------------------------------------------*/ @@ -2871,6 +2892,8 @@ static void xfrin_mark_empty(knot_node_t *node, void *data) } changes->old_nodes[changes->old_nodes_count++] = node; + // mark the node as empty + knot_node_set_empty(node); if (node->parent != NULL) { assert(node->parent->children > 0); @@ -2903,6 +2926,8 @@ static void xfrin_mark_empty_nsec3(knot_node_t *node, void *data) } changes->old_nsec3[changes->old_nsec3_count++] = node; + // mark the node as empty + knot_node_set_empty(node); if (node->parent != NULL) { assert(node->parent->children > 0); @@ -2950,11 +2975,13 @@ static int xfrin_remove_empty_nodes(knot_zone_contents_t *contents, zone_node = NULL; hash_item = NULL; +dbg_xfrin_exec_detail( char *name = knot_dname_to_str(knot_node_owner( changes->old_nodes[i])); dbg_xfrin_detail("Old node #%d: %p, %s\n", i, changes->old_nodes[i], name); free(name); +); ret = knot_zone_contents_remove_node( contents, changes->old_nodes[i], &zone_node, @@ -2967,9 +2994,7 @@ static int xfrin_remove_empty_nodes(knot_zone_contents_t *contents, free(hash_item); free(zone_node); - knot_node_free(&changes->old_nodes[i], 0); } - changes->old_nodes_count = 0; // remove NSEC3 nodes for (int i = 0; i < changes->old_nsec3_count; ++i) { @@ -2990,9 +3015,7 @@ static int xfrin_remove_empty_nodes(knot_zone_contents_t *contents, } free(zone_node); - knot_node_free(&changes->old_nsec3[i], 0); } - changes->old_nsec3_count = 0; return KNOT_EOK; } @@ -3060,9 +3083,6 @@ int xfrin_apply_changesets(knot_zone_t *zone, dbg_xfrin("Applying changesets to zone...\n"); -// dbg_xfrin("\nOLD ZONE CONTENTS:\n\n"); -// knot_zone_contents_dump(old_contents, 1); - /* * Ensure that the zone generation is set to 0. */ @@ -3130,7 +3150,7 @@ int xfrin_apply_changesets(knot_zone_t *zone, dbg_xfrin_verb("Old contents apex: %p, new apex: %p\n", old_contents->apex, contents_copy->apex); for (int i = 0; i < chsets->count; ++i) { - if ((ret = xfrin_apply_changeset2(contents_copy, changes, + if ((ret = xfrin_apply_changeset(contents_copy, changes, &chsets->sets[i])) != KNOT_EOK) { xfrin_rollback_update(old_contents, @@ -3155,7 +3175,8 @@ int xfrin_apply_changesets(knot_zone_t *zone, */ /* - * Select and delete empty nodes. + * Select and remove empty nodes from zone trees. Do not free them right + * away as they may be referenced by some domain names. */ ret = xfrin_remove_empty_nodes(contents_copy, changes); if (ret != KNOT_EOK) { @@ -3165,11 +3186,9 @@ int xfrin_apply_changesets(knot_zone_t *zone, return ret; } - dbg_xfrin("Adjusting zone contents.\n"); dbg_xfrin_verb("Old contents apex: %p, new apex: %p\n", old_contents->apex, contents_copy->apex); -// ret = xfrin_adjust_contents(contents_copy, &changes); ret = knot_zone_contents_adjust(contents_copy); if (ret != KNOT_EOK) { dbg_xfrin("Failed to finalize zone contents: %s\n", @@ -3187,7 +3206,6 @@ int xfrin_apply_changesets(knot_zone_t *zone, return ret; } - //xfrin_cleanup_update(&changes); chsets->changes = changes; *new_contents = contents_copy; @@ -3215,6 +3233,20 @@ int xfrin_switch_zone(knot_zone_t *zone, dbg_xfrin_verb("Old contents: %p, apex: %p, new apex: %p\n", old, (old) ? old->apex : NULL, new_contents->apex); + // switch pointers in domain names, now only the new zone is used + if (transfer_type == XFR_TYPE_IIN) { + // Traverse also the dname table and change the node pointers + // in dnames + int ret = knot_zone_contents_dname_table_apply( + new_contents, + xfrin_switch_node_in_dname_table, NULL); + assert(ret == KNOT_EOK); + } + + // set generation to old, so that the flags may be used in next transfer + // and we do not search for new nodes anymore + knot_zone_contents_set_gen_old(new_contents); + // wait for readers to finish dbg_xfrin_verb("Waiting for readers to finish...\n"); synchronize_rcu(); diff --git a/src/libknot/updates/xfr-in.h b/src/libknot/updates/xfr-in.h index b009152..a762b81 100644..100755 --- a/src/libknot/updates/xfr-in.h +++ b/src/libknot/updates/xfr-in.h @@ -5,7 +5,7 @@ * * \brief XFR client API. * - * \addtogroup query_processing + * \addtogroup xfr * @{ */ /* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> @@ -189,9 +189,6 @@ int xfrin_switch_zone(knot_zone_t *zone, knot_zone_contents_t *new_contents, int deep_free); -//void xfrin_cleanup_failed_update(knot_zone_contents_t *old_contents, -// knot_zone_contents_t **new_contents); - void xfrin_cleanup_successful_update(knot_changes_t **changes); void xfrin_rollback_update(knot_zone_contents_t *old_contents, diff --git a/src/libknot/util/conv.c b/src/libknot/util/conv.c deleted file mode 100644 index 6626ddd..0000000 --- a/src/libknot/util/conv.c +++ /dev/null @@ -1,325 +0,0 @@ -/* - * Copyright (c) 2001-2011, NLnet Labs. All rights reserved. - * - * This software is open source. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of the NLNET LABS nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <stdlib.h> -#include <stdint.h> -#include <ctype.h> -#include "conv.h" - -#define B64BUFSIZE 65535 /*!< Buffer size for b64 conversion. */ - - -static const char Base64[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -static const char Pad64 = '='; - -static int b64rmap_initialized = 0; -static uint8_t b64rmap[256]; - -static const uint8_t b64rmap_special = 0xf0; -static const uint8_t b64rmap_end = 0xfd; -static const uint8_t b64rmap_space = 0xfe; -static const uint8_t b64rmap_invalid = 0xff; - -/** - * Initializing the reverse map is not thread safe. - * Which is fine for NSD. For now... - **/ -static void b64_initialize_rmap() -{ - int i; - char ch; - - /* Null: end of string, stop parsing */ - b64rmap[0] = b64rmap_end; - - for (i = 1; i < 256; ++i) { - ch = (char)i; - /* Whitespaces */ - if (isspace(ch)) { - b64rmap[i] = b64rmap_space; - } - /* Padding: stop parsing */ - else if (ch == Pad64) { - b64rmap[i] = b64rmap_end; - } - /* Non-base64 char */ - else { - b64rmap[i] = b64rmap_invalid; - } - } - - /* Fill reverse mapping for base64 chars */ - for (i = 0; Base64[i] != '\0'; ++i) { - b64rmap[(uint8_t)Base64[i]] = i; - } - - b64rmap_initialized = 1; -} - -static int b64_pton_do(char const *src, uint8_t *target, size_t targsize) -{ - int tarindex, state, ch; - uint8_t ofs; - - state = 0; - tarindex = 0; - - while (1) { - ch = *src++; - ofs = b64rmap[ch]; - - if (ofs >= b64rmap_special) { - /* Ignore whitespaces */ - if (ofs == b64rmap_space) { - continue; - } - /* End of base64 characters */ - if (ofs == b64rmap_end) { - break; - } - /* A non-base64 character. */ - return (-1); - } - - switch (state) { - case 0: - if ((size_t)tarindex >= targsize) { - return (-1); - } - target[tarindex] = ofs << 2; - state = 1; - break; - case 1: - if ((size_t)tarindex + 1 >= targsize) { - return (-1); - } - target[tarindex] |= ofs >> 4; - target[tarindex+1] = (ofs & 0x0f) - << 4 ; - tarindex++; - state = 2; - break; - case 2: - if ((size_t)tarindex + 1 >= targsize) { - return (-1); - } - target[tarindex] |= ofs >> 2; - target[tarindex+1] = (ofs & 0x03) - << 6; - tarindex++; - state = 3; - break; - case 3: - if ((size_t)tarindex >= targsize) { - return (-1); - } - target[tarindex] |= ofs; - tarindex++; - state = 0; - break; - default: - abort(); - } - } - - /* - * We are done decoding Base-64 chars. Let's see if we ended - * on a byte boundary, and/or with erroneous trailing characters. - */ - - if (ch == Pad64) { /* We got a pad char. */ - ch = *src++; /* Skip it, get next. */ - switch (state) { - case 0: /* Invalid = in first position */ - case 1: /* Invalid = in second position */ - return (-1); - - case 2: /* Valid, means one byte of info */ - /* Skip any number of spaces. */ - for ((void)NULL; ch != '\0'; ch = *src++) - if (b64rmap[ch] != b64rmap_space) { - break; - } - /* Make sure there is another trailing = sign. */ - if (ch != Pad64) { - return (-1); - } - ch = *src++; /* Skip the = */ - /* Fall through to "single trailing =" case. */ - /* FALLTHROUGH */ - - case 3: /* Valid, means two bytes of info */ - /* - * We know this char is an =. Is there anything but - * whitespace after it? - */ - for ((void)NULL; ch != '\0'; ch = *src++) - if (b64rmap[ch] != b64rmap_space) { - return (-1); - } - - /* - * Now make sure for cases 2 and 3 that the "extra" - * bits that slopped past the last full byte were - * zeros. If we don't check them, they become a - * subliminal channel. - */ - if (target[tarindex] != 0) { - return (-1); - } - } - } else { - /* - * We ended by seeing the end of the string. Make sure we - * have no partial bytes lying around. - */ - if (state != 0) { - return (-1); - } - } - - return (tarindex); -} - - -static int b64_pton_len(char const *src) -{ - int tarindex, state, ch; - uint8_t ofs; - - state = 0; - tarindex = 0; - - while (1) { - ch = *src++; - ofs = b64rmap[ch]; - - if (ofs >= b64rmap_special) { - /* Ignore whitespaces */ - if (ofs == b64rmap_space) { - continue; - } - /* End of base64 characters */ - if (ofs == b64rmap_end) { - break; - } - /* A non-base64 character. */ - return (-1); - } - - switch (state) { - case 0: - state = 1; - break; - case 1: - tarindex++; - state = 2; - break; - case 2: - tarindex++; - state = 3; - break; - case 3: - tarindex++; - state = 0; - break; - default: - abort(); - } - } - - /* - * We are done decoding Base-64 chars. Let's see if we ended - * on a byte boundary, and/or with erroneous trailing characters. - */ - - if (ch == Pad64) { /* We got a pad char. */ - ch = *src++; /* Skip it, get next. */ - switch (state) { - case 0: /* Invalid = in first position */ - case 1: /* Invalid = in second position */ - return (-1); - - case 2: /* Valid, means one byte of info */ - /* Skip any number of spaces. */ - for ((void)NULL; ch != '\0'; ch = *src++) - if (b64rmap[ch] != b64rmap_space) { - break; - } - /* Make sure there is another trailing = sign. */ - if (ch != Pad64) { - return (-1); - } - ch = *src++; /* Skip the = */ - /* Fall through to "single trailing =" case. */ - /* FALLTHROUGH */ - - case 3: /* Valid, means two bytes of info */ - /* - * We know this char is an =. Is there anything but - * whitespace after it? - */ - for ((void)NULL; ch != '\0'; ch = *src++) - if (b64rmap[ch] != b64rmap_space) { - return (-1); - } - - } - } else { - /* - * We ended by seeing the end of the string. Make sure we - * have no partial bytes lying around. - */ - if (state != 0) { - return (-1); - } - } - - return (tarindex); -} - -int b64_pton(char const *src, uint8_t *target, size_t targsize) -{ - if (!b64rmap_initialized) { - b64_initialize_rmap(); - } - - if (target) { - return b64_pton_do(src, target, targsize); - } else { - return b64_pton_len(src); - } -} - -#define B64BUFSIZE 65535 /*!< Buffer size for b64 conversion. */ diff --git a/src/libknot/util/conv.h b/src/libknot/util/conv.h deleted file mode 100644 index d1e6dae..0000000 --- a/src/libknot/util/conv.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2001-2011, NLnet Labs. All rights reserved. - * - * This software is open source. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of the NLNET LABS nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _KNOT_CONV_H_ -#define _KNOT_CONV_H_ - -#define B64BUFSIZE 65535 /*!< Buffer size for b64 conversion. */ - -/*! - * \brief Base64 presentation to wire conversion. - */ -int b64_pton(char const *src, uint8_t *target, size_t targsize); - -#endif // _KNOT_CONV_H_ diff --git a/src/libknot/util/debug.c b/src/libknot/util/debug.c index f14c3cd..a6555ad 100644..100755 --- a/src/libknot/util/debug.c +++ b/src/libknot/util/debug.c @@ -105,7 +105,6 @@ void knot_rrset_dump(const knot_rrset_t *rrset, char loaded_zone) return; } - fprintf(stderr, " rdata count: %d\n", rrset->rdata->count); knot_rdata_t *tmp = rrset->rdata; while (tmp->next != rrset->rdata && tmp->next != NULL) { @@ -133,11 +132,6 @@ void knot_node_dump(knot_node_t *node, void *loaded_zone) hex_print((char *)node->owner->labels, node->owner->label_count); fprintf(stderr, "node: %p\n", node); fprintf(stderr, "node (in node's owner): %p\n", node->owner->node); - if (loaded_zone && node->prev != NULL) { - name = knot_dname_to_str(node->prev->owner); - fprintf(stderr, "previous node: %s\n", name); - free(name); - } if (knot_node_is_deleg_point(node)) { fprintf(stderr, "delegation point\n"); @@ -197,6 +191,8 @@ void knot_node_dump(knot_node_t *node, void *loaded_zone) } else { fprintf(stderr, "none\n"); } + + fprintf(stderr, "Zone: %p\n", node->zone); fprintf(stderr, "RRSet count: %d\n", node->rrset_count); diff --git a/src/libknot/util/debug.h b/src/libknot/util/debug.h index b6aba6e..731fed8 100644..100755 --- a/src/libknot/util/debug.h +++ b/src/libknot/util/debug.h @@ -42,6 +42,7 @@ #define KNOT_ZONE_DEBUG #define KNOT_ZONEDB_DEBUG #define KNOT_NODE_DEBUG + #define KNOT_ZONEDIFF_DEBUG #endif #ifdef KNOT_NS_DEBUG @@ -368,6 +369,48 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); #define dbg_zonedb_exec_detail(cmds) #endif +#ifdef KNOT_ZONEDIFF_DEBUG + +/* Brief messages. */ +#ifdef DEBUG_ENABLE_BRIEF +#define dbg_zonediff(msg...) fprintf(stderr, msg) +#define dbg_zonediff_hex(data, len) hex_print((data), (len)) +#else +#define dbg_zonediff(msg...) +#define dbg_zonediff_hex(data, len) +#endif + +/* Verbose messages. */ +#ifdef DEBUG_ENABLE_VERBOSE +#define dbg_zonediff_verb(msg...) fprintf(stderr, msg) +#define dbg_zonediff_hex_verb(data, len) hex_print((data), (len)) +#else +#define dbg_zonediff_verb(msg...) +#define dbg_zonediff_hex_verb(data, len) +#endif + +/* Detail messages. */ +#ifdef DEBUG_ENABLE_DETAILS +#define dbg_zonediff_detail(msg...) fprintf(stderr, msg) +#define dbg_zonediff_hex_detail(data, len) hex_print((data), (len)) +#define dbg_zonediff_exec_detail(cmds) do { cmds } while (0) +#else +#define dbg_zonediff_detail(msg...) +#define dbg_zonediff_hex_detail(data, len) +#define dbg_zonediff_exec_detail(cmds) +#endif + +/* No messages. */ +#else +#define dbg_zonediff(msg...) +#define dbg_zonediff_hex(data, len) +#define dbg_zonediff_verb(msg...) +#define dbg_zonediff_hex_verb(data, len) +#define dbg_zonediff_detail(msg...) +#define dbg_zonediff_hex_detail(data, len) +#define dbg_zonediff_exec_detail(cmds) +#endif + /******************************************************************************/ #ifdef KNOT_RESPONSE_DEBUG @@ -607,7 +650,6 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Brief messages. */ #ifdef DEBUG_ENABLE_BRIEF #define dbg_ck_hash(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) -#define dbg_ck_rehash(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) #define dbg_ck_hash_hex(data, len) hex_log(LOG_SERVER, (data), (len)) #else #define dbg_ck_hash(msg...) @@ -636,7 +678,6 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* No messages. */ #else #define dbg_ck_hash(msg...) -#define dbg_ck_rehash(msg...) #define dbg_ck_hash_hex(data, len) #define dbg_ck_hash_verb(msg...) #define dbg_ck_hash_hex_verb(data, len) @@ -646,6 +687,21 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /******************************************************************************/ +#ifdef KNOT_STASH_DEBUG + +#ifdef DEBUG_ENABLE_BRIEF +#define dbg_stash(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) +#else +#define dbg_stash(msg...) +#endif + +#else +#define dbg_stash(msg...) +#endif + + +/******************************************************************************/ + #ifdef KNOT_XFRIN_DEBUG /* Brief messages. */ @@ -780,37 +836,46 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); #ifdef DEBUG_ENABLE_BRIEF #define dbg_rrset(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) #define dbg_rrset_hex(data, len) hex_log(LOG_ZONE, (data), (len)) +#define dbg_rrset_exec(cmds) do { cmds } while (0) #else #define dbg_rrset(msg...) #define dbg_rrset_hex(data, len) +#define dbg_rrset_exec(cmds) #endif /* Verbose messages. */ #ifdef DEBUG_ENABLE_VERBOSE #define dbg_rrset_verb(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) #define dbg_rrset_hex_verb(data, len) hex_log(LOG_ZONE, (data), (len)) +#define dbg_rrset_exec_verb(cmds) do { cmds } while (0) #else #define dbg_rrset_verb(msg...) #define dbg_rrset_hex_verb(data, len) +#define dbg_rrset_exec_verb(cmds) #endif /* Detail messages. */ #ifdef DEBUG_ENABLE_DETAILS #define dbg_rrset_detail(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) #define dbg_rrset_hex_detail(data, len) hex_log(LOG_ZONE, (data), (len)) +#define dbg_rrset_exec_detail(cmds) do { cmds } while (0) #else #define dbg_rrset_detail(msg...) #define dbg_rrset_hex_detail(data, len) +#define dbg_rrset_exec_detail(cmds) #endif /* No messages. */ #else #define dbg_rrset(msg...) #define dbg_rrset_hex(data, len) +#define dbg_rrset_exec(cmds) #define dbg_rrset_verb(msg...) #define dbg_rrset_hex_verb(data, len) +#define dbg_rrset_exec_verb(cmds) #define dbg_rrset_detail(msg...) #define dbg_rrset_hex_detail(data, len) +#define dbg_rrset_exec_detail(cmds) #endif /******************************************************************************/ diff --git a/src/libknot/util/descriptor.c b/src/libknot/util/descriptor.c index 63e1747..35ae77e 100644..100755 --- a/src/libknot/util/descriptor.c +++ b/src/libknot/util/descriptor.c @@ -569,3 +569,5 @@ int knot_rrtype_is_metatype(uint16_t type) || type == KNOT_RRTYPE_OPT); } +/*! @} */ + diff --git a/src/libknot/util/descriptor.h b/src/libknot/util/descriptor.h index b7e4a53..b7e4a53 100644..100755 --- a/src/libknot/util/descriptor.h +++ b/src/libknot/util/descriptor.h diff --git a/src/libknot/util/error.h b/src/libknot/util/error.h index 888669a..96eff68 100644..100755 --- a/src/libknot/util/error.h +++ b/src/libknot/util/error.h @@ -52,6 +52,7 @@ enum knot_error { KNOT_EACCES, /*!< Permission is denied. */ KNOT_ECRYPTO, /*!< Error in crypto library. */ KNOT_ENSEC3PAR, /*!< Missing or wrong NSEC3PARAM record. */ + KNOT_ENSEC3CHAIN, /*!< Missing or wrong NSEC3 chain in the zone. */ KNOT_EBADZONE, /*!< Domain name does not belong to the zone. */ KNOT_EHASH, /*!< Error in hash table. */ KNOT_EZONEIN, /*!< Error inserting zone. */ @@ -65,10 +66,12 @@ enum knot_error { KNOT_ENOXFR, /*!< Transfer was not sent. */ KNOT_ENOIXFR, /*!< Transfer is not IXFR (is in AXFR format). */ KNOT_EXFRREFUSED, /*!< Zone transfer refused by the server. */ + KNOT_EXFRDENIED, /*!< Transfer not allowed. */ KNOT_ECONN, /*!< Connection reset. */ KNOT_EIXFRSPACE, /*!< IXFR reply did not fit in. */ KNOT_ECNAME, /*!< CNAME loop found in zone. */ - KNOT_ERROR_COUNT = 34 + KNOT_ENODIFF, /*!< No zone diff can be created. */ + KNOT_ERROR_COUNT = 37 }; /*! \brief Table linking error messages to error codes. */ diff --git a/src/libknot/util/libknot_error.c b/src/libknot/util/libknot_error.c index f787565..dd4280d 100644..100755 --- a/src/libknot/util/libknot_error.c +++ b/src/libknot/util/libknot_error.c @@ -24,7 +24,7 @@ const error_table_t knot_error_msgs[KNOT_ERROR_COUNT] = { {KNOT_ENOTSUP, "Operation not supported."}, {KNOT_EAGAIN, "OS lacked necessary resources."}, {KNOT_ERANGE, "Value is out of range."}, - {KNOT_EBADARG, "Wrong argument supported."}, + {KNOT_EBADARG, "Wrong argument supplied."}, {KNOT_EFEWDATA, "Not enough data to parse."}, {KNOT_ESPACE, "Not enough space provided."}, {KNOT_EMALF, "Malformed data."}, @@ -32,6 +32,7 @@ const error_table_t knot_error_msgs[KNOT_ERROR_COUNT] = { {KNOT_EACCES, "Permission to perform requested operation is denied."}, {KNOT_ECRYPTO, "Error in crypto library."}, {KNOT_ENSEC3PAR, "Missing or wrong NSEC3PARAM record."}, + {KNOT_ENSEC3CHAIN, "Missing or wrong NSEC3 chain in the zone."}, {KNOT_EBADZONE, "Domain name does not belong to the given zone."}, {KNOT_EHASH, "Error in hash table."}, {KNOT_EZONEIN, "Error inserting zone."}, @@ -45,11 +46,13 @@ const error_table_t knot_error_msgs[KNOT_ERROR_COUNT] = { {KNOT_ENOXFR, "Transfer was not sent."}, {KNOT_ENOIXFR, "Transfer is not IXFR (is in AXFR format)."}, {KNOT_EXFRREFUSED, "Zone transfer refused by the server."}, + {KNOT_EXFRDENIED, "Transfer not allowed."}, {KNOT_TSIG_EBADSIG, "Failed to verify TSIG MAC." }, {KNOT_TSIG_EBADKEY, "TSIG key not recognized or invalid." }, {KNOT_TSIG_EBADTIME, "TSIG signing time out of range." }, {KNOT_ECONN, "Connection reset."}, {KNOT_EIXFRSPACE, "IXFR reply did not fit in."}, {KNOT_ECNAME, "CNAME loop found in zone."}, + {KNOT_ENODIFF, "Cannot create zone diff."}, {KNOT_ERROR, 0} }; diff --git a/src/libknot/util/tolower.c b/src/libknot/util/tolower.c index d71c467..d71c467 100644..100755 --- a/src/libknot/util/tolower.c +++ b/src/libknot/util/tolower.c diff --git a/src/libknot/util/tolower.h b/src/libknot/util/tolower.h index 6b9e98c..2e92258 100644..100755 --- a/src/libknot/util/tolower.h +++ b/src/libknot/util/tolower.h @@ -55,3 +55,5 @@ static inline uint8_t knot_tolower(uint8_t c) { } #endif /* _KNOT_TOLOWER_H_ */ + +/*! @} */ diff --git a/src/libknot/util/utils.c b/src/libknot/util/utils.c index 04e12c5..04e12c5 100644..100755 --- a/src/libknot/util/utils.c +++ b/src/libknot/util/utils.c diff --git a/src/libknot/util/utils.h b/src/libknot/util/utils.h index fd275b3..fd275b3 100644..100755 --- a/src/libknot/util/utils.h +++ b/src/libknot/util/utils.h diff --git a/src/libknot/util/wire.h b/src/libknot/util/wire.h index 0a24ff1..0a24ff1 100644..100755 --- a/src/libknot/util/wire.h +++ b/src/libknot/util/wire.h diff --git a/src/libknot/zone/dname-table.c b/src/libknot/zone/dname-table.c index d2d97c2..d2d97c2 100644..100755 --- a/src/libknot/zone/dname-table.c +++ b/src/libknot/zone/dname-table.c diff --git a/src/libknot/zone/dname-table.h b/src/libknot/zone/dname-table.h index 945b6de..945b6de 100644..100755 --- a/src/libknot/zone/dname-table.h +++ b/src/libknot/zone/dname-table.h diff --git a/src/libknot/zone/node.c b/src/libknot/zone/node.c index 4ad2a27..c196f29 100644..100755 --- a/src/libknot/zone/node.c +++ b/src/libknot/zone/node.c @@ -81,67 +81,29 @@ static inline void knot_node_flags_set_nonauth(uint8_t *flags) *flags |= KNOT_NODE_FLAGS_NONAUTH; } -///*----------------------------------------------------------------------------*/ -///*! -// * \brief Returns the old node flag -// * -// * \param flags Flags to retrieve the flag from. -// * -// * \return A byte with only the old node flag set if it was set in \a flags. -// */ -//static inline uint8_t knot_node_flags_get_old(uint8_t flags) -//{ -// return flags & KNOT_NODE_FLAGS_OLD; -//} - -///*----------------------------------------------------------------------------*/ -///*! -// * \brief Sets the old node flag. -// * -// * \param flags Flags to set the flag in. -// */ -//static inline void knot_node_flags_set_new(uint8_t *flags) -//{ -// *flags |= KNOT_NODE_FLAGS_NEW; -//} - -///*----------------------------------------------------------------------------*/ -///*! -// * \brief Returns the new node flag -// * -// * \param flags Flags to retrieve the flag from. -// * -// * \return A byte with only the new node flag set if it was set in \a flags. -// */ -//static inline uint8_t knot_node_flags_get_new(uint8_t flags) -//{ -// return flags & KNOT_NODE_FLAGS_NEW; -//} - -///*----------------------------------------------------------------------------*/ -///*! -// * \brief Sets the new node flag. -// * -// * \param flags Flags to set the flag in. -// */ -//static inline void knot_node_flags_set_old(uint8_t *flags) -//{ -// *flags |= KNOT_NODE_FLAGS_OLD; -//} - -///*----------------------------------------------------------------------------*/ - -//static inline void knot_node_flags_clear_new(uint8_t *flags) -//{ -// *flags &= ~KNOT_NODE_FLAGS_NEW; -//} - -///*----------------------------------------------------------------------------*/ - -//static inline void knot_node_flags_clear_old(uint8_t *flags) -//{ -// *flags &= ~KNOT_NODE_FLAGS_OLD; -//} +/*----------------------------------------------------------------------------*/ +/*! + * \brief Sets the empty node flag. + * + * \param flags Flags to set the flag in. + */ +static inline void knot_node_flags_set_empty(uint8_t *flags) +{ + *flags |= KNOT_NODE_FLAGS_EMPTY; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Returns the empty node flag + * + * \param flags Flags to retrieve the flag from. + * + * \return A byte with only the empty node flag set if it was set in \a flags. + */ +static inline uint8_t knot_node_flags_get_empty(uint8_t flags) +{ + return flags & KNOT_NODE_FLAGS_EMPTY; +} /*----------------------------------------------------------------------------*/ /*! @@ -166,26 +128,6 @@ static int compare_rrset_types(void *rr1, void *rr2) } /*----------------------------------------------------------------------------*/ - -//static int knot_node_zone_gen_is_new(const knot_node_t *node) -//{ -// assert(node->zone != NULL); -// knot_zone_contents_t *cont = rcu_dereference(node->zone->contents); -// assert(cont != NULL); -// return knot_zone_contents_gen_is_new(cont); -//} - -///*----------------------------------------------------------------------------*/ - -//static int knot_node_zone_gen_is_old(const knot_node_t *node) -//{ -// assert(node->zone != NULL); -// knot_zone_contents_t *cont = rcu_dereference(node->zone->contents); -// assert(cont != NULL); -// return knot_zone_contents_gen_is_old(cont); -//} - -/*----------------------------------------------------------------------------*/ /* API functions */ /*----------------------------------------------------------------------------*/ @@ -211,9 +153,12 @@ knot_node_t *knot_node_new(knot_dname_t *owner, knot_node_t *parent, } /*----------------------------------------------------------------------------*/ - +/*! \todo Consider replacing rrset_merge() with rrset_merge_no_dupl(). Currently + * this function is never called with merge=1, so it's not a problem, + * but it may be in the future. + */ int knot_node_add_rrset(knot_node_t *node, knot_rrset_t *rrset, - int merge) + int merge) { if (node == NULL) { return KNOT_EBADARG; @@ -235,6 +180,24 @@ int knot_node_add_rrset(knot_node_t *node, knot_rrset_t *rrset, } } +int knot_node_add_rrset_no_dupl(knot_node_t *node, knot_rrset_t *rrset) +{ + int ret = 0; + + if ((ret = (gen_tree_add(node->rrset_tree, rrset, + knot_rrset_merge_no_dupl))) < 0) { + dbg_node("Failed to add rrset to node->rrset_tree.\n"); + return KNOT_ERROR; + } + + if (ret >= 0) { + node->rrset_count += (ret > 0 ? 0 : 1); + return ret; + } else { + return KNOT_ERROR; + } +} + /*----------------------------------------------------------------------------*/ const knot_rrset_t *knot_node_rrset(const knot_node_t *node, @@ -315,6 +278,8 @@ struct knot_node_save_rrset_arg { size_t max_count; }; +/*----------------------------------------------------------------------------*/ + static void save_rrset_to_array(void *node, void *data) { struct knot_node_save_rrset_arg *args = @@ -329,6 +294,8 @@ static void save_rrset_to_array(void *node, void *data) args->array[args->count++] = rrset; } +/*----------------------------------------------------------------------------*/ + knot_rrset_t **knot_node_get_rrsets(const knot_node_t *node) { if (node == NULL || node->rrset_count == 0) { @@ -463,17 +430,6 @@ 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; -} - -/*----------------------------------------------------------------------------*/ - void knot_node_set_previous(knot_node_t *node, knot_node_t *prev) { if (node == NULL) { @@ -620,7 +576,7 @@ void knot_node_set_new_node(knot_node_t *node, /*----------------------------------------------------------------------------*/ -void knot_node_set_zone(knot_node_t *node, knot_zone_t *zone) +void knot_node_set_zone(knot_node_t *node, const knot_zone_t *zone) { if (node == NULL) { return; @@ -631,6 +587,17 @@ void knot_node_set_zone(knot_node_t *node, knot_zone_t *zone) /*----------------------------------------------------------------------------*/ +const knot_zone_t *knot_node_zone(const knot_node_t *node) +{ + if (node == NULL) { + return NULL; + } + + return node->zone; +} + +/*----------------------------------------------------------------------------*/ + void knot_node_update_ref(knot_node_t **ref) { if (*ref != NULL && (*ref)->new_node != NULL) { @@ -644,8 +611,6 @@ void knot_node_update_refs(knot_node_t *node) { // reference to previous node knot_node_update_ref(&node->prev); - // reference to next node - knot_node_update_ref(&node->next); // reference to parent knot_node_update_ref(&node->parent); // reference to wildcard child @@ -713,6 +678,20 @@ int knot_node_is_auth(const knot_node_t *node) /*----------------------------------------------------------------------------*/ +int knot_node_is_empty(const knot_node_t *node) +{ + return knot_node_flags_get_empty(node->flags); +} + +/*----------------------------------------------------------------------------*/ + +void knot_node_set_empty(knot_node_t *node) +{ + knot_node_flags_set_empty(&node->flags); +} + +/*----------------------------------------------------------------------------*/ + static void knot_node_free_rrsets_from_tree(void *item, void *data) { if (item == NULL) { @@ -727,14 +706,6 @@ static void knot_node_free_rrsets_from_tree(void *item, void *data) void knot_node_free_rrsets(knot_node_t *node, int free_rdata_dnames) { - /* CLEANUP */ -// knot_rrset_t **rrsets = knot_node_get_rrsets(node); -// for (int i = 0; i < node->rrset_count; i++) { -// knot_rrset_deep_free(&(rrsets[i]), 0, 1, free_rdata_dnames); -// } - -// free(rrsets); - if (node == NULL) { return; } @@ -748,16 +719,16 @@ void knot_node_free_rrsets(knot_node_t *node, int free_rdata_dnames) /*----------------------------------------------------------------------------*/ -void knot_node_free(knot_node_t **node, int fix_refs) +void knot_node_free(knot_node_t **node) { if (node == NULL || *node == NULL) { return; } - dbg_node("Freeing node: %p\n", *node); + dbg_node_detail("Freeing node: %p\n", *node); if ((*node)->rrset_tree != NULL) { - dbg_node("Freeing RRSets.\n"); + dbg_node_detail("Freeing RRSets.\n"); gen_tree_destroy(&(*node)->rrset_tree, NULL, NULL); } @@ -768,53 +739,13 @@ void knot_node_free(knot_node_t **node, int fix_refs) knot_dname_set_node((*node)->owner, NULL); } - dbg_node("Releasing owner.\n"); + dbg_node_detail("Releasing owner.\n"); knot_dname_release((*node)->owner); - // check nodes referencing this node and fix the references - - if (fix_refs) { - // previous node - dbg_node("Checking previous.\n"); - if ((*node)->prev && (*node)->prev->next == (*node)) { - (*node)->prev->next = (*node)->next; - } - - dbg_node("Checking next.\n"); - if ((*node)->next && (*node)->next->prev == (*node)) { - (*node)->next->prev = (*node)->prev; - } - - // NSEC3 node - dbg_node("Checking NSEC3.\n"); - if ((*node)->nsec3_node - && (*node)->nsec3_node->nsec3_referer == (*node)) { - (*node)->nsec3_node->nsec3_referer = NULL; - } - - dbg_node("Checking NSEC3 ref.\n"); - if ((*node)->nsec3_referer - && (*node)->nsec3_referer->nsec3_node == (*node)) { - (*node)->nsec3_referer->nsec3_node = NULL; - } - - // wildcard child node - dbg_node("Checking parent's wildcard child.\n"); - if ((*node)->parent - && (*node)->parent->wildcard_child == (*node)) { - (*node)->parent->wildcard_child = NULL; - } - - // fix parent's children count - if ((*node)->parent) { - --(*node)->parent->children; - } - } - free(*node); *node = NULL; - dbg_node("Done.\n"); + dbg_node_detail("Done.\n"); } /*----------------------------------------------------------------------------*/ diff --git a/src/libknot/zone/node.h b/src/libknot/zone/node.h index 11cd0ce..1ab814a 100644..100755 --- a/src/libknot/zone/node.h +++ b/src/libknot/zone/node.h @@ -62,8 +62,6 @@ struct knot_node { */ struct knot_node *prev; - struct knot_node *next; - /*! * \brief NSEC3 node corresponding to this node. * @@ -74,7 +72,7 @@ struct knot_node { struct knot_node *nsec3_referer; - struct knot_zone *zone; + const struct knot_zone *zone; struct knot_node *new_node; @@ -83,22 +81,12 @@ struct knot_node { unsigned short rrset_count; /*!< Number of RRSets stored in the node. */ /*! - * \brief Generation of node to be used. - * - * If set to 0, the old node will be used. Otherwise new nodes will - * be used. This applies when getting some referenced node. - - */ -// short **generation; - - /*! * \brief Various flags. * * Currently only two: * 0x01 - node is a delegation point * 0x02 - node is non-authoritative (under a delegation point) - * 0x80 - node is old and will be removed (during update) - * 0x40 - node is new, should not be used while zone is old + * 0x10 - node is empty and will be deleted after update */ uint8_t flags; }; @@ -113,9 +101,11 @@ typedef enum { /*! \brief Node is not authoritative (i.e. below a zone cut). */ KNOT_NODE_FLAGS_NONAUTH = (uint8_t)0x02, /*! \brief Node is old and will be removed (during update). */ - KNOT_NODE_FLAGS_OLD = (uint8_t)0x80, + KNOT_NODE_FLAGS_OLD = (uint8_t)0x04, /*! \brief Node is new and should not be used while zoen is old. */ - KNOT_NODE_FLAGS_NEW = (uint8_t)0x40 + KNOT_NODE_FLAGS_NEW = (uint8_t)0x08, + /*! \brief Node is empty and will be deleted after update. */ + KNOT_NODE_FLAGS_EMPTY = (uint8_t)0x10 } knot_node_flags_t; /*----------------------------------------------------------------------------*/ @@ -147,6 +137,8 @@ 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); +int knot_node_add_rrset_no_dupl(knot_node_t *node, knot_rrset_t *rrset); + /*! * \brief Returns the RRSet of the given type from the node. * @@ -255,8 +247,6 @@ const knot_node_t *knot_node_previous(const knot_node_t *node); */ knot_node_t *knot_node_get_previous(const knot_node_t *node); -const knot_node_t *knot_node_next(const knot_node_t *node); - /*! * \brief Sets the previous node of the given node. * @@ -351,7 +341,9 @@ 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); -void knot_node_set_zone(knot_node_t *node, struct knot_zone *zone); +void knot_node_set_zone(knot_node_t *node, const struct knot_zone *zone); + +const struct knot_zone *knot_node_zone(const knot_node_t *node); void knot_node_update_ref(knot_node_t **ref); @@ -405,6 +397,10 @@ void knot_node_clear_new(knot_node_t *node); void knot_node_clear_old(knot_node_t *node); +int knot_node_is_empty(const knot_node_t *node); + +void knot_node_set_empty(knot_node_t *node); + /*! * \brief Destroys the RRSets within the node structure. * @@ -428,7 +424,7 @@ void knot_node_free_rrsets(knot_node_t *node, int free_rdata_dnames); * * \todo Document missing parameters. */ -void knot_node_free(knot_node_t **node, int fix_refs); +void knot_node_free(knot_node_t **node); /*! * \brief Compares two nodes according to their owner. diff --git a/src/libknot/zone/zone-contents.c b/src/libknot/zone/zone-contents.c index 19268c4..7e453a5 100644..100755 --- a/src/libknot/zone/zone-contents.c +++ b/src/libknot/zone/zone-contents.c @@ -20,6 +20,8 @@ #include "util/error.h" #include "util/debug.h" #include "common/base32hex.h" +/*! \todo XXX TODO FIXME remove once testing is done. */ +#include "zcompile/zcompile.h" #include "consts.h" /*----------------------------------------------------------------------------*/ @@ -42,7 +44,7 @@ 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_FIN = 1 << 1; /* 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 */ @@ -91,8 +93,8 @@ dbg_zone_exec( char *node_owner = knot_dname_to_str(knot_node_owner(node)); char *apex_owner = knot_dname_to_str(contents->apex->owner); dbg_zone("zone: Trying to insert foreign node to a " - "zone. Node owner: %s, zone apex: %s\n", - node_owner, apex_owner); + "zone. Node owner: %s, zone apex: %s\n", + node_owner, apex_owner); free(node_owner); free(apex_owner); ); @@ -137,7 +139,7 @@ static void knot_zone_contents_destroy_node_owner_from_tree( UNUSED(data); /*!< \todo change completely! */ - knot_node_free(&tnode->node, 0); + knot_node_free(&tnode->node); } /*----------------------------------------------------------------------------*/ @@ -159,11 +161,8 @@ static int knot_zone_contents_dnames_from_rdata_to_table( == KNOT_RDATA_WF_UNCOMPRESSED_DNAME || d->wireformat[j] == KNOT_RDATA_WF_LITERAL_DNAME) { -// printf("Saving dname from rdata to dname table: " -// "%p.\n", knot_rdata_get_item(rdata, j)->dname); rc = knot_dname_table_add_dname_check(table, &knot_rdata_get_item(rdata, j)->dname); -// printf("Returned: %d\n", rc); if (rc < 0) { dbg_zone("Error: %s\n", knot_strerror(rc)); return rc; @@ -171,7 +170,7 @@ static int knot_zone_contents_dnames_from_rdata_to_table( } } - dbg_zone("RDATA OK.\n"); + dbg_zone_detail("RDATA OK.\n"); return KNOT_EOK; } @@ -187,7 +186,7 @@ static int knot_zone_contents_dnames_from_rrset_to_table( // discard the old owner and replace it with the new knot_rrset_set_owner(rrset, owner); } - dbg_zone("RRSet owner: %p\n", rrset->owner); + dbg_zone_detail("RRSet owner: %p\n", rrset->owner); knot_rrtype_descriptor_t *desc = knot_rrtype_descriptor_by_type( knot_rrset_type(rrset)); @@ -197,10 +196,6 @@ static int knot_zone_contents_dnames_from_rrset_to_table( return KNOT_EOK; } // for each RDATA in RRSet -// char *name = knot_dname_to_str(rrset->owner); -// char *type = knot_rrtype_to_string(rrset->type); -// printf("Storing dnames from RDATA from RRSet %s, %s\n", name, type); -// free(name); knot_rdata_t *rdata = knot_rrset_get_rdata(rrset); while (rdata != NULL) { int rc = knot_zone_contents_dnames_from_rdata_to_table(table, @@ -227,10 +222,10 @@ static int knot_zone_contents_dnames_from_node_to_table( // insert owner char *name = knot_dname_to_str(node->owner); - dbg_zone("Node owner before inserting to dname table: %p.\n", - node->owner); - dbg_zone("Node owner before inserting to dname table: %s.\n", - name); + dbg_zone_detail("Node owner before inserting to dname table: %p.\n", + node->owner); + dbg_zone_detail("Node owner before inserting to dname table: %s.\n", + name); free(name); //knot_dname_t *old_owner = node->owner; int rc = knot_dname_table_add_dname_check(table, &node->owner); @@ -239,17 +234,18 @@ static int knot_zone_contents_dnames_from_node_to_table( return rc; } int replace_owner = (rc > 0); - dbg_zone("Node owner after inserting to dname table: %p.\n", - node->owner); + +dbg_zone_exec_detail( name = knot_dname_to_str(node->owner); - dbg_zone("Node owner after inserting to dname table: %s.\n", - name); + dbg_zone_detail("Node owner after inserting to dname table: %p (%s).\n", + node->owner, name); free(name); +); knot_rrset_t **rrsets = knot_node_get_rrsets(node); // for each RRSet for (int i = 0; i < knot_node_rrset_count(node); ++i) { - dbg_zone("Inserting RRSets from node to table.\n"); + dbg_zone_detail("Inserting RRSets from node to table.\n"); rc = knot_zone_contents_dnames_from_rrset_to_table(table, rrsets[i], replace_owner, node->owner); if (rc != KNOT_EOK) { @@ -264,27 +260,46 @@ static int knot_zone_contents_dnames_from_node_to_table( } /*----------------------------------------------------------------------------*/ -/*! - * \brief Finds and sets wildcard child for given node's owner. - * - * \param zone Current zone. - * \param node Node to be used. - */ -//static void find_and_set_wildcard_child(knot_zone_contents_t *zone, -// knot_node_t *node) -//{ -// knot_dname_t *chopped = knot_dname_left_chop(node->owner); -// assert(chopped); -// knot_node_t *wildcard_parent; -// wildcard_parent = -// knot_zone_contents_get_node(zone, chopped); -// knot_dname_free(&chopped); +static const knot_node_t *knot_zone_contents_find_wildcard_child( + knot_zone_contents_t *zone, const knot_node_t *closest_encloser) +{ + assert(zone != NULL); + assert(closest_encloser != NULL); + + knot_dname_t *tmp = knot_dname_new_from_str("*", 1, NULL); + CHECK_ALLOC(tmp, NULL); -// assert(wildcard_parent); /* it *has* to be there */ + knot_dname_t *wildcard = knot_dname_cat(tmp, knot_node_owner( + closest_encloser)); + if (wildcard == NULL) { + free(tmp); + return NULL; + } -// knot_node_set_wildcard_child(wildcard_parent, node); -//} + assert(wildcard == tmp); + +dbg_zone_exec_detail( + char *name = knot_dname_to_str(knot_node_owner(closest_encloser)); + char *name2 = knot_dname_to_str(wildcard); + dbg_zone_detail("Searching for wildcard child of %s (%s)\n", name, + name2); + free(name); + free(name2); +); + + const knot_node_t *found = NULL, *ce = NULL, *prev = NULL; + int ret = knot_zone_contents_find_dname(zone, wildcard, &found, &ce, + &prev); + + knot_dname_free(&wildcard); + + if (ret != KNOT_ZONE_NAME_FOUND) { + return NULL; + } else { + return found; + } +} /*----------------------------------------------------------------------------*/ /*! @@ -303,54 +318,79 @@ static int knot_zone_contents_dnames_from_node_to_table( * \param zone Zone to which the RDATA belongs. * \param pos Position of the RDATA item in the RDATA. */ -//static void knot_zone_contents_adjust_rdata_item(knot_rdata_t *rdata, -// knot_zone_contents_t *zone, -// knot_node_t *node, -// int pos) -//{ -// return; -// const knot_rdata_item_t *dname_item -// = knot_rdata_item(rdata, pos); - -// assert(dname_item); - -// if (dname_item != NULL) { -// knot_dname_t *dname = dname_item->dname; -// const knot_node_t *n = NULL; -// const knot_node_t *closest_encloser = NULL; -// const knot_node_t *prev = NULL; - -// if (knot_dname_is_wildcard(dname)) { -// find_and_set_wildcard_child(zone, node); -// } - -// int ret = knot_zone_contents_find_dname(zone, dname, &n, -// &closest_encloser, &prev); - -// // n = knot_zone_find_node(zone, dname); - -// if (ret == KNOT_EBADARG || ret == KNOT_EBADZONE) { -// // TODO: do some cleanup if needed -// return; -// } - -// assert(ret != KNOT_ZONE_NAME_FOUND -// || n == closest_encloser); - -// if (ret != KNOT_ZONE_NAME_FOUND -// && (closest_encloser != NULL)) { -// dbg_zone("Saving closest encloser to RDATA.\n"); -// // save pointer to the closest encloser -// knot_rdata_item_t *item = -// knot_rdata_get_item(rdata, pos); -// assert(item->dname != NULL); -// assert(item->dname->node == NULL); -// //skip_insert(list, (void *)item->dname, -// // (void *)closest_encloser->owner, NULL); -// item->dname->node = closest_encloser->owner->node; -// } -// } -//} +static void knot_zone_contents_adjust_rdata_item(knot_rdata_t *rdata, + knot_zone_contents_t *zone, + knot_node_t *node, int pos) +{ + const knot_rdata_item_t *dname_item = knot_rdata_item(rdata, pos); + + assert(dname_item); + + if (dname_item != NULL) { + knot_dname_t *dname = dname_item->dname; + + /* + * The case when dname.node is already set is handled here. + * No use to check it later. + */ + if (knot_dname_node(dname) != NULL + || !knot_dname_is_subdomain(dname, knot_node_owner( + knot_zone_contents_apex(zone)))) { + // The name's node is either already set + // or the name does not belong to the zone + dbg_zone_detail("Name's node either set or the name " + "does not belong to the zone (%p).\n", + knot_dname_node(dname)); + return; + } + + const knot_node_t *n = NULL; + const knot_node_t *closest_encloser = NULL; + const knot_node_t *prev = NULL; + + int ret = knot_zone_contents_find_dname(zone, dname, &n, + &closest_encloser, &prev); + + if (ret == KNOT_EBADARG || ret == KNOT_EBADZONE) { + // TODO: do some cleanup if needed + dbg_zone_detail("Failed to find the name in zone: %s\n", + knot_strerror(ret)); + return; + } + + assert(ret != KNOT_ZONE_NAME_FOUND || n == closest_encloser); + + if (ret != KNOT_ZONE_NAME_FOUND && (closest_encloser != NULL)) { + /*! + * \note There is no need to set closer encloser to the + * name. We may find the possible wildcard child + * right away. + * Having the closest encloser saved in the dname + * would disrupt the query processing algorithms + * anyway. + */ + + dbg_zone_verb("Trying to find wildcard child.\n"); + + n = knot_zone_contents_find_wildcard_child(zone, + closest_encloser); + + if (n != NULL) { + knot_dname_set_node(dname, (knot_node_t *)n); + dbg_zone_exec_detail( + char *name = knot_dname_to_str( + knot_node_owner(n)); + char *name2 = knot_dname_to_str(dname); + dbg_zone_detail("Set wildcard node %s " + "to RDATA dname %s.\n", + name, name2); + free(name); + free(name2); + ); + } + } + } +} /*----------------------------------------------------------------------------*/ /*! @@ -364,65 +404,64 @@ static int knot_zone_contents_dnames_from_node_to_table( * \param rrset RRSet to adjust RDATA in. * \param zone Zone to which the RRSet belongs. */ -//static void knot_zone_contents_adjust_rdata_in_rrset(knot_rrset_t *rrset, -// knot_zone_contents_t *zone, -// knot_node_t *node) -//{ -// uint16_t type = knot_rrset_type(rrset); +static void knot_zone_contents_adjust_rdata_in_rrset(knot_rrset_t *rrset, + knot_zone_contents_t *zone, + knot_node_t *node) +{ + uint16_t type = knot_rrset_type(rrset); -// knot_rrtype_descriptor_t *desc = -// knot_rrtype_descriptor_by_type(type); -// assert(desc); + knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type(type); + assert(desc); -// knot_rdata_t *rdata_first = knot_rrset_get_rdata(rrset); -// knot_rdata_t *rdata = rdata_first; + knot_rdata_t *rdata_first = knot_rrset_get_rdata(rrset); + knot_rdata_t *rdata = rdata_first; -// if (rdata == NULL) { -// return; -// } + if (rdata == NULL) { + return; + } -// while (rdata->next != rdata_first) { -// for (int i = 0; i < rdata->count; ++i) { -// if (desc->wireformat[i] -// == KNOT_RDATA_WF_COMPRESSED_DNAME -// || desc->wireformat[i] -// == KNOT_RDATA_WF_UNCOMPRESSED_DNAME -// || desc->wireformat[i] -// == KNOT_RDATA_WF_LITERAL_DNAME) { -// dbg_zone("Adjusting domain name at " -// "position %d of RDATA of record with owner " -// "%s and type %s.\n", -// i, rrset->owner->name, -// knot_rrtype_to_string(type)); - -// knot_zone_contents_adjust_rdata_item(rdata, -// zone, -// node, -// i); -// } -// } -// rdata = rdata->next; -// } + while (rdata->next != rdata_first) { + for (int i = 0; i < rdata->count; ++i) { + if (desc->wireformat[i] + == KNOT_RDATA_WF_COMPRESSED_DNAME + || desc->wireformat[i] + == KNOT_RDATA_WF_UNCOMPRESSED_DNAME + || desc->wireformat[i] + == KNOT_RDATA_WF_LITERAL_DNAME) { + dbg_zone("Adjusting domain name at " + "position %d of RDATA of record with owner " + "%s and type %s.\n", + i, rrset->owner->name, + knot_rrtype_to_string(type)); + + knot_zone_contents_adjust_rdata_item(rdata, + zone, node, + i); + } + } + rdata = rdata->next; + } -// for (int i = 0; i < rdata->count; ++i) { -// if (desc->wireformat[i] -// == KNOT_RDATA_WF_COMPRESSED_DNAME -// || desc->wireformat[i] -// == KNOT_RDATA_WF_UNCOMPRESSED_DNAME -// || desc->wireformat[i] -// == KNOT_RDATA_WF_LITERAL_DNAME) { -// dbg_zone("Adjusting domain name at " -// "position %d of RDATA of record with owner " -// "%s and type %s.\n", -// i, rrset->owner->name, -// knot_rrtype_to_string(type)); - -// knot_zone_contents_adjust_rdata_item(rdata, zone, -// node, i); -// } -// } + for (int i = 0; i < rdata->count; ++i) { + if (desc->wireformat[i] + == KNOT_RDATA_WF_COMPRESSED_DNAME + || desc->wireformat[i] + == KNOT_RDATA_WF_UNCOMPRESSED_DNAME + || desc->wireformat[i] + == KNOT_RDATA_WF_LITERAL_DNAME) { + dbg_zone("Adjusting domain name at " + "position %d of RDATA of record with owner " + "%s and type %s.\n", + i, rrset->owner->name, + knot_rrtype_to_string(type)); + + knot_zone_contents_adjust_rdata_item(rdata, zone, node, + i); + } + } -//} +} /*----------------------------------------------------------------------------*/ /*! @@ -435,32 +474,29 @@ static int knot_zone_contents_dnames_from_node_to_table( * \param node Zone node to adjust the RRSets in. * \param zone Zone to which the node belongs. */ -//static void knot_zone_contents_adjust_rrsets(knot_node_t *node, -// knot_zone_contents_t *zone) -//{ -// //return; -// knot_rrset_t **rrsets = knot_node_get_rrsets(node); -// short count = knot_node_rrset_count(node); - -// assert(count == 0 || rrsets != NULL); - -// for (int r = 0; r < count; ++r) { -// assert(rrsets[r] != NULL); -// dbg_zone("Adjusting next RRSet.\n"); -// knot_zone_contents_adjust_rdata_in_rrset(rrsets[r], zone, -// node); -// knot_rrset_t *rrsigs = rrsets[r]->rrsigs; -// if (rrsigs != NULL) { -// dbg_zone("Adjusting next RRSIGs.\n"); -// knot_zone_contents_adjust_rdata_in_rrset(rrsigs, -// zone, -// node); -// } -// } - -// free(rrsets); -//} +static void knot_zone_contents_adjust_rrsets(knot_node_t *node, + knot_zone_contents_t *zone) +{ + knot_rrset_t **rrsets = knot_node_get_rrsets(node); + short count = knot_node_rrset_count(node); + + assert(count == 0 || rrsets != NULL); + + for (int r = 0; r < count; ++r) { + assert(rrsets[r] != NULL); + dbg_zone("Adjusting next RRSet.\n"); + knot_zone_contents_adjust_rdata_in_rrset(rrsets[r], zone, + node); + knot_rrset_t *rrsigs = rrsets[r]->rrsigs; + if (rrsigs != NULL) { + dbg_zone("Adjusting next RRSIGs.\n"); + knot_zone_contents_adjust_rdata_in_rrset(rrsigs, zone, + node); + } + } + free(rrsets); +} /*----------------------------------------------------------------------------*/ /*! * \brief Adjusts zone node for faster query processing. @@ -481,35 +517,24 @@ static int knot_zone_contents_dnames_from_node_to_table( static void knot_zone_contents_adjust_node(knot_node_t *node, knot_zone_contents_t *zone) { - -dbg_zone_exec( - char *name = knot_dname_to_str(node->owner); - dbg_zone("----- Adjusting node %s -----\n", name); - free(name); -); - // adjust domain names in RDATA - /*! - * \note This is unnecessary, as the code in adjust_rdata_item() is not - * reachable anyway. However, it's not clear why we disabled the - * code, so this would need further investigation. - */ - //knot_zone_contents_adjust_rrsets(node, zone); + /*! \note Enabled again after a LONG time. Should test thoroughly. */ + knot_zone_contents_adjust_rrsets(node, zone); -dbg_zone_exec( +dbg_zone_exec_detail( if (knot_node_parent(node)) { char *name = knot_dname_to_str(knot_node_owner( knot_node_parent(node))); - dbg_zone("Parent: %s\n", name); - dbg_zone("Parent is delegation point: %s\n", + dbg_zone_detail("Parent: %s\n", name); + dbg_zone_detail("Parent is delegation point: %s\n", knot_node_is_deleg_point(knot_node_parent(node)) ? "yes" : "no"); - dbg_zone("Parent is non-authoritative: %s\n", + dbg_zone_detail("Parent is non-authoritative: %s\n", knot_node_is_non_auth(knot_node_parent(node)) ? "yes" : "no"); free(name); } else { - dbg_zone("No parent!\n"); + dbg_zone_detail("No parent!\n"); } ); // delegation point / non-authoritative node @@ -539,17 +564,19 @@ dbg_zone_exec( int match = knot_zone_contents_find_nsec3_for_name(zone, knot_node_owner(node), &nsec3, &prev); + UNUSED(prev); + if (match != KNOT_ZONE_NAME_FOUND) { nsec3 = NULL; } knot_node_set_nsec3_node(node, (knot_node_t *)nsec3); - dbg_zone("Set flags to the node: \n"); - dbg_zone("Delegation point: %s\n", - knot_node_is_deleg_point(node) ? "yes" : "no"); - dbg_zone("Non-authoritative: %s\n", - knot_node_is_non_auth(node) ? "yes" : "no"); + dbg_zone_detail("Set flags to the node: \n"); + dbg_zone_detail("Delegation point: %s\n", + knot_node_is_deleg_point(node) ? "yes" : "no"); + dbg_zone_detail("Non-authoritative: %s\n", + knot_node_is_non_auth(node) ? "yes" : "no"); } /*----------------------------------------------------------------------------*/ @@ -578,19 +605,16 @@ static void knot_zone_contents_adjust_node_in_tree( return; } - /* - * 1) Set previous node pointer. - */ - knot_node_set_previous(node, args->previous_node); +dbg_zone_exec_verb( + char *name = knot_dname_to_str(node->owner); + dbg_zone_verb("----- Adjusting node %s -----\n", name); + free(name); +); - if (args->first_node == NULL) { - args->first_node = node; - } knot_zone_contents_t *zone = args->zone; /* - * 2) Store domain names to dname table. - * + * 1) Store domain names to dname table. * TODO: make optional! */ assert(zone->dname_table != NULL); @@ -605,13 +629,35 @@ static void knot_zone_contents_adjust_node_in_tree( } /* - * 3) Do other adjusting (flags, closest enclosers, wildcard children, + * 2) Do other adjusting (flags, closest enclosers, wildcard children, * etc.). */ knot_zone_contents_adjust_node(node, zone); +} + +/*----------------------------------------------------------------------------*/ + +static void knot_zone_contents_adjust_node_in_tree_ptr( + knot_zone_tree_node_t *tnode, void *data) +{ + assert(data != NULL); + assert(tnode != NULL); + assert(tnode->node != NULL); + + knot_zone_adjust_arg_t *args = (knot_zone_adjust_arg_t *)data; + knot_node_t *node = tnode->node; /* - * 4) Store previous node depending on the type of this node. + * 1) Set previous node pointer. + */ + knot_node_set_previous(node, args->previous_node); + + if (args->first_node == NULL) { + args->first_node = node; + } + + /* + * 2) Store previous node depending on the type of this node. */ if (!knot_node_is_non_auth(node) && knot_node_rrset_count(node) > 0) { @@ -639,8 +685,11 @@ static void knot_zone_contents_adjust_nsec3_node_in_tree( knot_zone_adjust_arg_t *args = (knot_zone_adjust_arg_t *)data; knot_node_t *node = tnode->node; - // set previous node - knot_node_set_previous(node, args->previous_node); + if (args->err != KNOT_EOK) { + dbg_xfrin_detail("Error during adjusting: %s, skipping node.\n", + knot_strerror(args->err)); + return; + } // assure that owner has proper node if (knot_dname_node(knot_node_owner(node)) == NULL) { @@ -661,6 +710,22 @@ static void knot_zone_contents_adjust_nsec3_node_in_tree( args->err = ret; return; } +} + +/*----------------------------------------------------------------------------*/ + +static void knot_zone_contents_adjust_nsec3_node_in_tree_ptr( + knot_zone_tree_node_t *tnode, void *data) +{ + assert(data != NULL); + assert(tnode != NULL); + assert(tnode->node != NULL); + + knot_zone_adjust_arg_t *args = (knot_zone_adjust_arg_t *)data; + knot_node_t *node = tnode->node; + + // set previous node + knot_node_set_previous(node, args->previous_node); // here is nothing to consider, all nodes are the same args->previous_node = node; @@ -710,9 +775,9 @@ dbg_zone_exec( uint8_t *hashed_name = NULL; size_t hash_size = 0; -dbg_zone_exec( +dbg_zone_exec_verb( char *n = knot_dname_to_str(name); - dbg_zone("Hashing name %s.\n", n); + dbg_zone_verb("Hashing name %s.\n", n); free(n); ); @@ -737,8 +802,7 @@ dbg_zone_exec( if (size == 0) { char *n = knot_dname_to_str(name); - dbg_zone("Error while encoding hashed name %s to " - "base32.\n", n); + dbg_zone("Error while encoding hashed name %s to base32.\n", n); free(n); if (name_b32 != NULL) { free(name_b32); @@ -749,7 +813,7 @@ dbg_zone_exec( assert(name_b32 != NULL); free(hashed_name); - dbg_zone("Base32-encoded hash: %s\n", name_b32); + dbg_zone_verb("Base32-encoded hash: %s\n", name_b32); /* Will be returned to caller, make sure it is released after use. */ *nsec3_name = knot_dname_new_from_str(name_b32, size, NULL); @@ -757,8 +821,7 @@ dbg_zone_exec( free(name_b32); if (*nsec3_name == NULL) { - dbg_zone("Error while creating domain name for hashed" - " name.\n"); + dbg_zone("Error while creating domain name for hashed name.\n"); return KNOT_ERROR; } @@ -767,7 +830,7 @@ dbg_zone_exec( if (ret == NULL) { dbg_zone("Error while creating NSEC3 domain name for " - "hashed name.\n"); + "hashed name.\n"); knot_dname_release(*nsec3_name); return KNOT_ERROR; } @@ -805,31 +868,14 @@ static int knot_zone_contents_find_in_tree(knot_zone_tree_t *tree, assert(previous != NULL); knot_node_t *found = NULL, *prev = NULL; -// knot_node_t *found2 = NULL, *prev2 = NULL; int exact_match = knot_zone_tree_get_less_or_equal(tree, name, &found, &prev); -// assert(prev != NULL); assert(exact_match >= 0); *node = found; *previous = prev; -// if (prev == NULL) { -// // either the returned node is the root of the tree, or it is -// // the leftmost node in the tree; in both cases node was found -// // set the previous node of the found node -// assert(exact_match); -// assert(found != NULL); -// *previous = knot_node_get_previous(found, 1); -// } else { -// // otherwise check if the previous node is not an empty -// // non-terminal -// *previous = (knot_node_rrset_count(prev) == 0) -// ? knot_node_get_previous(prev, 1) -// : prev; -// } - return exact_match; } @@ -852,7 +898,6 @@ static void knot_zone_contents_node_to_hash(knot_zone_tree_node_t *tnode, */ #ifdef USE_HASH_TABLE - //assert(zone->table != NULL); // add the node also to the hash table if authoritative, or deleg. point if (zone->table != NULL && ck_insert_item(zone->table, @@ -977,23 +1022,6 @@ static void knot_zone_contents_check_loops_in_tree(knot_zone_tree_node_t *tnode, args->zone, next_name, &next_node, &ce); -// char *name1 = knot_dname_to_str(next_name); -// char *name2 = (next_node != NULL) -// ? knot_dname_to_str(knot_node_owner(next_node)) -// : "none"; -// char *name3 = (ce != NULL) -// ? knot_dname_to_str(knot_node_owner(ce)) -// : "none"; -// printf("Searched: %s, found: %p (%s), %p (%s); ret: %d" -// ".\n", name1, next_node, name2, ce, name3, ret); -// free(name1); -// if (next_node != NULL) { -// free(name2); -// } -// if (ce != NULL) { -// free(name3); -// } - if (ret != KNOT_ZONE_NAME_FOUND && ce != NULL) { // try to find wildcard child @@ -1025,6 +1053,32 @@ static void knot_zone_contents_check_loops_in_tree(knot_zone_tree_node_t *tnode, } /*----------------------------------------------------------------------------*/ + +static int knot_zc_nsec3_parameters_match(const knot_rdata_t *rdata, + const knot_nsec3_params_t *params) +{ + assert(rdata != NULL && params != NULL); + + dbg_zone_detail("RDATA algo: %u, iterations: %u, salt length: %u, salt:" + " %.*s\n", + knot_rdata_nsec3_algorithm(rdata), + knot_rdata_nsec3_iterations(rdata), + knot_rdata_nsec3_salt_length(rdata), + knot_rdata_nsec3_salt_length(rdata), + knot_rdata_nsec3_salt(rdata)); + dbg_zone_detail("NSEC3PARAM algo: %u, iterations: %u, salt length: %u, " + "salt: %.*s\n", params->algorithm, params->iterations, + params->salt_length, params->salt_length, params->salt); + + return (knot_rdata_nsec3_algorithm(rdata) == params->algorithm + && knot_rdata_nsec3_iterations(rdata) == params->iterations + && knot_rdata_nsec3_salt_length(rdata) == params->salt_length + && strncmp((const char *)knot_rdata_nsec3_salt(rdata), + (const char *)params->salt, params->salt_length) + == 0); +} + +/*----------------------------------------------------------------------------*/ /* API functions */ /*----------------------------------------------------------------------------*/ @@ -1041,22 +1095,19 @@ knot_zone_contents_t *knot_zone_contents_new(knot_node_t *apex, return NULL; } -// printf("created cont: %p (%s)\n", -// contents, knot_dname_to_str(apex->owner)); - contents->apex = apex; contents->zone = zone; - knot_node_set_zone(apex, zone); + knot_node_set_zone(apex, contents->zone); contents->node_count = 1; - dbg_zone("Creating tree for normal nodes.\n"); + dbg_zone_verb("Creating tree for normal nodes.\n"); contents->nodes = malloc(sizeof(knot_zone_tree_t)); if (contents->nodes == NULL) { ERR_ALLOC_FAILED; goto cleanup; } - dbg_zone("Creating tree for NSEC3 nodes.\n"); + dbg_zone_verb("Creating tree for NSEC3 nodes.\n"); contents->nsec3_nodes = malloc(sizeof(knot_zone_tree_t)); if (contents->nsec3_nodes == NULL) { ERR_ALLOC_FAILED; @@ -1064,7 +1115,7 @@ knot_zone_contents_t *knot_zone_contents_new(knot_node_t *apex, } if (use_domain_table) { - dbg_zone("Creating domain name table.\n"); + dbg_zone_verb("Creating domain name table.\n"); contents->dname_table = knot_dname_table_new(); if (contents->dname_table == NULL) { ERR_ALLOC_FAILED; @@ -1077,20 +1128,20 @@ knot_zone_contents_t *knot_zone_contents_new(knot_node_t *apex, //contents->node_count = node_count; /* Initialize NSEC3 params */ - dbg_zone("Initializing NSEC3 parameters.\n"); + dbg_zone_verb("Initializing NSEC3 parameters.\n"); contents->nsec3_params.algorithm = 0; contents->nsec3_params.flags = 0; contents->nsec3_params.iterations = 0; contents->nsec3_params.salt_length = 0; contents->nsec3_params.salt = NULL; - dbg_zone("Initializing zone trees.\n"); + dbg_zone_verb("Initializing zone trees.\n"); if (knot_zone_tree_init(contents->nodes) != KNOT_EOK || knot_zone_tree_init(contents->nsec3_nodes) != KNOT_EOK) { goto cleanup; } - dbg_zone("Inserting apex into the zone tree.\n"); + dbg_zone_verb("Inserting apex into the zone tree.\n"); if (knot_zone_tree_insert(contents->nodes, apex) != KNOT_EOK) { dbg_zone("Failed to insert apex to the zone tree.\n"); goto cleanup; @@ -1098,14 +1149,14 @@ knot_zone_contents_t *knot_zone_contents_new(knot_node_t *apex, #ifdef USE_HASH_TABLE if (node_count > 0) { - dbg_zone("Creating hash table.\n"); + dbg_zone_verb("Creating hash table.\n"); contents->table = ck_create_table(node_count); if (contents->table == NULL) { goto cleanup; } // insert the apex into the hash table - dbg_zone("Inserting apex into the hash table.\n"); + dbg_zone_verb("Inserting apex into the hash table.\n"); if (ck_insert_item(contents->table, (const char *)knot_dname_name( knot_node_owner(apex)), @@ -1121,7 +1172,7 @@ knot_zone_contents_t *knot_zone_contents_new(knot_node_t *apex, // insert names from the apex to the domain table if (use_domain_table) { - dbg_zone("Inserting names from apex to table.\n"); + dbg_zone_verb("Inserting names from apex to table.\n"); int rc = knot_zone_contents_dnames_from_node_to_table( contents->dname_table, apex); if (rc != KNOT_EOK) { @@ -1133,7 +1184,7 @@ knot_zone_contents_t *knot_zone_contents_new(knot_node_t *apex, return contents; cleanup: - dbg_zone("Cleaning up.\n"); + dbg_zone_verb("Cleaning up.\n"); free(contents->dname_table); free(contents->nodes); free(contents->nsec3_nodes); @@ -1234,6 +1285,12 @@ int knot_zone_contents_add_node(knot_zone_contents_t *zone, return KNOT_EBADARG; } +dbg_zone_exec_detail( + char *name = knot_dname_to_str(knot_node_owner(node)); + dbg_zone_detail("Adding node to zone: %s.\n", name); + free(name); +); + int ret = 0; if ((ret = knot_zone_contents_check_node(zone, node)) != 0) { dbg_zone("Node check failed.\n"); @@ -1257,10 +1314,6 @@ int knot_zone_contents_add_node(knot_zone_contents_t *zone, } #ifdef USE_HASH_TABLE -// char *name = knot_dname_to_str(node->owner); -// dbg_zone("Adding node with owner %s to hash table.\n", name); -// free(name); - //assert(zone->table != NULL); // add the node also to the hash table if authoritative, or deleg. point if (zone->table != NULL && ck_insert_item(zone->table, @@ -1281,7 +1334,7 @@ int knot_zone_contents_add_node(knot_zone_contents_t *zone, return KNOT_EOK; } - dbg_zone("Creating parents of the node.\n"); + dbg_zone_detail("Creating parents of the node.\n"); knot_dname_t *chopped = knot_dname_left_chop(knot_node_owner(node)); @@ -1293,7 +1346,7 @@ int knot_zone_contents_add_node(knot_zone_contents_t *zone, } if (knot_dname_compare(knot_node_owner(zone->apex), chopped) == 0) { - dbg_zone("Zone apex is the parent.\n"); + dbg_zone_detail("Zone apex is the parent.\n"); knot_node_set_parent(node, zone->apex); // check if the node is not wildcard child of the parent @@ -1307,7 +1360,7 @@ int knot_zone_contents_add_node(knot_zone_contents_t *zone, = knot_zone_contents_get_node(zone, chopped)) == NULL && chopped != NULL) { /* Adding new dname to zone + add to table. */ - dbg_zone("Creating new node.\n"); + dbg_zone_detail("Creating new node.\n"); assert(chopped); next_node = knot_node_new(chopped, NULL, flags); @@ -1322,7 +1375,7 @@ int knot_zone_contents_add_node(knot_zone_contents_t *zone, knot_zone_contents_dnames_from_node_to_table( zone->dname_table, next_node); if (ret != KNOT_EOK) { - knot_node_free(&next_node, 0); + knot_node_free(&next_node); knot_dname_release(chopped); return ret; } @@ -1339,14 +1392,13 @@ int knot_zone_contents_add_node(knot_zone_contents_t *zone, == NULL); assert(knot_node_owner(next_node) == chopped); - dbg_zone("Inserting new node to zone tree.\n"); -// TREE_INSERT(zone->tree, knot_node, avl, next_node); + dbg_zone_detail("Inserting new node to zone tree.\n"); ret = knot_zone_tree_insert(zone->nodes, next_node); if (ret != KNOT_EOK) { dbg_zone("Failed to insert new node " - "to zone tree.\n"); + "to zone tree.\n"); /*! \todo Delete the node?? */ /* Directly discard. */ knot_dname_release(chopped); @@ -1354,11 +1406,11 @@ int knot_zone_contents_add_node(knot_zone_contents_t *zone, } #ifdef USE_HASH_TABLE -dbg_zone_exec( +dbg_zone_exec_detail( char *name = knot_dname_to_str( knot_node_owner(next_node)); - dbg_zone("Adding new node with owner %s to " - "hash table.\n", name); + dbg_zone_detail("Adding new node with owner %s to " + "hash table.\n", name); free(name); ); @@ -1369,7 +1421,7 @@ dbg_zone_exec( knot_dname_size(knot_node_owner(next_node)), (void *)next_node) != 0) { dbg_zone("Error inserting node into " - "hash table!\n"); + "hash table!\n"); /*! \todo Delete the node?? */ /* Directly discard. */ knot_dname_release(chopped); @@ -1390,7 +1442,7 @@ dbg_zone_exec( ++zone->node_count; - dbg_zone("Next parent.\n"); + dbg_zone_detail("Next parent.\n"); node = next_node; knot_dname_t *chopped_last = chopped; chopped = knot_dname_left_chop(chopped); @@ -1406,7 +1458,7 @@ dbg_zone_exec( assert(knot_node_parent(node) == NULL); knot_node_set_parent(node, next_node); - dbg_zone("Created all parents.\n"); + dbg_zone_detail("Created all parents.\n"); } /* Directly discard. */ @@ -1419,15 +1471,22 @@ dbg_zone_exec( /*----------------------------------------------------------------------------*/ int knot_zone_contents_add_rrset(knot_zone_contents_t *zone, - knot_rrset_t *rrset, knot_node_t **node, - knot_rrset_dupl_handling_t dupl, - int use_domain_table) + knot_rrset_t *rrset, knot_node_t **node, + knot_rrset_dupl_handling_t dupl, + int use_domain_table) { if (zone == NULL || rrset == NULL || zone->apex == NULL || zone->apex->owner == NULL || node == NULL) { return KNOT_EBADARG; } +dbg_zone_exec_detail( + char *name = knot_dname_to_str(knot_rrset_owner(rrset)); + dbg_zone_detail("Adding RRSet to zone contents: %s, type %s\n", + name, knot_rrtype_to_string(knot_rrset_type(rrset))); + free(name); +); + // check if the RRSet belongs to the zone if (knot_dname_compare(knot_rrset_owner(rrset), zone->apex->owner) != 0 @@ -1448,8 +1507,12 @@ int knot_zone_contents_add_rrset(knot_zone_contents_t *zone, int rc; /*! \todo REMOVE RRSET */ - rc = knot_node_add_rrset(*node, rrset, - dupl == KNOT_RRSET_DUPL_MERGE); + if (dupl == KNOT_RRSET_DUPL_MERGE) { + rc = knot_node_add_rrset_no_dupl(*node, rrset); + } else { + rc = knot_node_add_rrset(*node, rrset, 0); + } + if (rc < 0) { dbg_zone("Failed to add RRSet to node.\n"); return rc; @@ -1458,14 +1521,13 @@ int knot_zone_contents_add_rrset(knot_zone_contents_t *zone, int ret = rc; if (use_domain_table) { - dbg_zone("Saving RRSet to table.\n"); + dbg_zone_detail("Saving RRSet to table.\n"); rc = knot_zone_contents_dnames_from_rrset_to_table( zone->dname_table, rrset, 0, (*node)->owner); if (rc != KNOT_EOK) { dbg_zone("Error saving domain names from " - "RRSIGs to the domain name table.\n " - "The zone may be in an inconsistent " - "state.\n"); + "RRSIGs to the domain name table.\n " + "The zone may be in an inconsistent state.\n"); // WARNING: the zone is not in consistent state now - // there may be domain names in it that are not inserted // into the domain table @@ -1480,7 +1542,7 @@ int knot_zone_contents_add_rrset(knot_zone_contents_t *zone, knot_rrset_set_owner(rrset, (*node)->owner); } - dbg_zone("RRSet OK.\n"); + dbg_zone_detail("RRSet OK.\n"); return ret; } @@ -1493,11 +1555,13 @@ int knot_zone_contents_add_rrsigs(knot_zone_contents_t *zone, knot_rrset_dupl_handling_t dupl, int use_domain_table) { + dbg_zone_verb("Adding RRSIGs to zone contents.\n"); + if (zone == NULL || rrsigs == NULL || rrset == NULL || node == NULL || zone->apex == NULL || zone->apex->owner == NULL) { dbg_zone_exec( dbg_zone("Parameters: zone=%p, rrsigs=%p, rrset=%p, " - "node=%p\n", zone, rrsigs, rrset, node); + "node=%p\n", zone, rrsigs, rrset, node); if (zone != NULL) { dbg_zone("zone->apex=%p\n", zone->apex); if (zone->apex != NULL) { @@ -1522,7 +1586,7 @@ dbg_zone_exec( if (*rrset != NULL && (knot_dname_compare(knot_rrset_owner(rrsigs), knot_rrset_owner(*rrset)) != 0)) { - dbg_zone("RRSIGs does not belong to the given RRSet.\n"); + dbg_zone("RRSIGs do not belong to the given RRSet.\n"); return KNOT_EBADARG; } @@ -1548,8 +1612,8 @@ dbg_zone_exec( // find the RRSet in the node // take only the first RDATA from the RRSIGs - dbg_zone("Finding RRSet for type %s\n", - knot_rrtype_to_string( + dbg_zone_detail("Finding RRSet for type %s\n", + knot_rrtype_to_string( knot_rdata_rrsig_type_covered( knot_rrset_rdata(rrsigs)))); *rrset = knot_node_get_rrset( @@ -1563,28 +1627,28 @@ dbg_zone_exec( assert(*rrset != NULL); - // add all domain names from the RRSet to domain name table int rc; int ret = KNOT_EOK; rc = knot_rrset_add_rrsigs(*rrset, rrsigs, dupl); if (rc < 0) { - dbg_dname("Failed to add RRSIGs to RRSet.\n"); + dbg_zone("Failed to add RRSIGs to RRSet.\n"); return rc; } else if (rc > 0) { - assert(dupl == KNOT_RRSET_DUPL_MERGE); + assert(dupl == KNOT_RRSET_DUPL_MERGE || + dupl == KNOT_RRSET_DUPL_SKIP); ret = 1; } + // add all domain names from the RRSet to domain name table if (use_domain_table) { - dbg_zone("Saving RRSIG RRSet to table.\n"); + dbg_zone_detail("Saving RRSIG RRSet to table.\n"); rc = knot_zone_contents_dnames_from_rrset_to_table( - zone->dname_table, rrsigs, 0, (*rrset)->owner); + zone->dname_table, (*rrset)->rrsigs, 0, (*rrset)->owner); if (rc != KNOT_EOK) { dbg_zone("Error saving domain names from " - "RRSIGs to the domain name table.\n " - "The zone may be in an inconsistent " - "state.\n"); + "RRSIGs to the domain name table.\n " + "The zone may be in an inconsistent state.\n"); // WARNING: the zone is not in consistent state now - // there may be domain names in it that are not inserted // into the domain table @@ -1598,7 +1662,7 @@ dbg_zone_exec( knot_rrset_set_owner((*rrset)->rrsigs, (*rrset)->owner); } - dbg_zone("RRSIGs OK\n"); + dbg_zone_detail("RRSIGs OK\n"); return ret; } @@ -1617,6 +1681,7 @@ int knot_zone_contents_add_nsec3_node(knot_zone_contents_t *zone, int ret = 0; if ((ret = knot_zone_contents_check_node(zone, node)) != 0) { + dbg_zone("Failed node check: %s\n", knot_strerror(ret)); return ret; } @@ -1624,6 +1689,8 @@ int knot_zone_contents_add_nsec3_node(knot_zone_contents_t *zone, // TREE_INSERT(zone->nsec3_nodes, knot_node, avl, node); ret = knot_zone_tree_insert(zone->nsec3_nodes, node); if (ret != KNOT_EOK) { + dbg_zone("Failed to insert node into NSEC3 tree: %s.\n", + knot_strerror(ret)); return ret; } @@ -1632,7 +1699,8 @@ int knot_zone_contents_add_nsec3_node(knot_zone_contents_t *zone, zone->dname_table, node); if (ret != KNOT_EOK) { /*! \todo Remove the node from the tree. */ - dbg_zone("Failed to add dnames into table.\n"); + dbg_zone("Failed to add dnames into table: %s.\n", + knot_strerror(ret)); return ret; } } @@ -1682,8 +1750,12 @@ int knot_zone_contents_add_nsec3_rrset(knot_zone_contents_t *zone, int rc; /*! \todo REMOVE RRSET */ - rc = knot_node_add_rrset(*node, rrset, - dupl == KNOT_RRSET_DUPL_MERGE); + if (dupl == KNOT_RRSET_DUPL_MERGE) { + rc = knot_node_add_rrset_no_dupl(*node, rrset); + } else { + rc = knot_node_add_rrset(*node, rrset, 0); + } + if (rc < 0) { return rc; } @@ -1691,14 +1763,13 @@ int knot_zone_contents_add_nsec3_rrset(knot_zone_contents_t *zone, int ret = rc; if (use_domain_table) { - dbg_zone("Saving NSEC3 RRSet to table.\n"); + dbg_zone_detail("Saving NSEC3 RRSet to table.\n"); rc = knot_zone_contents_dnames_from_rrset_to_table( zone->dname_table, rrset, 0, (*node)->owner); if (rc != KNOT_EOK) { dbg_zone("Error saving domain names from " - "RRSIGs to the domain name table.\n " - "The zone may be in an inconsistent " - "state.\n"); + "RRSIGs to the domain name table.\n " + "The zone may be in an inconsistent state.\n"); // WARNING: the zone is not in consistent state now - // there may be domain names in it that are not inserted // into the domain table @@ -1713,7 +1784,7 @@ int knot_zone_contents_add_nsec3_rrset(knot_zone_contents_t *zone, knot_rrset_set_owner(rrset, (*node)->owner); } - dbg_zone("NSEC3 OK\n"); + dbg_zone_detail("NSEC3 OK\n"); return ret; } @@ -1740,9 +1811,6 @@ dbg_zone_exec_verb( *removed_hash = ck_remove_item(contents->table, (const char *)knot_dname_name(owner), knot_dname_size(owner)); -// int ret = ck_detete_item(contents->table, -// (const char *)knot_dname_name(owner), -// knot_dname_size(owner), NULL, 0); if (*removed_hash == NULL) { return KNOT_ENONODE; } @@ -1837,11 +1905,6 @@ knot_node_t *knot_zone_contents_get_node(const knot_zone_contents_t *zone, return NULL; } - // create dummy node to use for lookup -// knot_node_t *tmp = knot_node_new((knot_dname_t *)name, NULL); -// knot_node_t *n = TREE_FIND(zone->tree, knot_node, avl, tmp); -// knot_node_free(&tmp, 0); - knot_node_t *n; int ret = knot_zone_tree_get(zone->nodes, name, &n); if (ret != KNOT_EOK) { @@ -1861,10 +1924,6 @@ knot_node_t *knot_zone_contents_get_nsec3_node( return NULL; } - // create dummy node to use for lookup -// knot_node_t *tmp = knot_node_new((knot_dname_t *)name, NULL); -// knot_node_t *n = TREE_FIND(zone->nsec3_nodes, knot_node, avl, tmp); -// knot_node_free(&tmp, 0); knot_node_t *n; int ret = knot_zone_tree_get(zone->nsec3_nodes, name, &n); @@ -1899,11 +1958,11 @@ int knot_zone_contents_find_dname(const knot_zone_contents_t *zone, return KNOT_EBADARG; } -dbg_zone_exec( +dbg_zone_exec_verb( char *name_str = knot_dname_to_str(name); char *zone_str = knot_dname_to_str(zone->apex->owner); - dbg_zone("Searching for name %s in zone %s...\n", - name_str, zone_str); + dbg_zone_verb("Searching for name %s in zone %s...\n", + name_str, zone_str); free(name_str); free(zone_str); ); @@ -1928,14 +1987,14 @@ dbg_zone_exec( *node = found; *previous = prev; -dbg_zone_exec( +dbg_zone_exec_detail( char *name_str = (*node) ? knot_dname_to_str((*node)->owner) : "(nil)"; char *name_str2 = (*previous != NULL) ? knot_dname_to_str((*previous)->owner) : "(nil)"; - dbg_zone("Search function returned %d, node %s and prev: %s\n", - exact_match, name_str, name_str2); +dbg_zone_detail("Search function returned %d, node %s (%p) and prev: %s (%p)\n", + exact_match, name_str, *node, name_str2, *previous); if (*node) { free(name_str); @@ -1944,19 +2003,23 @@ dbg_zone_exec( free(name_str2); } ); - - *closest_encloser = *node; - // there must be at least one node with domain name less or equal to // the searched name if the name belongs to the zone (the root) - if (*node == NULL) { + if (*node == NULL && *previous == NULL) { return KNOT_EBADZONE; } - // TODO: this could be replaced by saving pointer to closest encloser - // in node + /* This function was quite out of date. The find_in_tree() function + * may return NULL in the 'found' field, so we cannot search for the + * closest encloser from this node. + */ + + if (exact_match) { + *closest_encloser = *node; + } else { + *closest_encloser = *previous; + assert(*closest_encloser != NULL); - if (!exact_match) { int matched_labels = knot_dname_matched_labels( knot_node_owner((*closest_encloser)), name); while (matched_labels < knot_dname_label_count( @@ -1968,11 +2031,11 @@ dbg_zone_exec( } dbg_zone_exec( char *n = knot_dname_to_str(knot_node_owner((*closest_encloser))); - dbg_zone("Closest encloser: %s\n", n); + dbg_zone_detail("Closest encloser: %s\n", n); free(n); ); - dbg_zone("find_dname() returning %d\n", exact_match); + dbg_zone_verb("find_dname() returning %d\n", exact_match); return (exact_match) ? KNOT_ZONE_NAME_FOUND @@ -2055,11 +2118,11 @@ int knot_zone_contents_find_dname_hash(const knot_zone_contents_t *zone, return KNOT_EBADARG; } -dbg_zone_exec( +dbg_zone_exec_verb( char *name_str = knot_dname_to_str(name); char *zone_str = knot_dname_to_str(zone->apex->owner); - dbg_zone("Searching for name %s in zone %s...\n", - name_str, zone_str); + dbg_zone_verb("Searching for name %s in zone %s...\n", + name_str, zone_str); free(name_str); free(zone_str); ); @@ -2092,9 +2155,9 @@ dbg_zone_exec( *node = (const knot_node_t *)item->value; *closest_encloser = *node; - dbg_zone("Found node in hash table: %p (owner %p, " - "labels: %d)\n", *node, (*node)->owner, - knot_dname_label_count((*node)->owner)); + dbg_zone_detail("Found node in hash table: %p (owner %p, " + "labels: %d)\n", *node, (*node)->owner, + knot_dname_label_count((*node)->owner)); assert(*node != NULL); assert(*closest_encloser != NULL); return KNOT_ZONE_NAME_FOUND; @@ -2104,34 +2167,22 @@ dbg_zone_exec( // chop leftmost labels until some node is found // copy the name for chopping - /* Local allocation, will be discarded. */ - //knot_dname_t *name_copy = knot_dname_deep_copy(name); -dbg_zone_exec( - //char *n = knot_dname_to_str(name_copy); - dbg_zone("Finding closest encloser..\nStarting with: %.*s\n", - (int)name_size, name_tmp); - //free(n); -); + + dbg_zone_detail("Finding closest encloser..\nStarting with: %.*s\n", + (int)name_size, name_tmp); while (item == NULL) { - //knot_dname_left_chop_no_copy(name_copy); knot_zone_contents_left_chop(name_tmp, &name_size); -dbg_zone_exec( - //char *n = knot_dname_to_str(name_copy); - dbg_zone("Chopped leftmost label: %.*s\n", - (int)name_size, name_tmp); - //free(n); +dbg_zone_exec_detail( + dbg_zone_detail("Chopped leftmost label: %.*s\n", + (int)name_size, name_tmp); ); // not satisfied in root zone!! - //assert(name_copy->label_count > 0); assert(name_size > 0); item = ck_find_item(zone->table, name_tmp, name_size); } - /* Directly discard. */ - //knot_dname_free(&name_copy); - assert(item != NULL); *closest_encloser = (const knot_node_t *)item->value; @@ -2165,9 +2216,16 @@ int knot_zone_contents_find_nsec3_for_name(const knot_zone_contents_t *zone, return ret; } -dbg_zone_exec( + // check if the NSEC3 tree is not empty + if (zone->nsec3_nodes->th_root == NULL) { + dbg_zone("NSEC3 tree is empty.\n"); + knot_dname_release(nsec3_name); + return KNOT_ENSEC3CHAIN; + } + +dbg_zone_exec_verb( char *n = knot_dname_to_str(nsec3_name); - dbg_zone("NSEC3 node name: %s.\n", n); + dbg_zone_verb("NSEC3 node name: %s.\n", n); free(n); ); @@ -2180,26 +2238,33 @@ dbg_zone_exec( knot_dname_release(nsec3_name); -dbg_zone_exec( +dbg_zone_exec_detail( if (found) { char *n = knot_dname_to_str(found->owner); - dbg_zone("Found NSEC3 node: %s.\n", n); + dbg_zone_detail("Found NSEC3 node: %s.\n", n); free(n); } else { - dbg_zone("Found no NSEC3 node.\n"); + dbg_zone_detail("Found no NSEC3 node.\n"); } if (prev) { assert(prev->owner); char *n = knot_dname_to_str(prev->owner); - dbg_zone("Found previous NSEC3 node: %s.\n", n); + dbg_zone_detail("Found previous NSEC3 node: %s.\n", n); free(n); } else { - dbg_zone("Found no previous NSEC3 node.\n"); + dbg_zone_detail("Found no previous NSEC3 node.\n"); } ); *nsec3_node = found; + // This check cannot be used now, the function returns proper return + // value if the node was not found +// if (*nsec3_node == NULL) { +// // there is no NSEC3 node even if there should be +// return KNOT_ENSEC3CHAIN; +// } + if (prev == NULL) { // either the returned node is the root of the tree, or it is // the leftmost node in the tree; in both cases node was found @@ -2211,7 +2276,55 @@ dbg_zone_exec( *nsec3_previous = prev; } - dbg_zone("find_nsec3_for_name() returning %d\n", exact_match); + dbg_zone_verb("find_nsec3_for_name() returning %d\n", exact_match); + + /* The previous may be from wrong NSEC3 chain. Search for previous + * from the right chain. Check iterations, hash algorithm and salt + * values and compare them to the ones from NSEC3PARAM. + */ + const knot_rrset_t *nsec3_rrset = knot_node_rrset(*nsec3_previous, + KNOT_RRTYPE_NSEC3); + const knot_rdata_t *nsec3_rdata = (nsec3_rrset != NULL) + ? knot_rrset_rdata(nsec3_rrset) + : NULL; + const knot_node_t *original_prev = *nsec3_previous; + + while (nsec3_rdata != NULL + && !knot_zc_nsec3_parameters_match(nsec3_rdata, + &zone->nsec3_params)) { + /* Try other RDATA if there are some. In case of name collision + * the node would contain records from both NSEC3 chains. + */ + if ((nsec3_rdata = knot_rrset_rdata_next( + nsec3_rrset, nsec3_rdata)) != NULL) { + continue; + } + + /* If there is none, try previous node. */ + + *nsec3_previous = knot_node_previous(*nsec3_previous); + nsec3_rrset = knot_node_rrset(*nsec3_previous, + KNOT_RRTYPE_NSEC3); + nsec3_rdata = (nsec3_rrset != NULL) + ? knot_rrset_rdata(nsec3_rrset) + : NULL; +dbg_zone_exec_detail( + char *name = (*nsec3_previous) + ? knot_dname_to_str( + knot_node_owner(*nsec3_previous)) + : "none"; + dbg_zone_detail("Previous node: %s, checking parameters...\n", + name); + if (*nsec3_previous) { + free(name); + } +); + if (*nsec3_previous == original_prev || nsec3_rdata == NULL) { + // cycle + *nsec3_previous = NULL; + break; + } + } return (exact_match) ? KNOT_ZONE_NAME_FOUND @@ -2257,23 +2370,18 @@ int knot_zone_contents_adjust(knot_zone_contents_t *zone) adjust_arg.first_node = NULL; adjust_arg.previous_node = NULL; adjust_arg.err = KNOT_EOK; -// adjust_arg.check_ver = check_ver; /* - * Adjust the NSEC3 nodes first. - * There are independent on the normal nodes, but the normal nodes are - * dependent on them. + * First of all we must set node.prev pointers, as these are used in + * the search functions. */ - - dbg_zone("Adjusting NSEC3 nodes.\n"); - int ret = knot_zone_tree_forward_apply_inorder( - zone->nsec3_nodes, - knot_zone_contents_adjust_nsec3_node_in_tree, - &adjust_arg); + dbg_zone("Setting 'prev' pointers to NSEC3 nodes.\n"); + int ret = knot_zone_tree_forward_apply_inorder(zone->nsec3_nodes, + knot_zone_contents_adjust_nsec3_node_in_tree_ptr, &adjust_arg); assert(ret == KNOT_EOK); if (adjust_arg.err != KNOT_EOK) { - dbg_zone("Failed to adjust NSEC3 nodes: %s\n", + dbg_zone("Failed to set 'prev' pointers to NSEC3 nodes: %s\n", knot_strerror(adjust_arg.err)); return adjust_arg.err; } @@ -2281,13 +2389,46 @@ int knot_zone_contents_adjust(knot_zone_contents_t *zone) // set the last node as previous of the first node if (adjust_arg.first_node) { knot_node_set_previous(adjust_arg.first_node, - adjust_arg.previous_node); + adjust_arg.previous_node); } dbg_zone("Done.\n"); adjust_arg.first_node = NULL; adjust_arg.previous_node = NULL; + dbg_zone("Setting 'prev' pointers to normal nodes.\n"); + ret = knot_zone_tree_forward_apply_inorder(zone->nodes, + knot_zone_contents_adjust_node_in_tree_ptr, &adjust_arg); + assert(ret == KNOT_EOK); + + if (adjust_arg.err != KNOT_EOK) { + dbg_zone("Failed to set 'prev' pointers to normal nodes: %s\n", + knot_strerror(adjust_arg.err)); + return adjust_arg.err; + } + + // set the last node as previous of the first node + assert(zone->apex == adjust_arg.first_node); + knot_node_set_previous(zone->apex, adjust_arg.previous_node); + dbg_zone("Done.\n"); + + /* + * Adjust the NSEC3 nodes first. + * There are independent on the normal nodes, but the normal nodes are + * dependent on them. + */ + + dbg_zone("Adjusting NSEC3 nodes.\n"); + ret = knot_zone_tree_forward_apply_inorder(zone->nsec3_nodes, + knot_zone_contents_adjust_nsec3_node_in_tree, &adjust_arg); + assert(ret == KNOT_EOK); + + if (adjust_arg.err != KNOT_EOK) { + dbg_zone("Failed to adjust NSEC3 nodes: %s\n", + knot_strerror(adjust_arg.err)); + return adjust_arg.err; + } + dbg_zone("Adjusting normal nodes.\n"); ret = knot_zone_tree_forward_apply_inorder(zone->nodes, knot_zone_contents_adjust_node_in_tree, @@ -2300,9 +2441,6 @@ int knot_zone_contents_adjust(knot_zone_contents_t *zone) return adjust_arg.err; } - assert(zone->apex == adjust_arg.first_node); - knot_node_set_previous(zone->apex, adjust_arg.previous_node); - dbg_zone("Done.\n"); return ret; @@ -2339,58 +2477,6 @@ int knot_zone_contents_check_loops(knot_zone_contents_t *zone) /*----------------------------------------------------------------------------*/ -int knot_zone_contents_adjust_old(knot_zone_contents_t *zone) -{ - if (zone == NULL) { - return KNOT_EBADARG; - } - - // load NSEC3PARAM (needed on adjusting function) - knot_zone_contents_load_nsec3param(zone); - - knot_zone_adjust_arg_t adjust_arg; - adjust_arg.zone = zone; - adjust_arg.first_node = NULL; - adjust_arg.previous_node = NULL; -// adjust_arg.check_ver = check_ver; - adjust_arg.err = KNOT_EOK; - - dbg_zone("Adjusting normal nodes.\n"); - int ret = knot_zone_tree_forward_apply_inorder(zone->nodes, - knot_zone_contents_adjust_node_in_tree, - &adjust_arg); - if (ret != KNOT_EOK) { - return ret; - } - if (adjust_arg.err != KNOT_EOK) { - dbg_zone("Failed node adjusting: %s\n", - knot_strerror(adjust_arg.err)); - return adjust_arg.err; - } - - dbg_zone("Done.\n"); - - assert(zone->apex == adjust_arg.first_node); - knot_node_set_previous(zone->apex, adjust_arg.previous_node); - - adjust_arg.first_node = NULL; - adjust_arg.previous_node = NULL; - - dbg_zone("Adjusting NSEC3 nodes.\n"); - ret = knot_zone_tree_forward_apply_inorder(zone->nsec3_nodes, - knot_zone_contents_adjust_nsec3_node_in_tree, &adjust_arg); - - dbg_zone("Done.\n"); - if (adjust_arg.first_node) { - knot_node_set_previous(adjust_arg.first_node, - adjust_arg.previous_node); - } - - return ret; -} - -/*----------------------------------------------------------------------------*/ - int knot_zone_contents_load_nsec3param(knot_zone_contents_t *zone) { if (zone == NULL || zone->apex == NULL) { @@ -2418,8 +2504,8 @@ int knot_zone_contents_nsec3_enabled(const knot_zone_contents_t *zone) return KNOT_EBADARG; } - //return (zone->nsec3_params.algorithm != 0); - return (zone->nsec3_nodes->th_root != NULL); + return (zone->nsec3_params.algorithm != 0 + && zone->nsec3_nodes->th_root != NULL); } /*----------------------------------------------------------------------------*/ @@ -2662,16 +2748,15 @@ int knot_zone_contents_shallow_copy(const knot_zone_contents_t *from, // ret = ck_copy_table(from->table, &contents->table); ret = ck_shallow_copy(from->table, &contents->table); if (ret != 0) { - dbg_zone("knot_zone_contents_shallow_copy: " - "hash table copied\n"); + dbg_zone_verb("knot_zone_contents_shallow_copy: " + "hash table copied\n"); ret = KNOT_ERROR; goto cleanup; } } #endif - dbg_zone("knot_zone_contents_shallow_copy: " - "finished OK\n"); + dbg_zone("knot_zone_contents_shallow_copy: finished OK\n"); *to = contents; return KNOT_EOK; @@ -2740,13 +2825,11 @@ int knot_zone_contents_shallow_copy2(const knot_zone_contents_t *from, contents->node_count = from->node_count; contents->flags = from->flags; + // set the 'new' flag + knot_zone_contents_set_gen_new(contents); contents->zone = from->zone; -// /* Initialize NSEC3 params */ -// memcpy(&contents->nsec3_params, &from->nsec3_params, -// sizeof(knot_nsec3_params_t)); - if ((ret = knot_zone_tree_deep_copy(from->nodes, contents->nodes)) != KNOT_EOK || (ret = knot_zone_tree_deep_copy(from->nsec3_nodes, @@ -2758,8 +2841,8 @@ int knot_zone_contents_shallow_copy2(const knot_zone_contents_t *from, if (from->table != NULL) { ret = ck_deep_copy(from->table, &contents->table); if (ret != 0) { - dbg_zone("knot_zone_contents_shallow_copy: " - "hash table copied\n"); + dbg_zone_verb("knot_zone_contents_shallow_copy: " + "hash table copied\n"); ret = KNOT_ERROR; goto cleanup; } @@ -2903,16 +2986,6 @@ static void knot_zc_integrity_check_previous(const knot_node_t *node, ++check_data->errors; } -// if (knot_node_next(check_data->previous) != node) { -// char *name2 = knot_dname_to_str(knot_node_owner( -// knot_node_next(check_data->previous))); -// fprintf(stderr, "Wrong next node: node %s, next %s. " -// "Should be %s.\n", name_prev, name2 ,name); -// free(name2); - -// ++check_data->errors; -// } - free(name_prev); } } @@ -2995,11 +3068,6 @@ static void knot_zc_integrity_check_parent(const knot_node_t *node, && knot_dname_matched_labels(node_owner, parent_owner) == knot_dname_label_count(parent_owner)) { -// // increase the parent's children count -// fprintf(stderr, "Parent: %s, node: %s. Increasing children count.\n", -// pname, name); -// ++check_data->children; - // check the parent pointer const knot_node_t *parent = knot_node_parent(node); if (parent != check_data->parent) { @@ -3038,22 +3106,6 @@ static void knot_zc_integrity_check_parent(const knot_node_t *node, ++check_data->errors; } } - } else { - // not a direct child, check children count -// if (check_data->parent -// && knot_node_children(check_data->parent) -// != check_data->children) { -// fprintf(stderr, "Wrong children count: node %s, count: " -// "%u. Should be: %u\n", pname, -// knot_node_children(check_data->parent), -// check_data->children); - -// ++check_data->errors; -// } - - // reset the children count - //check_data->parent = node; -// check_data->children = 0; } free(pname); @@ -3110,15 +3162,6 @@ static int knot_zc_integrity_check_find_dname(const knot_zone_contents_t *zone, const char *node_name) { int ret = 0; - -// find_dname_data_t data_find; -// data_find.found = NULL; -// data_find.to_find = to_find; - -// int res = knot_zone_contents_dname_table_apply( -// (knot_zone_contents_t *)zone, -// find_in_dname_table, (void *)&data_find); -// assert(res == KNOT_EOK); knot_dname_t *found = knot_dname_table_find_dname(zone->dname_table, (knot_dname_t *)to_find); @@ -3364,27 +3407,12 @@ static void reset_new_nodes(knot_zone_tree_node_t *tree_node, void *data) /*----------------------------------------------------------------------------*/ -/*!< \todo remove debug code. */ -//static void print_child_count(knot_node_t *node, void *data) -//{ -// UNUSED(data); -// assert(node != NULL); - -// char *name = knot_dname_to_str(knot_node_owner(node)); -// fprintf(stderr, "Node: %s, children count: %d\n", name, -// knot_node_children(node)); -// free(name); -//} - -/*----------------------------------------------------------------------------*/ - static void count_nsec3_nodes(knot_zone_tree_node_t *tree_node, void *data) { assert(tree_node != NULL); assert(tree_node->node != NULL); assert(data != NULL); -// int *count = (int *)data; knot_node_t *apex = (knot_node_t *)data; assert(apex != NULL); @@ -3406,10 +3434,6 @@ int knot_zc_integrity_check_child_count(check_data_t *data) knot_zone_tree_init(nodes_copy); -// int ret = knot_zone_contents_tree_apply_inorder(data->contents, -// print_child_count, -// NULL); - int ret = knot_zone_tree_deep_copy(data->contents->nodes, nodes_copy); assert(ret == KNOT_EOK); @@ -3425,9 +3449,8 @@ int knot_zc_integrity_check_child_count(check_data_t *data) knot_zone_tree_forward_apply_inorder(nodes_copy, count_children, NULL); // add count of NSEC3 nodes to the apex' children count -// int nsec3_nodes = 0; - dbg_zone("Children count of new apex before NSEC3: %d\n", - data->contents->apex->new_node->children); + fprintf(stderr, "Children count of new apex before NSEC3: %d\n", + data->contents->apex->new_node->children); knot_zone_tree_forward_apply_inorder(data->contents->nsec3_nodes, count_nsec3_nodes, (void *)apex_copy); @@ -3435,7 +3458,6 @@ int knot_zc_integrity_check_child_count(check_data_t *data) // now compare the children counts // iterate over the old zone and search for nodes in the copy -// data->children = nsec3_nodes; knot_zone_tree_forward_apply_inorder(nodes_copy, check_child_count, (void *)data); diff --git a/src/libknot/zone/zone-contents.h b/src/libknot/zone/zone-contents.h index 3143ef9..2ca333e 100644..100755 --- a/src/libknot/zone/zone-contents.h +++ b/src/libknot/zone/zone-contents.h @@ -55,7 +55,7 @@ typedef struct knot_zone_contents_t { knot_nsec3_params_t nsec3_params; - /*! + /*! * \todo Unify the use of this field - authoritative nodes vs. all. */ uint node_count; @@ -80,17 +80,14 @@ typedef struct knot_zone_contents_t { /*----------------------------------------------------------------------------*/ knot_zone_contents_t *knot_zone_contents_new(knot_node_t *apex, - uint node_count, - int use_domain_table, - struct knot_zone *zone); - -//short knot_zone_contents_generation(const knot_zone_contents_t *contents); + uint node_count, + int use_domain_table, + struct knot_zone *zone); int knot_zone_contents_gen_is_old(const knot_zone_contents_t *contents); int knot_zone_contents_gen_is_new(const knot_zone_contents_t *contents); int knot_zone_contents_gen_is_finished(const knot_zone_contents_t *contents); -//void knot_zone_contents_switch_generation(knot_zone_contents_t *contents); void knot_zone_contents_set_gen_old(knot_zone_contents_t *contents); void knot_zone_contents_set_gen_new(knot_zone_contents_t *contents); @@ -187,9 +184,6 @@ int knot_zone_contents_remove_node(knot_zone_contents_t *contents, const knot_node_t *node, knot_zone_tree_node_t **removed_tree, ck_hash_table_item_t **removed_hash); -//knot_zone_tree_node_t *knot_zone_contents_remove_node( -// knot_zone_contents_t *contents, const knot_node_t *node); - int knot_zone_contents_remove_nsec3_node(knot_zone_contents_t *contents, const knot_node_t *node, knot_zone_tree_node_t **removed); @@ -357,9 +351,6 @@ const knot_node_t *knot_zone_contents_apex( knot_node_t *knot_zone_contents_get_apex( const knot_zone_contents_t *contents); -//knot_dname_t *knot_zone_contents_name( -// const knot_zone_contents_t *contents); - /*! * \brief Optimizes zone by replacing domain names in RDATA with references to * domain names present in zone (as node owners). @@ -555,12 +546,6 @@ int knot_zone_contents_shallow_copy(const knot_zone_contents_t *from, int knot_zone_contents_shallow_copy2(const knot_zone_contents_t *from, knot_zone_contents_t **to); -//int knot_zone_contents_dnames_from_node_to_table( -// knot_dname_table_t *table, knot_node_t *node); - -//void knot_zone_contents_adjust_node(knot_node_t *node, -// knot_zone_contents_t *zone, int check_ver); - void knot_zone_contents_free(knot_zone_contents_t **contents); void knot_zone_contents_deep_free(knot_zone_contents_t **contents, diff --git a/src/libknot/zone/zone-diff.c b/src/libknot/zone/zone-diff.c new file mode 100755 index 0000000..d3fd961 --- /dev/null +++ b/src/libknot/zone/zone-diff.c @@ -0,0 +1,1004 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <assert.h> +#include <config.h> + +#include "libknot/util/error.h" +#include "libknot/util/debug.h" +#include "libknot/rdata.h" +#include "zone-diff.h" +#include "libknot/nameserver/name-server.h" + +struct zone_diff_param { + const knot_zone_contents_t *contents; + char nsec3; + knot_changeset_t *changeset; + int ret; +}; + +// forward declaration +static int knot_zone_diff_rdata(const knot_rrset_t *rrset1, + const knot_rrset_t *rrset2, + knot_changeset_t *changeset); + +static int knot_zone_diff_load_soas(const knot_zone_contents_t *zone1, + const knot_zone_contents_t *zone2, + knot_changeset_t *changeset) +{ + if (zone1 == NULL || zone2 == NULL || changeset == NULL) { + return KNOT_EBADARG; + } + + const knot_node_t *apex1 = knot_zone_contents_apex(zone1); + const knot_node_t *apex2 = knot_zone_contents_apex(zone2); + if (apex1 == NULL || apex2 == NULL) { + dbg_zonediff("zone_diff: " + "both zones must have apex nodes.\n"); + return KNOT_EBADARG; + } + + knot_rrset_t *soa_rrset1 = knot_node_get_rrset(apex1, KNOT_RRTYPE_SOA); + knot_rrset_t *soa_rrset2 = knot_node_get_rrset(apex2, KNOT_RRTYPE_SOA); + if (soa_rrset1 == NULL || soa_rrset2 == NULL) { + dbg_zonediff("zone_diff: " + "both zones must have apex nodes.\n"); + return KNOT_EBADARG; + } + + if (knot_rrset_rdata(soa_rrset1) == NULL || + knot_rrset_rdata(soa_rrset2) == NULL) { + dbg_zonediff("zone_diff: " + "both zones must have apex nodes with SOA " + "RRs.\n"); + return KNOT_EBADARG; + } + + int64_t soa_serial1 = + knot_rdata_soa_serial(knot_rrset_rdata(soa_rrset1)); + if (soa_serial1 == -1) { + dbg_zonediff("zone_diff: load_soas: Got bad SOA.\n"); + } + + int64_t soa_serial2 = + knot_rdata_soa_serial(knot_rrset_rdata(soa_rrset2)); + + if (soa_serial2 == -1) { + dbg_zonediff("zone_diff: load_soas: Got bad SOA.\n"); + } + + if (ns_serial_compare(soa_serial1, soa_serial2) == 0) { + dbg_zonediff("zone_diff: " + "second zone must have higher serial than the " + "first one. (%lld vs. %lld)\n", + soa_serial1, soa_serial2); + return KNOT_ENODIFF; + } + + if (ns_serial_compare(soa_serial1, soa_serial2) > 0) { + dbg_zonediff("zone_diff: " + "second zone must have higher serial than the " + "first one. (%lld vs. %lld)\n", + soa_serial1, soa_serial2); + return KNOT_ERANGE; + } + + /* We will not touch SOA later, now is the time to handle RRSIGs. */ + int ret = knot_zone_diff_rdata(knot_rrset_rrsigs(soa_rrset1), + knot_rrset_rrsigs(soa_rrset2), + changeset); + if (ret != KNOT_EOK) { + dbg_zonediff_verb("zone_diff: load_soas: Failed to diff SOAs' RRSIGs." + " Reason: %s.\n", knot_strerror(ret)); + /* This might not necasarilly be an error. */ + } + + assert(changeset); + + ret = knot_rrset_deep_copy(soa_rrset1, &changeset->soa_from, 1); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: load_soas: Cannot copy RRSet.\n"); + return ret; + } + + /* We MUST NOT save this RRSIG. */ + knot_rrset_deep_free(&changeset->soa_from->rrsigs, 1, 1, 1); + assert(changeset->soa_from->rrsigs == NULL); + + ret = knot_rrset_deep_copy(soa_rrset2, &changeset->soa_to, 1); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: load_soas: Cannot copy RRSet.\n"); + return ret; + } + + knot_rrset_deep_free(&changeset->soa_to->rrsigs, 1, 1, 1); + assert(changeset->soa_to->rrsigs == NULL); + + changeset->serial_from = soa_serial1; + changeset->serial_to = soa_serial2; + + dbg_zonediff_verb("zone_diff: load_soas: SOAs diffed. (%lld -> %lld)\n", + soa_serial1, soa_serial2); + + return KNOT_EOK; +} + +/*!< \todo Only use add or remove function, not both as they are the same. */ +/*!< \todo Also, this might be all handled by function in changesets.h!!! */ +static int knot_zone_diff_changeset_add_rrset(knot_changeset_t *changeset, + const knot_rrset_t *rrset) +{ + /* Remove all RRs of the RRSet. */ + if (changeset == NULL || rrset == NULL) { + dbg_zonediff("zone_diff: add_rrset: NULL parameters.\n"); + return KNOT_EBADARG; + } + + if (knot_rrset_rdata_rr_count(rrset) == 0) { + dbg_zonediff_detail("zone_diff: Nothing to add.\n"); + return KNOT_EOK; + } + + dbg_zonediff_detail("zone_diff: add_rrset: Adding RRSet (%d RRs):\n", + knot_rrset_rdata_rr_count(rrset)); + knot_rrset_dump(rrset, 1); + + knot_rrset_t *rrset_copy = NULL; + int ret = knot_rrset_deep_copy(rrset, &rrset_copy, 1); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: add_rrset: Cannot copy RRSet.\n"); + return ret; + } + if (rrset_copy->rrsigs != NULL) { + knot_rrset_deep_free(&rrset_copy->rrsigs, 1, 1, 1); + } + assert(knot_rrset_rrsigs(rrset_copy) == NULL); + + ret = knot_changeset_add_new_rr(changeset, rrset_copy, + XFRIN_CHANGESET_ADD); + if (ret != KNOT_EOK) { + /* We have to free the copy now! */ + knot_rrset_deep_free(&rrset_copy, 1, 1, 1); + dbg_zonediff("zone_diff: add_rrset: Could not add RRSet. " + "Reason: %s.\n", knot_strerror(ret)); + return ret; + } + + return KNOT_EOK; +} + +static int knot_zone_diff_changeset_remove_rrset(knot_changeset_t *changeset, + const knot_rrset_t *rrset) +{ + /* Remove all RRs of the RRSet. */ + if (changeset == NULL) { + dbg_zonediff("zone_diff: remove_rrset: NULL parameters.\n"); + return KNOT_EBADARG; + } + + if (rrset == NULL) { + return KNOT_EOK; + } + + if (knot_rrset_rdata_rr_count(rrset) == 0) { + dbg_zonediff_detail("zone_diff: Nothing to remove.\n"); + return KNOT_EOK; + } + + dbg_zonediff_detail("zone_diff: remove_rrset: Removing RRSet (%d RRs):\n", + knot_rrset_rdata_rr_count(rrset)); + knot_rrset_dump(rrset, 1); + + knot_rrset_t *rrset_copy = NULL; + int ret = knot_rrset_deep_copy(rrset, &rrset_copy, 1); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: remove_rrset: Cannot copy RRSet.\n"); + return ret; + } + if (rrset_copy->rrsigs != NULL) { + knot_rrset_deep_free(&rrset_copy->rrsigs, 1, 1, 1); + } + assert(knot_rrset_rrsigs(rrset_copy) == NULL); + + ret = knot_changeset_add_new_rr(changeset, rrset_copy, + XFRIN_CHANGESET_REMOVE); + if (ret != KNOT_EOK) { + /* We have to free the copy now. */ + knot_rrset_deep_free(&rrset_copy, 1, 1, 1); + dbg_zonediff("zone_diff: remove_rrset: Could not remove RRSet. " + "Reason: %s.\n", knot_strerror(ret)); + return ret; + } + + return KNOT_EOK; +} + +static int knot_zone_diff_add_node(const knot_node_t *node, + knot_changeset_t *changeset) +{ + if (node == NULL || changeset == NULL) { + dbg_zonediff("zone_diff: add_node: NULL arguments.\n"); + return KNOT_EBADARG; + } + + /* Add all rrsets from node. */ + const knot_rrset_t **rrsets = knot_node_rrsets(node); + if (rrsets == NULL) { + /* Empty non-terminals - legal case. */ + dbg_zonediff_detail("zone_diff: Node has no RRSets.\n"); + return KNOT_EOK; + } + + for (uint i = 0; i < knot_node_rrset_count(node); i++) { + assert(rrsets[i]); + int ret = knot_zone_diff_changeset_add_rrset(changeset, + rrsets[i]); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: add_node: Cannot add RRSet (%s).\n", + knot_strerror(ret)); + free(rrsets); + return ret; + } + } + + free(rrsets); + + return KNOT_EOK; +} + +static int knot_zone_diff_remove_node(knot_changeset_t *changeset, + const knot_node_t *node) +{ + if (changeset == NULL || node == NULL) { + dbg_zonediff("zone_diff: remove_node: NULL parameters.\n"); + return KNOT_EBADARG; + } + + dbg_zonediff("zone_diff: remove_node: Removing node:\n"); +dbg_zonediff_exec_detail( + knot_node_dump((knot_node_t *)node, 1); +); + + const knot_rrset_t **rrsets = knot_node_rrsets(node); + if (rrsets == NULL) { + dbg_zonediff_verb("zone_diff: remove_node: " + "Nothing to remove.\n"); + return KNOT_EOK; + } + + dbg_zonediff_detail("zone_diff: remove_node: Will be removing %d RRSets.\n", + knot_node_rrset_count(node)); + + /* Remove all the RRSets of the node. */ + for (uint i = 0; i < knot_node_rrset_count(node); i++) { + int ret = knot_zone_diff_changeset_remove_rrset(changeset, + rrsets[i]); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: remove_node: Failed to " + "remove rrset. Error: %s\n", + knot_strerror(ret)); + free(rrsets); + return ret; + } + } + + free(rrsets); + + return KNOT_EOK; +} + +static int knot_zone_diff_rdata_return_changes(const knot_rrset_t *rrset1, + const knot_rrset_t *rrset2, + knot_rrset_t **changes) +{ + if (rrset1 == NULL || rrset2 == NULL) { + dbg_zonediff("zone_diff: diff_rdata: NULL arguments. (%p) (%p).\n", + rrset1, rrset2); + return KNOT_EBADARG; + } + + /* + * Take one rdata from first list and search through the second list + * looking for an exact match. If no match occurs, it means that this + * particular RR has changed. + * After the list has been traversed, we have a list of + * changed/removed rdatas. This has awful computation time. + */ + dbg_zonediff_detail("zone_diff: diff_rdata: Diff of %s, type=%s. " + "RR count 1=%d RR count 2=%d.\n", + knot_dname_to_str(rrset1->owner), + knot_rrtype_to_string(rrset1->type), + knot_rrset_rdata_rr_count(rrset1), + knot_rrset_rdata_rr_count(rrset2)); + + /* Create fake RRSet, it will be easier to handle. */ + *changes = knot_rrset_new(knot_rrset_get_owner(rrset1), + knot_rrset_type(rrset1), + knot_rrset_class(rrset1), + knot_rrset_ttl(rrset1)); + if (*changes == NULL) { + dbg_zonediff("zone_diff: diff_rdata: " + "Could not create RRSet with changes.\n"); + return KNOT_ENOMEM; + } + + knot_rrtype_descriptor_t *desc = + knot_rrtype_descriptor_by_type(knot_rrset_type(rrset1)); + assert(desc); + + const knot_rdata_t *tmp_rdata = knot_rrset_rdata(rrset1); + while(tmp_rdata != NULL) { + const knot_rdata_t *tmp_rdata_second_rrset = + knot_rrset_rdata(rrset2); + while ((tmp_rdata_second_rrset != NULL) && + (knot_rdata_compare(tmp_rdata, + tmp_rdata_second_rrset, + desc->wireformat) != 0)) { + tmp_rdata_second_rrset = + knot_rrset_rdata_next(rrset2, + tmp_rdata_second_rrset); + } + if (tmp_rdata_second_rrset == NULL) { + /* + * This means that the while cycle above has finished + * because the list was traversed - there's no match. + */ + dbg_zonediff("zone_diff: diff_rdata: " + "No match for RR (type=%s owner=%s).\n", + knot_rrtype_to_string(knot_rrset_type(rrset1)), + knot_dname_to_str(rrset1->owner)); + /* Make a copy of tmp_rdata. */ + knot_rdata_t *tmp_rdata_copy = + knot_rdata_deep_copy(tmp_rdata, + knot_rrset_type(rrset1), + 1); + int ret = knot_rrset_add_rdata(*changes, + tmp_rdata_copy); + /*!< \todo dispose of the copy. */ + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: diff_rdata: " + "Could not add rdata to rrset."); + knot_rrset_deep_free(changes, 1, 1, 0); + return ret; + } + } else { + dbg_zonediff_detail("zone_diff: diff_rdata: " + "Found matching RR for type %s.\n", + knot_rrtype_to_string(rrset1->type)); + } + tmp_rdata = knot_rrset_rdata_next(rrset1, tmp_rdata); + } + return KNOT_EOK; +} + +static int knot_zone_diff_rdata(const knot_rrset_t *rrset1, + const knot_rrset_t *rrset2, + knot_changeset_t *changeset) +{ + if ((changeset == NULL) || (rrset1 == NULL && rrset2 == NULL)) { + dbg_zonediff("zone_diff: diff_rdata: NULL arguments.\n"); + return KNOT_EBADARG; + } + /* + * The easiest solution is to remove all the RRs that had no match and + * to add all RRs that had no match, but those from second RRSet. */ + + /* Get RRs to remove from zone. */ + knot_rrset_t *to_remove = NULL; + if (rrset1 != NULL && rrset2 == NULL) { + assert(rrset1->type == KNOT_RRTYPE_RRSIG); + dbg_zonediff_detail("zone_diff: diff_rdata: RRSIG will be " + "removed.\n"); + int ret = knot_rrset_deep_copy(rrset1, &to_remove, 1); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: diff_rdata: Could not copy rrset. " + "Error: %s.\n", knot_strerror(ret)); + return ret; + } + } else if (rrset1 != NULL && rrset2 != NULL) { + int ret = knot_zone_diff_rdata_return_changes(rrset1, rrset2, + &to_remove); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: diff_rdata: Could not get changes. " + "Error: %s.\n", knot_strerror(ret)); + return ret; + } + } else { + dbg_zonediff("zone_diff: diff_rdata: These are not the diffs you " + "are looking for.\n"); + } + + dbg_zonediff_detail("zone_diff: diff_rdata: To remove:\n"); + knot_rrset_dump(to_remove, 1); + + int ret = knot_zone_diff_changeset_remove_rrset(changeset, + to_remove); + if (ret != KNOT_EOK) { + knot_rrset_deep_free(&to_remove, 1, 1, 1); + dbg_zonediff("zone_diff: diff_rdata: Could not remove RRs. " + "Error: %s.\n", knot_strerror(ret)); + return ret; + } + + /* Copy was made in add_rrset function, we can free now. */ + knot_rrset_deep_free(&to_remove, 1, 1, 1); + + /* Get RRs to add to zone. */ + knot_rrset_t *to_add = NULL; + if (rrset2 != NULL && rrset1 == NULL) { + assert(rrset2->type == KNOT_RRTYPE_RRSIG); + dbg_zonediff_detail("zone_diff: diff_rdata: RRSIG will be " + "added.\n"); + int ret = knot_rrset_deep_copy(rrset2, &to_add, 1); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: diff_rdata: Could not copy rrset. " + "Error: %s.\n", knot_strerror(ret)); + return ret; + } + } else if (rrset1 != NULL && rrset2 != NULL) { + ret = knot_zone_diff_rdata_return_changes(rrset2, rrset1, + &to_add); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: diff_rdata: Could not get changes. " + "Error: %s.\n", knot_strerror(ret)); + return ret; + } + } else { + dbg_zonediff("zone_diff: diff_rdata: These are not the diffs you " + "are looking for.\n"); + } + + dbg_zonediff_detail("zone_diff: diff_rdata: To add:\n"); + knot_rrset_dump(to_add, 1); + + ret = knot_zone_diff_changeset_add_rrset(changeset, + to_add); + if (ret != KNOT_EOK) { + knot_rrset_deep_free(&to_add, 1, 1, 1); + dbg_zonediff("zone_diff: diff_rdata: Could not remove RRs. " + "Error: %s.\n", knot_strerror(ret)); + return ret; + } + + /* Copy was made in add_rrset function, we can free now. */ + knot_rrset_deep_free(&to_add, 1, 1, 1); + + return KNOT_EOK; +} + +static int knot_zone_diff_rrsets(const knot_rrset_t *rrset1, + const knot_rrset_t *rrset2, + knot_changeset_t *changeset) +{ +// if (rrset1 == NULL || rrset2 == NULL) { +// /* This could happen when diffing RRSIGs. */ +// if (rrset1 == NULL && rrset2 != NULL) { +// dbg_zonediff("zone_diff: diff_rrsets: RRSIG missing in first" +// " rrset1.\n"); +// int ret = +// knot_zone_diff_changeset_add_rrset(changeset, +// rrset2); +// if (ret != KNOT_EOK) { +// dbg_zonediff("zone_diff: diff_rrsets: " +// "Cannot add RRSIG. (%s)\n", +// knot_strerror(ret)); +// } +// } else if (rrset1 != NULL && rrset2 == NULL) { +// dbg_zonediff("zone_diff: diff_rrsets: RRSIG missing in second" +// " rrset1.\n"); +// int ret = +// knot_zone_diff_changeset_remove_rrset(changeset, +// rrset1); +// if (ret != KNOT_EOK) { +// dbg_zonediff("zone_diff: diff_rrsets: " +// "Cannot remove RRSIG. (%s)\n", +// knot_strerror(ret)); +// } +// } +// dbg_zonediff_detail("zone_diff: diff_rrsets: " +// "NULL arguments (RRSIGs?). (%p) (%p)\n", +// rrset1, rrset2); +// return KNOT_EOK; +// } + + assert(knot_dname_compare(knot_rrset_owner(rrset1), + knot_rrset_owner(rrset2)) == 0); + assert(knot_rrset_type(rrset1) == knot_rrset_type(rrset2)); + + int ret = knot_zone_diff_rdata(knot_rrset_rrsigs(rrset1), + knot_rrset_rrsigs(rrset2), changeset); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: diff_rrsets (%s:%s): Failed to diff RRSIGs. " + "They were: %p %p. (%s).\n", + knot_dname_to_str(rrset1->owner), + knot_rrtype_to_string(rrset1->type), + rrset1->rrsigs, + rrset2->rrsigs, knot_strerror(ret)); + } + + /* RRs (=rdata) have to be cross-compared, unfortunalely. */ + return knot_zone_diff_rdata(rrset1, rrset2, changeset); +} + +/*!< \todo this could be generic function for adding / removing. */ +static void knot_zone_diff_node(knot_node_t *node, void *data) +{ + if (node == NULL || data == NULL) { + dbg_zonediff("zone_diff: diff_node: NULL arguments.\n"); + return; + } + + struct zone_diff_param *param = (struct zone_diff_param *)data; + if (param->changeset == NULL || param->contents == NULL) { + dbg_zonediff("zone_diff: diff_node: NULL arguments.\n"); + param->ret = KNOT_EBADARG; + return; + } + + if (param->ret != KNOT_EOK) { + /* Error occured before, no point in continuing. */ + dbg_zonediff_detail("zone_diff: diff_node: error: %s\n", + knot_strerror(param->ret)); + return; + } + + /* + * First, we have to search the second tree to see if there's according + * node, if not, the whole node has been removed. + */ + const knot_node_t *node_in_second_tree = NULL; + const knot_dname_t *node_owner = knot_node_owner(node); + assert(node_owner); + if (!param->nsec3) { + node_in_second_tree = + knot_zone_contents_find_node(param->contents, + node_owner); + } else { + dbg_zonediff_verb("zone_diff: diff_node: NSEC3 zone.\n"); + node_in_second_tree = + knot_zone_contents_find_nsec3_node(param->contents, + node_owner); + } + + if (node_in_second_tree == NULL) { + dbg_zonediff_detail("zone_diff: diff_node: Node %s is not " + "in the second tree.\n", + knot_dname_to_str(node_owner)); + int ret = knot_zone_diff_remove_node(param->changeset, + node); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: failed to remove node.\n"); + param->ret = ret; + return; + } + param->ret = KNOT_EOK; + return; + } + + assert(node_in_second_tree != node); + + dbg_zonediff_detail("zone_diff: diff_node: Node %s is present in " + "both trees.\n", knot_dname_to_str(node_owner)); + /* The nodes are in both trees, we have to diff each RRSet. */ + const knot_rrset_t **rrsets = knot_node_rrsets(node); + if (rrsets == NULL) { + dbg_zonediff("zone_diff: Node in first tree has no RRSets.\n"); + /* + * If there are no RRs in the first tree, all of the RRs + * in the second tree will have to be inserted to ADD section. + */ + int ret = knot_zone_diff_add_node(node_in_second_tree, + param->changeset); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: diff_node: " + "Could not add node from second tree. " + "Reason: %s.\n", knot_strerror(ret)); + } + param->ret = ret; + return; + } + + for (uint i = 0; i < knot_node_rrset_count(node); i++) { + /* Search for the RRSet in the node from the second tree. */ + const knot_rrset_t *rrset = rrsets[i]; + assert(rrset); + + /* SOAs are handled explicitly. */ + if (knot_rrset_type(rrset) == KNOT_RRTYPE_SOA) { + continue; + } + + const knot_rrset_t *rrset_from_second_node = + knot_node_rrset(node_in_second_tree, + knot_rrset_type(rrset)); + if (rrset_from_second_node == NULL) { + dbg_zonediff("zone_diff: diff_node: There is no counterpart " + "for RRSet of type %s in second tree.\n", + knot_rrtype_to_string(knot_rrset_type(rrset))); + /* RRSet has been removed. Make a copy and remove. */ + assert(rrset); + int ret = knot_zone_diff_changeset_remove_rrset( + param->changeset, + rrset); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: diff_node: " + "Failed to remove RRSet.\n"); + param->ret = ret; + free(rrsets); + return; + } + } else { + dbg_zonediff("zone_diff: diff_node: There is a counterpart " + "for RRSet of type %s in second tree.\n", + knot_rrtype_to_string(knot_rrset_type(rrset))); + /* Diff RRSets. */ + int ret = knot_zone_diff_rrsets(rrset, + rrset_from_second_node, + param->changeset); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: " + "Failed to diff RRSets.\n"); + param->ret = ret; + free(rrsets); + return; + } + +// dbg_zonediff_verb("zone_diff: diff_node: Changes in " +// "RRSIGs.\n"); +// /*! \todo There is ad-hoc solution in the function, maybe handle here. */ +// ret = knot_zone_diff_rrsets(rrset->rrsigs, +// rrset_from_second_node->rrsigs, +// param->changeset); +// if (ret != KNOT_EOK) { +// dbg_zonediff("zone_diff: " +// "Failed to diff RRSIGs.\n"); +// param->ret = ret; +// return; +// } + } + } + + free(rrsets); + + /*! \todo move to one function with the code above. */ + rrsets = knot_node_rrsets(node_in_second_tree); + if (rrsets == NULL) { + dbg_zonediff("zone_diff: Node in second tree has no RRSets.\n"); + /* + * This can happen when node in second + * tree is empty non-terminal and as such has no RRs. + * Whole node from the first tree has to be removed. + */ + // TODO following code creates duplicated RR in diff. + // IHMO such case should be handled here +// int ret = knot_zone_diff_remove_node(param->changeset, +// node); +// if (ret != KNOT_EOK) { +// dbg_zonediff("zone_diff: diff_node: " +// "Cannot remove node. Reason: %s.\n", +// knot_strerror(ret)); +// } + param->ret = KNOT_EOK; + return; + } + + for (uint i = 0; i < knot_node_rrset_count(node_in_second_tree); i++) { + /* Search for the RRSet in the node from the second tree. */ + const knot_rrset_t *rrset = rrsets[i]; + assert(rrset); + + /* SOAs are handled explicitly. */ + if (knot_rrset_type(rrset) == KNOT_RRTYPE_SOA) { + continue; + } + + const knot_rrset_t *rrset_from_first_node = + knot_node_rrset(node, + knot_rrset_type(rrset)); + if (rrset_from_first_node == NULL) { + dbg_zonediff("zone_diff: diff_node: There is no counterpart " + "for RRSet of type %s in first tree.\n", + knot_rrtype_to_string(knot_rrset_type(rrset))); + /* RRSet has been added. Make a copy and add. */ + assert(rrset); + int ret = knot_zone_diff_changeset_add_rrset( + param->changeset, + rrset); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: diff_node: " + "Failed to add RRSet.\n"); + param->ret = ret; + free(rrsets); + return; + } + } else { + /* Already handled. */ + ; + } + } + + free(rrsets); + + assert(param->ret == KNOT_EOK); +} + +/*!< \todo possibly not needed! */ +static void knot_zone_diff_add_new_nodes(knot_node_t *node, void *data) +{ + assert(node); + if (node == NULL || data == NULL) { + dbg_zonediff("zone_diff: add_new_nodes: NULL arguments.\n"); + return; + } + + struct zone_diff_param *param = (struct zone_diff_param *)data; + if (param->changeset == NULL || param->contents == NULL) { + dbg_zonediff("zone_diff: add_new_nodes: NULL arguments.\n"); + param->ret = KNOT_EBADARG; + return; + } + + if (param->ret != KNOT_EOK) { + /* Error occured before, no point in continuing. */ + dbg_zonediff_detail("zone_diff: add_new_nodes: error: %s\n", + knot_strerror(param->ret)); + return; + } + + /* + * If a node is not present in the second zone, it is a new node + * and has to be added to changeset. Differencies on the RRSet level are + * already handled. + */ + const knot_zone_contents_t *other_zone = param->contents; + assert(other_zone); + + const knot_dname_t *node_owner = knot_node_owner(node); + /* + * Node should definitely have an owner, otherwise it would not be in + * the tree. + */ + assert(node_owner); + + knot_node_t *new_node = NULL; + if (!param->nsec3) { + new_node = knot_zone_contents_get_node(other_zone, node_owner); + } else { + new_node = knot_zone_contents_get_nsec3_node(other_zone, + node_owner); + } + + if (!new_node) { + assert(node); + int ret = knot_zone_diff_add_node(node, param->changeset); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: add_new_nodes: Cannot add " + "node: %s to changeset. Reason: %s.\n", + knot_dname_to_str(node->owner), + knot_strerror(ret)); + } + } + + assert(param->ret == KNOT_EOK); +} + +int knot_zone_contents_diff(const knot_zone_contents_t *zone1, + const knot_zone_contents_t *zone2, + knot_changeset_t *changeset) +{ + if (zone1 == NULL || zone2 == NULL) { + dbg_zonediff("zone_diff: NULL argument(s).\n"); + return KNOT_EBADARG; + } + +// /* Create changeset structure. */ +// *changeset = malloc(sizeof(knot_changeset_t)); +// if (*changeset == NULL) { +// ERR_ALLOC_FAILED; +// return KNOT_ENOMEM; +// } + memset(changeset, 0, sizeof(knot_changeset_t)); + + /* Settle SOAs first. */ + int ret = knot_zone_diff_load_soas(zone1, zone2, changeset); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: loas_SOAs failed with error: %s\n", + knot_strerror(ret)); + return ret; + } + + dbg_zonediff("zone_diff: SOAs loaded.\n"); + + /* Traverse one tree, compare every node, each RRSet with its rdata. */ + struct zone_diff_param param; + param.contents = zone2; + param.nsec3 = 0; + param.changeset = changeset; + param.ret = KNOT_EOK; + ret = knot_zone_contents_tree_apply_inorder( + (knot_zone_contents_t *)zone1, + knot_zone_diff_node, + ¶m); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: Tree traversal failed " + "with error: %s. Error from inner function: %s\n", + knot_strerror(ret), + knot_strerror(param.ret)); + return ret; + } + + /* Do the same for NSEC3 nodes. */ + param.nsec3 = 1; + ret = knot_zone_contents_nsec3_apply_inorder((knot_zone_contents_t *)zone1, knot_zone_diff_node, + ¶m); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: Tree traversal failed " + "with error: %s\n", + knot_strerror(ret)); + return ret; + } + + /* + * Some nodes may have been added. The code above will not notice, + * we have to go through the second tree and add missing nodes to + * changeset. + */ + param.nsec3 = 0; + param.contents = zone1; + ret = knot_zone_contents_tree_apply_inorder((knot_zone_contents_t *)zone2, + knot_zone_diff_add_new_nodes, + ¶m); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: Tree traversal failed " + "with error: %s. Error from inner function: %s\n", + knot_strerror(ret), + knot_strerror(param.ret)); + return ret; + } + + /* NSEC3 nodes. */ + param.nsec3 = 1; + param.contents = zone1; + ret = knot_zone_contents_nsec3_apply_inorder((knot_zone_contents_t *)zone2, + knot_zone_diff_add_new_nodes, + ¶m); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: Tree traversal failed " + "with error: %s\n", + knot_strerror(ret)); + return ret; + } + + return KNOT_EOK; +} + +#ifdef KNOT_ZONEDIFF_DEBUG +#ifdef DEBUG_ENABLE_DETAILS +static void knot_zone_diff_dump_changeset(knot_changeset_t *ch) +{ + dbg_zonediff_detail("Changeset FROM: %d\n", ch->serial_from); + rrset_dump_text(ch->soa_from, stderr); + dbg_zonediff_detail("\n"); + dbg_zonediff_detail("Changeset TO: %d\n", ch->serial_to); + rrset_dump_text(ch->soa_to, stderr); + dbg_zonediff_detail("\n"); + dbg_zonediff_detail("Adding %d RRs.\n", ch->add_count); + dbg_zonediff_detail("Removing %d RRs.\n", ch->remove_count); + + dbg_zonediff_detail("ADD section:\n"); + dbg_zonediff_detail("**********************************************\n"); + for (int i = 0; i < ch->add_count; i++) { + rrset_dump_text(ch->add[i], stderr); + dbg_zonediff_detail("\n"); + } + dbg_zonediff_detail("REMOVE section:\n"); + dbg_zonediff_detail("**********************************************\n"); + for (int i = 0; i < ch->remove_count; i++) { + rrset_dump_text(ch->remove[i], stderr); + dbg_zonediff_detail("\n"); + } +} +#endif +#endif + +int knot_zone_diff_create_changesets(const knot_zone_contents_t *z1, + const knot_zone_contents_t *z2, + knot_changesets_t **changesets) +{ + if (z1 == NULL || z2 == NULL) { + dbg_zonediff("zone_diff: create_changesets: NULL arguments.\n"); + return KNOT_EBADARG; + } + /* Create changesets. */ + int ret = knot_changeset_allocate(changesets); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: create_changesets: " + "Could not allocate changesets." + "Reason: %s.\n", knot_strerror(ret)); + return ret; + } + + memset((*changesets)->sets, 0, sizeof(knot_changeset_t)); + + ret = knot_zone_contents_diff(z1, z2, (*changesets)->sets); + if (ret != KNOT_EOK) { + dbg_zonediff("zone_diff: create_changesets: " + "Could not diff zones. " + "Reason: %s.\n", knot_strerror(ret)); + return ret; + } + + (*changesets)->count = 1; + + dbg_zonediff("Changesets created successfully!\n"); + dbg_zonediff_detail("Changeset dump:\n"); +dbg_zonediff_exec_detail( + knot_zone_diff_dump_changeset((*changesets)->sets); +); + + return KNOT_EOK; +} + +/* Mostly just for testing. We only shall diff zones in memory later. */ +//int knot_zone_diff_zones(const char *zonefile1, const char *zonefile2) +//{ + /* Compile test zones. */ +// int ret = zone_read("example.com.", "/home/jan/test/testzone1", "tmpzone1.db", 0); +// assert(ret == KNOT_EOK); +// ret = zone_read("example.com.", "/home/jan/test/testzone2", "tmpzone2.db", 0); +// assert(ret == KNOT_EOK); +// /* Load test zones. */ +// zloader_t *loader = NULL; +// int ret = knot_zload_open(&loader, "tmpzone1.db"); +// assert(ret == KNOT_EOK); +// knot_zone_t *z1 = knot_zload_load(loader); +// ret = knot_zload_open(&loader, "tmpzone2.db"); +// assert(ret == KNOT_EOK); +// knot_zone_t *z2 = knot_zload_load(loader); +// assert(z1 && z2); +// knot_changeset_t *changeset = malloc(sizeof(knot_changeset_t)); +// memset(changeset, 0, sizeof(knot_changeset_t)); +// assert(knot_zone_contents_diff(z1->contents, z2->contents, +// changeset) == KNOT_EOK); +// dbg_zonediff("Changeset created: From=%d to=%d.\n", changeset.serial_from, +// changeset.serial_to); +//// knot_changesets_t chngsets; +//// chngsets->sets = malloc(sizeof(knot_changeset_t)); +//// chngsets->sets[0] = changeset; +//// chngsets->count = 1; +//// chngsets->allocated = 1; +//// knot_zone_contents_t *new_zone = NULL; +//// ret = xfrin_apply_changesets(z1, chngsets, &new_zone); +//// if (ret != KNOT_EOK) { +//// dbg_zonediff("Application of changesets failed. (%s)\n", +//// knot_strerror(ret)); +//// } + +//// assert(new_zone); + +// /* Dump creted zone. */ +//// FILE *f = fopen("testovani", "w"); +//// zone_dump_text(new_zone, f); + +// knot_zone_deep_free(&z2, 0); +// knot_zone_deep_free(&z1, 0); +//// knot_zone_contents_deep_free(&new_zone, 1); +//// knot_zone_free(&z1); + +// knot_free_changeset(&changeset); +// exit(0); +//} + diff --git a/src/tests/common/da_tests.h b/src/libknot/zone/zone-diff.h index d51b7be..6e0eb1d 100644..100755 --- a/src/tests/common/da_tests.h +++ b/src/libknot/zone/zone-diff.h @@ -14,12 +14,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef _KNOTD_DA_TESTS_H_ -#define _KNOTD_DA_TESTS_H_ +#ifndef _KNOT_ZONE_DIFF_H_ +#define _KNOT_ZONE_DIFF_H_ -#include "common/libtap/tap_unit.h" +#include "libknot/zone/zone-contents.h" +#include "libknot/updates/changesets.h" -/* Unit API. */ -unit_api da_tests_api; +/*! \brief zone1 -> zone2 */ +int knot_zone_diff_create_changesets(const knot_zone_contents_t *z1, + const knot_zone_contents_t *z2, + knot_changesets_t **changesets); -#endif /* _KNOTD_DA_TESTS_H_ */ +#endif // _KNOT_ZONE_DIFF_H_ diff --git a/src/libknot/zone/zone-tree.c b/src/libknot/zone/zone-tree.c index 2b79f86..7de460a 100644..100755 --- a/src/libknot/zone/zone-tree.c +++ b/src/libknot/zone/zone-tree.c @@ -110,7 +110,7 @@ static void knot_zone_tree_free_node(knot_zone_tree_node_t *node, knot_zone_tree_free_node(node->avl.avl_right, free_data); if (free_data) { - knot_node_free(&node->node, 0); + knot_node_free(&node->node); } free(node); @@ -132,8 +132,7 @@ static int knot_zone_tree_deep_copy_node(knot_zone_tree_node_t *from, } int ret = knot_node_shallow_copy(from->node, &(*to)->node); -// printf("Copied node: %p to node %p. New node1: %p, new node 2: %p\n", -// from->node, (*to)->node, from->node->new_node, (*to)->node->new_node); + if (ret != KNOT_EOK) { dbg_zone_verb("Failed to do shallow copy of node.\n"); free(*to); @@ -155,7 +154,7 @@ static int knot_zone_tree_deep_copy_node(knot_zone_tree_node_t *from, dbg_zone_verb("Failed to do shallow copy of right subtree.\n"); knot_zone_tree_free_node((*to)->avl.avl_left, 1); (*to)->avl.avl_left = NULL; - knot_node_free(&(*to)->node, 0); + knot_node_free(&(*to)->node); free(*to); *to = NULL; return ret; @@ -250,7 +249,7 @@ int knot_zone_tree_get(knot_zone_tree_t *tree, const knot_dname_t *owner, knot_zone_tree_node_t *n = TREE_FIND(tree, knot_zone_tree_node, avl, tmp); - knot_node_free(&tmp_data, 0); + knot_node_free(&tmp_data); free(tmp); if (n != NULL) { @@ -313,7 +312,7 @@ int knot_zone_tree_get_less_or_equal(knot_zone_tree_t *tree, int exact_match = TREE_FIND_LESS_EQUAL( tree, knot_zone_tree_node, avl, tmp, &f, &prev); - knot_node_free(&tmp_data, 0); + knot_node_free(&tmp_data); free(tmp); *found = (exact_match > 0) ? f->node : NULL; @@ -356,9 +355,17 @@ dbg_zone_exec_detail( /*! \todo Here we assume that the 'prev' pointer always points * to an empty non-terminal. */ + /*! \todo What did I mean by the previous TODO?? + * Nevertheless, it seems to me that node->prev can be + * an empty non-terminal too, cannot it? + */ + dbg_zone_detail("Previous: %p\n", prev->node); *previous = (knot_node_rrset_count(prev->node) == 0) ? knot_node_get_previous(prev->node) : prev->node; + dbg_zone_detail("Previous: %p, is empty: %d\n", *previous, + (*previous) ? knot_node_is_empty(*previous) + : -1); } assert(exact_match >= 0); @@ -399,11 +406,9 @@ int knot_zone_tree_remove(knot_zone_tree_t *tree, /*! \todo How to know if this was successful? */ TREE_REMOVE(tree, knot_zone_tree_node, avl, tmp); - knot_node_free(&tmp_data, 0); + knot_node_free(&tmp_data); free(tmp); -// *removed = (n) ? n->node : NULL; -// free(n); *removed = n; return KNOT_EOK; diff --git a/src/libknot/zone/zone-tree.h b/src/libknot/zone/zone-tree.h index ca65fe6..95b4e23 100644..100755 --- a/src/libknot/zone/zone-tree.h +++ b/src/libknot/zone/zone-tree.h @@ -39,8 +39,6 @@ typedef struct knot_zone_tree_node { TREE_ENTRY(knot_zone_tree_node) avl; /*! \brief Zone tree data. */ knot_node_t *node; - /*! \brief Owner of the node. */ -// knot_dname_t *owner; } knot_zone_tree_node_t; /*----------------------------------------------------------------------------*/ diff --git a/src/libknot/zone/zone.c b/src/libknot/zone/zone.c index 122b014..65f810d 100644..100755 --- a/src/libknot/zone/zone.c +++ b/src/libknot/zone/zone.c @@ -33,6 +33,12 @@ #include "hash/cuckoo-hash-table.h" #include "zone/zone-contents.h" +/*! \brief Adaptor for knot_zone_deep_free() */ +static void knot_zone_dtor(struct ref_t *p) { + knot_zone_t *z = (knot_zone_t *)p; + knot_zone_deep_free(&z, 0); +} + /*----------------------------------------------------------------------------*/ /* API functions */ /*----------------------------------------------------------------------------*/ @@ -55,6 +61,13 @@ knot_zone_t *knot_zone_new_empty(knot_dname_t *name) // save the zone name dbg_zone("Setting zone name.\n"); zone->name = name; + + /* Initialize reference counting. */ + ref_init(&zone->ref, knot_zone_dtor); + + /* Set reference counter to 1, caller should release it after use. */ + knot_zone_retain(zone); + return zone; } @@ -133,14 +146,18 @@ void knot_zone_set_version(knot_zone_t *zone, time_t version) short knot_zone_is_master(const knot_zone_t *zone) { - return zone->master; + return zone->flags & KNOT_ZONE_MASTER; } /*----------------------------------------------------------------------------*/ void knot_zone_set_master(knot_zone_t *zone, short master) { - zone->master = master; + if (master) { + zone->flags |= KNOT_ZONE_MASTER; + } else { + zone->flags &= ~KNOT_ZONE_MASTER; + } } /*----------------------------------------------------------------------------*/ @@ -175,6 +192,7 @@ knot_zone_contents_t *knot_zone_switch_contents(knot_zone_t *zone, knot_zone_contents_t *old_contents = rcu_xchg_pointer(&zone->contents, new_contents); + return old_contents; } @@ -192,7 +210,7 @@ void knot_zone_free(knot_zone_t **zone) && !knot_zone_contents_gen_is_old((*zone)->contents)) { // zone is in the middle of an update, report dbg_zone("Destroying zone that is in the middle of an " - "update.\n"); + "update.\n"); } knot_dname_release((*zone)->name); @@ -221,7 +239,7 @@ void knot_zone_deep_free(knot_zone_t **zone, int destroy_dname_table) && !knot_zone_contents_gen_is_old((*zone)->contents)) { // zone is in the middle of an update, report dbg_zone("Destroying zone that is in the middle of an " - "update.\n"); + "update.\n"); } dbg_zone_exec( @@ -241,3 +259,21 @@ dbg_zone_exec( free(*zone); *zone = NULL; } + +void knot_zone_set_dtor(knot_zone_t *zone, int (*dtor)(struct knot_zone *)) +{ + if (zone != NULL) { + zone->dtor = dtor; + } +} + +void knot_zone_set_flag(knot_zone_t *zone, knot_zone_flag_t flag, unsigned on) +{ + if (zone != NULL) { + if (on) { + zone->flags |= flag; + } else { + zone->flags &= ~flag; + } + } +} diff --git a/src/libknot/zone/zone.h b/src/libknot/zone/zone.h index 331ef1f..31ff2ac 100644..100755 --- a/src/libknot/zone/zone.h +++ b/src/libknot/zone/zone.h @@ -34,6 +34,7 @@ #include "nsec3.h" #include "zone/dname-table.h" #include "common/tree.h" +#include "common/ref.h" #include "hash/cuckoo-hash-table.h" #include "zone-tree.h" @@ -41,11 +42,6 @@ #include "zone/zone-contents.h" /*----------------------------------------------------------------------------*/ - -//typedef TREE_HEAD(avl_tree, knot_node) avl_tree_t; -//struct event_t; - -/*----------------------------------------------------------------------------*/ /*! * \brief Return values for search functions. * @@ -58,6 +54,15 @@ enum knot_zone_retvals { typedef enum knot_zone_retvals knot_zone_retvals_t; +/*! + * \brief Zone flags. + */ +typedef enum knot_zone_flag_t { + KNOT_ZONE_SLAVE = 0 << 0, /*! Slave zone */ + KNOT_ZONE_MASTER = 1 << 0, /*! Master zone. */ + KNOT_ZONE_DISCARDED = 1 << 1 /*! Zone waiting to be discarded. */ +} knot_zone_flag_t; + /*----------------------------------------------------------------------------*/ /*! @@ -68,14 +73,14 @@ typedef enum knot_zone_retvals knot_zone_retvals_t; * double-free errors when destroying the zone. */ struct knot_zone { + ref_t ref; /*!< Reference counting. */ knot_dname_t *name; knot_zone_contents_t *contents; time_t version; - /*! \todo Set when loading zone. */ - short master; + unsigned flags; void *data; /*!< Pointer to generic zone-related data. */ int (*dtor)(struct knot_zone *); /*!< Data destructor. */ @@ -88,7 +93,7 @@ typedef struct knot_zone knot_zone_t; /*! * \brief Creates new empty DNS zone. * - * \notice Zone will be created without contents. + * \note Zone will be created without contents. * * \param name Zone owner. * @@ -152,6 +157,54 @@ void knot_zone_free(knot_zone_t **zone); */ void knot_zone_deep_free(knot_zone_t **zone, int destroy_dname_table); +/*! + * \brief Set destructor and initialize reference counter to 1. + * + * \param zone Related zone. + * \param dtor Destructor. + */ +void knot_zone_set_dtor(knot_zone_t *zone, int (*dtor)(struct knot_zone *)); + +/*! + * \brief Increment reference counter for dname. + * + * \param zone Referenced zone. + */ + static inline void knot_zone_retain(knot_zone_t *zone) { + if (zone != NULL) { + ref_retain(&zone->ref); + } +} + +/*! + * \brief Decrement reference counter for dname. + * + * \param zone Referenced zone. + */ + static inline void knot_zone_release(knot_zone_t *zone) { + if (zone != NULL) { + ref_release(&zone->ref); + } +} + +/*! + * \brief Return zone flags. + * + * \param zone Zone. + */ +static inline unsigned knot_zone_flags(knot_zone_t *zone) { + return zone->flags; +} + +/*! + * \brief Set zone flag. + * + * \param zone Zone. + * \param flag Respected flag. + * \param on 1 to set, 0 to unset flag. + */ +void knot_zone_set_flag(knot_zone_t *zone, knot_zone_flag_t flag, unsigned on); + #endif /*! @} */ diff --git a/src/libknot/zone/zonedb.c b/src/libknot/zone/zonedb.c index a9b6545..43b4489 100644..100755 --- a/src/libknot/zone/zonedb.c +++ b/src/libknot/zone/zonedb.c @@ -51,11 +51,11 @@ static int knot_zonedb_compare_zone_names(void *p1, void *p2) int ret = knot_dname_compare(zone1->name, zone2->name); -dbg_zonedb_exec( +dbg_zonedb_exec_detail( char *name1 = knot_dname_to_str(zone1->name); char *name2 = knot_dname_to_str(zone2->name); - dbg_zonedb("Compared names %s and %s, result: %d.\n", - name1, name2, ret); + dbg_zonedb_detail("Compared names %s and %s, result: %d.\n", + name1, name2, ret); free(name1); free(name2); ); @@ -64,23 +64,6 @@ dbg_zonedb_exec( } /*----------------------------------------------------------------------------*/ - -//static int knot_zonedb_replace_zone_in_list(void **list_item, void **new_zone) -//{ -// assert(list_item != NULL); -// assert(*list_item != NULL); -// assert(new_zone != NULL); -// assert(*new_zone != NULL); - -// dbg_zonedb("Replacing list item %p with new zone %p\n", -// *list_item, *new_zone); - -// *list_item = *new_zone; - -// return 0; -//} - -/*----------------------------------------------------------------------------*/ /* API functions */ /*----------------------------------------------------------------------------*/ @@ -152,63 +135,13 @@ knot_zone_t *knot_zonedb_remove_zone(knot_zonedb_t *db, // remove the zone from the skip list, but do not destroy it gen_tree_remove(db->zone_tree, &dummy_zone); -// if (destroy_zone) { -// // properly destroy the zone and all its contents -// knot_zone_deep_free(&z, 0); -// } - db->zone_count--; - //return KNOT_EOK; return z; } /*----------------------------------------------------------------------------*/ -//knot_zone_t *knot_zonedb_replace_zone(knot_zonedb_t *db, -// knot_zone_t *zone) -//{ -// knot_zone_t *z = knot_zonedb_find_zone(db, -// knot_node_owner(knot_zone_apex(zone))); -// if (z == NULL) { -// return NULL; -// } - -// /*! \todo The replace should be atomic!!! */ - -// dbg_zonedb("Found zone: %p\n", z); - -// int ret = skip_remove(db->zones, -// (void *)knot_node_owner(knot_zone_apex(zone)), -// NULL, NULL); -// if (ret != 0) { -// return NULL; -// } - -// dbg_zonedb("Removed zone, return value: %d\n", ret); -// dbg_zonedb("Old zone: %p\n", z); - -// ret = skip_insert(db->zones, -// (void *)knot_node_owner(knot_zone_apex(zone)), -// (void *)zone, NULL); - -// dbg_zonedb("Inserted zone, return value: %d\n", ret); - -// if (ret != 0) { -// // return the removed zone back -// skip_insert(db->zones, -// (void *)knot_node_owner(knot_zone_apex(z)), -// (void *)z, NULL); -// /*! \todo There may be problems and the zone may remain -// removed. */ -// return NULL; -// } - -// return z; -//} - -/*----------------------------------------------------------------------------*/ - knot_zone_t *knot_zonedb_find_zone(const knot_zonedb_t *db, const knot_dname_t *zone_name) { @@ -229,11 +162,7 @@ const knot_zone_t *knot_zonedb_find_zone_for_name(knot_zonedb_t *db, knot_zone_t dummy_zone; dummy_zone.name = knot_dname_deep_copy(dname); void *found = NULL; - -// int exact_match = gen_tree_find_less_or_equal(db->zone_tree, -// &dummy_zone, -// &found); -// UNUSED(exact_match); + found = gen_tree_find(db->zone_tree, &dummy_zone); while (found == NULL && knot_dname_label_count(dummy_zone.name) > 0) { knot_dname_left_chop_no_copy(dummy_zone.name); @@ -351,54 +280,16 @@ static void delete_zone_from_db(void *node, void *data) knot_zone_t *zone = (knot_zone_t *)node; assert(zone); synchronize_rcu(); - knot_zone_deep_free(&zone, 0); + knot_zone_set_flag(zone, KNOT_ZONE_DISCARDED, 1); + knot_zone_release(zone); + zone = NULL; } void knot_zonedb_deep_free(knot_zonedb_t **db) { dbg_zonedb("Deleting zone db (%p).\n", *db); -// dbg_zonedb("Is it empty (%p)? %s\n", -// (*db)->zones, skip_is_empty((*db)->zones) ? "yes" : "no"); - -//dbg_zonedb_exec( -// int i = 1; -// char *name = NULL; -// while (zn != NULL) { -// dbg_zonedb("%d. zone: %p, key: %p\n", i, zn->value, -// zn->key); -// assert(zn->key == ((knot_zone_t *)zn->value)->apex->owner); -// name = knot_dname_to_str((knot_dname_t *)zn->key); -// dbg_zonedb(" zone name: %s\n", name); -// free(name); - -// zn = skip_next(zn); -// } - -// zn = skip_first((*db)->zones); -//); - -// while (zn != NULL) { -// zone = (knot_zone_t *)zn->value; -// assert(zone != NULL); - -// // remove the zone from the database -// skip_remove((*db)->zones, zn->key, NULL, NULL); -// // wait for all readers to finish -// synchronize_rcu; -// // destroy the zone -// knot_zone_deep_free(&zone, 0); - -// zn = skip_first((*db)->zones); -// } - -// assert(skip_is_empty((*db)->zones)); - -// skip_destroy_list(&(*db)->zones, NULL, NULL); gen_tree_destroy(&((*db)->zone_tree), delete_zone_from_db, NULL); assert((*db)->zone_tree == NULL); free(*db); *db = NULL; } - -/*----------------------------------------------------------------------------*/ - diff --git a/src/libknot/zone/zonedb.h b/src/libknot/zone/zonedb.h index d5a4992..81326bf 100644..100755 --- a/src/libknot/zone/zonedb.h +++ b/src/libknot/zone/zonedb.h @@ -85,9 +85,6 @@ int knot_zonedb_add_zone(knot_zonedb_t *db, knot_zone_t *zone); knot_zone_t * knot_zonedb_remove_zone(knot_zonedb_t *db, const knot_dname_t *zone_name); -//knot_zone_t *knot_zonedb_replace_zone(knot_zonedb_t *db, -// knot_zone_t *zone); - /*! * \brief Finds zone exactly matching the given zone name. * diff --git a/src/tests/README b/src/tests/README index 2f299ad..2f299ad 100644..100755 --- a/src/tests/README +++ b/src/tests/README diff --git a/src/tests/common/acl_tests.c b/src/tests/common/acl_tests.c index c1884cd..c1884cd 100644..100755 --- a/src/tests/common/acl_tests.c +++ b/src/tests/common/acl_tests.c diff --git a/src/tests/common/acl_tests.h b/src/tests/common/acl_tests.h index a928e2d..a928e2d 100644..100755 --- a/src/tests/common/acl_tests.h +++ b/src/tests/common/acl_tests.h diff --git a/src/tests/common/da_tests.c b/src/tests/common/da_tests.c deleted file mode 100644 index 627e8aa..0000000 --- a/src/tests/common/da_tests.c +++ /dev/null @@ -1,330 +0,0 @@ -/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include "tests/common/da_tests.h" -#include "common/dynamic-array.h" -#include <unistd.h> -#include <urcu.h> - -static int da_tests_count(int argc, char *argv[]); -static int da_tests_run(int argc, char *argv[]); - -/* - * Unit API. - */ -unit_api da_tests_api = { - "Dynamic array", - &da_tests_count, - &da_tests_run -}; - -/* - * Unit implementation. - */ - -static const int DA_TEST_COUNT = 5; -static const int RCU_THREADS = 3; -static const int DA_FRAGMENT = 10; -static const int DA_DEF_SIZE = 1000; -static const int DA_OPERATIONS = 1000; -enum Operations { - DA_RESERVE = 0, - DA_OCCUPY = 1, - DA_RELEASE = 2, - DA_OPCOUNT = 3 -}; - -static int da_tests_count(int argc, char *argv[]) -{ - return DA_TEST_COUNT; -} - -static void do_something(int loops) -{ - int i; - int res = 1; - - static const int LOOPS = 10000; - - for (int j = 1; j <= LOOPS; ++j) { - for (i = 1; i <= loops; ++i) { - res *= i; - } - } -} - -static void *test_rcu_routine(void *obj) -{ - rcu_register_thread(); - rcu_read_lock(); - - do_something(1000); - - rcu_read_unlock(); - rcu_unregister_thread(); - - return NULL; -} - -static int test_rcu_threads() -{ - // Create threads - pthread_t *threads = malloc(RCU_THREADS * sizeof(pthread_t)); - for (int i = 0; i < RCU_THREADS; ++i) { - if (pthread_create(&threads[i], NULL, test_rcu_routine, NULL)) { - diag("rcu: failed to create thread %d", i); - free(threads); - return 0; - } - } - - // Join threads - void *pret = NULL; - for (int i = 0; i < RCU_THREADS; ++i) { - if (pthread_join(threads[i], &pret)) { - diag("rcu: failed to join thread %d", i); - free(threads); - return 0; - } - } - - synchronize_rcu(); - free(threads); - - return 1; -} - -static int test_da_init(da_array_t *arr) -{ - return da_initialize(arr, DA_DEF_SIZE, sizeof(uint)) == 0; -} - -static int test_da_random_op(da_array_t *arr) -{ - unsigned seed = (unsigned)time(0); - uint allocated = DA_DEF_SIZE; - uint size = 0; - - for (int i = 0; i < DA_OPERATIONS; ++i) { - int r = rand_r(&seed) % DA_OPCOUNT; - int count = rand_r(&seed) % DA_FRAGMENT + 1; - - switch (r) { - - // Perform reserve operation - case DA_RESERVE: - if (da_reserve(arr, count) >= 0 && - size <= allocated) { - if ((allocated - size) < count) { - allocated *= 2; - } - } else { - diag("dynamic-array: da_reserve(%p, %d) failed" - " (size %d, alloc'd %d)", - arr, count, size, allocated); - return 0; - } - break; - - // Perform occupy operation - case DA_OCCUPY: - if (da_occupy(arr, count) == 0) { - uint *items = (uint *) da_get_items(arr); - for (int j = 0; j < da_get_count(arr); ++j) { - items[j] = rand_r(&seed); - } - if (size <= allocated && - (allocated - size) >= count) { - size += count; - } else { - return 0; - } - } else { - diag("dynamic-array: da_occupy(%p, %d) failed" - " (size %d, alloc'd %d)", - arr, count, size, allocated); - return 0; - } - break; - - // Perform release operation - case DA_RELEASE: - if (arr->count > 0) { - count = (rand_r(&seed) % DA_FRAGMENT) % arr->count; - da_release(arr, count); - - if (size <= allocated && size >= count) { - size -= count; - } else { - return 0; - } - } - break; - - default: - break; - } - - // Check allocated / size - if (allocated != arr->allocated || size != arr->count) { - diag("dynamic-array: allocated memory %d (expected %d)" - " size %d (expected %d) mismatch", - arr->allocated, allocated, arr->count, size); - return 0; - } - } - - return 1; -} - -void *test_da_read(void *obj) -{ - rcu_register_thread(); - rcu_read_lock(); - - unsigned seed = (unsigned)time(0); - da_array_t *arr = (da_array_t *) obj; - int index = rand_r(&seed) % da_get_count(arr); - - note(" dynamic-array: read thread"); - note(" read thread: saving pointer to %d. item", index); - uint *item = &((uint *) da_get_items(arr))[index]; - note(" read thread: before: pointer: %p item: %u", item, *item); - - do_something(100000); - - note(" read thread after: pointer: %p item: %u", item, *item); - rcu_read_unlock(); - note(" read thread unlocked: pointer: %p item: %u", item, *item); - - do_something(10000); - - note(" read thread: now the item should be deallocated"); - //note(" read thread: pointer: %p item: %u", item, *item); - - rcu_unregister_thread(); - - return NULL; -} - -static int test_da_resize_holding(da_array_t *arr) -{ - int ret = 1; - rcu_register_thread(); - pthread_t reader; - - // Create thread for reading - note("dynamic-array: creating read threads"); - if (pthread_create(&reader, NULL, test_da_read, (void *)arr)) { - diag("dynamic-array: failed to create reading thread", - __func__); - rcu_unregister_thread(); - return 0; - } - - // Wait some time, so the other thread gets the item for reading - do_something(5000); - - // Force resize - note(" dynamic-array: array resized"); - if (da_reserve(arr, arr->allocated - arr->count + 1) == -1) { - diag("dynamic-array: da_reserve(%p, %d) failed", arr, - arr->allocated - arr->count + 1); - ret = 0; - } - - //Wait for the thread to finish - void *pret = NULL; - if (pthread_join(reader, &pret)) { - diag("dynamic-array: failed to join reading thread", - __func__); - ret = 0; - } - - rcu_unregister_thread(); - return ret; -} - -static int test_da_resize(da_array_t *arr) -{ - unsigned seed = (unsigned)time(0); - int orig_count = da_get_count(arr); - note("dynamic-array: allocated: %d, items: %d", arr->allocated, - orig_count); - // store the items currently in the array - int *items = (int *)malloc(orig_count * sizeof(int)); - for (int i = 0; i < orig_count; ++i) { - items[i] = ((int *)da_get_items(arr))[i]; - } - - // force resize - int res = 0; - while ((res = da_reserve(arr, 10)) == 0) { - int i = da_get_count(arr); - da_occupy(arr, 10); - for (; i < da_get_count(arr); ++i) { - ((int *)da_get_items(arr))[i] = rand_r(&seed); - } - } - - if (res < 0) { - diag("dynamic-array: failed to reserve space"); - return 0; - } - - int errors = 0; - for (int i = 0; i < orig_count; ++i) { - if (items[i] != ((int *)da_get_items(arr))[i]) { - diag("dynamic-array: Wrong item on position %d." - "Should be: %d, " - "present value: %d", i, items[i], - ((int *)da_get_items(arr))[i]); - ++errors; - } - } - - free(items); - - return errors == 0; -} - -static int da_tests_run(int argc, char *argv[]) -{ - // Init - rcu_init(); - da_array_t array; - - // Test 1: test rcu - ok(test_rcu_threads(), "dynamic-array: rcu tests"); - - // Test 2: init - ok(test_da_init(&array), "dynamic-array: init"); - - // Test 3: reserve/occupy random operations - ok(test_da_random_op(&array), - "dynamic-array: randomized reserve/occupy/release"); - - // Test 4: resizing array while holding an item - ok(test_da_resize_holding(&array), - "dynamic-array: resize array while holding an item"); - - // Test 5: resize - ok(test_da_resize(&array), "dynamic-array: resize array"); - - // Cleanup - da_destroy(&array); - return 0; -} diff --git a/src/tests/common/events_tests.c b/src/tests/common/events_tests.c index 0acd706..0acd706 100644..100755 --- a/src/tests/common/events_tests.c +++ b/src/tests/common/events_tests.c diff --git a/src/tests/common/events_tests.h b/src/tests/common/events_tests.h index b54b6da..b54b6da 100644..100755 --- a/src/tests/common/events_tests.h +++ b/src/tests/common/events_tests.h diff --git a/src/tests/common/fdset_tests.c b/src/tests/common/fdset_tests.c index 08e0577..08e0577 100644..100755 --- a/src/tests/common/fdset_tests.c +++ b/src/tests/common/fdset_tests.c diff --git a/src/tests/common/fdset_tests.h b/src/tests/common/fdset_tests.h index d29e1a9..d29e1a9 100644..100755 --- a/src/tests/common/fdset_tests.h +++ b/src/tests/common/fdset_tests.h diff --git a/src/tests/common/skiplist_tests.c b/src/tests/common/skiplist_tests.c index 4fe99ec..4fe99ec 100644..100755 --- a/src/tests/common/skiplist_tests.c +++ b/src/tests/common/skiplist_tests.c diff --git a/src/tests/common/skiplist_tests.h b/src/tests/common/skiplist_tests.h index ff91706..ff91706 100644..100755 --- a/src/tests/common/skiplist_tests.h +++ b/src/tests/common/skiplist_tests.h diff --git a/src/tests/common/slab_tests.c b/src/tests/common/slab_tests.c index f362ca0..5724a23 100644..100755 --- a/src/tests/common/slab_tests.c +++ b/src/tests/common/slab_tests.c @@ -23,6 +23,11 @@ #include "common/slab/slab.h" #include "knot/common.h" +/*! \brief Type-safe maximum macro. */ +#define SLAB_MAX(a, b) \ + ({ typeof (a) _a = (a); typeof (b) _b = (b); _a > _b ? _a : _b; }) + + /* Explicitly ask for symbols, * as the constructor and destructor * aren't created for test modules. @@ -119,7 +124,7 @@ static int slab_tests_run(int argc, char *argv[]) for(int i = 0; i < alloc_count; ++i) { double roll = rand() / (double) RAND_MAX; size_t bsize = roll * 2048; - bsize = MAX(bsize, 8); + bsize = SLAB_MAX(bsize, 8); if ((ptrs_i == 0) || (roll < 0.6)) { void* m = slab_alloc_alloc(&alloc, bsize); if (m == 0) { diff --git a/src/tests/common/slab_tests.h b/src/tests/common/slab_tests.h index 4d45fb8..4d45fb8 100644..100755 --- a/src/tests/common/slab_tests.h +++ b/src/tests/common/slab_tests.h diff --git a/src/tests/files/sample_conf b/src/tests/files/sample_conf index b15fce5..b15fce5 100644..100755 --- a/src/tests/files/sample_conf +++ b/src/tests/files/sample_conf diff --git a/src/tests/knot/conf_tests.c b/src/tests/knot/conf_tests.c index 61520ea..61520ea 100644..100755 --- a/src/tests/knot/conf_tests.c +++ b/src/tests/knot/conf_tests.c diff --git a/src/tests/knot/conf_tests.h b/src/tests/knot/conf_tests.h index dfd2fd7..dfd2fd7 100644..100755 --- a/src/tests/knot/conf_tests.h +++ b/src/tests/knot/conf_tests.h diff --git a/src/tests/knot/dthreads_tests.c b/src/tests/knot/dthreads_tests.c index 982329b..982329b 100644..100755 --- a/src/tests/knot/dthreads_tests.c +++ b/src/tests/knot/dthreads_tests.c diff --git a/src/tests/knot/dthreads_tests.h b/src/tests/knot/dthreads_tests.h index e41bdc5..e41bdc5 100644..100755 --- a/src/tests/knot/dthreads_tests.h +++ b/src/tests/knot/dthreads_tests.h diff --git a/src/tests/knot/journal_tests.c b/src/tests/knot/journal_tests.c index 7c8125e..5c89de9 100644..100755 --- a/src/tests/knot/journal_tests.c +++ b/src/tests/knot/journal_tests.c @@ -34,7 +34,7 @@ unit_api journal_tests_api = { /* * Unit implementation. */ -static const int JOURNAL_TEST_COUNT = 20; +static const int JOURNAL_TEST_COUNT = 21; /*! \brief Generate random string with given length. */ static int randstr(char* dst, size_t len) @@ -76,6 +76,7 @@ static int journal_tests_run(int argc, char *argv[]) int tmp_fd = mkstemp(jfn_buf); ok(tmp_fd >= 0, "journal: create temporary file"); skip(tmp_fd < 0, JOURNAL_TEST_COUNT - 1); + close(tmp_fd); /* Test 2: Create journal. */ const char *jfilename = jfn_buf; @@ -139,7 +140,9 @@ static int journal_tests_run(int argc, char *argv[]) journal_close(journal); /* Recreate journal = NORMAL mode. */ - remove(jfilename); + if (remove(jfilename) < 0) { + diag("journal: couldn't remove filename"); + } fsize = 8092; jsize = 512; ret = journal_create(jfilename, jsize); @@ -199,7 +202,7 @@ static int journal_tests_run(int argc, char *argv[]) ok(j && ret == 0, "journal: mapped entry data integrity check"); endskip; - /* Test 17: Make a transaction. */ + /* Test 16: Make a transaction. */ uint64_t tskey = 0x75750000; ret = journal_trans_begin(j); ok(j && ret == 0, "journal: TRANS begin"); @@ -208,16 +211,16 @@ static int journal_tests_run(int argc, char *argv[]) journal_write(j, tskey + i, tmpbuf, sizeof(tmpbuf)); } - /* Test 18: Check if uncommited node exists. */ + /* Test 17: Check if uncommited node exists. */ ret = journal_read(j, tskey + rand() % 16, NULL, chk_buf); ok(j && ret != 0, "journal: check for uncommited node"); - /* Test 19: Commit transaction. */ + /* Test 18: Commit transaction. */ ret = journal_trans_commit(j); int read_ret = journal_read(j, tskey + rand() % 16, NULL, chk_buf); ok(j && ret == 0 && read_ret == 0, "journal: transaction commit"); - /* Test 20: Rollback transaction. */ + /* Test 19: Rollback transaction. */ tskey = 0x6B6B0000; journal_trans_begin(j); for (int i = 0; i < 16; ++i) { @@ -228,7 +231,7 @@ static int journal_tests_run(int argc, char *argv[]) read_ret = journal_read(j, tskey + rand() % 16, NULL, chk_buf); ok(j && ret == 0 && read_ret != 0, "journal: transaction rollback"); - /* Test 16: Write random data. */ + /* Test 20: Write random data. */ ret = 0; for (int i = 0; i < 512; ++i) { int key = i; @@ -258,16 +261,17 @@ static int journal_tests_run(int argc, char *argv[]) break; } } - - /* Test 16: Check data integrity. */ ok(j && ret == 0, "journal: sustained mmap r/w"); + /* Test 21: Open + create journal. */ + journal_close(j); + remove(jfilename); + j = journal_open(jfilename, fsize, 0, 0); + ok(j != NULL, "journal: open+create from scratch"); + /* Close journal. */ journal_close(j); - /* Close temporary file fd. */ - close(tmp_fd); - /* Delete journal. */ remove(jfilename); diff --git a/src/tests/knot/journal_tests.h b/src/tests/knot/journal_tests.h index beec8ca..beec8ca 100644..100755 --- a/src/tests/knot/journal_tests.h +++ b/src/tests/knot/journal_tests.h diff --git a/src/tests/knot/server_tests.c b/src/tests/knot/server_tests.c index 5ae04d8..5ae04d8 100644..100755 --- a/src/tests/knot/server_tests.c +++ b/src/tests/knot/server_tests.c diff --git a/src/tests/knot/server_tests.h b/src/tests/knot/server_tests.h index 43ad0c1..43ad0c1 100644..100755 --- a/src/tests/knot/server_tests.h +++ b/src/tests/knot/server_tests.h diff --git a/src/tests/libknot/files/parsed_data b/src/tests/libknot/files/parsed_data Binary files differindex 4027c92..4027c92 100644..100755 --- a/src/tests/libknot/files/parsed_data +++ b/src/tests/libknot/files/parsed_data diff --git a/src/tests/libknot/files/parsed_data_queries b/src/tests/libknot/files/parsed_data_queries Binary files differindex 5857c87..5857c87 100644..100755 --- a/src/tests/libknot/files/parsed_data_queries +++ b/src/tests/libknot/files/parsed_data_queries diff --git a/src/tests/libknot/files/raw_data b/src/tests/libknot/files/raw_data Binary files differindex f94236b..f94236b 100644..100755 --- a/src/tests/libknot/files/raw_data +++ b/src/tests/libknot/files/raw_data diff --git a/src/tests/libknot/files/raw_data_queries b/src/tests/libknot/files/raw_data_queries Binary files differindex 9062d5a..9062d5a 100644..100755 --- a/src/tests/libknot/files/raw_data_queries +++ b/src/tests/libknot/files/raw_data_queries diff --git a/src/tests/libknot/libknot/cuckoo_tests.c b/src/tests/libknot/libknot/cuckoo_tests.c index c1306a3..8d22e36 100644..100755 --- a/src/tests/libknot/libknot/cuckoo_tests.c +++ b/src/tests/libknot/libknot/cuckoo_tests.c @@ -15,6 +15,7 @@ */ #include <time.h> #include <assert.h> +#include <string.h> #include "tests/libknot/libknot/cuckoo_tests.h" diff --git a/src/tests/libknot/libknot/cuckoo_tests.h b/src/tests/libknot/libknot/cuckoo_tests.h index b6b0db8..b6b0db8 100644..100755 --- a/src/tests/libknot/libknot/cuckoo_tests.h +++ b/src/tests/libknot/libknot/cuckoo_tests.h diff --git a/src/tests/libknot/libknot/dname_table_tests.c b/src/tests/libknot/libknot/dname_table_tests.c index 0d00a44..0d00a44 100644..100755 --- a/src/tests/libknot/libknot/dname_table_tests.c +++ b/src/tests/libknot/libknot/dname_table_tests.c diff --git a/src/tests/libknot/libknot/dname_table_tests.h b/src/tests/libknot/libknot/dname_table_tests.h index f3088e9..f3088e9 100644..100755 --- a/src/tests/libknot/libknot/dname_table_tests.h +++ b/src/tests/libknot/libknot/dname_table_tests.h diff --git a/src/tests/libknot/libknot/dname_tests.c b/src/tests/libknot/libknot/dname_tests.c index 35ac230..35ac230 100644..100755 --- a/src/tests/libknot/libknot/dname_tests.c +++ b/src/tests/libknot/libknot/dname_tests.c diff --git a/src/tests/libknot/libknot/dname_tests.h b/src/tests/libknot/libknot/dname_tests.h index a7d75aa..a7d75aa 100644..100755 --- a/src/tests/libknot/libknot/dname_tests.h +++ b/src/tests/libknot/libknot/dname_tests.h diff --git a/src/tests/libknot/libknot/edns_tests.c b/src/tests/libknot/libknot/edns_tests.c index ac5d130..4d1a37a 100644..100755 --- a/src/tests/libknot/libknot/edns_tests.c +++ b/src/tests/libknot/libknot/edns_tests.c @@ -495,12 +495,13 @@ static int test_edns_has_option() */ for (int i = 0; i < TEST_EDNS; i++) { knot_opt_rr_t *edns = knot_edns_new(); - assert(edns->option_count == 0); if (edns == NULL) { ERR_ALLOC_FAILED; return 0; } + + assert(edns->option_count == 0); for (int j = 0; j < test_edns_data[i].option_count; j++) { if (knot_edns_add_option(edns, diff --git a/src/tests/libknot/libknot/edns_tests.h b/src/tests/libknot/libknot/edns_tests.h index 4553234..4553234 100644..100755 --- a/src/tests/libknot/libknot/edns_tests.h +++ b/src/tests/libknot/libknot/edns_tests.h diff --git a/src/tests/libknot/libknot/node_tests.c b/src/tests/libknot/libknot/node_tests.c index 10b01fa..b252982 100644..100755 --- a/src/tests/libknot/libknot/node_tests.c +++ b/src/tests/libknot/libknot/node_tests.c @@ -76,7 +76,7 @@ static int test_node_create() errors++; diag("Failed to create node structure"); } - knot_node_free(&tmp, 0); + knot_node_free(&tmp); } return (errors == 0); } @@ -134,7 +134,7 @@ static int test_node_add_rrset() diag("Values in found rrset are wrong"); } - knot_node_free(&tmp, 0); + knot_node_free(&tmp); } return (errors == 0); @@ -166,7 +166,7 @@ static int test_node_get_rrset() diag("Failed to get proper rrset from node"); } } - knot_node_free(&nodes[i], 0); + knot_node_free(&nodes[i]); } return (errors == 0); @@ -194,7 +194,7 @@ static int test_node_get_parent() errors++; diag("Failed to get proper parent from node"); } - knot_node_free(&nodes[i], 0); + knot_node_free(&nodes[i]); } return (errors == 0); } @@ -230,7 +230,7 @@ static int test_node_sorting() // last = *((uint16_t *)node->key); // } - knot_node_free(&tmp, 0); + knot_node_free(&tmp); return (errors == 0); } @@ -244,7 +244,7 @@ static int test_node_delete() tmp_node = knot_node_new(&test_nodes[i].owner, test_nodes[i].parent, 0); - knot_node_free(&tmp_node, 0); + knot_node_free(&tmp_node); errors += (tmp_node != NULL); } @@ -269,9 +269,9 @@ static int test_node_set_parent() diag("Parent node is wrongly set."); errors++; } - knot_node_free(&tmp_node, 0); + knot_node_free(&tmp_node); } - knot_node_free(&tmp_parent, 0); + knot_node_free(&tmp_parent); return (errors == 0); } @@ -289,7 +289,7 @@ static int test_node_free_rrsets() // errors += (tmp_node->rrsets != NULL); - knot_node_free(&tmp_node, 0); + knot_node_free(&tmp_node); } return (errors == 0); } diff --git a/src/tests/libknot/libknot/node_tests.h b/src/tests/libknot/libknot/node_tests.h index a90179f..a90179f 100644..100755 --- a/src/tests/libknot/libknot/node_tests.h +++ b/src/tests/libknot/libknot/node_tests.h diff --git a/src/tests/libknot/libknot/nsec3_tests.c b/src/tests/libknot/libknot/nsec3_tests.c index 7b95549..7b95549 100644..100755 --- a/src/tests/libknot/libknot/nsec3_tests.c +++ b/src/tests/libknot/libknot/nsec3_tests.c diff --git a/src/tests/libknot/libknot/nsec3_tests.h b/src/tests/libknot/libknot/nsec3_tests.h index 10e7ed9..10e7ed9 100644..100755 --- a/src/tests/libknot/libknot/nsec3_tests.h +++ b/src/tests/libknot/libknot/nsec3_tests.h diff --git a/src/tests/libknot/libknot/packet_tests.c b/src/tests/libknot/libknot/packet_tests.c index 916328d..916328d 100644..100755 --- a/src/tests/libknot/libknot/packet_tests.c +++ b/src/tests/libknot/libknot/packet_tests.c diff --git a/src/tests/libknot/libknot/packet_tests.h b/src/tests/libknot/libknot/packet_tests.h index 5a8ce03..5a8ce03 100644..100755 --- a/src/tests/libknot/libknot/packet_tests.h +++ b/src/tests/libknot/libknot/packet_tests.h diff --git a/src/tests/libknot/libknot/query_tests.c b/src/tests/libknot/libknot/query_tests.c index 1e4e081..1e4e081 100644..100755 --- a/src/tests/libknot/libknot/query_tests.c +++ b/src/tests/libknot/libknot/query_tests.c diff --git a/src/tests/libknot/libknot/query_tests.h b/src/tests/libknot/libknot/query_tests.h index 037ecab..037ecab 100644..100755 --- a/src/tests/libknot/libknot/query_tests.h +++ b/src/tests/libknot/libknot/query_tests.h diff --git a/src/tests/libknot/libknot/rdata_tests.c b/src/tests/libknot/libknot/rdata_tests.c index 0c53613..0c53613 100644..100755 --- a/src/tests/libknot/libknot/rdata_tests.c +++ b/src/tests/libknot/libknot/rdata_tests.c diff --git a/src/tests/libknot/libknot/rdata_tests.h b/src/tests/libknot/libknot/rdata_tests.h index 1f43c91..1f43c91 100644..100755 --- a/src/tests/libknot/libknot/rdata_tests.h +++ b/src/tests/libknot/libknot/rdata_tests.h diff --git a/src/tests/libknot/libknot/response_tests.c b/src/tests/libknot/libknot/response_tests.c index f40bb76..f40bb76 100644..100755 --- a/src/tests/libknot/libknot/response_tests.c +++ b/src/tests/libknot/libknot/response_tests.c diff --git a/src/tests/libknot/libknot/response_tests.h b/src/tests/libknot/libknot/response_tests.h index c9a117b..c9a117b 100644..100755 --- a/src/tests/libknot/libknot/response_tests.h +++ b/src/tests/libknot/libknot/response_tests.h diff --git a/src/tests/libknot/libknot/rrset_tests.c b/src/tests/libknot/libknot/rrset_tests.c index 41284df..41284df 100644..100755 --- a/src/tests/libknot/libknot/rrset_tests.c +++ b/src/tests/libknot/libknot/rrset_tests.c diff --git a/src/tests/libknot/libknot/rrset_tests.h b/src/tests/libknot/libknot/rrset_tests.h index b0787d6..b0787d6 100644..100755 --- a/src/tests/libknot/libknot/rrset_tests.h +++ b/src/tests/libknot/libknot/rrset_tests.h diff --git a/src/tests/libknot/libknot/tsig_tests.c b/src/tests/libknot/libknot/tsig_tests.c index e0a3d34..e0a3d34 100644..100755 --- a/src/tests/libknot/libknot/tsig_tests.c +++ b/src/tests/libknot/libknot/tsig_tests.c diff --git a/src/tests/libknot/libknot/tsig_tests.h b/src/tests/libknot/libknot/tsig_tests.h index 8ea15f6..8ea15f6 100644..100755 --- a/src/tests/libknot/libknot/tsig_tests.h +++ b/src/tests/libknot/libknot/tsig_tests.h diff --git a/src/tests/libknot/libknot/zone_tests.c b/src/tests/libknot/libknot/zone_tests.c index 72aae39..54cd38d 100644..100755 --- a/src/tests/libknot/libknot/zone_tests.c +++ b/src/tests/libknot/libknot/zone_tests.c @@ -95,13 +95,13 @@ static int test_zone_create(knot_zone_contents_t **zone) if ((*zone) == NULL) { diag("zone: Failed to create zone."); - knot_node_free(&node, 0); + knot_node_free(&node); return 0; } if ((*zone)->apex != node) { diag("zone: Zone apex not set right."); - knot_node_free(&node, 0); + knot_node_free(&node); return 0; } @@ -133,7 +133,7 @@ static int test_zone_add_node(knot_zone_contents_t *zone, int nsec3) : knot_zone_contents_add_node(zone, node, 0, 0, 0))) != 0) { diag("zone: Failed to insert node into zone (returned" " %d).", res); - knot_node_free(&node, 0); + knot_node_free(&node); ++errors; } /* TODO check values in the node as well */ @@ -157,7 +157,7 @@ static int test_zone_add_node(knot_zone_contents_t *zone, int nsec3) KNOT_EBADZONE); ++errors; } - knot_node_free(&node, 0); + knot_node_free(&node); } //note("NULL zone"); @@ -179,7 +179,7 @@ static int test_zone_add_node(knot_zone_contents_t *zone, int nsec3) ++errors; } - knot_node_free(&node, 0); + knot_node_free(&node); //note("NULL node"); note("Inserting NULL node...\n"); @@ -211,7 +211,7 @@ static int test_zone_add_node(knot_zone_contents_t *zone, int nsec3) ++errors; } - knot_node_free(&node, 0); + knot_node_free(&node); } // check if all nodes are inserted diff --git a/src/tests/libknot/libknot/zone_tests.h b/src/tests/libknot/libknot/zone_tests.h index 5539709..5539709 100644..100755 --- a/src/tests/libknot/libknot/zone_tests.h +++ b/src/tests/libknot/libknot/zone_tests.h diff --git a/src/tests/libknot/libknot/zone_tree_tests.c b/src/tests/libknot/libknot/zone_tree_tests.c index 207afea..207afea 100644..100755 --- a/src/tests/libknot/libknot/zone_tree_tests.c +++ b/src/tests/libknot/libknot/zone_tree_tests.c diff --git a/src/tests/libknot/libknot/zone_tree_tests.h b/src/tests/libknot/libknot/zone_tree_tests.h index 4cea88c..4cea88c 100644..100755 --- a/src/tests/libknot/libknot/zone_tree_tests.h +++ b/src/tests/libknot/libknot/zone_tree_tests.h diff --git a/src/tests/libknot/libknot/zonedb_tests.c b/src/tests/libknot/libknot/zonedb_tests.c index 7b45587..7b45587 100644..100755 --- a/src/tests/libknot/libknot/zonedb_tests.c +++ b/src/tests/libknot/libknot/zonedb_tests.c diff --git a/src/tests/libknot/libknot/zonedb_tests.h b/src/tests/libknot/libknot/zonedb_tests.h index 0c4f8ef..0c4f8ef 100644..100755 --- a/src/tests/libknot/libknot/zonedb_tests.h +++ b/src/tests/libknot/libknot/zonedb_tests.h diff --git a/src/tests/libknot/realdata/files/parsed_data b/src/tests/libknot/realdata/files/parsed_data Binary files differindex fe22b90..fe22b90 100644..100755 --- a/src/tests/libknot/realdata/files/parsed_data +++ b/src/tests/libknot/realdata/files/parsed_data diff --git a/src/tests/libknot/realdata/files/parsed_data_queries b/src/tests/libknot/realdata/files/parsed_data_queries Binary files differindex 5857c87..5857c87 100644..100755 --- a/src/tests/libknot/realdata/files/parsed_data_queries +++ b/src/tests/libknot/realdata/files/parsed_data_queries diff --git a/src/tests/libknot/realdata/files/raw_data b/src/tests/libknot/realdata/files/raw_data Binary files differindex 502005e..502005e 100644..100755 --- a/src/tests/libknot/realdata/files/raw_data +++ b/src/tests/libknot/realdata/files/raw_data diff --git a/src/tests/libknot/realdata/files/raw_data_queries b/src/tests/libknot/realdata/files/raw_data_queries Binary files differindex 9062d5a..9062d5a 100644..100755 --- a/src/tests/libknot/realdata/files/raw_data_queries +++ b/src/tests/libknot/realdata/files/raw_data_queries diff --git a/src/tests/libknot/realdata/libknot/dname_tests_realdata.c b/src/tests/libknot/realdata/libknot/dname_tests_realdata.c index d0216c7..d0216c7 100644..100755 --- a/src/tests/libknot/realdata/libknot/dname_tests_realdata.c +++ b/src/tests/libknot/realdata/libknot/dname_tests_realdata.c diff --git a/src/tests/libknot/realdata/libknot/dname_tests_realdata.h b/src/tests/libknot/realdata/libknot/dname_tests_realdata.h index a7d75aa..a7d75aa 100644..100755 --- a/src/tests/libknot/realdata/libknot/dname_tests_realdata.h +++ b/src/tests/libknot/realdata/libknot/dname_tests_realdata.h diff --git a/src/tests/libknot/realdata/libknot/edns_tests_realdata.c b/src/tests/libknot/realdata/libknot/edns_tests_realdata.c index 257d480..257d480 100644..100755 --- a/src/tests/libknot/realdata/libknot/edns_tests_realdata.c +++ b/src/tests/libknot/realdata/libknot/edns_tests_realdata.c diff --git a/src/tests/libknot/realdata/libknot/edns_tests_realdata.h b/src/tests/libknot/realdata/libknot/edns_tests_realdata.h index cfa64b0..cfa64b0 100644..100755 --- a/src/tests/libknot/realdata/libknot/edns_tests_realdata.h +++ b/src/tests/libknot/realdata/libknot/edns_tests_realdata.h diff --git a/src/tests/libknot/realdata/libknot/node_tests_realdata.c b/src/tests/libknot/realdata/libknot/node_tests_realdata.c index b9415ef..91209c9 100644..100755 --- a/src/tests/libknot/realdata/libknot/node_tests_realdata.c +++ b/src/tests/libknot/realdata/libknot/node_tests_realdata.c @@ -94,7 +94,7 @@ static int test_node_create(const list *node_list) errors++; diag("Failed to create node structure"); } - knot_node_free(&tmp, 0); + knot_node_free(&tmp); } return (errors == 0); @@ -168,7 +168,7 @@ static int test_node_add_rrset(list *rrset_list) diag("Values in found rrset are wrong"); } - knot_node_free(&tmp, 0); + knot_node_free(&tmp); } return (errors == 0); diff --git a/src/tests/libknot/realdata/libknot/node_tests_realdata.h b/src/tests/libknot/realdata/libknot/node_tests_realdata.h index a90179f..a90179f 100644..100755 --- a/src/tests/libknot/realdata/libknot/node_tests_realdata.h +++ b/src/tests/libknot/realdata/libknot/node_tests_realdata.h diff --git a/src/tests/libknot/realdata/libknot/packet_tests_realdata.c b/src/tests/libknot/realdata/libknot/packet_tests_realdata.c index 08c0882..08c0882 100644..100755 --- a/src/tests/libknot/realdata/libknot/packet_tests_realdata.c +++ b/src/tests/libknot/realdata/libknot/packet_tests_realdata.c diff --git a/src/tests/libknot/realdata/libknot/packet_tests_realdata.h b/src/tests/libknot/realdata/libknot/packet_tests_realdata.h index c0e0479..c0e0479 100644..100755 --- a/src/tests/libknot/realdata/libknot/packet_tests_realdata.h +++ b/src/tests/libknot/realdata/libknot/packet_tests_realdata.h diff --git a/src/tests/libknot/realdata/libknot/rdata_tests_realdata.c b/src/tests/libknot/realdata/libknot/rdata_tests_realdata.c index f4ba64c..f4ba64c 100644..100755 --- a/src/tests/libknot/realdata/libknot/rdata_tests_realdata.c +++ b/src/tests/libknot/realdata/libknot/rdata_tests_realdata.c diff --git a/src/tests/libknot/realdata/libknot/rdata_tests_realdata.h b/src/tests/libknot/realdata/libknot/rdata_tests_realdata.h index 570b2b1..570b2b1 100644..100755 --- a/src/tests/libknot/realdata/libknot/rdata_tests_realdata.h +++ b/src/tests/libknot/realdata/libknot/rdata_tests_realdata.h diff --git a/src/tests/libknot/realdata/libknot/response_tests_realdata.c b/src/tests/libknot/realdata/libknot/response_tests_realdata.c index 7dac341..7dac341 100644..100755 --- a/src/tests/libknot/realdata/libknot/response_tests_realdata.c +++ b/src/tests/libknot/realdata/libknot/response_tests_realdata.c diff --git a/src/tests/libknot/realdata/libknot/response_tests_realdata.h b/src/tests/libknot/realdata/libknot/response_tests_realdata.h index 731604b..731604b 100644..100755 --- a/src/tests/libknot/realdata/libknot/response_tests_realdata.h +++ b/src/tests/libknot/realdata/libknot/response_tests_realdata.h diff --git a/src/tests/libknot/realdata/libknot/rrset_tests_realdata.c b/src/tests/libknot/realdata/libknot/rrset_tests_realdata.c index cb59f4c..cb59f4c 100644..100755 --- a/src/tests/libknot/realdata/libknot/rrset_tests_realdata.c +++ b/src/tests/libknot/realdata/libknot/rrset_tests_realdata.c diff --git a/src/tests/libknot/realdata/libknot/rrset_tests_realdata.h b/src/tests/libknot/realdata/libknot/rrset_tests_realdata.h index cc3b705..cc3b705 100644..100755 --- a/src/tests/libknot/realdata/libknot/rrset_tests_realdata.h +++ b/src/tests/libknot/realdata/libknot/rrset_tests_realdata.h diff --git a/src/tests/libknot/realdata/libknot/zone_tests_realdata.c b/src/tests/libknot/realdata/libknot/zone_tests_realdata.c index 2738dab..4687978 100644..100755 --- a/src/tests/libknot/realdata/libknot/zone_tests_realdata.c +++ b/src/tests/libknot/realdata/libknot/zone_tests_realdata.c @@ -77,7 +77,7 @@ static int test_zone_create(list node_list) errors++; } knot_node_free_rrsets(node, 1); - knot_node_free(&node, 0); + knot_node_free(&node); } return (errors == 0); diff --git a/src/tests/libknot/realdata/libknot/zone_tests_realdata.h b/src/tests/libknot/realdata/libknot/zone_tests_realdata.h index 5539709..5539709 100644..100755 --- a/src/tests/libknot/realdata/libknot/zone_tests_realdata.h +++ b/src/tests/libknot/realdata/libknot/zone_tests_realdata.h diff --git a/src/tests/libknot/realdata/libknot/zonedb_tests_realdata.c b/src/tests/libknot/realdata/libknot/zonedb_tests_realdata.c index 96d1517..96d1517 100644..100755 --- a/src/tests/libknot/realdata/libknot/zonedb_tests_realdata.c +++ b/src/tests/libknot/realdata/libknot/zonedb_tests_realdata.c diff --git a/src/tests/libknot/realdata/libknot/zonedb_tests_realdata.h b/src/tests/libknot/realdata/libknot/zonedb_tests_realdata.h index 0c4f8ef..0c4f8ef 100644..100755 --- a/src/tests/libknot/realdata/libknot/zonedb_tests_realdata.h +++ b/src/tests/libknot/realdata/libknot/zonedb_tests_realdata.h diff --git a/src/tests/libknot/realdata/libknot_tests_loader_realdata.c b/src/tests/libknot/realdata/libknot_tests_loader_realdata.c index e972855..e972855 100644..100755 --- a/src/tests/libknot/realdata/libknot_tests_loader_realdata.c +++ b/src/tests/libknot/realdata/libknot_tests_loader_realdata.c diff --git a/src/tests/libknot/realdata/libknot_tests_loader_realdata.h b/src/tests/libknot/realdata/libknot_tests_loader_realdata.h index 8f57944..8f57944 100644..100755 --- a/src/tests/libknot/realdata/libknot_tests_loader_realdata.h +++ b/src/tests/libknot/realdata/libknot_tests_loader_realdata.h diff --git a/src/tests/libknot/realdata/unittests_libknot_realdata.c b/src/tests/libknot/realdata/unittests_libknot_realdata.c index e557c43..e557c43 100644..100755 --- a/src/tests/libknot/realdata/unittests_libknot_realdata.c +++ b/src/tests/libknot/realdata/unittests_libknot_realdata.c diff --git a/src/tests/libknot/unittests_libknot.c b/src/tests/libknot/unittests_libknot.c index d522e1d..d522e1d 100644..100755 --- a/src/tests/libknot/unittests_libknot.c +++ b/src/tests/libknot/unittests_libknot.c diff --git a/src/tests/unittests_main.c b/src/tests/unittests_main.c index 1ec336a..21eae14 100644..100755 --- a/src/tests/unittests_main.c +++ b/src/tests/unittests_main.c @@ -22,7 +22,6 @@ #include "tests/common/slab_tests.h" #include "tests/common/skiplist_tests.h" #include "tests/common/events_tests.h" -#include "tests/common/da_tests.h" #include "tests/common/acl_tests.h" #include "tests/common/fdset_tests.h" #include "tests/knot/dthreads_tests.h" @@ -47,7 +46,6 @@ int main(int argc, char *argv[]) &skiplist_tests_api, //! Skip list unit &dthreads_tests_api, //! DThreads testing unit &events_tests_api, //! Events testing unit - &da_tests_api, //! Dynamic array unit &acl_tests_api, //! ACLs &fdset_tests_api, //! FDSET polling wrapper diff --git a/src/tests/xfr_tests.c b/src/tests/xfr_tests.c index 5017109..b78678b 100644..100755 --- a/src/tests/xfr_tests.c +++ b/src/tests/xfr_tests.c @@ -172,11 +172,11 @@ int main(int argc, char **argv) server_t *server = server_create(); // Initialize configuration - conf_read_lock(); + rcu_read_lock(); conf_add_hook(conf(), CONF_LOG, log_conf_hook, 0); conf_add_hook(conf(), CONF_LOG, zones_ns_conf_hook, server->nameserver); conf_add_hook(conf(), CONF_LOG, server_conf_hook, server); - conf_read_unlock(); + rcu_read_unlock(); // Find implicit configuration file if (!config_fn) { @@ -215,7 +215,7 @@ int main(int argc, char **argv) log_server_error("Couldn't open configuration file " "'%s'.\n", config_fn); } else { - log_server_error("Failed to parse configuration '%s'.\n", + log_server_error("Failed to load configuration '%s'.\n", config_fn); } server_destroy(&server); diff --git a/src/tests/xfr_tests.h b/src/tests/xfr_tests.h index 29de11d..29de11d 100644..100755 --- a/src/tests/xfr_tests.h +++ b/src/tests/xfr_tests.h diff --git a/src/zcompile/LICENSE b/src/zcompile/LICENSE index 55faacf..55faacf 100644..100755 --- a/src/zcompile/LICENSE +++ b/src/zcompile/LICENSE diff --git a/src/zcompile/parser-descriptor.c b/src/zcompile/parser-descriptor.c index b876877..bc3ee16 100644..100755 --- a/src/zcompile/parser-descriptor.c +++ b/src/zcompile/parser-descriptor.c @@ -539,3 +539,4 @@ uint16_t parser_rrclass_from_string(const char *name) return (uint16_t) rrclass; } +/*! @} */ diff --git a/src/zcompile/parser-descriptor.h b/src/zcompile/parser-descriptor.h index 48c6f02..48c6f02 100644..100755 --- a/src/zcompile/parser-descriptor.h +++ b/src/zcompile/parser-descriptor.h diff --git a/src/zcompile/parser-util.c b/src/zcompile/parser-util.c index cfbc624..955a7b0 100644..100755 --- a/src/zcompile/parser-util.c +++ b/src/zcompile/parser-util.c @@ -1128,25 +1128,32 @@ static ssize_t rdata_wireformat_to_rdata_atoms(const uint16_t *wireformat, // break; case KNOT_RDATA_WF_IPSECGATEWAY: dbg_rdata("Parsed item is an IPSECGATEWAY address.\n"); - switch (rdata_atom_data(temp_rdatas[1])[0]) { + dbg_rdata("Gateway type: %d\n", + ((uint8_t *)rdata_atom_data(temp_rdatas[1]))[0]); + switch (((uint8_t *)rdata_atom_data(temp_rdatas[1]))[0]) { /* gateway type */ - default: case IPSECKEY_NOGATEWAY: + dbg_rdata("NOGATEWAY\n"); length = 0; break; case IPSECKEY_IP4: + dbg_rdata("IPv4\n"); length = 4; break; case IPSECKEY_IP6: + dbg_rdata("IPv6\n"); length = IP6ADDRLEN; break; case IPSECKEY_DNAME: + dbg_rdata("DNAME\n"); is_domain = 1; is_wirestore = 1; break; - } - - break; + default: + dbg_rdata("Unknown IPSECKEY gateway!\n"); + free(temp_rdatas); + return -1; + } // switch } if (is_domain) { @@ -2473,3 +2480,4 @@ void set_bitnsec(uint8_t bits[NSEC_WINDOW_COUNT][NSEC_WINDOW_BITS_SIZE], bits[window][bit / 8] |= (1 << (7 - bit % 8)); } +/*! @} */ diff --git a/src/zcompile/parser-util.h b/src/zcompile/parser-util.h index 57258dc..57258dc 100644..100755 --- a/src/zcompile/parser-util.h +++ b/src/zcompile/parser-util.h diff --git a/src/zcompile/tests/unittests_zp_main.c b/src/zcompile/tests/unittests_zp_main.c index 5d8c5e9..5d8c5e9 100644..100755 --- a/src/zcompile/tests/unittests_zp_main.c +++ b/src/zcompile/tests/unittests_zp_main.c diff --git a/src/zcompile/tests/zcompile_tests.c b/src/zcompile/tests/zcompile_tests.c index 5d3dce6..5d3dce6 100644..100755 --- a/src/zcompile/tests/zcompile_tests.c +++ b/src/zcompile/tests/zcompile_tests.c diff --git a/src/zcompile/zcompile-error.c b/src/zcompile/zcompile-error.c index 9357cde..9357cde 100644..100755 --- a/src/zcompile/zcompile-error.c +++ b/src/zcompile/zcompile-error.c diff --git a/src/zcompile/zcompile-error.h b/src/zcompile/zcompile-error.h index c6d999c..c6d999c 100644..100755 --- a/src/zcompile/zcompile-error.h +++ b/src/zcompile/zcompile-error.h diff --git a/src/zcompile/zcompile.c b/src/zcompile/zcompile.c index c4415d4..e2f05e3 100644..100755 --- a/src/zcompile/zcompile.c +++ b/src/zcompile/zcompile.c @@ -42,6 +42,7 @@ #include "zcompile/parser-util.h" #include "zcompile/zcompile-error.h" #include "knot/zone/zone-dump.h" +#include "libknot/zone/zone-diff.h" #include "libknot/libknot.h" #include "libknot/util/utils.h" @@ -111,69 +112,6 @@ static void rrset_list_delete(rrset_list_t **head) dbg_zp("zp: list_delete: List deleleted.\n"); } -static int find_rrset_for_rrsig_in_zone(knot_zone_contents_t *zone, - knot_rrset_t *rrsig) -{ - assert(rrsig != NULL); - assert(rrsig->rdata->items[0].raw_data); - - knot_node_t *tmp_node = NULL; - - if (knot_rdata_rrsig_type_covered(knot_rrset_rdata(rrsig)) - != KNOT_RRTYPE_NSEC3) { - tmp_node = knot_zone_contents_get_node(zone, rrsig->owner); - } else { - tmp_node = knot_zone_contents_get_nsec3_node(zone, - rrsig->owner); - } - - dbg_zp_verb("zp: find_rr_for_sig: Found this node for RRSIG: %p.\n", - tmp_node); - - if (tmp_node == NULL) { - dbg_zp("zp: find_rr_for_sig: There is no node for this RR.\n"); - return KNOTDZCOMPILE_EINVAL; - } - - knot_rrset_t *tmp_rrset = - knot_node_get_rrset(tmp_node, - knot_rdata_rrsig_type_covered( - rrsig->rdata)); - - dbg_zp_verb("zp: find_rr_for_sig: Found this RRSet for RRSIG: %p.\n", - tmp_rrset); - - if (tmp_rrset == NULL) { - dbg_zp("zp: find_rr_for_sig: There is no RRSet " - "for this RRSIG.\n"); - return KNOTDZCOMPILE_EINVAL; - } - - - if (tmp_rrset->rrsigs != NULL) { - int ret = knot_zone_contents_add_rrsigs(zone, rrsig, - &tmp_rrset, &tmp_node, - KNOT_RRSET_DUPL_MERGE, 1); - if (ret != KNOT_EOK) { - dbg_zp("zp: find_rr_for_sig: Cannot add RRSIG.\n"); - return ret; - } - knot_rrset_free(&rrsig); - } else { - int ret = knot_zone_contents_add_rrsigs(zone, rrsig, - &tmp_rrset, &tmp_node, - KNOT_RRSET_DUPL_SKIP, 1); - if (ret != KNOT_EOK) { - dbg_zp("zp: find_rr_for_sig: Cannot add RRSIG.\n"); - return ret; - } - } - - dbg_zp("zp: find_rr_for_sig: Found node: %p found rrset: %p.\n", - tmo_node, tmp_rrset); - return KNOTDZCOMPILE_EOK; -} - static int find_rrset_for_rrsig_in_node(knot_zone_contents_t *zone, knot_node_t *node, knot_rrset_t *rrsig) @@ -187,28 +125,51 @@ static int find_rrset_for_rrsig_in_node(knot_zone_contents_t *zone, knot_rrset_t *tmp_rrset = knot_node_get_rrset(node, rrsig_type_covered(rrsig)); + int ret; + if (tmp_rrset == NULL) { dbg_zp("zp: find_rr_for_sig_in_node: Node does not contain " "RRSet of type %s.\n", knot_rrtype_to_string(rrsig_type_covered(rrsig))); - return KNOTDZCOMPILE_EINVAL; - } + tmp_rrset = knot_rrset_new(rrsig->owner, + rrsig_type_covered(rrsig), + rrsig->rclass, + rrsig->ttl); + if (tmp_rrset == NULL) { + dbg_zp("zp: find_rr_for_sig_in_node: Cannot create " + "dummy RRSet.\n"); + return KNOT_ERROR; + } - if (tmp_rrset->rrsigs != NULL) { - if (knot_zone_contents_add_rrsigs(zone, rrsig, - &tmp_rrset, &node, - KNOT_RRSET_DUPL_MERGE, 1) < 0) { - dbg_zp("zp: find_rr_for_sig: Cannot add RRSIG.\n"); - return KNOTDZCOMPILE_EINVAL; + ret = knot_zone_contents_add_rrset(zone, tmp_rrset, &node, + KNOT_RRSET_DUPL_MERGE, 1); + assert(ret <= 0); + if (ret < 0) { + dbg_zp("zp: Failed to add new dummy RRSet to the zone." + "\n"); + return KNOT_ERROR; } + } + + assert(tmp_rrset); + + if (tmp_rrset->ttl != rrsig->ttl) { + char *name = knot_dname_to_str(tmp_rrset->owner); + assert(name); + log_zone_warning("RRSIG owned by: %s cannot be added to " + "its RRSet, because their TTLs differ. " + "Changing TTL to value=%d.\n", + name, tmp_rrset->ttl); + free(name); + } + + ret = knot_zone_contents_add_rrsigs(zone, rrsig, &tmp_rrset, &node, + KNOT_RRSET_DUPL_MERGE, 1); + if (ret < 0) { + dbg_zp("zp: find_rr_for_sig: Cannot add RRSIG.\n"); + return KNOTDZCOMPILE_EINVAL; + } else if (ret > 0) { knot_rrset_free(&rrsig); - } else { - if (knot_zone_contents_add_rrsigs(zone, rrsig, - &tmp_rrset, &node, - KNOT_RRSET_DUPL_SKIP, 1) < 0) { - dbg_zp("zp: find_rr_for_sig: Cannot add RRSIG.\n"); - return KNOTDZCOMPILE_EINVAL; - } } assert(tmp_rrset->rrsigs != NULL); @@ -244,10 +205,9 @@ static void process_rrsigs_in_node(knot_zone_contents_t *zone, rrset_list_t *tmp = parser->node_rrsigs; while (tmp != NULL) { if (find_rrset_for_rrsig_in_node(zone, node, - tmp->data) != 0) { - rrset_list_add(&parser->rrsig_orphans, - tmp->data); - parser->rrsig_orphan_count++; + tmp->data) != KNOT_EOK) { + zc_error_prev_line("Could not add RRSIG to zone!\n"); + return; } tmp = tmp->next; } @@ -279,6 +239,7 @@ dbg_zp_exec_detail( assert(current_rrset->rdata->count == descriptor->length); } + assert(current_rrset->rdata->count > 0); assert(knot_dname_is_fqdn(current_rrset->owner)); @@ -336,6 +297,7 @@ dbg_zp_exec_detail( } if (current_rrset->type == KNOT_RRTYPE_RRSIG) { + /*!< \todo Use deep copy function here! */ knot_rrset_t *tmp_rrsig = knot_rrset_new(current_rrset->owner, KNOT_RRTYPE_RRSIG, @@ -458,11 +420,10 @@ dbg_zp_exec_detail( "add RDATA to RRSet.\n"); return KNOTDZCOMPILE_EBRDATA; } - - /* I chose skip, but there should not really be - * any rrset to skip */ + + /* Selected merge option does not really matter here. */ if (knot_zone_contents_add_rrset(contents, rrset, &node, - KNOT_RRSET_DUPL_SKIP, 1) < 0) { + KNOT_RRSET_DUPL_MERGE, 1) < 0) { knot_rrset_free(&rrset); dbg_zp("zp: process_rr: Cannot " "add RDATA to RRSet.\n"); @@ -472,8 +433,9 @@ dbg_zp_exec_detail( if (current_rrset->type != KNOT_RRTYPE_RRSIG && rrset->ttl != current_rrset->ttl) { - zc_error_prev_line( - "TTL does not match the TTL of the RRSet"); + zc_warning_prev_line( + "TTL does not match the TTL of the RRSet. " + "Changing to %lu.\n", rrset->ttl); } if (knot_zone_contents_add_rrset(contents, current_rrset, @@ -497,31 +459,6 @@ dbg_zp_exec_detail( return KNOTDZCOMPILE_EOK; } -static uint find_rrsets_orphans(knot_zone_contents_t *zone, rrset_list_t - *head) -{ - uint found_rrsets = 0; - while (head != NULL) { - if (find_rrset_for_rrsig_in_zone(zone, head->data) == 0) { - found_rrsets += 1; - dbg_zp("zp: find_orphans: " - "RRSet succesfully found: owner %s type %s\n", - knot_dname_to_str(head->data->owner), - knot_rrtype_to_string(head->data->type)); - } - else { /* we can throw it away now */ - dbg_zp("zp: find_orphans: " - "RRSet not found for RRSIG: %s (%s)\n", - knot_dname_to_str(head->data->owner), - knot_rrtype_to_string( - knot_rdata_rrsig_type_covered(head->data->rdata))); - knot_rrset_free(&head->data); - } - head = head->next; - } - return found_rrsets; -} - static int zone_open(const char *filename, uint32_t ttl, uint16_t rclass, knot_node_t *origin, void *scanner, knot_dname_t *origin_from_config) { @@ -549,19 +486,23 @@ 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. */ - 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); + FILE *f = fopen(outfile, "wb"); + if (f == NULL) { + log_zone_error("Cannot write zone db to file '%s' (%s).\n", + outfile, strerror(errno)); + return KNOTDZCOMPILE_EINVAL; } + fclose(f); knot_dname_t *dname = knot_dname_new_from_str(name, strlen(name), NULL); @@ -570,7 +511,7 @@ int zone_read(const char *name, const char *zonefile, const char *outfile, } if (!knot_dname_is_fqdn(dname)) { - fprintf(stderr, "Error: given zone origin is not FQDN.\n"); + log_zone_error("Error: given zone origin is not FQDN.\n"); knot_dname_release(dname); return KNOTDZCOMPILE_EINVAL; } @@ -587,7 +528,7 @@ int zone_read(const char *name, const char *zonefile, const char *outfile, knot_dname_t *origin_from_config = knot_dname_new_from_str(name, strlen(name), NULL); if (origin_from_config == NULL) { - knot_node_free(&origin_node, 0); + knot_node_free(&origin_node); return KNOTDZCOMPILE_ENOMEM; } @@ -595,7 +536,7 @@ int zone_read(const char *name, const char *zonefile, const char *outfile, zp_lex_init(&scanner); if (scanner == NULL) { knot_dname_release(origin_from_config); - knot_node_free(&origin_node, 0); + knot_node_free(&origin_node); return KNOTDZCOMPILE_ENOMEM; } @@ -608,25 +549,55 @@ int zone_read(const char *name, const char *zonefile, const char *outfile, // knot_node_free(&origin_node, 0); return KNOTDZCOMPILE_EZONEINVAL; } + + /* Lock zone file. There should not be any modifications. */ + struct flock lock; + lock.l_type = F_RDLCK; + lock.l_start = 0; + lock.l_whence = SEEK_SET; + lock.l_len = 0; + lock.l_pid = getpid(); + if (fcntl(fileno(zp_get_in(scanner)), F_SETLK, &lock) == -1) { + log_zone_error("Cannot obtain zone source file lock (%d).\n", + errno); + FILE *in_file = (FILE *)zp_get_in(scanner); + fclose(in_file); + zp_lex_destroy(scanner); + knot_dname_release(origin_from_config); + return KNOTDZCOMPILE_EINVAL; + } + + /* Change lock type to unlock rigth away. */ + lock.l_type = F_UNLCK; if (zp_parse(scanner) != 0) { - /*!< \todo #1676 Implement proper locking. */ + log_zone_error("Parse failed.\n"); FILE *in_file = (FILE *)zp_get_in(scanner); fclose(in_file); - zp_lex_destroy(scanner); knot_dname_release(origin_from_config); // knot_node_free(&origin_node, 0); + /* Release file lock. */ + if (fcntl(fileno(zp_get_in(scanner)), F_SETLK, &lock) == -1) { + log_zone_error("Cannot release zone source file " + "lock (%d).\n", + errno); + } + zp_lex_destroy(scanner); return KNOTDZCOMPILE_ESYNT; } knot_zone_contents_t *contents = knot_zone_get_contents(parser->current_zone); + + /* Release file lock. */ + if (fcntl(fileno(zp_get_in(scanner)), F_SETLK, &lock) == -1) { + log_zone_error("Cannot release zone source file lock (%d).\n", + errno); + } FILE *in_file = (FILE *)zp_get_in(scanner); fclose(in_file); zp_lex_destroy(scanner); - - /*!< \todo #1676 Implement proper locking. */ dbg_zp("zp: zone_read: Parse complete for %s.\n", zonefile); @@ -650,31 +621,20 @@ int zone_read(const char *name, const char *zonefile, const char *outfile, return KNOTDZCOMPILE_EZONEINVAL; } - uint found_orphans; - found_orphans = find_rrsets_orphans(contents, - parser->rrsig_orphans); - - dbg_zp("zp: zone_read: %u RRSIG orphans found.\n", found_orphans); - - rrset_list_delete(&parser->rrsig_orphans); - - if (found_orphans != parser->rrsig_orphan_count) { - /*! \todo This might be desired behaviour. */ - fprintf(stderr, - "There are unassigned RRSIGs in the zone!\n"); + int ret = knot_zone_contents_adjust(contents); + if (ret != KNOT_EOK) { + fprintf(stderr, "Zone could not be adjusted, error: %s.\n", + knot_strerror(ret)); parser->errors++; } - - /*! \todo Check return value. */ - knot_zone_contents_adjust(contents); - + dbg_zp("zp: zone_read: Zone adjusted.\n"); if (parser->errors != 0) { - log_zone_error("Parser finished with %d error(s)%s\n", - parser->errors, outfile == NULL ? - "." : ", not dumping the zone!"); - } else if (outfile != NULL) { + log_zone_error("Parser finished with %d error(s), " + "not dumping the zone!\n", + parser->errors); + } else { 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", @@ -688,7 +648,10 @@ int zone_read(const char *name, const char *zonefile, const char *outfile, if (ret != KNOT_EOK) { log_zone_error("Could not dump zone, reason: " "%s.\n", knot_strerror(ret)); - remove(outfile); + if (remove(outfile) != 0) { + log_zone_error("Could not remove " + "db file!\n"); + } totalerrors++; } else { /* Write CRC file. */ diff --git a/src/zcompile/zcompile.h b/src/zcompile/zcompile.h index 37b3791..d19ef4c 100644..100755 --- a/src/zcompile/zcompile.h +++ b/src/zcompile/zcompile.h @@ -131,18 +131,11 @@ struct zparser { knot_rrset_t *current_rrset; /*!< Current RRSet. */ knot_rdata_item_t *temporary_items; /*!< Temporary rdata items. */ - /*! - * \brief list of RRSIGs that were not inside their nodes in zone file - */ - rrset_list_t *rrsig_orphans; - unsigned long rrsig_orphan_count; /*!< RRSIG orphan count */ - knot_dname_t *root_domain; /*!< Root domain name. */ slab_cache_t *parser_slab; /*!< Slab for parser. */ rrset_list_t *node_rrsigs; /*!< List of RRSIGs in current node. */ int rdata_count; /*!< Count of parsed rdata. */ - int origin_directive; /*!< Set to 1 if $ORIGIN directive is present. */ }; typedef struct zparser zparser_type; diff --git a/src/zcompile/zcompile_main.c b/src/zcompile/zcompile_main.c index c84515e..983376a 100644..100755 --- a/src/zcompile/zcompile_main.c +++ b/src/zcompile/zcompile_main.c @@ -26,7 +26,7 @@ static void help(int argc, char **argv) { printf("Usage: %s [parameters] origin zonefile\n", argv[0]); - printf("Parameters:\n" + printf("\n:Parameters:\n" " -o <outfile> Override output file.\n" " -v Verbose mode - additional runtime information.\n" " -s Enable semantic checks.\n" @@ -114,7 +114,6 @@ int main(int argc, char **argv) } else { log_zone_info("Zone file for '%s' is OK.\n", origin); } - //log_close(); return 0; } diff --git a/src/zcompile/zlexer.l b/src/zcompile/zlexer.l index 58e6439..58e6439 100644..100755 --- a/src/zcompile/zlexer.l +++ b/src/zcompile/zlexer.l diff --git a/src/zcompile/zparser.y b/src/zcompile/zparser.y index 89af437..c35060e 100644..100755 --- a/src/zcompile/zparser.y +++ b/src/zcompile/zparser.y @@ -314,7 +314,6 @@ origin_directive: DOLLAR_ORIGIN sp abs_dname trail // knot_node_free(&parser->origin, 1); } parser->origin = origin_node; - parser->origin_directive = 1; } | DOLLAR_ORIGIN sp rel_dname trail { @@ -406,12 +405,8 @@ abs_dname: '.' } | '@' { - if (parser->origin_directive) { - $$ = parser->origin->owner; - } else { - zc_error("@ used, but no $ORIGIN specified.\n"); - $$ = parser->origin->owner; - } + assert(parser->origin != NULL); + $$ = parser->origin->owner; } | rel_dname '.' { @@ -1267,13 +1262,13 @@ rdata_apl: rdata_apl_seq trail rdata_apl_seq: dotted_str { - zadd_rdata_wireformat(zparser_conv_apl_rdata($1.str)); + zadd_rdata_txt_wireformat(zparser_conv_apl_rdata($1.str), 1); free($1.str); } | rdata_apl_seq sp dotted_str { - zadd_rdata_wireformat(zparser_conv_apl_rdata($3.str)); + zadd_rdata_txt_wireformat(zparser_conv_apl_rdata($3.str), 0); free($3.str); } @@ -1637,13 +1632,9 @@ zparser_init(const char *filename, uint32_t ttl, uint16_t rclass, parser->current_zone = knot_zone_new(origin, 0, 1); parser->node_rrsigs = NULL; - parser->rrsig_orphans = NULL; - parser->rrsig_orphan_count = 0; parser->current_rrset->rclass = parser->default_class; parser->current_rrset->rdata = NULL; - - parser->origin_directive = 0; } |