diff options
Diffstat (limited to 'usr.sbin/nsd')
-rw-r--r-- | usr.sbin/nsd/Makefile.in | 6 | ||||
-rw-r--r-- | usr.sbin/nsd/axfr.c | 4 | ||||
-rw-r--r-- | usr.sbin/nsd/compat/b64_pton.c | 8 | ||||
-rw-r--r-- | usr.sbin/nsd/config.h.in | 15 | ||||
-rw-r--r-- | usr.sbin/nsd/configparser.y | 24 | ||||
-rw-r--r-- | usr.sbin/nsd/configure | 70 | ||||
-rw-r--r-- | usr.sbin/nsd/configure.ac | 26 | ||||
-rw-r--r-- | usr.sbin/nsd/difffile.c | 15 | ||||
-rw-r--r-- | usr.sbin/nsd/dname.c | 7 | ||||
-rw-r--r-- | usr.sbin/nsd/namedb.c | 13 | ||||
-rw-r--r-- | usr.sbin/nsd/namedb.h | 10 | ||||
-rw-r--r-- | usr.sbin/nsd/nsd-checkconf.8.in | 2 | ||||
-rw-r--r-- | usr.sbin/nsd/nsd-checkconf.c | 2 | ||||
-rw-r--r-- | usr.sbin/nsd/nsd-control.8.in | 10 | ||||
-rw-r--r-- | usr.sbin/nsd/nsd.c | 8 | ||||
-rw-r--r-- | usr.sbin/nsd/nsd.conf.5.in | 12 | ||||
-rw-r--r-- | usr.sbin/nsd/query.c | 60 | ||||
-rw-r--r-- | usr.sbin/nsd/rdata.c | 6 | ||||
-rw-r--r-- | usr.sbin/nsd/region-allocator.c | 48 | ||||
-rw-r--r-- | usr.sbin/nsd/remote.c | 105 | ||||
-rw-r--r-- | usr.sbin/nsd/rrl.c | 5 | ||||
-rw-r--r-- | usr.sbin/nsd/server.c | 39 | ||||
-rw-r--r-- | usr.sbin/nsd/udb.c | 9 | ||||
-rw-r--r-- | usr.sbin/nsd/util.c | 23 | ||||
-rw-r--r-- | usr.sbin/nsd/util.h | 2 | ||||
-rw-r--r-- | usr.sbin/nsd/zonec.c | 22 | ||||
-rw-r--r-- | usr.sbin/nsd/zparser.y | 35 |
27 files changed, 423 insertions, 163 deletions
diff --git a/usr.sbin/nsd/Makefile.in b/usr.sbin/nsd/Makefile.in index fffb32cf99d..d193cc6629e 100644 --- a/usr.sbin/nsd/Makefile.in +++ b/usr.sbin/nsd/Makefile.in @@ -228,6 +228,9 @@ malloc.o: $(srcdir)/compat/malloc.c pselect.o: $(srcdir)/compat/pselect.c $(COMPILE) -c $(srcdir)/compat/pselect.c +reallocarray.o: $(srcdir)/compat/reallocarray.c + $(COMPILE) -c $(srcdir)/compat/reallocarray.c + fake-rfc2553.o: $(srcdir)/compat/fake-rfc2553.c $(COMPILE) -c $(srcdir)/compat/fake-rfc2553.c @@ -373,7 +376,7 @@ namedb.o: $(srcdir)/namedb.c config.h $(srcdir)/namedb.h $(srcdir)/dname.h $(src $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/nsec3.h netio.o: $(srcdir)/netio.c config.h $(srcdir)/netio.h $(srcdir)/region-allocator.h $(srcdir)/util.h nsd.o: $(srcdir)/nsd.c config.h $(srcdir)/nsd.h $(srcdir)/dns.h $(srcdir)/edns.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h \ - $(srcdir)/util.h $(srcdir)/options.h $(srcdir)/rbtree.h $(srcdir)/tsig.h $(srcdir)/dname.h $(srcdir)/remote.h + $(srcdir)/util.h $(srcdir)/options.h $(srcdir)/rbtree.h $(srcdir)/tsig.h $(srcdir)/dname.h $(srcdir)/remote.h $(srcdir)/xfrd-disk.h nsd-checkconf.o: $(srcdir)/nsd-checkconf.c config.h $(srcdir)/tsig.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dname.h $(srcdir)/options.h $(srcdir)/rbtree.h $(srcdir)/rrl.h $(srcdir)/query.h \ $(srcdir)/namedb.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/packet.h @@ -456,6 +459,7 @@ malloc.o: $(srcdir)/compat/malloc.c memcmp.o: $(srcdir)/compat/memcmp.c config.h memmove.o: $(srcdir)/compat/memmove.c config.h pselect.o: $(srcdir)/compat/pselect.c config.h +reallocarray.o: $(srcdir)/compat/reallocarray.c config.h snprintf.o: $(srcdir)/compat/snprintf.c config.h strlcat.o: $(srcdir)/compat/strlcat.c config.h strlcpy.o: $(srcdir)/compat/strlcpy.c config.h diff --git a/usr.sbin/nsd/axfr.c b/usr.sbin/nsd/axfr.c index 069d30d3d4e..3990a32ccb5 100644 --- a/usr.sbin/nsd/axfr.c +++ b/usr.sbin/nsd/axfr.c @@ -176,10 +176,10 @@ answer_axfr_ixfr(struct nsd *nsd, struct query *q) if(!zone_opt || acl_check_incoming(zone_opt->pattern->provide_xfr, q, &acl)==-1) { - if (verbosity > 0) { + if (verbosity >= 2) { char a[128]; addr2str(&q->addr, a, sizeof(a)); - VERBOSITY(1, (LOG_INFO, "axfr for zone %s from client %s refused, %s", + VERBOSITY(2, (LOG_INFO, "axfr for %s from %s refused, %s", dname_to_string(q->qname, NULL), a, acl?"blocked":"no acl matches")); } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "axfr refused, %s", diff --git a/usr.sbin/nsd/compat/b64_pton.c b/usr.sbin/nsd/compat/b64_pton.c index 4825a9aec98..86a6ebeff1d 100644 --- a/usr.sbin/nsd/compat/b64_pton.c +++ b/usr.sbin/nsd/compat/b64_pton.c @@ -168,7 +168,7 @@ b64_initialize_rmap () } static int -b64_pton_do(char const *src, uint8_t *target, size_t targsize) +b64_pton_do(unsigned char const *src, uint8_t *target, size_t targsize) { int tarindex, state, ch; uint8_t ofs; @@ -285,7 +285,7 @@ b64_pton_do(char const *src, uint8_t *target, size_t targsize) static int -b64_pton_len(char const *src) +b64_pton_len(unsigned char const *src) { int tarindex, state, ch; uint8_t ofs; @@ -384,7 +384,7 @@ b64_pton(char const *src, uint8_t *target, size_t targsize) b64_initialize_rmap (); if (target) - return b64_pton_do (src, target, targsize); + return b64_pton_do ((unsigned char*)src, target, targsize); else - return b64_pton_len (src); + return b64_pton_len ((unsigned char*)src); } diff --git a/usr.sbin/nsd/config.h.in b/usr.sbin/nsd/config.h.in index 5b2d44520cd..c8fd3a82a03 100644 --- a/usr.sbin/nsd/config.h.in +++ b/usr.sbin/nsd/config.h.in @@ -85,12 +85,6 @@ /* Define to 1 if you have the <event.h> header file. */ #undef HAVE_EVENT_H -/* Define to 1 if you have the `EVP_sha1' function. */ -#undef HAVE_EVP_SHA1 - -/* Define to 1 if you have the `EVP_sha256' function. */ -#undef HAVE_EVP_SHA256 - /* Define to 1 if you have the `ev_default_loop' function. */ #undef HAVE_EV_DEFAULT_LOOP @@ -203,6 +197,9 @@ /* Define to 1 if you have the `pwrite' function. */ #undef HAVE_PWRITE +/* Define to 1 if you have the `reallocarray' function. */ +#undef HAVE_REALLOCARRAY + /* Define if recvmmsg is implemented */ #undef HAVE_RECVMMSG @@ -356,6 +353,9 @@ /* Define this to enable IPv6 support. */ #undef INET6 +/* If flex defines yy_current_buffer as a macro */ +#undef LEX_DEFINES_YY_CURRENT_BUFFER + /* Define to the maximum message length to pass to syslog. */ #undef MAXSYSLOGMSGLEN @@ -742,6 +742,9 @@ size_t strlcat(char *dst, const char *src, size_t siz); #ifndef HAVE_STRLCPY size_t strlcpy(char *dst, const char *src, size_t siz); #endif +#ifndef HAVE_REALLOCARRAY +void* reallocarray(void *ptr, size_t nmemb, size_t size); +#endif #ifndef HAVE_GETADDRINFO #include "compat/fake-rfc2553.h" #endif diff --git a/usr.sbin/nsd/configparser.y b/usr.sbin/nsd/configparser.y index 827b83ee0fb..259c82a92ef 100644 --- a/usr.sbin/nsd/configparser.y +++ b/usr.sbin/nsd/configparser.y @@ -209,24 +209,30 @@ server_identity: VAR_IDENTITY STRING server_nsid: VAR_NSID STRING { unsigned char* nsid = 0; - uint16_t nsid_len = 0; + size_t nsid_len = 0; OUTYY(("P(server_nsid:%s)\n", $2)); if (strncasecmp($2, "ascii_", 6) == 0) { nsid_len = strlen($2+6); - cfg_parser->opt->nsid = region_alloc(cfg_parser->opt->region, nsid_len*2+1); - hex_ntop((uint8_t*)$2+6, nsid_len, (char*)cfg_parser->opt->nsid, nsid_len*2+1); + if(nsid_len < 65535) { + cfg_parser->opt->nsid = region_alloc(cfg_parser->opt->region, nsid_len*2+1); + hex_ntop((uint8_t*)$2+6, nsid_len, (char*)cfg_parser->opt->nsid, nsid_len*2+1); + } else + yyerror("NSID too long"); } else if (strlen($2) % 2 != 0) { yyerror("the NSID must be a hex string of an even length."); } else { nsid_len = strlen($2) / 2; - nsid = xalloc(nsid_len); - if (hex_pton($2, nsid, nsid_len) == -1) - yyerror("hex string cannot be parsed in NSID."); - else - cfg_parser->opt->nsid = region_strdup(cfg_parser->opt->region, $2); - free(nsid); + if(nsid_len < 65535) { + nsid = xalloc(nsid_len); + if (hex_pton($2, nsid, nsid_len) == -1) + yyerror("hex string cannot be parsed in NSID."); + else + cfg_parser->opt->nsid = region_strdup(cfg_parser->opt->region, $2); + free(nsid); + } else + yyerror("NSID too long"); } } ; diff --git a/usr.sbin/nsd/configure b/usr.sbin/nsd/configure index 1e52f2b4597..80abd927aa8 100644 --- a/usr.sbin/nsd/configure +++ b/usr.sbin/nsd/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for NSD 4.1.1. +# Generated by GNU Autoconf 2.69 for NSD 4.1.3. # # Report bugs to <nsd-bugs@nlnetlabs.nl>. # @@ -580,8 +580,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='NSD' PACKAGE_TARNAME='nsd' -PACKAGE_VERSION='4.1.1' -PACKAGE_STRING='NSD 4.1.1' +PACKAGE_VERSION='4.1.3' +PACKAGE_STRING='NSD 4.1.3' PACKAGE_BUGREPORT='nsd-bugs@nlnetlabs.nl' PACKAGE_URL='' @@ -1280,7 +1280,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures NSD 4.1.1 to adapt to many kinds of systems. +\`configure' configures NSD 4.1.3 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1341,7 +1341,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of NSD 4.1.1:";; + short | recursive ) echo "Configuration of NSD 4.1.3:";; esac cat <<\_ACEOF @@ -1478,7 +1478,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -NSD configure 4.1.1 +NSD configure 4.1.3 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2187,7 +2187,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by NSD $as_me 4.1.1, which was +It was created by NSD $as_me 4.1.3, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -4936,6 +4936,30 @@ done test -n "$YACC" || YACC="yacc" +if test "$LEX" != ":" -a "$LEX" != ""; then + # Check if lex defines yy_current_buffer, because 2.4.6 and older use it, + # but later could define it as a macro and then we should not redefine it. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if lex defines yy_current_buffer" >&5 +$as_echo_n "checking if lex defines yy_current_buffer... " >&6; } + cat <<EOF >conftest.lex +%% +EOF + $LEX -i -t conftest.lex >> conftest.c + if grep "^#define yy_current_buffer" conftest.c >/dev/null; then + +cat >>confdefs.h <<_ACEOF +#define LEX_DEFINES_YY_CURRENT_BUFFER 1 +_ACEOF + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + rm -f conftest.lex conftest.c +fi + @@ -8072,6 +8096,20 @@ esac fi +ac_fn_c_check_func "$LINENO" "reallocarray" "ac_cv_func_reallocarray" +if test "x$ac_cv_func_reallocarray" = xyes; then : + $as_echo "#define HAVE_REALLOCARRAY 1" >>confdefs.h + +else + case " $LIBOBJS " in + *" reallocarray.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS reallocarray.$ac_objext" + ;; +esac + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pselect prototype in sys/select.h" >&5 $as_echo_n "checking for pselect prototype in sys/select.h... " >&6; } @@ -8199,7 +8237,7 @@ cat >>confdefs.h <<_ACEOF _ACEOF -max_ips=16 +max_ips=32 # Check whether --with-max_ips was given. if test "${with_max_ips+set}" = set; then : @@ -8553,18 +8591,6 @@ else fi - for ac_func in EVP_sha1 EVP_sha256 -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - -fi -done - fi fi @@ -9396,7 +9422,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by NSD $as_me 4.1.1, which was +This file was extended by NSD $as_me 4.1.3, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -9458,7 +9484,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -NSD config.status 4.1.1 +NSD config.status 4.1.3 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/usr.sbin/nsd/configure.ac b/usr.sbin/nsd/configure.ac index cb4875458f4..fcbf40b075c 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.1,nsd-bugs@nlnetlabs.nl) +AC_INIT(NSD,4.1.3,nsd-bugs@nlnetlabs.nl) AC_CONFIG_HEADER([config.h]) CFLAGS="$CFLAGS" @@ -168,6 +168,23 @@ AC_PROG_INSTALL AC_PROG_LEX AC_PROG_YACC +if test "$LEX" != ":" -a "$LEX" != ""; then + # Check if lex defines yy_current_buffer, because 2.4.6 and older use it, + # but later could define it as a macro and then we should not redefine it. + AC_MSG_CHECKING(if lex defines yy_current_buffer) + cat <<EOF >conftest.lex +%% +EOF + $LEX -i -t conftest.lex >> conftest.c + if grep "^#define yy_current_buffer" conftest.c >/dev/null; then + AC_DEFINE_UNQUOTED(LEX_DEFINES_YY_CURRENT_BUFFER, 1, [If flex defines yy_current_buffer as a macro]) + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + fi + rm -f conftest.lex conftest.c +fi + AC_DEFUN([AC_CHECK_FORMAT_ATTRIBUTE], [AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING(whether the C compiler (${CC-cc}) accepts the "format" attribute) @@ -320,7 +337,6 @@ AC_DEFUN([CHECK_SSL], [ AC_CHECK_LIB(crypto, HMAC_CTX_init,, [ AC_MSG_ERROR([OpenSSL found in $ssldir, but version 0.9.7 or higher is required]) ]) - AC_CHECK_FUNCS([EVP_sha1 EVP_sha256]) fi AC_SUBST(HAVE_SSL) fi @@ -642,6 +658,7 @@ AC_REPLACE_FUNCS(b64_pton) AC_REPLACE_FUNCS(b64_ntop) AC_REPLACE_FUNCS(pselect) AC_REPLACE_FUNCS(memmove) +AC_REPLACE_FUNCS(reallocarray) AC_MSG_CHECKING(for pselect prototype in sys/select.h) AC_EGREP_HEADER([[^a-zA-Z_]*pselect[^a-zA-Z_]], sys/select.h, AC_DEFINE(HAVE_PSELECT_PROTO, 1, @@ -688,7 +705,7 @@ AC_DEFINE_UNQUOTED([FACILITY], $facility, [Define to the default facility for sy dnl dnl Determine the maximum number of ip-addresses that are allowed dnl -max_ips=16 +max_ips=32 AC_ARG_WITH([max_ips], AC_HELP_STRING([--with-max-ips=number], [Limit on the number of ip-addresses that may be specified]), [max_ips=$withval]) @@ -958,6 +975,9 @@ size_t strlcat(char *dst, const char *src, size_t siz); #ifndef HAVE_STRLCPY size_t strlcpy(char *dst, const char *src, size_t siz); #endif +#ifndef HAVE_REALLOCARRAY +void* reallocarray(void *ptr, size_t nmemb, size_t size); +#endif #ifndef HAVE_GETADDRINFO #include "compat/fake-rfc2553.h" #endif diff --git a/usr.sbin/nsd/difffile.c b/usr.sbin/nsd/difffile.c index 490dd0f043d..4196f79e066 100644 --- a/usr.sbin/nsd/difffile.c +++ b/usr.sbin/nsd/difffile.c @@ -702,8 +702,8 @@ delete_RR(namedb_type* db, const dname_type* dname, rrset->rrs[rrnum] = rrset->rrs[rrset->rr_count-1]; memset(&rrset->rrs[rrset->rr_count-1], 0, sizeof(rr_type)); /* realloc the rrs array one smaller */ - rrset->rrs = region_alloc_init(db->region, rrs_orig, - sizeof(rr_type) * (rrset->rr_count-1)); + rrset->rrs = region_alloc_array_init(db->region, rrs_orig, + (rrset->rr_count-1), sizeof(rr_type)); if(!rrset->rrs) { log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__); exit(1); @@ -791,11 +791,16 @@ add_RR(namedb_type* db, const dname_type* dname, *softfail = 1; return 1; } + if(rrset->rr_count == 65535) { + log_msg(LOG_ERR, "diff: too many RRs at %s", + dname_to_string(dname,0)); + return 0; + } /* re-alloc the rrs and add the new */ rrs_old = rrset->rrs; - rrset->rrs = region_alloc(db->region, - (rrset->rr_count+1) * sizeof(rr_type)); + rrset->rrs = region_alloc_array(db->region, + (rrset->rr_count+1), sizeof(rr_type)); if(!rrset->rrs) { log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__); exit(1); @@ -1403,7 +1408,7 @@ apply_ixfr_for_zone(nsd_type* nsd, zone_type* zonedb, FILE* in, double elapsed = (double)(time_end_0 - time_start_0)+ (double)((double)time_end_1 -(double)time_start_1) / 1000000.0; - VERBOSITY(2, (LOG_INFO, "zone %s %s of %d bytes in %g seconds", + VERBOSITY(1, (LOG_INFO, "zone %s %s of %d bytes in %g seconds", zone_buf, log_buf, num_bytes, elapsed)); } } diff --git a/usr.sbin/nsd/dname.c b/usr.sbin/nsd/dname.c index eacc95a75cf..2432f65f62e 100644 --- a/usr.sbin/nsd/dname.c +++ b/usr.sbin/nsd/dname.c @@ -63,7 +63,7 @@ dname_make(region_type *region, const uint8_t *name, int normalize) result = (dname_type *) region_alloc( region, (sizeof(dname_type) - + (label_count + name_size) * sizeof(uint8_t))); + + (((size_t)label_count) + ((size_t)name_size)) * sizeof(uint8_t))); result->name_size = name_size; result->label_count = label_count; memcpy((uint8_t *) dname_label_offsets(result), @@ -244,6 +244,9 @@ int dname_parse_wire(uint8_t* dname, const char* name) } /* Add root label. */ + if (h - dname >= MAXDOMAINLEN) { + return 0; + } *h = 0; return p-dname; @@ -482,7 +485,7 @@ dname_replace(region_type* region, return NULL; res = (dname_type*)region_alloc(region, sizeof(dname_type) + - (x_labels+dest->label_count + x_len+dest->name_size) + (x_labels+((int)dest->label_count) + x_len+((int)dest->name_size)) *sizeof(uint8_t)); res->name_size = x_len+dest->name_size; res->label_count = x_labels+dest->label_count; diff --git a/usr.sbin/nsd/namedb.c b/usr.sbin/nsd/namedb.c index b30e96b01c7..96aec38c1dd 100644 --- a/usr.sbin/nsd/namedb.c +++ b/usr.sbin/nsd/namedb.c @@ -443,19 +443,6 @@ domain_table_insert(domain_table_type* table, return result; } -int -domain_table_iterate(domain_table_type* table, - domain_table_iterator_type iterator, - void* user_data) -{ - int error = 0; - struct radnode* n; - for(n = radix_first(table->nametree); n; n = radix_next(n)) { - error += iterator((domain_type*)n->elem, user_data); - } - return error; -} - domain_type *domain_previous_existing_child(domain_type* domain) { domain_type* parent = domain->parent; diff --git a/usr.sbin/nsd/namedb.h b/usr.sbin/nsd/namedb.h index 51d54001181..d264c685679 100644 --- a/usr.sbin/nsd/namedb.h +++ b/usr.sbin/nsd/namedb.h @@ -223,16 +223,6 @@ void prehash_del(domain_table_type* table, domain_type* domain); int domain_is_prehash(domain_table_type* table, domain_type* domain); /* - * Iterate over all the domain names in the domain tree. - */ -typedef int (*domain_table_iterator_type)(domain_type *node, - void *user_data); - -int domain_table_iterate(domain_table_type* table, - domain_table_iterator_type iterator, - void* user_data); - -/* * Add an RRset to the specified domain. Updates the is_existing flag * as required. */ diff --git a/usr.sbin/nsd/nsd-checkconf.8.in b/usr.sbin/nsd/nsd-checkconf.8.in index 7d6040d939b..212d080cb5b 100644 --- a/usr.sbin/nsd/nsd-checkconf.8.in +++ b/usr.sbin/nsd/nsd-checkconf.8.in @@ -1,4 +1,4 @@ -.TH "nsd\-checkconf" "8" "Feb 3, 2015" "NLnet Labs" "nsd 4.1.1" +.TH "nsd\-checkconf" "8" "Jun 23, 2015" "NLnet Labs" "nsd 4.1.3" .\" Copyright (c) 2001\-2008, NLnet Labs. All rights reserved. .\" See LICENSE for the license. .SH "NAME" diff --git a/usr.sbin/nsd/nsd-checkconf.c b/usr.sbin/nsd/nsd-checkconf.c index fa255db6685..25c23d161d0 100644 --- a/usr.sbin/nsd/nsd-checkconf.c +++ b/usr.sbin/nsd/nsd-checkconf.c @@ -520,7 +520,7 @@ static void append_trailing_slash(const char** dirname, region_type* region) { int l = strlen(*dirname); - if (l>0 && (*dirname)[l-1] != '/') { + if (l>0 && (*dirname)[l-1] != '/' && l < 0xffffff) { char *dirname_slash = region_alloc(region, l+2); memcpy(dirname_slash, *dirname, l+1); strlcat(dirname_slash, "/", l+2); diff --git a/usr.sbin/nsd/nsd-control.8.in b/usr.sbin/nsd/nsd-control.8.in index 2860eb57afb..82bfbf0241e 100644 --- a/usr.sbin/nsd/nsd-control.8.in +++ b/usr.sbin/nsd/nsd-control.8.in @@ -1,4 +1,4 @@ -.TH "nsd\-control" "8" "Feb 3, 2015" "NLnet Labs" "nsd 4.1.1" +.TH "nsd\-control" "8" "Jun 23, 2015" "NLnet Labs" "nsd 4.1.3" .\" Copyright (c) 2011, NLnet Labs. All rights reserved. .\" See LICENSE for the license. .SH "NAME" @@ -88,6 +88,14 @@ inside nsd.conf itself cannot be removed this way because the daemon does not write to the nsd.conf file, you need to add such zones to the zonelist file to be able to delete them with the delzone command. .TP +.B addzones +Add zones read from stdin of nsd\-control. Input is read per line, +with name space patternname on a line. For bulk additions. +.TP +.B delzones +Remove zones read from stdin of nsd\-control. Input is one name per line. +For bulk removals. +.TP .B write [<zone>] Write zonefiles to disk, or the given zonefile to disk. Zones that have changed (via AXFR or IXFR) are written, or if the zonefile has not been diff --git a/usr.sbin/nsd/nsd.c b/usr.sbin/nsd/nsd.c index 8ddc41403e5..b8b39b5e8f7 100644 --- a/usr.sbin/nsd/nsd.c +++ b/usr.sbin/nsd/nsd.c @@ -44,6 +44,7 @@ #include "options.h" #include "tsig.h" #include "remote.h" +#include "xfrd-disk.h" /* The server handler... */ struct nsd nsd; @@ -132,7 +133,7 @@ static void append_trailing_slash(const char** dirname, region_type* region) { int l = strlen(*dirname); - if (l>0 && (*dirname)[l-1] != '/') { + if (l>0 && (*dirname)[l-1] != '/' && l < 0xffffff) { char *dirname_slash = region_alloc(region, l+2); memcpy(dirname_slash, *dirname, l+1); strlcat(dirname_slash, "/", l+2); @@ -742,8 +743,8 @@ main(int argc, char *argv[]) #endif /* defined(INET6) */ /* Number of child servers to fork. */ - nsd.children = (struct nsd_child *) region_alloc( - nsd.region, nsd.child_count * sizeof(struct nsd_child)); + nsd.children = (struct nsd_child *) region_alloc_array( + nsd.region, nsd.child_count, sizeof(struct nsd_child)); for (i = 0; i < nsd.child_count; ++i) { nsd.children[i].kind = NSD_SERVER_BOTH; nsd.children[i].pid = -1; @@ -1106,6 +1107,7 @@ main(int argc, char *argv[]) nsd.username)); } #endif /* HAVE_GETPWNAM */ + xfrd_make_tempdir(&nsd); #ifdef USE_ZONE_STATS options_zonestatnames_create(nsd.options); server_zonestat_alloc(&nsd); diff --git a/usr.sbin/nsd/nsd.conf.5.in b/usr.sbin/nsd/nsd.conf.5.in index 3d7a5f6858e..7d1a83d8e56 100644 --- a/usr.sbin/nsd/nsd.conf.5.in +++ b/usr.sbin/nsd/nsd.conf.5.in @@ -1,4 +1,4 @@ -.TH "nsd.conf" "5" "Feb 3, 2015" "NLnet Labs" "nsd 4.1.1" +.TH "nsd.conf" "5" "Jun 23, 2015" "NLnet Labs" "nsd 4.1.3" .\" Copyright (c) 2001\-2008, NLnet Labs. All rights reserved. .\" See LICENSE for the license. .SH "NAME" @@ -299,6 +299,16 @@ once per the number of seconds. The default is 1 second. This value specifies the verbosity level for (non\-debug) logging. Default is 0. 1 gives more information about incoming notifies and zone transfers. 2 lists soft warnings that are encountered. +.IP +Verbosity 0 will print warnings and errors, and other events that are +important to keep NSD running. +.IP +Verbosity 1 prints additionally messages of interest. Successful notifies, +successful incoming zone transfer (the zone is updated), failed incoming +zone transfers or the inability to process zone updates. +.IP +Verbosity 2 prints additionally soft errors, like connection resets over TCP. +And notify refusal, and axfr request refusals. .TP .B hide\-version:\fR <yes or no> Prevent NSD from replying with the version string on CHAOS class diff --git a/usr.sbin/nsd/query.c b/usr.sbin/nsd/query.c index 4651b1157bd..d1a2b92c6b1 100644 --- a/usr.sbin/nsd/query.c +++ b/usr.sbin/nsd/query.c @@ -146,10 +146,28 @@ query_error (struct query *q, nsd_rc_type rcode) return QUERY_PROCESSED; } +static int +query_ratelimit_err(nsd_type* nsd) +{ + time_t now = time(NULL); + if(nsd->err_limit_time == now) { + /* see if limit is exceeded for this second */ + if(nsd->err_limit_count++ > ERROR_RATELIMIT) + return 1; + } else { + /* new second, new limits */ + nsd->err_limit_time = now; + nsd->err_limit_count = 1; + } + return 0; +} + static query_state_type -query_formerr (struct query *query) +query_formerr (struct query *query, nsd_type* nsd) { int opcode = OPCODE(query->packet); + if(query_ratelimit_err(nsd)) + return QUERY_DISCARDED; FLAGS_SET(query->packet, FLAGS(query->packet) & 0x0100U); /* Preserve the RD flag. Clear the rest. */ OPCODE_SET(query->packet, opcode); @@ -454,6 +472,18 @@ answer_notify(struct nsd* nsd, struct query *query) strerror(errno)); return query_error(query, NSD_RC_SERVFAIL); } + if(verbosity >= 1) { + uint32_t serial = 0; + char address[128]; + addr2str(&query->addr, address, sizeof(address)); + if(packet_find_notify_serial(query->packet, &serial)) + VERBOSITY(1, (LOG_INFO, "notify for %s from %s serial %u", + dname_to_string(query->qname, NULL), address, + (unsigned)serial)); + else + VERBOSITY(1, (LOG_INFO, "notify for %s from %s", + dname_to_string(query->qname, NULL), address)); + } /* create notify reply - keep same query contents */ QR_SET(query->packet); /* This is an answer. */ @@ -466,20 +496,14 @@ answer_notify(struct nsd* nsd, struct query *query) pos = buffer_position(query->packet); buffer_clear(query->packet); buffer_set_position(query->packet, pos); - if(verbosity >= 1) { - char address[128]; - addr2str(&query->addr, address, sizeof(address)); - VERBOSITY(2, (LOG_INFO, "notify for %s from %s", - dname_to_string(query->qname, NULL), address)); - } /* tsig is added in add_additional later (if needed) */ return QUERY_PROCESSED; } - if (verbosity >= 1) { + if (verbosity >= 2) { char address[128]; addr2str(&query->addr, address, sizeof(address)); - VERBOSITY(1, (LOG_INFO, "notify for zone %s from client %s refused, %s%s", + VERBOSITY(2, (LOG_INFO, "notify for %s from %s refused, %s%s", dname_to_string(query->qname, NULL), address, why?why->key_name:"no acl matches", @@ -1291,7 +1315,7 @@ query_process(query_type *q, nsd_type *nsd) } if (RCODE(q->packet) != RCODE_OK || !process_query_section(q)) { - return query_formerr(q); + return query_formerr(q, nsd); } /* Update statistics. */ @@ -1303,6 +1327,8 @@ query_process(query_type *q, nsd_type *nsd) if (q->opcode == OPCODE_NOTIFY) { return answer_notify(nsd, q); } else { + if(query_ratelimit_err(nsd)) + return QUERY_DISCARDED; return query_error(q, NSD_RC_IMPL); } } @@ -1310,7 +1336,7 @@ query_process(query_type *q, nsd_type *nsd) /* Dont bother to answer more than one question at once... */ if (QDCOUNT(q->packet) != 1) { FLAGS_SET(q->packet, 0); - return query_formerr(q); + return query_formerr(q, nsd); } /* Ignore settings of flags */ @@ -1318,13 +1344,13 @@ query_process(query_type *q, nsd_type *nsd) except for IXFR queries. */ if (ANCOUNT(q->packet) != 0 || (q->qtype!=TYPE_IXFR && NSCOUNT(q->packet) != 0)) { - return query_formerr(q); + return query_formerr(q, nsd); } if(q->qtype==TYPE_IXFR && NSCOUNT(q->packet) > 0) { int i; /* skip ixfr soa information data here */ for(i=0; i< NSCOUNT(q->packet); i++) if(!packet_skip_rr(q->packet, 0)) - return query_formerr(q); + return query_formerr(q, nsd); } arcount = ARCOUNT(q->packet); @@ -1340,7 +1366,7 @@ query_process(query_type *q, nsd_type *nsd) /* see if tsig is before edns record */ if (!tsig_parse_rr(&q->tsig, q->packet)) - return query_formerr(q); + return query_formerr(q, nsd); if(q->tsig.status != TSIG_NOT_PRESENT) --arcount; } @@ -1353,20 +1379,20 @@ query_process(query_type *q, nsd_type *nsd) if (arcount > 0 && q->tsig.status == TSIG_NOT_PRESENT) { /* see if tsig is after the edns record */ if (!tsig_parse_rr(&q->tsig, q->packet)) - return query_formerr(q); + return query_formerr(q, nsd); if(q->tsig.status != TSIG_NOT_PRESENT) --arcount; } /* If more RRs left in Add. Section, FORMERR. */ if (arcount > 0) { - return query_formerr(q); + return query_formerr(q, nsd); } /* Do we have any trailing garbage? */ #ifdef STRICT_MESSAGE_PARSE if (buffer_remaining(q->packet) > 0) { /* If we're strict.... */ - return query_formerr(q); + return query_formerr(q, nsd); } #endif /* Remove trailing garbage. */ diff --git a/usr.sbin/nsd/rdata.c b/usr.sbin/nsd/rdata.c index ec5d6ff4be0..c7385c5e77e 100644 --- a/usr.sbin/nsd/rdata.c +++ b/usr.sbin/nsd/rdata.c @@ -809,7 +809,7 @@ rdata_wireformat_to_rdata_atoms(region_type *region, } if(is_wirestore) { temp_rdatas[i].data = (uint16_t *) region_alloc( - region, sizeof(uint16_t) + dname->name_size); + region, sizeof(uint16_t) + ((size_t)dname->name_size)); temp_rdatas[i].data[0] = dname->name_size; memcpy(temp_rdatas[i].data+1, dname_name(dname), dname->name_size); @@ -845,8 +845,8 @@ rdata_wireformat_to_rdata_atoms(region_type *region, return -1; } - *rdatas = (rdata_atom_type *) region_alloc_init( - region, temp_rdatas, i * sizeof(rdata_atom_type)); + *rdatas = (rdata_atom_type *) region_alloc_array_init( + region, temp_rdatas, i, sizeof(rdata_atom_type)); region_destroy(temp_region); return (ssize_t)i; } diff --git a/usr.sbin/nsd/region-allocator.c b/usr.sbin/nsd/region-allocator.c index a57ad516daa..5a280d832aa 100644 --- a/usr.sbin/nsd/region-allocator.c +++ b/usr.sbin/nsd/region-allocator.c @@ -14,11 +14,15 @@ #include <string.h> #include "region-allocator.h" +#include "util.h" + +/** This value is enough so that x*y does not overflow if both < than this */ +#define REGION_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) #ifdef ALIGNMENT #undef ALIGNMENT #endif -#define ALIGN_UP(x, s) (((x) + s - 1) & (~(s - 1))) +#define REGION_ALIGN_UP(x, s) (((x) + s - 1) & (~(s - 1))) #if SIZEOF_OFF_T > SIZEOF_VOIDP #define ALIGNMENT (sizeof(off_t)) #else @@ -247,7 +251,7 @@ region_alloc(region_type *region, size_t size) if (size == 0) { size = 1; } - aligned_size = ALIGN_UP(size, ALIGNMENT); + aligned_size = REGION_ALIGN_UP(size, ALIGNMENT); if (aligned_size >= region->large_object_size) { result = region->allocator(size + sizeof(struct large_elem)); @@ -329,6 +333,40 @@ region_alloc_zero(region_type *region, size_t size) return result; } +void * +region_alloc_array_init(region_type *region, const void *init, size_t num, + size_t size) +{ + if((num >= REGION_NO_OVERFLOW || size >= REGION_NO_OVERFLOW) && + num > 0 && SIZE_MAX / num < size) { + log_msg(LOG_ERR, "region_alloc_array_init failed because of integer overflow"); + exit(1); + } + return region_alloc_init(region, init, num*size); +} + +void * +region_alloc_array_zero(region_type *region, size_t num, size_t size) +{ + if((num >= REGION_NO_OVERFLOW || size >= REGION_NO_OVERFLOW) && + num > 0 && SIZE_MAX / num < size) { + log_msg(LOG_ERR, "region_alloc_array_zero failed because of integer overflow"); + exit(1); + } + return region_alloc_zero(region, num*size); +} + +void * +region_alloc_array(region_type *region, size_t num, size_t size) +{ + if((num >= REGION_NO_OVERFLOW || size >= REGION_NO_OVERFLOW) && + num > 0 && SIZE_MAX / num < size) { + log_msg(LOG_ERR, "region_alloc_array failed because of integer overflow"); + exit(1); + } + return region_alloc(region, num*size); +} + void region_free_all(region_type *region) { @@ -389,7 +427,7 @@ region_recycle(region_type *region, void *block, size_t size) if (size == 0) { size = 1; } - aligned_size = ALIGN_UP(size, ALIGNMENT); + aligned_size = REGION_ALIGN_UP(size, ALIGNMENT); if(aligned_size < region->large_object_size) { struct recycle_elem* elem = (struct recycle_elem*)block; @@ -472,9 +510,7 @@ size_t region_get_mem_unused(region_type* region) return region->unused_space; } -/* debug routine, includes here to keep base region-allocator independent */ -#undef ALIGN_UP -#include "util.h" +/* debug routine */ void region_log_stats(region_type *region) { diff --git a/usr.sbin/nsd/remote.c b/usr.sbin/nsd/remote.c index cfd1da56881..fa1528fdf85 100644 --- a/usr.sbin/nsd/remote.c +++ b/usr.sbin/nsd/remote.c @@ -77,7 +77,6 @@ #include "nsd.h" #include "options.h" #include "difffile.h" -#include "xfrd.h" #include "ipc.h" #ifdef HAVE_SYS_TYPES_H @@ -1106,15 +1105,15 @@ zonestat_inc_ifneeded(xfrd_state_t* xfrd) #endif /* USE_ZONE_STATS */ } -/** do the addzone command */ -static void -do_addzone(SSL* ssl, xfrd_state_t* xfrd, char* arg) +/** perform the addzone command for one zone */ +static int +perform_addzone(SSL* ssl, xfrd_state_t* xfrd, char* arg) { const dname_type* dname; zone_options_t* zopt; char* arg2 = NULL; if(!find_arg2(ssl, arg, &arg2)) - return; + return 0; /* if we add it to the xfrd now, then xfrd could download AXFR and * store it and the NSD-reload would see it in the difffile before @@ -1128,13 +1127,13 @@ do_addzone(SSL* ssl, xfrd_state_t* xfrd, char* arg) if(!rbtree_search(xfrd->nsd->options->patterns, arg2)) { (void)ssl_printf(ssl, "error pattern %s does not exist\n", arg2); - return; + return 0; } dname = dname_parse(xfrd->region, arg); if(!dname) { (void)ssl_printf(ssl, "error cannot parse zone name\n"); - return; + return 0; } /* see if zone is a duplicate */ @@ -1142,8 +1141,7 @@ do_addzone(SSL* ssl, xfrd_state_t* xfrd, char* arg) region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); (void)ssl_printf(ssl, "zone %s already exists\n", arg); - send_ok(ssl); /* a nop operation */ - return; + return 1; } region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); dname = NULL; @@ -1153,7 +1151,7 @@ do_addzone(SSL* ssl, xfrd_state_t* xfrd, char* arg) if(!zopt) { /* also dname parse error here */ (void)ssl_printf(ssl, "error could not add zonelist entry\n"); - return; + return 0; } /* make addzone task and schedule reload */ task_new_add_zone(xfrd->nsd->task[xfrd->nsd->mytask], @@ -1167,13 +1165,12 @@ do_addzone(SSL* ssl, xfrd_state_t* xfrd, char* arg) if(zone_is_slave(zopt)) { xfrd_init_slave_zone(xfrd, zopt); } - - send_ok(ssl); + return 1; } -/** do the delzone command */ -static void -do_delzone(SSL* ssl, xfrd_state_t* xfrd, char* arg) +/** perform the delzone command for one zone */ +static int +perform_delzone(SSL* ssl, xfrd_state_t* xfrd, char* arg) { const dname_type* dname; zone_options_t* zopt; @@ -1181,7 +1178,7 @@ do_delzone(SSL* ssl, xfrd_state_t* xfrd, char* arg) dname = dname_parse(xfrd->region, arg); if(!dname) { (void)ssl_printf(ssl, "error cannot parse zone name\n"); - return; + return 0; } /* see if we have the zone in question */ @@ -1191,9 +1188,8 @@ do_delzone(SSL* ssl, xfrd_state_t* xfrd, char* arg) dname_total_size(dname)); /* nothing to do */ if(!ssl_printf(ssl, "warning zone %s not present\n", arg)) - return; - send_ok(ssl); - return; + return 0; + return 1; } /* see if it can be deleted */ @@ -1203,7 +1199,7 @@ do_delzone(SSL* ssl, xfrd_state_t* xfrd, char* arg) (void)ssl_printf(ssl, "error zone defined in nsd.conf, " "cannot delete it in this manner: remove it from " "nsd.conf yourself and repattern\n"); - return; + return 0; } /* create deletion task */ @@ -1219,9 +1215,72 @@ do_delzone(SSL* ssl, xfrd_state_t* xfrd, char* arg) zone_list_del(xfrd->nsd->options, zopt); region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); + return 1; +} + +/** do the addzone command */ +static void +do_addzone(SSL* ssl, xfrd_state_t* xfrd, char* arg) +{ + if(!perform_addzone(ssl, xfrd, arg)) + return; + send_ok(ssl); +} + +/** do the delzone command */ +static void +do_delzone(SSL* ssl, xfrd_state_t* xfrd, char* arg) +{ + if(!perform_delzone(ssl, xfrd, arg)) + return; send_ok(ssl); } +/** do the addzones command */ +static void +do_addzones(SSL* ssl, xfrd_state_t* xfrd) +{ + char buf[2048]; + int num = 0; + while(ssl_read_line(ssl, buf, sizeof(buf))) { + if(buf[0] == 0x04 && buf[1] == 0) + break; /* end of transmission */ + if(!perform_addzone(ssl, xfrd, buf)) { + if(!ssl_printf(ssl, "error for input line '%s'\n", + buf)) + return; + } else { + if(!ssl_printf(ssl, "added: %s\n", buf)) + return; + num++; + } + } + (void)ssl_printf(ssl, "added %d zones\n", num); +} + +/** do the delzones command */ +static void +do_delzones(SSL* ssl, xfrd_state_t* xfrd) +{ + char buf[2048]; + int num = 0; + while(ssl_read_line(ssl, buf, sizeof(buf))) { + if(buf[0] == 0x04 && buf[1] == 0) + break; /* end of transmission */ + if(!perform_delzone(ssl, xfrd, buf)) { + if(!ssl_printf(ssl, "error for input line '%s'\n", + buf)) + return; + } else { + if(!ssl_printf(ssl, "removed: %s\n", buf)) + return; + num++; + } + } + (void)ssl_printf(ssl, "deleted %d zones\n", num); +} + + /** remove TSIG key from config and add task so that reload does too */ static void remove_key(xfrd_state_t* xfrd, const char* kname) { @@ -1662,6 +1721,10 @@ execute_cmd(struct daemon_remote* rc, SSL* ssl, char* cmd, struct rc_state* rs) do_addzone(ssl, rc->xfrd, skipwhite(p+7)); } else if(cmdcmp(p, "delzone", 7)) { do_delzone(ssl, rc->xfrd, skipwhite(p+7)); + } else if(cmdcmp(p, "addzones", 8)) { + do_addzones(ssl, rc->xfrd); + } else if(cmdcmp(p, "delzones", 8)) { + do_delzones(ssl, rc->xfrd); } else if(cmdcmp(p, "notify", 6)) { do_notify(ssl, rc->xfrd, skipwhite(p+6)); } else if(cmdcmp(p, "transfer", 8)) { @@ -1938,7 +2001,7 @@ print_stat_block(SSL* ssl, char* n, char* d, struct nsdst* st) static void resize_zonestat(xfrd_state_t* xfrd, size_t num) { - struct nsdst** a = xalloc_zero(num * sizeof(struct nsdst*)); + struct nsdst** a = xalloc_array_zero(num, sizeof(struct nsdst*)); if(xfrd->zonestat_clear_num != 0) memcpy(a, xfrd->zonestat_clear, xfrd->zonestat_clear_num * sizeof(struct nsdst*)); diff --git a/usr.sbin/nsd/rrl.c b/usr.sbin/nsd/rrl.c index d6670dedab7..e6b1490f553 100644 --- a/usr.sbin/nsd/rrl.c +++ b/usr.sbin/nsd/rrl.c @@ -80,7 +80,7 @@ void rrl_mmap_init(int numch, size_t numbuck, size_t lm, size_t wlm, size_t sm, /* allocate the ratelimit hashtable in a memory map so it is * preserved across reforks (every child its own table) */ rrl_maps_num = (size_t)numch; - rrl_maps = (void**)xalloc(sizeof(void*)*rrl_maps_num); + rrl_maps = (void**)xmallocarray(rrl_maps_num, sizeof(void*)); for(i=0; i<rrl_maps_num; i++) { rrl_maps[i] = mmap(NULL, sizeof(struct rrl_bucket)*rrl_array_size, @@ -110,7 +110,8 @@ void rrl_set_limit(size_t lm, size_t wlm, size_t sm) void rrl_init(size_t ch) { if(!rrl_maps || ch >= rrl_maps_num) - rrl_array = xalloc_zero(sizeof(struct rrl_bucket)*rrl_array_size); + rrl_array = xalloc_array_zero(sizeof(struct rrl_bucket), + rrl_array_size); #ifdef HAVE_MMAP else rrl_array = (struct rrl_bucket*)rrl_maps[ch]; #endif diff --git a/usr.sbin/nsd/server.c b/usr.sbin/nsd/server.c index 8014da70801..07dfc1d41fb 100644 --- a/usr.sbin/nsd/server.c +++ b/usr.sbin/nsd/server.c @@ -29,7 +29,6 @@ #include <time.h> #include <unistd.h> #include <signal.h> -#include <fcntl.h> #include <netdb.h> #ifndef SHUT_WR #define SHUT_WR 1 @@ -366,11 +365,11 @@ server_zonestat_alloc(struct nsd* nsd) /* file names */ nsd->zonestatfname[0] = 0; nsd->zonestatfname[1] = 0; - snprintf(tmpfile, sizeof(tmpfile), "%snsd.%u.zstat.0", - nsd->options->xfrdir, (unsigned)getpid()); + snprintf(tmpfile, sizeof(tmpfile), "%snsd-xfr-%d/nsd.%u.zstat.0", + nsd->options->xfrdir, (int)getpid(), (unsigned)getpid()); nsd->zonestatfname[0] = region_strdup(nsd->region, tmpfile); - snprintf(tmpfile, sizeof(tmpfile), "%snsd.%u.zstat.1", - nsd->options->xfrdir, (unsigned)getpid()); + snprintf(tmpfile, sizeof(tmpfile), "%snsd-xfr-%d/nsd.%u.zstat.1", + nsd->options->xfrdir, (int)getpid(), (unsigned)getpid()); nsd->zonestatfname[1] = region_strdup(nsd->region, tmpfile); /* file descriptors */ @@ -536,8 +535,8 @@ initialize_dname_compression_tables(struct nsd *nsd) compressed_dname_offsets); free(compressed_dname_offsets); } - compressed_dname_offsets = (uint16_t *) xalloc( - needed * sizeof(uint16_t)); + compressed_dname_offsets = (uint16_t *) xmallocarray( + needed, sizeof(uint16_t)); region_add_cleanup(nsd->db->region, cleanup_dname_compression_tables, compressed_dname_offsets); compression_table_capacity = needed; @@ -957,16 +956,27 @@ server_prepare_xfrd(struct nsd* nsd) char tmpfile[256]; /* create task mmaps */ nsd->mytask = 0; - snprintf(tmpfile, sizeof(tmpfile), "%snsd.%u.task.0", - nsd->options->xfrdir, (unsigned)getpid()); + snprintf(tmpfile, sizeof(tmpfile), "%snsd-xfr-%d/nsd.%u.task.0", + nsd->options->xfrdir, (int)getpid(), (unsigned)getpid()); nsd->task[0] = task_file_create(tmpfile); - if(!nsd->task[0]) + if(!nsd->task[0]) { +#ifdef USE_ZONE_STATS + unlink(nsd->zonestatfname[0]); + unlink(nsd->zonestatfname[1]); +#endif + xfrd_del_tempdir(nsd); exit(1); - snprintf(tmpfile, sizeof(tmpfile), "%snsd.%u.task.1", - nsd->options->xfrdir, (unsigned)getpid()); + } + snprintf(tmpfile, sizeof(tmpfile), "%snsd-xfr-%d/nsd.%u.task.1", + nsd->options->xfrdir, (int)getpid(), (unsigned)getpid()); nsd->task[1] = task_file_create(tmpfile); if(!nsd->task[1]) { unlink(nsd->task[0]->fname); +#ifdef USE_ZONE_STATS + unlink(nsd->zonestatfname[0]); + unlink(nsd->zonestatfname[1]); +#endif + xfrd_del_tempdir(nsd); exit(1); } assert(udb_base_get_userdata(nsd->task[0])->data == 0); @@ -1930,8 +1940,9 @@ server_child(struct nsd *nsd) * connections. */ tcp_accept_handler_count = nsd->ifs; - tcp_accept_handlers = (struct tcp_accept_handler_data*) region_alloc( - server_region, nsd->ifs * sizeof(*tcp_accept_handlers)); + tcp_accept_handlers = (struct tcp_accept_handler_data*) + region_alloc_array(server_region, + nsd->ifs, sizeof(*tcp_accept_handlers)); if (nsd->server_kind & NSD_SERVER_TCP) { for (i = 0; i < nsd->ifs; ++i) { struct event *handler = &tcp_accept_handlers[i].event; diff --git a/usr.sbin/nsd/udb.c b/usr.sbin/nsd/udb.c index 49532516a99..6ec17aec0b6 100644 --- a/usr.sbin/nsd/udb.c +++ b/usr.sbin/nsd/udb.c @@ -91,7 +91,8 @@ udb_base_create_fd(const char* fname, int fd, udb_walk_relptr_func walkfunc, udb->fd = fd; udb->ram_size = 1024; udb->ram_mask = (int)udb->ram_size - 1; - udb->ram_hash = (udb_ptr**)xalloc_zero(sizeof(udb_ptr*)*udb->ram_size); + udb->ram_hash = (udb_ptr**)xalloc_array_zero(sizeof(udb_ptr*), + udb->ram_size); if(!udb->ram_hash) { free(udb->fname); free(udb); @@ -432,10 +433,10 @@ void udb_base_link_ptr(udb_base* udb, udb_ptr* ptr) assert(udb_valid_dataptr(udb, ptr->data)); /* must be to whole chunk*/ #endif udb->ram_num++; - if(udb->ram_num == udb->ram_size && udb->ram_size<(size_t)0xefffffff) { + if(udb->ram_num == udb->ram_size && udb->ram_size<(size_t)0x7fffffff) { /* grow the array, if allocation succeeds */ - udb_ptr** newram = (udb_ptr**)xalloc_zero(sizeof(udb_ptr*)* - udb->ram_size*2); + udb_ptr** newram = (udb_ptr**)xalloc_array_zero( + sizeof(udb_ptr*), udb->ram_size*2); if(newram) { grow_ram_hash(udb, newram); } diff --git a/usr.sbin/nsd/util.c b/usr.sbin/nsd/util.c index 14b9379d580..507bfee4f69 100644 --- a/usr.sbin/nsd/util.c +++ b/usr.sbin/nsd/util.c @@ -259,6 +259,18 @@ xalloc(size_t size) } void * +xmallocarray(size_t num, size_t size) +{ + void *result = reallocarray(NULL, num, size); + + if (!result) { + log_msg(LOG_ERR, "reallocarray failed: %s", strerror(errno)); + exit(1); + } + return result; +} + +void * xalloc_zero(size_t size) { void *result = calloc(1, size); @@ -270,6 +282,17 @@ xalloc_zero(size_t size) } void * +xalloc_array_zero(size_t num, size_t size) +{ + void *result = calloc(num, size); + if (!result) { + log_msg(LOG_ERR, "calloc failed: %s", strerror(errno)); + exit(1); + } + return result; +} + +void * xrealloc(void *ptr, size_t size) { ptr = realloc(ptr, size); diff --git a/usr.sbin/nsd/util.h b/usr.sbin/nsd/util.h index e8100bd724b..51741cef58e 100644 --- a/usr.sbin/nsd/util.h +++ b/usr.sbin/nsd/util.h @@ -135,7 +135,9 @@ lookup_table_type *lookup_by_id(lookup_table_type table[], int id); * return NULL. */ void *xalloc(size_t size); +void *xmallocarray(size_t num, size_t size); void *xalloc_zero(size_t size); +void *xalloc_array_zero(size_t num, size_t size); void *xrealloc(void *ptr, size_t size); /* diff --git a/usr.sbin/nsd/zonec.c b/usr.sbin/nsd/zonec.c index ae1aa0373a3..49fa74417cc 100644 --- a/usr.sbin/nsd/zonec.c +++ b/usr.sbin/nsd/zonec.c @@ -1150,6 +1150,10 @@ void zadd_rdata_txt_wireformat(uint16_t *data, int first) { rdata_atom_type *rd; + if (parser->current_rr.rdata_count >= MAXRDATALEN) { + zc_error_prev_line("too many rdata txt elements"); + return; + } /* First STR in str_seq, allocate 65K in first unused rdata * else find last used rdata */ @@ -1183,8 +1187,10 @@ zadd_rdata_txt_clean_wireformat() { uint16_t *tmp_data; rdata_atom_type *rd = &parser->current_rr.rdatas[parser->current_rr.rdata_count-1]; + if(!rd || !rd->data) + return; /* previous syntax failure */ if ((tmp_data = (uint16_t *) region_alloc(parser->region, - rd->data[0] + 2)) != NULL) { + ((size_t)rd->data[0]) + ((size_t)2))) != NULL) { memcpy(tmp_data, rd->data, rd->data[0] + 2); /* rd->data of u16+65535 freed when rr_region is freed */ rd->data = tmp_data; @@ -1442,11 +1448,15 @@ process_rr(void) if (i < rrset->rr_count) { return 0; } + if(rrset->rr_count == 65535) { + zc_error_prev_line("too may RRs for domain RRset"); + return 0; + } /* Add it... */ o = rrset->rrs; - rrset->rrs = (rr_type *) region_alloc(parser->region, - (rrset->rr_count + 1) * sizeof(rr_type)); + rrset->rrs = (rr_type *) region_alloc_array(parser->region, + (rrset->rr_count + 1), sizeof(rr_type)); memcpy(rrset->rrs, o, (rrset->rr_count) * sizeof(rr_type)); region_recycle(parser->region, o, (rrset->rr_count) * sizeof(rr_type)); @@ -1585,7 +1595,8 @@ zonec_read(const char* name, const char* zonefile, zone_type* zone) yyparse(); /* remove origin if it was unused */ - domain_table_deldomain(parser->db, parser->origin); + if(parser->origin != error_domain) + domain_table_deldomain(parser->db, parser->origin); /* rr_region has been emptied by now */ dname = dname_parse(parser->rr_region, name); @@ -1691,7 +1702,8 @@ zonec_parse_string(region_type* region, domain_table_type* domains, *parsed = NULL; else *parsed = parser->prev_dname; /* remove origin if it was not used during the parse */ - domain_table_deldomain(parser->db, parser->origin); + if(parser->origin != error_domain) + domain_table_deldomain(parser->db, parser->origin); zonec_desetup_string_parser(); return errors; } diff --git a/usr.sbin/nsd/zparser.y b/usr.sbin/nsd/zparser.y index f916a74d936..e8a8563fef9 100644 --- a/usr.sbin/nsd/zparser.y +++ b/usr.sbin/nsd/zparser.y @@ -97,21 +97,29 @@ line: NL | PREV NL {} /* Lines containing only whitespace. */ | ttl_directive { + region_free_all(parser->rr_region); + parser->current_rr.type = 0; + parser->current_rr.rdata_count = 0; + parser->current_rr.rdatas = parser->temporary_rdatas; parser->error_occurred = 0; } | origin_directive { + region_free_all(parser->rr_region); + parser->current_rr.type = 0; + parser->current_rr.rdata_count = 0; + parser->current_rr.rdatas = parser->temporary_rdatas; parser->error_occurred = 0; } | rr { /* rr should be fully parsed */ if (!parser->error_occurred) { parser->current_rr.rdatas - = (rdata_atom_type *) region_alloc_init( + =(rdata_atom_type *)region_alloc_array_init( parser->region, parser->current_rr.rdatas, - (parser->current_rr.rdata_count - * sizeof(rdata_atom_type))); + parser->current_rr.rdata_count, + sizeof(rdata_atom_type)); process_rr(); } @@ -148,7 +156,12 @@ ttl_directive: DOLLAR_TTL sp STR trail origin_directive: DOLLAR_ORIGIN sp abs_dname trail { /* if previous origin is unused, remove it, do not leak it */ - domain_table_deldomain(parser->db, parser->origin); + if(parser->origin != error_domain && parser->origin != $3) { + /* protect $3 from deletion, because deldomain walks up */ + $3->usage ++; + domain_table_deldomain(parser->db, parser->origin); + $3->usage --; + } parser->origin = $3; } | DOLLAR_ORIGIN sp rel_dname trail @@ -207,6 +220,9 @@ dname: abs_dname { if ($1 == error_dname) { $$ = error_domain; + } else if(parser->origin == error_domain) { + zc_error("cannot concatenate origin to domain name, because origin failed to parse"); + $$ = error_domain; } else if ($1->name_size + domain_dname(parser->origin)->name_size - 1 > MAXDOMAINLEN) { zc_error("domain name exceeds %d character limit", MAXDOMAINLEN); $$ = error_domain; @@ -949,9 +965,14 @@ rdata_ipsec_base: STR sp STR sp STR sp dotted_str zc_error_prev_line("IPSECKEY must specify gateway name"); if(!(name = dname_parse(parser->region, $7.str))) zc_error_prev_line("IPSECKEY bad gateway dname %s", $7.str); - if($7.str[strlen($7.str)-1] != '.') + if($7.str[strlen($7.str)-1] != '.') { + if(parser->origin == error_domain) { + zc_error("cannot concatenate origin to domain name, because origin failed to parse"); + break; + } name = dname_concatenate(parser->rr_region, name, domain_dname(parser->origin)); + } zadd_rdata_wireformat(alloc_rdata_init(parser->region, dname_name(name), name->name_size)); break; @@ -1060,8 +1081,8 @@ zparser_create(region_type *region, region_type *rr_region, namedb_type *db) result->prev_dname = NULL; result->default_apex = NULL; - result->temporary_rdatas = (rdata_atom_type *) region_alloc( - result->region, MAXRDATALEN * sizeof(rdata_atom_type)); + result->temporary_rdatas = (rdata_atom_type *) region_alloc_array( + result->region, MAXRDATALEN, sizeof(rdata_atom_type)); return result; } |