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 <[email protected]>.
#
@@ -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='[email protected]'
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,[email protected])
+AC_INIT(NSD,4.1.13,[email protected])
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.