I have been prodded by dhill & brad, so here is a diff.
Running with it now but haven't reviewed it, yet.

(I have a git repo with all intermediate diffs if someone wants to
look at those...)

Tests / OKs? (I will review the diff myself before committing)

diff --git Makefile.in Makefile.in
index 3fbd01b..3391cd0 100644
--- Makefile.in
+++ Makefile.in
@@ -317,7 +317,7 @@ DEPEND_TMP2=depend1074.tmp
 DEPEND_TARGET=Makefile
 DEPEND_TARGET2=Makefile.in
 depend:
-       (cd $(srcdir) ; $(CC) -MM $(CPPFLAGS) *.c compat/*.c tpkg/cutest/*.c) | 
\
+       (cd $(srcdir) ; $(CC) -MM $(CPPFLAGS) *.c compat/*.c `if test -d 
tpkg/cutest; then echo tpkg/cutest/*.c; fi`) | \
                sed -e 's? *\([^ ]*\.[ch]\)? $$(srcdir)/\1?g' | \
                sed -e 's?$$(srcdir)/config.h?config.h?g' \
                        -e 's?$$(srcdir)/configlexer.c?configlexer.c?g' \
diff --git axfr.c axfr.c
index 09eb082..92d4f2f 100644
--- axfr.c
+++ axfr.c
@@ -91,7 +91,7 @@ query_axfr(struct nsd *nsd, struct query *query)
                query->edns.status = EDNS_NOT_PRESENT;
                buffer_set_limit(query->packet, QHEADERSZ);
                QDCOUNT_SET(query->packet, 0);
-               query_prepare_response(query, nsd);
+               query_prepare_response(query);
        }
 
        /* Add zone RRs until answer is full.  */
diff --git configlexer.lex configlexer.lex
index d536352..0ce80bd 100644
--- configlexer.lex
+++ configlexer.lex
@@ -7,6 +7,8 @@
  * See LICENSE for the license.
  *
  */
+/* because flex keeps having sign-unsigned compare problems that are unfixed*/
+#pragma GCC diagnostic ignored "-Wsign-compare"
 
 #include "config.h"
 
@@ -273,6 +275,7 @@ max-refresh-time{COLON}     { LEXOUT(("v(%s) ", yytext)); 
return VAR_MAX_REFRESH_TIM
 min-refresh-time{COLON}        { LEXOUT(("v(%s) ", yytext)); return 
VAR_MIN_REFRESH_TIME;}
 max-retry-time{COLON}  { LEXOUT(("v(%s) ", yytext)); return 
VAR_MAX_RETRY_TIME;}
 min-retry-time{COLON}  { LEXOUT(("v(%s) ", yytext)); return 
VAR_MIN_RETRY_TIME;}
+multi-master-check{COLON}      { LEXOUT(("v(%s) ", yytext)); return 
VAR_MULTI_MASTER_CHECK;}
 {NEWLINE}              { LEXOUT(("NL\n")); cfg_parser->line++;}
 
        /* Quoted strings. Strip leading and ending quotes */
diff --git configparser.y configparser.y
index 9089665..204d236 100644
--- configparser.y
+++ configparser.y
@@ -71,6 +71,7 @@ extern config_parser_state_t* cfg_parser;
 %token VAR_ROUND_ROBIN VAR_ZONESTATS VAR_REUSEPORT VAR_VERSION
 %token VAR_MAX_REFRESH_TIME VAR_MIN_REFRESH_TIME
 %token VAR_MAX_RETRY_TIME VAR_MIN_RETRY_TIME
+%token VAR_MULTI_MASTER_CHECK
 
 %%
 toplevelvars: /* empty */ | toplevelvars toplevelvar ;
@@ -602,7 +603,7 @@ zone_config_item: zone_zonefile | zone_allow_notify | 
zone_request_xfr |
        zone_outgoing_interface | zone_allow_axfr_fallback | include_pattern |
        zone_rrl_whitelist | zone_zonestats | zone_max_refresh_time |
        zone_min_refresh_time | zone_max_retry_time | zone_min_retry_time |
-       zone_size_limit_xfr;
+       zone_size_limit_xfr | zone_multi_master_check;
 pattern_name: VAR_NAME STRING
        { 
                OUTYY(("P(pattern_name:%s)\n", $2)); 
@@ -871,6 +872,13 @@ zone_min_retry_time: VAR_MIN_RETRY_TIME STRING
                cfg_parser->current_pattern->min_retry_time_is_default = 0;
        }
 };
+zone_multi_master_check: VAR_MULTI_MASTER_CHECK STRING
+       {
+               OUTYY(("P(zone_multi_master_check:%s)\n", $2));
+               if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+                       yyerror("expected yes or no.");
+               else cfg_parser->current_pattern->multi_master_check = 
(strcmp($2, "yes")==0);
+       }
 
 /* key: declaration */
 keystart: VAR_KEY
@@ -883,6 +891,7 @@ keystart: VAR_KEY
                        key_options_insert(cfg_parser->opt, 
cfg_parser->current_key);
                }
                cfg_parser->current_key = 
key_options_create(cfg_parser->opt->region);
+               cfg_parser->current_key->algorithm = 
region_strdup(cfg_parser->opt->region, "sha256");
        }
        ;
 contents_key: contents_key content_key | content_key;
@@ -907,6 +916,8 @@ key_algorithm: VAR_ALGORITHM STRING
 #ifndef NDEBUG
                assert(cfg_parser->current_key);
 #endif
+               if(cfg_parser->current_key->algorithm)
+                       region_recycle(cfg_parser->opt->region, 
cfg_parser->current_key->algorithm, 
strlen(cfg_parser->current_key->algorithm)+1);
                cfg_parser->current_key->algorithm = 
region_strdup(cfg_parser->opt->region, $2);
                if(tsig_get_algorithm_by_name($2) == NULL)
                        c_error_msg("Bad tsig algorithm %s", $2);
diff --git configure configure
index 4ac0670..41bb666 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.12.
+# Generated by GNU Autoconf 2.69 for NSD 4.1.13.
 #
 # Report bugs to <nsd-b...@nlnetlabs.nl>.
 #
@@ -580,8 +580,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='NSD'
 PACKAGE_TARNAME='nsd'
-PACKAGE_VERSION='4.1.12'
-PACKAGE_STRING='NSD 4.1.12'
+PACKAGE_VERSION='4.1.13'
+PACKAGE_STRING='NSD 4.1.13'
 PACKAGE_BUGREPORT='nsd-b...@nlnetlabs.nl'
 PACKAGE_URL=''
 
@@ -731,6 +731,7 @@ with_ssl
 enable_nsec3
 enable_minimal_responses
 enable_mmap
