nsd 4.1.19

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

nsd 4.1.19

Florian Obser-2
so, here is 4.1.19. I haven't gotten around to reading the diff yet.
But I tossed it in production.

When trying to re-gen config.h.in autheader bombs out:

[florian@openbsd-build:/usr/src/usr.sbin/nsd]$ autoheader-2.69
autoheader-2.69: warning: missing template: HAVE_B64_NTOP
autoheader-2.69: Use AC_DEFINE([HAVE_B64_NTOP], [], [Description])
autoheader-2.69: warning: missing template: HAVE_B64_PTON

I suppose this has something to do with our b64 half-arsery?
Anyone has a clue? For now I copied config.h.in from the
release tgz.

Tests, OKs?

diff --git Makefile.in Makefile.in
index 495160c0826..3468101c19d 100644
--- Makefile.in
+++ Makefile.in
@@ -286,9 +286,6 @@ qtest.o: $(srcdir)/tpkg/cutest/qtest.c
 udb-inspect.o: $(srcdir)/tpkg/cutest/udb-inspect.c
  $(COMPILE) -c $(srcdir)/tpkg/cutest/udb-inspect.c
 
-xfr-inspect.o: $(srcdir)/tpkg/cutest/xfr-inspect.c
- $(COMPILE) -c $(srcdir)/tpkg/cutest/xfr-inspect.c
-
 zlexer.c: $(srcdir)/zlexer.lex
  if test "$(LEX)" != ":"; then rm -f $@ ;\
  echo '#include "config.h"' > $@ ;\
@@ -516,7 +513,7 @@ udb-inspect.o: $(srcdir)/tpkg/cutest/udb-inspect.c config.h $(srcdir)/udb.h $(sr
  $(srcdir)/udb.h $(srcdir)/udbzone.h $(srcdir)/dns.h $(srcdir)/udbradtree.h $(srcdir)/util.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h \
  $(srcdir)/util.h $(srcdir)/packet.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/rdata.h \
  $(srcdir)/namedb.h $(srcdir)/difffile.h $(srcdir)/options.h config.h
-xfr-inspect.o: $(srcdir)/tpkg/cutest/xfr-inspect.c config.h $(srcdir)/udbzone.h $(srcdir)/udb.h $(srcdir)/dns.h \
+xfr-inspect.o: $(srcdir)/xfr-inspect.c config.h $(srcdir)/udbzone.h $(srcdir)/udb.h $(srcdir)/dns.h \
  $(srcdir)/udbradtree.h $(srcdir)/util.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/packet.h $(srcdir)/namedb.h \
  $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/rdata.h $(srcdir)/namedb.h $(srcdir)/difffile.h \
  $(srcdir)/options.h config.h
diff --git axfr.c axfr.c
index 6f6b0957e99..dd34c0c3cee 100644
--- axfr.c
+++ axfr.c
@@ -201,6 +201,7 @@ answer_axfr_ixfr(struct nsd *nsd, struct query *q)
  return query_axfr(nsd, q);
  }
  /** Fallthrough: AXFR over UDP queries are discarded. */
+ /* fallthrough */
  case TYPE_IXFR:
  RCODE_SET(q->packet, RCODE_IMPL);
  return QUERY_PROCESSED;
diff --git config.h.in config.h.in
index 6c44616432f..34091d5eb3f 100644
--- config.h.in
+++ config.h.in
@@ -73,6 +73,9 @@
 /* Define to 1 if you have the `endpwent' function. */
 #undef HAVE_ENDPWENT
 
+/* Define to 1 if you have the `ERR_load_crypto_strings' function. */
+#undef HAVE_ERR_LOAD_CRYPTO_STRINGS
+
 /* Define to 1 if you have the `event_base_free' function. */
 #undef HAVE_EVENT_BASE_FREE
 
@@ -88,6 +91,9 @@
 /* Define to 1 if you have the <event.h> header file. */
 #undef HAVE_EVENT_H
 
+/* Define to 1 if you have the `EVP_cleanup' function. */
+#undef HAVE_EVP_CLEANUP
+
 /* Define to 1 if you have the `ev_default_loop' function. */
 #undef HAVE_EV_DEFAULT_LOOP
 
@@ -194,6 +200,12 @@
 /* Define to 1 if you have the <openssl/err.h> header file. */
 #undef HAVE_OPENSSL_ERR_H
 
+/* Define to 1 if you have the `OPENSSL_init_crypto' function. */
+#undef HAVE_OPENSSL_INIT_CRYPTO
+
+/* Define to 1 if you have the `OPENSSL_init_ssl' function. */
+#undef HAVE_OPENSSL_INIT_SSL
+
 /* Define to 1 if you have the <openssl/rand.h> header file. */
 #undef HAVE_OPENSSL_RAND_H
 
@@ -426,6 +438,9 @@
 /* Define to the version of this package. */
 #undef PACKAGE_VERSION
 
+/* Define this to use packed structure alignment. */
+#undef PACKED_STRUCTS
+
 /* Pathname to the NSD pidfile */
 #undef PIDFILE
 
@@ -483,6 +498,9 @@
 /* Define this to enable mmap instead of malloc. Experimental. */
 #undef USE_MMAP_ALLOC
 
+/* Define this to configure to use the radix tree. */
+#undef USE_RADIX_TREE
+
 /* Enable extensions on AIX 3, Interix.  */
 #ifndef _ALL_SOURCE
 # undef _ALL_SOURCE
@@ -817,5 +835,11 @@ int memcmp(const void *x, const void *y, size_t n);
 #endif /* !HAVE_STRUCT_TIMESPEC */
 #endif /* !CONFIG_DEFINES */
 
+#ifdef PACKED_STRUCTS
+#define ATTR_PACKED __attribute__((packed))
+#else
+#define ATTR_PACKED
+#endif
+
 int __b64_ntop(uint8_t const *, size_t, char *, size_t);
 int __b64_pton(char const *, uint8_t*, size_t);
diff --git configure configure
index 15ceae2b292..c8a8743f384 100644
--- configure
+++ configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for NSD 4.1.17.
+# Generated by GNU Autoconf 2.69 for NSD 4.1.19.
 #
 # Report bugs to <[hidden email]>.
 #
@@ -580,8 +580,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='NSD'
 PACKAGE_TARNAME='nsd'
-PACKAGE_VERSION='4.1.17'
-PACKAGE_STRING='NSD 4.1.17'
+PACKAGE_VERSION='4.1.19'
+PACKAGE_STRING='NSD 4.1.19'
 PACKAGE_BUGREPORT='[hidden email]'
 PACKAGE_URL=''
 
@@ -732,6 +732,7 @@ enable_nsec3
 enable_minimal_responses
 enable_mmap
 enable_radix_tree
