Update to 4.1.10
authorflorian <florian@openbsd.org>
Fri, 24 Jun 2016 08:34:02 +0000 (08:34 +0000)
committerflorian <florian@openbsd.org>
Fri, 24 Jun 2016 08:34:02 +0000 (08:34 +0000)
Testing by millert@, sthen@ and me.
came up with the same diff & OK sthen@

38 files changed:
usr.sbin/nsd/Makefile.in
usr.sbin/nsd/acx_nlnetlabs.m4
usr.sbin/nsd/answer.c
usr.sbin/nsd/axfr.c
usr.sbin/nsd/configlexer.lex
usr.sbin/nsd/configparser.y
usr.sbin/nsd/configure.ac
usr.sbin/nsd/dbaccess.c
usr.sbin/nsd/dbcreate.c
usr.sbin/nsd/difffile.c
usr.sbin/nsd/dns.c
usr.sbin/nsd/dns.h
usr.sbin/nsd/namedb.c
usr.sbin/nsd/namedb.h
usr.sbin/nsd/nsd-checkconf.8.in
usr.sbin/nsd/nsd-checkconf.c
usr.sbin/nsd/nsd-checkzone.8.in
usr.sbin/nsd/nsd-control.8.in
usr.sbin/nsd/nsd.8.in
usr.sbin/nsd/nsd.c
usr.sbin/nsd/nsd.conf.5.in
usr.sbin/nsd/nsd.conf.sample.in
usr.sbin/nsd/nsd.h
usr.sbin/nsd/nsec3.c
usr.sbin/nsd/options.c
usr.sbin/nsd/options.h
usr.sbin/nsd/query.c
usr.sbin/nsd/rrl.c
usr.sbin/nsd/server.c
usr.sbin/nsd/tsig-openssl.c
usr.sbin/nsd/udb.h
usr.sbin/nsd/udbzone.c
usr.sbin/nsd/udbzone.h
usr.sbin/nsd/util.c
usr.sbin/nsd/util.h
usr.sbin/nsd/xfrd-tcp.c
usr.sbin/nsd/xfrd.c
usr.sbin/nsd/zparser.y

index 9103291..3fbd01b 100644 (file)
@@ -439,9 +439,9 @@ xfrd-disk.o: $(srcdir)/xfrd-disk.c config.h $(srcdir)/xfrd-disk.h $(srcdir)/xfrd
 xfrd-notify.o: $(srcdir)/xfrd-notify.c config.h $(srcdir)/xfrd-notify.h $(srcdir)/tsig.h $(srcdir)/buffer.h \
  $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dname.h $(srcdir)/rbtree.h $(srcdir)/xfrd.h $(srcdir)/namedb.h $(srcdir)/dns.h \
  $(srcdir)/radtree.h $(srcdir)/options.h $(srcdir)/xfrd-tcp.h $(srcdir)/packet.h
-xfrd-tcp.o: $(srcdir)/xfrd-tcp.c config.h $(srcdir)/xfrd-tcp.h $(srcdir)/xfrd.h $(srcdir)/rbtree.h \
- $(srcdir)/region-allocator.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h \
- $(srcdir)/options.h $(srcdir)/tsig.h $(srcdir)/packet.h $(srcdir)/xfrd-disk.h
+xfrd-tcp.o: $(srcdir)/xfrd-tcp.c config.h $(srcdir)/nsd.h $(srcdir)/dns.h $(srcdir)/edns.h $(srcdir)/buffer.h \
+ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/xfrd-tcp.h $(srcdir)/xfrd.h $(srcdir)/rbtree.h $(srcdir)/namedb.h $(srcdir)/dname.h \
+ $(srcdir)/radtree.h $(srcdir)/options.h $(srcdir)/tsig.h $(srcdir)/packet.h $(srcdir)/xfrd-disk.h
 zlexer.o: zlexer.c config.h $(srcdir)/zonec.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h \
  $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h zparser.h
 zonec.o: $(srcdir)/zonec.c config.h $(srcdir)/zonec.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h \
index 26513e4..a6c174f 100644 (file)
@@ -2,7 +2,11 @@
 # Copyright 2009, Wouter Wijngaards, NLnet Labs.   
 # BSD licensed.
 #
-# Version 30
+# Version 34
+# 2016-03-21 Check -ldl -pthread for libcrypto for ldns and openssl 1.1.0.
+# 2016-03-21 Use HMAC_Update instead of HMAC_CTX_Init (for openssl-1.1.0).
+# 2016-01-04 -D_DEFAULT_SOURCE defined with -D_BSD_SOURCE for Linux glibc 2.20
+# 2015-12-11 FLTO check for new OSX, clang.
 # 2015-11-18 spelling check fix.
 # 2015-11-05 ACX_SSL_CHECKS no longer adds -ldl needlessly.
 # 2015-08-28 ACX_CHECK_PIE and ACX_CHECK_RELRO_NOW added.
@@ -241,7 +245,7 @@ ACX_CHECK_COMPILER_FLAG(xc99, [C99FLAG="-xc99"])
 
 AC_CHECK_HEADERS([getopt.h time.h],,, [AC_INCLUDES_DEFAULT])
 
-ACX_CHECK_COMPILER_FLAG_NEEDED($C99FLAG -D__EXTENSIONS__ -D_BSD_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED=1 -D_ALL_SOURCE,
+ACX_CHECK_COMPILER_FLAG_NEEDED($C99FLAG -D__EXTENSIONS__ -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED=1 -D_ALL_SOURCE,
 [
 #include "confdefs.h"
 #include <stdlib.h>
@@ -276,9 +280,9 @@ int test() {
                a = 0;
        return a;
 }
-], [CFLAGS="$CFLAGS $C99FLAG -D__EXTENSIONS__ -D_BSD_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED=1 -D_ALL_SOURCE"])
+], [CFLAGS="$CFLAGS $C99FLAG -D__EXTENSIONS__ -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED=1 -D_ALL_SOURCE"])
 
-ACX_CHECK_COMPILER_FLAG_NEEDED($C99FLAG -D__EXTENSIONS__ -D_BSD_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -D_ALL_SOURCE,
+ACX_CHECK_COMPILER_FLAG_NEEDED($C99FLAG -D__EXTENSIONS__ -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -D_ALL_SOURCE,
 [
 #include "confdefs.h"
 #include <stdlib.h>
@@ -313,7 +317,7 @@ int test() {
                a = 0;
        return a;
 }
-], [CFLAGS="$CFLAGS $C99FLAG -D__EXTENSIONS__ -D_BSD_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -D_ALL_SOURCE"])
+], [CFLAGS="$CFLAGS $C99FLAG -D__EXTENSIONS__ -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -D_ALL_SOURCE"])
 
 ACX_CHECK_COMPILER_FLAG_NEEDED($C99FLAG,
 [
@@ -325,7 +329,7 @@ int test() {
 }
 ], [CFLAGS="$CFLAGS $C99FLAG"])
 