+enable_radix_tree
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1283,7 +1284,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.12 to adapt to many kinds of systems.
+\`configure' configures NSD 4.1.13 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1344,7 +1345,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of NSD 4.1.12:";;
+     short | recursive ) echo "Configuration of NSD 4.1.13:";;
    esac
   cat <<\_ACEOF
 
@@ -1377,6 +1378,9 @@ Optional Features:
   --disable-minimal-responses
                           Disable response minimization. More truncation.
   --enable-mmap           Use mmap instead of malloc. Experimental.
+  --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.
 
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
@@ -1487,7 +1491,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-NSD configure 4.1.12
+NSD configure 4.1.13
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2196,7 +2200,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.12, which was
+It was created by NSD $as_me 4.1.13, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -8675,7 +8679,6 @@ _ACEOF
 esac
 
 
-
 # we need SSL for TSIG (and maybe also for NSEC3).
 
 
@@ -8978,7 +8981,7 @@ fi
 
 done
 
-       for ac_func in HMAC_CTX_reset HMAC_CTX_new
+       for ac_func in HMAC_CTX_reset HMAC_CTX_new EVP_cleanup 
ERR_load_crypto_strings OPENSSL_init_crypto
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
 ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
@@ -8990,6 +8993,22 @@ _ACEOF
 fi
 done
 
+
+       BAKLIBS="$LIBS"
+       LIBS="-lssl $LIBS"
+       for ac_func in OPENSSL_init_ssl
+do :
+  ac_fn_c_check_func "$LINENO" "OPENSSL_init_ssl" "ac_cv_func_OPENSSL_init_ssl"
+if test "x$ac_cv_func_OPENSSL_init_ssl" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_OPENSSL_INIT_SSL 1
+_ACEOF
+
+fi
+done
+
+       LIBS="$BAKLIBS"
+
 else
        { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: No SSL, therefore 
remote-control is disabled" >&5
 $as_echo "$as_me: WARNING: No SSL, therefore remote-control is disabled" >&2;}
@@ -9135,6 +9154,23 @@ _ACEOF
                 ;;
 esac
 
+# Check whether --enable-radix-tree was given.
+if test "${enable_radix_tree+set}" = set; then :
+  enableval=$enable_radix_tree;
+fi
+
+case "$enable_radix_tree" in
+        no)
+       ;;
+       yes|*)
+
+cat >>confdefs.h <<_ACEOF
+#define USE_RADIX_TREE /**/
+_ACEOF
+
+       ;;
+esac
+
 
 
 
@@ -9681,7 +9717,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.12, which was
+This file was extended by NSD $as_me 4.1.13, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -9743,7 +9779,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.12
+NSD config.status 4.1.13
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
diff --git configure.ac configure.ac
index 75a44c5..e2aca4d 100644
--- configure.ac
+++ configure.ac
@@ -4,7 +4,7 @@ dnl
 
 sinclude(acx_nlnetlabs.m4)
 
-AC_INIT(NSD,4.1.12,nsd-b...@nlnetlabs.nl)
+AC_INIT(NSD,4.1.13,nsd-b...@nlnetlabs.nl)
 AC_CONFIG_HEADER([config.h])
 
 CFLAGS="$CFLAGS"
@@ -825,7 +825,6 @@ case "$enable_ratelimit_default_is_off" in
 esac
 AC_SUBST(ratelimit_default)
 
-
 # we need SSL for TSIG (and maybe also for NSEC3).
 CHECK_SSL
 if test x$HAVE_SSL = x"yes"; then
@@ -862,7 +861,13 @@ if test x$HAVE_SSL = x"yes"; then
        AC_CHECK_HEADERS([openssl/ssl.h],,, [AC_INCLUDES_DEFAULT])
        AC_CHECK_HEADERS([openssl/err.h],,, [AC_INCLUDES_DEFAULT])
        AC_CHECK_HEADERS([openssl/rand.h],,, [AC_INCLUDES_DEFAULT])
-       AC_CHECK_FUNCS([HMAC_CTX_reset HMAC_CTX_new])
+       AC_CHECK_FUNCS([HMAC_CTX_reset HMAC_CTX_new EVP_cleanup 
ERR_load_crypto_strings OPENSSL_init_crypto])
+
+       BAKLIBS="$LIBS"
+       LIBS="-lssl $LIBS"
+       AC_CHECK_FUNCS([OPENSSL_init_ssl])
+       LIBS="$BAKLIBS"
+
 else
        AC_MSG_WARN([No SSL, therefore remote-control is disabled])
 fi
@@ -904,6 +909,15 @@ case "$enable_mmap" in
                 ;;
 esac
 
+AC_ARG_ENABLE(radix-tree, AC_HELP_STRING([--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.]))
+case "$enable_radix_tree" in
+        no)
+       ;;
+       yes|*)
+       AC_DEFINE_UNQUOTED([USE_RADIX_TREE], [], [Define this to configure to 
use the radix tree.])
+       ;;
+esac
+
 AH_BOTTOM([
 /* define before includes as it specifies what standard to use. */
 #if (defined(HAVE_PSELECT) && !defined (HAVE_PSELECT_PROTO)) \
diff --git difffile.c difffile.c
index b2325c5..6890a31 100644
--- difffile.c
+++ difffile.c
@@ -372,14 +372,14 @@ debug_find_rr_num(rrset_type* rrset, uint16_t type, 
uint16_t klass,
                if (rrset->rrs[i].type != type) {
                        log_msg(LOG_WARNING, "diff: RR <%s, %s> does not match "
                                "RR num %d type %s",
-                               dname_to_string(rrset->rrs[i].owner->dname,0),
+                               
dname_to_string(domain_dname(rrset->rrs[i].owner),0),
                                rrtype_to_string(type), i,
                                rrtype_to_string(rrset->rrs[i].type));
                }
                if (rrset->rrs[i].klass != klass) {
                        log_msg(LOG_WARNING, "diff: RR <%s, %s> class %d "
                                "does not match RR num %d class %d",
-                               dname_to_string(rrset->rrs[i].owner->dname,0),
+                               
dname_to_string(domain_dname(rrset->rrs[i].owner),0),
                                rrtype_to_string(type),
                                klass, i,
                                rrset->rrs[i].klass);
@@ -387,7 +387,7 @@ debug_find_rr_num(rrset_type* rrset, uint16_t type, 
uint16_t klass,
                if (rrset->rrs[i].rdata_count != rdata_num) {
                        log_msg(LOG_WARNING, "diff: RR <%s, %s> rdlen %u "
                                "does not match RR num %d rdlen %d",
-                               dname_to_string(rrset->rrs[i].owner->dname,0),
+                               
dname_to_string(domain_dname(rrset->rrs[i].owner),0),
                                rrtype_to_string(type),
                                (unsigned) rdata_num, i,
                                (unsigned) rrset->rrs[i].rdata_count);
@@ -396,7 +396,7 @@ debug_find_rr_num(rrset_type* rrset, uint16_t type, 
uint16_t klass,
                        &rd, &reason)) {
                        log_msg(LOG_WARNING, "diff: RR <%s, %s> rdata element "
                                "%d differs from RR num %d rdata (%s)",
-                               dname_to_string(rrset->rrs[i].owner->dname,0),
+                               
dname_to_string(domain_dname(rrset->rrs[i].owner),0),
                                rrtype_to_string(type),
                                rd, i, reason);
                }
@@ -1299,9 +1299,9 @@ apply_ixfr_for_zone(nsd_type* nsd, zone_type* zonedb, 
FILE* in,
        }
 
        /* has been read in completely */
-       if(strcmp(zone_buf, dname_to_string(zonedb->apex->dname,0)) != 0) {
+       if(strcmp(zone_buf, domain_to_string(zonedb->apex)) != 0) {
                log_msg(LOG_ERR, "file %s does not match task %s",
-                       zone_buf, dname_to_string(zonedb->apex->dname,0));
+                       zone_buf, domain_to_string(zonedb->apex));
                return 0;
        }
        if(!committed) {
@@ -1321,7 +1321,7 @@ apply_ixfr_for_zone(nsd_type* nsd, zone_type* zonedb, 
FILE* in,
        if(committed)
        {
                int is_axfr=0, delete_mode=0, rr_count=0, softfail=0;
-               const dname_type* apex = zonedb->apex->dname;
+               const dname_type* apex = domain_dname_const(zonedb->apex);
                udb_ptr z;
 
                DEBUG(DEBUG_XFRD,1, (LOG_INFO, "processing xfr: %s", zone_buf));
diff --git dns.c dns.c
index 037cd4c..c50fbe7 100644
--- dns.c
+++ dns.c
@@ -297,9 +297,10 @@ static rrtype_descriptor_type 
rrtype_descriptors[(RRTYPE_DESCRIPTORS_LENGTH+1)]
          { RDATA_WF_SHORT, RDATA_WF_BYTE, RDATA_WF_BYTE, RDATA_WF_BINARY },
          { RDATA_ZF_SHORT, RDATA_ZF_BYTE, RDATA_ZF_ALGORITHM,
            RDATA_ZF_BASE64 } },
-       /* 61 */
-       { 61, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } },
-       /* 62 */
+       /* 61 - OPENPGPKEY */
+       { TYPE_OPENPGPKEY, "OPENPGPKEY", T_OPENPGPKEY, 1, 1,
+         { RDATA_WF_BINARY }, { RDATA_ZF_BASE64 } },
+       /* 62 - CSYNC */
        { TYPE_CSYNC, "CSYNC", T_CSYNC, 3, 3, { RDATA_WF_LONG, RDATA_WF_SHORT,
         RDATA_WF_BINARY }, { RDATA_ZF_LONG, RDATA_ZF_SHORT, RDATA_ZF_NSEC } },
        /* 63 */
diff --git dns.h dns.h
index 810cd70..5fc3504 100644
--- dns.h
+++ dns.h
@@ -138,6 +138,7 @@ typedef enum nsd_rc nsd_rc_type;
 #define TYPE_TLSA      52      /* RFC 6698 */
 #define TYPE_CDS       59      /* RFC 7344 */
 #define TYPE_CDNSKEY   60      /* RFC 7344 */
+#define TYPE_OPENPGPKEY 61     /* RFC 7929 */
 #define TYPE_CSYNC     62      /* RFC 7477 */
 
 #define TYPE_SPF        99      /* RFC 4408 */
diff --git edns.c edns.c
index d37e624..72a38d0 100644
--- edns.c
+++ edns.c
@@ -14,6 +14,8 @@
 
 #include "dns.h"
 #include "edns.h"
+#include "nsd.h"
+#include "query.h"
 
 void
 edns_init_data(edns_data_type *data, uint16_t max_length)
@@ -53,12 +55,42 @@ edns_init_record(edns_record_type *edns)
        edns->status = EDNS_NOT_PRESENT;
        edns->position = 0;
        edns->maxlen = 0;
+       edns->opt_reserved_space = 0;
        edns->dnssec_ok = 0;
        edns->nsid = 0;
 }
 
+/** handle a single edns option in the query */
+static int
+edns_handle_option(uint16_t optcode, uint16_t optlen, buffer_type* packet,
+       edns_record_type* edns, struct query* query, nsd_type* nsd)
+{
+       (void) query; /* in case edns options need the query structure */
+       /* handle opt code and read the optlen bytes from the packet */
+       switch(optcode) {
+       case NSID_CODE:
+               /* is NSID enabled? */
+               if(nsd->nsid_len > 0) {
+                       edns->nsid = 1;
+                       /* we have to check optlen, and move the buffer along */
+                       buffer_skip(packet, optlen);
+                       /* in the reply we need space for 
optcode+optlen+nsid_bytes */
+                       edns->opt_reserved_space += OPT_HDR + nsd->nsid_len;
+               } else {
+                       /* ignore option */
+                       buffer_skip(packet, optlen);
+               }
+               break;
+       default:
+               buffer_skip(packet, optlen);
+               break;
+       }
+       return 1;
+}
+
 int
-edns_parse_record(edns_record_type *edns, buffer_type *packet)
+edns_parse_record(edns_record_type *edns, buffer_type *packet,
+       query_type* query, nsd_type* nsd)
 {
        /* OPT record type... */
        uint8_t  opt_owner;
@@ -67,7 +99,6 @@ edns_parse_record(edns_record_type *edns, buffer_type *packet)
        uint8_t  opt_version;
        uint16_t opt_flags;
        uint16_t opt_rdlen;
-       uint16_t opt_nsid;
 
        edns->position = buffer_position(packet);
 
@@ -97,13 +128,19 @@ edns_parse_record(edns_record_type *edns, buffer_type 
*packet)
        if (opt_rdlen > 0) {
                if(!buffer_available(packet, opt_rdlen))
                        return 0;
-               if(opt_rdlen < 4)
+               /* there is more to come, read opt code */
+               while(opt_rdlen >= 4) {
+                       uint16_t optcode = buffer_read_u16(packet);
+                       uint16_t optlen = buffer_read_u16(packet);
+                       if(opt_rdlen < 4+optlen)
+                               return 0; /* opt too long, formerr */
+                       opt_rdlen -= (4+optlen);
+                       if(!edns_handle_option(optcode, optlen, packet,
+                               edns, query, nsd))
+                               return 0;
+               }
+               if(opt_rdlen != 0)
                        return 0;
-               /* there is more to come, read opt code
-                * should be NSID - there are no others */
-               opt_nsid = buffer_read_u16(packet);
-               edns->nsid = (opt_nsid == NSID_CODE);
-               /* extra check for the value */
        }
 
        edns->status = EDNS_OK;
@@ -116,5 +153,5 @@ size_t
 edns_reserved_space(edns_record_type *edns)
 {
        /* MIEK; when a pkt is too large?? */
-       return edns->status == EDNS_NOT_PRESENT ? 0 : (OPT_LEN + OPT_RDATA);
+       return edns->status == EDNS_NOT_PRESENT ? 0 : (OPT_LEN + OPT_RDATA + 
edns->opt_reserved_space);
 }
diff --git edns.h edns.h
index b8643e9..9325beb 100644
--- edns.h
+++ edns.h
@@ -11,6 +11,8 @@
 #define _EDNS_H_
 
 #include "buffer.h"
+struct nsd;
+struct query;
 
 #define OPT_LEN 9U                      /* Length of the NSD EDNS response 
record minus 2 */
 #define OPT_RDATA 2                     /* holds the rdata length comes after 
OPT_LEN */
@@ -42,6 +44,7 @@ struct edns_record
        edns_status_type status;
        size_t           position;
        size_t           maxlen;
+       size_t           opt_reserved_space;
        int              dnssec_ok;
        int              nsid;
 };
@@ -49,7 +52,8 @@ typedef struct edns_record edns_record_type;
 
 void edns_init_data(edns_data_type *data, uint16_t max_length);
 void edns_init_record(edns_record_type *data);
-int edns_parse_record(edns_record_type *data, buffer_type *packet);
+int edns_parse_record(edns_record_type *data, buffer_type *packet,
+       struct query* q, struct nsd* nsd);
 
 /*
  * The amount of space to reserve in the response for the EDNS data
diff --git namedb.c namedb.c
index dbe8efd..fd381e9 100644
--- namedb.c
+++ namedb.c
@@ -33,7 +33,12 @@ allocate_domain_info(domain_table_type* table,
 
        result = (domain_type *) region_alloc(table->region,
                                              sizeof(domain_type));
-       result->dname = dname_partial_copy(
+#ifdef USE_RADIX_TREE
+       result->dname 
+#else
+       result->node.key
+#endif
+               = dname_partial_copy(
                table->region, dname, domain_dname(parent)->label_count + 1);
        result->parent = parent;
        result->wildcard_child_closest_match = result;
@@ -252,9 +257,13 @@ do_deldomain(namedb_type* db, domain_type* domain)
                        domain_previous_existing_child(domain);
 
        /* actual removal */
+#ifdef USE_RADIX_TREE
        radix_delete(db->domains->nametree, domain->rnode);
-       region_recycle(db->domains->region, (dname_type*)domain->dname,
-               dname_total_size(domain->dname));
+#else
+       rbtree_delete(db->domains->names_to_domains, domain->node.key);
+#endif
+       region_recycle(db->domains->region, domain_dname(domain),
+               dname_total_size(domain_dname(domain)));
        region_recycle(db->domains->region, domain, sizeof(domain_type));
 }
 
@@ -313,7 +322,12 @@ domain_table_create(region_type* region)
        origin = dname_make(region, (uint8_t *) "", 0);
 
        root = (domain_type *) region_alloc(region, sizeof(domain_type));
-       root->dname = origin;
+#ifdef USE_RADIX_TREE
+       root->dname
+#else
+       root->node.key
+#endif
+               = origin;
        root->parent = NULL;
        root->wildcard_child_closest_match = root;
        root->rrsets = NULL;
@@ -330,9 +344,15 @@ domain_table_create(region_type* region)
        result = (domain_table_type *) region_alloc(region,
                                                    sizeof(domain_table_type));
        result->region = region;
+#ifdef USE_RADIX_TREE
        result->nametree = radix_tree_create(region);
        root->rnode = radname_insert(result->nametree, dname_name(root->dname),
                root->dname->name_size, root);
+#else
+       result->names_to_domains = rbtree_create(
+               region, (int (*)(const void *, const void *)) dname_compare);
+       rbtree_insert(result->names_to_domains, (rbnode_t *) root);
+#endif
 
        result->root = root;
        result->numlist_last = root;
@@ -357,9 +377,13 @@ domain_table_search(domain_table_type *table,
        assert(closest_match);
        assert(closest_encloser);
 
+#ifdef USE_RADIX_TREE
        exact = radname_find_less_equal(table->nametree, dname_name(dname),
                dname->name_size, (struct radnode**)closest_match);
        *closest_match = (domain_type*)((*(struct 
radnode**)closest_match)->elem);
+#else
+       exact = rbtree_find_less_equal(table->names_to_domains, dname, 
(rbnode_t **) closest_match);
+#endif
        assert(*closest_match);
 
        *closest_encloser = *closest_match;
@@ -416,9 +440,13 @@ domain_table_insert(domain_table_type* table,
                        result = allocate_domain_info(table,
                                                      dname,
                                                      closest_encloser);
+#ifdef USE_RADIX_TREE
                        result->rnode = radname_insert(table->nametree,
                                dname_name(result->dname),
                                result->dname->name_size, result);
+#else
+                       rbtree_insert(table->names_to_domains, (rbnode_t *) 
result);
+#endif
 
                        /*
                         * If the newly added domain name is larger
diff --git namedb.h namedb.h
index e5cf36c..d8cefeb 100644
--- namedb.h
+++ namedb.h
@@ -37,7 +37,11 @@ typedef struct namedb namedb_type;
 struct domain_table
 {
        region_type* region;
+#ifdef USE_RADIX_TREE
        struct radtree *nametree;
+#else
+       rbtree_t      *names_to_domains;
+#endif
        domain_type* root;
        /* ptr to biggest domain.number and last in list.
         * the root is the lowest and first in the list. */
@@ -86,8 +90,12 @@ struct nsec3_domain_data {
 
 struct domain
 {
+#ifdef USE_RADIX_TREE
        struct radnode* rnode;
        const dname_type* dname;
+#else
+       rbnode_t     node;
+#endif
        domain_type* parent;
        domain_type* wildcard_child_closest_match;
        rrset_type* rrsets;
@@ -190,7 +198,11 @@ int domain_table_search(domain_table_type* table,
 static inline uint32_t
 domain_table_count(domain_table_type* table)
 {
+#ifdef USE_RADIX_TREE
        return table->nametree->count;
+#else
+       return table->names_to_domains->count;
+#endif
 }
 
 /*
@@ -247,24 +259,48 @@ domain_type *domain_previous_existing_child(domain_type* 
domain);
 
 int zone_is_secure(zone_type* zone);
 
-static inline const dname_type *
+static inline dname_type *
 domain_dname(domain_type* domain)
 {
+#ifdef USE_RADIX_TREE
+       return (dname_type *) domain->dname;
+#else
+       return (dname_type *) domain->node.key;
+#endif
+}
+
+static inline const dname_type *
+domain_dname_const(const domain_type* domain)
+{
+#ifdef USE_RADIX_TREE
        return domain->dname;
+#else
+       return (const dname_type *) domain->node.key;
+#endif
 }
 
 static inline domain_type *
 domain_previous(domain_type* domain)
 {
+#ifdef USE_RADIX_TREE
        struct radnode* prev = radix_prev(domain->rnode);
        return prev == NULL ? NULL : (domain_type*)prev->elem;
+#else
+       rbnode_t *prev = rbtree_previous((rbnode_t *) domain);
+       return prev == RBTREE_NULL ? NULL : (domain_type *) prev;
+#endif
 }
 
 static inline domain_type *
 domain_next(domain_type* domain)
 {
+#ifdef USE_RADIX_TREE
        struct radnode* next = radix_next(domain->rnode);
        return next == NULL ? NULL : (domain_type*)next->elem;
+#else
+       rbnode_t *next = rbtree_next((rbnode_t *) domain);
+       return next == RBTREE_NULL ? NULL : (domain_type *) next;
+#endif
 }
 
 /* easy comparison for subdomain, true if d1 is subdomain of d2. */
diff --git nsd-checkconf.c nsd-checkconf.c
index b7afdd1..4559c3a 100644
--- nsd-checkconf.c
+++ nsd-checkconf.c
@@ -320,6 +320,7 @@ config_print_zone(nsd_options_t* opt, const char* k, int s, 
const char *o,
 #ifdef RATELIMIT
                ZONE_GET_RRL(rrl_whitelist, o, zone->pattern);
 #endif
+               ZONE_GET_BIN(multi_master_check, o, zone->pattern);
                printf("Zone option not handled: %s %s\n", z, o);
                exit(1);
        } else if(pat) {
@@ -350,6 +351,7 @@ config_print_zone(nsd_options_t* opt, const char* k, int s, 
const char *o,
 #ifdef RATELIMIT
                ZONE_GET_RRL(rrl_whitelist, o, p);
 #endif
+               ZONE_GET_BIN(multi_master_check, o, p);
                printf("Pattern option not handled: %s %s\n", pat, o);
                exit(1);
        } else {
@@ -437,6 +439,8 @@ static void print_zone_content_elems(pattern_options_t* pat)
 #endif
        print_acl("allow-notify:", pat->allow_notify);
        print_acl("request-xfr:", pat->request_xfr);
+       if(pat->multi_master_check)
+               printf("\tmulti-master-check: %s\n", 
pat->multi_master_check?"yes":"no");
        if(!pat->notify_retry_is_default)
                printf("\tnotify-retry: %d\n", pat->notify_retry);
        print_acl("notify:", pat->notify);
diff --git nsd-control.c nsd-control.c
index 3b7a2c6..0b48283 100644
--- nsd-control.c
+++ nsd-control.c
@@ -367,10 +367,22 @@ int main(int argc, char* argv[])
 #endif
        log_init("nsd-control");
 
+#ifdef HAVE_ERR_LOAD_CRYPTO_STRINGS
        ERR_load_crypto_strings();
+#endif
        ERR_load_SSL_strings();
+#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO)
        OpenSSL_add_all_algorithms();
+#else
+       OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
+               | OPENSSL_INIT_ADD_ALL_DIGESTS
+               | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
+#endif
+#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
        (void)SSL_library_init();
+#else
+       OPENSSL_init_ssl(0, NULL);
+#endif
 
        if(!RAND_status()) {
                 /* try to seed it */
diff --git nsd-mem.c nsd-mem.c
index 05710c4..105b88d 100644
--- nsd-mem.c
+++ nsd-mem.c
@@ -110,7 +110,7 @@ account_zone(struct namedb* db, struct zone_mem* zmem)
                zmem->udb_overhead = (size_t)(db->udb->alloc->disk->stat_alloc -
                        db->udb->alloc->disk->stat_data);
        }
-       zmem->domaincount = db->domains->nametree->count;
+       zmem->domaincount = domain_table_count(db->domains);
 }
 
 static void
diff --git nsd.conf.5.in nsd.conf.5.in
index bcec054..6b2588f 100644
--- nsd.conf.5.in
+++ nsd.conf.5.in
@@ -666,6 +666,11 @@ are logged in the loglines when a subnet is blocked (in 
verbosity 2).
 The RRL classification types are: nxdomain, error, referral, any, rrsig,
 wildcard, nodata, dnskey, positive, all.
 .\" rrlend
+.TP
+.B multi\-master\-check:\fR <yes or no>
+Default no.  If enabled, checks all masters for the last version.  It uses
+the higher version of all the configured masters.  Useful if you have multiple
+masters that have different version numbers served.
 .SS "Key Declarations"
 The 
 .B key: 
@@ -674,9 +679,15 @@ the following attributes.
 .TP
 .B name:\fR <string>
 The key name. Used to refer to this key in the access control list.
+The key name has to be correct for tsig to work.
+This is because the key name is output on the wire.
 .TP
 .B algorithm:\fR <string>
-Authentication algorithm for this key.
+Authentication algorithm for this key.  Such as hmac\-md5, hmac\-sha1,
+hmac\-sha224, hmac\-sha256, hmac\-sha384 and hmac\-sha512.  Can also be
+abbreviated as 'sha1', 'sha256'.  Default is sha256.
+Algorithms are only available when they were compiled in (available in the
+crypto library).
 .TP
 .B secret:\fR <base64 blob>
 The base64 encoded shared secret. It is possible to put the 
@@ -685,6 +696,9 @@ declaration (and base64 blob) into a different file, and 
then to
 .B include:
 that file. In this way the key secret and the rest of the configuration
 file, which may have different security policies, can be split apart.
+The content of the secret is the agreed base64 secret content.  To make it
+up, enter a password (its length must be a multiple of 4 characters, 
A\-Za\-z0\-9), or use
+dev-random output through a base64 encode filter.
 .SH "NSD CONFIGURATION FOR BIND9 HACKERS"
 BIND9 is a name server implementation with its own configuration 
 file format, named.conf(5). BIND9 types zones as 'Master' or 'Slave'. 
diff --git nsd.conf.sample.in nsd.conf.sample.in
index cda7dd0..2f2214c 100644
--- nsd.conf.sample.in
+++ nsd.conf.sample.in
@@ -204,8 +204,8 @@ remote-control:
 # key:
        # The key name is sent to the other party, it must be the same
        #name: "keyname"
-       # algorithm hmac-md5, or hmac-sha1, or hmac-sha256 (if compiled in)
-       #algorithm: hmac-sha256
+       # algorithm hmac-md5, or sha1, sha256, sha224, sha384, sha512
+       #algorithm: sha256
        # secret material, must be the same as the other party uses.
        # base64 encoded random number.
        # e.g. from dd if=/dev/random of=/dev/stdout count=1 bs=32 | base64
@@ -263,6 +263,9 @@ remote-control:
        #min-refresh-time: 0
        #max-retry-time: 1209600
        #min-retry-time: 0
+       # Slave server tries zone transfer to all masters and picks highest
+       # zone version available, for when masters have different versions.
+       #multi-master-check: no
 
        # limit the zone transfer size (in bytes), stops very large transfers
        # 0 is no limits enforced.
diff --git nsec3.c nsec3.c
index bad5af8..777b9f9 100644
--- nsec3.c
+++ nsec3.c
@@ -27,6 +27,8 @@ cmp_hash_tree(const void* x, const void* y)
 {
        const domain_type* a = (const domain_type*)x;
        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);
 }
@@ -37,6 +39,8 @@ cmp_wchash_tree(const void* x, const void* y)
 {
        const domain_type* a = (const domain_type*)x;
        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);
 }
@@ -47,6 +51,8 @@ cmp_dshash_tree(const void* x, const void* y)
 {
        const domain_type* a = (const domain_type*)x;
        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);
 }
@@ -59,9 +65,9 @@ cmp_nsec3_tree(const void* x, const void* y)
        const domain_type* a = (const domain_type*)x;
        const domain_type* b = (const domain_type*)y;
        /* labelcount + 32long label */
-       assert(dname_name(a->dname)[0] == 32);
-       assert(dname_name(b->dname)[0] == 32);
-       return memcmp(dname_name(a->dname), dname_name(b->dname), 33);
+       assert(dname_name(domain_dname_const(a))[0] == 32);
+       assert(dname_name(domain_dname_const(b))[0] == 32);
+       return memcmp(dname_name(domain_dname_const(a)), 
dname_name(domain_dname_const(b)), 33);
 }
 
 void nsec3_zone_trees_create(struct region* region, zone_type* zone)
@@ -438,7 +444,7 @@ nsec3_tree_zone(namedb_type* db, domain_type* d)
                                        rrset_rrtype(rrset) == TYPE_DNSKEY ||
                                        rrset_rrtype(rrset) == TYPE_NSEC3PARAM)
                                        return rrset->zone;
-                       return namedb_find_zone(db, d->dname);
+                       return namedb_find_zone(db, domain_dname(d));
                }
                d = d->parent;
        }
@@ -465,7 +471,11 @@ nsec3_find_cover(zone_type* zone, uint8_t* hash, size_t 
hashlen,
 
        /* nsec3tree is sorted by b32 encoded domain name of the NSEC3 */
        b32_ntop(hash, hashlen, (char*)(n+5), sizeof(n)-5);
+#ifdef USE_RADIX_TREE
        d.dname = (dname_type*)n;
+#else
+       d.node.key = n;
+#endif
        n[0] = 34; /* name_size */
        n[1] = 2; /* label_count */
        n[2] = 0; /* label_offset[0] */
diff --git options.c options.c
index 058ceec..8c1e58a 100644
--- options.c
+++ options.c
@@ -834,6 +834,7 @@ pattern_options_create(region_type* region)
 #ifdef RATELIMIT
        p->rrl_whitelist = 0;
 #endif
+       p->multi_master_check = 0;
        return p;
 }
 
@@ -964,6 +965,7 @@ copy_pat_fixed(region_type* region, pattern_options_t* orig,
 #ifdef RATELIMIT
        orig->rrl_whitelist = p->rrl_whitelist;
 #endif
+       orig->multi_master_check = p->multi_master_check;
 }
 
 void
@@ -1049,6 +1051,7 @@ pattern_options_equal(pattern_options_t* p, 
pattern_options_t* q)
 #ifdef RATELIMIT
        if(p->rrl_whitelist != q->rrl_whitelist) return 0;
 #endif
+       if(!booleq(p->multi_master_check,q->multi_master_check)) return 0;
        if(p->size_limit_xfr != q->size_limit_xfr) return 0;
        return 1;
 }
@@ -1208,6 +1211,7 @@ pattern_options_marshal(struct buffer* b, 
pattern_options_t* p)
        marshal_u8(b, p->max_retry_time_is_default);
        marshal_u32(b, p->min_retry_time);
        marshal_u8(b, p->min_retry_time_is_default);
+       marshal_u8(b, p->multi_master_check);
 }
 
 pattern_options_t*
@@ -1239,6 +1243,7 @@ pattern_options_unmarshal(region_type* r, struct buffer* 
b)
        p->max_retry_time_is_default = unmarshal_u8(b);
        p->min_retry_time = unmarshal_u32(b);
        p->min_retry_time_is_default = unmarshal_u8(b);
+       p->multi_master_check = unmarshal_u8(b);
        return p;
 }
 
@@ -1594,7 +1599,10 @@ acl_key_matches(acl_options_t* acl, struct query* q)
                return 0; /* wrong key name */
        }
        if(tsig_strlowercmp(q->tsig.algorithm->short_name,
-               acl->key_options->algorithm) != 0) {
+               acl->key_options->algorithm) != 0 && (
+               strncmp("hmac-", q->tsig.algorithm->short_name, 5) != 0 ||
+               tsig_strlowercmp(q->tsig.algorithm->short_name+5,
+               acl->key_options->algorithm) != 0) ) {
                DEBUG(DEBUG_XFRD,2, (LOG_ERR, "query tsig wrong algorithm"));
                return 0; /* no such algo */
        }
@@ -1979,6 +1987,8 @@ config_apply_pattern(const char* name)
                pat->provide_xfr);
        append_acl(&a->outgoing_interface, &cfg_parser->
                current_outgoing_interface, pat->outgoing_interface);
+       if(pat->multi_master_check)
+               a->multi_master_check = pat->multi_master_check;
 }
 
 void
diff --git options.h options.h
index e0f749c..d826c03 100644
--- options.h
+++ options.h
@@ -163,6 +163,7 @@ struct pattern_options {
        uint32_t min_retry_time;
        uint8_t min_retry_time_is_default;
        uint64_t size_limit_xfr;
+       uint8_t multi_master_check;
 };
 
 #define PATTERN_IMPLICIT_MARKER "_implicit_"
diff --git query.c query.c
index 7256449..fc2d45e 100644
--- query.c
+++ query.c
@@ -580,7 +580,11 @@ find_covering_nsec(domain_type *closest_match,
        assert(nsec_rrset);
 
        /* loop away temporary created domains. For real ones it is 
&RBTREE_NULL */
+#ifdef USE_RADIX_TREE
        while (closest_match->rnode == NULL)
+#else
+       while (closest_match->node.parent == NULL)
+#endif
                closest_match = closest_match->parent;
        while (closest_match) {
                *nsec_rrset = domain_find_rrset(closest_match, zone, TYPE_NSEC);
@@ -656,8 +660,13 @@ add_additional_rrsets(struct query *query, answer_type 
*answer,
                        domain_type *wildcard_child = 
domain_wildcard_child(match);
                        domain_type *temp = (domain_type *) region_alloc(
                                query->region, sizeof(domain_type));
+#ifdef USE_RADIX_TREE
                        temp->rnode = NULL;
                        temp->dname = additional->dname;
+#else
+                       memcpy(&temp->node, &additional->node, 
sizeof(rbnode_t));
+                       temp->node.parent = NULL;
+#endif
                        temp->number = additional->number;
                        temp->parent = match;
                        temp->wildcard_child_closest_match = temp;
@@ -728,6 +737,10 @@ add_rrset(struct query   *query,
                add_additional_rrsets(query, answer, rrset, 1, 0,
                                      rt_additional_rr_types);
                break;
+       case TYPE_SRV:
+               add_additional_rrsets(query, answer, rrset, 3, 0,
+                                     default_additional_rr_types);
+               break;
        default:
                break;
        }
@@ -764,7 +777,11 @@ query_synthesize_cname(struct query* q, struct answer* 
answer, const dname_type*
                        return 0;
                newdom->is_existing = 1;
                newdom->parent = lastparent;
+#ifdef USE_RADIX_TREE
                newdom->dname
+#else
+               newdom->node.key
+#endif
                        = dname_partial_copy(q->region,
                        from_name, domain_dname(src)->label_count + i + 1);
                if(dname_compare(domain_dname(newdom), q->qname) == 0) {
@@ -787,7 +804,11 @@ query_synthesize_cname(struct query* q, struct answer* 
answer, const dname_type*
                        return 0;
                newdom->is_existing = 0;
                newdom->parent = lastparent;
+#ifdef USE_RADIX_TREE
                newdom->dname
+#else
+               newdom->node.key
+#endif
                        = dname_partial_copy(q->region,
                        to_name, domain_dname(to_closest_encloser)->label_count 
+ i + 1);
                DEBUG(DEBUG_QUERY,2, (LOG_INFO, "created temp domain dest %d. 
%s nr %d", i,
@@ -1088,8 +1109,13 @@ answer_authoritative(struct nsd   *nsd,
 
                match = (domain_type *) region_alloc(q->region,
                                                     sizeof(domain_type));
+#ifdef USE_RADIX_TREE
                match->rnode = NULL;
                match->dname = wildcard_child->dname;
+#else
+               memcpy(&match->node, &wildcard_child->node, sizeof(rbnode_t));
+               match->node.parent = NULL;
+#endif
                match->parent = closest_encloser;
                match->wildcard_child_closest_match = match;
                match->number = domain_number;
@@ -1284,7 +1310,7 @@ answer_query(struct nsd *nsd, struct query *q)
 }
 
 void
-query_prepare_response(query_type *q, nsd_type *nsd)
+query_prepare_response(query_type *q)
 {
        uint16_t flags;
 
@@ -1299,9 +1325,6 @@ query_prepare_response(query_type *q, nsd_type *nsd)
         */
        q->reserved_space = edns_reserved_space(&q->edns);
        q->reserved_space += tsig_reserved_space(&q->tsig);
-       if(q->edns.nsid == 1 && nsd->nsid_len > 0 &&
-               q->edns.status != EDNS_NOT_PRESENT)
-               q->reserved_space += OPT_HDR + nsd->nsid_len;
 
        /* Update the flags.  */
        flags = FLAGS(q->packet);
@@ -1401,7 +1424,7 @@ query_process(query_type *q, nsd_type *nsd)
        }
        /* See if there is an OPT RR. */
        if (arcount > 0) {
-               if (edns_parse_record(&q->edns, q->packet))
+               if (edns_parse_record(&q->edns, q->packet, q, nsd))
                        --arcount;
        }
        /* See if there is a TSIG RR. */
@@ -1440,7 +1463,7 @@ query_process(query_type *q, nsd_type *nsd)
                return query_error(q, NSD_RC_OK);
        }
 
-       query_prepare_response(q, nsd);
+       query_prepare_response(q);
 
        if (q->qclass != CLASS_IN && q->qclass != CLASS_ANY) {
                if (q->qclass == CLASS_CH) {
@@ -1479,17 +1502,20 @@ query_add_optional(query_type *q, nsd_type *nsd)
                if (q->edns.dnssec_ok)  edns->ok[7] = 0x80;
                else                    edns->ok[7] = 0x00;
                buffer_write(q->packet, edns->ok, OPT_LEN);
-               if (nsd->nsid_len > 0 && q->edns.nsid == 1 && buffer_available(
-                       q->packet, OPT_RDATA+OPT_HDR+nsd->nsid_len)) {
-                       /* rdata length */
-                       buffer_write(q->packet, edns->rdata_nsid, OPT_RDATA);
-                       /* nsid opt header */
-                       buffer_write(q->packet, edns->nsid, OPT_HDR);
-                       /* nsid payload */
-                       buffer_write(q->packet, nsd->nsid, nsd->nsid_len);
-               }  else {
+               if(q->edns.opt_reserved_space == 0 || !buffer_available(
+                       q->packet, 2+q->edns.opt_reserved_space)) {
                        /* fill with NULLs */
                        buffer_write(q->packet, edns->rdata_none, OPT_RDATA);
+               } else {
+                       /* rdata length */
+                       buffer_write_u16(q->packet, q->edns.opt_reserved_space);
+                       /* edns options */
+                       if(q->edns.nsid) {
+                               /* nsid opt header */
+                               buffer_write(q->packet, edns->nsid, OPT_HDR);
+                               /* nsid payload */
+                               buffer_write(q->packet, nsd->nsid, 
nsd->nsid_len);
+                       }
                }
                ARCOUNT_SET(q->packet, ARCOUNT(q->packet) + 1);
                STATUP(nsd, edns);
diff --git query.h query.h
index a950de3..f22b722 100644
--- query.h
+++ query.h
@@ -191,7 +191,7 @@ query_state_type query_process(query_type *q, nsd_type 
*nsd);
  * includes the packet header and question section. Space is reserved
  * for the optional EDNS record, if required.
  */
-void query_prepare_response(query_type *q, nsd_type* nsd);
+void query_prepare_response(query_type *q);
 
 /*
  * Add EDNS0 information to the response if required.
diff --git remote.c remote.c
index c0319c4..d961dbf 100644
--- remote.c
+++ remote.c
@@ -237,10 +237,22 @@ daemon_remote_create(nsd_options_t* cfg)
        assert(cfg->control_enable);
 
        /* init SSL library */
+#ifdef HAVE_ERR_LOAD_CRYPTO_STRINGS
        ERR_load_crypto_strings();
+#endif
        ERR_load_SSL_strings();
+#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO)
        OpenSSL_add_all_algorithms();
+#else
+       OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
+               | OPENSSL_INIT_ADD_ALL_DIGESTS
+               | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
+#endif
+#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
        (void)SSL_library_init();
+#else
+       OPENSSL_init_ssl(0, NULL);
+#endif
 
        if(!RAND_status()) {
                /* try to seed it */
diff --git tsig-openssl.c tsig-openssl.c
index 62203dc..f38284e 100644
--- tsig-openssl.c
+++ tsig-openssl.c
@@ -61,7 +61,11 @@ int
 tsig_openssl_init(region_type *region)
 {
        int count = 0;
+#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO)
        OpenSSL_add_all_digests();
+#else
+       OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_DIGESTS, NULL);
+#endif
 
        count += tsig_openssl_init_algorithm(region,
            "md5", "hmac-md5","hmac-md5.sig-alg.reg.int.");
@@ -137,7 +141,9 @@ final(void *context, uint8_t *digest, size_t *size)
 void
 tsig_openssl_finalize()
 {
+#ifdef HAVE_EVP_CLEANUP
        EVP_cleanup();
+#endif
 }
 
 #endif /* defined(HAVE_SSL) */
diff --git tsig.c tsig.c
index 316f477..b58191c 100644
--- tsig.c
+++ tsig.c
@@ -192,6 +192,9 @@ tsig_get_algorithm_by_name(const char *name)
                {
                        return algorithm_entry->algorithm;
                }
+               if(strncmp("hmac-", algorithm_entry->algorithm->short_name, 5) 
== 0 && tsig_strlowercmp(name, algorithm_entry->algorithm->short_name+5) == 0) {
+                       return algorithm_entry->algorithm;
+               }
        }
 
        return NULL;
diff --git xfrd-disk.c xfrd-disk.c
index 654e78e..c724a2c 100644
--- xfrd-disk.c
+++ xfrd-disk.c
@@ -267,14 +267,14 @@ xfrd_read_state(struct xfrd_state* xfrd)
                 * or there is a soa && current time is past refresh point
                 */
                soa_refresh = ntohl(soa_disk_read.refresh);
-               if (soa_refresh > zone->zone_options->pattern->max_refresh_time)
+               if (soa_refresh > 
(time_t)zone->zone_options->pattern->max_refresh_time)
                        soa_refresh = 
zone->zone_options->pattern->max_refresh_time;
-               else if (soa_refresh < 
zone->zone_options->pattern->min_refresh_time)
+               else if (soa_refresh < 
(time_t)zone->zone_options->pattern->min_refresh_time)
                        soa_refresh = 
zone->zone_options->pattern->min_refresh_time;
                if(timeout == 0 || soa_notified_acquired_read != 0 ||
                        (soa_disk_acquired_read != 0 &&
                        (uint32_t)xfrd_time() - soa_disk_acquired_read
-                               > soa_refresh))
+                               > (uint32_t)soa_refresh))
                {
                        zone->state = xfrd_zone_refreshing;
                        xfrd_set_refresh_now(zone);
diff --git xfrd-tcp.c xfrd-tcp.c
index 9bc01d3..a4a7a23 100644
--- xfrd-tcp.c
+++ xfrd-tcp.c
@@ -870,6 +870,11 @@ xfrd_tcp_read(struct xfrd_tcp_pipeline* tp)
                        tp->num_skip++;
                        /* fall through to remove zone from tp */
                case xfrd_packet_transfer:
+                       if(zone->zone_options->pattern->multi_master_check) {
+                               xfrd_tcp_release(xfrd->tcp_set, zone);
+                               xfrd_make_request(zone);
+                               break;
+                       }
                        xfrd_tcp_release(xfrd->tcp_set, zone);
                        assert(zone->round_num == -1);
                        break;
diff --git xfrd.c xfrd.c
index 0eacce7..a0b3444 100644
--- xfrd.c
+++ xfrd.c
@@ -437,6 +437,8 @@ xfrd_init_slave_zone(xfrd_state_t* xfrd, zone_options_t* 
zone_opt)
        xzone->udp_waiting = 0;
        xzone->is_activated = 0;
 
+       xzone->multi_master_first_master = -1;
+       xzone->multi_master_update_check = -1;
        tsig_create_record_custom(&xzone->tsig, NULL, 0, 0, 4);
 
        /* set refreshing anyway, if we have data it may be old */
@@ -703,9 +705,9 @@ xfrd_set_timer_refresh(xfrd_zone_t* zone)
        }
        /* refresh or expire timeout, whichever is earlier */
        set_refresh = ntohl(zone->soa_disk.refresh);
-       if (set_refresh > zone->zone_options->pattern->max_refresh_time)
+       if (set_refresh > (time_t)zone->zone_options->pattern->max_refresh_time)
                set_refresh = zone->zone_options->pattern->max_refresh_time;
-       else if (set_refresh < zone->zone_options->pattern->min_refresh_time)
+       else if (set_refresh < 
(time_t)zone->zone_options->pattern->min_refresh_time)
                set_refresh = zone->zone_options->pattern->min_refresh_time;
        set_refresh += zone->soa_disk_acquired;
        set_expire = zone->soa_disk_acquired + ntohl(zone->soa_disk.expire);
@@ -750,9 +752,9 @@ xfrd_set_timer_retry(xfrd_zone_t* zone)
                zone->soa_disk_acquired + (time_t)ntohl(zone->soa_disk.expire))
        {
                set_retry = ntohl(zone->soa_disk.retry);
-               if(set_retry > zone->zone_options->pattern->max_retry_time)
+               if(set_retry > 
(time_t)zone->zone_options->pattern->max_retry_time)
                        set_retry = zone->zone_options->pattern->max_retry_time;
-               else if(set_retry < zone->zone_options->pattern->min_retry_time)
+               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;
@@ -875,8 +877,31 @@ xfrd_make_request(xfrd_zone_t* zone)
                        DEBUG(DEBUG_XFRD,1, (LOG_INFO,
                                "xfrd zone %s makereq wait_retry, rd %d mr %d 
nx %d",
                                zone->apex_str, zone->round_num, 
zone->master_num, zone->next_master));
+                       zone->multi_master_first_master = -1;
+                       return;
+               }
+       }
+
+       /* multi-master-check */
+       if(zone->zone_options->pattern->multi_master_check) {
+               if(zone->multi_master_first_master == zone->master_num &&
+                       zone->round_num > 0 &&
+                       zone->state != xfrd_zone_expired) {
+                       /* tried all servers and update zone */
+                       if(zone->multi_master_update_check >= 0) {
+                               VERBOSITY(2, (LOG_INFO, "xfrd: multi master "
+                                       "check: zone %s completed transfers",
+                                       zone->apex_str));
+                       }
+                       zone->round_num = -1; /* next try start anew */
+                       zone->multi_master_first_master = -1;
+                       xfrd_set_timer_refresh(zone);
                        return;
                }
+               if(zone->multi_master_first_master < 0) {
+                       zone->multi_master_first_master = zone->master_num;
+                       zone->multi_master_update_check = -1;
+               }
        }
 
        /* cache ixfr_disabled only for XFRD_NO_IXFR_CACHE time */
@@ -1267,6 +1292,11 @@ xfrd_udp_read(xfrd_zone_t* zone)
                        xfrd_tcp_obtain(xfrd->tcp_set, zone);
                        break;
                case xfrd_packet_transfer:
+                       if(zone->zone_options->pattern->multi_master_check) {
+                               xfrd_udp_release(zone);
+                               xfrd_make_request(zone);
+                               break;
+                       }
                case xfrd_packet_newlease:
                        /* nothing more to do */
                        assert(zone->round_num == -1);
@@ -1835,6 +1865,10 @@ xfrd_parse_received_xfr_packet(xfrd_zone_t* zone, 
buffer_type* packet,
                        zone->soa_disk_acquired = xfrd_time();
                        if(zone->soa_nsd.serial == soa->serial)
                                zone->soa_nsd_acquired = xfrd_time();
+                       if(zone->zone_options->pattern->multi_master_check) {
+                               region_destroy(tempregion);
+                               return xfrd_packet_drop;
+                       }
                        xfrd_set_zone_state(zone, xfrd_zone_ok);
                        DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s is ok",
                                zone->apex_str));
@@ -1992,7 +2026,7 @@ xfrd_handle_received_xfr_packet(xfrd_zone_t* zone, 
buffer_type* packet)
            xfrfile_size > zone->zone_options->pattern->size_limit_xfr ) {
             /*     xfrd_unlink_xfrfile(xfrd->nsd, zone->xfrfilenumber);
                     xfrd_set_reload_timeout(); */
-            log_msg(LOG_INFO, "xfrd : transfered zone data was too large 
%llu", (long long unsigned)xfrfile_size);
+            log_msg(LOG_INFO, "xfrd : transferred zone data was too large 
%llu", (long long unsigned)xfrfile_size);
            return xfrd_packet_bad;
        }
        if(res == xfrd_packet_more) {
@@ -2048,6 +2082,11 @@ xfrd_handle_received_xfr_packet(xfrd_zone_t* zone, 
buffer_type* packet)
                DEBUG(DEBUG_XFRD,1, (LOG_INFO,
                        "xfrd: zone %s is waiting for reload",
                        zone->apex_str));
+               if(zone->zone_options->pattern->multi_master_check) {
+                       zone->multi_master_update_check = zone->master_num;
+                       xfrd_set_reload_timeout();
+                       return xfrd_packet_transfer;
+               }
                zone->round_num = -1; /* next try start anew */
                xfrd_set_timer_refresh(zone);
                xfrd_set_reload_timeout();
@@ -2256,8 +2295,17 @@ xfrd_check_failed_updates()
                                                                 "transfer 
(notified zone)",
                                        zone->apex_str, 
(unsigned)ntohl(zone->soa_disk.serial));
                                /* revert the soa; it has not been acquired 
properly */
-                               zone->soa_disk_acquired = 
zone->soa_nsd_acquired;
-                               zone->soa_disk = zone->soa_nsd;
+                               if(zone->soa_disk_acquired == 
zone->soa_nsd_acquired) {
+                                       /* this was the same as served,
+                                        * perform force_axfr , re-download
+                                        * same serial from master */
+                                       zone->soa_disk_acquired = 0;
+                                       zone->soa_nsd_acquired = 0;
+                               } else {
+                                       /* revert soa to the one in server */
+                                       zone->soa_disk_acquired = 
zone->soa_nsd_acquired;
+                                       zone->soa_disk = zone->soa_nsd;
+                               }
                                /* pretend we are notified with disk soa.
                                   This will cause a refetch of the data, and 
reload. */
                                xfrd_handle_incoming_notify(zone, &dumped_soa);
diff --git xfrd.h xfrd.h
index ff903db..24541db 100644
--- xfrd.h
+++ xfrd.h
@@ -217,6 +217,8 @@ struct xfrd_zone {
        tsig_record_type tsig; /* tsig state for IXFR/AXFR */
        uint64_t xfrfilenumber; /* identifier for file to store xfr into,
                                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 */
 };
 
 enum xfrd_packet_result {
diff --git zlexer.lex zlexer.lex
index 90a1df3..a25d7af 100644
--- zlexer.lex
+++ zlexer.lex
@@ -7,6 +7,8 @@
  * See LICENSE for the license.
  *
  */
+/* because flex keeps having sign-unsigned compare problems that are unfixed*/
+#pragma GCC diagnostic ignored "-Wsign-compare"
 
 #include "config.h"
 
diff --git zparser.y zparser.y
index d823478..a2e6fcd 100644
--- zparser.y
+++ zparser.y
@@ -68,7 +68,7 @@ nsec3_add_params(const char* hash_algo_str, const char* 
flag_str,
 %token <type> T_AXFR T_MAILB T_MAILA T_DS T_DLV T_SSHFP T_RRSIG T_NSEC T_DNSKEY
 %token <type> T_SPF T_NSEC3 T_IPSECKEY T_DHCID T_NSEC3PARAM T_TLSA T_URI
 %token <type> T_NID T_L32 T_L64 T_LP T_EUI48 T_EUI64 T_CAA T_CDS T_CDNSKEY
-%token <type> T_CSYNC
+%token <type> T_OPENPGPKEY T_CSYNC
 
 /* other tokens */
 %token        DOLLAR_TTL DOLLAR_ORIGIN NL SP
@@ -633,6 +633,8 @@ type_and_rdata:
     |  T_CDS sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
     |  T_CDNSKEY sp rdata_dnskey
     |  T_CDNSKEY sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+    |  T_OPENPGPKEY sp rdata_openpgpkey
+    |  T_OPENPGPKEY sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
     |  T_CSYNC sp rdata_csync
     |  T_CSYNC sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
     |  T_URI sp rdata_uri
@@ -1053,6 +1055,13 @@ rdata_caa:       STR sp STR sp STR trail
     }
     ;
 
+/* RFC7929 */
+rdata_openpgpkey:      str_sp_seq trail
+    {
+           zadd_rdata_wireformat(zparser_conv_b64(parser->region, $1.str));
+    }
+    ;
+
 /* RFC7477 */
 rdata_csync:   STR sp STR nsec_seq
     {


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

Reply via email to