+enable_packed
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1284,7 +1285,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures NSD 4.1.17 to adapt to many kinds of systems.
+\`configure' configures NSD 4.1.19 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1345,7 +1346,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of NSD 4.1.17:";;
+     short | recursive ) echo "Configuration of NSD 4.1.19:";;
    esac
   cat <<\_ACEOF
 
@@ -1381,6 +1382,8 @@ Optional Features:
   --disable-radix-tree    You can disable the radix tree and use the red-black
                           tree for the main lookups, the red-black tree uses
                           less memory, but uses some more CPU.
+  --enable-packed         Enable packed structure alignment, uses less memory,
+                          but unaligned reads.
 
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
@@ -1491,7 +1494,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-NSD configure 4.1.17
+NSD configure 4.1.19
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2200,7 +2203,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by NSD $as_me 4.1.17, which was
+It was created by NSD $as_me 4.1.19, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -9171,6 +9174,54 @@ _ACEOF
  ;;
 esac
 
+# Check whether --enable-packed was given.
+if test "${enable_packed+set}" = set; then :
+  enableval=$enable_packed;
+fi
+
+case "$enable_packed" in
+ yes)
+
+cat >>confdefs.h <<_ACEOF
+#define PACKED_STRUCTS /**/
+_ACEOF
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wno-address-of-packed-member" >&5
+$as_echo_n "checking whether $CC supports -Wno-address-of-packed-member... " >&6; }
+cache=`echo Wno-address-of-packed-member | sed 'y%.=/+-%___p_%'`
+if eval \${cv_prog_cc_flag_$cache+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+echo 'void f(void){}' >conftest.c
+if test -z "`$CC $CPPFLAGS $CFLAGS -Wno-address-of-packed-member -c conftest.c 2>&1`"; then
+eval "cv_prog_cc_flag_$cache=yes"
+else
+eval "cv_prog_cc_flag_$cache=no"
+fi
+rm -f conftest conftest.o conftest.c
+
+fi
+
+if eval "test \"`echo '$cv_prog_cc_flag_'$cache`\" = yes"; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+:
+CFLAGS="$CFLAGS -Wno-address-of-packed-member"
+else
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+:
+
+fi
+
+ ;;
+ no|*)
+ ;;
+esac
+
 
 
 
@@ -9717,7 +9768,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by NSD $as_me 4.1.17, which was
+This file was extended by NSD $as_me 4.1.19, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -9779,7 +9830,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-NSD config.status 4.1.17
+NSD config.status 4.1.19
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
diff --git configure.ac configure.ac
index 89d69d88ebe..a47860eb34f 100644
--- configure.ac
+++ configure.ac
@@ -4,7 +4,7 @@ dnl
 
 sinclude(acx_nlnetlabs.m4)
 
-AC_INIT(NSD,4.1.17,[hidden email])
+AC_INIT(NSD,4.1.19,[hidden email])
 AC_CONFIG_HEADER([config.h])
 
 CFLAGS="$CFLAGS"
@@ -918,6 +918,16 @@ case "$enable_radix_tree" in
  ;;
 esac
 
+AC_ARG_ENABLE(packed, AC_HELP_STRING([--enable-packed], [Enable packed structure alignment, uses less memory, but unaligned reads.]))
+case "$enable_packed" in
+ yes)
+ AC_DEFINE_UNQUOTED([PACKED_STRUCTS], [], [Define this to use packed structure alignment.])
+ ACX_CHECK_COMPILER_FLAG(Wno-address-of-packed-member, [CFLAGS="$CFLAGS -Wno-address-of-packed-member"])
+ ;;
+ no|*)
+ ;;
+esac
+
 AH_BOTTOM([
 /* define before includes as it specifies what standard to use. */
 #if (defined(HAVE_PSELECT) && !defined (HAVE_PSELECT_PROTO)) \
@@ -1096,6 +1106,12 @@ AH_BOTTOM([
 #endif /* !__timespec_defined */
 #endif /* !HAVE_STRUCT_TIMESPEC */
 #endif /* !CONFIG_DEFINES */
+
+#ifdef PACKED_STRUCTS
+#define ATTR_PACKED __attribute__((packed))
+#else
+#define ATTR_PACKED
+#endif
 ])
 
 # big fat warning
diff --git difffile.c difffile.c
index dfef60dccc7..1fb5bda0003 100644
--- difffile.c
+++ difffile.c
@@ -478,7 +478,8 @@ nsec3_rrsets_changed_remove_prehash(domain_type* domain, zone_type* zone)
  /* see if the domain is no longer precompiled */
  /* it has a hash_node, but no longer fulfills conditions */
  if(nsec3_domain_part_of_zone(domain, zone) && domain->nsec3 &&
- domain->nsec3->hash_node.key &&
+ domain->nsec3->hash_wc &&
+ domain->nsec3->hash_wc->hash.node.key &&
  !nsec3_condition_hash(domain, zone)) {
  /* remove precompile */
  domain->nsec3->nsec3_cover = NULL;
@@ -486,12 +487,13 @@ nsec3_rrsets_changed_remove_prehash(domain_type* domain, zone_type* zone)
  domain->nsec3->nsec3_is_exact = 0;
  /* remove it from the hash tree */
  zone_del_domain_in_hash_tree(zone->hashtree,
- &domain->nsec3->hash_node);
+ &domain->nsec3->hash_wc->hash.node);
  zone_del_domain_in_hash_tree(zone->wchashtree,
- &domain->nsec3->wchash_node);
+ &domain->nsec3->hash_wc->wc.node);
  }
  if(domain != zone->apex && domain->nsec3 &&
- domain->nsec3->dshash_node.key &&
+ domain->nsec3->ds_parent_hash &&
+ domain->nsec3->ds_parent_hash->node.key &&
  (!domain->parent || nsec3_domain_part_of_zone(domain->parent, zone)) &&
  !nsec3_condition_dshash(domain, zone)) {
  /* remove precompile */
@@ -499,7 +501,7 @@ nsec3_rrsets_changed_remove_prehash(domain_type* domain, zone_type* zone)
  domain->nsec3->nsec3_ds_parent_is_exact = 0;
  /* remove it from the hash tree */
  zone_del_domain_in_hash_tree(zone->dshashtree,
- &domain->nsec3->dshash_node);
+ &domain->nsec3->ds_parent_hash->node);
  }
 }
 
@@ -510,13 +512,15 @@ nsec3_rrsets_changed_add_prehash(namedb_type* db, domain_type* domain,
 {
  if(!zone->nsec3_param)
  return;
- if((!domain->nsec3 || !domain->nsec3->hash_node.key)
+ if((!domain->nsec3 || !domain->nsec3->hash_wc
+                   || !domain->nsec3->hash_wc->hash.node.key)
  && nsec3_condition_hash(domain, zone)) {
  region_type* tmpregion = region_create(xalloc, free);
  nsec3_precompile_domain(db, domain, zone, tmpregion);
  region_destroy(tmpregion);
  }
- if((!domain->nsec3 || !domain->nsec3->dshash_node.key)
+ if((!domain->nsec3 || !domain->nsec3->ds_parent_hash
+                   || !domain->nsec3->ds_parent_hash->node.key)
  && nsec3_condition_dshash(domain, zone)) {
  nsec3_precompile_domain_ds(db, domain, zone);
  }
diff --git lookup3.c lookup3.c
index e0179f06d29..9602ffa374b 100644
--- lookup3.c
+++ lookup3.c
@@ -5,6 +5,7 @@
      added #ifdef VALGRIND to remove 298,384,660 'unused variable k8' warnings.
      added include of lookup3.h to check definitions match declarations.
      removed include of stdint - config.h takes care of platform independence.
+     added fallthrough comments for new gcc warning suppression.
   url http://burtleburtle.net/bob/hash/index.html.
 */
 /*
@@ -235,7 +236,9 @@ uint32_t        initval)         /* the previous hash, or an arbitrary value */
   switch(length)                     /* all the case statements fall through */
   {
   case 3 : c+=k[2];
+   /* fallthrough */
   case 2 : b+=k[1];
+   /* fallthrough */
   case 1 : a+=k[0];
     final(a,b,c);
   case 0:     /* case 0: nothing left to add */
@@ -473,16 +476,27 @@ uint32_t hashlittle( const void *key, size_t length, uint32_t initval)
     switch(length)                   /* all the case statements fall through */
     {
     case 12: c+=((uint32_t)k[11])<<24;
+   /* fallthrough */
     case 11: c+=((uint32_t)k[10])<<16;
+   /* fallthrough */
     case 10: c+=((uint32_t)k[9])<<8;
+   /* fallthrough */
     case 9 : c+=k[8];
+   /* fallthrough */
     case 8 : b+=((uint32_t)k[7])<<24;
+   /* fallthrough */
     case 7 : b+=((uint32_t)k[6])<<16;
+   /* fallthrough */
     case 6 : b+=((uint32_t)k[5])<<8;
+   /* fallthrough */
     case 5 : b+=k[4];
+   /* fallthrough */
     case 4 : a+=((uint32_t)k[3])<<24;
+   /* fallthrough */
     case 3 : a+=((uint32_t)k[2])<<16;
+   /* fallthrough */
     case 2 : a+=((uint32_t)k[1])<<8;
+   /* fallthrough */
     case 1 : a+=k[0];
              break;
     case 0 : return c;
diff --git namedb.c namedb.c
index bcc41aad926..bc7690d87b6 100644
--- namedb.c
+++ namedb.c
@@ -73,15 +73,11 @@ allocate_domain_nsec3(domain_table_type* table, domain_type* result)
  result->nsec3->nsec3_ds_parent_cover = NULL;
  result->nsec3->nsec3_is_exact = 0;
  result->nsec3->nsec3_ds_parent_is_exact = 0;
- result->nsec3->have_nsec3_hash = 0;
- result->nsec3->have_nsec3_wc_hash = 0;
- result->nsec3->have_nsec3_ds_parent_hash = 0;
+ result->nsec3->hash_wc = NULL;
+ result->nsec3->ds_parent_hash = NULL;
  result->nsec3->prehash_prev = NULL;
  result->nsec3->prehash_next = NULL;
  result->nsec3->nsec3_node.key = NULL;
- result->nsec3->hash_node.key = NULL;
- result->nsec3->wchash_node.key = NULL;
- result->nsec3->dshash_node.key = NULL;
 }
 #endif /* NSEC3 */
 
@@ -89,7 +85,7 @@ allocate_domain_nsec3(domain_table_type* table, domain_type* result)
 static void
 numlist_make_last(domain_table_type* table, domain_type* domain)
 {
- size_t sw;
+ uint32_t sw;
  domain_type* last = table->numlist_last;
  if(domain == last)
  return;
@@ -235,15 +231,17 @@ do_deldomain(namedb_type* db, domain_type* domain)
  if(domain->nsec3->nsec3_node.key)
  zone_del_domain_in_hash_tree(nsec3_tree_zone(db, domain)
  ->nsec3tree, &domain->nsec3->nsec3_node);
- if(domain->nsec3->hash_node.key)
- zone_del_domain_in_hash_tree(nsec3_tree_zone(db, domain)
- ->hashtree, &domain->nsec3->hash_node);
- if(domain->nsec3->wchash_node.key)
- zone_del_domain_in_hash_tree(nsec3_tree_zone(db, domain)
- ->wchashtree, &domain->nsec3->wchash_node);
- if(domain->nsec3->dshash_node.key)
+ if(domain->nsec3->hash_wc) {
+ if(domain->nsec3->hash_wc->hash.node.key)
+ zone_del_domain_in_hash_tree(nsec3_tree_zone(db, domain)
+ ->hashtree, &domain->nsec3->hash_wc->hash.node);
+ if(domain->nsec3->hash_wc->wc.node.key)
+ zone_del_domain_in_hash_tree(nsec3_tree_zone(db, domain)
+ ->wchashtree, &domain->nsec3->hash_wc->wc.node);
+ }
+ if(domain->nsec3->ds_parent_hash && domain->nsec3->ds_parent_hash->node.key)
  zone_del_domain_in_hash_tree(nsec3_tree_dszone(db, domain)
- ->dshashtree, &domain->nsec3->dshash_node);
+ ->dshashtree, &domain->nsec3->ds_parent_hash->node);
  region_recycle(db->domains->region, domain->nsec3,
  sizeof(struct nsec3_domain_data));
  }
diff --git namedb.h namedb.h
index e2d84517854..c7cf6d96802 100644
--- namedb.h
+++ namedb.h
@@ -53,6 +53,20 @@ struct domain_table
 };
 
 #ifdef NSEC3
+typedef struct nsec3_hash_node nsec3_hash_node_type;
+struct nsec3_hash_node {
+ /* hash value */
+ uint8_t hash[NSEC3_HASH_LEN];
+ /* entry in the hashtree */
+ rbnode_type node;
+} ATTR_PACKED;
+
+typedef struct nsec3_hash_wc_node nsec3_hash_wc_node_type;
+struct nsec3_hash_wc_node {
+ nsec3_hash_node_type hash;
+ nsec3_hash_node_type wc;
+};
+
 struct nsec3_domain_data {
  /* (if nsec3 chain complete) always the covering nsec3 record */
  domain_type* nsec3_cover;
@@ -64,28 +78,18 @@ struct nsec3_domain_data {
  domain_type* prehash_prev, *prehash_next;
  /* entry in the nsec3tree (for NSEC3s in the chain in use) */
  rbnode_type nsec3_node;
- /* entry in the hashtree (for precompiled domains) */
- rbnode_type hash_node;
- /* entry in the wchashtree (the wildcard precompile) */
- rbnode_type wchash_node;
- /* entry in the dshashtree (the parent ds precompile) */
- rbnode_type dshash_node;
-
- /* nsec3 hash */
- uint8_t nsec3_hash[NSEC3_HASH_LEN];
- /* nsec3 hash of wildcard before this name */
- uint8_t nsec3_wc_hash[NSEC3_HASH_LEN];
- /* parent-side DS hash */
- uint8_t nsec3_ds_parent_hash[NSEC3_HASH_LEN];
- /* if the nsec3 has is available */
- unsigned  have_nsec3_hash : 1;
- unsigned  have_nsec3_wc_hash : 1;
- unsigned  have_nsec3_ds_parent_hash : 1;
+
+ /* node for the precompiled domain and the precompiled wildcard */
+ nsec3_hash_wc_node_type* hash_wc;
+
+ /* node for the precompiled parent ds */
+ nsec3_hash_node_type* ds_parent_hash;
+
  /* if the domain has an NSEC3 for it, use cover ptr to get it. */
  unsigned     nsec3_is_exact : 1;
  /* same but on parent side */
  unsigned     nsec3_ds_parent_is_exact : 1;
-};
+} ATTR_PACKED;
 #endif /* NSEC3 */
 
 struct domain
@@ -104,8 +108,8 @@ struct domain
 #endif
  /* double-linked list sorted by domain.number */
  domain_type* numlist_prev, *numlist_next;
- size_t     number; /* Unique domain name number.  */
- size_t     usage; /* number of ptrs to this from RRs(in rdata) and
+ uint32_t     number; /* Unique domain name number.  */
+ uint32_t     usage; /* number of ptrs to this from RRs(in rdata) and
      from zone-apex pointers, also the root has one
      more to make sure it cannot be deleted. */
 
@@ -114,7 +118,7 @@ struct domain
  */
  unsigned     is_existing : 1;
  unsigned     is_apex : 1;
-};
+} ATTR_PACKED;
 
 struct zone
 {
@@ -140,7 +144,7 @@ struct zone
  unsigned     is_secure : 1; /* zone uses DNSSEC */
  unsigned     is_ok : 1; /* zone has not expired. */
  unsigned     is_changed : 1; /* zone was changed by AXFR */
-};
+} ATTR_PACKED;
 
 /* a RR in DNS */
 struct rr {
@@ -150,7 +154,7 @@ struct rr {
  uint16_t         type;
  uint16_t         klass;
  uint16_t         rdata_count;
-};
+} ATTR_PACKED;
 
 /*
  * An RRset consists of at least one RR.  All RRs are from the same
@@ -162,7 +166,7 @@ struct rrset
  zone_type*  zone;
  rr_type*    rrs;
  uint16_t    rr_count;
-};
+} ATTR_PACKED;
 
 /*
  * The field used is based on the wireformat the atom is stored in.
diff --git netio.c netio.c
index 6c4b395babe..58fd2e18b49 100644
--- netio.c
+++ netio.c
@@ -94,7 +94,7 @@ netio_current_time(netio_type *netio)
  if (!netio->have_current_time) {
  struct timeval current_timeval;
  if (gettimeofday(&current_timeval, NULL) == -1) {
- log_msg(LOG_CRIT, "gettimeofday: %s, aborting.", strerror(errno));
+ log_msg(LOG_ERR, "gettimeofday: %s, aborting.", strerror(errno));
  abort();
  }
  timeval_to_timespec(&netio->cached_current_time, &current_timeval);
diff --git nsd.c nsd.c
index f2cf6ccf0cb..dfbc58696b3 100644
--- nsd.c
+++ nsd.c
@@ -579,6 +579,7 @@ main(int argc, char *argv[])
  case 'v':
  version();
  /* version exits */
+ break;
 #ifndef NDEBUG
  case 'F':
  sscanf(optarg, "%x", &nsd_debug_facilities);
@@ -980,6 +981,7 @@ main(int argc, char *argv[])
  break;
  case -1:
  error("fork() failed: %s", strerror(errno));
+ break;
  default:
  /* Parent is done */
  server_close_all_sockets(nsd.udp, nsd.ifs);
diff --git nsec3.c nsec3.c
index 960e7216dad..dad4f23d7bf 100644
--- nsec3.c
+++ nsec3.c
@@ -29,8 +29,10 @@ cmp_hash_tree(const void* x, const void* y)
  const domain_type* b = (const domain_type*)y;
  if(!a->nsec3) return (b->nsec3?-1:0);
  if(!b->nsec3) return 1;
- return memcmp(a->nsec3->nsec3_hash, b->nsec3->nsec3_hash,
- NSEC3_HASH_LEN);
+ if(!a->nsec3->hash_wc) return (b->nsec3->hash_wc?-1:0);
+ if(!b->nsec3->hash_wc) return 1;
+ return memcmp(a->nsec3->hash_wc->hash.hash,
+ b->nsec3->hash_wc->hash.hash, NSEC3_HASH_LEN);
 }
 
 /* compare nsec3 hashes in nsec3 wc tree */
@@ -41,8 +43,10 @@ cmp_wchash_tree(const void* x, const void* y)
  const domain_type* b = (const domain_type*)y;
  if(!a->nsec3) return (b->nsec3?-1:0);
  if(!b->nsec3) return 1;
- return memcmp(a->nsec3->nsec3_wc_hash, b->nsec3->nsec3_wc_hash,
- NSEC3_HASH_LEN);
+ if(!a->nsec3->hash_wc) return (b->nsec3->hash_wc?-1:0);
+ if(!b->nsec3->hash_wc) return 1;
+ return memcmp(a->nsec3->hash_wc->wc.hash,
+ b->nsec3->hash_wc->wc.hash, NSEC3_HASH_LEN);
 }
 
 /* compare nsec3 hashes in nsec3 ds tree */
@@ -53,8 +57,10 @@ cmp_dshash_tree(const void* x, const void* y)
  const domain_type* b = (const domain_type*)y;
  if(!a->nsec3) return (b->nsec3?-1:0);
  if(!b->nsec3) return 1;
- return memcmp(a->nsec3->nsec3_ds_parent_hash,
- b->nsec3->nsec3_ds_parent_hash, NSEC3_HASH_LEN);
+ if(!a->nsec3->ds_parent_hash) return (b->nsec3->ds_parent_hash?-1:0);
+ if(!b->nsec3->ds_parent_hash) return 1;
+ return memcmp(a->nsec3->ds_parent_hash->hash,
+ b->nsec3->ds_parent_hash->hash, NSEC3_HASH_LEN);
 }
 
 /* compare base32-encoded nsec3 hashes in nsec3 rr tree, they are
@@ -129,32 +135,36 @@ nsec3_hash_and_store(zone_type* zone, const dname_type* dname, uint8_t* store)
 
 /** find hash or create it and store it */
 static void
-nsec3_lookup_hash_and_wc(zone_type* zone, const dname_type* dname,
- domain_type* domain, region_type* tmpregion)
+nsec3_lookup_hash_and_wc(region_type* region, zone_type* zone,
+ const dname_type* dname, domain_type* domain, region_type* tmpregion)
 {
  const dname_type* wcard;
- if(domain->nsec3->have_nsec3_hash && domain->nsec3->have_nsec3_wc_hash) {
+ if(domain->nsec3->hash_wc) {
  return;
  }
  /* lookup failed; disk failure or so */
- nsec3_hash_and_store(zone, dname, domain->nsec3->nsec3_hash);
- domain->nsec3->have_nsec3_hash = 1;
+ domain->nsec3->hash_wc = (nsec3_hash_wc_node_type *)
+ region_alloc(region, sizeof(nsec3_hash_wc_node_type));
+ domain->nsec3->hash_wc->hash.node.key = NULL;
+ domain->nsec3->hash_wc->wc.node.key = NULL;
+ nsec3_hash_and_store(zone, dname, domain->nsec3->hash_wc->hash.hash);
  wcard = dname_parse(tmpregion, "*");
  wcard = dname_concatenate(tmpregion, wcard, dname);
- nsec3_hash_and_store(zone, wcard, domain->nsec3->nsec3_wc_hash);
- domain->nsec3->have_nsec3_wc_hash = 1;
+ nsec3_hash_and_store(zone, wcard, domain->nsec3->hash_wc->wc.hash);
 }
 
 static void
-nsec3_lookup_hash_ds(zone_type* zone, const dname_type* dname,
- domain_type* domain)
+nsec3_lookup_hash_ds(region_type* region, zone_type* zone,
+ const dname_type* dname, domain_type* domain)
 {
- if(domain->nsec3->have_nsec3_ds_parent_hash) {
+ if(domain->nsec3->ds_parent_hash) {
  return;
  }
  /* lookup failed; disk failure or so */
- nsec3_hash_and_store(zone, dname, domain->nsec3->nsec3_ds_parent_hash);
- domain->nsec3->have_nsec3_ds_parent_hash = 1;
+ domain->nsec3->ds_parent_hash = (nsec3_hash_node_type *)
+ region_alloc(region, sizeof(nsec3_hash_node_type));
+ domain->nsec3->ds_parent_hash->node.key = NULL;
+ nsec3_hash_and_store(zone, dname, domain->nsec3->ds_parent_hash->hash);
 }
 
 static int
@@ -380,17 +390,23 @@ nsec3_clear_precompile(struct namedb* db, zone_type* zone)
  walk->nsec3->nsec3_cover = NULL;
  walk->nsec3->nsec3_wcard_child_cover = NULL;
  walk->nsec3->nsec3_is_exact = 0;
- walk->nsec3->have_nsec3_hash = 0;
- walk->nsec3->have_nsec3_wc_hash = 0;
- walk->nsec3->hash_node.key = NULL;
- walk->nsec3->wchash_node.key = NULL;
+ if (walk->nsec3->hash_wc) {
+ region_recycle(db->domains->region,
+ walk->nsec3->hash_wc,
+ sizeof(nsec3_hash_wc_node_type));
+ walk->nsec3->hash_wc = NULL;
+ }
  }
  if(!walk->parent ||
  nsec3_domain_part_of_zone(walk->parent, zone)) {
  walk->nsec3->nsec3_ds_parent_cover = NULL;
  walk->nsec3->nsec3_ds_parent_is_exact = 0;
- walk->nsec3->have_nsec3_ds_parent_hash = 0;
- walk->nsec3->dshash_node.key = NULL;
+ if (walk->nsec3->ds_parent_hash) {
+ region_recycle(db->domains->region,
+ walk->nsec3->ds_parent_hash,
+ sizeof(nsec3_hash_node_type));
+ walk->nsec3->ds_parent_hash = NULL;
+ }
  }
  }
  walk = domain_next(walk);
@@ -503,25 +519,26 @@ nsec3_precompile_domain(struct namedb* db, struct domain* domain,
  allocate_domain_nsec3(db->domains, domain);
 
  /* hash it */
- nsec3_lookup_hash_and_wc(zone, domain_dname(domain), domain, tmpregion);
+ nsec3_lookup_hash_and_wc(db->region,
+ zone, domain_dname(domain), domain, tmpregion);
 
  /* add into tree */
  zone_add_domain_in_hash_tree(db->region, &zone->hashtree,
- cmp_hash_tree, domain, &domain->nsec3->hash_node);
+ cmp_hash_tree, domain, &domain->nsec3->hash_wc->hash.node);
  zone_add_domain_in_hash_tree(db->region, &zone->wchashtree,
- cmp_wchash_tree, domain, &domain->nsec3->wchash_node);
+ cmp_wchash_tree, domain, &domain->nsec3->hash_wc->wc.node);
 
  /* lookup in tree cover ptr (or exact) */
- exact = nsec3_find_cover(zone, domain->nsec3->nsec3_hash,
- sizeof(domain->nsec3->nsec3_hash), &result);
+ exact = nsec3_find_cover(zone, domain->nsec3->hash_wc->hash.hash,
+ sizeof(domain->nsec3->hash_wc->hash.hash), &result);
  domain->nsec3->nsec3_cover = result;
  if(exact)
  domain->nsec3->nsec3_is_exact = 1;
  else domain->nsec3->nsec3_is_exact = 0;
 
  /* find cover for *.domain for wildcard denial */
- exact = nsec3_find_cover(zone, domain->nsec3->nsec3_wc_hash,
- sizeof(domain->nsec3->nsec3_wc_hash), &result);
+ exact = nsec3_find_cover(zone, domain->nsec3->hash_wc->wc.hash,
+ sizeof(domain->nsec3->hash_wc->wc.hash), &result);
  domain->nsec3->nsec3_wcard_child_cover = result;
 }
 
@@ -535,17 +552,17 @@ nsec3_precompile_domain_ds(struct namedb* db, struct domain* domain,
 
  /* hash it : it could have different hash parameters then the
    other hash for this domain name */
- nsec3_lookup_hash_ds(zone, domain_dname(domain), domain);
+ nsec3_lookup_hash_ds(db->region, zone, domain_dname(domain), domain);
  /* lookup in tree cover ptr (or exact) */
- exact = nsec3_find_cover(zone, domain->nsec3->nsec3_ds_parent_hash,
- sizeof(domain->nsec3->nsec3_ds_parent_hash), &result);
+ exact = nsec3_find_cover(zone, domain->nsec3->ds_parent_hash->hash,
+ sizeof(domain->nsec3->ds_parent_hash->hash), &result);
  if(exact)
  domain->nsec3->nsec3_ds_parent_is_exact = 1;
  else domain->nsec3->nsec3_ds_parent_is_exact = 0;
  domain->nsec3->nsec3_ds_parent_cover = result;
  /* add into tree */
  zone_add_domain_in_hash_tree(db->region, &zone->dshashtree,
- cmp_dshash_tree, domain, &domain->nsec3->dshash_node);
+ cmp_dshash_tree, domain, &domain->nsec3->ds_parent_hash->node);
 }
 
 static void
@@ -644,15 +661,15 @@ prehash_zone_complete(struct namedb* db, struct zone* zone)
 
 static void
 init_lookup_key_hash_tree(domain_type* d, uint8_t* hash)
-{ memcpy(d->nsec3->nsec3_hash, hash, NSEC3_HASH_LEN); }
+{ memcpy(d->nsec3->hash_wc->hash.hash, hash, NSEC3_HASH_LEN); }
 
 static void
 init_lookup_key_wc_tree(domain_type* d, uint8_t* hash)
-{ memcpy(d->nsec3->nsec3_wc_hash, hash, NSEC3_HASH_LEN); }
+{ memcpy(d->nsec3->hash_wc->wc.hash, hash, NSEC3_HASH_LEN); }
 
 static void
 init_lookup_key_ds_tree(domain_type* d, uint8_t* hash)
-{ memcpy(d->nsec3->nsec3_ds_parent_hash, hash, NSEC3_HASH_LEN); }
+{ memcpy(d->nsec3->ds_parent_hash->hash, hash, NSEC3_HASH_LEN); }
 
 /* find first in the tree and true if the first to process it */
 static int
@@ -661,10 +678,18 @@ process_first(rbtree_type* tree, uint8_t* hash, rbnode_type** p,
 {
  domain_type d;
  struct nsec3_domain_data n;
+ nsec3_hash_wc_node_type hash_wc;
+ nsec3_hash_node_type ds_parent_hash;
+
  if(!tree) {
  *p = RBTREE_NULL;
  return 0;
  }
+ hash_wc.hash.node.key = NULL;
+ hash_wc.wc.node.key = NULL;
+ n.hash_wc = &hash_wc;
+ ds_parent_hash.node.key = NULL;
+ n.ds_parent_hash = &ds_parent_hash;
  d.nsec3 = &n;
  init(&d, hash);
  if(rbtree_find_less_equal(tree, &d, p)) {
@@ -687,10 +712,18 @@ process_end(rbtree_type* tree, uint8_t* hash, rbnode_type** p,
 {
  domain_type d;
  struct nsec3_domain_data n;
+ nsec3_hash_wc_node_type hash_wc;
+ nsec3_hash_node_type ds_parent_hash;
+
  if(!tree) {
  *p = RBTREE_NULL;
  return;
  }
+ hash_wc.hash.node.key = NULL;
+ hash_wc.wc.node.key = NULL;
+ n.hash_wc = &hash_wc;
+ ds_parent_hash.node.key = NULL;
+ n.ds_parent_hash = &ds_parent_hash;
  d.nsec3 = &n;
  init(&d, hash);
  if(rbtree_find_less_equal(tree, &d, p)) {
@@ -854,9 +887,34 @@ nsec3_add_nonexist_proof(struct query* query, struct answer* answer,
  if(nsec3_find_cover(query->zone, hash, sizeof(hash), &cover))
  {
  /* exact match, hash collision */
+ domain_type* walk;
+ char hashbuf[512];
+ char reversebuf[512];
+ (void)b32_ntop(hash, sizeof(hash), hashbuf, sizeof(hashbuf));
+ snprintf(reversebuf, sizeof(reversebuf), "(no name in the zone hashes to this nsec3 record)");
+ walk = query->zone->apex;
+ while(walk) {
+ if(walk->nsec3 && walk->nsec3->nsec3_cover == cover) {
+ snprintf(reversebuf, sizeof(reversebuf),
+ "%s %s", domain_to_string(walk),
+ walk->nsec3->nsec3_is_exact?"exact":"no_exact_hash_match");
+ if(walk->nsec3->nsec3_is_exact)
+ break;
+ }
+ if(walk->nsec3 && walk->nsec3->nsec3_ds_parent_cover == cover) {
+ snprintf(reversebuf, sizeof(reversebuf),
+ "%s %s", domain_to_string(walk),
+ walk->nsec3->nsec3_ds_parent_is_exact?"exact":"no_exact_hash_match");
+ if(walk->nsec3->nsec3_ds_parent_is_exact)
+ break;
+ }
+ walk = domain_next(walk);
+ }
+
+
  /* the hashed name of the query corresponds to an existing name. */
- VERBOSITY(3, (LOG_ERR, "nsec3 hash collision for name=%s",
- dname_to_string(to_prove, NULL)));
+ VERBOSITY(3, (LOG_ERR, "nsec3 hash collision for name=%s hash=%s reverse=%s",
+ dname_to_string(to_prove, NULL), hashbuf, reversebuf));
  RCODE_SET(query->packet, RCODE_SERVFAIL);
  return;
  }
diff --git options.h options.h
index dedb9bfb662..bbfbbf98c41 100644
--- options.h
+++ options.h
@@ -165,7 +165,7 @@ struct pattern_options {
  uint8_t min_retry_time_is_default;
  uint64_t size_limit_xfr;
  uint8_t multi_master_check;
-};
+} ATTR_PACKED;
 
 #define PATTERN_IMPLICIT_MARKER "_implicit_"
 
@@ -186,7 +186,7 @@ struct zone_options {
  struct pattern_options* pattern;
  /* zone is fixed into the main config, not in zonelist, cannot delete */
  uint8_t part_of_config;
-};
+} ATTR_PACKED;
 
 union acl_addr_storage {
 #ifdef INET6
@@ -227,7 +227,7 @@ struct acl_options {
  uint8_t blocked;
  const char* key_name;
  struct key_options* key_options;
-};
+} ATTR_PACKED;
 
 /*
  * Key definition
@@ -238,7 +238,7 @@ struct key_options {
  char* algorithm;
  char* secret;
  struct tsig_key* tsig_key;
-};
+} ATTR_PACKED;
 
 /** zone list free space */
 struct zonelist_free {
diff --git query.c query.c
index d6e45a2e9d3..7b862a45bc7 100644
--- query.c
+++ query.c
@@ -1241,8 +1241,15 @@ answer_lookup_zone(struct nsd *nsd, struct query *q, answer_type *answer,
  * authoritative for the parent zone.
  */
  zone_type *zone = domain_find_parent_zone(nsd->db, q->zone);
- if (zone)
+ if (zone) {
  q->zone = zone;
+ if(!q->zone->apex || !q->zone->soa_rrset) {
+ /* zone is configured but not loaded */
+ if(q->cname_count == 0)
+ RCODE_SET(q->packet, RCODE_SERVFAIL);
+ return;
+ }
+ }
  }
 
  /* see if the zone has expired (for secondary zones) */
diff --git radtree.h radtree.h
index fdc58e7a903..c5d830a138b 100644
--- radtree.h
+++ radtree.h
@@ -49,7 +49,7 @@ struct radnode {
  uint16_t capacity;
  /** the lookup array by [byte-offset] */
  struct radsel* array;
-};
+} ATTR_PACKED;
 
 /**
  * radix select edge in array
@@ -61,7 +61,7 @@ struct radsel {
  radstrlen_type len;
  /** node that deals with byte+str */
  struct radnode* node;
-};
+} ATTR_PACKED;
 
 /**
  * Create new radix tree
diff --git rbtree.h rbtree.h
index d6e54862a23..eb9b3941245 100644
--- rbtree.h
+++ rbtree.h
@@ -24,7 +24,7 @@ struct rbnode {
  rbnode_type  *right;
  const void   *key;
  uint8_t      color;
-};
+} ATTR_PACKED;
 
 #define RBTREE_NULL &rbtree_null_node
 extern rbnode_type rbtree_null_node;
@@ -44,7 +44,7 @@ struct rbtree {
 
  /* Key compare function. <0,0,>0 like strcmp. Return 0 on two NULL ptrs. */
  int (*cmp) (const void *, const void *);
-};
+} ATTR_PACKED;
 
 /* rbtree.c */
 rbtree_type *rbtree_create(region_type *region, int (*cmpf)(const void *, const void *));
diff --git region-allocator.c region-allocator.c
index 95454a66678..8b5d2c77989 100644
--- region-allocator.c
+++ region-allocator.c
@@ -23,12 +23,17 @@
 #ifdef ALIGNMENT
 #undef ALIGNMENT
 #endif
+#ifndef PACKED_STRUCTS
 #define REGION_ALIGN_UP(x, s)     (((x) + s - 1) & (~(s - 1)))
 #if SIZEOF_OFF_T > SIZEOF_VOIDP
 #define ALIGNMENT (sizeof(off_t))
 #else
 #define ALIGNMENT (sizeof(void *))
 #endif
+#else
+#define REGION_ALIGN_UP(x, s) ((x)<SIZEOF_VOIDP?SIZEOF_VOIDP:(x))
+#define ALIGNMENT 1
+#endif /* PACKED_STRUCTS */
 /* #define CHECK_DOUBLE_FREE 0 */ /* set to 1 to perform expensive check for double recycle() */
 
 typedef struct cleanup cleanup_type;
@@ -285,7 +290,13 @@ region_alloc(region_type *region, size_t size)
  return NULL;
 
  wasted = (region->chunk_size - region->allocated) & (~(ALIGNMENT-1));
- if(wasted >= ALIGNMENT) {
+ if(
+#ifndef PACKED_STRUCTS
+ wasted >= ALIGNMENT
+#else
+ wasted >= SIZEOF_VOIDP
+#endif
+ ) {
  /* put wasted part in recycle bin for later use */
  region->total_allocated += wasted;
  ++region->small_objects;
diff --git remote.c remote.c
index f7c88222b68..d3f5153d549 100644
--- remote.c
+++ remote.c
@@ -958,10 +958,17 @@ print_zonestatus(SSL* ssl, xfrd_state_type* xfrd, struct zone_options* zo)
  if(nz->is_waiting) {
  if(!ssl_printf(ssl, " notify: \"waiting-for-fd\"\n"))
  return 0;
- } else if(nz->notify_send_enable) {
- if(!ssl_printf(ssl, " notify: \"sent try %d "
- "to %s with serial %u\"\n", nz->notify_retry,
- nz->notify_current->ip_address_spec,
+ } else if(nz->notify_send_enable || nz->notify_send6_enable) {
+ int i;
+ if(!ssl_printf(ssl, " notify: \"send"))
+ return 0;
+ for(i=0; i<NOTIFY_CONCURRENT_MAX; i++) {
+ if(!nz->pkts[i].dest) continue;
+ if(!ssl_printf(ssl, " %s",
+ nz->pkts[i].dest->ip_address_spec))
+ return 0;
+ }
+ if(!ssl_printf(ssl, " with serial %u\"\n",
  (unsigned)ntohl(nz->current_soa->serial)))
  return 0;
  }
@@ -985,6 +992,10 @@ print_zonestatus(SSL* ssl, xfrd_state_type* xfrd, struct zone_options* zo)
  if(!print_soa_status(ssl, "notified-serial", &xz->soa_notified,
  xz->soa_notified_acquired))
  return 0;
+ } else if(xz->event_added) {
+ if(!ssl_printf(ssl, "\twait: \"%u sec between attempts\"\n",
+ (unsigned)xz->timeout.tv_sec))
+ return 0;
  }
 
  /* UDP */
diff --git rrl.c rrl.c
index 2a7ca4f05b7..c8dec3fc908 100644
--- rrl.c
+++ rrl.c
@@ -156,7 +156,7 @@ static const char* rrlsource2str(uint64_t s, uint16_t c2)
  if(!inet_ntop(AF_INET6, &a6, buf, sizeof(buf)))
  strlcpy(buf, "[ip6 ntop failed]", sizeof(buf));
  else {
- static char prefix[4];
+ static char prefix[5];
  snprintf(prefix, sizeof(prefix), "/%d", rrl_ipv6_prefixlen);
  strlcat(buf, &prefix[0], sizeof(buf));
  }
@@ -170,7 +170,7 @@ static const char* rrlsource2str(uint64_t s, uint16_t c2)
  if(!inet_ntop(AF_INET, &a4, buf, sizeof(buf)))
  strlcpy(buf, "[ip4 ntop failed]", sizeof(buf));
  else {
- static char prefix[4];
+ static char prefix[5];
  snprintf(prefix, sizeof(prefix), "/%d", rrl_ipv4_prefixlen);
  strlcat(buf, &prefix[0], sizeof(buf));
  }
diff --git util.h util.h
index b59b7b69bd1..5f00911d0a1 100644
--- util.h
+++ util.h
@@ -25,6 +25,10 @@ struct region;
 #  define LOG_WARNING 4
 #  define LOG_NOTICE 5
 #  define LOG_INFO 6
+
+/* Unused, but passed to log_open. */
+#  define LOG_PID 0x01
+#  define LOG_DAEMON (3<<3)
 #endif
 
 #define ALIGN_UP(n, alignment)  \
diff --git xfr-inspect.c xfr-inspect.c
new file mode 100644
index 00000000000..e31d64a413a
--- /dev/null
+++ xfr-inspect.c
@@ -0,0 +1,531 @@
+/* xfr-inspect - list the contents and inspect an zone transfer XFR file
+ * By W.C.A. Wijngaards
+ * Copyright 2017, NLnet Labs.
+ * BSD, see LICENSE.
+ */
+
+#include "config.h"
+#include "udbzone.h"
+#include "util.h"
+#include "buffer.h"
+#include "packet.h"
+#include "rdata.h"
+#include "namedb.h"
+#include "difffile.h"
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+
+/** verbosity for inspect */
+static int v = 0;
+/** shorthand for ease */
+#ifdef ULL
+#undef ULL
+#endif
+#define ULL (unsigned long long)
+
+/** print usage text */
+static void
+usage(void)
+{
+ printf("usage: xfr-inspect [options] file\n");
+ printf(" -h this help\n");
+ printf(" -v increase verbosity: "
+       "with -v(list chunks), -vv(inside chunks)\n");
+ printf(" -l list contents of transfer\n");
+}
+
+static int
+xi_diff_read_64(FILE *in, uint64_t* result)
+{
+ if (fread(result, sizeof(*result), 1, in) == 1) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static int
+xi_diff_read_32(FILE *in, uint32_t* result)
+{
+ if (fread(result, sizeof(*result), 1, in) == 1) {
+ *result = ntohl(*result);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static int
+xi_diff_read_8(FILE *in, uint8_t* result)
+{
+        if (fread(result, sizeof(*result), 1, in) == 1) {
+                return 1;
+        } else {
+                return 0;
+        }
+}
+
+static int
+xi_diff_read_str(FILE* in, char* buf, size_t len)
+{
+ uint32_t disklen;
+ if(!xi_diff_read_32(in, &disklen))
+ return 0;
+ if(disklen >= len)
+ return 0;
+ if(fread(buf, disklen, 1, in) != 1)
+ return 0;
+ buf[disklen] = 0;
+ return 1;
+}
+
+
+/** inspect header of xfr file, return num_parts */
+static int
+inspect_header(FILE* in)
+{
+ char zone_buf[3072];
+ char patname_buf[2048];
+
+ uint32_t old_serial, new_serial, num_parts, type;
+ uint64_t time_end_0, time_start_0;
+ uint32_t time_end_1, time_start_1;
+ uint8_t committed;
+
+ time_t time_end, time_start;
+
+ if(!xi_diff_read_32(in, &type)) {
+ printf("could not read type, file short\n");
+ fclose(in);
+ exit(1);
+ }
+ if(type != DIFF_PART_XFRF) {
+ printf("type: %x (BAD FILE TYPE)\n", type);
+ fclose(in);
+ exit(1);
+ }
+ if(!xi_diff_read_8(in, &committed) ||
+ !xi_diff_read_32(in, &num_parts) ||
+ !xi_diff_read_64(in, &time_end_0) ||
+ !xi_diff_read_32(in, &time_end_1) ||
+ !xi_diff_read_32(in, &old_serial) ||
+ !xi_diff_read_32(in, &new_serial) ||
+ !xi_diff_read_64(in, &time_start_0) ||
+ !xi_diff_read_32(in, &time_start_1) ||
+ !xi_diff_read_str(in, zone_buf, sizeof(zone_buf)) ||
+ !xi_diff_read_str(in, patname_buf, sizeof(patname_buf))) {
+ printf("diff file bad commit part, file too short");
+ fclose(in);
+ exit(1);
+ }
+ time_end = (time_t)time_end_0;
+ time_start = (time_t)time_start_0;
+
+ /* printf("type: %x\n", (int)type); */
+ printf("committed: %d (%s)\n", (int)committed,
+ committed?"yes":"no");
+ printf("num_parts: %d\n", (int)num_parts);
+ printf("time_end: %d.%6.6d %s", (int)time_end_0,
+ (int)time_end_1, ctime(&time_end));
+ printf("old_serial: %u\n", (unsigned)old_serial);
+ printf("new_serial: %u\n", (unsigned)new_serial);
+ printf("time_start: %d.%6.6d %s", (int)time_start_0,
+ (int)time_start_1, ctime(&time_start));
+ printf("zone: %s\n", zone_buf);
+ printf("patname: %s\n", patname_buf);
+
+ return num_parts;
+}
+
+/** print records in packet */
+static void
+print_records(region_type* region, buffer_type* pkt, int num, int qsection)
+{
+ domain_table_type* table;
+ int i;
+ rr_type* rr;
+ region_type* tmpregion = region_create(xalloc, free);
+ buffer_type* tmpbuf;
+ if(!tmpregion) {
+ printf("out of memory\n");
+ return;
+ }
+ tmpbuf = buffer_create(region, QIOBUFSZ);
+ if(!tmpbuf) {
+ printf("out of memory\n");
+ return;
+ }
+ table = domain_table_create(tmpregion);
+ if(!table) {
+ printf("out of memory\n");
+ return;
+ }
+
+ for(i=0; i<num; ++i) {
+ rr = packet_read_rr(region, table, pkt, qsection);
+ if(!rr) {
+ printf("; cannot read rr %d\n", i);
+ return;
+ }
+ if(qsection) {
+ printf("%s", dname_to_string(domain_dname(rr->owner),
+ NULL));
+ printf("\t%s", rrclass_to_string(rr->klass));
+ if(rr->type == TYPE_IXFR)
+ printf("\tIXFR\n");
+ else if(rr->type == TYPE_AXFR)
+ printf("\tAXFR\n");
+ else printf("\t%s\n", rrtype_to_string(rr->type));
+ } else {
+ if(!print_rr(stdout, NULL, rr, tmpregion, tmpbuf)) {
+ printf("; cannot print rr %d\n", i);
+ }
+ }
+ }
+ region_destroy(tmpregion);
+}
+
+/** inspect packet (IXFR or AXFR) */
+static void
+inspect_packet(region_type* region, buffer_type* pkt)
+{
+ printf("\n");
+ if(buffer_limit(pkt) < QHEADERSZ) {
+ printf("packet too short\n");
+ return;
+ }
+ printf("; id=%4.4x ; flags%s%s%s%s%s%s%s%s ; rcode %s ; opcode %d\n",
+ ID(pkt), QR(pkt)?" QR":"", AA(pkt)?" AA":"", TC(pkt)?" TC":"",
+ RD(pkt)?" RD":"", RA(pkt)?" RA":"", Z(pkt)?" Z":"",
+ AD(pkt)?" AD":"", CD(pkt)?" CD":"", rcode2str(RCODE(pkt)),
+ OPCODE(pkt));
+ printf("; qdcount %d ; ancount %d ; nscount %d ; arcount %d\n",
+ QDCOUNT(pkt), ANCOUNT(pkt), NSCOUNT(pkt), ARCOUNT(pkt));
+ buffer_skip(pkt, QHEADERSZ);
+
+ if(QDCOUNT(pkt) != 0) {
+ printf("; QUESTION SECTION\n");
+ print_records(region, pkt, QDCOUNT(pkt), 1);
+ }
+ if(ANCOUNT(pkt) != 0) {
+ printf("; ANSWER SECTION\n");
+ print_records(region, pkt, ANCOUNT(pkt), 0);
+ }
+ if(NSCOUNT(pkt) != 0) {
+ printf("; AUTHORITY SECTION\n");
+ print_records(region, pkt, NSCOUNT(pkt), 0);
+ }
+ if(ARCOUNT(pkt) != 0) {
+ printf("; ADDITIONAL SECTION\n");
+ print_records(region, pkt, ARCOUNT(pkt), 0);
+ }
+}
+
+/** inspect part of xfr file */
+static void
+inspect_part(FILE* in, int partnum)
+{
+ uint32_t pkttype, msglen, msglen2;
+ region_type* region;
+ buffer_type* packet;
+ region = region_create(xalloc, free);
+ if(!region) {
+ printf("out of memory\n");
+ fclose(in);
+ exit(1);
+ }
+ packet = buffer_create(region, QIOBUFSZ);
+ if(!xi_diff_read_32(in, &pkttype)) {
+ printf("cannot read part %d\n", partnum);
+ fclose(in);
+ exit(1);
+ }
+ if(pkttype != DIFF_PART_XXFR) {
+ printf("bad part %d: not type XXFR\n", partnum);
+ fclose(in);
+ exit(1);
+ }
+ if(!xi_diff_read_32(in, &msglen)) {
+ printf("bad part %d: not msglen, file too short\n", partnum);
+ fclose(in);
+ exit(1);
+ }
+ if(msglen < QHEADERSZ || msglen > QIOBUFSZ) {
+ printf("bad part %d: msglen %u (too short or too long)\n",
+ partnum, (unsigned)msglen);
+ fclose(in);
+ exit(1);
+ }
+ if(fread(buffer_begin(packet), msglen, 1, in) != 1) {
+ printf("bad part %d: short packet, file too short, %s\n",
+ partnum, strerror(errno));
+ fclose(in);
+ exit(1);
+ }
+ if(!xi_diff_read_32(in, &msglen2)) {
+ printf("bad part %d: cannot read msglen2, file too short\n", partnum);
+ fclose(in);
+ exit(1);
+ }
+ if(v==0) {
+ region_destroy(region);
+ return;
+ }
+
+ printf("\n");
+ /* printf("type : %x\n", pkttype); */
+ printf("part : %d\n", partnum);
+ printf("msglen : %u\n", (unsigned)msglen);
+ printf("msglen2 : %u (%s)\n", (unsigned)msglen2,
+ (msglen==msglen2)?"ok":"wrong");
+
+ if(v>=2) {
+ buffer_set_limit(packet, msglen);
+ inspect_packet(region, packet);
+ }
+
+ region_destroy(region);
+}
+
+/** inspect parts of xfr file */
+static void
+inspect_parts(FILE* in, int num)
+{
+ int i;
+ for(i=0; i<num; i++) {
+ inspect_part(in, i);
+ }
+}
+
+/** inspect trail of xfr file */
+static void
+inspect_trail(FILE* in)
+{
+ char log_buf[5120];
+ if(!xi_diff_read_str(in, log_buf, sizeof(log_buf))) {
+ printf("bad trail: cannot read log string\n");
+ fclose(in);
+ exit(1);
+ }
+ printf("\n");
+ printf("log: %s\n", log_buf);
+}
+
+/** inspect contents of xfr file */
+static void
+inspect_file(char* fname)
+{
+ FILE* in;
+ int num;
+ log_init("udb-inspect");
+ if(!(in=fopen(fname, "r"))) {
+ printf("cannot open %s: %s\n", fname, strerror(errno));
+ exit(1);
+ }
+ printf("file: %s\n", fname);
+ num = inspect_header(in);
+ inspect_parts(in, num);
+ inspect_trail(in);
+ fclose(in);
+}
+
+/** list header of xfr file, return num_parts */
+static int
+list_header(FILE* in)
+{
+ char zone_buf[3072];
+ char patname_buf[2048];
+
+ uint32_t old_serial, new_serial, num_parts, type;
+ uint64_t time_end_0, time_start_0;
+ uint32_t time_end_1, time_start_1;
+ uint8_t committed;
+
+ time_t time_end, time_start;
+
+ if(!xi_diff_read_32(in, &type)) {
+ printf("could not read type, file short\n");
+ fclose(in);
+ exit(1);
+ }
+ if(type != DIFF_PART_XFRF) {
+ printf("type: %x (BAD FILE TYPE)\n", type);
+ fclose(in);
+ exit(1);
+ }
+ if(!xi_diff_read_8(in, &committed) ||
+ !xi_diff_read_32(in, &num_parts) ||
+ !xi_diff_read_64(in, &time_end_0) ||
+ !xi_diff_read_32(in, &time_end_1) ||
+ !xi_diff_read_32(in, &old_serial) ||
+ !xi_diff_read_32(in, &new_serial) ||
+ !xi_diff_read_64(in, &time_start_0) ||
+ !xi_diff_read_32(in, &time_start_1) ||
+ !xi_diff_read_str(in, zone_buf, sizeof(zone_buf)) ||
+ !xi_diff_read_str(in, patname_buf, sizeof(patname_buf))) {
+ printf("diff file bad commit part, file too short");
+ fclose(in);
+ exit(1);
+ }
+ time_end = (time_t)time_end_0;
+ time_start = (time_t)time_start_0;
+
+ /* printf("; type: %x\n", (int)type); */
+ printf("; commited: %d (%s)\n", (int)committed,
+ committed?"yes":"no");
+ printf("; num_parts: %d\n", (int)num_parts);
+ printf("; time_end: %d.%6.6d %s", (int)time_end_0,
+ (int)time_end_1, ctime(&time_end));
+ printf("; old_serial: %u\n", (unsigned)old_serial);
+ printf("; new_serial: %u\n", (unsigned)new_serial);
+ printf("; time_start: %d.%6.6d %s", (int)time_start_0,
+ (int)time_start_1, ctime(&time_start));
+ printf("; zone: %s\n", zone_buf);
+ printf("; patname: %s\n", patname_buf);
+
+ return num_parts;
+}
+
+/** list packet (IXFR or AXFR) */
+static void
+list_packet(region_type* region, buffer_type* pkt, int partnum)
+{
+ if(buffer_limit(pkt) < QHEADERSZ) {
+ printf("packet too short\n");
+ return;
+ }
+ buffer_skip(pkt, QHEADERSZ);
+
+ if(partnum == 0 && QDCOUNT(pkt) == 1) {
+ /* print query AXFR or IXFR */
+ printf("; ");
+ print_records(region, pkt, QDCOUNT(pkt), 1);
+ }
+ if(ANCOUNT(pkt) != 0) {
+ print_records(region, pkt, ANCOUNT(pkt), 0);
+ }
+}
+
+/** list part of xfr file */
+static void
+list_part(FILE* in, int partnum)
+{
+ uint32_t pkttype, msglen, msglen2;
+ region_type* region;
+ buffer_type* packet;
+ region = region_create(xalloc, free);
+ if(!region) {
+ printf("out of memory\n");
+ fclose(in);
+ exit(1);
+ }
+ packet = buffer_create(region, QIOBUFSZ);
+ if(!xi_diff_read_32(in, &pkttype)) {
+ printf("cannot read part %d\n", partnum);
+ fclose(in);
+ exit(1);
+ }
+ if(pkttype != DIFF_PART_XXFR) {
+ printf("bad part %d: not type XXFR\n", partnum);
+ fclose(in);
+ exit(1);
+ }
+ if(!xi_diff_read_32(in, &msglen)) {
+ printf("bad part %d: not msglen, file too short\n", partnum);
+ fclose(in);
+ exit(1);
+ }
+ if(msglen < QHEADERSZ || msglen > QIOBUFSZ) {
+ printf("bad part %d: msglen %u (too short or too long)\n",
+ partnum, (unsigned)msglen);
+ fclose(in);
+ exit(1);
+ }
+ if(fread(buffer_begin(packet), msglen, 1, in) != 1) {
+ printf("bad part %d: short packet, file too short, %s\n",
+ partnum, strerror(errno));
+ fclose(in);
+ exit(1);
+ }
+ if(!xi_diff_read_32(in, &msglen2)) {
+ printf("bad part %d: cannot read msglen2, file too short\n", partnum);
+ fclose(in);
+ exit(1);
+ }
+
+ buffer_set_limit(packet, msglen);
+ list_packet(region, packet, partnum);
+ region_destroy(region);
+}
+
+/** list parts of xfr file */
+static void
+list_parts(FILE* in, int num)
+{
+ int i;
+ for(i=0; i<num; i++) {
+ list_part(in, i);
+ }
+}
+
+/** list contents of xfr file */
+static void
+list_file(char* fname)
+{
+ FILE* in;
+ int num;
+ log_init("udb-inspect");
+ if(!(in=fopen(fname, "r"))) {
+ printf("cannot open %s: %s\n", fname, strerror(errno));
+ exit(1);
+ }
+ num = list_header(in);
+ list_parts(in, num);
+
+ fclose(in);
+}
+
+/** getopt global, in case header files fail to declare it. */
+extern int optind;
+/** getopt global, in case header files fail to declare it. */
+extern char* optarg;
+
+/**
+ * main program. Set options given commandline arguments.
+ * @param argc: number of commandline arguments.
+ * @param argv: array of commandline arguments.
+ * @return: exit status of the program.
+ */
+int
+main(int argc, char* argv[])
+{
+ int c, list=0;
+ while( (c=getopt(argc, argv, "hlv")) != -1) {
+ switch(c) {
+ case 'l':
+ list=1;
+ break;
+ case 'v':
+ v++;
+ break;
+ default:
+ case 'h':
+ usage();
+ return 1;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if(argc != 1) {
+ usage();
+ return 1;
+ }
+ if(list) list_file(argv[0]);
+ else inspect_file(argv[0]);
+
+ return 0;
+}
diff --git xfrd-notify.c xfrd-notify.c
index 918b32142c9..3f9853e6409 100644
--- xfrd-notify.c
+++ xfrd-notify.c
@@ -17,7 +17,7 @@
 #include "xfrd-tcp.h"
 #include "packet.h"
 
-#define XFRD_NOTIFY_RETRY_TIMOUT 15 /* seconds between retries sending NOTIFY */
+#define XFRD_NOTIFY_RETRY_TIMOUT 3 /* seconds between retries sending NOTIFY */
 
 /* start sending notifies */
 static void notify_enable(struct notify_zone* zone,
@@ -25,15 +25,10 @@ static void notify_enable(struct notify_zone* zone,
 /* setup the notify active state */
 static void setup_notify_active(struct notify_zone* zone);
 
-/* returns if the notify send is done for the notify_current acl */
-static int xfrd_handle_notify_reply(struct notify_zone* zone, buffer_type* packet);
-
 /* handle zone notify send */
 static void xfrd_handle_notify_send(int fd, short event, void* arg);
 
-static void xfrd_notify_next(struct notify_zone* zone);
-
-static void xfrd_notify_send_udp(struct notify_zone* zone, buffer_type* packet);
+static int xfrd_notify_send_udp(struct notify_zone* zone, int index);
 
 static void
 notify_send_disable(struct notify_zone* zone)
@@ -42,6 +37,18 @@ notify_send_disable(struct notify_zone* zone)
  event_del(&zone->notify_send_handler);
  if(zone->notify_send_handler.ev_fd != -1) {
  close(zone->notify_send_handler.ev_fd);
+ zone->notify_send_handler.ev_fd = -1;
+ }
+}
+
+static void
+notify_send6_disable(struct notify_zone* zone)
+{
+ zone->notify_send6_enable = 0;
+ event_del(&zone->notify_send6_handler);
+ if(zone->notify_send6_handler.ev_fd != -1) {
+ close(zone->notify_send6_handler.ev_fd);
+ zone->notify_send6_handler.ev_fd = -1;
  }
 }
 
@@ -53,6 +60,9 @@ notify_disable(struct notify_zone* zone)
  if(zone->notify_send_enable) {
  notify_send_disable(zone);
  }
+ if(zone->notify_send6_enable) {
+ notify_send6_disable(zone);
+ }
 
  if(xfrd->notify_udp_num == XFRD_MAX_UDP_NOTIFY) {
  /* find next waiting and needy zone */
@@ -96,9 +106,12 @@ init_notify_send(rbtree_type* tree, region_type* region,
  sizeof(struct xfrd_soa));
  memset(not->current_soa, 0, sizeof(struct xfrd_soa));
 
+ not->notify_send_handler.ev_fd = -1;
+ not->notify_send6_handler.ev_fd = -1;
  not->is_waiting = 0;
 
  not->notify_send_enable = 0;
+ not->notify_send6_enable = 0;
  tsig_create_record_custom(&not->notify_tsig, NULL, 0, 0, 4);
  not->notify_current = 0;
  rbtree_insert(tree, (rbnode_type*)not);
@@ -125,7 +138,7 @@ xfrd_del_notify(xfrd_state_type* xfrd, const dname_type* dname)
  }
 
  /* event */
- if(not->notify_send_enable) {
+ if(not->notify_send_enable || not->notify_send6_enable) {
  notify_disable(not);
  }
 
@@ -139,62 +152,134 @@ xfrd_del_notify(xfrd_state_type* xfrd, const dname_type* dname)
 }
 
 static int
-xfrd_handle_notify_reply(struct notify_zone* zone, buffer_type* packet)
+reply_pkt_is_ack(struct notify_zone* zone, buffer_type* packet, int index)
 {
  if((OPCODE(packet) != OPCODE_NOTIFY) ||
  (QR(packet) == 0)) {
- log_msg(LOG_ERR, "xfrd: zone %s: received bad notify reply opcode/flags",
- zone->apex_str);
+ log_msg(LOG_ERR, "xfrd: zone %s: received bad notify reply opcode/flags from %s",
+ zone->apex_str, zone->pkts[index].dest->ip_address_spec);
+
  return 0;
  }
  /* we know it is OPCODE NOTIFY, QUERY_REPLY and for this zone */
- if(ID(packet) != zone->notify_query_id) {
- log_msg(LOG_ERR, "xfrd: zone %s: received notify-ack with bad ID",
- zone->apex_str);
+ if(ID(packet) != zone->pkts[index].notify_query_id) {
+ log_msg(LOG_ERR, "xfrd: zone %s: received notify-ack with bad ID from %s",
+ zone->apex_str, zone->pkts[index].dest->ip_address_spec);
  return 0;
  }
  /* could check tsig, but why. The reply does not cause processing. */
  if(RCODE(packet) != RCODE_OK) {
  log_msg(LOG_ERR, "xfrd: zone %s: received notify response error %s from %s",
  zone->apex_str, rcode2str(RCODE(packet)),
- zone->notify_current->ip_address_spec);
+ zone->pkts[index].dest->ip_address_spec);
  if(RCODE(packet) == RCODE_IMPL)
  return 1; /* rfc1996: notimpl notify reply: consider retries done */
  return 0;
  }
  DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s: host %s acknowledges notify",
- zone->apex_str, zone->notify_current->ip_address_spec));
+ zone->apex_str, zone->pkts[index].dest->ip_address_spec));
  return 1;
 }
 
+/* compare sockaddr and acl_option addr and port numbers */
+static int
+cmp_addr_equal(struct sockaddr* a, socklen_t a_len, struct acl_options* dest)
+{
+ if(dest) {
+ unsigned int destport = ((dest->port == 0)?
+ (unsigned)atoi(TCP_PORT):dest->port);
+#ifdef INET6
+ struct sockaddr_storage* a1 = (struct sockaddr_storage*)a;
+ if(a1->ss_family == AF_INET6 && dest->is_ipv6) {
+ struct sockaddr_in6* a2 = (struct sockaddr_in6*)a;
+ if(a_len < sizeof(struct sockaddr_in6))
+ return 0; /* too small */
+ if(ntohs(a2->sin6_port) != destport)
+ return 0; /* different port number */
+ if(memcmp(&a2->sin6_addr, &dest->addr.addr6,
+ sizeof(struct in6_addr)) != 0)
+ return 0; /* different address */
+ return 1;
+ }
+ if(a1->ss_family == AF_INET6 || dest->is_ipv6)
+ return 0; /* different address family */
+ else {
+#endif /* INET6 */
+ struct sockaddr_in* a3 = (struct sockaddr_in*)a;
+ if(a_len < sizeof(struct sockaddr_in))
+ return 0; /* too small */
+ if(ntohs(a3->sin_port) != destport)
+ return 0; /* different port number */
+ if(memcmp(&a3->sin_addr, &dest->addr.addr,
+ sizeof(struct in_addr)) != 0)
+ return 0; /* different address */
+ return 1;
+#ifdef INET6
+ }
+#endif
+ }
+ return 0;
+}
+
 static void
-xfrd_notify_next(struct notify_zone* zone)
+notify_pkt_done(struct notify_zone* zone, int index)
 {
- /* advance to next in acl */
- zone->notify_current = zone->notify_current->next;
- zone->notify_retry = 0;
- if(zone->notify_current == 0) {
- DEBUG(DEBUG_XFRD,1, (LOG_INFO,
- "xfrd: zone %s: no more notify-send acls. stop notify.",
- zone->apex_str));
- notify_disable(zone);
+ zone->pkts[index].dest = NULL;
+ zone->pkts[index].notify_retry = 0;
+ zone->pkts[index].send_time = 0;
+ zone->pkts[index].notify_query_id = 0;
+ zone->notify_pkt_count--;
+}
+
+static void
+notify_pkt_retry(struct notify_zone* zone, int index)
+{
+ if(++zone->pkts[index].notify_retry >=
+ zone->options->pattern->notify_retry) {
+ log_msg(LOG_ERR, "xfrd: zone %s: max notify send count reached, %s unreachable",
+ zone->apex_str,
+ zone->pkts[index].dest->ip_address_spec);
+ notify_pkt_done(zone, index);
  return;
  }
+ if(!xfrd_notify_send_udp(zone, index)) {
+ notify_pkt_retry(zone, index);
+ }
 }
 
 static void
-xfrd_notify_send_udp(struct notify_zone* zone, buffer_type* packet)
+xfrd_handle_notify_reply(struct notify_zone* zone, buffer_type* packet,
+ struct sockaddr* src, socklen_t srclen)
 {
- int fd;
- if(zone->notify_send_enable) {
- notify_send_disable(zone);
+ int i;
+ for(i=0; i<NOTIFY_CONCURRENT_MAX; i++) {
+ /* is this entry in use */
+ if(!zone->pkts[i].dest)
+ continue;
+ /* based on destination */
+ if(!cmp_addr_equal(src, srclen, zone->pkts[i].dest))
+ continue;
+ if(reply_pkt_is_ack(zone, packet, i)) {
+ /* is done */
+ notify_pkt_done(zone, i);
+ return;
+ } else {
+ /* retry */
+ notify_pkt_retry(zone, i);
+ return;
+ }
  }
- /* Set timeout for next reply */
- zone->notify_timeout.tv_sec = XFRD_NOTIFY_RETRY_TIMOUT;
+}
+
+static int
+xfrd_notify_send_udp(struct notify_zone* zone, int index)
+{
+ buffer_type* packet = xfrd_get_temp_buffer();
+ if(!zone->pkts[index].dest) return 0;
  /* send NOTIFY to secondary. */
  xfrd_setup_packet(packet, TYPE_SOA, CLASS_IN, zone->apex,
  qid_generate());
- zone->notify_query_id = ID(packet);
+ zone->pkts[index].notify_query_id = ID(packet);
  OPCODE_SET(packet, OPCODE_NOTIFY);
  AA_SET(packet);
  if(zone->current_soa->serial != 0) {
@@ -202,35 +287,123 @@ xfrd_notify_send_udp(struct notify_zone* zone, buffer_type* packet)
  ANCOUNT_SET(packet, 1);
  xfrd_write_soa_buffer(packet, zone->apex, zone->current_soa);
  }
- if(zone->notify_current->key_options) {
- xfrd_tsig_sign_request(packet, &zone->notify_tsig, zone->notify_current);
+ if(zone->pkts[index].dest->key_options) {
+ xfrd_tsig_sign_request(packet, &zone->notify_tsig, zone->pkts[index].dest);
  }
  buffer_flip(packet);
- fd = xfrd_send_udp(zone->notify_current, packet,
- zone->options->pattern->outgoing_interface);
- if(fd == -1) {
- log_msg(LOG_ERR, "xfrd: zone %s: could not send notify #%d to %s",
- zone->apex_str, zone->notify_retry,
- zone->notify_current->ip_address_spec);
- event_set(&zone->notify_send_handler, -1, EV_TIMEOUT,
+
+ if((zone->pkts[index].dest->is_ipv6
+ && zone->notify_send6_handler.ev_fd == -1) ||
+ (!zone->pkts[index].dest->is_ipv6
+ && zone->notify_send_handler.ev_fd == -1)) {
+ /* open fd */
+ int fd = xfrd_send_udp(zone->pkts[index].dest, packet,
+ zone->options->pattern->outgoing_interface);
+ if(fd == -1) {
+ log_msg(LOG_ERR, "xfrd: zone %s: could not send notify #%d to %s",
+ zone->apex_str, zone->pkts[index].notify_retry,
+ zone->pkts[index].dest->ip_address_spec);
+ return 0;
+ }
+ if(zone->pkts[index].dest->is_ipv6)
+ zone->notify_send6_handler.ev_fd = fd;
+ else zone->notify_send_handler.ev_fd = fd;
+ } else {
+ /* send on existing fd */
+#ifdef INET6
+         struct sockaddr_storage to;
+#else
+         struct sockaddr_in to;
+#endif /* INET6 */
+ int fd;
+ socklen_t to_len = xfrd_acl_sockaddr_to(
+ zone->pkts[index].dest, &to);
+ if(zone->pkts[index].dest->is_ipv6)
+ fd = zone->notify_send6_handler.ev_fd;
+ else fd = zone->notify_send_handler.ev_fd;
+ if(sendto(fd,
+ buffer_current(packet), buffer_remaining(packet), 0,
+ (struct sockaddr*)&to, to_len) == -1) {
+ log_msg(LOG_ERR, "xfrd notify: sendto %s failed %s",
+ zone->pkts[index].dest->ip_address_spec,
+ strerror(errno));
+ return 0;
+ }
+ }
+ zone->pkts[index].send_time = time(NULL);
+ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s: sent notify #%d to %s",
+ zone->apex_str, zone->pkts[index].notify_retry,
+ zone->pkts[index].dest->ip_address_spec));
+ return 1;
+}
+
+static void
+notify_timeout_check(struct notify_zone* zone)
+{
+ time_t now = time(NULL);
+ int i;
+ for(i=0; i<NOTIFY_CONCURRENT_MAX; i++) {
+ if(!zone->pkts[i].dest)
+ continue;
+ if(now >= zone->pkts[i].send_time + XFRD_NOTIFY_RETRY_TIMOUT) {
+ notify_pkt_retry(zone, i);
+ }
+ }
+}
+
+static void
+notify_start_pkts(struct notify_zone* zone)
+{
+ int i;
+ if(!zone->notify_current) return; /* no more acl to send to */
+ for(i=0; i<NOTIFY_CONCURRENT_MAX; i++) {
+ /* while loop, in case the retries all fail, and we can
+ * start another on this slot, or run out of notify acls */
+ while(zone->pkts[i].dest==NULL && zone->notify_current) {
+ zone->pkts[i].dest = zone->notify_current;
+ zone->notify_current = zone->notify_current->next;
+ zone->pkts[i].notify_retry = 0;
+ zone->pkts[i].notify_query_id = 0;
+ zone->pkts[i].send_time = 0;
+ zone->notify_pkt_count++;
+ if(!xfrd_notify_send_udp(zone, i)) {
+ notify_pkt_retry(zone, i);
+ }
+ }
+ }
+}
+
+static void
+notify_setup_event(struct notify_zone* zone)
+{
+ if(zone->notify_send_handler.ev_fd != -1) {
+ int fd = zone->notify_send_handler.ev_fd;
+ if(zone->notify_send_enable) {
+ event_del(&zone->notify_send_handler);
+ }
+ zone->notify_timeout.tv_sec = XFRD_NOTIFY_RETRY_TIMOUT;
+ event_set(&zone->notify_send_handler, fd, EV_READ | EV_TIMEOUT,
  xfrd_handle_notify_send, zone);
  if(event_base_set(xfrd->event_base, &zone->notify_send_handler) != 0)
  log_msg(LOG_ERR, "notify_send: event_base_set failed");
- if(evtimer_add(&zone->notify_send_handler, &zone->notify_timeout) != 0)
- log_msg(LOG_ERR, "notify_send: evtimer_add failed");
+ if(event_add(&zone->notify_send_handler, &zone->notify_timeout) != 0)
+ log_msg(LOG_ERR, "notify_send: event_add failed");
  zone->notify_send_enable = 1;
- return;
  }
- event_set(&zone->notify_send_handler, fd, EV_READ | EV_TIMEOUT,
- xfrd_handle_notify_send, zone);
- if(event_base_set(xfrd->event_base, &zone->notify_send_handler) != 0)
- log_msg(LOG_ERR, "notify_send: event_base_set failed");
- if(event_add(&zone->notify_send_handler, &zone->notify_timeout) != 0)
- log_msg(LOG_ERR, "notify_send: evtimer_add failed");
- zone->notify_send_enable = 1;
- DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s: sent notify #%d to %s",
- zone->apex_str, zone->notify_retry,
- zone->notify_current->ip_address_spec));
+ if(zone->notify_send6_handler.ev_fd != -1) {
+ int fd = zone->notify_send6_handler.ev_fd;
+ if(zone->notify_send6_enable) {
+ event_del(&zone->notify_send6_handler);
+ }
+ zone->notify_timeout.tv_sec = XFRD_NOTIFY_RETRY_TIMOUT;
+ event_set(&zone->notify_send6_handler, fd, EV_READ | EV_TIMEOUT,
+ xfrd_handle_notify_send, zone);
+ if(event_base_set(xfrd->event_base, &zone->notify_send6_handler) != 0)
+ log_msg(LOG_ERR, "notify_send: event_base_set failed");
+ if(event_add(&zone->notify_send6_handler, &zone->notify_timeout) != 0)
+ log_msg(LOG_ERR, "notify_send: event_add failed");
+ zone->notify_send6_enable = 1;
+ }
 }
 
 static void
@@ -238,44 +411,54 @@ xfrd_handle_notify_send(int fd, short event, void* arg)
 {
  struct notify_zone* zone = (struct notify_zone*)arg;
  buffer_type* packet = xfrd_get_temp_buffer();
- assert(zone->notify_current);
  if(zone->is_waiting) {
  DEBUG(DEBUG_XFRD,1, (LOG_INFO,
  "xfrd: notify waiting, skipped, %s", zone->apex_str));
  return;
  }
  if((event & EV_READ)) {
+ struct sockaddr_storage src;
+ socklen_t srclen = (socklen_t)sizeof(src);
  DEBUG(DEBUG_XFRD,1, (LOG_INFO,
  "xfrd: zone %s: read notify ACK", zone->apex_str));
  assert(fd != -1);
- if(xfrd_udp_read_packet(packet, fd)) {
- if(xfrd_handle_notify_reply(zone, packet))
- xfrd_notify_next(zone);
+ if(xfrd_udp_read_packet(packet, fd, (struct sockaddr*)&src,
+ &srclen)) {
+ /* find entry, send retry or make entry NULL */
+ xfrd_handle_notify_reply(zone, packet,
+ (struct sockaddr*)&src, srclen);
  }
- } else if((event & EV_TIMEOUT)) {
+ }
+ if((event & EV_TIMEOUT)) {
  DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s: notify timeout",
  zone->apex_str));
  /* timeout, try again */
  }
- /* see if notify is still enabled */
- if(zone->notify_current) {
- zone->notify_retry++;
- if(zone->notify_retry > zone->options->pattern->notify_retry) {
- log_msg(LOG_ERR, "xfrd: zone %s: max notify send count reached, %s unreachable",
- zone->apex_str, zone->notify_current->ip_address_spec);
- xfrd_notify_next(zone);
- }
- }
- if(zone->notify_current) {
- /* try again */
- xfrd_notify_send_udp(zone, packet);
+
+ /* see which pkts have timeouted, retry or NULL them */
+ notify_timeout_check(zone);
+
+ /* start new packets if we have empty space */
+ notify_start_pkts(zone);
+
+ /* see if we are done */
+ if(!zone->notify_current && !zone->notify_pkt_count) {
+ /* we are done */
+ DEBUG(DEBUG_XFRD,1, (LOG_INFO,
+ "xfrd: zone %s: no more notify-send acls. stop notify.",
+ zone->apex_str));
+ notify_disable(zone);
+ return;
  }
+
+ notify_setup_event(zone);
 }
 
 static void
 setup_notify_active(struct notify_zone* zone)
 {
- zone->notify_retry = 0;
+ zone->notify_pkt_count = 0;
+ memset(zone->pkts, 0, sizeof(zone->pkts));
  zone->notify_current = zone->options->pattern->notify;
  zone->notify_timeout.tv_sec = 0;
  zone->notify_timeout.tv_usec = 0;
@@ -329,7 +512,8 @@ void
 xfrd_notify_start(struct notify_zone* zone, struct xfrd_state* xfrd)
 {
  xfrd_zone_type* xz;
- if(zone->is_waiting || zone->notify_send_enable)
+ if(zone->is_waiting || zone->notify_send_enable ||
+ zone->notify_send6_enable)
  return;
  xz = (xfrd_zone_type*)rbtree_search(xfrd->zones, zone->apex);
  if(xz && xz->soa_nsd_acquired)
@@ -344,7 +528,7 @@ xfrd_send_notify(rbtree_type* tree, const dname_type* apex, struct xfrd_soa* new
  struct notify_zone* zone = (struct notify_zone*)
  rbtree_search(tree, apex);
  assert(zone);
- if(zone->notify_send_enable)
+ if(zone->notify_send_enable || zone->notify_send6_enable)
  notify_disable(zone);
 
  notify_enable(zone, new_soa);
@@ -363,7 +547,7 @@ notify_handle_master_zone_soainfo(rbtree_type* tree,
  if( (new_soa == NULL && zone->current_soa->serial == 0) ||
  (new_soa && new_soa->serial == zone->current_soa->serial))
  return;
- if(zone->notify_send_enable)
+ if(zone->notify_send_enable || zone->notify_send6_enable)
  notify_disable(zone);
  notify_enable(zone, new_soa);
 }
@@ -374,7 +558,7 @@ close_notify_fds(rbtree_type* tree)
  struct notify_zone* zone;
  RBTREE_FOR(zone, struct notify_zone*, tree)
  {
- if(zone->notify_send_enable)
+ if(zone->notify_send_enable || zone->notify_send6_enable)
  notify_send_disable(zone);
  }
 }
diff --git xfrd-notify.h xfrd-notify.h
index 153dca5129b..3a20f383ff1 100644
--- xfrd-notify.h
+++ xfrd-notify.h
@@ -33,6 +33,17 @@ struct xfrd_soa;
 struct acl_options;
 struct xfrd_state;
 
+/** number of concurrent notify packets in flight */
+#define NOTIFY_CONCURRENT_MAX 16
+
+/** notify packet info */
+struct notify_pkt {
+ struct acl_options* dest; /* target, NULL if entry not in use */
+ uint8_t notify_retry; /* how manieth retry in sending to current */
+ uint16_t notify_query_id;
+ time_t send_time;
+};
+
 /**
  * This struct keeps track of outbound notifies for a zone.
  */
@@ -50,18 +61,20 @@ struct notify_zone {
  /* Not saved on disk (i.e. kill of daemon stops notifies) */
  int notify_send_enable;
  struct event notify_send_handler;
+ int notify_send6_enable;
+ struct event notify_send6_handler;
  struct timeval notify_timeout;
  struct acl_options* notify_current; /* current slave to notify */
  uint8_t notify_restart; /* restart notify after repattern */
- uint8_t notify_retry; /* how manieth retry in sending to current */
- uint16_t notify_query_id;
+ struct notify_pkt pkts[NOTIFY_CONCURRENT_MAX];
+ int notify_pkt_count; /* number of entries nonNULL in pkts */
 
  /* is this notify waiting for a socket? */
  uint8_t is_waiting;
  /* the double linked waiting list for the udp sockets */
  struct notify_zone* waiting_next;
  struct notify_zone* waiting_prev;
-};
+} ATTR_PACKED;
 
 /* initialise outgoing notifies */
 void init_notify_send(rbtree_type* tree, region_type* region,
diff --git xfrd-tcp.c xfrd-tcp.c
index 2715689439f..3c176a38ff8 100644
--- xfrd-tcp.c
+++ xfrd-tcp.c
@@ -13,6 +13,7 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <stdlib.h>
+#include <sys/uio.h>
 #include "nsd.h"
 #include "xfrd-tcp.h"
 #include "buffer.h"
@@ -898,6 +899,7 @@ xfrd_tcp_read(struct xfrd_tcp_pipeline* tp)
  tp->id[zone->query_id] = TCP_NULL_SKIP;
  tp->num_skip++;
  /* fall through to remove zone from tp */
+ /* fallthrough */
  case xfrd_packet_transfer:
  if(zone->zone_options->pattern->multi_master_check) {
  xfrd_tcp_release(xfrd->tcp_set, zone);
diff --git xfrd.c xfrd.c
index 1c03750dacf..3520f5d3b1b 100644
--- xfrd.c
+++ xfrd.c
@@ -767,7 +767,7 @@ xfrd_set_timer_retry(xfrd_zone_type* zone)
  else if(set_retry < (time_t)zone->zone_options->pattern->min_retry_time)
  set_retry = zone->zone_options->pattern->min_retry_time;
  if(set_retry < XFRD_LOWERBOUND_RETRY)
- set_retry =  XFRD_LOWERBOUND_RETRY;
+ set_retry = XFRD_LOWERBOUND_RETRY;
  xfrd_set_timer(zone, set_retry);
  } else {
  set_retry = ntohl(zone->soa_disk.expire);
@@ -1210,14 +1210,15 @@ xfrd_send_expire_notification(xfrd_zone_type* zone)
 }
 
 int
-xfrd_udp_read_packet(buffer_type* packet, int fd)
+xfrd_udp_read_packet(buffer_type* packet, int fd, struct sockaddr* src,
+ socklen_t* srclen)
 {
  ssize_t received;
 
  /* read the data */
  buffer_clear(packet);
  received = recvfrom(fd, buffer_begin(packet), buffer_remaining(packet),
- 0, NULL, NULL);
+ 0, src, srclen);
  if(received == -1) {
  log_msg(LOG_ERR, "xfrd: recvfrom failed: %s",
  strerror(errno));
@@ -1299,7 +1300,8 @@ static void
 xfrd_udp_read(xfrd_zone_type* zone)
 {
  DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s read udp data", zone->apex_str));
- if(!xfrd_udp_read_packet(xfrd->packet, zone->zone_handler.ev_fd)) {
+ if(!xfrd_udp_read_packet(xfrd->packet, zone->zone_handler.ev_fd,
+ NULL, NULL)) {
  zone->master->bad_xfr_count++;
  if (zone->master->bad_xfr_count > 2) {
  xfrd_disable_ixfr(zone);
@@ -1323,6 +1325,7 @@ xfrd_udp_read(xfrd_zone_type* zone)
  xfrd_make_request(zone);
  break;
  }
+ /* fallthrough */
  case xfrd_packet_newlease:
  /* nothing more to do */
  assert(zone->round_num == -1);
diff --git xfrd.h xfrd.h
index 44e7ba1795a..c58780c7065 100644
--- xfrd.h
+++ xfrd.h
@@ -136,7 +136,7 @@ struct xfrd_soa {
  uint32_t retry;
  uint32_t expire;
  uint32_t minimum;
-};
+} ATTR_PACKED;
 
 
 /*
@@ -219,7 +219,7 @@ struct xfrd_zone {
  valid if msg_seq_nr nonzero */
  int multi_master_first_master; /* >0: first check master_num */
  int multi_master_update_check; /* -1: not update >0: last update master_num */
-};
+} ATTR_PACKED;
 
 enum xfrd_packet_result {
  xfrd_packet_bad, /* drop the packet/connection */
@@ -239,10 +239,10 @@ enum xfrd_packet_result {
    Note that also some sockets are used for writing the ixfr.db, xfrd.state
    files and for the pipes to the main parent process.
 */
-#define XFRD_MAX_TCP 32 /* max number of TCP AXFR/IXFR concurrent connections.*/
+#define XFRD_MAX_TCP 128 /* max number of TCP AXFR/IXFR concurrent connections.*/
  /* Each entry has 64Kb buffer preallocated.*/
-#define XFRD_MAX_UDP 64 /* max number of UDP sockets at a time for IXFR */
-#define XFRD_MAX_UDP_NOTIFY 64 /* max concurrent UDP sockets for NOTIFY */
+#define XFRD_MAX_UDP 128 /* max number of UDP sockets at a time for IXFR */
+#define XFRD_MAX_UDP_NOTIFY 128 /* max concurrent UDP sockets for NOTIFY */
 
 #define XFRD_TRANSFER_TIMEOUT_START 10 /* empty zone timeout is between x and 2*x seconds */
 #define XFRD_TRANSFER_TIMEOUT_MAX 86400 /* empty zone timeout max expbackoff */
@@ -300,7 +300,8 @@ int xfrd_send_udp(struct acl_options* acl, buffer_type* packet,
 /*
  * read from udp port packet into buffer, returns 0 on failure
  */
-int xfrd_udp_read_packet(buffer_type* packet, int fd);
+int xfrd_udp_read_packet(buffer_type* packet, int fd, struct sockaddr* src,
+ socklen_t* srclen);
 
 /*
  * Release udp socket that a zone is using
diff --git zlexer.lex zlexer.lex
index 90a1df3741c..d98dabc1d9a 100644
--- zlexer.lex
+++ zlexer.lex
@@ -83,6 +83,16 @@ parser_pop_stringbuf(void)
  oldstate = NULL;
 }
 
+ static int paren_open = 0;
+ static enum lexer_state lexer_state = EXPECT_OWNER;
+void
+parser_flush(void)
+{
+ YY_FLUSH_BUFFER;
+ paren_open = 0;
+ lexer_state = EXPECT_OWNER;
+}
+
 #ifndef yy_set_bol /* compat definition, for flex 2.4.6 */
 #define yy_set_bol(at_bol) \
  { \
@@ -119,8 +129,6 @@ ANY     [^\"\n\\]|\\.
 %x incl bitlabel quotedstring
 
 %%
- static int paren_open = 0;
- static enum lexer_state lexer_state = EXPECT_OWNER;
 {SPACE}*{COMMENT}.* /* ignore */
 ^{DOLLAR}TTL            { lexer_state = PARSING_RDATA; return DOLLAR_TTL; }
 ^{DOLLAR}ORIGIN         { lexer_state = PARSING_RDATA; return DOLLAR_ORIGIN; }
@@ -131,9 +139,13 @@ ANY     [^\"\n\\]|\\.
  */
 ^{DOLLAR}INCLUDE        {
  BEGIN(incl);
+ /* ignore case statement fallthrough on incl<EOF> flex rule */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
 }
-<incl>\n |
+<incl>\n |
 <incl><<EOF>> {
+#pragma GCC diagnostic pop
  int error_occurred = parser->error_occurred;
  BEGIN(INITIAL);
  zc_error("missing file name in $INCLUDE directive");
diff --git zonec.c zonec.c
index 1b20b84d90f..de0a03ca4cd 100644
--- zonec.c
+++ zonec.c
@@ -1627,6 +1627,7 @@ zonec_read(const char* name, const char* zonefile, zone_type* zone)
  parser->current_zone->soa_rrset->rrs[0].owner));
  }
 
+ parser_flush();
  fclose(yyin);
  if(!zone_is_slave(zone->opts))
  check_dname(zone);
@@ -1719,5 +1720,6 @@ zonec_parse_string(region_type* region, domain_table_type* domains,
  if(parser->origin != error_domain)
  domain_table_deldomain(parser->db, parser->origin);
  zonec_desetup_string_parser();
+ parser_flush();
  return errors;
 }
diff --git zonec.h zonec.h
index 4057b12cf36..b14bedb20ca 100644
--- zonec.h
+++ zonec.h
@@ -82,6 +82,7 @@ void zc_error_prev_line(const char *fmt, ...) ATTR_FORMAT(printf, 1, 2);
 
 void parser_push_stringbuf(char* str);
 void parser_pop_stringbuf(void);
+void parser_flush(void);
 
 int process_rr(void);
 uint16_t *zparser_conv_hex(region_type *region, const char *hex, size_t len);


--
I'm not entirely sure you are real.

Reply | Threaded
Open this post in threaded view
|

Re: nsd 4.1.19

Florian Obser-2

Oh and yes, that packed BS is completely retarded.

Seeing how many commits it took to have it not constantly spass out on
different compilers, it's amazing that someone didn't take the hint and
gave up on it. No idea what the usecase is suppsed to be.

--
I'm not entirely sure you are real.

Reply | Threaded
Open this post in threaded view
|

Re: nsd 4.1.19

Todd C. Miller-2
In reply to this post by Florian Obser-2
On Fri, 12 Jan 2018 18:20:58 +0100, Florian Obser wrote:

> so, here is 4.1.19. I haven't gotten around to reading the diff yet.
> But I tossed it in production.
>
> When trying to re-gen config.h.in autheader bombs out:
>
> [florian@openbsd-build:/usr/src/usr.sbin/nsd]$ autoheader-2.69
> autoheader-2.69: warning: missing template: HAVE_B64_NTOP
> autoheader-2.69: Use AC_DEFINE([HAVE_B64_NTOP], [], [Description])
> autoheader-2.69: warning: missing template: HAVE_B64_PTON

This will fix it.  I guess no one tried to re-run autoheader after
the configure.ac changes.

 - todd

--- configure.ac.orig Fri Jan 12 11:27:48 2018
+++ configure.ac Fri Jan 12 11:27:57 2018
@@ -687,8 +687,8 @@
  fi
 fi
 if test "x$found_b64_ntop" = xyes; then
- AC_DEFINE(HAVE_B64_NTOP)
- AC_DEFINE(HAVE_B64_PTON)
+ AC_DEFINE(HAVE_B64_NTOP, 1, [Define to 1 if you have the `b64_ntop' function.])
+ AC_DEFINE(HAVE_B64_PTON, 1, [Define to 1 if you have the `b64_ntop' function.])
  AC_MSG_RESULT(yes)
 else
  AC_LIBOBJ([b64_ntop])

Reply | Threaded
Open this post in threaded view
|

Re: nsd 4.1.19

Todd C. Miller-2
In reply to this post by Florian Obser-2
On Fri, 12 Jan 2018 18:20:58 +0100, Florian Obser wrote:

> so, here is 4.1.19. I haven't gotten around to reading the diff yet.
> But I tossed it in production.

So far so good here.  A note to others, you'll need to "make cleandir"
in /usr/src/usr.sbin/nsd (or just remove /usr/obj/usr.sbin/nsd)
before rebuilding or you will get errors about ATTR_PACKED.

We may want to add a make rule to re-run configure when it changes
(or when config.h.in changes) to avoid this kind of problem.

 - todd

Reply | Threaded
Open this post in threaded view
|

Re: nsd 4.1.19

Florian Obser-2
In reply to this post by Todd C. Miller-2
On Fri, Jan 12, 2018 at 11:28:48AM -0700, Todd C. Miller wrote:

> On Fri, 12 Jan 2018 18:20:58 +0100, Florian Obser wrote:
>
> > so, here is 4.1.19. I haven't gotten around to reading the diff yet.
> > But I tossed it in production.
> >
> > When trying to re-gen config.h.in autheader bombs out:
> >
> > [florian@openbsd-build:/usr/src/usr.sbin/nsd]$ autoheader-2.69
> > autoheader-2.69: warning: missing template: HAVE_B64_NTOP
> > autoheader-2.69: Use AC_DEFINE([HAVE_B64_NTOP], [], [Description])
> > autoheader-2.69: warning: missing template: HAVE_B64_PTON
>
> This will fix it.  I guess no one tried to re-run autoheader after
> the configure.ac changes.

Indeed. Please commit, OK florian

>
>  - todd
>
> --- configure.ac.orig Fri Jan 12 11:27:48 2018
> +++ configure.ac Fri Jan 12 11:27:57 2018
> @@ -687,8 +687,8 @@
>   fi
>  fi
>  if test "x$found_b64_ntop" = xyes; then
> - AC_DEFINE(HAVE_B64_NTOP)
> - AC_DEFINE(HAVE_B64_PTON)
> + AC_DEFINE(HAVE_B64_NTOP, 1, [Define to 1 if you have the `b64_ntop' function.])
> + AC_DEFINE(HAVE_B64_PTON, 1, [Define to 1 if you have the `b64_ntop' function.])
>   AC_MSG_RESULT(yes)
>  else
>   AC_LIBOBJ([b64_ntop])
>

--
I'm not entirely sure you are real.

Reply | Threaded
Open this post in threaded view
|

Re: nsd 4.1.19

Florian Obser-2
In reply to this post by Florian Obser-2
anyone else?
Got around to read the diff, not too much insanity in there, going to
commit soon.

rebased on top of millert@'s autohell fix:

diff --git Makefile.in Makefile.in
index 495160c0826..3468101c19d 100644
--- Makefile.in
+++ Makefile.in
@@ -286,9 +286,6 @@ qtest.o: $(srcdir)/tpkg/cutest/qtest.c
 udb-inspect.o: $(srcdir)/tpkg/cutest/udb-inspect.c
  $(COMPILE) -c $(srcdir)/tpkg/cutest/udb-inspect.c
 
-xfr-inspect.o: $(srcdir)/tpkg/cutest/xfr-inspect.c
- $(COMPILE) -c $(srcdir)/tpkg/cutest/xfr-inspect.c
-
 zlexer.c: $(srcdir)/zlexer.lex
  if test "$(LEX)" != ":"; then rm -f $@ ;\
  echo '#include "config.h"' > $@ ;\
@@ -516,7 +513,7 @@ udb-inspect.o: $(srcdir)/tpkg/cutest/udb-inspect.c config.h $(srcdir)/udb.h $(sr
  $(srcdir)/udb.h $(srcdir)/udbzone.h $(srcdir)/dns.h $(srcdir)/udbradtree.h $(srcdir)/util.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h \
  $(srcdir)/util.h $(srcdir)/packet.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/rdata.h \
  $(srcdir)/namedb.h $(srcdir)/difffile.h $(srcdir)/options.h config.h
-xfr-inspect.o: $(srcdir)/tpkg/cutest/xfr-inspect.c config.h $(srcdir)/udbzone.h $(srcdir)/udb.h $(srcdir)/dns.h \
+xfr-inspect.o: $(srcdir)/xfr-inspect.c config.h $(srcdir)/udbzone.h $(srcdir)/udb.h $(srcdir)/dns.h \
  $(srcdir)/udbradtree.h $(srcdir)/util.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/packet.h $(srcdir)/namedb.h \
  $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/rdata.h $(srcdir)/namedb.h $(srcdir)/difffile.h \
  $(srcdir)/options.h config.h
diff --git axfr.c axfr.c
index 6f6b0957e99..dd34c0c3cee 100644
--- axfr.c
+++ axfr.c
@@ -201,6 +201,7 @@ answer_axfr_ixfr(struct nsd *nsd, struct query *q)
  return query_axfr(nsd, q);
  }
  /** Fallthrough: AXFR over UDP queries are discarded. */
+ /* fallthrough */
  case TYPE_IXFR:
  RCODE_SET(q->packet, RCODE_IMPL);
  return QUERY_PROCESSED;
diff --git config.h.in config.h.in
index 6c44616432f..3cc7d4e546d 100644
--- config.h.in
+++ config.h.in
@@ -73,6 +73,9 @@
 /* Define to 1 if you have the `endpwent' function. */
 #undef HAVE_ENDPWENT
 
+/* Define to 1 if you have the `ERR_load_crypto_strings' function. */
+#undef HAVE_ERR_LOAD_CRYPTO_STRINGS
+
 /* Define to 1 if you have the `event_base_free' function. */
 #undef HAVE_EVENT_BASE_FREE
 
@@ -88,6 +91,9 @@
 /* Define to 1 if you have the <event.h> header file. */
 #undef HAVE_EVENT_H
 
+/* Define to 1 if you have the `EVP_cleanup' function. */
+#undef HAVE_EVP_CLEANUP
+
 /* Define to 1 if you have the `ev_default_loop' function. */
 #undef HAVE_EV_DEFAULT_LOOP
 
@@ -194,6 +200,12 @@
 /* Define to 1 if you have the <openssl/err.h> header file. */
 #undef HAVE_OPENSSL_ERR_H
 
+/* Define to 1 if you have the `OPENSSL_init_crypto' function. */
+#undef HAVE_OPENSSL_INIT_CRYPTO
+
+/* Define to 1 if you have the `OPENSSL_init_ssl' function. */
+#undef HAVE_OPENSSL_INIT_SSL
+
 /* Define to 1 if you have the <openssl/rand.h> header file. */
 #undef HAVE_OPENSSL_RAND_H
 
@@ -426,6 +438,9 @@
 /* Define to the version of this package. */
 #undef PACKAGE_VERSION
 
+/* Define this to use packed structure alignment. */
+#undef PACKED_STRUCTS
+
 /* Pathname to the NSD pidfile */
 #undef PIDFILE
 
@@ -483,6 +498,9 @@
 /* Define this to enable mmap instead of malloc. Experimental. */
 #undef USE_MMAP_ALLOC
 
+/* Define this to configure to use the radix tree. */
+#undef USE_RADIX_TREE
+
 /* Enable extensions on AIX 3, Interix.  */
 #ifndef _ALL_SOURCE
 # undef _ALL_SOURCE
@@ -659,6 +677,29 @@
 
 
 
+
+/* provide timespec def if not available */
+#ifndef CONFIG_DEFINES
+#define CONFIG_DEFINES
+#ifndef HAVE_STRUCT_TIMESPEC
+#ifndef __timespec_defined
+#define __timespec_defined 1
+ struct timespec {
+ long    tv_sec;         /* seconds */
+ long    tv_nsec;        /* nanoseconds */
+ };
+#endif /* !__timespec_defined */
+#endif /* !HAVE_STRUCT_TIMESPEC */
+#endif /* !CONFIG_DEFINES */
+
+#ifdef PACKED_STRUCTS
+#define ATTR_PACKED __attribute__((packed))
+#else
+#define ATTR_PACKED
+#endif
+
+
+
 #ifdef HAVE_VA_LIST_DOUBLE_DEF
 /* workaround double va_list definition on some platforms */
 #  ifndef _VA_LIST_DEFINED
@@ -736,13 +777,12 @@
 
 
 
-#ifndef HAVE_B64_NTOP
-int b64_ntop(uint8_t const *src, size_t srclength,
+int __b64_ntop(uint8_t const *src, size_t srclength,
      char *target, size_t targsize);
-#endif /* !HAVE_B64_NTOP */
-#ifndef HAVE_B64_PTON
-int b64_pton(char const *src, uint8_t *target, size_t targsize);
-#endif /* !HAVE_B64_PTON */
+int __b64_pton(char const *src, uint8_t *target, size_t targsize);
+
+
+
 #ifndef HAVE_FSEEKO
 #define fseeko fseek
 #define ftello ftell
@@ -800,22 +840,3 @@ int memcmp(const void *x, const void *y, size_t n);
 #endif
 
 
-
-
-
-/* provide timespec def if not available */
-#ifndef CONFIG_DEFINES
-#define CONFIG_DEFINES
-#ifndef HAVE_STRUCT_TIMESPEC
-#ifndef __timespec_defined
-#define __timespec_defined 1
- struct timespec {
- long    tv_sec;         /* seconds */
- long    tv_nsec;        /* nanoseconds */
- };
-#endif /* !__timespec_defined */
-#endif /* !HAVE_STRUCT_TIMESPEC */
-#endif /* !CONFIG_DEFINES */
-
-int __b64_ntop(uint8_t const *, size_t, char *, size_t);
-int __b64_pton(char const *, uint8_t*, size_t);
diff --git configure configure
index 15ceae2b292..e73ca9121cd 100644
--- configure
+++ configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for NSD 4.1.17.
+# Generated by GNU Autoconf 2.69 for NSD 4.1.19.
 #
 # Report bugs to <[hidden email]>.
 #
@@ -580,8 +580,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='NSD'
 PACKAGE_TARNAME='nsd'
-PACKAGE_VERSION='4.1.17'
-PACKAGE_STRING='NSD 4.1.17'
+PACKAGE_VERSION='4.1.19'
+PACKAGE_STRING='NSD 4.1.19'
 PACKAGE_BUGREPORT='[hidden email]'
 PACKAGE_URL=''
 
@@ -732,6 +732,7 @@ enable_nsec3
 enable_minimal_responses
 enable_mmap
 enable_radix_tree
+enable_packed
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1284,7 +1285,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures NSD 4.1.17 to adapt to many kinds of systems.
+\`configure' configures NSD 4.1.19 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1345,7 +1346,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of NSD 4.1.17:";;
+     short | recursive ) echo "Configuration of NSD 4.1.19:";;
    esac
   cat <<\_ACEOF
 
@@ -1381,6 +1382,8 @@ Optional Features:
   --disable-radix-tree    You can disable the radix tree and use the red-black
                           tree for the main lookups, the red-black tree uses
                           less memory, but uses some more CPU.
+  --enable-packed         Enable packed structure alignment, uses less memory,
+                          but unaligned reads.
 
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
@@ -1491,7 +1494,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-NSD configure 4.1.17
+NSD configure 4.1.19
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2200,7 +2203,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by NSD $as_me 4.1.17, which was
+It was created by NSD $as_me 4.1.19, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -8266,9 +8269,11 @@ $as_echo "no" >&6; }
  fi
 fi
 if test "x$found_b64_ntop" = xyes; then
- $as_echo "#define HAVE_B64_NTOP 1" >>confdefs.h
 
- $as_echo "#define HAVE_B64_PTON 1" >>confdefs.h
+$as_echo "#define HAVE_B64_NTOP 1" >>confdefs.h
+
+
+$as_echo "#define HAVE_B64_PTON 1" >>confdefs.h
 
  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
@@ -9171,6 +9176,54 @@ _ACEOF
  ;;
 esac
 
+# Check whether --enable-packed was given.
+if test "${enable_packed+set}" = set; then :
+  enableval=$enable_packed;
+fi
+
+case "$enable_packed" in
+ yes)
+
+cat >>confdefs.h <<_ACEOF
+#define PACKED_STRUCTS /**/
+_ACEOF
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wno-address-of-packed-member" >&5
+$as_echo_n "checking whether $CC supports -Wno-address-of-packed-member... " >&6; }
+cache=`echo Wno-address-of-packed-member | sed 'y%.=/+-%___p_%'`
+if eval \${cv_prog_cc_flag_$cache+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+echo 'void f(void){}' >conftest.c
+if test -z "`$CC $CPPFLAGS $CFLAGS -Wno-address-of-packed-member -c conftest.c 2>&1`"; then
+eval "cv_prog_cc_flag_$cache=yes"
+else
+eval "cv_prog_cc_flag_$cache=no"
+fi
+rm -f conftest conftest.o conftest.c
+
+fi
+
+if eval "test \"`echo '$cv_prog_cc_flag_'$cache`\" = yes"; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+:
+CFLAGS="$CFLAGS -Wno-address-of-packed-member"
+else
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+:
+
+fi
+
+ ;;
+ no|*)
+ ;;
+esac
+
 
 
 
@@ -9717,7 +9770,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by NSD $as_me 4.1.17, which was
+This file was extended by NSD $as_me 4.1.19, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -9779,7 +9832,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-NSD config.status 4.1.17
+NSD config.status 4.1.19
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
diff --git configure.ac configure.ac
index 2ad31c51d32..7dd787eaed5 100644
--- configure.ac
+++ configure.ac
@@ -4,7 +4,7 @@ dnl
 
 sinclude(acx_nlnetlabs.m4)
 
-AC_INIT(NSD,4.1.17,[hidden email])
+AC_INIT(NSD,4.1.19,[hidden email])
 AC_CONFIG_HEADER([config.h])
 
 CFLAGS="$CFLAGS"
@@ -918,6 +918,16 @@ case "$enable_radix_tree" in
  ;;
 esac
 
+AC_ARG_ENABLE(packed, AC_HELP_STRING([--enable-packed], [Enable packed structure alignment, uses less memory, but unaligned reads.]))
+case "$enable_packed" in
+ yes)
+ AC_DEFINE_UNQUOTED([PACKED_STRUCTS], [], [Define this to use packed structure alignment.])
+ ACX_CHECK_COMPILER_FLAG(Wno-address-of-packed-member, [CFLAGS="$CFLAGS -Wno-address-of-packed-member"])
+ ;;
+ no|*)
+ ;;
+esac
+
 AH_BOTTOM([
 /* define before includes as it specifies what standard to use. */
 #if (defined(HAVE_PSELECT) && !defined (HAVE_PSELECT_PROTO)) \
@@ -1096,6 +1106,12 @@ AH_BOTTOM([
 #endif /* !__timespec_defined */
 #endif /* !HAVE_STRUCT_TIMESPEC */
 #endif /* !CONFIG_DEFINES */
+
+#ifdef PACKED_STRUCTS
+#define ATTR_PACKED __attribute__((packed))
+#else
+#define ATTR_PACKED
+#endif
 ])
 
 # big fat warning
diff --git difffile.c difffile.c
index dfef60dccc7..1fb5bda0003 100644
--- difffile.c
+++ difffile.c
@@ -478,7 +478,8 @@ nsec3_rrsets_changed_remove_prehash(domain_type* domain, zone_type* zone)
  /* see if the domain is no longer precompiled */
  /* it has a hash_node, but no longer fulfills conditions */
  if(nsec3_domain_part_of_zone(domain, zone) && domain->nsec3 &&
- domain->nsec3->hash_node.key &&
+ domain->nsec3->hash_wc &&
+ domain->nsec3->hash_wc->hash.node.key &&
  !nsec3_condition_hash(domain, zone)) {
  /* remove precompile */
  domain->nsec3->nsec3_cover = NULL;
@@ -486,12 +487,13 @@ nsec3_rrsets_changed_remove_prehash(domain_type* domain, zone_type* zone)
  domain->nsec3->nsec3_is_exact = 0;
  /* remove it from the hash tree */
  zone_del_domain_in_hash_tree(zone->hashtree,
- &domain->nsec3->hash_node);
+ &domain->nsec3->hash_wc->hash.node);
  zone_del_domain_in_hash_tree(zone->wchashtree,
- &domain->nsec3->wchash_node);
+ &domain->nsec3->hash_wc->wc.node);
  }
  if(domain != zone->apex && domain->nsec3 &&
- domain->nsec3->dshash_node.key &&
+ domain->nsec3->ds_parent_hash &&
+ domain->nsec3->ds_parent_hash->node.key &&
  (!domain->parent || nsec3_domain_part_of_zone(domain->parent, zone)) &&
  !nsec3_condition_dshash(domain, zone)) {
  /* remove precompile */
@@ -499,7 +501,7 @@ nsec3_rrsets_changed_remove_prehash(domain_type* domain, zone_type* zone)
  domain->nsec3->nsec3_ds_parent_is_exact = 0;
  /* remove it from the hash tree */
  zone_del_domain_in_hash_tree(zone->dshashtree,
- &domain->nsec3->dshash_node);
+ &domain->nsec3->ds_parent_hash->node);
  }
 }
 
@@ -510,13 +512,15 @@ nsec3_rrsets_changed_add_prehash(namedb_type* db, domain_type* domain,
 {
  if(!zone->nsec3_param)
  return;
- if((!domain->nsec3 || !domain->nsec3->hash_node.key)
+ if((!domain->nsec3 || !domain->nsec3->hash_wc
+                   || !domain->nsec3->hash_wc->hash.node.key)
  && nsec3_condition_hash(domain, zone)) {
  region_type* tmpregion = region_create(xalloc, free);
  nsec3_precompile_domain(db, domain, zone, tmpregion);
  region_destroy(tmpregion);
  }
- if((!domain->nsec3 || !domain->nsec3->dshash_node.key)
+ if((!domain->nsec3 || !domain->nsec3->ds_parent_hash
+                   || !domain->nsec3->ds_parent_hash->node.key)
  && nsec3_condition_dshash(domain, zone)) {
  nsec3_precompile_domain_ds(db, domain, zone);
  }
diff --git lookup3.c lookup3.c
index e0179f06d29..9602ffa374b 100644
--- lookup3.c
+++ lookup3.c
@@ -5,6 +5,7 @@
      added #ifdef VALGRIND to remove 298,384,660 'unused variable k8' warnings.
      added include of lookup3.h to check definitions match declarations.
      removed include of stdint - config.h takes care of platform independence.
+     added fallthrough comments for new gcc warning suppression.
   url http://burtleburtle.net/bob/hash/index.html.
 */
 /*
@@ -235,7 +236,9 @@ uint32_t        initval)         /* the previous hash, or an arbitrary value */
   switch(length)                     /* all the case statements fall through */
   {
   case 3 : c+=k[2];
+   /* fallthrough */
   case 2 : b+=k[1];
+   /* fallthrough */
   case 1 : a+=k[0];
     final(a,b,c);
   case 0:     /* case 0: nothing left to add */
@@ -473,16 +476,27 @@ uint32_t hashlittle( const void *key, size_t length, uint32_t initval)
     switch(length)                   /* all the case statements fall through */
     {
     case 12: c+=((uint32_t)k[11])<<24;
+   /* fallthrough */
     case 11: c+=((uint32_t)k[10])<<16;
+   /* fallthrough */
     case 10: c+=((uint32_t)k[9])<<8;
+   /* fallthrough */
     case 9 : c+=k[8];
+   /* fallthrough */
     case 8 : b+=((uint32_t)k[7])<<24;
+   /* fallthrough */
     case 7 : b+=((uint32_t)k[6])<<16;
+   /* fallthrough */
     case 6 : b+=((uint32_t)k[5])<<8;
+   /* fallthrough */
     case 5 : b+=k[4];
+   /* fallthrough */
     case 4 : a+=((uint32_t)k[3])<<24;
+   /* fallthrough */
     case 3 : a+=((uint32_t)k[2])<<16;
+   /* fallthrough */
     case 2 : a+=((uint32_t)k[1])<<8;
+   /* fallthrough */
     case 1 : a+=k[0];
              break;
     case 0 : return c;
diff --git namedb.c namedb.c
index bcc41aad926..bc7690d87b6 100644
--- namedb.c
+++ namedb.c
@@ -73,15 +73,11 @@ allocate_domain_nsec3(domain_table_type* table, domain_type* result)
  result->nsec3->nsec3_ds_parent_cover = NULL;
  result->nsec3->nsec3_is_exact = 0;
  result->nsec3->nsec3_ds_parent_is_exact = 0;
- result->nsec3->have_nsec3_hash = 0;
- result->nsec3->have_nsec3_wc_hash = 0;
- result->nsec3->have_nsec3_ds_parent_hash = 0;
+ result->nsec3->hash_wc = NULL;
+ result->nsec3->ds_parent_hash = NULL;
  result->nsec3->prehash_prev = NULL;
  result->nsec3->prehash_next = NULL;
  result->nsec3->nsec3_node.key = NULL;
- result->nsec3->hash_node.key = NULL;
- result->nsec3->wchash_node.key = NULL;
- result->nsec3->dshash_node.key = NULL;
 }
 #endif /* NSEC3 */
 
@@ -89,7 +85,7 @@ allocate_domain_nsec3(domain_table_type* table, domain_type* result)
 static void
 numlist_make_last(domain_table_type* table, domain_type* domain)
 {
- size_t sw;
+ uint32_t sw;
  domain_type* last = table->numlist_last;
  if(domain == last)
  return;
@@ -235,15 +231,17 @@ do_deldomain(namedb_type* db, domain_type* domain)
  if(domain->nsec3->nsec3_node.key)
  zone_del_domain_in_hash_tree(nsec3_tree_zone(db, domain)
  ->nsec3tree, &domain->nsec3->nsec3_node);
- if(domain->nsec3->hash_node.key)
- zone_del_domain_in_hash_tree(nsec3_tree_zone(db, domain)
- ->hashtree, &domain->nsec3->hash_node);
- if(domain->nsec3->wchash_node.key)
- zone_del_domain_in_hash_tree(nsec3_tree_zone(db, domain)
- ->wchashtree, &domain->nsec3->wchash_node);
- if(domain->nsec3->dshash_node.key)
+ if(domain->nsec3->hash_wc) {
+ if(domain->nsec3->hash_wc->hash.node.key)
+ zone_del_domain_in_hash_tree(nsec3_tree_zone(db, domain)
+ ->hashtree, &domain->nsec3->hash_wc->hash.node);
+ if(domain->nsec3->hash_wc->wc.node.key)
+ zone_del_domain_in_hash_tree(nsec3_tree_zone(db, domain)
+ ->wchashtree, &domain->nsec3->hash_wc->wc.node);
+ }
+ if(domain->nsec3->ds_parent_hash && domain->nsec3->ds_parent_hash->node.key)
  zone_del_domain_in_hash_tree(nsec3_tree_dszone(db, domain)
- ->dshashtree, &domain->nsec3->dshash_node);
+ ->dshashtree, &domain->nsec3->ds_parent_hash->node);
  region_recycle(db->domains->region, domain->nsec3,
  sizeof(struct nsec3_domain_data));
  }
diff --git namedb.h namedb.h
index e2d84517854..c7cf6d96802 100644
--- namedb.h
+++ namedb.h
@@ -53,6 +53,20 @@ struct domain_table
 };
 
 #ifdef NSEC3
+typedef struct nsec3_hash_node nsec3_hash_node_type;
+struct nsec3_hash_node {
+ /* hash value */
+ uint8_t hash[NSEC3_HASH_LEN];
+ /* entry in the hashtree */
+ rbnode_type node;
+} ATTR_PACKED;
+
+typedef struct nsec3_hash_wc_node nsec3_hash_wc_node_type;
+struct nsec3_hash_wc_node {
+ nsec3_hash_node_type hash;
+ nsec3_hash_node_type wc;
+};
+
 struct nsec3_domain_data {
  /* (if nsec3 chain complete) always the covering nsec3 record */
  domain_type* nsec3_cover;
@@ -64,28 +78,18 @@ struct nsec3_domain_data {
  domain_type* prehash_prev, *prehash_next;
  /* entry in the nsec3tree (for NSEC3s in the chain in use) */
  rbnode_type nsec3_node;
- /* entry in the hashtree (for precompiled domains) */
- rbnode_type hash_node;
- /* entry in the wchashtree (the wildcard precompile) */
- rbnode_type wchash_node;
- /* entry in the dshashtree (the parent ds precompile) */
- rbnode_type dshash_node;
-
- /* nsec3 hash */
- uint8_t nsec3_hash[NSEC3_HASH_LEN];
- /* nsec3 hash of wildcard before this name */
- uint8_t nsec3_wc_hash[NSEC3_HASH_LEN];
- /* parent-side DS hash */
- uint8_t nsec3_ds_parent_hash[NSEC3_HASH_LEN];
- /* if the nsec3 has is available */
- unsigned  have_nsec3_hash : 1;
- unsigned  have_nsec3_wc_hash : 1;
- unsigned  have_nsec3_ds_parent_hash : 1;
+
+ /* node for the precompiled domain and the precompiled wildcard */
+ nsec3_hash_wc_node_type* hash_wc;
+
+ /* node for the precompiled parent ds */
+ nsec3_hash_node_type* ds_parent_hash;
+
  /* if the domain has an NSEC3 for it, use cover ptr to get it. */
  unsigned     nsec3_is_exact : 1;
  /* same but on parent side */
  unsigned     nsec3_ds_parent_is_exact : 1;
-};
+} ATTR_PACKED;
 #endif /* NSEC3 */
 
 struct domain
@@ -104,8 +108,8 @@ struct domain
 #endif
  /* double-linked list sorted by domain.number */
  domain_type* numlist_prev, *numlist_next;
- size_t     number; /* Unique domain name number.  */
- size_t     usage; /* number of ptrs to this from RRs(in rdata) and
+ uint32_t     number; /* Unique domain name number.  */
+ uint32_t     usage; /* number of ptrs to this from RRs(in rdata) and
      from zone-apex pointers, also the root has one
      more to make sure it cannot be deleted. */
 
@@ -114,7 +118,7 @@ struct domain
  */
  unsigned     is_existing : 1;
  unsigned     is_apex : 1;
-};
+} ATTR_PACKED;
 
 struct zone
 {
@@ -140,7 +144,7 @@ struct zone
  unsigned     is_secure : 1; /* zone uses DNSSEC */
  unsigned     is_ok : 1; /* zone has not expired. */
  unsigned     is_changed : 1; /* zone was changed by AXFR */
-};
+} ATTR_PACKED;
 
 /* a RR in DNS */
 struct rr {
@@ -150,7 +154,7 @@ struct rr {
  uint16_t         type;
  uint16_t         klass;
  uint16_t         rdata_count;
-};
+} ATTR_PACKED;
 
 /*
  * An RRset consists of at least one RR.  All RRs are from the same
@@ -162,7 +166,7 @@ struct rrset
  zone_type*  zone;
  rr_type*    rrs;
  uint16_t    rr_count;
-};
+} ATTR_PACKED;
 
 /*
  * The field used is based on the wireformat the atom is stored in.
diff --git netio.c netio.c
index 6c4b395babe..58fd2e18b49 100644
--- netio.c
+++ netio.c
@@ -94,7 +94,7 @@ netio_current_time(netio_type *netio)
  if (!netio->have_current_time) {
  struct timeval current_timeval;
  if (gettimeofday(&current_timeval, NULL) == -1) {
- log_msg(LOG_CRIT, "gettimeofday: %s, aborting.", strerror(errno));
+ log_msg(LOG_ERR, "gettimeofday: %s, aborting.", strerror(errno));
  abort();
  }
  timeval_to_timespec(&netio->cached_current_time, &current_timeval);
diff --git nsd.c nsd.c
index f2cf6ccf0cb..dfbc58696b3 100644
--- nsd.c
+++ nsd.c
@@ -579,6 +579,7 @@ main(int argc, char *argv[])
  case 'v':
  version();
  /* version exits */
+ break;
 #ifndef NDEBUG
  case 'F':
  sscanf(optarg, "%x", &nsd_debug_facilities);
@@ -980,6 +981,7 @@ main(int argc, char *argv[])
  break;
  case -1:
  error("fork() failed: %s", strerror(errno));
+ break;
  default:
  /* Parent is done */
  server_close_all_sockets(nsd.udp, nsd.ifs);
diff --git nsec3.c nsec3.c
index 960e7216dad..dad4f23d7bf 100644
--- nsec3.c
+++ nsec3.c
@@ -29,8 +29,10 @@ cmp_hash_tree(const void* x, const void* y)
  const domain_type* b = (const domain_type*)y;
  if(!a->nsec3) return (b->nsec3?-1:0);
  if(!b->nsec3) return 1;
- return memcmp(a->nsec3->nsec3_hash, b->nsec3->nsec3_hash,
- NSEC3_HASH_LEN);
+ if(!a->nsec3->hash_wc) return (b->nsec3->hash_wc?-1:0);
+ if(!b->nsec3->hash_wc) return 1;
+ return memcmp(a->nsec3->hash_wc->hash.hash,
+ b->nsec3->hash_wc->hash.hash, NSEC3_HASH_LEN);
 }
 
 /* compare nsec3 hashes in nsec3 wc tree */
@@ -41,8 +43,10 @@ cmp_wchash_tree(const void* x, const void* y)
  const domain_type* b = (const domain_type*)y;
  if(!a->nsec3) return (b->nsec3?-1:0);
  if(!b->nsec3) return 1;
- return memcmp(a->nsec3->nsec3_wc_hash, b->nsec3->nsec3_wc_hash,
- NSEC3_HASH_LEN);
+ if(!a->nsec3->hash_wc) return (b->nsec3->hash_wc?-1:0);
+ if(!b->nsec3->hash_wc) return 1;
+ return memcmp(a->nsec3->hash_wc->wc.hash,
+ b->nsec3->hash_wc->wc.hash, NSEC3_HASH_LEN);
 }
 
 /* compare nsec3 hashes in nsec3 ds tree */
@@ -53,8 +57,10 @@ cmp_dshash_tree(const void* x, const void* y)
  const domain_type* b = (const domain_type*)y;
  if(!a->nsec3) return (b->nsec3?-1:0);
  if(!b->nsec3) return 1;
- return memcmp(a->nsec3->nsec3_ds_parent_hash,
- b->nsec3->nsec3_ds_parent_hash, NSEC3_HASH_LEN);
+ if(!a->nsec3->ds_parent_hash) return (b->nsec3->ds_parent_hash?-1:0);
+ if(!b->nsec3->ds_parent_hash) return 1;
+ return memcmp(a->nsec3->ds_parent_hash->hash,
+ b->nsec3->ds_parent_hash->hash, NSEC3_HASH_LEN);
 }
 
 /* compare base32-encoded nsec3 hashes in nsec3 rr tree, they are
@@ -129,32 +135,36 @@ nsec3_hash_and_store(zone_type* zone, const dname_type* dname, uint8_t* store)
 
 /** find hash or create it and store it */
 static void
-nsec3_lookup_hash_and_wc(zone_type* zone, const dname_type* dname,
- domain_type* domain, region_type* tmpregion)
+nsec3_lookup_hash_and_wc(region_type* region, zone_type* zone,
+ const dname_type* dname, domain_type* domain, region_type* tmpregion)
 {
  const dname_type* wcard;
- if(domain->nsec3->have_nsec3_hash && domain->nsec3->have_nsec3_wc_hash) {
+ if(domain->nsec3->hash_wc) {
  return;
  }
  /* lookup failed; disk failure or so */
- nsec3_hash_and_store(zone, dname, domain->nsec3->nsec3_hash);
- domain->nsec3->have_nsec3_hash = 1;
+ domain->nsec3->hash_wc = (nsec3_hash_wc_node_type *)
+ region_alloc(region, sizeof(nsec3_hash_wc_node_type));
+ domain->nsec3->hash_wc->hash.node.key = NULL;
+ domain->nsec3->hash_wc->wc.node.key = NULL;
+ nsec3_hash_and_store(zone, dname, domain->nsec3->hash_wc->hash.hash);
  wcard = dname_parse(tmpregion, "*");
  wcard = dname_concatenate(tmpregion, wcard, dname);
- nsec3_hash_and_store(zone, wcard, domain->nsec3->nsec3_wc_hash);
- domain->nsec3->have_nsec3_wc_hash = 1;
+ nsec3_hash_and_store(zone, wcard, domain->nsec3->hash_wc->wc.hash);
 }
 
 static void
-nsec3_lookup_hash_ds(zone_type* zone, const dname_type* dname,
- domain_type* domain)
+nsec3_lookup_hash_ds(region_type* region, zone_type* zone,
+ const dname_type* dname, domain_type* domain)
 {
- if(domain->nsec3->have_nsec3_ds_parent_hash) {
+ if(domain->nsec3->ds_parent_hash) {
  return;
  }
  /* lookup failed; disk failure or so */
- nsec3_hash_and_store(zone, dname, domain->nsec3->nsec3_ds_parent_hash);
- domain->nsec3->have_nsec3_ds_parent_hash = 1;
+ domain->nsec3->ds_parent_hash = (nsec3_hash_node_type *)
+ region_alloc(region, sizeof(nsec3_hash_node_type));
+ domain->nsec3->ds_parent_hash->node.key = NULL;
+ nsec3_hash_and_store(zone, dname, domain->nsec3->ds_parent_hash->hash);
 }
 
 static int
@@ -380,17 +390,23 @@ nsec3_clear_precompile(struct namedb* db, zone_type* zone)
  walk->nsec3->nsec3_cover = NULL;
  walk->nsec3->nsec3_wcard_child_cover = NULL;
  walk->nsec3->nsec3_is_exact = 0;
- walk->nsec3->have_nsec3_hash = 0;
- walk->nsec3->have_nsec3_wc_hash = 0;
- walk->nsec3->hash_node.key = NULL;
- walk->nsec3->wchash_node.key = NULL;
+ if (walk->nsec3->hash_wc) {
+ region_recycle(db->domains->region,
+ walk->nsec3->hash_wc,
+ sizeof(nsec3_hash_wc_node_type));
+ walk->nsec3->hash_wc = NULL;
+ }
  }
  if(!walk->parent ||
  nsec3_domain_part_of_zone(walk->parent, zone)) {
  walk->nsec3->nsec3_ds_parent_cover = NULL;
  walk->nsec3->nsec3_ds_parent_is_exact = 0;
- walk->nsec3->have_nsec3_ds_parent_hash = 0;
- walk->nsec3->dshash_node.key = NULL;
+ if (walk->nsec3->ds_parent_hash) {
+ region_recycle(db->domains->region,
+ walk->nsec3->ds_parent_hash,
+ sizeof(nsec3_hash_node_type));
+ walk->nsec3->ds_parent_hash = NULL;
+ }
  }
  }
  walk = domain_next(walk);
@@ -503,25 +519,26 @@ nsec3_precompile_domain(struct namedb* db, struct domain* domain,
  allocate_domain_nsec3(db->domains, domain);
 
  /* hash it */
- nsec3_lookup_hash_and_wc(zone, domain_dname(domain), domain, tmpregion);
+ nsec3_lookup_hash_and_wc(db->region,
+ zone, domain_dname(domain), domain, tmpregion);
 
  /* add into tree */
  zone_add_domain_in_hash_tree(db->region, &zone->hashtree,
- cmp_hash_tree, domain, &domain->nsec3->hash_node);
+ cmp_hash_tree, domain, &domain->nsec3->hash_wc->hash.node);
  zone_add_domain_in_hash_tree(db->region, &zone->wchashtree,
- cmp_wchash_tree, domain, &domain->nsec3->wchash_node);
+ cmp_wchash_tree, domain, &domain->nsec3->hash_wc->wc.node);
 
  /* lookup in tree cover ptr (or exact) */
- exact = nsec3_find_cover(zone, domain->nsec3->nsec3_hash,
- sizeof(domain->nsec3->nsec3_hash), &result);
+ exact = nsec3_find_cover(zone, domain->nsec3->hash_wc->hash.hash,
+ sizeof(domain->nsec3->hash_wc->hash.hash), &result);
  domain->nsec3->nsec3_cover = result;
  if(exact)
  domain->nsec3->nsec3_is_exact = 1;
  else domain->nsec3->nsec3_is_exact = 0;
 
  /* find cover for *.domain for wildcard denial */
- exact = nsec3_find_cover(zone, domain->nsec3->nsec3_wc_hash,
- sizeof(domain->nsec3->nsec3_wc_hash), &result);
+ exact = nsec3_find_cover(zone, domain->nsec3->hash_wc->wc.hash,
+ sizeof(domain->nsec3->hash_wc->wc.hash), &result);
  domain->nsec3->nsec3_wcard_child_cover = result;
 }
 
@@ -535,17 +552,17 @@ nsec3_precompile_domain_ds(struct namedb* db, struct domain* domain,
 
  /* hash it : it could have different hash parameters then the
    other hash for this domain name */
- nsec3_lookup_hash_ds(zone, domain_dname(domain), domain);
+ nsec3_lookup_hash_ds(db->region, zone, domain_dname(domain), domain);
  /* lookup in tree cover ptr (or exact) */
- exact = nsec3_find_cover(zone, domain->nsec3->nsec3_ds_parent_hash,
- sizeof(domain->nsec3->nsec3_ds_parent_hash), &result);
+ exact = nsec3_find_cover(zone, domain->nsec3->ds_parent_hash->hash,
+ sizeof(domain->nsec3->ds_parent_hash->hash), &result);
  if(exact)
  domain->nsec3->nsec3_ds_parent_is_exact = 1;
  else domain->nsec3->nsec3_ds_parent_is_exact = 0;
  domain->nsec3->nsec3_ds_parent_cover = result;
  /* add into tree */
  zone_add_domain_in_hash_tree(db->region, &zone->dshashtree,
- cmp_dshash_tree, domain, &domain->nsec3->dshash_node);
+ cmp_dshash_tree, domain, &domain->nsec3->ds_parent_hash->node);
 }
 
 static void
@@ -644,15 +661,15 @@ prehash_zone_complete(struct namedb* db, struct zone* zone)
 
 static void
 init_lookup_key_hash_tree(domain_type* d, uint8_t* hash)
-{ memcpy(d->nsec3->nsec3_hash, hash, NSEC3_HASH_LEN); }
+{ memcpy(d->nsec3->hash_wc->hash.hash, hash, NSEC3_HASH_LEN); }
 
 static void
 init_lookup_key_wc_tree(domain_type* d, uint8_t* hash)
-{ memcpy(d->nsec3->nsec3_wc_hash, hash, NSEC3_HASH_LEN); }
+{ memcpy(d->nsec3->hash_wc->wc.hash, hash, NSEC3_HASH_LEN); }
 
 static void
 init_lookup_key_ds_tree(domain_type* d, uint8_t* hash)
-{ memcpy(d->nsec3->nsec3_ds_parent_hash, hash, NSEC3_HASH_LEN); }
+{ memcpy(d->nsec3->ds_parent_hash->hash, hash, NSEC3_HASH_LEN); }
 
 /* find first in the tree and true if the first to process it */
 static int
@@ -661,10 +678,18 @@ process_first(rbtree_type* tree, uint8_t* hash, rbnode_type** p,
 {
  domain_type d;
  struct nsec3_domain_data n;
+ nsec3_hash_wc_node_type hash_wc;
+ nsec3_hash_node_type ds_parent_hash;
+
  if(!tree) {
  *p = RBTREE_NULL;
  return 0;
  }
+ hash_wc.hash.node.key = NULL;
+ hash_wc.wc.node.key = NULL;
+ n.hash_wc = &hash_wc;
+ ds_parent_hash.node.key = NULL;
+ n.ds_parent_hash = &ds_parent_hash;
  d.nsec3 = &n;
  init(&d, hash);
  if(rbtree_find_less_equal(tree, &d, p)) {
@@ -687,10 +712,18 @@ process_end(rbtree_type* tree, uint8_t* hash, rbnode_type** p,
 {
  domain_type d;
  struct nsec3_domain_data n;
+ nsec3_hash_wc_node_type hash_wc;
+ nsec3_hash_node_type ds_parent_hash;
+
  if(!tree) {
  *p = RBTREE_NULL;
  return;
  }
+ hash_wc.hash.node.key = NULL;
+ hash_wc.wc.node.key = NULL;
+ n.hash_wc = &hash_wc;
+ ds_parent_hash.node.key = NULL;
+ n.ds_parent_hash = &ds_parent_hash;
  d.nsec3 = &n;
  init(&d, hash);
  if(rbtree_find_less_equal(tree, &d, p)) {
@@ -854,9 +887,34 @@ nsec3_add_nonexist_proof(struct query* query, struct answer* answer,
  if(nsec3_find_cover(query->zone, hash, sizeof(hash), &cover))
  {
  /* exact match, hash collision */
+ domain_type* walk;
+ char hashbuf[512];
+ char reversebuf[512];
+ (void)b32_ntop(hash, sizeof(hash), hashbuf, sizeof(hashbuf));
+ snprintf(reversebuf, sizeof(reversebuf), "(no name in the zone hashes to this nsec3 record)");
+ walk = query->zone->apex;
+ while(walk) {
+ if(walk->nsec3 && walk->nsec3->nsec3_cover == cover) {
+ snprintf(reversebuf, sizeof(reversebuf),
+ "%s %s", domain_to_string(walk),
+ walk->nsec3->nsec3_is_exact?"exact":"no_exact_hash_match");
+ if(walk->nsec3->nsec3_is_exact)
+ break;
+ }
+ if(walk->nsec3 && walk->nsec3->nsec3_ds_parent_cover == cover) {
+ snprintf(reversebuf, sizeof(reversebuf),
+ "%s %s", domain_to_string(walk),
+ walk->nsec3->nsec3_ds_parent_is_exact?"exact":"no_exact_hash_match");
+ if(walk->nsec3->nsec3_ds_parent_is_exact)
+ break;
+ }
+ walk = domain_next(walk);
+ }
+
+
  /* the hashed name of the query corresponds to an existing name. */
- VERBOSITY(3, (LOG_ERR, "nsec3 hash collision for name=%s",
- dname_to_string(to_prove, NULL)));
+ VERBOSITY(3, (LOG_ERR, "nsec3 hash collision for name=%s hash=%s reverse=%s",
+ dname_to_string(to_prove, NULL), hashbuf, reversebuf));
  RCODE_SET(query->packet, RCODE_SERVFAIL);
  return;
  }
diff --git options.h options.h
index dedb9bfb662..bbfbbf98c41 100644
--- options.h
+++ options.h
@@ -165,7 +165,7 @@ struct pattern_options {
  uint8_t min_retry_time_is_default;
  uint64_t size_limit_xfr;
  uint8_t multi_master_check;
-};
+} ATTR_PACKED;
 
 #define PATTERN_IMPLICIT_MARKER "_implicit_"
 
@@ -186,7 +186,7 @@ struct zone_options {
  struct pattern_options* pattern;
  /* zone is fixed into the main config, not in zonelist, cannot delete */
  uint8_t part_of_config;
-};
+} ATTR_PACKED;
 
 union acl_addr_storage {
 #ifdef INET6
@@ -227,7 +227,7 @@ struct acl_options {
  uint8_t blocked;
  const char* key_name;
  struct key_options* key_options;
-};
+} ATTR_PACKED;
 
 /*
  * Key definition
@@ -238,7 +238,7 @@ struct key_options {
  char* algorithm;
  char* secret;
  struct tsig_key* tsig_key;
-};
+} ATTR_PACKED;
 
 /** zone list free space */
 struct zonelist_free {
diff --git query.c query.c
index d6e45a2e9d3..7b862a45bc7 100644
--- query.c
+++ query.c
@@ -1241,8 +1241,15 @@ answer_lookup_zone(struct nsd *nsd, struct query *q, answer_type *answer,
  * authoritative for the parent zone.
  */
  zone_type *zone = domain_find_parent_zone(nsd->db, q->zone);
- if (zone)
+ if (zone) {
  q->zone = zone;
+ if(!q->zone->apex || !q->zone->soa_rrset) {
+ /* zone is configured but not loaded */
+ if(q->cname_count == 0)
+ RCODE_SET(q->packet, RCODE_SERVFAIL);
+ return;
+ }
+ }
  }
 
  /* see if the zone has expired (for secondary zones) */
diff --git radtree.h radtree.h
index fdc58e7a903..c5d830a138b 100644
--- radtree.h
+++ radtree.h
@@ -49,7 +49,7 @@ struct radnode {
  uint16_t capacity;
  /** the lookup array by [byte-offset] */
  struct radsel* array;
-};
+} ATTR_PACKED;
 
 /**
  * radix select edge in array
@@ -61,7 +61,7 @@ struct radsel {
  radstrlen_type len;
  /** node that deals with byte+str */
  struct radnode* node;
-};
+} ATTR_PACKED;
 
 /**
  * Create new radix tree
diff --git rbtree.h rbtree.h
index d6e54862a23..eb9b3941245 100644
--- rbtree.h
+++ rbtree.h
@@ -24,7 +24,7 @@ struct rbnode {
  rbnode_type  *right;
  const void   *key;
  uint8_t      color;
-};
+} ATTR_PACKED;
 
 #define RBTREE_NULL &rbtree_null_node
 extern rbnode_type rbtree_null_node;
@@ -44,7 +44,7 @@ struct rbtree {
 
  /* Key compare function. <0,0,>0 like strcmp. Return 0 on two NULL ptrs. */
  int (*cmp) (const void *, const void *);
-};
+} ATTR_PACKED;
 
 /* rbtree.c */
 rbtree_type *rbtree_create(region_type *region, int (*cmpf)(const void *, const void *));
diff --git region-allocator.c region-allocator.c
index 95454a66678..8b5d2c77989 100644
--- region-allocator.c
+++ region-allocator.c
@@ -23,12 +23,17 @@
 #ifdef ALIGNMENT
 #undef ALIGNMENT
 #endif
+#ifndef PACKED_STRUCTS
 #define REGION_ALIGN_UP(x, s)     (((x) + s - 1) & (~(s - 1)))
 #if SIZEOF_OFF_T > SIZEOF_VOIDP
 #define ALIGNMENT (sizeof(off_t))
 #else
 #define ALIGNMENT (sizeof(void *))
 #endif
+#else
+#define REGION_ALIGN_UP(x, s) ((x)<SIZEOF_VOIDP?SIZEOF_VOIDP:(x))
+#define ALIGNMENT 1
+#endif /* PACKED_STRUCTS */
 /* #define CHECK_DOUBLE_FREE 0 */ /* set to 1 to perform expensive check for double recycle() */
 
 typedef struct cleanup cleanup_type;
@@ -285,7 +290,13 @@ region_alloc(region_type *region, size_t size)
  return NULL;
 
  wasted = (region->chunk_size - region->allocated) & (~(ALIGNMENT-1));
- if(wasted >= ALIGNMENT) {
+ if(
+#ifndef PACKED_STRUCTS
+ wasted >= ALIGNMENT
+#else
+ wasted >= SIZEOF_VOIDP
+#endif
+ ) {
  /* put wasted part in recycle bin for later use */
  region->total_allocated += wasted;
  ++region->small_objects;
diff --git remote.c remote.c
index f7c88222b68..d3f5153d549 100644
--- remote.c
+++ remote.c
@@ -958,10 +958,17 @@ print_zonestatus(SSL* ssl, xfrd_state_type* xfrd, struct zone_options* zo)
  if(nz->is_waiting) {
  if(!ssl_printf(ssl, " notify: \"waiting-for-fd\"\n"))
  return 0;
- } else if(nz->notify_send_enable) {
- if(!ssl_printf(ssl, " notify: \"sent try %d "
- "to %s with serial %u\"\n", nz->notify_retry,
- nz->notify_current->ip_address_spec,
+ } else if(nz->notify_send_enable || nz->notify_send6_enable) {
+ int i;
+ if(!ssl_printf(ssl, " notify: \"send"))
+ return 0;
+ for(i=0; i<NOTIFY_CONCURRENT_MAX; i++) {
+ if(!nz->pkts[i].dest) continue;
+ if(!ssl_printf(ssl, " %s",
+ nz->pkts[i].dest->ip_address_spec))
+ return 0;
+ }
+ if(!ssl_printf(ssl, " with serial %u\"\n",
  (unsigned)ntohl(nz->current_soa->serial)))
  return 0;
  }
@@ -985,6 +992,10 @@ print_zonestatus(SSL* ssl, xfrd_state_type* xfrd, struct zone_options* zo)
  if(!print_soa_status(ssl, "notified-serial", &xz->soa_notified,
  xz->soa_notified_acquired))
  return 0;
+ } else if(xz->event_added) {
+ if(!ssl_printf(ssl, "\twait: \"%u sec between attempts\"\n",
+ (unsigned)xz->timeout.tv_sec))
+ return 0;
  }
 
  /* UDP */
diff --git rrl.c rrl.c
index 2a7ca4f05b7..c8dec3fc908 100644
--- rrl.c
+++ rrl.c
@@ -156,7 +156,7 @@ static const char* rrlsource2str(uint64_t s, uint16_t c2)
  if(!inet_ntop(AF_INET6, &a6, buf, sizeof(buf)))
  strlcpy(buf, "[ip6 ntop failed]", sizeof(buf));
  else {
- static char prefix[4];
+ static char prefix[5];
  snprintf(prefix, sizeof(prefix), "/%d", rrl_ipv6_prefixlen);
  strlcat(buf, &prefix[0], sizeof(buf));
  }
@@ -170,7 +170,7 @@ static const char* rrlsource2str(uint64_t s, uint16_t c2)
  if(!inet_ntop(AF_INET, &a4, buf, sizeof(buf)))
  strlcpy(buf, "[ip4 ntop failed]", sizeof(buf));
  else {
- static char prefix[4];
+ static char prefix[5];
  snprintf(prefix, sizeof(prefix), "/%d", rrl_ipv4_prefixlen);
  strlcat(buf, &prefix[0], sizeof(buf));
  }
diff --git util.h util.h
index b59b7b69bd1..5f00911d0a1 100644
--- util.h
+++ util.h
@@ -25,6 +25,10 @@ struct region;
 #  define LOG_WARNING 4
 #  define LOG_NOTICE 5
 #  define LOG_INFO 6
+
+/* Unused, but passed to log_open. */
+#  define LOG_PID 0x01
+#  define LOG_DAEMON (3<<3)
 #endif
 
 #define ALIGN_UP(n, alignment)  \
diff --git xfr-inspect.c xfr-inspect.c
new file mode 100644
index 00000000000..e31d64a413a
--- /dev/null
+++ xfr-inspect.c
@@ -0,0 +1,531 @@
+/* xfr-inspect - list the contents and inspect an zone transfer XFR file
+ * By W.C.A. Wijngaards
+ * Copyright 2017, NLnet Labs.
+ * BSD, see LICENSE.
+ */
+
+#include "config.h"
+#include "udbzone.h"
+#include "util.h"
+#include "buffer.h"
+#include "packet.h"
+#include "rdata.h"
+#include "namedb.h"
+#include "difffile.h"
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+
+/** verbosity for inspect */
+static int v = 0;
+/** shorthand for ease */
+#ifdef ULL
+#undef ULL
+#endif
+#define ULL (unsigned long long)
+
+/** print usage text */
+static void
+usage(void)
+{
+ printf("usage: xfr-inspect [options] file\n");
+ printf(" -h this help\n");
+ printf(" -v increase verbosity: "
+       "with -v(list chunks), -vv(inside chunks)\n");
+ printf(" -l list contents of transfer\n");
+}
+
+static int
+xi_diff_read_64(FILE *in, uint64_t* result)
+{
+ if (fread(result, sizeof(*result), 1, in) == 1) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static int
+xi_diff_read_32(FILE *in, uint32_t* result)
+{
+ if (fread(result, sizeof(*result), 1, in) == 1) {
+ *result = ntohl(*result);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static int
+xi_diff_read_8(FILE *in, uint8_t* result)
+{
+        if (fread(result, sizeof(*result), 1, in) == 1) {
+                return 1;
+        } else {
+                return 0;
+        }
+}
+
+static int
+xi_diff_read_str(FILE* in, char* buf, size_t len)
+{
+ uint32_t disklen;
+ if(!xi_diff_read_32(in, &disklen))
+ return 0;
+ if(disklen >= len)
+ return 0;
+ if(fread(buf, disklen, 1, in) != 1)
+ return 0;
+ buf[disklen] = 0;
+ return 1;
+}
+
+
+/** inspect header of xfr file, return num_parts */
+static int
+inspect_header(FILE* in)
+{
+ char zone_buf[3072];
+ char patname_buf[2048];
+
+ uint32_t old_serial, new_serial, num_parts, type;
+ uint64_t time_end_0, time_start_0;
+ uint32_t time_end_1, time_start_1;
+ uint8_t committed;
+
+ time_t time_end, time_start;
+
+ if(!xi_diff_read_32(in, &type)) {
+ printf("could not read type, file short\n");
+ fclose(in);
+ exit(1);
+ }
+ if(type != DIFF_PART_XFRF) {
+ printf("type: %x (BAD FILE TYPE)\n", type);
+ fclose(in);
+ exit(1);
+ }
+ if(!xi_diff_read_8(in, &committed) ||
+ !xi_diff_read_32(in, &num_parts) ||
+ !xi_diff_read_64(in, &time_end_0) ||
+ !xi_diff_read_32(in, &time_end_1) ||
+ !xi_diff_read_32(in, &old_serial) ||
+ !xi_diff_read_32(in, &new_serial) ||
+ !xi_diff_read_64(in, &time_start_0) ||
+ !xi_diff_read_32(in, &time_start_1) ||
+ !xi_diff_read_str(in, zone_buf, sizeof(zone_buf)) ||
+ !xi_diff_read_str(in, patname_buf, sizeof(patname_buf))) {
+ printf("diff file bad commit part, file too short");
+ fclose(in);
+ exit(1);
+ }
+ time_end = (time_t)time_end_0;
+ time_start = (time_t)time_start_0;
+
+ /* printf("type: %x\n", (int)type); */
+ printf("committed: %d (%s)\n", (int)committed,
+ committed?"yes":"no");
+ printf("num_parts: %d\n", (int)num_parts);
+ printf("time_end: %d.%6.6d %s", (int)time_end_0,
+ (int)time_end_1, ctime(&time_end));
+ printf("old_serial: %u\n", (unsigned)old_serial);
+ printf("new_serial: %u\n", (unsigned)new_serial);
+ printf("time_start: %d.%6.6d %s", (int)time_start_0,
+ (int)time_start_1, ctime(&time_start));
+ printf("zone: %s\n", zone_buf);
+ printf("patname: %s\n", patname_buf);
+
+ return num_parts;
+}
+
+/** print records in packet */
+static void
+print_records(region_type* region, buffer_type* pkt, int num, int qsection)
+{
+ domain_table_type* table;
+ int i;
+ rr_type* rr;
+ region_type* tmpregion = region_create(xalloc, free);
+ buffer_type* tmpbuf;
+ if(!tmpregion) {
+ printf("out of memory\n");
+ return;
+ }
+ tmpbuf = buffer_create(region, QIOBUFSZ);
+ if(!tmpbuf) {
+ printf("out of memory\n");
+ return;
+ }
+ table = domain_table_create(tmpregion);
+ if(!table) {
+ printf("out of memory\n");
+ return;
+ }
+
+ for(i=0; i<num; ++i) {
+ rr = packet_read_rr(region, table, pkt, qsection);
+ if(!rr) {
+ printf("; cannot read rr %d\n", i);
+ return;
+ }
+ if(qsection) {
+ printf("%s", dname_to_string(domain_dname(rr->owner),
+ NULL));
+ printf("\t%s", rrclass_to_string(rr->klass));
+ if(rr->type == TYPE_IXFR)
+ printf("\tIXFR\n");
+ else if(rr->type == TYPE_AXFR)
+ printf("\tAXFR\n");
+ else printf("\t%s\n", rrtype_to_string(rr->type));
+ } else {
+ if(!print_rr(stdout, NULL, rr, tmpregion, tmpbuf)) {
+ printf("; cannot print rr %d\n", i);
+ }
+ }
+ }
+ region_destroy(tmpregion);
+}
+
+/** inspect packet (IXFR or AXFR) */
+static void
+inspect_packet(region_type* region, buffer_type* pkt)
+{
+ printf("\n");
+ if(buffer_limit(pkt) < QHEADERSZ) {
+ printf("packet too short\n");
+ return;
+ }
+ printf("; id=%4.4x ; flags%s%s%s%s%s%s%s%s ; rcode %s ; opcode %d\n",
+ ID(pkt), QR(pkt)?" QR":"", AA(pkt)?" AA":"", TC(pkt)?" TC":"",
+ RD(pkt)?" RD":"", RA(pkt)?" RA":"", Z(pkt)?" Z":"",
+ AD(pkt)?" AD":"", CD(pkt)?" CD":"", rcode2str(RCODE(pkt)),
+ OPCODE(pkt));
+ printf("; qdcount %d ; ancount %d ; nscount %d ; arcount %d\n",
+ QDCOUNT(pkt), ANCOUNT(pkt), NSCOUNT(pkt), ARCOUNT(pkt));
+ buffer_skip(pkt, QHEADERSZ);
+
+ if(QDCOUNT(pkt) != 0) {
+ printf("; QUESTION SECTION\n");
+ print_records(region, pkt, QDCOUNT(pkt), 1);
+ }
+ if(ANCOUNT(pkt) != 0) {
+ printf("; ANSWER SECTION\n");
+ print_records(region, pkt, ANCOUNT(pkt), 0);
+ }
+ if(NSCOUNT(pkt) != 0) {
+ printf("; AUTHORITY SECTION\n");
+ print_records(region, pkt, NSCOUNT(pkt), 0);
+ }
+ if(ARCOUNT(pkt) != 0) {
+ printf("; ADDITIONAL SECTION\n");
+ print_records(region, pkt, ARCOUNT(pkt), 0);
+ }
+}
+
+/** inspect part of xfr file */
+static void
+inspect_part(FILE* in, int partnum)
+{
+ uint32_t pkttype, msglen, msglen2;
+ region_type* region;
+ buffer_type* packet;
+ region = region_create(xalloc, free);
+ if(!region) {
+ printf("out of memory\n");
+ fclose(in);
+ exit(1);
+ }
+ packet = buffer_create(region, QIOBUFSZ);
+ if(!xi_diff_read_32(in, &pkttype)) {
+ printf("cannot read part %d\n", partnum);
+ fclose(in);
+ exit(1);
+ }
+ if(pkttype != DIFF_PART_XXFR) {
+ printf("bad part %d: not type XXFR\n", partnum);
+ fclose(in);
+ exit(1);
+ }
+ if(!xi_diff_read_32(in, &msglen)) {
+ printf("bad part %d: not msglen, file too short\n", partnum);
+ fclose(in);
+ exit(1);
+ }
+ if(msglen < QHEADERSZ || msglen > QIOBUFSZ) {
+ printf("bad part %d: msglen %u (too short or too long)\n",
+ partnum, (unsigned)msglen);
+ fclose(in);
+ exit(1);
+ }
+ if(fread(buffer_begin(packet), msglen, 1, in) != 1) {
+ printf("bad part %d: short packet, file too short, %s\n",
+ partnum, strerror(errno));
+ fclose(in);
+ exit(1);
+ }
+ if(!xi_diff_read_32(in, &msglen2)) {
+ printf("bad part %d: cannot read msglen2, file too short\n", partnum);
+ fclose(in);
+ exit(1);
+ }
+ if(v==0) {
+ region_destroy(region);
+ return;
+ }
+
+ printf("\n");
+ /* printf("type : %x\n", pkttype); */
+ printf("part : %d\n", partnum);
+ printf("msglen : %u\n", (unsigned)msglen);
+ printf("msglen2 : %u (%s)\n", (unsigned)msglen2,
+ (msglen==msglen2)?"ok":"wrong");
+
+ if(v>=2) {
+ buffer_set_limit(packet, msglen);
+ inspect_packet(region, packet);
+ }
+
+ region_destroy(region);
+}
+
+/** inspect parts of xfr file */
+static void
+inspect_parts(FILE* in, int num)
+{
+ int i;
+ for(i=0; i<num; i++) {
+ inspect_part(in, i);
+ }
+}
+
+/** inspect trail of xfr file */
+static void
+inspect_trail(FILE* in)
+{
+ char log_buf[5120];
+ if(!xi_diff_read_str(in, log_buf, sizeof(log_buf))) {
+ printf("bad trail: cannot read log string\n");
+ fclose(in);
+ exit(1);
+ }
+ printf("\n");
+ printf("log: %s\n", log_buf);
+}
+
+/** inspect contents of xfr file */
+static void
+inspect_file(char* fname)
+{
+ FILE* in;
+ int num;
+ log_init("udb-inspect");
+ if(!(in=fopen(fname, "r"))) {
+ printf("cannot open %s: %s\n", fname, strerror(errno));
+ exit(1);
+ }
+ printf("file: %s\n", fname);
+ num = inspect_header(in);
+ inspect_parts(in, num);
+ inspect_trail(in);
+ fclose(in);
+}
+
+/** list header of xfr file, return num_parts */
+static int
+list_header(FILE* in)
+{
+ char zone_buf[3072];
+ char patname_buf[2048];
+
+ uint32_t old_serial, new_serial, num_parts, type;
+ uint64_t time_end_0, time_start_0;
+ uint32_t time_end_1, time_start_1;
+ uint8_t committed;
+
+ time_t time_end, time_start;
+
+ if(!xi_diff_read_32(in, &type)) {
+ printf("could not read type, file short\n");
+ fclose(in);
+ exit(1);
+ }
+ if(type != DIFF_PART_XFRF) {
+ printf("type: %x (BAD FILE TYPE)\n", type);
+ fclose(in);
+ exit(1);
+ }
+ if(!xi_diff_read_8(in, &committed) ||
+ !xi_diff_read_32(in, &num_parts) ||
+ !xi_diff_read_64(in, &time_end_0) ||
+ !xi_diff_read_32(in, &time_end_1) ||
+ !xi_diff_read_32(in, &old_serial) ||
+ !xi_diff_read_32(in, &new_serial) ||
+ !xi_diff_read_64(in, &time_start_0) ||
+ !xi_diff_read_32(in, &time_start_1) ||
+ !xi_diff_read_str(in, zone_buf, sizeof(zone_buf)) ||
+ !xi_diff_read_str(in, patname_buf, sizeof(patname_buf))) {
+ printf("diff file bad commit part, file too short");
+ fclose(in);
+ exit(1);
+ }
+ time_end = (time_t)time_end_0;
+ time_start = (time_t)time_start_0;
+
+ /* printf("; type: %x\n", (int)type); */
+ printf("; commited: %d (%s)\n", (int)committed,
+ committed?"yes":"no");
+ printf("; num_parts: %d\n", (int)num_parts);
+ printf("; time_end: %d.%6.6d %s", (int)time_end_0,
+ (int)time_end_1, ctime(&time_end));
+ printf("; old_serial: %u\n", (unsigned)old_serial);
+ printf("; new_serial: %u\n", (unsigned)new_serial);
+ printf("; time_start: %d.%6.6d %s", (int)time_start_0,
+ (int)time_start_1, ctime(&time_start));
+ printf("; zone: %s\n", zone_buf);
+ printf("; patname: %s\n", patname_buf);
+
+ return num_parts;
+}
+
+/** list packet (IXFR or AXFR) */
+static void
+list_packet(region_type* region, buffer_type* pkt, int partnum)
+{
+ if(buffer_limit(pkt) < QHEADERSZ) {
+ printf("packet too short\n");
+ return;
+ }
+ buffer_skip(pkt, QHEADERSZ);
+
+ if(partnum == 0 && QDCOUNT(pkt) == 1) {
+ /* print query AXFR or IXFR */
+ printf("; ");
+ print_records(region, pkt, QDCOUNT(pkt), 1);
+ }
+ if(ANCOUNT(pkt) != 0) {
+ print_records(region, pkt, ANCOUNT(pkt), 0);
+ }
+}
+
+/** list part of xfr file */
+static void
+list_part(FILE* in, int partnum)
+{
+ uint32_t pkttype, msglen, msglen2;
+ region_type* region;
+ buffer_type* packet;
+ region = region_create(xalloc, free);
+ if(!region) {
+ printf("out of memory\n");
+ fclose(in);
+ exit(1);
+ }
+ packet = buffer_create(region, QIOBUFSZ);
+ if(!xi_diff_read_32(in, &pkttype)) {
+ printf("cannot read part %d\n", partnum);
+ fclose(in);
+ exit(1);
+ }
+ if(pkttype != DIFF_PART_XXFR) {
+ printf("bad part %d: not type XXFR\n", partnum);
+ fclose(in);
+ exit(1);
+ }
+ if(!xi_diff_read_32(in, &msglen)) {
+ printf("bad part %d: not msglen, file too short\n", partnum);
+ fclose(in);
+ exit(1);
+ }
+ if(msglen < QHEADERSZ || msglen > QIOBUFSZ) {
+ printf("bad part %d: msglen %u (too short or too long)\n",
+ partnum, (unsigned)msglen);
+ fclose(in);
+ exit(1);
+ }
+ if(fread(buffer_begin(packet), msglen, 1, in) != 1) {
+ printf("bad part %d: short packet, file too short, %s\n",
+ partnum, strerror(errno));
+ fclose(in);
+ exit(1);
+ }
+ if(!xi_diff_read_32(in, &msglen2)) {
+ printf("bad part %d: cannot read msglen2, file too short\n", partnum);
+ fclose(in);
+ exit(1);
+ }
+
+ buffer_set_limit(packet, msglen);
+ list_packet(region, packet, partnum);
+ region_destroy(region);
+}
+
+/** list parts of xfr file */
+static void
+list_parts(FILE* in, int num)
+{
+ int i;
+ for(i=0; i<num; i++) {
+ list_part(in, i);
+ }
+}
+
+/** list contents of xfr file */
+static void
+list_file(char* fname)
+{
+ FILE* in;
+ int num;
+ log_init("udb-inspect");
+ if(!(in=fopen(fname, "r"))) {
+ printf("cannot open %s: %s\n", fname, strerror(errno));
+ exit(1);
+ }
+ num = list_header(in);
+ list_parts(in, num);
+
+ fclose(in);
+}
+
+/** getopt global, in case header files fail to declare it. */
+extern int optind;
+/** getopt global, in case header files fail to declare it. */
+extern char* optarg;
+
+/**
+ * main program. Set options given commandline arguments.
+ * @param argc: number of commandline arguments.
+ * @param argv: array of commandline arguments.
+ * @return: exit status of the program.
+ */
+int
+main(int argc, char* argv[])
+{
+ int c, list=0;
+ while( (c=getopt(argc, argv, "hlv")) != -1) {
+ switch(c) {
+ case 'l':
+ list=1;
+ break;
+ case 'v':
+ v++;
+ break;
+ default:
+ case 'h':
+ usage();
+ return 1;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if(argc != 1) {
+ usage();
+ return 1;
+ }
+ if(list) list_file(argv[0]);
+ else inspect_file(argv[0]);
+
+ return 0;
+}
diff --git xfrd-notify.c xfrd-notify.c
index 918b32142c9..3f9853e6409 100644
--- xfrd-notify.c
+++ xfrd-notify.c
@@ -17,7 +17,7 @@
 #include "xfrd-tcp.h"
 #include "packet.h"
 
-#define XFRD_NOTIFY_RETRY_TIMOUT 15 /* seconds between retries sending NOTIFY */
+#define XFRD_NOTIFY_RETRY_TIMOUT 3 /* seconds between retries sending NOTIFY */
 
 /* start sending notifies */
 static void notify_enable(struct notify_zone* zone,
@@ -25,15 +25,10 @@ static void notify_enable(struct notify_zone* zone,
 /* setup the notify active state */
 static void setup_notify_active(struct notify_zone* zone);
 
-/* returns if the notify send is done for the notify_current acl */
-static int xfrd_handle_notify_reply(struct notify_zone* zone, buffer_type* packet);
-
 /* handle zone notify send */
 static void xfrd_handle_notify_send(int fd, short event, void* arg);
 
-static void xfrd_notify_next(struct notify_zone* zone);
-
-static void xfrd_notify_send_udp(struct notify_zone* zone, buffer_type* packet);
+static int xfrd_notify_send_udp(struct notify_zone* zone, int index);
 
 static void
 notify_send_disable(struct notify_zone* zone)
@@ -42,6 +37,18 @@ notify_send_disable(struct notify_zone* zone)
  event_del(&zone->notify_send_handler);
  if(zone->notify_send_handler.ev_fd != -1) {
  close(zone->notify_send_handler.ev_fd);
+ zone->notify_send_handler.ev_fd = -1;
+ }
+}
+
+static void
+notify_send6_disable(struct notify_zone* zone)
+{
+ zone->notify_send6_enable = 0;
+ event_del(&zone->notify_send6_handler);
+ if(zone->notify_send6_handler.ev_fd != -1) {
+ close(zone->notify_send6_handler.ev_fd);
+ zone->notify_send6_handler.ev_fd = -1;
  }
 }
 
@@ -53,6 +60,9 @@ notify_disable(struct notify_zone* zone)
  if(zone->notify_send_enable) {
  notify_send_disable(zone);
  }
+ if(zone->notify_send6_enable) {
+ notify_send6_disable(zone);
+ }
 
  if(xfrd->notify_udp_num == XFRD_MAX_UDP_NOTIFY) {
  /* find next waiting and needy zone */
@@ -96,9 +106,12 @@ init_notify_send(rbtree_type* tree, region_type* region,
  sizeof(struct xfrd_soa));
  memset(not->current_soa, 0, sizeof(struct xfrd_soa));
 
+ not->notify_send_handler.ev_fd = -1;
+ not->notify_send6_handler.ev_fd = -1;
  not->is_waiting = 0;
 
  not->notify_send_enable = 0;
+ not->notify_send6_enable = 0;
  tsig_create_record_custom(&not->notify_tsig, NULL, 0, 0, 4);
  not->notify_current = 0;
  rbtree_insert(tree, (rbnode_type*)not);
@@ -125,7 +138,7 @@ xfrd_del_notify(xfrd_state_type* xfrd, const dname_type* dname)
  }
 
  /* event */
- if(not->notify_send_enable) {
+ if(not->notify_send_enable || not->notify_send6_enable) {
  notify_disable(not);
  }
 
@@ -139,62 +152,134 @@ xfrd_del_notify(xfrd_state_type* xfrd, const dname_type* dname)
 }
 
 static int
-xfrd_handle_notify_reply(struct notify_zone* zone, buffer_type* packet)
+reply_pkt_is_ack(struct notify_zone* zone, buffer_type* packet, int index)
 {
  if((OPCODE(packet) != OPCODE_NOTIFY) ||
  (QR(packet) == 0)) {
- log_msg(LOG_ERR, "xfrd: zone %s: received bad notify reply opcode/flags",
- zone->apex_str);
+ log_msg(LOG_ERR, "xfrd: zone %s: received bad notify reply opcode/flags from %s",
+ zone->apex_str, zone->pkts[index].dest->ip_address_spec);
+
  return 0;
  }
  /* we know it is OPCODE NOTIFY, QUERY_REPLY and for this zone */
- if(ID(packet) != zone->notify_query_id) {
- log_msg(LOG_ERR, "xfrd: zone %s: received notify-ack with bad ID",
- zone->apex_str);
+ if(ID(packet) != zone->pkts[index].notify_query_id) {
+ log_msg(LOG_ERR, "xfrd: zone %s: received notify-ack with bad ID from %s",
+ zone->apex_str, zone->pkts[index].dest->ip_address_spec);
  return 0;
  }
  /* could check tsig, but why. The reply does not cause processing. */
  if(RCODE(packet) != RCODE_OK) {
  log_msg(LOG_ERR, "xfrd: zone %s: received notify response error %s from %s",
  zone->apex_str, rcode2str(RCODE(packet)),
- zone->notify_current->ip_address_spec);
+ zone->pkts[index].dest->ip_address_spec);
  if(RCODE(packet) == RCODE_IMPL)
  return 1; /* rfc1996: notimpl notify reply: consider retries done */
  return 0;
  }
  DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s: host %s acknowledges notify",
- zone->apex_str, zone->notify_current->ip_address_spec));
+ zone->apex_str, zone->pkts[index].dest->ip_address_spec));
  return 1;
 }
 
+/* compare sockaddr and acl_option addr and port numbers */
+static int
+cmp_addr_equal(struct sockaddr* a, socklen_t a_len, struct acl_options* dest)
+{
+ if(dest) {
+ unsigned int destport = ((dest->port == 0)?
+ (unsigned)atoi(TCP_PORT):dest->port);
+#ifdef INET6
+ struct sockaddr_storage* a1 = (struct sockaddr_storage*)a;
+ if(a1->ss_family == AF_INET6 && dest->is_ipv6) {
+ struct sockaddr_in6* a2 = (struct sockaddr_in6*)a;
+ if(a_len < sizeof(struct sockaddr_in6))
+ return 0; /* too small */
+ if(ntohs(a2->sin6_port) != destport)
+ return 0; /* different port number */
+ if(memcmp(&a2->sin6_addr, &dest->addr.addr6,
+ sizeof(struct in6_addr)) != 0)
+ return 0; /* different address */
+ return 1;
+ }
+ if(a1->ss_family == AF_INET6 || dest->is_ipv6)
+ return 0; /* different address family */
+ else {
+#endif /* INET6 */
+ struct sockaddr_in* a3 = (struct sockaddr_in*)a;
+ if(a_len < sizeof(struct sockaddr_in))
+ return 0; /* too small */
+ if(ntohs(a3->sin_port) != destport)
+ return 0; /* different port number */
+ if(memcmp(&a3->sin_addr, &dest->addr.addr,
+ sizeof(struct in_addr)) != 0)
+ return 0; /* different address */
+ return 1;
+#ifdef INET6
+ }
+#endif
+ }
+ return 0;
+}
+
 static void
-xfrd_notify_next(struct notify_zone* zone)
+notify_pkt_done(struct notify_zone* zone, int index)
 {
- /* advance to next in acl */
- zone->notify_current = zone->notify_current->next;
- zone->notify_retry = 0;
- if(zone->notify_current == 0) {
- DEBUG(DEBUG_XFRD,1, (LOG_INFO,
- "xfrd: zone %s: no more notify-send acls. stop notify.",
- zone->apex_str));
- notify_disable(zone);
+ zone->pkts[index].dest = NULL;
+ zone->pkts[index].notify_retry = 0;
+ zone->pkts[index].send_time = 0;
+ zone->pkts[index].notify_query_id = 0;
+ zone->notify_pkt_count--;
+}
+
+static void
+notify_pkt_retry(struct notify_zone* zone, int index)
+{
+ if(++zone->pkts[index].notify_retry >=
+ zone->options->pattern->notify_retry) {
+ log_msg(LOG_ERR, "xfrd: zone %s: max notify send count reached, %s unreachable",
+ zone->apex_str,
+ zone->pkts[index].dest->ip_address_spec);
+ notify_pkt_done(zone, index);
  return;
  }
+ if(!xfrd_notify_send_udp(zone, index)) {
+ notify_pkt_retry(zone, index);
+ }
 }
 
 static void
-xfrd_notify_send_udp(struct notify_zone* zone, buffer_type* packet)
+xfrd_handle_notify_reply(struct notify_zone* zone, buffer_type* packet,
+ struct sockaddr* src, socklen_t srclen)
 {
- int fd;
- if(zone->notify_send_enable) {
- notify_send_disable(zone);
+ int i;
+ for(i=0; i<NOTIFY_CONCURRENT_MAX; i++) {
+ /* is this entry in use */
+ if(!zone->pkts[i].dest)
+ continue;
+ /* based on destination */
+ if(!cmp_addr_equal(src, srclen, zone->pkts[i].dest))
+ continue;
+ if(reply_pkt_is_ack(zone, packet, i)) {
+ /* is done */
+ notify_pkt_done(zone, i);
+ return;
+ } else {
+ /* retry */
+ notify_pkt_retry(zone, i);
+ return;
+ }
  }
- /* Set timeout for next reply */
- zone->notify_timeout.tv_sec = XFRD_NOTIFY_RETRY_TIMOUT;
+}
+
+static int
+xfrd_notify_send_udp(struct notify_zone* zone, int index)
+{
+ buffer_type* packet = xfrd_get_temp_buffer();
+ if(!zone->pkts[index].dest) return 0;
  /* send NOTIFY to secondary. */
  xfrd_setup_packet(packet, TYPE_SOA, CLASS_IN, zone->apex,
  qid_generate());
- zone->notify_query_id = ID(packet);
+ zone->pkts[index].notify_query_id = ID(packet);
  OPCODE_SET(packet, OPCODE_NOTIFY);
  AA_SET(packet);
  if(zone->current_soa->serial != 0) {
@@ -202,35 +287,123 @@ xfrd_notify_send_udp(struct notify_zone* zone, buffer_type* packet)
  ANCOUNT_SET(packet, 1);
  xfrd_write_soa_buffer(packet, zone->apex, zone->current_soa);
  }
- if(zone->notify_current->key_options) {
- xfrd_tsig_sign_request(packet, &zone->notify_tsig, zone->notify_current);
+ if(zone->pkts[index].dest->key_options) {
+ xfrd_tsig_sign_request(packet, &zone->notify_tsig, zone->pkts[index].dest);
  }
  buffer_flip(packet);
- fd = xfrd_send_udp(zone->notify_current, packet,
- zone->options->pattern->outgoing_interface);
- if(fd == -1) {
- log_msg(LOG_ERR, "xfrd: zone %s: could not send notify #%d to %s",
- zone->apex_str, zone->notify_retry,
- zone->notify_current->ip_address_spec);
- event_set(&zone->notify_send_handler, -1, EV_TIMEOUT,
+
+ if((zone->pkts[index].dest->is_ipv6
+ && zone->notify_send6_handler.ev_fd == -1) ||
+ (!zone->pkts[index].dest->is_ipv6
+ && zone->notify_send_handler.ev_fd == -1)) {
+ /* open fd */
+ int fd = xfrd_send_udp(zone->pkts[index].dest, packet,
+ zone->options->pattern->outgoing_interface);
+ if(fd == -1) {
+ log_msg(LOG_ERR, "xfrd: zone %s: could not send notify #%d to %s",
+ zone->apex_str, zone->pkts[index].notify_retry,
+ zone->pkts[index].dest->ip_address_spec);
+ return 0;
+ }
+ if(zone->pkts[index].dest->is_ipv6)
+ zone->notify_send6_handler.ev_fd = fd;
+ else zone->notify_send_handler.ev_fd = fd;
+ } else {
+ /* send on existing fd */
+#ifdef INET6
+         struct sockaddr_storage to;
+#else
+         struct sockaddr_in to;
+#endif /* INET6 */
+ int fd;
+ socklen_t to_len = xfrd_acl_sockaddr_to(
+ zone->pkts[index].dest, &to);
+ if(zone->pkts[index].dest->is_ipv6)
+ fd = zone->notify_send6_handler.ev_fd;
+ else fd = zone->notify_send_handler.ev_fd;
+ if(sendto(fd,
+ buffer_current(packet), buffer_remaining(packet), 0,
+ (struct sockaddr*)&to, to_len) == -1) {
+ log_msg(LOG_ERR, "xfrd notify: sendto %s failed %s",
+ zone->pkts[index].dest->ip_address_spec,
+ strerror(errno));
+ return 0;
+ }
+ }
+ zone->pkts[index].send_time = time(NULL);
+ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s: sent notify #%d to %s",
+ zone->apex_str, zone->pkts[index].notify_retry,
+ zone->pkts[index].dest->ip_address_spec));
+ return 1;
+}
+
+static void
+notify_timeout_check(struct notify_zone* zone)
+{
+ time_t now = time(NULL);
+ int i;
+ for(i=0; i<NOTIFY_CONCURRENT_MAX; i++) {
+ if(!zone->pkts[i].dest)
+ continue;
+ if(now >= zone->pkts[i].send_time + XFRD_NOTIFY_RETRY_TIMOUT) {
+ notify_pkt_retry(zone, i);
+ }
+ }
+}
+
+static void
+notify_start_pkts(struct notify_zone* zone)
+{
+ int i;
+ if(!zone->notify_current) return; /* no more acl to send to */
+ for(i=0; i<NOTIFY_CONCURRENT_MAX; i++) {
+ /* while loop, in case the retries all fail, and we can
+ * start another on this slot, or run out of notify acls */
+ while(zone->pkts[i].dest==NULL && zone->notify_current) {
+ zone->pkts[i].dest = zone->notify_current;
+ zone->notify_current = zone->notify_current->next;
+ zone->pkts[i].notify_retry = 0;
+ zone->pkts[i].notify_query_id = 0;
+ zone->pkts[i].send_time = 0;
+ zone->notify_pkt_count++;
+ if(!xfrd_notify_send_udp(zone, i)) {
+ notify_pkt_retry(zone, i);
+ }
+ }
+ }
+}
+
+static void
+notify_setup_event(struct notify_zone* zone)
+{
+ if(zone->notify_send_handler.ev_fd != -1) {
+ int fd = zone->notify_send_handler.ev_fd;
+ if(zone->notify_send_enable) {
+ event_del(&zone->notify_send_handler);
+ }
+ zone->notify_timeout.tv_sec = XFRD_NOTIFY_RETRY_TIMOUT;
+ event_set(&zone->notify_send_handler, fd, EV_READ | EV_TIMEOUT,
  xfrd_handle_notify_send, zone);
  if(event_base_set(xfrd->event_base, &zone->notify_send_handler) != 0)
  log_msg(LOG_ERR, "notify_send: event_base_set failed");
- if(evtimer_add(&zone->notify_send_handler, &zone->notify_timeout) != 0)
- log_msg(LOG_ERR, "notify_send: evtimer_add failed");
+ if(event_add(&zone->notify_send_handler, &zone->notify_timeout) != 0)
+ log_msg(LOG_ERR, "notify_send: event_add failed");
  zone->notify_send_enable = 1;
- return;
  }
- event_set(&zone->notify_send_handler, fd, EV_READ | EV_TIMEOUT,
- xfrd_handle_notify_send, zone);
- if(event_base_set(xfrd->event_base, &zone->notify_send_handler) != 0)
- log_msg(LOG_ERR, "notify_send: event_base_set failed");
- if(event_add(&zone->notify_send_handler, &zone->notify_timeout) != 0)
- log_msg(LOG_ERR, "notify_send: evtimer_add failed");
- zone->notify_send_enable = 1;
- DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s: sent notify #%d to %s",
- zone->apex_str, zone->notify_retry,
- zone->notify_current->ip_address_spec));
+ if(zone->notify_send6_handler.ev_fd != -1) {
+ int fd = zone->notify_send6_handler.ev_fd;
+ if(zone->notify_send6_enable) {
+ event_del(&zone->notify_send6_handler);
+ }
+ zone->notify_timeout.tv_sec = XFRD_NOTIFY_RETRY_TIMOUT;
+ event_set(&zone->notify_send6_handler, fd, EV_READ | EV_TIMEOUT,
+ xfrd_handle_notify_send, zone);
+ if(event_base_set(xfrd->event_base, &zone->notify_send6_handler) != 0)
+ log_msg(LOG_ERR, "notify_send: event_base_set failed");
+ if(event_add(&zone->notify_send6_handler, &zone->notify_timeout) != 0)
+ log_msg(LOG_ERR, "notify_send: event_add failed");
+ zone->notify_send6_enable = 1;
+ }
 }
 
 static void
@@ -238,44 +411,54 @@ xfrd_handle_notify_send(int fd, short event, void* arg)
 {
  struct notify_zone* zone = (struct notify_zone*)arg;
  buffer_type* packet = xfrd_get_temp_buffer();
- assert(zone->notify_current);
  if(zone->is_waiting) {
  DEBUG(DEBUG_XFRD,1, (LOG_INFO,
  "xfrd: notify waiting, skipped, %s", zone->apex_str));
  return;
  }
  if((event & EV_READ)) {
+ struct sockaddr_storage src;
+ socklen_t srclen = (socklen_t)sizeof(src);
  DEBUG(DEBUG_XFRD,1, (LOG_INFO,
  "xfrd: zone %s: read notify ACK", zone->apex_str));
  assert(fd != -1);
- if(xfrd_udp_read_packet(packet, fd)) {
- if(xfrd_handle_notify_reply(zone, packet))
- xfrd_notify_next(zone);
+ if(xfrd_udp_read_packet(packet, fd, (struct sockaddr*)&src,
+ &srclen)) {
+ /* find entry, send retry or make entry NULL */
+ xfrd_handle_notify_reply(zone, packet,
+ (struct sockaddr*)&src, srclen);
  }
- } else if((event & EV_TIMEOUT)) {
+ }
+ if((event & EV_TIMEOUT)) {
  DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s: notify timeout",
  zone->apex_str));
  /* timeout, try again */
  }
- /* see if notify is still enabled */
- if(zone->notify_current) {
- zone->notify_retry++;
- if(zone->notify_retry > zone->options->pattern->notify_retry) {
- log_msg(LOG_ERR, "xfrd: zone %s: max notify send count reached, %s unreachable",
- zone->apex_str, zone->notify_current->ip_address_spec);
- xfrd_notify_next(zone);
- }
- }
- if(zone->notify_current) {
- /* try again */
- xfrd_notify_send_udp(zone, packet);
+
+ /* see which pkts have timeouted, retry or NULL them */
+ notify_timeout_check(zone);
+
+ /* start new packets if we have empty space */
+ notify_start_pkts(zone);
+
+ /* see if we are done */
+ if(!zone->notify_current && !zone->notify_pkt_count) {
+ /* we are done */
+ DEBUG(DEBUG_XFRD,1, (LOG_INFO,
+ "xfrd: zone %s: no more notify-send acls. stop notify.",
+ zone->apex_str));
+ notify_disable(zone);
+ return;
  }
+
+ notify_setup_event(zone);
 }
 
 static void
 setup_notify_active(struct notify_zone* zone)
 {
- zone->notify_retry = 0;
+ zone->notify_pkt_count = 0;
+ memset(zone->pkts, 0, sizeof(zone->pkts));
  zone->notify_current = zone->options->pattern->notify;
  zone->notify_timeout.tv_sec = 0;
  zone->notify_timeout.tv_usec = 0;
@@ -329,7 +512,8 @@ void
 xfrd_notify_start(struct notify_zone* zone, struct xfrd_state* xfrd)
 {
  xfrd_zone_type* xz;
- if(zone->is_waiting || zone->notify_send_enable)
+ if(zone->is_waiting || zone->notify_send_enable ||
+ zone->notify_send6_enable)
  return;
  xz = (xfrd_zone_type*)rbtree_search(xfrd->zones, zone->apex);
  if(xz && xz->soa_nsd_acquired)
@@ -344,7 +528,7 @@ xfrd_send_notify(rbtree_type* tree, const dname_type* apex, struct xfrd_soa* new
  struct notify_zone* zone = (struct notify_zone*)
  rbtree_search(tree, apex);
  assert(zone);
- if(zone->notify_send_enable)
+ if(zone->notify_send_enable || zone->notify_send6_enable)
  notify_disable(zone);
 
  notify_enable(zone, new_soa);
@@ -363,7 +547,7 @@ notify_handle_master_zone_soainfo(rbtree_type* tree,
  if( (new_soa == NULL && zone->current_soa->serial == 0) ||
  (new_soa && new_soa->serial == zone->current_soa->serial))
  return;
- if(zone->notify_send_enable)
+ if(zone->notify_send_enable || zone->notify_send6_enable)
  notify_disable(zone);
  notify_enable(zone, new_soa);
 }
@@ -374,7 +558,7 @@ close_notify_fds(rbtree_type* tree)
  struct notify_zone* zone;
  RBTREE_FOR(zone, struct notify_zone*, tree)
  {
- if(zone->notify_send_enable)
+ if(zone->notify_send_enable || zone->notify_send6_enable)
  notify_send_disable(zone);
  }
 }
diff --git xfrd-notify.h xfrd-notify.h
index 153dca5129b..3a20f383ff1 100644
--- xfrd-notify.h
+++ xfrd-notify.h
@@ -33,6 +33,17 @@ struct xfrd_soa;
 struct acl_options;
 struct xfrd_state;
 
+/** number of concurrent notify packets in flight */
+#define NOTIFY_CONCURRENT_MAX 16
+
+/** notify packet info */
+struct notify_pkt {
+ struct acl_options* dest; /* target, NULL if entry not in use */
+ uint8_t notify_retry; /* how manieth retry in sending to current */
+ uint16_t notify_query_id;
+ time_t send_time;
+};
+
 /**
  * This struct keeps track of outbound notifies for a zone.
  */
@@ -50,18 +61,20 @@ struct notify_zone {
  /* Not saved on disk (i.e. kill of daemon stops notifies) */
  int notify_send_enable;
  struct event notify_send_handler;
+ int notify_send6_enable;
+ struct event notify_send6_handler;
  struct timeval notify_timeout;
  struct acl_options* notify_current; /* current slave to notify */
  uint8_t notify_restart; /* restart notify after repattern */
- uint8_t notify_retry; /* how manieth retry in sending to current */
- uint16_t notify_query_id;
+ struct notify_pkt pkts[NOTIFY_CONCURRENT_MAX];
+ int notify_pkt_count; /* number of entries nonNULL in pkts */
 
  /* is this notify waiting for a socket? */
  uint8_t is_waiting;
  /* the double linked waiting list for the udp sockets */
  struct notify_zone* waiting_next;
  struct notify_zone* waiting_prev;
-};
+} ATTR_PACKED;
 
 /* initialise outgoing notifies */
 void init_notify_send(rbtree_type* tree, region_type* region,
diff --git xfrd-tcp.c xfrd-tcp.c
index 2715689439f..3c176a38ff8 100644
--- xfrd-tcp.c
+++ xfrd-tcp.c
@@ -13,6 +13,7 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <stdlib.h>
+#include <sys/uio.h>
 #include "nsd.h"
 #include "xfrd-tcp.h"
 #include "buffer.h"
@@ -898,6 +899,7 @@ xfrd_tcp_read(struct xfrd_tcp_pipeline* tp)
  tp->id[zone->query_id] = TCP_NULL_SKIP;
  tp->num_skip++;
  /* fall through to remove zone from tp */
+ /* fallthrough */
  case xfrd_packet_transfer:
  if(zone->zone_options->pattern->multi_master_check) {
  xfrd_tcp_release(xfrd->tcp_set, zone);
diff --git xfrd.c xfrd.c
index 1c03750dacf..3520f5d3b1b 100644
--- xfrd.c
+++ xfrd.c
@@ -767,7 +767,7 @@ xfrd_set_timer_retry(xfrd_zone_type* zone)
  else if(set_retry < (time_t)zone->zone_options->pattern->min_retry_time)
  set_retry = zone->zone_options->pattern->min_retry_time;
  if(set_retry < XFRD_LOWERBOUND_RETRY)
- set_retry =  XFRD_LOWERBOUND_RETRY;
+ set_retry = XFRD_LOWERBOUND_RETRY;
  xfrd_set_timer(zone, set_retry);
  } else {
  set_retry = ntohl(zone->soa_disk.expire);
@@ -1210,14 +1210,15 @@ xfrd_send_expire_notification(xfrd_zone_type* zone)
 }
 
 int
-xfrd_udp_read_packet(buffer_type* packet, int fd)
+xfrd_udp_read_packet(buffer_type* packet, int fd, struct sockaddr* src,
+ socklen_t* srclen)
 {
  ssize_t received;
 
  /* read the data */
  buffer_clear(packet);
  received = recvfrom(fd, buffer_begin(packet), buffer_remaining(packet),
- 0, NULL, NULL);
+ 0, src, srclen);
  if(received == -1) {
  log_msg(LOG_ERR, "xfrd: recvfrom failed: %s",
  strerror(errno));
@@ -1299,7 +1300,8 @@ static void
 xfrd_udp_read(xfrd_zone_type* zone)
 {
  DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s read udp data", zone->apex_str));
- if(!xfrd_udp_read_packet(xfrd->packet, zone->zone_handler.ev_fd)) {
+ if(!xfrd_udp_read_packet(xfrd->packet, zone->zone_handler.ev_fd,
+ NULL, NULL)) {
  zone->master->bad_xfr_count++;
  if (zone->master->bad_xfr_count > 2) {
  xfrd_disable_ixfr(zone);
@@ -1323,6 +1325,7 @@ xfrd_udp_read(xfrd_zone_type* zone)
  xfrd_make_request(zone);
  break;
  }
+ /* fallthrough */
  case xfrd_packet_newlease:
  /* nothing more to do */
  assert(zone->round_num == -1);
diff --git xfrd.h xfrd.h
index 44e7ba1795a..c58780c7065 100644
--- xfrd.h
+++ xfrd.h
@@ -136,7 +136,7 @@ struct xfrd_soa {
  uint32_t retry;
  uint32_t expire;
  uint32_t minimum;
-};
+} ATTR_PACKED;
 
 
 /*
@@ -219,7 +219,7 @@ struct xfrd_zone {
  valid if msg_seq_nr nonzero */
  int multi_master_first_master; /* >0: first check master_num */
  int multi_master_update_check; /* -1: not update >0: last update master_num */
-};
+} ATTR_PACKED;
 
 enum xfrd_packet_result {
  xfrd_packet_bad, /* drop the packet/connection */
@@ -239,10 +239,10 @@ enum xfrd_packet_result {
    Note that also some sockets are used for writing the ixfr.db, xfrd.state
    files and for the pipes to the main parent process.
 */
-#define XFRD_MAX_TCP 32 /* max number of TCP AXFR/IXFR concurrent connections.*/
+#define XFRD_MAX_TCP 128 /* max number of TCP AXFR/IXFR concurrent connections.*/
  /* Each entry has 64Kb buffer preallocated.*/
-#define XFRD_MAX_UDP 64 /* max number of UDP sockets at a time for IXFR */
-#define XFRD_MAX_UDP_NOTIFY 64 /* max concurrent UDP sockets for NOTIFY */
+#define XFRD_MAX_UDP 128 /* max number of UDP sockets at a time for IXFR */
+#define XFRD_MAX_UDP_NOTIFY 128 /* max concurrent UDP sockets for NOTIFY */
 
 #define XFRD_TRANSFER_TIMEOUT_START 10 /* empty zone timeout is between x and 2*x seconds */
 #define XFRD_TRANSFER_TIMEOUT_MAX 86400 /* empty zone timeout max expbackoff */
@@ -300,7 +300,8 @@ int xfrd_send_udp(struct acl_options* acl, buffer_type* packet,
 /*
  * read from udp port packet into buffer, returns 0 on failure
  */
-int xfrd_udp_read_packet(buffer_type* packet, int fd);
+int xfrd_udp_read_packet(buffer_type* packet, int fd, struct sockaddr* src,
+ socklen_t* srclen);
 
 /*
  * Release udp socket that a zone is using
diff --git zlexer.lex zlexer.lex
index 90a1df3741c..728f92603f6 100644
--- zlexer.lex
+++ zlexer.lex
@@ -83,6 +83,16 @@ parser_pop_stringbuf(void)
  oldstate = NULL;
 }
 
+ static int paren_open = 0;
+ static enum lexer_state lexer_state = EXPECT_OWNER;
+void
+parser_flush(void)
+{
+ YY_FLUSH_BUFFER;
+ paren_open = 0;
+ lexer_state = EXPECT_OWNER;
+}
+
 #ifndef yy_set_bol /* compat definition, for flex 2.4.6 */
 #define yy_set_bol(at_bol) \
  { \
@@ -119,8 +129,6 @@ ANY     [^\"\n\\]|\\.
 %x incl bitlabel quotedstring
 
 %%
- static int paren_open = 0;
- static enum lexer_state lexer_state = EXPECT_OWNER;
 {SPACE}*{COMMENT}.* /* ignore */
 ^{DOLLAR}TTL            { lexer_state = PARSING_RDATA; return DOLLAR_TTL; }
 ^{DOLLAR}ORIGIN         { lexer_state = PARSING_RDATA; return DOLLAR_ORIGIN; }
diff --git zonec.c zonec.c
index 1b20b84d90f..de0a03ca4cd 100644
--- zonec.c
+++ zonec.c
@@ -1627,6 +1627,7 @@ zonec_read(const char* name, const char* zonefile, zone_type* zone)
  parser->current_zone->soa_rrset->rrs[0].owner));
  }
 
+ parser_flush();
  fclose(yyin);
  if(!zone_is_slave(zone->opts))
  check_dname(zone);
@@ -1719,5 +1720,6 @@ zonec_parse_string(region_type* region, domain_table_type* domains,
  if(parser->origin != error_domain)
  domain_table_deldomain(parser->db, parser->origin);
  zonec_desetup_string_parser();
+ parser_flush();
  return errors;
 }
diff --git zonec.h zonec.h
index 4057b12cf36..b14bedb20ca 100644
--- zonec.h
+++ zonec.h
@@ -82,6 +82,7 @@ void zc_error_prev_line(const char *fmt, ...) ATTR_FORMAT(printf, 1, 2);
 
 void parser_push_stringbuf(char* str);
 void parser_pop_stringbuf(void);
+void parser_flush(void);
 
 int process_rr(void);
 uint16_t *zparser_conv_hex(region_type *region, const char *hex, size_t len);


--
I'm not entirely sure you are real.

Reply | Threaded
Open this post in threaded view
|

Re: nsd 4.1.19

Stuart Henderson
On 2018/01/26 18:12, Florian Obser wrote:
> anyone else?
> Got around to read the diff, not too much insanity in there, going to
> commit soon.

ok with me.

> diff --git nsd.c nsd.c
> index f2cf6ccf0cb..dfbc58696b3 100644
> --- nsd.c
> +++ nsd.c
> @@ -579,6 +579,7 @@ main(int argc, char *argv[])
>   case 'v':
>   version();
>   /* version exits */
> + break;
>  #ifndef NDEBUG
>   case 'F':
>   sscanf(optarg, "%x", &nsd_debug_facilities);
> @@ -980,6 +981,7 @@ main(int argc, char *argv[])
>   break;
>   case -1:
>   error("fork() failed: %s", strerror(errno));
> + break;
>   default:
>   /* Parent is done */
>   server_close_all_sockets(nsd.udp, nsd.ifs);

that gcc lint thing doesn't seem particularly clever if those are needed!

Reply | Threaded
Open this post in threaded view
|

Re: nsd 4.1.19

Florian Obser-2
On Fri, Jan 26, 2018 at 05:38:46PM +0000, Stuart Henderson wrote:

> On 2018/01/26 18:12, Florian Obser wrote:
> > anyone else?
> > Got around to read the diff, not too much insanity in there, going to
> > commit soon.
>
> ok with me.
>
> > diff --git nsd.c nsd.c
> > index f2cf6ccf0cb..dfbc58696b3 100644
> > --- nsd.c
> > +++ nsd.c
> > @@ -579,6 +579,7 @@ main(int argc, char *argv[])
> >   case 'v':
> >   version();
> >   /* version exits */
> > + break;
> >  #ifndef NDEBUG
> >   case 'F':
> >   sscanf(optarg, "%x", &nsd_debug_facilities);
> > @@ -980,6 +981,7 @@ main(int argc, char *argv[])
> >   break;
> >   case -1:
> >   error("fork() failed: %s", strerror(errno));
> > + break;
> >   default:
> >   /* Parent is done */
> >   server_close_all_sockets(nsd.udp, nsd.ifs);
>
> that gcc lint thing doesn't seem particularly clever if those are needed!
>

Indeed, there is also some comment spam that's not relevant for us, I
left that in to not create conflicts for future updates.

I like this one :D

  /** Fallthrough: AXFR over UDP queries are discarded. */
+ /* fallthrough */


I dropped this though:

+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"

Don't want to find out in two weeks time what gcc on the luna88k
thinks about that...

--
I'm not entirely sure you are real.