summaryrefslogtreecommitdiff
path: root/usr.sbin/nsd
diff options
context:
space:
mode:
authorFlorian Obser <florian@cvs.openbsd.org>2016-10-24 09:44:44 +0000
committerFlorian Obser <florian@cvs.openbsd.org>2016-10-24 09:44:44 +0000
commit8315636eb7e20f93c481fa3b3378520aaac549e1 (patch)
treebc22714375d7ad38b3b9e1036aba37c644d403c3 /usr.sbin/nsd
parent16b65a12f55b72643d9408b58aa7eaeae4e204e2 (diff)
Update to 4.1.13
Testing millert, brad and myself. OK millert@
Diffstat (limited to 'usr.sbin/nsd')
-rw-r--r--usr.sbin/nsd/Makefile.in2
-rw-r--r--usr.sbin/nsd/axfr.c2
-rw-r--r--usr.sbin/nsd/configlexer.lex3
-rw-r--r--usr.sbin/nsd/configparser.y13
-rw-r--r--usr.sbin/nsd/configure.ac20
-rw-r--r--usr.sbin/nsd/difffile.c14
-rw-r--r--usr.sbin/nsd/dns.c7
-rw-r--r--usr.sbin/nsd/dns.h1
-rw-r--r--usr.sbin/nsd/edns.c55
-rw-r--r--usr.sbin/nsd/edns.h7
-rw-r--r--usr.sbin/nsd/namedb.c36
-rw-r--r--usr.sbin/nsd/namedb.h38
-rw-r--r--usr.sbin/nsd/nsd-checkconf.c4
-rw-r--r--usr.sbin/nsd/nsd-control.c12
-rw-r--r--usr.sbin/nsd/nsd-mem.c31
-rw-r--r--usr.sbin/nsd/nsd.conf.5.in16
-rw-r--r--usr.sbin/nsd/nsd.conf.sample.in7
-rw-r--r--usr.sbin/nsd/nsec3.c18
-rw-r--r--usr.sbin/nsd/options.c12
-rw-r--r--usr.sbin/nsd/options.h1
-rw-r--r--usr.sbin/nsd/query.c56
-rw-r--r--usr.sbin/nsd/query.h23
-rw-r--r--usr.sbin/nsd/remote.c12
-rw-r--r--usr.sbin/nsd/tsig-openssl.c6
-rw-r--r--usr.sbin/nsd/tsig.c3
-rw-r--r--usr.sbin/nsd/xfrd-disk.c6
-rw-r--r--usr.sbin/nsd/xfrd-tcp.c5
-rw-r--r--usr.sbin/nsd/xfrd.c62
-rw-r--r--usr.sbin/nsd/xfrd.h2
-rw-r--r--usr.sbin/nsd/zlexer.lex2
-rw-r--r--usr.sbin/nsd/zparser.y11
31 files changed, 397 insertions, 90 deletions
diff --git a/usr.sbin/nsd/Makefile.in b/usr.sbin/nsd/Makefile.in
index 3fbd01b6814..3391cd0d4b2 100644
--- a/usr.sbin/nsd/Makefile.in
+++ b/usr.sbin/nsd/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 a/usr.sbin/nsd/axfr.c b/usr.sbin/nsd/axfr.c
index 09eb0823cb4..92d4f2fc0c1 100644
--- a/usr.sbin/nsd/axfr.c
+++ b/usr.sbin/nsd/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 a/usr.sbin/nsd/configlexer.lex b/usr.sbin/nsd/configlexer.lex
index d53635298b1..0ce80bd8bb4 100644
--- a/usr.sbin/nsd/configlexer.lex
+++ b/usr.sbin/nsd/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 a/usr.sbin/nsd/configparser.y b/usr.sbin/nsd/configparser.y
index 908966588f6..204d236b653 100644
--- a/usr.sbin/nsd/configparser.y
+++ b/usr.sbin/nsd/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 a/usr.sbin/nsd/configure.ac b/usr.sbin/nsd/configure.ac
index 75a44c54fe6..e2aca4d531e 100644
--- a/usr.sbin/nsd/configure.ac
+++ b/usr.sbin/nsd/configure.ac
@@ -4,7 +4,7 @@ dnl
sinclude(acx_nlnetlabs.m4)
-AC_INIT(NSD,4.1.12,nsd-bugs@nlnetlabs.nl)
+AC_INIT(NSD,4.1.13,nsd-bugs@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 a/usr.sbin/nsd/difffile.c b/usr.sbin/nsd/difffile.c
index b2325c5b81b..6890a31db9d 100644
--- a/usr.sbin/nsd/difffile.c
+++ b/usr.sbin/nsd/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 a/usr.sbin/nsd/dns.c b/usr.sbin/nsd/dns.c
index 037cd4cbb6a..c50fbe78bfe 100644
--- a/usr.sbin/nsd/dns.c
+++ b/usr.sbin/nsd/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 a/usr.sbin/nsd/dns.h b/usr.sbin/nsd/dns.h
index 810cd7010b3..5fc35046c40 100644
--- a/usr.sbin/nsd/dns.h
+++ b/usr.sbin/nsd/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 a/usr.sbin/nsd/edns.c b/usr.sbin/nsd/edns.c
index d37e624a716..72a38d0a300 100644
--- a/usr.sbin/nsd/edns.c
+++ b/usr.sbin/nsd/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 a/usr.sbin/nsd/edns.h b/usr.sbin/nsd/edns.h
index 79e26a20b4b..9325beb244c 100644
--- a/usr.sbin/nsd/edns.h
+++ b/usr.sbin/nsd/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 */
@@ -32,6 +34,7 @@ enum edns_status
{
EDNS_NOT_PRESENT,
EDNS_OK,
+ /* EDNS states may be extended in the future */
EDNS_ERROR
};
typedef enum edns_status edns_status_type;
@@ -41,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;
};
@@ -48,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 a/usr.sbin/nsd/namedb.c b/usr.sbin/nsd/namedb.c
index dbe8efd89ad..fd381e98d32 100644
--- a/usr.sbin/nsd/namedb.c
+++ b/usr.sbin/nsd/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 a/usr.sbin/nsd/namedb.h b/usr.sbin/nsd/namedb.h
index e5cf36c0159..d8cefeb1af5 100644
--- a/usr.sbin/nsd/namedb.h
+++ b/usr.sbin/nsd/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 a/usr.sbin/nsd/nsd-checkconf.c b/usr.sbin/nsd/nsd-checkconf.c
index b7afdd1b916..4559c3ac068 100644
--- a/usr.sbin/nsd/nsd-checkconf.c
+++ b/usr.sbin/nsd/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 a/usr.sbin/nsd/nsd-control.c b/usr.sbin/nsd/nsd-control.c
index 3b7a2c69240..0b482839b47 100644
--- a/usr.sbin/nsd/nsd-control.c
+++ b/usr.sbin/nsd/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 a/usr.sbin/nsd/nsd-mem.c b/usr.sbin/nsd/nsd-mem.c
index 0981eafef73..105b88dad14 100644
--- a/usr.sbin/nsd/nsd-mem.c
+++ b/usr.sbin/nsd/nsd-mem.c
@@ -26,6 +26,7 @@
#include "util.h"
static void error(const char *format, ...) ATTR_FORMAT(printf, 1, 2);
+struct nsd nsd;
/*
* Print the help text.
@@ -104,10 +105,12 @@ account_zone(struct namedb* db, struct zone_mem* zmem)
{
zmem->data = region_get_mem(db->region);
zmem->data_unused = region_get_mem_unused(db->region);
- zmem->udb_data = (size_t)db->udb->alloc->disk->stat_data;
- zmem->udb_overhead = (size_t)(db->udb->alloc->disk->stat_alloc -
- db->udb->alloc->disk->stat_data);
- zmem->domaincount = db->domains->nametree->count;
+ if(db->udb) {
+ zmem->udb_data = (size_t)db->udb->alloc->disk->stat_data;
+ zmem->udb_overhead = (size_t)(db->udb->alloc->disk->stat_alloc -
+ db->udb->alloc->disk->stat_data);
+ }
+ zmem->domaincount = domain_table_count(db->domains);
}
static void
@@ -192,6 +195,7 @@ static void
check_zone_mem(const char* tf, const char* df, zone_options_t* zo,
nsd_options_t* opt, struct tot_mem* totmem)
{
+ struct nsd nsd;
struct namedb* db;
const dname_type* dname = (const dname_type*)zo->node.key;
zone_type* zone;
@@ -203,14 +207,15 @@ check_zone_mem(const char* tf, const char* df, zone_options_t* zo,
/* init*/
memset(&zmem, 0, sizeof(zmem));
- db = namedb_open(df, opt);
+ memset(&nsd, 0, sizeof(nsd));
+ nsd.db = db = namedb_open(df, opt);
if(!db) error("cannot open %s: %s", df, strerror(errno));
zone = namedb_zone_create(db, dname, zo);
taskudb = udb_base_create_new(tf, &namedb_walkfunc, NULL);
udb_ptr_init(&last_task, taskudb);
/* read the zone */
- namedb_read_zonefile(db, zone, taskudb, &last_task);
+ namedb_read_zonefile(&nsd, zone, taskudb, &last_task);
/* account the memory for this zone */
account_zone(db, &zmem);
@@ -237,7 +242,9 @@ check_mem(nsd_options_t* opt)
char df[512];
memset(&totmem, 0, sizeof(totmem));
snprintf(tf, sizeof(tf), "./nsd-mem-task-%u.db", (unsigned)getpid());
- snprintf(df, sizeof(df), "./nsd-mem-db-%u.db", (unsigned)getpid());
+ if(opt->database == NULL || opt->database[0] == 0)
+ df[0] = 0;
+ else snprintf(df, sizeof(df), "./nsd-mem-db-%u.db", (unsigned)getpid());
/* read all zones and account memory */
RBTREE_FOR(zo, zone_options_t*, opt->zone_options) {
@@ -250,10 +257,12 @@ check_mem(nsd_options_t* opt)
print_tot_mem(&totmem);
/* final advice */
- printf("\nFinal advice estimate:\n");
- printf("(The partial mmap causes reload&AXFR to take longer(disk access))\n");
- pretty_mem(totmem.ram + totmem.disk, "data and big mmap");
- pretty_mem(totmem.ram + totmem.disk/6, "data and partial mmap");
+ if(opt->database != NULL && opt->database[0] != 0) {
+ printf("\nFinal advice estimate:\n");
+ printf("(The partial mmap causes reload&AXFR to take longer(disk access))\n");
+ pretty_mem(totmem.ram + totmem.disk, "data and big mmap");
+ pretty_mem(totmem.ram + totmem.disk/6, "data and partial mmap");
+ }
}
/* dummy functions to link */
diff --git a/usr.sbin/nsd/nsd.conf.5.in b/usr.sbin/nsd/nsd.conf.5.in
index bcec054af2c..6b2588f19cc 100644
--- a/usr.sbin/nsd/nsd.conf.5.in
+++ b/usr.sbin/nsd/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 a/usr.sbin/nsd/nsd.conf.sample.in b/usr.sbin/nsd/nsd.conf.sample.in
index cda7dd084ba..2f2214c9570 100644
--- a/usr.sbin/nsd/nsd.conf.sample.in
+++ b/usr.sbin/nsd/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 a/usr.sbin/nsd/nsec3.c b/usr.sbin/nsd/nsec3.c
index bad5af8a1bc..777b9f941e4 100644
--- a/usr.sbin/nsd/nsec3.c
+++ b/usr.sbin/nsd/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 a/usr.sbin/nsd/options.c b/usr.sbin/nsd/options.c
index 058ceeccab4..8c1e58a3b90 100644
--- a/usr.sbin/nsd/options.c
+++ b/usr.sbin/nsd/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 a/usr.sbin/nsd/options.h b/usr.sbin/nsd/options.h
index e0f749cb972..d826c03fd7c 100644
--- a/usr.sbin/nsd/options.h
+++ b/usr.sbin/nsd/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 a/usr.sbin/nsd/query.c b/usr.sbin/nsd/query.c
index 7256449d38d..fc2d45e9b86 100644
--- a/usr.sbin/nsd/query.c
+++ b/usr.sbin/nsd/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 a/usr.sbin/nsd/query.h b/usr.sbin/nsd/query.h
index 89ea960570e..f22b7229e81 100644
--- a/usr.sbin/nsd/query.h
+++ b/usr.sbin/nsd/query.h
@@ -56,12 +56,10 @@ struct query {
/* EDNS information provided by the client. */
edns_record_type edns;
-#ifdef TSIG
/* TSIG record information and running hash for query-response */
tsig_record_type tsig;
/* tsig actions can be overridden, for axfr transfer. */
int tsig_prepare_it, tsig_update_it, tsig_sign_it;
-#endif /* TSIG */
int tcp;
uint16_t tcplen;
@@ -78,9 +76,6 @@ struct query {
/* The zone used to answer the query. */
zone_type *zone;
- /* The domain used to answer the query. */
- domain_type *domain;
-
/* The delegation domain, if any. */
domain_type *delegation_domain;
@@ -108,10 +103,10 @@ struct query {
* query name when generated from a wildcard record.
*/
uint16_t *compressed_dname_offsets;
- uint32_t compressed_dname_offsets_size;
+ size_t compressed_dname_offsets_size;
/* number of temporary domains used for the query */
- uint32_t number_temporary_domains;
+ size_t number_temporary_domains;
/*
* Used for AXFR processing.
@@ -121,6 +116,11 @@ struct query {
domain_type *axfr_current_domain;
rrset_type *axfr_current_rrset;
uint16_t axfr_current_rr;
+
+#ifdef RATELIMIT
+ /* if we encountered a wildcard, its domain */
+ domain_type *wildcard_domain;
+#endif
};
@@ -157,7 +157,7 @@ void query_clear_dname_offsets(struct query *query, size_t max_offset);
* Clear the compression tables.
*/
void query_clear_compression_tables(struct query *query);
-
+
/*
* Enter the specified domain into the compression table starting at
* the specified offset.
@@ -172,7 +172,7 @@ void query_add_compression_domain(struct query *query,
*/
query_type *query_create(region_type *region,
uint16_t *compressed_dname_offsets,
- uint32_t compressed_dname_size);
+ size_t compressed_dname_size);
/*
* Reset a query structure so it is ready for receiving and processing
@@ -209,9 +209,4 @@ query_overflow(query_type *q)
{
return buffer_position(q->packet) > (q->maxlen - q->reserved_space);
}
-static inline int
-query_overflow_nsid(query_type *q, uint16_t nsid_len)
-{
- return buffer_position(q->packet) > (q->maxlen - q->reserved_space - nsid_len);
-}
#endif /* _QUERY_H_ */
diff --git a/usr.sbin/nsd/remote.c b/usr.sbin/nsd/remote.c
index c0319c4bc6f..d961dbf4146 100644
--- a/usr.sbin/nsd/remote.c
+++ b/usr.sbin/nsd/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 a/usr.sbin/nsd/tsig-openssl.c b/usr.sbin/nsd/tsig-openssl.c
index 62203dc3525..f38284edfa5 100644
--- a/usr.sbin/nsd/tsig-openssl.c
+++ b/usr.sbin/nsd/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 a/usr.sbin/nsd/tsig.c b/usr.sbin/nsd/tsig.c
index 316f477894d..b58191ce9b8 100644
--- a/usr.sbin/nsd/tsig.c
+++ b/usr.sbin/nsd/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 a/usr.sbin/nsd/xfrd-disk.c b/usr.sbin/nsd/xfrd-disk.c
index 654e78edfd4..c724a2c9cc6 100644
--- a/usr.sbin/nsd/xfrd-disk.c
+++ b/usr.sbin/nsd/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 a/usr.sbin/nsd/xfrd-tcp.c b/usr.sbin/nsd/xfrd-tcp.c
index 9bc01d3ed72..a4a7a23fe29 100644
--- a/usr.sbin/nsd/xfrd-tcp.c
+++ b/usr.sbin/nsd/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 a/usr.sbin/nsd/xfrd.c b/usr.sbin/nsd/xfrd.c
index 0eacce799d3..a0b34446ae5 100644
--- a/usr.sbin/nsd/xfrd.c
+++ b/usr.sbin/nsd/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 a/usr.sbin/nsd/xfrd.h b/usr.sbin/nsd/xfrd.h
index ff903dbacc0..24541dbfc44 100644
--- a/usr.sbin/nsd/xfrd.h
+++ b/usr.sbin/nsd/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 a/usr.sbin/nsd/zlexer.lex b/usr.sbin/nsd/zlexer.lex
index 90a1df3741c..a25d7af626b 100644
--- a/usr.sbin/nsd/zlexer.lex
+++ b/usr.sbin/nsd/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 a/usr.sbin/nsd/zparser.y b/usr.sbin/nsd/zparser.y
index d82347893bc..a2e6fcd7a9d 100644
--- a/usr.sbin/nsd/zparser.y
+++ b/usr.sbin/nsd/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
{