-ACX_CHECK_COMPILER_FLAG_NEEDED(-D_BSD_SOURCE,
+ACX_CHECK_COMPILER_FLAG_NEEDED(-D_BSD_SOURCE -D_DEFAULT_SOURCE,
 [
 #include <ctype.h>
 
@@ -334,7 +338,7 @@ int test() {
         a = isascii(32);
         return a;
 }
-], [CFLAGS="$CFLAGS -D_BSD_SOURCE"])
+], [CFLAGS="$CFLAGS -D_BSD_SOURCE -D_DEFAULT_SOURCE"])
 
 ACX_CHECK_COMPILER_FLAG_NEEDED(-D_GNU_SOURCE,
 [
@@ -423,7 +427,7 @@ AC_DEFUN([ACX_CHECK_FLTO], [
         BAKCFLAGS="$CFLAGS"
         CFLAGS="$CFLAGS -flto"
         AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])], [
-            if $CC $CFLAGS -o conftest conftest.c 2>&1 | grep "warning: no debug symbols in executable" >/dev/null; then
+            if $CC $CFLAGS -o conftest conftest.c 2>&1 | $GREP -e "warning: no debug symbols in executable" -e "warning: object" >/dev/null; then
                 CFLAGS="$BAKCFLAGS"
                 AC_MSG_RESULT(no)
             else
@@ -669,16 +673,16 @@ AC_DEFUN([ACX_SSL_CHECKS], [
                 ACX_RUNTIME_PATH_ADD([$ssldir/lib])
             fi
         
-            AC_MSG_CHECKING([for HMAC_CTX_init in -lcrypto])
+            AC_MSG_CHECKING([for HMAC_Update in -lcrypto])
             LIBS="$LIBS -lcrypto"
             LIBSSL_LIBS="$LIBSSL_LIBS -lcrypto"
             AC_TRY_LINK(, [
-                int HMAC_CTX_init(void);
-                (void)HMAC_CTX_init();
+                int HMAC_Update(void);
+                (void)HMAC_Update();
               ], [
                 AC_MSG_RESULT(yes)
-                AC_DEFINE([HAVE_HMAC_CTX_INIT], 1, 
-                          [If you have HMAC_CTX_init])
+                AC_DEFINE([HAVE_HMAC_UPDATE], 1, 
+                          [If you have HMAC_Update])
               ], [
                 AC_MSG_RESULT(no)
                 # check if -lwsock32 or -lgdi32 are needed.    
@@ -688,11 +692,11 @@ AC_DEFUN([ACX_SSL_CHECKS], [
                 LIBSSL_LIBS="$LIBSSL_LIBS -lgdi32"
                 AC_MSG_CHECKING([if -lcrypto needs -lgdi32])
                 AC_TRY_LINK([], [
-                    int HMAC_CTX_init(void);
-                    (void)HMAC_CTX_init();
+                    int HMAC_Update(void);
+                    (void)HMAC_Update();
                   ],[
-                    AC_DEFINE([HAVE_HMAC_CTX_INIT], 1, 
-                        [If you have HMAC_CTX_init])
+                    AC_DEFINE([HAVE_HMAC_UPDATE], 1, 
+                        [If you have HMAC_Update])
                     AC_MSG_RESULT(yes) 
                   ],[
                     AC_MSG_RESULT(no)
@@ -702,15 +706,30 @@ AC_DEFUN([ACX_SSL_CHECKS], [
                     LIBSSL_LIBS="$LIBSSL_LIBS -ldl"
                     AC_MSG_CHECKING([if -lcrypto needs -ldl])
                     AC_TRY_LINK([], [
-                        int HMAC_CTX_init(void);
-                        (void)HMAC_CTX_init();
+                        int HMAC_Update(void);
+                        (void)HMAC_Update();
                       ],[
-                        AC_DEFINE([HAVE_HMAC_CTX_INIT], 1, 
-                            [If you have HMAC_CTX_init])
+                        AC_DEFINE([HAVE_HMAC_UPDATE], 1, 
+                            [If you have HMAC_Update])
                         AC_MSG_RESULT(yes) 
                       ],[
                         AC_MSG_RESULT(no)
-                    AC_MSG_ERROR([OpenSSL found in $ssldir, but version 0.9.7 or higher is required])
+                        LIBS="$BAKLIBS"
+                        LIBSSL_LIBS="$BAKSSLLIBS"
+                        LIBS="$LIBS -ldl -pthread"
+                        LIBSSL_LIBS="$LIBSSL_LIBS -ldl -pthread"
+                        AC_MSG_CHECKING([if -lcrypto needs -ldl -pthread])
+                        AC_TRY_LINK([], [
+                            int HMAC_Update(void);
+                            (void)HMAC_Update();
+                          ],[
+                            AC_DEFINE([HAVE_HMAC_UPDATE], 1, 
+                                [If you have HMAC_Update])
+                            AC_MSG_RESULT(yes) 
+                          ],[
+                            AC_MSG_RESULT(no)
+                            AC_MSG_ERROR([OpenSSL found in $ssldir, but version 0.9.7 or higher is required])
+                       ])
                     ])
                 ])
             ])
@@ -1284,6 +1303,7 @@ AC_DEFUN([ACX_STRIP_EXT_FLAGS],
   AC_MSG_NOTICE([Stripping extension flags...])
   ACX_CFLAGS_STRIP(-D_GNU_SOURCE)
   ACX_CFLAGS_STRIP(-D_BSD_SOURCE)
+  ACX_CFLAGS_STRIP(-D_DEFAULT_SOURCE)
   ACX_CFLAGS_STRIP(-D__EXTENSIONS__)
   ACX_CFLAGS_STRIP(-D_POSIX_C_SOURCE=200112)
   ACX_CFLAGS_STRIP(-D_XOPEN_SOURCE=600)
@@ -1311,6 +1331,7 @@ dnl config.h part to define omitted cflags, use with ACX_STRIP_EXT_FLAGS.
 AC_DEFUN([AHX_CONFIG_EXT_FLAGS],
 [AHX_CONFIG_FLAG_EXT(-D_GNU_SOURCE)
 AHX_CONFIG_FLAG_EXT(-D_BSD_SOURCE)
+AHX_CONFIG_FLAG_EXT(-D_DEFAULT_SOURCE)
 AHX_CONFIG_FLAG_EXT(-D__EXTENSIONS__)
 AHX_CONFIG_FLAG_EXT(-D_POSIX_C_SOURCE=200112)
 AHX_CONFIG_FLAG_EXT(-D_XOPEN_SOURCE=600)
index be43c4c..c7b86fb 100644 (file)
@@ -95,6 +95,11 @@ encode_answer(query_type *q, const answer_type *answer)
                 * sections.
                 */
                if (done) {
+                       /* delegations should have a usable address in it */
+                       if(section == ADDITIONAL_A_SECTION &&
+                               counts[ADDITIONAL_A_SECTION] == 0 &&
+                               q->delegation_domain)
+                               TC_SET(q->packet);
                        break;
                }
 #endif
index f7e0caa..09eb082 100644 (file)
@@ -95,9 +95,10 @@ query_axfr(struct nsd *nsd, struct query *query)
        }
 
        /* Add zone RRs until answer is full.  */
-       assert(query->axfr_current_domain);
-
-       do {
+       while (query->axfr_current_domain != NULL &&
+                       domain_is_subdomain(query->axfr_current_domain,
+                                           query->axfr_zone->apex))
+       {
                if (!query->axfr_current_rrset) {
                        query->axfr_current_rrset = domain_find_any_rrset(
                                query->axfr_current_domain,
@@ -128,9 +129,6 @@ query_axfr(struct nsd *nsd, struct query *query)
                query->axfr_current_domain
                        = domain_next(query->axfr_current_domain);
        }
-       while (query->axfr_current_domain != NULL &&
-                       domain_is_subdomain(query->axfr_current_domain,
-                                           query->axfr_zone->apex));
 
        /* Add terminating SOA RR.  */
        assert(query->axfr_zone->soa_rrset->rr_count == 1);
index 20304b7..113fa22 100644 (file)
@@ -199,6 +199,7 @@ name{COLON}         { LEXOUT(("v(%s) ", yytext)); return VAR_NAME;}
 ip-address{COLON}      { LEXOUT(("v(%s) ", yytext)); return VAR_IP_ADDRESS;}
 interface{COLON}       { LEXOUT(("v(%s) ", yytext)); return VAR_IP_ADDRESS;}
 ip-transparent{COLON}  { LEXOUT(("v(%s) ", yytext)); return VAR_IP_TRANSPARENT;}
+ip-freebind{COLON}     { LEXOUT(("v(%s) ", yytext)); return VAR_IP_FREEBIND;}
 debug-mode{COLON}      { LEXOUT(("v(%s) ", yytext)); return VAR_DEBUG_MODE;}
 hide-version{COLON}    { LEXOUT(("v(%s) ", yytext)); return VAR_HIDE_VERSION;}
 ip4-only{COLON}                { LEXOUT(("v(%s) ", yytext)); return VAR_IP4_ONLY;}
@@ -214,6 +215,8 @@ server-count{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_SERVER_COUNT;}
 tcp-count{COLON}       { LEXOUT(("v(%s) ", yytext)); return VAR_TCP_COUNT;}
 tcp-query-count{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TCP_QUERY_COUNT;}
 tcp-timeout{COLON}     { LEXOUT(("v(%s) ", yytext)); return VAR_TCP_TIMEOUT;}
+tcp-mss{COLON}         { LEXOUT(("v(%s) ", yytext)); return VAR_TCP_MSS;}
+outgoing-tcp-mss{COLON}        { LEXOUT(("v(%s) ", yytext)); return VAR_OUTGOING_TCP_MSS;}
 ipv4-edns-size{COLON}  { LEXOUT(("v(%s) ", yytext)); return VAR_IPV4_EDNS_SIZE;}
 ipv6-edns-size{COLON}  { LEXOUT(("v(%s) ", yytext)); return VAR_IPV6_EDNS_SIZE;}
 pidfile{COLON}         { LEXOUT(("v(%s) ", yytext)); return VAR_PIDFILE;}
index 36a3ddd..1d824d1 100644 (file)
@@ -51,6 +51,7 @@ extern config_parser_state_t* cfg_parser;
 %token VAR_CHROOT VAR_USERNAME VAR_ZONESDIR VAR_XFRDFILE VAR_DIFFFILE
 %token VAR_XFRD_RELOAD_TIMEOUT VAR_TCP_QUERY_COUNT VAR_TCP_TIMEOUT
 %token VAR_IPV4_EDNS_SIZE VAR_IPV6_EDNS_SIZE VAR_DO_IP4 VAR_DO_IP6
+%token VAR_TCP_MSS VAR_OUTGOING_TCP_MSS VAR_IP_FREEBIND
 %token VAR_ZONEFILE 
 %token VAR_ZONE
 %token VAR_ALLOW_NOTIFY VAR_REQUEST_XFR VAR_NOTIFY VAR_PROVIDE_XFR 
@@ -93,11 +94,12 @@ content_server: server_ip_address | server_ip_transparent | server_debug_mode |
        server_tcp_query_count | server_tcp_timeout | server_ipv4_edns_size |
        server_ipv6_edns_size | server_verbosity | server_hide_version |
        server_zonelistfile | server_xfrdir |
+       server_tcp_mss | server_outgoing_tcp_mss |
        server_rrl_size | server_rrl_ratelimit | server_rrl_slip | 
        server_rrl_ipv4_prefix_length | server_rrl_ipv6_prefix_length | server_rrl_whitelist_ratelimit |
        server_zonefiles_check | server_do_ip4 | server_do_ip6 |
        server_zonefiles_write | server_log_time_ascii | server_round_robin |
-       server_reuseport | server_version;
+       server_reuseport | server_version | server_ip_freebind;
 server_ip_address: VAR_IP_ADDRESS STRING 
        { 
                OUTYY(("P(server_ip_address:%s)\n", $2)); 
@@ -128,6 +130,14 @@ server_ip_transparent: VAR_IP_TRANSPARENT STRING
                else cfg_parser->opt->ip_transparent = (strcmp($2, "yes")==0);
        }
        ;
+server_ip_freebind: VAR_IP_FREEBIND STRING 
+       { 
+               OUTYY(("P(server_ip_freebind:%s)\n", $2)); 
+               if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+                       yyerror("expected yes or no.");
+               else cfg_parser->opt->ip_freebind = (strcmp($2, "yes")==0);
+       }
+       ;
 server_debug_mode: VAR_DEBUG_MODE STRING 
        { 
                OUTYY(("P(server_debug_mode:%s)\n", $2)); 
@@ -381,6 +391,22 @@ server_tcp_timeout: VAR_TCP_TIMEOUT STRING
                cfg_parser->opt->tcp_timeout = atoi($2);
        }
        ;
+server_tcp_mss: VAR_TCP_MSS STRING
+       {
+               OUTYY(("P(server_tcp_mss:%s)\n", $2));
+               if(atoi($2) == 0 && strcmp($2, "0") != 0)
+                       yyerror("number expected");
+               cfg_parser->opt->tcp_mss = atoi($2);
+       }
+       ;
+server_outgoing_tcp_mss: VAR_OUTGOING_TCP_MSS STRING
+       {
+               OUTYY(("P(server_outgoing_tcp_mss:%s)\n", $2));
+               if(atoi($2) == 0 && strcmp($2, "0") != 0)
+                       yyerror("number expected");
+               cfg_parser->opt->outgoing_tcp_mss = atoi($2);
+       }
+       ;
 server_ipv4_edns_size: VAR_IPV4_EDNS_SIZE STRING
        { 
                OUTYY(("P(server_ipv4_edns_size:%s)\n", $2)); 
index c04deac..4c451bd 100644 (file)
@@ -4,7 +4,7 @@ dnl
 
 sinclude(acx_nlnetlabs.m4)
 
-AC_INIT(NSD,4.1.7,nsd-bugs@nlnetlabs.nl)
+AC_INIT(NSD,4.1.10,nsd-bugs@nlnetlabs.nl)
 AC_CONFIG_HEADER([config.h])
 
 CFLAGS="$CFLAGS"
@@ -415,7 +415,7 @@ fi
 # Checks for header files.
 AC_HEADER_STDC
 AC_HEADER_SYS_WAIT
-AC_CHECK_HEADERS([time.h arpa/inet.h signal.h string.h strings.h fcntl.h limits.h netinet/in.h stddef.h sys/param.h sys/socket.h syslog.h unistd.h sys/select.h stdarg.h stdint.h netdb.h sys/bitypes.h tcpd.h glob.h grp.h endian.h])
+AC_CHECK_HEADERS([time.h arpa/inet.h signal.h string.h strings.h fcntl.h limits.h netinet/in.h netinet/tcp.h stddef.h sys/param.h sys/socket.h syslog.h unistd.h sys/select.h stdarg.h stdint.h netdb.h sys/bitypes.h tcpd.h glob.h grp.h endian.h])
 
 AC_DEFUN([CHECK_VALIST_DEF],
 [
@@ -585,6 +585,7 @@ AC_CHECK_TYPE(in_addr_t, [], [AC_DEFINE([in_addr_t], [uint32_t], [in_addr_t])],
 # include <netinet/in.h>
 #endif])
 ACX_CHECK_SS_FAMILY
+AC_CHECK_MEMBERS([struct stat.st_mtimensec, struct stat.st_mtim.tv_nsec])
 
 # Checks for library functions.
 AC_FUNC_CHOWN
@@ -596,9 +597,9 @@ AC_SYS_LARGEFILE
 AC_CHECK_SIZEOF(void*)
 AC_CHECK_SIZEOF(off_t)
 AC_CHECK_FUNCS([arc4random arc4random_uniform])
-AC_CHECK_FUNCS([tzset alarm chroot dup2 endpwent gethostname memset memcpy pwrite socket strcasecmp strchr strdup strerror strncasecmp strtol writev getaddrinfo getnameinfo freeaddrinfo gai_strerror sigaction sigprocmask strptime strftime localtime_r setusercontext glob initgroups setresuid setreuid setresgid setregid getpwnam mmap ppoll])
+AC_CHECK_FUNCS([tzset alarm chroot dup2 endpwent gethostname memset memcpy pwrite socket strcasecmp strchr strdup strerror strncasecmp strtol writev getaddrinfo getnameinfo freeaddrinfo gai_strerror sigaction sigprocmask strptime strftime localtime_r setusercontext glob initgroups setresuid setreuid setresgid setregid getpwnam mmap ppoll clock_gettime])
 
-AC_ARG_ENABLE(recvmmsg, AC_HELP_STRING([--enable-recvmmsg], [Enable recvmmsg and sendmmsg compilation, faster but some kernel versions may have implementation problems]))
+AC_ARG_ENABLE(recvmmsg, AC_HELP_STRING([--enable-recvmmsg], [Enable recvmmsg and sendmmsg compilation, faster but some kernel versions may have implementation problems for IPv6]))
 case "$enable_recvmmsg" in
         yes)
                AC_CHECK_FUNC([recvmmsg], [
@@ -829,8 +830,30 @@ AC_SUBST(ratelimit_default)
 CHECK_SSL
 if test x$HAVE_SSL = x"yes"; then
        ACX_LIB_SSL
+
+       # Check for -pthread
+       BAKLIBS="$LIBS"
+       LIBS="-lcrypto $LIBS"
+       AC_TRY_LINK([], [
+               int HMAC_Update(void);
+               (void)HMAC_Update();
+       ], [],[
+               dnl so link fails for HMAC_Update, try with -pthread.
+               BAKCFLAGS="$CFLAGS"
+               CFLAGS="$CFLAGS -pthread"
+               AC_MSG_CHECKING([if libcrypto needs -pthread])
+               AC_TRY_LINK_FUNC([HMAC_Update], [
+                       AC_MSG_RESULT([yes])
+               ] , [
+                       AC_MSG_RESULT([no])
+                       dnl restore the nonpthread value
+                       CFLAGS="$BAKCFLAGS"
+               ])
+       ])
+       LIBS="$BAKLIBS"
+
        if test -n "$ssldir"; then 
-            AC_CHECK_LIB(crypto, HMAC_CTX_init,, [
+            AC_CHECK_LIB(crypto, HMAC_Update,, [
                     AC_MSG_ERROR([OpenSSL found in $ssldir, but version 0.9.7 or higher is required])
                 ])
        fi
@@ -839,6 +862,7 @@ 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])
 else
        AC_MSG_WARN([No SSL, therefore remote-control is disabled])
 fi
@@ -894,6 +918,9 @@ AH_BOTTOM([
 #  ifndef _BSD_SOURCE
 #    define _BSD_SOURCE 1
 #  endif
+#  ifndef _DEFAULT_SOURCE
+#    define _DEFAULT_SOURCE 1
+#  endif
 #  ifndef __EXTENSIONS__
 #    define __EXTENSIONS__ 1
 #  endif 
@@ -938,6 +965,10 @@ AH_BOTTOM([
 #include <netinet/in.h>
 #endif
 
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+
 #ifdef HAVE_ARPA_INET_H
 #include <arpa/inet.h>
 #endif
index 86891f2..cc49a51 100644 (file)
@@ -271,7 +271,8 @@ namedb_zone_create(namedb_type* db, const dname_type* dname,
        zone->opts = zo;
        zone->filename = NULL;
        zone->logstr = NULL;
-       zone->mtime = 0;
+       zone->mtime.tv_sec = 0;
+       zone->mtime.tv_nsec = 0;
        zone->zonestatid = 0;
        zone->is_secure = 0;
        zone->is_changed = 0;
@@ -491,17 +492,25 @@ namedb_open (const char* filename, nsd_options_t* opt)
 }
 
 /** the the file mtime stat (or nonexist or error) */
-static int
-file_get_mtime(const char* file, time_t* mtime, int* nonexist)
+int
+file_get_mtime(const char* file, struct timespec* mtime, int* nonexist)
 {
        struct stat s;
        if(stat(file, &s) != 0) {
-               *mtime = 0;
+               mtime->tv_sec = 0;
+               mtime->tv_nsec = 0;
                *nonexist = (errno == ENOENT);
                return 0;
        }
        *nonexist = 0;
-       *mtime = s.st_mtime;
+       mtime->tv_sec = s.st_mtime;
+#ifdef HAVE_STRUCT_STAT_ST_MTIMENSEC
+       mtime->tv_nsec = s.st_mtimensec;
+#elif defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
+       mtime->tv_nsec = s.st_mtim.tv_nsec;
+#else
+       mtime->tv_nsec = 0;
+#endif
        return 1;
 }
 
@@ -509,12 +518,14 @@ void
 namedb_read_zonefile(struct nsd* nsd, struct zone* zone, udb_base* taskudb,
        udb_ptr* last_task)
 {
-       time_t mtime = 0;
+       struct timespec mtime;
        int nonexist = 0;
        unsigned int errors;
        const char* fname;
        if(!nsd->db || !zone || !zone->opts || !zone->opts->pattern->zonefile)
                return;
+       mtime.tv_sec = 0;
+       mtime.tv_nsec = 0;
        fname = config_make_zonefile(zone->opts, nsd);
        if(!file_get_mtime(fname, &mtime, &nonexist)) {
                if(nonexist) {
@@ -527,20 +538,21 @@ namedb_read_zonefile(struct nsd* nsd, struct zone* zone, udb_base* taskudb,
                return;
        } else {
                const char* zone_fname = zone->filename;
-               time_t zone_mtime = zone->mtime;
+               struct timespec zone_mtime = zone->mtime;
                if(nsd->db->udb) {
                        zone_fname = udb_zone_get_file_str(nsd->db->udb,
                                dname_name(domain_dname(zone->apex)),
                                domain_dname(zone->apex)->name_size);
-                       zone_mtime = (time_t)udb_zone_get_mtime(nsd->db->udb,
+                       udb_zone_get_mtime(nsd->db->udb,
                                dname_name(domain_dname(zone->apex)),
-                               domain_dname(zone->apex)->name_size);
+                               domain_dname(zone->apex)->name_size,
+                               &zone_mtime);
                }
                /* if no zone_fname, then it was acquired in zone transfer,
                 * see if the file is newer than the zone transfer
                 * (regardless if this is a different file), because the
                 * zone transfer is a different content source too */
-               if(!zone_fname && zone_mtime >= mtime) {
+               if(!zone_fname && timespec_compare(&zone_mtime, &mtime) >= 0) {
                        VERBOSITY(3, (LOG_INFO, "zonefile %s is older than "
                                "zone transfer in memory", fname));
                        return;
@@ -548,7 +560,8 @@ namedb_read_zonefile(struct nsd* nsd, struct zone* zone, udb_base* taskudb,
                /* if zone_fname, then the file was acquired from reading it,
                 * and see if filename changed or mtime newer to read it */
                } else if(zone_fname && fname &&
-                  strcmp(zone_fname, fname) == 0 && zone_mtime >= mtime) {
+                  strcmp(zone_fname, fname) == 0 &&
+                  timespec_compare(&zone_mtime, &mtime) == 0) {
                        VERBOSITY(3, (LOG_INFO, "zonefile %s is not modified",
                                fname));
                        return;
@@ -614,7 +627,8 @@ namedb_read_zonefile(struct nsd* nsd, struct zone* zone, udb_base* taskudb,
                zone->is_changed = 0;
                /* store zone into udb */
                if(nsd->db->udb) {
-                       if(!write_zone_to_udb(nsd->db->udb, zone, mtime, fname)) {
+                       if(!write_zone_to_udb(nsd->db->udb, zone, &mtime,
+                               fname)) {
                                log_msg(LOG_ERR, "failed to store zone in db");
                        } else {
                                VERBOSITY(2, (LOG_INFO, "zone %s written to db",
index 24866af..ce21491 100644 (file)
@@ -146,7 +146,7 @@ write_zone(udb_base* udb, udb_ptr* z, zone_type* zone)
 
 /** create and write a zone */
 int
-write_zone_to_udb(udb_base* udb, zone_type* zone, time_t mtime,
+write_zone_to_udb(udb_base* udb, zone_type* zone, struct timespec* mtime,
        const char* file_str)
 {
        udb_ptr z;
@@ -165,7 +165,8 @@ write_zone_to_udb(udb_base* udb, zone_type* zone, time_t mtime,
                }
        }
        /* set mtime */
-       ZONE(&z)->mtime = (uint64_t)mtime;
+       ZONE(&z)->mtime = (uint64_t)mtime->tv_sec;
+       ZONE(&z)->mtime_nsec = (uint64_t)mtime->tv_nsec;
        ZONE(&z)->is_changed = 0;
        udb_zone_set_log_str(udb, &z, NULL);
        udb_zone_set_file_str(udb, &z, file_str);
@@ -350,6 +351,7 @@ namedb_write_zonefile(struct nsd* nsd, zone_options_t* zopt)
        if(notexist || zone->is_changed) {
                char logs[4096];
                char bakfile[4096];
+               struct timespec mtime;
                udb_ptr zudb;
                if(nsd->db->udb) {
                        if(!udb_zone_search(nsd->db->udb, &zudb,
@@ -384,13 +386,19 @@ namedb_write_zonefile(struct nsd* nsd, zone_options_t* zopt)
                        return;
                }
                zone->is_changed = 0;
+               /* fetch the mtime of the just created zonefile so we
+                * do not waste effort reading it back in */
+               if(!file_get_mtime(zfile, &mtime, &notexist)) {
+                       get_time(&mtime);
+               }
                if(nsd->db->udb) {
-                       ZONE(&zudb)->mtime = (uint64_t)time(0);
+                       ZONE(&zudb)->mtime = (uint64_t)mtime.tv_sec;
+                       ZONE(&zudb)->mtime_nsec = (uint64_t)mtime.tv_nsec;
                        ZONE(&zudb)->is_changed = 0;
                        udb_zone_set_log_str(nsd->db->udb, &zudb, NULL);
                        udb_ptr_unlink(&zudb, nsd->db->udb);
                } else {
-                       zone->mtime = time(0);
+                       zone->mtime = mtime;
                        if(zone->filename)
                                region_recycle(nsd->db->region, zone->filename,
                                        strlen(zone->filename)+1);
index 4196f79..b2325c5 100644 (file)
@@ -1378,11 +1378,13 @@ apply_ixfr_for_zone(nsd_type* nsd, zone_type* zonedb, FILE* in,
                if(nsd->db->udb) {
                        ZONE(&z)->is_changed = 1;
                        ZONE(&z)->mtime = time_end_0;
+                       ZONE(&z)->mtime_nsec = time_end_1*1000;
                        udb_zone_set_log_str(nsd->db->udb, &z, log_buf);
                        udb_zone_set_file_str(nsd->db->udb, &z, NULL);
                        udb_ptr_unlink(&z, nsd->db->udb);
                } else {
-                       zonedb->mtime = time_end_0;
+                       zonedb->mtime.tv_sec = time_end_0;
+                       zonedb->mtime.tv_nsec = time_end_1*1000;
                        if(zonedb->logstr)
                                region_recycle(nsd->db->region, zonedb->logstr,
                                        strlen(zonedb->logstr)+1);
index 2ba99d3..037cd4c 100644 (file)
@@ -300,7 +300,8 @@ static rrtype_descriptor_type rrtype_descriptors[(RRTYPE_DESCRIPTORS_LENGTH+1)]
        /* 61 */
        { 61, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } },
        /* 62 */
-       { 62, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } },
+       { 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 */
        { 63, NULL, T_UTYPE, 1, 1, { RDATA_WF_BINARY }, { RDATA_ZF_UNKNOWN } },
        /* 64 */
index 3e9e88c..810cd70 100644 (file)
@@ -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_CSYNC     62      /* RFC 7477 */
 
 #define TYPE_SPF        99      /* RFC 4408 */
 
index 96aec38..db90965 100644 (file)
@@ -561,6 +561,18 @@ domain_find_ns_rrsets(domain_type* domain, zone_type* zone, rrset_type **ns)
        return NULL;
 }
 
+domain_type *
+find_dname_above(domain_type* domain, zone_type* zone)
+{
+       domain_type* d = domain->parent;
+       while(d && d != zone->apex) {
+               if(domain_find_rrset(d, zone, TYPE_DNAME))
+                       return d;
+               d = d->parent;
+       }
+       return NULL;
+}
+
 int
 domain_is_glue(domain_type* domain, zone_type* zone)
 {
index d264c68..ca46477 100644 (file)
@@ -127,7 +127,7 @@ struct zone
        struct zone_options* opts;
        char*        filename; /* set if read from file, which file */
        char*        logstr; /* set for zone xfer, the log string */
-       time_t       mtime; /* time of last modification */
+       struct timespec mtime; /* time of last modification */
        unsigned     zonestatid; /* array index for zone stats */
        unsigned     is_secure : 1; /* zone uses DNSSEC */
        unsigned     is_ok : 1; /* zone has not expired. */
@@ -235,6 +235,8 @@ zone_type* domain_find_zone(namedb_type* db, domain_type* domain);
 zone_type* domain_find_parent_zone(zone_type* zone);
 
 domain_type* domain_find_ns_rrsets(domain_type* domain, zone_type* zone, rrset_type **ns);
+/* find DNAME rrset in domain->parent or higher and return that domain */
+domain_type * find_dname_above(domain_type* domain, zone_type* zone);
 
 int domain_is_glue(domain_type* domain, zone_type* zone);
 
@@ -326,8 +328,8 @@ void domain_table_deldomain(namedb_type* db, domain_type* domain);
 /** dbcreate.c */
 int udb_write_rr(struct udb_base* udb, struct udb_ptr* z, rr_type* rr);
 void udb_del_rr(struct udb_base* udb, struct udb_ptr* z, rr_type* rr);
-int write_zone_to_udb(struct udb_base* udb, zone_type* zone, time_t mtime,
-       const char* file_str);
+int write_zone_to_udb(struct udb_base* udb, zone_type* zone,
+       struct timespec* mtime, const char* file_str);
 /** marshal rdata into buffer, must be MAX_RDLENGTH in size */
 size_t rr_marshal_rdata(rr_type* rr, uint8_t* rdata, size_t sz);
 /* dbaccess.c */
@@ -354,6 +356,7 @@ void namedb_zone_delete(namedb_type* db, zone_type* zone);
 void namedb_write_zonefile(struct nsd* nsd, struct zone_options* zopt);
 void namedb_write_zonefiles(struct nsd* nsd, struct nsd_options* options);
 int create_dirs(const char* path);
+int file_get_mtime(const char* file, struct timespec* mtime, int* nonexist);
 void allocate_domain_nsec3(domain_table_type *table, domain_type *result);
 
 static inline int
index 9bf8306..2425e69 100644 (file)
@@ -1,4 +1,4 @@
-.TH "nsd\-checkconf" "8" "Dec 10, 2015" "NLnet Labs" "nsd 4.1.7"
+.TH "nsd\-checkconf" "8" "Jun 14, 2016" "NLnet Labs" "nsd 4.1.10"
 .\" Copyright (c) 2001\-2008, NLnet Labs. All rights reserved.
 .\" See LICENSE for the license.
 .SH "NAME"
index 6cbe71e..e5f669f 100644 (file)
@@ -341,6 +341,7 @@ config_print_zone(nsd_options_t* opt, const char* k, int s, const char *o,
                SERV_GET_IP(ip_address, ip_addresses, o);
                /* bin */
                SERV_GET_BIN(ip_transparent, o);
+               SERV_GET_BIN(ip_freebind, o);
                SERV_GET_BIN(debug_mode, o);
                SERV_GET_BIN(do_ip4, o);
                SERV_GET_BIN(do_ip6, o);
@@ -368,6 +369,8 @@ config_print_zone(nsd_options_t* opt, const char* k, int s, const char *o,
                SERV_GET_INT(tcp_count, o);
                SERV_GET_INT(tcp_query_count, o);
                SERV_GET_INT(tcp_timeout, o);
+               SERV_GET_INT(tcp_mss, o);
+               SERV_GET_INT(outgoing_tcp_mss, o);
                SERV_GET_INT(ipv4_edns_size, o);
                SERV_GET_INT(ipv6_edns_size, o);
                SERV_GET_INT(statistics, o);
@@ -442,6 +445,7 @@ config_test_print_server(nsd_options_t* opt)
        printf("server:\n");
        printf("\tdebug-mode: %s\n", opt->debug_mode?"yes":"no");
        printf("\tip-transparent: %s\n", opt->ip_transparent?"yes":"no");
+       printf("\tip-freebind: %s\n", opt->ip_freebind?"yes":"no");
        printf("\treuseport: %s\n", opt->reuseport?"yes":"no");
        printf("\tdo-ip4: %s\n", opt->do_ip4?"yes":"no");
        printf("\tdo-ip6: %s\n", opt->do_ip6?"yes":"no");
@@ -451,10 +455,12 @@ config_test_print_server(nsd_options_t* opt)
        print_string_var("version:", opt->version);
        print_string_var("nsid:", opt->nsid);
        print_string_var("logfile:", opt->logfile);
-       printf("\tserver_count: %d\n", opt->server_count);
-       printf("\ttcp_count: %d\n", opt->tcp_count);
-       printf("\ttcp_query_count: %d\n", opt->tcp_query_count);
-       printf("\ttcp_timeout: %d\n", opt->tcp_timeout);
+       printf("\tserver-count: %d\n", opt->server_count);
+       printf("\ttcp-count: %d\n", opt->tcp_count);
+       printf("\ttcp-query-count: %d\n", opt->tcp_query_count);
+       printf("\ttcp-timeout: %d\n", opt->tcp_timeout);
+       printf("\ttcp-mss: %d\n", opt->tcp_mss);
+       printf("\toutgoing-tcp-mss: %d\n", opt->outgoing_tcp_mss);
        printf("\tipv4-edns-size: %d\n", (int) opt->ipv4_edns_size);
        printf("\tipv6-edns-size: %d\n", (int) opt->ipv6_edns_size);
        print_string_var("pidfile:", opt->pidfile);
@@ -466,7 +472,7 @@ config_test_print_server(nsd_options_t* opt)
        print_string_var("xfrdfile:", opt->xfrdfile);
        print_string_var("zonelistfile:", opt->zonelistfile);
        print_string_var("xfrdir:", opt->xfrdir);
-       printf("\txfrd_reload_timeout: %d\n", opt->xfrd_reload_timeout);
+       printf("\txfrd-reload-timeout: %d\n", opt->xfrd_reload_timeout);
        printf("\tlog-time-ascii: %s\n", opt->log_time_ascii?"yes":"no");
        printf("\tround-robin: %s\n", opt->round_robin?"yes":"no");
        printf("\tverbosity: %d\n", opt->verbosity);
index f58e0da..2be9443 100644 (file)
@@ -1,4 +1,4 @@
-.TH "nsd\-checkzone" "8" "Dec 10, 2015" "NLnet Labs" "nsd 4.1.7"
+.TH "nsd\-checkzone" "8" "Jun 14, 2016" "NLnet Labs" "nsd 4.1.10"
 .\" Copyright (c) 2014, NLnet Labs. All rights reserved.
 .\" See LICENSE for the license.
 .SH "NAME"
index 4f6a590..bf8d90d 100644 (file)
@@ -1,4 +1,4 @@
-.TH "nsd\-control" "8" "Dec 10, 2015" "NLnet Labs" "nsd 4.1.7"
+.TH "nsd\-control" "8" "Jun 14, 2016" "NLnet Labs" "nsd 4.1.10"
 .\" Copyright (c) 2011, NLnet Labs. All rights reserved.
 .\" See LICENSE for the license.
 .SH "NAME"
index 0ef0cfa..89afd9c 100644 (file)
@@ -1,9 +1,9 @@
-.TH "NSD" "8" "Dec 10, 2015" "NLnet Labs" "NSD 4.1.7"
+.TH "NSD" "8" "Jun 14, 2016" "NLnet Labs" "NSD 4.1.10"
 .\" Copyright (c) 2001\-2008, NLnet Labs. All rights reserved.
 .\" See LICENSE for the license.
 .SH "NAME"
 .B nsd
-\- Name Server Daemon (NSD) version 4.1.7.
+\- Name Server Daemon (NSD) version 4.1.10.
 .SH "SYNOPSIS"
 .B nsd
 .RB [ \-4 ] 
@@ -115,7 +115,7 @@ Do not fork, stay in the foreground.
 Use the specified
 .I database
 instead of the default of
-.IR @dbfile@ .
+.IR '@dbfile@' .
 If a 
 .B zonesdir: 
 is specified in the config file this path can be relative to that 
@@ -224,7 +224,7 @@ SIGUSR1
 Dump BIND8\-style statistics into the log. Ignored otherwise.
 .SH "FILES"
 .TP
-@dbfile@
+"@dbfile@"
 default
 .B NSD
 database
index 3f35f11..f964386 100644 (file)
@@ -681,6 +681,8 @@ main(int argc, char *argv[])
        }
        nsd.tcp_timeout = nsd.options->tcp_timeout;
        nsd.tcp_query_count = nsd.options->tcp_query_count;
+       nsd.tcp_mss = nsd.options->tcp_mss;
+       nsd.outgoing_tcp_mss = nsd.options->outgoing_tcp_mss;
        nsd.ipv4_edns_size = nsd.options->ipv4_edns_size;
        nsd.ipv6_edns_size = nsd.options->ipv6_edns_size;
 
@@ -909,6 +911,7 @@ main(int argc, char *argv[])
                        VERBOSITY(2, (LOG_WARNING, "chown %s failed: %s",
                                nsd.log_filename, strerror(errno)));
        }
+       log_msg(LOG_NOTICE, "%s starting (%s)", argv0, PACKAGE_STRING);
 
        /* Do we have a running nsd? */
        if ((oldpid = readpid(nsd.pidfile)) == -1) {
index 2fe1bf4..44493c7 100644 (file)
@@ -1,4 +1,4 @@
-.TH "nsd.conf" "5" "Dec 10, 2015" "NLnet Labs" "nsd 4.1.7"
+.TH "nsd.conf" "5" "Jun 14, 2016" "NLnet Labs" "nsd 4.1.10"
 .\" Copyright (c) 2001\-2008, NLnet Labs. All rights reserved.
 .\" See LICENSE for the license.
 .SH "NAME"
@@ -169,6 +169,10 @@ Allows NSD to bind to non local addresses. This is useful to have NSD
 listen to IP addresses that are not (yet) added to the network interface, so
 that it can answer immediately when the address is added. Default is no.
 .TP
+.B ip\-freebind:\fR <yes or no>
+Set the IP_FREEBIND option to bind to nonlocal addresses and interfaces
+that are down.  Similar to ip\-transparent.  Default is no.
+.TP
 .B reuseport:\fR <yes or no>
 Use the SO_REUSEPORT socket option, and create file descriptors for every
 server in the server\-count.  This improves performance of the network
@@ -193,7 +197,7 @@ If yes, NSD listens to IPv6 connections.  Default yes.
 .TP
 .B database:\fR <filename>
 By default 
-.I @dbfile@
+.I '@dbfile@'
 is used. The specified file is used to store the compiled 
 zone information. Same as commandline option 
 .BR \-f.
@@ -247,6 +251,23 @@ Default is 0, meaning there is no maximum.
 .B tcp\-timeout:\fR <number>
 Overrides the default TCP timeout. This also affects zone transfers over TCP.
 .TP
+.B tcp-mss:\fR <number>
+Maximum segment size (MSS) of TCP socket on which the server responds
+to queries. Value lower than common MSS on Ethernet 
+(1220 for example) will address path MTU problem.
+Note that not all platform supports socket option to set MSS (TCP_MAXSEG).
+Default is system default MSS determined by interface MTU and
+negotiation between server and client.
+.TP
+.B outgoing\-tcp\-mss:\fR <number>
+Maximum segment size (MSS) of TCP socket for outgoing XFR request
+to other namesevers. Value lower than
+common MSS on Ethernet (1220 for example) will
+address path MTU problem.
+Note that not all platform supports socket option to set MSS (TCP_MAXSEG).
+Default is system default MSS determined by interface MTU and
+negotiation between NSD and other servers.
+.TP
 .B ipv4\-edns\-size:\fR <number>
 Preferred EDNS buffer size for IPv4.  Default 4096.
 .TP
@@ -795,7 +816,7 @@ also function as a resolver or cache. The configuration options that
 BIND9 has for the resolver or caching thus have no equivalents for NSD.
 .SH "FILES"
 .TP
-@dbfile@
+"@dbfile@"
 default
 .B NSD
 database
index a78548e..48eef14 100644 (file)
@@ -27,6 +27,9 @@ server:
        # Allow binding to non local addresses. Default no.
        # ip-transparent: no
 
+       # Allow binding to addresses that are down.  Default no.
+       # ip-freebind: no
+
        # use the reuseport socket option for performance. Default no.
        # reuseport: no
 
@@ -102,6 +105,14 @@ server:
        # Override the default (120 seconds) TCP timeout.
        # tcp-timeout: 120
 
+       # Maximum segment size (MSS) of TCP socket on which the server
+       # responds to queries. Default is 0, system default MSS.
+       # tcp-mss: 0
+
+       # Maximum segment size (MSS) of TCP socket for outgoing AXFR request.
+       # Default is 0, system default MSS.
+       # outgoing-tcp-mss: 0
+
        # Preferred EDNS buffer size for IPv4.
        # ipv4-edns-size: 4096
 
index 8ebf1a2..290b065 100644 (file)
@@ -223,6 +223,8 @@ struct      nsd
        int current_tcp_count;
        int tcp_query_count;
        int tcp_timeout;
+       int tcp_mss;
+       int outgoing_tcp_mss;
        size_t ipv4_edns_size;
        size_t ipv6_edns_size;
 
index 92802bd..d4fd1a2 100644 (file)
@@ -965,9 +965,20 @@ nsec3_answer_nodata(struct query* query, struct answer* answer,
                                original->nsec3->nsec3_cover);
        }
        else {  /* add nsec3 to prove rrset does not exist */
-               if(original->nsec3 && original->nsec3->nsec3_is_exact) {
+               if(original->nsec3) {
+                       if(!original->nsec3->nsec3_is_exact) {
+                               /* go up to an existing parent */
+                               while(original->parent && original->parent->nsec3 && !original->parent->nsec3->nsec3_is_exact)
+                                       original = original->parent;
+                       }
                        nsec3_add_rrset(query, answer, AUTHORITY_SECTION,
                                original->nsec3->nsec3_cover);
+                       if(!original->nsec3->nsec3_is_exact) {
+                               if(original->parent && original->parent->nsec3 && original->parent->nsec3->nsec3_is_exact)
+                                   nsec3_add_rrset(query, answer, AUTHORITY_SECTION,
+                                       original->parent->nsec3->nsec3_cover);
+
+                       }
                }
        }
 }
@@ -1041,7 +1052,8 @@ nsec3_answer_authoritative(struct domain** match, struct query *query,
 #if 0
                query->qtype != TYPE_NSEC3 &&
 #endif
-               domain_has_only_NSEC3(*match, query->zone))
+               (domain_has_only_NSEC3(*match, query->zone) ||
+               !domain_find_any_rrset(*match, query->zone)))
        {
                /* this looks like a NSEC3 domain, but is actually an empty non-terminal. */
                nsec3_answer_nodata(query, answer, *match);
index 8896851..349e271 100644 (file)
@@ -49,6 +49,7 @@ nsd_options_create(region_type* region)
        opt->keys = rbtree_create(region, rbtree_strcmp);
        opt->ip_addresses = NULL;
        opt->ip_transparent = 0;
+       opt->ip_freebind = 0;
        opt->debug_mode = 0;
        opt->verbosity = 0;
        opt->hide_version = 0;
@@ -65,6 +66,8 @@ nsd_options_create(region_type* region)
        opt->tcp_count = 100;
        opt->tcp_query_count = 0;
        opt->tcp_timeout = TCP_TIMEOUT;
+       opt->tcp_mss = 0;
+       opt->outgoing_tcp_mss = 0;
        opt->ipv4_edns_size = EDNS_MAX_MESSAGE_LEN;
        opt->ipv6_edns_size = EDNS_MAX_MESSAGE_LEN;
        opt->pidfile = PIDFILE;
index 34ed295..ceba624 100644 (file)
@@ -60,6 +60,7 @@ struct nsd_options {
        ip_address_option_t* ip_addresses;
 
        int ip_transparent;
+       int ip_freebind;
        int debug_mode;
        int verbosity;
        int hide_version;
@@ -73,6 +74,8 @@ struct nsd_options {
        int tcp_count;
        int tcp_query_count;
        int tcp_timeout;
+       int tcp_mss;
+       int outgoing_tcp_mss;
        size_t ipv4_edns_size;
        size_t ipv6_edns_size;
        const char* pidfile;
index 4f26112..f8a429c 100644 (file)
@@ -609,6 +609,12 @@ struct additional_rr_types default_additional_rr_types[] = {
        { 0, (rr_section_type) 0 }
 };
 
+struct additional_rr_types swap_aaaa_additional_rr_types[] = {
+       { TYPE_AAAA, ADDITIONAL_A_SECTION },
+       { TYPE_A, ADDITIONAL_AAAA_SECTION },
+       { 0, (rr_section_type) 0 }
+};
+
 struct additional_rr_types rt_additional_rr_types[] = {
        { TYPE_A, ADDITIONAL_A_SECTION },
        { TYPE_AAAA, ADDITIONAL_AAAA_SECTION },
@@ -698,8 +704,11 @@ add_rrset(struct query   *query,
        result = answer_add_rrset(answer, section, owner, rrset);
        switch (rrset_rrtype(rrset)) {
        case TYPE_NS:
+               /* if query over IPv6, swap A and AAAA; put AAAA first */
                add_additional_rrsets(query, answer, rrset, 0, 1,
-                                     default_additional_rr_types);
+                       (query->addr.ss_family == AF_INET6)?
+                       swap_aaaa_additional_rr_types:
+                       default_additional_rr_types);
                break;
        case TYPE_MB:
                add_additional_rrsets(query, answer, rrset, 0, 0,
@@ -960,9 +969,6 @@ answer_domain(struct nsd* nsd, struct query *q, answer_type *answer,
                        zone_type* origzone = q->zone;
                        ++q->cname_count;
 
-                       while (!closest_encloser->is_existing)
-                               closest_encloser = closest_encloser->parent;
-
                        answer_lookup_zone(nsd, q, answer, closest_match->number,
                                             closest_match == closest_encloser,
                                             closest_match, closest_encloser,
@@ -1003,6 +1009,7 @@ answer_authoritative(struct nsd   *nsd,
 {
        domain_type *match;
        domain_type *original = closest_match;
+       domain_type *dname_ce;
        rrset_type *rrset;
 
 #ifdef NSEC3
@@ -1012,6 +1019,11 @@ answer_authoritative(struct nsd   *nsd,
                        closest_encloser = closest_encloser->parent;
        }
 #endif /* NSEC3 */
+       if((dname_ce = find_dname_above(closest_encloser, q->zone)) != NULL) {
+               /* occlude the found data, the DNAME is closest_encloser */
+               closest_encloser = dname_ce;
+               exact = 0;
+       }
 
        if (exact) {
                match = closest_match;
@@ -1053,8 +1065,6 @@ answer_authoritative(struct nsd   *nsd,
                                return;
                        }
 
-                       while (closest_encloser && !closest_encloser->is_existing)
-                               closest_encloser = closest_encloser->parent;
                        answer_lookup_zone(nsd, q, answer, newnum,
                                closest_match == closest_encloser,
                                closest_match, closest_encloser, newname);
@@ -1176,6 +1186,14 @@ answer_lookup_zone(struct nsd *nsd, struct query *q, answer_type *answer,
                        RCODE_SET(q->packet, RCODE_SERVFAIL);
                return;
        }
+       /* now move up the closest encloser until it exists, previous
+        * (possibly empty) closest encloser was useful to finding the zone
+        * (for empty zones too), but now we want actual data nodes */
+       if (closest_encloser && !closest_encloser->is_existing) {
+               exact = 0;
+               while (closest_encloser != NULL && !closest_encloser->is_existing)
+                       closest_encloser = closest_encloser->parent;
+       }
 
        /*
         * See RFC 4035 (DNSSEC protocol) section 3.1.4.1 Responding
@@ -1214,6 +1232,9 @@ answer_lookup_zone(struct nsd *nsd, struct query *q, answer_type *answer,
        } else {
                q->delegation_domain = domain_find_ns_rrsets(
                        closest_encloser, q->zone, &q->delegation_rrset);
+               if(q->delegation_domain && find_dname_above(q->delegation_domain, q->zone)) {
+                       q->delegation_domain = NULL; /* use higher DNAME */
+               }
 
                if (!q->delegation_domain
                    || (exact && q->qtype == TYPE_DS && closest_encloser == q->delegation_domain))
@@ -1244,15 +1265,6 @@ answer_query(struct nsd *nsd, struct query *q)
        answer_init(&answer);
 
        exact = namedb_lookup(nsd->db, q->qname, &closest_match, &closest_encloser);
-       if (!closest_encloser->is_existing) {
-               exact = 0;
-               while (closest_encloser != NULL && !closest_encloser->is_existing)
-                       closest_encloser = closest_encloser->parent;
-       }
-       if(!closest_encloser) {
-               RCODE_SET(q->packet, RCODE_SERVFAIL);
-               return;
-       }
 
        answer_lookup_zone(nsd, q, &answer, 0, exact, closest_match,
                closest_encloser, q->qname);
index 8358ea5..2a7ca4f 100644 (file)
@@ -449,7 +449,9 @@ int rrl_process_query(query_type* query)
 query_state_type rrl_slip(query_type* query)
 {
        /* discard number the packets, randomly */
-#ifdef HAVE_ARC4RANDOM
+#ifdef HAVE_ARC4RANDOM_UNIFORM
+       if((rrl_slip_ratio > 0) && ((rrl_slip_ratio == 1) || ((arc4random_uniform(rrl_slip_ratio)) == 0))) {
+#elif HAVE_ARC4RANDOM
        if((rrl_slip_ratio > 0) && ((rrl_slip_ratio == 1) || ((arc4random() % rrl_slip_ratio) == 0))) {
 #else
        if((rrl_slip_ratio > 0) && ((rrl_slip_ratio == 1) || ((random() % rrl_slip_ratio) == 0))) {
index 2b3be10..530b443 100644 (file)
@@ -560,7 +560,7 @@ server_init_ifs(struct nsd *nsd, size_t from, size_t to, int* reuseport_works)
 {
        struct addrinfo* addr;
        size_t i;
-#if defined(SO_REUSEPORT) || defined(SO_REUSEADDR) || (defined(INET6) && (defined(IPV6_V6ONLY) || defined(IPV6_USE_MIN_MTU) || defined(IPV6_MTU) || defined(IP_TRANSPARENT)))
+#if defined(SO_REUSEPORT) || defined(SO_REUSEADDR) || (defined(INET6) && (defined(IPV6_V6ONLY) || defined(IPV6_USE_MIN_MTU) || defined(IPV6_MTU) || defined(IP_TRANSPARENT)) || defined(IP_FREEBIND))
        int on = 1;
 #endif
 
@@ -734,6 +734,15 @@ server_init_ifs(struct nsd *nsd, size_t from, size_t to, int* reuseport_works)
                }
 
                /* Bind it... */
+               if (nsd->options->ip_freebind) {
+#ifdef IP_FREEBIND
+                       if (setsockopt(nsd->udp[i].s, IPPROTO_IP, IP_FREEBIND, &on, sizeof(on)) < 0) {
+                               log_msg(LOG_ERR, "setsockopt(...,IP_FREEBIND, ...) failed for udp: %s",
+                                       strerror(errno));
+                       }
+#endif /* IP_FREEBIND */
+               }
+
                if (nsd->options->ip_transparent) {
 #ifdef IP_TRANSPARENT
                        if (setsockopt(nsd->udp[i].s, IPPROTO_IP, IP_TRANSPARENT, &on, sizeof(on)) < 0) {
@@ -832,6 +841,21 @@ server_init_ifs(struct nsd *nsd, size_t from, size_t to, int* reuseport_works)
 # endif
                }
 #endif
+               /* set maximum segment size to tcp socket */
+               if(nsd->tcp_mss > 0) {
+#if defined(IPPROTO_TCP) && defined(TCP_MAXSEG)
+                       if(setsockopt(nsd->tcp[i].s, IPPROTO_TCP, TCP_MAXSEG,
+                                       (void*)&nsd->tcp_mss,
+                                       sizeof(nsd->tcp_mss)) < 0) {
+                               log_msg(LOG_ERR,
+                                       "setsockopt(...,TCP_MAXSEG,...)"
+                                       " failed for tcp: %s", strerror(errno));
+                       }
+#else
+                       log_msg(LOG_ERR, "setsockopt(TCP_MAXSEG) unsupported");
+#endif /* defined(IPPROTO_TCP) && defined(TCP_MAXSEG) */
+               }
+
                /* set it nonblocking */
                /* (StevensUNP p463), if tcp listening socket is blocking, then
                   it may block in accept, even if select() says readable. */
@@ -840,6 +864,15 @@ server_init_ifs(struct nsd *nsd, size_t from, size_t to, int* reuseport_works)
                }
 
                /* Bind it... */
+               if (nsd->options->ip_freebind) {
+#ifdef IP_FREEBIND
+                       if (setsockopt(nsd->tcp[i].s, IPPROTO_IP, IP_FREEBIND, &on, sizeof(on)) < 0) {
+                               log_msg(LOG_ERR, "setsockopt(...,IP_FREEBIND, ...) failed for tcp: %s",
+                                       strerror(errno));
+                       }
+#endif /* IP_FREEBIND */
+               }
+
                if (nsd->options->ip_transparent) {
 #ifdef IP_TRANSPARENT
                        if (setsockopt(nsd->tcp[i].s, IPPROTO_IP, IP_TRANSPARENT, &on, sizeof(on)) < 0) {
@@ -2395,7 +2428,10 @@ cleanup_tcp_handler(struct tcp_handler_data* data)
         */
        if (slowaccept || data->nsd->current_tcp_count == data->nsd->maximum_tcp_count) {
                configure_handler_event_types(EV_READ|EV_PERSIST);
-               slowaccept = 0;
+               if(slowaccept) {
+                       event_del(&slowaccept_event);
+                       slowaccept = 0;
+               }
        }
        --data->nsd->current_tcp_count;
        assert(data->nsd->current_tcp_count >= 0);
index 1088573..62203dc 100644 (file)
@@ -83,16 +83,28 @@ static void
 cleanup_context(void *data)
 {
        HMAC_CTX *context = (HMAC_CTX *) data;
+#ifdef HAVE_HMAC_CTX_NEW
+       HMAC_CTX_free(context);
+#else
        HMAC_CTX_cleanup(context);
+       free(context);
+#endif
 }
 
 static void *
 create_context(region_type *region)
 {
-       HMAC_CTX *context
-               = (HMAC_CTX *) region_alloc(region, sizeof(HMAC_CTX));
+#ifdef HAVE_HMAC_CTX_NEW
+       HMAC_CTX *context = HMAC_CTX_new();
+#else
+       HMAC_CTX *context = (HMAC_CTX *) malloc(sizeof(HMAC_CTX));
+#endif
        region_add_cleanup(region, cleanup_context, context);
+#ifdef HAVE_HMAC_CTX_RESET
+       HMAC_CTX_reset(context);
+#else
        HMAC_CTX_init(context);
+#endif
        return context;
 }
 
index 049760d..4cbe403 100644 (file)
@@ -342,7 +342,7 @@ struct udb_alloc {
 /** magic string that starts an UDB file, uint64_t, note first byte=0, to mark
  * header start as a chunk. */
 #define UDB_MAGIC (((uint64_t)'u'<<48)|((uint64_t)'d'<<40)|((uint64_t)'b' \
-       <<32)|((uint64_t)'v'<<24)|((uint64_t)'0'<<16)|((uint64_t)'a'<<8))
+       <<32)|((uint64_t)'v'<<24)|((uint64_t)'0'<<16)|((uint64_t)'b'<<8))
 
 /* UDB BASE */
 /**
index 67de2db..30f1c4b 100644 (file)
@@ -95,6 +95,7 @@ udb_zone_create(udb_base* udb, udb_ptr* result, const uint8_t* dname,
        ZONE(&z)->rr_count = 0;
        ZONE(&z)->expired = 0;
        ZONE(&z)->mtime = 0;
+       ZONE(&z)->mtime_nsec = 0;
        ZONE(&z)->namelen = dlen;
        memmove(ZONE(&z)->name, dname, dlen);
        if(!udb_radix_tree_create(udb, &dtree)) {
@@ -222,6 +223,7 @@ udb_zone_clear(udb_base* udb, udb_ptr* zone)
        ZONE(zone)->rr_count = 0;
        ZONE(zone)->expired = 0;
        ZONE(zone)->mtime = 0;
+       ZONE(zone)->mtime_nsec = 0;
        udb_ptr_unlink(&dtree, udb);
 }
 
@@ -255,15 +257,18 @@ udb_zone_search(udb_base* udb, udb_ptr* result, const uint8_t* dname,
        return 0;
 }
 
-uint64_t udb_zone_get_mtime(udb_base* udb, const uint8_t* dname, size_t dlen)
+void udb_zone_get_mtime(udb_base* udb, const uint8_t* dname, size_t dlen,
+       struct timespec* mtime)
 {
        udb_ptr z;
        if(udb_zone_search(udb, &z, dname, dlen)) {
-               uint64_t t = ZONE(&z)->mtime;
+               mtime->tv_sec = ZONE(&z)->mtime;
+               mtime->tv_nsec = ZONE(&z)->mtime_nsec;
                udb_ptr_unlink(&z, udb);
-               return t;
+               return;
        }
-       return 0;
+       mtime->tv_sec = 0;
+       mtime->tv_nsec = 0;
 }
 
 void udb_zone_set_log_str(udb_base* udb, udb_ptr* zone, const char* str)
index eb81675..8169857 100644 (file)
@@ -39,6 +39,8 @@ struct zone_d {
        udb_rel_ptr file_str;
        /** modification time, time when the zone data was changed */
        uint64_t mtime;
+       /** modification time, nsecs */
+       uint64_t mtime_nsec;
        /** number of RRsets in the zone */
        uint64_t rrset_count;
        /** number of RRs in the zone */
@@ -107,7 +109,8 @@ void udb_zone_delete(udb_base* udb, udb_ptr* zone);
 int udb_zone_search(udb_base* udb, udb_ptr* result, const uint8_t* dname,
        size_t dlen);
 /** get modification time for zone or 0 */
-uint64_t udb_zone_get_mtime(udb_base* udb, const uint8_t* dname, size_t dlen);
+void udb_zone_get_mtime(udb_base* udb, const uint8_t* dname, size_t dlen,
+       struct timespec* mtime);
 /** set log str in udb, or remove it */
 void udb_zone_set_log_str(udb_base* udb, udb_ptr* zone, const char* str);
 /** set file str in udb, or remove it */
index ff54eda..db3d7ce 100644 (file)
@@ -393,6 +393,28 @@ write_socket(int s, const void *buf, size_t size)
        return 1;
 }
 
+void get_time(struct timespec* t)
+{
+       struct timeval tv;
+#ifdef HAVE_CLOCK_GETTIME
+       /* first try nanosecond precision */
+       if(clock_gettime(CLOCK_REALTIME, t)>=0) {
+               return; /* success */
+       }
+       log_msg(LOG_ERR, "clock_gettime: %s", strerror(errno));
+#endif
+       /* try millisecond precision */
+       if(gettimeofday(&tv, NULL)>=0) {
+               t->tv_sec = tv.tv_sec;
+               t->tv_nsec = tv.tv_usec*1000;
+               return; /* success */
+       }
+       log_msg(LOG_ERR, "gettimeofday: %s", strerror(errno));
+       /* whole seconds precision */
+       t->tv_sec = time(0);
+       t->tv_nsec = 0;
+}
+
 int
 timespec_compare(const struct timespec *left,
                 const struct timespec *right)
index 5c572e3..702674f 100644 (file)
@@ -269,6 +269,8 @@ timeval_to_timespec(struct timespec *left,
        left->tv_nsec = 1000 * right->tv_usec;
 }
 
+/* get the time */
+void get_time(struct timespec* t);
 
 /*
  * Converts a string representation of a period of time into
index 2949e5a..9bc01d3 100644 (file)
@@ -13,6 +13,7 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <stdlib.h>
+#include "nsd.h"
 #include "xfrd-tcp.h"
 #include "buffer.h"
 #include "packet.h"
@@ -524,6 +525,19 @@ xfrd_tcp_open(xfrd_tcp_set_t* set, struct xfrd_tcp_pipeline* tp,
                return 0;
        }
 
+       if(xfrd->nsd->outgoing_tcp_mss > 0) {
+#if defined(IPPROTO_TCP) && defined(TCP_MAXSEG)
+               if(setsockopt(fd, IPPROTO_TCP, TCP_MAXSEG,
+                       (void*)&xfrd->nsd->outgoing_tcp_mss,
+                       sizeof(xfrd->nsd->outgoing_tcp_mss)) < 0) {
+                       log_msg(LOG_ERR, "xfrd: setsockopt(TCP_MAXSEG)"
+                                       "failed: %s", strerror(errno));
+               }
+#else
+               log_msg(LOG_ERR, "setsockopt(TCP_MAXSEG) unsupported");
+#endif
+       }
+
        tp->ip_len = xfrd_acl_sockaddr_to(zone->master, &tp->ip);
 
        /* bind it */
index 0413f4e..c2c75ed 100644 (file)
@@ -724,9 +724,12 @@ xfrd_set_timer_retry(xfrd_zone_t* zone)
                /* if no information, use reasonable timeout */
                if(zone->fresh_xfr_timeout == 0)
                        zone->fresh_xfr_timeout = XFRD_TRANSFER_TIMEOUT_START;
-#ifdef HAVE_ARC4RANDOM
+#ifdef HAVE_ARC4RANDOM_UNIFORM
                xfrd_set_timer(zone, zone->fresh_xfr_timeout
-                       + arc4random()%zone->fresh_xfr_timeout);
+                       + arc4random_uniform(zone->fresh_xfr_timeout));
+#elif HAVE_ARC4RANDOM
+               xfrd_set_timer(zone, zone->fresh_xfr_timeout
+                        + arc4random() % zone->fresh_xfr_timeout);
 #else
                xfrd_set_timer(zone, zone->fresh_xfr_timeout
                        + random()%zone->fresh_xfr_timeout);
@@ -1045,8 +1048,10 @@ xfrd_set_timer(xfrd_zone_t* zone, time_t t)
        /* only for times far in the future */
        if(t > 10) {
                time_t base = t*9/10;
-#ifdef HAVE_ARC4RANDOM
-               t = base + arc4random()%(t-base);
+#ifdef HAVE_ARC4RANDOM_UNIFORM
+               t = base + arc4random_uniform(t-base);
+#elif HAVE_ARC4RANDOM
+               t = base + arc4random() % (t-base);
 #else
                t = base + random()%(t-base);
 #endif
index 6640400..d823478 100644 (file)
@@ -68,6 +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
 
 /* other tokens */
 %token        DOLLAR_TTL DOLLAR_ORIGIN NL SP
@@ -632,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_CSYNC sp rdata_csync
+    |  T_CSYNC sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
     |  T_URI sp rdata_uri
     |  T_URI sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
     |  T_UTYPE sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
@@ -1050,6 +1053,17 @@ rdata_caa:       STR sp STR sp STR trail
     }
     ;
 
+/* RFC7477 */
+rdata_csync:   STR sp STR nsec_seq
+    {
+           zadd_rdata_wireformat(zparser_conv_serial(parser->region, $1.str));
+           zadd_rdata_wireformat(zparser_conv_short(parser->region, $3.str));
+           zadd_rdata_wireformat(zparser_conv_nsec(parser->region, nsecbits)); /* nsec bitlist */
+           memset(nsecbits, 0, sizeof(nsecbits));
+            nsec_highest_rcode = 0;
+    }
+    ;
+
 rdata_unknown: URR sp STR sp str_sp_seq trail
     {
            /* $2 is the number of octets, currently ignored */