diff options
author | Florian Obser <florian@cvs.openbsd.org> | 2016-10-24 09:44:44 +0000 |
---|---|---|
committer | Florian Obser <florian@cvs.openbsd.org> | 2016-10-24 09:44:44 +0000 |
commit | 8315636eb7e20f93c481fa3b3378520aaac549e1 (patch) | |
tree | bc22714375d7ad38b3b9e1036aba37c644d403c3 /usr.sbin/nsd | |
parent | 16b65a12f55b72643d9408b58aa7eaeae4e204e2 (diff) |
Update to 4.1.13
Testing millert, brad and myself.
OK millert@
Diffstat (limited to 'usr.sbin/nsd')
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 { |