diff options
-rw-r--r-- | usr.sbin/nsd/Makefile.in | 34 | ||||
-rw-r--r-- | usr.sbin/nsd/config.h.in | 16 | ||||
-rw-r--r-- | usr.sbin/nsd/configparser.y | 39 | ||||
-rw-r--r-- | usr.sbin/nsd/configure | 64 | ||||
-rw-r--r-- | usr.sbin/nsd/configure.ac | 28 | ||||
-rw-r--r-- | usr.sbin/nsd/dname.c | 2 | ||||
-rw-r--r-- | usr.sbin/nsd/dns.c | 79 | ||||
-rw-r--r-- | usr.sbin/nsd/lookup3.c | 11 | ||||
-rw-r--r-- | usr.sbin/nsd/nsd-checkconf.8.in | 7 | ||||
-rw-r--r-- | usr.sbin/nsd/nsd-checkconf.c | 6 | ||||
-rw-r--r-- | usr.sbin/nsd/nsd.8.in | 11 | ||||
-rw-r--r-- | usr.sbin/nsd/nsd.c | 2 | ||||
-rw-r--r-- | usr.sbin/nsd/nsd.conf.5.in | 118 | ||||
-rw-r--r-- | usr.sbin/nsd/nsec3.c | 70 | ||||
-rw-r--r-- | usr.sbin/nsd/rrl.c | 6 | ||||
-rw-r--r-- | usr.sbin/nsd/server.c | 118 | ||||
-rw-r--r-- | usr.sbin/nsd/util.c | 107 | ||||
-rw-r--r-- | usr.sbin/nsd/util.h | 7 | ||||
-rw-r--r-- | usr.sbin/nsd/xfrd-disk.c | 19 | ||||
-rw-r--r-- | usr.sbin/nsd/xfrd-tcp.c | 4 | ||||
-rw-r--r-- | usr.sbin/nsd/xfrd.c | 166 | ||||
-rw-r--r-- | usr.sbin/nsd/zparser.y | 6 |
22 files changed, 694 insertions, 226 deletions
diff --git a/usr.sbin/nsd/Makefile.in b/usr.sbin/nsd/Makefile.in index bb28f891f79..fffb32cf99d 100644 --- a/usr.sbin/nsd/Makefile.in +++ b/usr.sbin/nsd/Makefile.in @@ -67,14 +67,15 @@ EDIT = sed \ -e 's,@shell\@,$(SHELL),g' \ -e 's,@user\@,$(user),g' -TARGETS=nsd nsd-checkconf nsd-control nsd.conf.sample nsd-control-setup.sh -MANUALS=nsd.8 nsd-checkconf.8 nsd-control.8 nsd.conf.5 +TARGETS=nsd nsd-checkconf nsd-checkzone nsd-control nsd.conf.sample nsd-control-setup.sh +MANUALS=nsd.8 nsd-checkconf.8 nsd-checkzone.8 nsd-control.8 nsd.conf.5 COMMON_OBJ=answer.o axfr.o buffer.o configlexer.o configparser.o dname.o dns.o edns.o iterated_hash.o lookup3.o namedb.o nsec3.o options.o packet.o query.o rbtree.o radtree.o rdata.o region-allocator.o rrl.o tsig.o tsig-openssl.o udb.o udbradtree.o udbzone.o util.o XFRD_OBJ=xfrd-disk.o xfrd-notify.o xfrd-tcp.o xfrd.o remote.o NSD_OBJ=$(COMMON_OBJ) $(XFRD_OBJ) difffile.o ipc.o mini_event.o netio.o nsd.o server.o dbaccess.o dbcreate.o zlexer.o zonec.o zparser.o -ALL_OBJ=$(NSD_OBJ) nsd-checkconf.o nsd-control.o nsd-mem.o +ALL_OBJ=$(NSD_OBJ) nsd-checkconf.o nsd-checkzone.o nsd-control.o nsd-mem.o NSD_CHECKCONF_OBJ=$(COMMON_OBJ) nsd-checkconf.o +NSD_CHECKZONE_OBJ=$(COMMON_OBJ) $(XFRD_OBJ) dbaccess.o dbcreate.o difffile.o ipc.o mini_event.o netio.o server.o zonec.o zparser.o zlexer.o nsd-checkzone.o NSD_CONTROL_OBJ=$(COMMON_OBJ) nsd-control.o CUTEST_OBJ=$(COMMON_OBJ) $(XFRD_OBJ) dbaccess.o dbcreate.o difffile.o ipc.o mini_event.o netio.o server.o zonec.o zparser.o zlexer.o cutest_dname.o cutest_dns.o cutest_iterated_hash.o cutest_run.o cutest_radtree.o cutest_rbtree.o cutest_namedb.o cutest_options.o cutest_region.o cutest_rrl.o cutest_udb.o cutest_udbrad.o cutest_util.o cutest.o qtest.o NSD_MEM_OBJ=$(COMMON_OBJ) $(XFRD_OBJ) dbaccess.o dbcreate.o difffile.o ipc.o mini_event.o netio.o server.o zonec.o zparser.o zlexer.o nsd-mem.o @@ -104,6 +105,10 @@ nsd-checkconf.8: $(srcdir)/nsd-checkconf.8.in config.h rm -f nsd-checkconf.8 $(EDIT) $(srcdir)/nsd-checkconf.8.in > nsd-checkconf.8 +nsd-checkzone.8: $(srcdir)/nsd-checkzone.8.in config.h + rm -f nsd-checkzone.8 + $(EDIT) $(srcdir)/nsd-checkzone.8.in > nsd-checkzone.8 + nsd-control.8: $(srcdir)/nsd-control.8.in config.h rm -f nsd-control.8 $(EDIT) $(srcdir)/nsd-control.8.in > nsd-control.8 @@ -122,18 +127,20 @@ orig-install: all $(INSTALL) nsd $(DESTDIR)$(sbindir)/nsd $(INSTALL) nsd-control-setup.sh $(DESTDIR)$(sbindir)/nsd-control-setup $(INSTALL) nsd-checkconf $(DESTDIR)$(sbindir)/nsd-checkconf + $(INSTALL) nsd-checkzone $(DESTDIR)$(sbindir)/nsd-checkzone $(INSTALL) nsd-control $(DESTDIR)$(sbindir)/nsd-control - $(INSTALL_DATA) $(srcdir)/nsd.8 $(DESTDIR)$(mandir)/man8 - $(INSTALL_DATA) $(srcdir)/nsd-checkconf.8 $(DESTDIR)$(mandir)/man8/nsd-checkconf.8 - $(INSTALL_DATA) $(srcdir)/nsd-control.8 $(DESTDIR)$(mandir)/man8/nsd-control.8 - $(INSTALL_DATA) $(srcdir)/nsd.conf.5 $(DESTDIR)$(mandir)/man5/nsd.conf.5 + $(INSTALL_DATA) nsd.8 $(DESTDIR)$(mandir)/man8 + $(INSTALL_DATA) nsd-checkconf.8 $(DESTDIR)$(mandir)/man8/nsd-checkconf.8 + $(INSTALL_DATA) nsd-checkzone.8 $(DESTDIR)$(mandir)/man8/nsd-checkzone.8 + $(INSTALL_DATA) nsd-control.8 $(DESTDIR)$(mandir)/man8/nsd-control.8 + $(INSTALL_DATA) nsd.conf.5 $(DESTDIR)$(mandir)/man5/nsd.conf.5 $(INSTALL_DATA) nsd.conf.sample $(DESTDIR)$(nsdconfigfile).sample uninstall: @echo - rm -f -- $(DESTDIR)$(sbindir)/nsd $(DESTDIR)$(sbindir)/nsd-control-setup $(DESTDIR)$(sbindir)/nsd-checkconf $(DESTDIR)$(sbindir)/nsd-control + rm -f -- $(DESTDIR)$(sbindir)/nsd $(DESTDIR)$(sbindir)/nsd-control-setup $(DESTDIR)$(sbindir)/nsd-checkconf $(DESTDIR)$(sbindir)/nsd-checkzone $(DESTDIR)$(sbindir)/nsd-control rm -f -- $(DESTDIR)$(mandir)/man8/nsd.8 $(DESTDIR)$(mandir)/man5/nsd.conf.5 - rm -f -- $(DESTDIR)$(mandir)/man8/nsd-checkconf.8 $(DESTDIR)$(mandir)/man8/nsd-control.8 + rm -f -- $(DESTDIR)$(mandir)/man8/nsd-checkconf.8 $(DESTDIR)$(mandir)/man8/nsd-checkzone.8 $(DESTDIR)$(mandir)/man8/nsd-control.8 rm -f -- $(DESTDIR)$(pidfile) @echo @echo "You still need to remove $(DESTDIR)$(configdir), $(DESTDIR)$(piddir), $(DESTDIR)$(dbfile) directory by hand." @@ -146,6 +153,9 @@ nsd: $(NSD_OBJ) $(LIBOBJS) nsd-checkconf: $(NSD_CHECKCONF_OBJ) $(LIBOBJS) $(LINK) -o $@ $(NSD_CHECKCONF_OBJ) $(LIBOBJS) $(LIBS) +nsd-checkzone: $(NSD_CHECKZONE_OBJ) $(LIBOBJS) + $(LINK) -o $@ $(NSD_CHECKZONE_OBJ) $(LIBOBJS) $(SSL_LIBS) $(LIBS) + nsd-control: $(NSD_CONTROL_OBJ) $(LIBOBJS) $(LINK) -o $@ $(NSD_CONTROL_OBJ) $(LIBOBJS) $(SSL_LIBS) $(LIBS) @@ -367,6 +377,9 @@ nsd.o: $(srcdir)/nsd.c config.h $(srcdir)/nsd.h $(srcdir)/dns.h $(srcdir)/edns.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 +nsd-checkzone.o: $(srcdir)/nsd-checkzone.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)/zonec.h $(srcdir)/namedb.h $(srcdir)/dname.h \ + $(srcdir)/radtree.h nsd-control.o: $(srcdir)/nsd-control.c config.h $(srcdir)/util.h $(srcdir)/tsig.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/dname.h $(srcdir)/options.h $(srcdir)/rbtree.h nsd-mem.o: $(srcdir)/nsd-mem.c config.h $(srcdir)/nsd.h $(srcdir)/dns.h $(srcdir)/edns.h $(srcdir)/buffer.h \ @@ -475,7 +488,8 @@ cutest_rrl.o: $(srcdir)/tpkg/cutest/cutest_rrl.c config.h $(srcdir)/tpkg/cutest/ $(srcdir)/rrl.h $(srcdir)/query.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 $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/packet.h $(srcdir)/tsig.h cutest_run.o: $(srcdir)/tpkg/cutest/cutest_run.c config.h $(srcdir)/tpkg/cutest/cutest.h \ - $(srcdir)/tpkg/cutest/qtest.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h + $(srcdir)/tpkg/cutest/qtest.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/nsd.h $(srcdir)/dns.h \ + $(srcdir)/edns.h $(srcdir)/buffer.h cutest_udb.o: $(srcdir)/tpkg/cutest/cutest_udb.c config.h $(srcdir)/tpkg/cutest/cutest.h \ $(srcdir)/udb.h cutest_udbrad.o: $(srcdir)/tpkg/cutest/cutest_udbrad.c config.h \ diff --git a/usr.sbin/nsd/config.h.in b/usr.sbin/nsd/config.h.in index d80388b00bb..d9df0f4ce22 100644 --- a/usr.sbin/nsd/config.h.in +++ b/usr.sbin/nsd/config.h.in @@ -64,6 +64,9 @@ /* Define to 1 if you have the `dup2' function. */ #undef HAVE_DUP2 +/* Define to 1 if you have the <endian.h> header file. */ +#undef HAVE_ENDIAN_H + /* Define to 1 if you have the `endpwent' function. */ #undef HAVE_ENDPWENT @@ -121,6 +124,12 @@ /* Define to 1 if you have the `getpwnam' function. */ #undef HAVE_GETPWNAM +/* Define to 1 if you have the `glob' function. */ +#undef HAVE_GLOB + +/* Define to 1 if you have the <glob.h> header file. */ +#undef HAVE_GLOB_H + /* Define to 1 if you have the <grp.h> header file. */ #undef HAVE_GRP_H @@ -145,6 +154,9 @@ /* Define to 1 if you have the <limits.h> header file. */ #undef HAVE_LIMITS_H +/* Define to 1 if you have the `localtime_r' function. */ +#undef HAVE_LOCALTIME_R + /* Define to 1 if your system has a GNU libc compatible `malloc' function, and to 0 otherwise. */ #undef HAVE_MALLOC @@ -254,6 +266,9 @@ /* Define to 1 if you have the `strerror' function. */ #undef HAVE_STRERROR +/* Define to 1 if you have the `strftime' function. */ +#undef HAVE_STRFTIME + /* Define to 1 if you have the <strings.h> header file. */ #undef HAVE_STRINGS_H @@ -733,6 +748,7 @@ char *strptime(const char *s, const char *format, struct tm *tm); #endif #ifndef STRPTIME_WORKS #define STRPTIME_WORKS 1 +char *nsd_strptime(const char *s, const char *format, struct tm *tm); #define strptime(a,b,c) nsd_strptime((a),(b),(c)) #endif diff --git a/usr.sbin/nsd/configparser.y b/usr.sbin/nsd/configparser.y index 7a1edc7c620..61a76df3630 100644 --- a/usr.sbin/nsd/configparser.y +++ b/usr.sbin/nsd/configparser.y @@ -66,7 +66,8 @@ extern config_parser_state_t* cfg_parser; %token VAR_RRL_SIZE VAR_RRL_RATELIMIT VAR_RRL_SLIP %token VAR_RRL_IPV4_PREFIX_LENGTH VAR_RRL_IPV6_PREFIX_LENGTH %token VAR_RRL_WHITELIST_RATELIMIT VAR_RRL_WHITELIST -%token VAR_ZONEFILES_CHECK +%token VAR_ZONEFILES_CHECK VAR_ZONEFILES_WRITE VAR_LOG_TIME_ASCII +%token VAR_ROUND_ROBIN %% toplevelvars: /* empty */ | toplevelvars toplevelvar ; @@ -94,7 +95,8 @@ content_server: server_ip_address | server_ip_transparent | server_debug_mode | server_zonelistfile | server_xfrdir | 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_check | server_do_ip4 | server_do_ip6 | + server_zonefiles_write | server_log_time_ascii | server_round_robin; server_ip_address: VAR_IP_ADDRESS STRING { OUTYY(("P(server_ip_address:%s)\n", $2)); @@ -193,6 +195,9 @@ server_database: VAR_DATABASE STRING { OUTYY(("P(server_database:%s)\n", $2)); cfg_parser->opt->database = region_strdup(cfg_parser->opt->region, $2); + if(cfg_parser->opt->database[0] == 0 && + cfg_parser->opt->zonefiles_write == 0) + cfg_parser->opt->zonefiles_write = ZONEFILES_WRITE_INTERVAL; } ; server_identity: VAR_IDENTITY STRING @@ -231,6 +236,28 @@ server_logfile: VAR_LOGFILE STRING cfg_parser->opt->logfile = region_strdup(cfg_parser->opt->region, $2); } ; +server_log_time_ascii: VAR_LOG_TIME_ASCII STRING + { + OUTYY(("P(server_log_time_ascii:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else { + cfg_parser->opt->log_time_ascii = (strcmp($2, "yes")==0); + log_time_asc = cfg_parser->opt->log_time_ascii; + } + } + ; +server_round_robin: VAR_ROUND_ROBIN STRING + { + OUTYY(("P(server_round_robin:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else { + cfg_parser->opt->round_robin = (strcmp($2, "yes")==0); + round_robin = cfg_parser->opt->round_robin; + } + } + ; server_server_count: VAR_SERVER_COUNT STRING { OUTYY(("P(server_server_count:%s)\n", $2)); @@ -413,6 +440,14 @@ server_zonefiles_check: VAR_ZONEFILES_CHECK STRING else cfg_parser->opt->zonefiles_check = (strcmp($2, "yes")==0); } ; +server_zonefiles_write: VAR_ZONEFILES_WRITE STRING + { + OUTYY(("P(server_zonefiles_write:%s)\n", $2)); + if(atoi($2) == 0 && strcmp($2, "0") != 0) + yyerror("number expected"); + else cfg_parser->opt->zonefiles_write = atoi($2); + } + ; rcstart: VAR_REMOTE_CONTROL { diff --git a/usr.sbin/nsd/configure b/usr.sbin/nsd/configure index d2d28c195d8..b4cce0cec78 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.0.3. +# Generated by GNU Autoconf 2.69 for NSD 4.1.0. # # 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.0.3' -PACKAGE_STRING='NSD 4.0.3' +PACKAGE_VERSION='4.1.0' +PACKAGE_STRING='NSD 4.1.0' PACKAGE_BUGREPORT='nsd-bugs@nlnetlabs.nl' PACKAGE_URL='' @@ -1279,7 +1279,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.0.3 to adapt to many kinds of systems. +\`configure' configures NSD 4.1.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1340,7 +1340,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of NSD 4.0.3:";; + short | recursive ) echo "Configuration of NSD 4.1.0:";; esac cat <<\_ACEOF @@ -1474,7 +1474,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -NSD configure 4.0.3 +NSD configure 4.1.0 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2183,7 +2183,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.0.3, which was +It was created by NSD $as_me 4.1.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2534,6 +2534,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers config.h" +CFLAGS="$CFLAGS" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -4937,24 +4938,24 @@ test -n "$YACC" || YACC="yacc" # Checks for typedefs, structures, and compiler characteristics. -# if cflags not set by user, check O3, then O2, else elide O2 flag -if test "x$ac_cv_env_CFLAGS_set" = "x"; then +# allow user to override the -g -O2 flags. +if test "x$CFLAGS" = "x" ; then -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -O3" >&5 -$as_echo_n "checking whether $CC supports -O3... " >&6; } -cache=`echo O3 | sed 'y%.=/+-%___p_%'` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -g" >&5 +$as_echo_n "checking whether $CC supports -g... " >&6; } +cache=`echo g | sed 'y%.=/+-%___p_%'` if eval \${cv_prog_cc_flag_$cache+:} false; then : $as_echo_n "(cached) " >&6 else -echo 'void f(){}' >conftest.c -if test -z "`$CC -O3 -c conftest.c 2>&1`"; then +echo 'void f(void){}' >conftest.c +if test -z "`$CC $CPPFLAGS $CFLAGS -g -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" else eval "cv_prog_cc_flag_$cache=no" fi -rm -f conftest* +rm -f conftest conftest.o conftest.c fi @@ -4962,15 +4963,15 @@ if eval "test \"`echo '$cv_prog_cc_flag_'$cache`\" = yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } : - - CFLAGS=`echo $CFLAGS | sed -e "s/-O2//g"`" -O3" - CFLAGS=`echo $CFLAGS` - +CFLAGS="$CFLAGS -g" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } : +fi + + # we do not use O3 because it causes miscompilations. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -O2" >&5 @@ -4980,13 +4981,13 @@ if eval \${cv_prog_cc_flag_$cache+:} false; then : $as_echo_n "(cached) " >&6 else -echo 'void f(){}' >conftest.c -if test -z "`$CC -O2 -c conftest.c 2>&1`"; then +echo 'void f(void){}' >conftest.c +if test -z "`$CC $CPPFLAGS $CFLAGS -O2 -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" else eval "cv_prog_cc_flag_$cache=no" fi -rm -f conftest* +rm -f conftest conftest.o conftest.c fi @@ -4994,18 +4995,14 @@ if eval "test \"`echo '$cv_prog_cc_flag_'$cache`\" = yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } : - +CFLAGS="$CFLAGS -O2" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } : - CFLAGS=`echo $CFLAGS | sed -e "s/-O2//g"` -fi - fi -fi # Check whether --enable-flto was given. if test "${enable_flto+set}" = set; then : @@ -5050,6 +5047,7 @@ rm -f core conftest.err conftest.$ac_objext \ fi +fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 $as_echo_n "checking for an ANSI C-conforming const... " >&6; } if ${ac_cv_c_const+:} false; then : @@ -5900,7 +5898,7 @@ $as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h fi -for ac_header in 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 grp.h +for ac_header in 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 do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" @@ -6116,7 +6114,7 @@ else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#define _XOPEN_SOURCE +#define _XOPEN_SOURCE 600 #include <time.h> int main(void) { struct tm tm; char *res; res = strptime("20070207111842", "%Y%m%d%H%M%S", &tm); @@ -7794,7 +7792,7 @@ _ACEOF fi done -for ac_func in 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 setusercontext initgroups setresuid setreuid setresgid setregid getpwnam mmap +for ac_func in 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 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" @@ -8197,7 +8195,7 @@ cat >>confdefs.h <<_ACEOF _ACEOF -max_ips=8 +max_ips=16 # Check whether --with-max_ips was given. if test "${with_max_ips+set}" = set; then : @@ -9372,7 +9370,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.0.3, which was +This file was extended by NSD $as_me 4.1.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -9434,7 +9432,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.0.3 +NSD config.status 4.1.0 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 03fff3d815c..cb48dd92137 100644 --- a/usr.sbin/nsd/configure.ac +++ b/usr.sbin/nsd/configure.ac @@ -4,9 +4,10 @@ dnl sinclude(acx_nlnetlabs.m4) -AC_INIT(NSD,4.0.3,nsd-bugs@nlnetlabs.nl) +AC_INIT(NSD,4.1.0,nsd-bugs@nlnetlabs.nl) AC_CONFIG_HEADER([config.h]) +CFLAGS="$CFLAGS" AC_AIX if test "$ac_cv_header_minix_config_h" = "yes"; then AC_DEFINE(_NETBSD_SOURCE,1, [Enable for compile on Minix]) @@ -258,17 +259,13 @@ fi ])dnl # Checks for typedefs, structures, and compiler characteristics. -# if cflags not set by user, check O3, then O2, else elide O2 flag -if test "x$ac_cv_env_CFLAGS_set" = "x"; then - CHECK_COMPILER_FLAG(O3, [ - CFLAGS=`echo $CFLAGS | sed -e "s/-O2//g"`" -O3" - dnl remove double spaces - CFLAGS=`echo $CFLAGS` - ], [ - CHECK_COMPILER_FLAG(O2, [], [ CFLAGS=`echo $CFLAGS | sed -e "s/-O2//g"` ]) - ]) +# allow user to override the -g -O2 flags. +if test "x$CFLAGS" = "x" ; then + ACX_CHECK_COMPILER_FLAG(g, [CFLAGS="$CFLAGS -g"]) + # we do not use O3 because it causes miscompilations. + ACX_CHECK_COMPILER_FLAG(O2, [CFLAGS="$CFLAGS -O2"]) + ACX_CHECK_FLTO fi -ACX_CHECK_FLTO AC_C_CONST AC_C_INLINE AC_TYPE_UID_T @@ -401,7 +398,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 grp.h]) +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_DEFUN([CHECK_VALIST_DEF], [ @@ -465,7 +462,7 @@ AC_DEFUN([AC_CHECK_STRPTIME_WORKS], AC_MSG_CHECKING(whether strptime works) if test c${cross_compiling} = cno; then AC_RUN_IFELSE([AC_LANG_SOURCE([[ -#define _XOPEN_SOURCE +#define _XOPEN_SOURCE 600 #include <time.h> int main(void) { struct tm tm; char *res; res = strptime("20070207111842", "%Y%m%d%H%M%S", &tm); @@ -582,7 +579,7 @@ 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 setusercontext initgroups setresuid setreuid setresgid setregid getpwnam mmap]) +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]) AC_ARG_ENABLE(recvmmsg, AC_HELP_STRING([--enable-recvmmsg], [Enable recvmmsg and sendmmsg compilation, faster but some kernel versions may have implementation problems])) case "$enable_recvmmsg" in @@ -691,7 +688,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=8 +max_ips=16 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]) @@ -960,6 +957,7 @@ char *strptime(const char *s, const char *format, struct tm *tm); #endif #ifndef STRPTIME_WORKS #define STRPTIME_WORKS 1 +char *nsd_strptime(const char *s, const char *format, struct tm *tm); #define strptime(a,b,c) nsd_strptime((a),(b),(c)) #endif ]) diff --git a/usr.sbin/nsd/dname.c b/usr.sbin/nsd/dname.c index a2971982506..22d17221b95 100644 --- a/usr.sbin/nsd/dname.c +++ b/usr.sbin/nsd/dname.c @@ -530,7 +530,7 @@ char* wiredname2str(const uint8_t* dname) while(lablen) { while(lablen--) { uint8_t ch = *dname++; - if (isalnum(ch) || ch == '-' || ch == '_') { + if (isalnum(ch) || ch == '-' || ch == '_' || ch == '*') { *p++ = ch; } else if (ch == '.' || ch == '\\') { *p++ = '\\'; diff --git a/usr.sbin/nsd/dns.c b/usr.sbin/nsd/dns.c index 29552b8051c..a54fc9871c0 100644 --- a/usr.sbin/nsd/dns.c +++ b/usr.sbin/nsd/dns.c @@ -796,6 +796,85 @@ rrtype_from_string(const char *name) long rrtype; rrtype_descriptor_type *entry; + /* Because this routine is called during zone parse for every record, + * we optimise for frequently occuring records. + * Also, we optimise for 'IN' and numbers are not rr types, because + * during parse this routine is called for every rr class and TTL + * to determine that it is not an RR type */ + switch(name[0]) { + case 'r': + case 'R': + if(strcasecmp(name+1, "RSIG") == 0) return TYPE_RRSIG; + break; + case 'n': + case 'N': + switch(name[1]) { + case 's': + case 'S': + switch(name[2]) { + case 0: return TYPE_NS; + case 'e': + case 'E': + if(strcasecmp(name+2, "EC") == 0) return TYPE_NSEC; + if(strcasecmp(name+2, "EC3") == 0) return TYPE_NSEC3; + if(strcasecmp(name+2, "EC3PARAM") == 0) return TYPE_NSEC3PARAM; + break; + } + break; + } + break; + case 'd': + case 'D': + switch(name[1]) { + case 's': + case 'S': + if(name[2]==0) return TYPE_DS; + break; + case 'n': + case 'N': + if(strcasecmp(name+2, "SKEY") == 0) return TYPE_DNSKEY; + break; + } + break; + case 'a': + case 'A': + switch(name[1]) { + case 0: return TYPE_A; + case 'a': + case 'A': + if(strcasecmp(name+2, "AA") == 0) return TYPE_AAAA; + break; + } + break; + case 's': + case 'S': + if(strcasecmp(name+1, "OA") == 0) return TYPE_SOA; + break; + case 't': + case 'T': + if(strcasecmp(name+1, "XT") == 0) return TYPE_TXT; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return 0; /* no RR types start with 0-9 */ + case 'i': + case 'I': + switch(name[1]) { + case 'n': + case 'N': + return 0; /* 'IN' is a class not a type */ + } + break; + } + entry = rrtype_descriptor_by_name(name); if (entry) { return entry->type; diff --git a/usr.sbin/nsd/lookup3.c b/usr.sbin/nsd/lookup3.c index 64ebbf9d4e5..2776752bcf0 100644 --- a/usr.sbin/nsd/lookup3.c +++ b/usr.sbin/nsd/lookup3.c @@ -53,15 +53,16 @@ on 1 byte), but shoehorning those bytes into integers efficiently is messy. #ifdef HAVE_SYS_TYPES_H # include <sys/types.h> /* attempt to define endianness (solaris) */ #endif -#ifdef linux -# include <endian.h> /* attempt to define endianness */ +#if defined(linux) || defined(__OpenBSD__) +# ifdef HAVE_ENDIAN_H +# include <endian.h> /* attempt to define endianness */ +# else +# include <machine/endian.h> /* on older OpenBSD */ +# endif #endif #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) #include <sys/endian.h> /* attempt to define endianness */ #endif -#ifdef __OpenBSD__ -#include <machine/endian.h> /* attempt to define endianness */ -#endif /* random initial value */ static uint32_t raninit = 0xdeadbeef; diff --git a/usr.sbin/nsd/nsd-checkconf.8.in b/usr.sbin/nsd/nsd-checkconf.8.in index 28019daf0b7..a0e7bebed4e 100644 --- a/usr.sbin/nsd/nsd-checkconf.8.in +++ b/usr.sbin/nsd/nsd-checkconf.8.in @@ -1,12 +1,10 @@ -.TH "nsd\-checkconf" "8" "Mar 14, 2014" "NLnet Labs" "nsd 4.0.3" +.TH "nsd\-checkconf" "8" "Sep 4, 2014" "NLnet Labs" "nsd 4.1.0" .\" Copyright (c) 2001\-2008, NLnet Labs. All rights reserved. .\" See LICENSE for the license. .SH "NAME" -.LP .B nsd\-checkconf \- NSD configuration file checker. .SH "SYNOPSIS" -.LP .B nsd\-checkconf .RB [ \-v ] .RB [ \-h ] @@ -20,7 +18,6 @@ .IR keyname ] .I configfile .SH "DESCRIPTION" -.LP .B nsd\-checkconf reads a configuration file. It prints parse errors to standard error, and performs additional checks on the contents. The @@ -91,10 +88,8 @@ default .B NSD configuration file .SH "SEE ALSO" -.LP \fInsd\fR(8), \fInsd.conf\fR(5), \fInsd\-control\fR(8) .SH "AUTHORS" -.LP .B NSD was written by NLnet Labs and RIPE NCC joint team. Please see CREDITS file in the distribution for further details. diff --git a/usr.sbin/nsd/nsd-checkconf.c b/usr.sbin/nsd/nsd-checkconf.c index d940aadc133..ce088e6db7f 100644 --- a/usr.sbin/nsd/nsd-checkconf.c +++ b/usr.sbin/nsd/nsd-checkconf.c @@ -315,6 +315,8 @@ config_print_zone(nsd_options_t* opt, const char* k, int s, const char *o, SERV_GET_BIN(do_ip6, o); SERV_GET_BIN(hide_version, o); SERV_GET_BIN(zonefiles_check, o); + SERV_GET_BIN(log_time_ascii, o); + SERV_GET_BIN(round_robin, o); /* str */ SERV_GET_STR(database, o); SERV_GET_STR(identity, o); @@ -346,6 +348,7 @@ config_print_zone(nsd_options_t* opt, const char* k, int s, const char *o, SERV_GET_INT(rrl_ipv6_prefix_length, o); SERV_GET_INT(rrl_whitelist_ratelimit, o); #endif + SERV_GET_INT(zonefiles_write, o); /* remote control */ SERV_GET_BIN(control_enable, o); SERV_GET_IP(control_interface, control_interface, o); @@ -427,6 +430,8 @@ config_test_print_server(nsd_options_t* opt) print_string_var("zonelistfile:", opt->zonelistfile); print_string_var("xfrdir:", opt->xfrdir); 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); for(ip = opt->ip_addresses; ip; ip=ip->next) { @@ -441,6 +446,7 @@ config_test_print_server(nsd_options_t* opt) printf("\trrl-whitelist-ratelimit: %d\n", (int)opt->rrl_whitelist_ratelimit); #endif printf("\tzonefiles-check: %s\n", opt->zonefiles_check?"yes":"no"); + printf("\tzonefiles-write: %d\n", opt->zonefiles_write); printf("\nremote-control:\n"); printf("\tcontrol-enable: %s\n", opt->control_enable?"yes":"no"); diff --git a/usr.sbin/nsd/nsd.8.in b/usr.sbin/nsd/nsd.8.in index 739843b56c0..214630cad80 100644 --- a/usr.sbin/nsd/nsd.8.in +++ b/usr.sbin/nsd/nsd.8.in @@ -1,12 +1,10 @@ -.TH "NSD" "8" "Mar 14, 2014" "NLnet Labs" "NSD 4.0.3" +.TH "NSD" "8" "Sep 4, 2014" "NLnet Labs" "NSD 4.1.0" .\" Copyright (c) 2001\-2008, NLnet Labs. All rights reserved. .\" See LICENSE for the license. .SH "NAME" -.LP .B nsd -\- Name Server Daemon (NSD) version 4.0.3. +\- Name Server Daemon (NSD) version 4.1.0. .SH "SYNOPSIS" -.LP .B nsd .RB [ \-4 ] .RB [ \-6 ] @@ -42,7 +40,6 @@ .IR level ] .RB [ \-v ] .SH "DESCRIPTION" -.LP .B NSD is a complete implementation of an authoritative DNS nameserver. Upon startup, @@ -70,7 +67,6 @@ separately. If IPv6 is enabled when is compiled an IPv6 address can also be specified. .P .SH "OPTIONS" -.LP All the options can be specified in the configfile ( .B \-c argument), except for the @@ -240,17 +236,14 @@ default .B NSD configuration file .SH "DIAGNOSTICS" -.LP will log all the problems via the standard syslog(8) .I daemon facility, unless the .B \-d option is specified. .SH "SEE ALSO" -.LP \fInsd.conf\fR(5), \fInsd\-checkconf\fR(8), \fInsd\-control\fR(8) .SH "AUTHORS" -.LP .B NSD was written by NLnet Labs and RIPE NCC joint team. Please see CREDITS file in the distribution for further details. diff --git a/usr.sbin/nsd/nsd.c b/usr.sbin/nsd/nsd.c index 262484265cb..b8cfd3e3d59 100644 --- a/usr.sbin/nsd/nsd.c +++ b/usr.sbin/nsd/nsd.c @@ -46,7 +46,7 @@ #include "remote.h" /* The server handler... */ -static struct nsd nsd; +struct nsd nsd; static char hostname[MAXHOSTNAMELEN]; extern config_parser_state_t* cfg_parser; diff --git a/usr.sbin/nsd/nsd.conf.5.in b/usr.sbin/nsd/nsd.conf.5.in index 1fe0144382a..a2fe02c6bf0 100644 --- a/usr.sbin/nsd/nsd.conf.5.in +++ b/usr.sbin/nsd/nsd.conf.5.in @@ -1,12 +1,10 @@ -.TH "nsd.conf" "5" "Mar 14, 2014" "NLnet Labs" "nsd 4.0.3" +.TH "nsd.conf" "5" "Sep 4, 2014" "NLnet Labs" "nsd 4.1.0" .\" Copyright (c) 2001\-2008, NLnet Labs. All rights reserved. .\" See LICENSE for the license. .SH "NAME" -.LP .B nsd.conf \- NSD configuration file .SH "SYNOPSIS" -.LP .B nsd.conf .SH "DESCRIPTION" .B Nsd.conf @@ -15,13 +13,13 @@ values. Some attributes have attributes inside them. The notation is: attribute: value. .PP Comments start with # and last to the end of line. Empty lines are -ignored as is whitespace at the beginning of a line. +ignored as is whitespace at the beginning of a line. Quotes can be used, +for names with spaces, eg. "file name.zone". .PP .B Nsd.conf specifies options for the nsd server, zone files, primaries and secondaries. .SH "EXAMPLE" -.LP An example of a short nsd.conf file is below. .LP # Example.com nsd.conf file @@ -31,7 +29,10 @@ An example of a short nsd.conf file is below. .TP server: .RS 5 -database: "@dbfile@" +server-count: 1 # use this number of cpu cores +.RE +.RS 5 +database: "" # or use "@dbfile@" .RE .RS 5 zonelistfile: "@zonelistfile@" @@ -54,11 +55,45 @@ zone: name: example.com .RE .RS 5 -# note that quotes are optional on the value +zonefile: @configdir@/example.com.zone .RE +.TP +zone: .RS 5 -zonefile: @configdir@/example.com.zone +# this server is master, 192.0.2.1 is the secondary. +.RE +.RS 5 +name: masterzone.com +.RE +.RS 5 +zonefile: @configdir@/masterzone.com.zone +.RE +.RS 5 +notify: 192.0.2.1 NOKEY +.RE +.RS 5 +provide-xfr: 192.0.2.1 NOKEY +.RE +.TP +zone: +.RS 5 +# this server is secondary, 192.0.2.2 is master. +.RE +.RS 5 +name: secondzone.com +.RE +.RS 5 +zonefile: @configdir@/secondzone.com.zone +.RE +.RS 5 +allow-notify: 192.0.2.2 NOKEY .RE +.RS 5 +request-xfr: 192.0.2.2 NOKEY +.RE +.LP +Then, use kill \-HUP to reload changes from master zone files. +And use kill \-TERM to stop the server. .SH "FILE FORMAT" There must be whitespace between keywords. Attribute keywords end with a colon ':'. An attribute is followed by its containing @@ -100,7 +135,10 @@ argument. Processing continues as if the text from the included file was copied into the config file at that point. If a chroot is used an absolute filename is needed (with the chroot prepended), so that the include can be parsed before and after application of the chroot (and -the knowledge of what that chroot is). +the knowledge of what that chroot is). You can use '*' to include a +wildcard match of files, eg. "foo/nsd.d/*.conf". Also '?', '{}', '[]', +and '~' work, see \fBglob\fR(7). If no files match the pattern, this +is not an error. .SS "Server Options" .LP The global options (if not overridden from the NSD commandline) are @@ -120,7 +158,9 @@ If none are given NSD listens to the wildcard interface. Same as commandline opt Same as ip\-address (for easy of compatibility with unbound.conf). .TP .B ip\-transparent:\fR <yes or no> -Allows NSD to bind to non local addresses. Default is no. +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 debug\-mode:\fR <yes or no> Turns on debugging mode for nsd, does not fork a daemon process. @@ -139,6 +179,8 @@ By default is used. The specified file is used to store the compiled zone information. Same as commandline option .BR \-f. +If set to "" then no database is used. This uses less memory but +zone updates are not (immediately) spooled to disk. .TP .B zonelistfile:\fR <filename> By default @@ -233,11 +275,12 @@ is used. Ignored, for compatibility with NSD3 config files. .TP .B xfrdfile:\fR <filename> -The soa timeout and zone transfer daemon in NSD will save its state -to this file. State is read back after a restart. The state file can -be deleted without too much harm, but timestamps of zones will be -gone. For more details see the section on zone expiry behavior of -NSD. Default is +The soa timeout and zone transfer daemon in NSD will save its state to +this file. State is read back after a restart. The state file can be +deleted without too much harm, but timestamps of zones will be gone. +If it is configured as "", the state file is not used, all slave zones +are checked for updates upon startup. For more details see the section +on zone expiry behavior of NSD. Default is .IR @xfrdfile@ . .TP .B xfrdir:\fR <directory> @@ -261,11 +304,30 @@ zone transfers. 2 lists soft warnings that are encountered. Prevent NSD from replying with the version string on CHAOS class queries. .TP -.B zonefiles\-check\fR <yes or no> +.B log\-time\-ascii:\fR <yes or no> +Log time in ascii, if "no" then in seconds epoch. Default is yes. +This chooses the format when logging to file. The printout via syslog +has a timestamp formatted by syslog. +.TP +.B round\-robin:\fR <yes or no> +Enable round robin rotation of records in the answer. This changes the +order of records in the answer and this may balance load across them. +The default is off. +.TP +.B zonefiles\-check:\fR <yes or no> Make NSD check the mtime of zone files on start and sighup. If you disable it it starts faster (less disk activity in case of a lot of zones). The default is enabled. The nsd\-control reload command reloads zone files regardless of this option. +.TP +.B zonefiles\-write:\fR <seconds> +Write changed secondary zones to their zonefile every N seconds. If the +zone (pattern) configuration has "" zonefile, it is not written. Zones that +have received zone transfer updates are written to their zonefile. +Default is 0 (disabled) when there is a database, and 3600 (1 hour) when +database is "". The database also commits zone transfer contents. +You can configure it away from the default by putting the config statement +for zonefiles\-write: after the database: statement in the config file. .\" rrlstart .TP .B rrl\-size:\fR <numbuckets> @@ -396,6 +458,25 @@ each zone. The file containing the zone information. If this attribute is present it is used to read and write the zone contents. If the attribute is absent it prevents writing out of the zone. +.IP +The string is processed so that one string can be used (in a pattern) +for a lot of different zones. If the label or character does not exist the +percent-character is replaced with a period for output (i.e. for the +third character in a two letter domain name). +.IP +.B %s\fR is replaced with the zone name. +.IP +.B %1\fR is replaced with the first character of the zone name. +.IP +.B %2\fR is replaced with the second character of the zone name. +.IP +.B %3\fR is replaced with the third character of the zone name. +.IP +.B %z\fR is replaced with the toplevel domain name of the zone. +.IP +.B %y\fR is replaced with the next label under the toplevel domain. +.IP +.B %x\fR is replaced with the next-next label under the toplevel domain. .TP .B allow\-notify:\fR <ip\-spec> <key\-name | NOKEY | BLOCKED> Access control list. The listed (primary) address is allowed to @@ -457,6 +538,8 @@ address. The specified key is used during AXFR. For unlisted or BLOCKED addresses no data is provided, requests are discarded. BLOCKED supersedes other entries, other entries are scanned for a match in the order of the statements. +NSD provides AXFR for its secondaries, but IXFR is not implemented (IXFR +is implemented for request\-xfr, but not for provide\-xfr). .P .RS The ip\-spec is either a plain IP address (IPv4 or IPv6), or can be @@ -672,15 +755,12 @@ default .B NSD configuration file .SH "SEE ALSO" -.LP \fInsd\fR(8), \fInsd\-checkconf\fR(8), \fInsd\-control\fR(8) .SH "AUTHORS" -.LP .B NSD was written by NLnet Labs and RIPE NCC joint team. Please see CREDITS file in the distribution for further details. .SH "BUGS" -.LP .B nsd.conf is parsed by a primitive parser, error messages may not be to the point. diff --git a/usr.sbin/nsd/nsec3.c b/usr.sbin/nsd/nsec3.c index f84a4cedb6e..92802bd2b00 100644 --- a/usr.sbin/nsd/nsec3.c +++ b/usr.sbin/nsd/nsec3.c @@ -227,6 +227,7 @@ udb_zone_find_nsec3param(udb_base* udb, udb_ptr* uz, struct zone* z) for(i=0; i<rrset->rr_count; i++) { /* if this RR matches the udb RR then we are done */ rdata_atom_type* rd = rrset->rrs[i].rdatas; + if(rrset->rrs[i].rdata_count < 4) continue; if(RR(&urr)->wire[0] == rdata_atom_data(rd[0])[0] && /*alg*/ RR(&urr)->wire[1] == rdata_atom_data(rd[1])[0] && /*flg*/ RR(&urr)->wire[2] == rdata_atom_data(rd[2])[0] && /*iter*/ @@ -243,11 +244,55 @@ udb_zone_find_nsec3param(udb_base* udb, udb_ptr* uz, struct zone* z) return NULL; } +static struct rr* +db_find_nsec3param(struct zone* z, struct rr* avoid_rr) +{ + unsigned i; + rrset_type* rrset = domain_find_rrset(z->apex, z, TYPE_NSEC3PARAM); + if(!rrset) /* no NSEC3PARAM in mem */ + return NULL; + /* find first nsec3param we can support (SHA1, no flags) */ + for(i=0; i<rrset->rr_count; i++) { + rdata_atom_type* rd = rrset->rrs[i].rdatas; + /* do not use the RR that is going to be deleted (in IXFR) */ + if(&rrset->rrs[i] == avoid_rr) continue; + if(rrset->rrs[i].rdata_count < 4) continue; + if(rdata_atom_data(rd[0])[0] == NSEC3_SHA1_HASH && + rdata_atom_data(rd[1])[0] == 0) { + if(2 <= verbosity) { + char str[MAX_RDLENGTH*2+16]; + char* p; + p = str+snprintf(str, sizeof(str), "%u %u %u ", + (unsigned)rdata_atom_data(rd[0])[0], + (unsigned)rdata_atom_data(rd[1])[0], + (unsigned)read_uint16(rdata_atom_data(rd[2]))); + if(rdata_atom_data(rd[3])[0] == 0) + *p++ = '-'; + else { + p += hex_ntop(rdata_atom_data(rd[3])+1, + rdata_atom_data(rd[3])[0], p, + sizeof(str)-strlen(str)-1); + } + *p = 0; + VERBOSITY(2, (LOG_INFO, "rehash of zone %s with parameters %s", + domain_to_string(z->apex), str)); + } + return &rrset->rrs[i]; + } + } + return NULL; +} + void -nsec3_find_zone_param(struct namedb* db, struct zone* zone, udb_ptr* z) +nsec3_find_zone_param(struct namedb* db, struct zone* zone, udb_ptr* z, + struct rr* avoid_rr) { /* get nsec3param RR from udb */ - zone->nsec3_param = udb_zone_find_nsec3param(db->udb, z, zone); + if(db->udb) + zone->nsec3_param = udb_zone_find_nsec3param(db->udb, z, zone); + /* no db, get from memory, avoid using the rr that is going to be + * deleted, avoid_rr */ + else zone->nsec3_param = db_find_nsec3param(zone, avoid_rr); } /* check params ok for one RR */ @@ -529,7 +574,7 @@ nsec3_precompile_newparam(namedb_type* db, zone_type* zone) region_type* tmpregion = region_create(xalloc, free); domain_type* walk; time_t s = time(NULL); - unsigned n = 0, c = 0; + unsigned long n = 0, c = 0; /* add nsec3s of chain to nsec3tree */ for(walk=zone->apex; walk && domain_is_subdomain(walk, zone->apex); @@ -551,7 +596,8 @@ nsec3_precompile_newparam(namedb_type* db, zone_type* zone) if(++c % ZONEC_PCT_COUNT == 0 && time(NULL) > s + ZONEC_PCT_TIME) { s = time(NULL); VERBOSITY(1, (LOG_INFO, "nsec3 %s %d %%", - zone->opts->name, c*100/n)); + zone->opts->name, + (int)(c*((unsigned long)100)/n))); } } region_destroy(tmpregion); @@ -567,18 +613,22 @@ prehash_zone_complete(struct namedb* db, struct zone* zone) /* find zone settings */ assert(db && zone); - if(!udb_zone_search(db->udb, &udbz, dname_name(domain_dname( - zone->apex)), domain_dname(zone->apex)->name_size)) { - udb_ptr_init(&udbz, db->udb); /* zero the ptr */ + if(db->udb) { + if(!udb_zone_search(db->udb, &udbz, dname_name(domain_dname( + zone->apex)), domain_dname(zone->apex)->name_size)) { + udb_ptr_init(&udbz, db->udb); /* zero the ptr */ + } } - nsec3_find_zone_param(db, zone, &udbz); + nsec3_find_zone_param(db, zone, &udbz, NULL); if(!zone->nsec3_param || !check_apex_soa(db, zone)) { zone->nsec3_param = NULL; zone->nsec3_last = NULL; - udb_ptr_unlink(&udbz, db->udb); + if(db->udb) + udb_ptr_unlink(&udbz, db->udb); return; } - udb_ptr_unlink(&udbz, db->udb); + if(db->udb) + udb_ptr_unlink(&udbz, db->udb); nsec3_precompile_newparam(db, zone); } diff --git a/usr.sbin/nsd/rrl.c b/usr.sbin/nsd/rrl.c index 1c5e9c050f0..d6670dedab7 100644 --- a/usr.sbin/nsd/rrl.c +++ b/usr.sbin/nsd/rrl.c @@ -161,6 +161,8 @@ static const char* rrlsource2str(uint64_t s, uint16_t c2) } return buf; } +#else + (void)c2; #endif /* ipv4 */ a4.s_addr = (uint32_t)s; @@ -327,7 +329,7 @@ rrl_msg(query_type* query, const char* str) size_t d_len; uint64_t s; char address[128]; - if(verbosity < 2) return; + if(verbosity < 1) return; addr2str(&query->addr, address, sizeof(address)); s = rrl_get_source(query, &c2); c = rrl_classify(query, &d, &d_len) | c2; @@ -360,7 +362,7 @@ uint32_t rrl_update(query_type* query, uint32_t hash, uint64_t source, if(b->source != source || b->flags != flags || b->hash != hash) { /* initialise */ /* potentially the wrong limit here, used lower nonwhitelim */ - if(verbosity >=2 && + if(verbosity >= 1 && used_to_block(b->rate, b->counter, rrl_ratelimit)) { char address[128]; addr2str(&query->addr, address, sizeof(address)); diff --git a/usr.sbin/nsd/server.c b/usr.sbin/nsd/server.c index a00015d56cc..4fda07ada92 100644 --- a/usr.sbin/nsd/server.c +++ b/usr.sbin/nsd/server.c @@ -28,6 +28,7 @@ #include <string.h> #include <time.h> #include <unistd.h> +#include <signal.h> #include <fcntl.h> #include <netdb.h> #ifndef SHUT_WR @@ -420,7 +421,7 @@ server_init(struct nsd *nsd) # endif /* SO_RCVBUFFORCE */ if(setsockopt(nsd->udp[i].s, SOL_SOCKET, SO_RCVBUF, (void*)&rcv, (socklen_t)sizeof(rcv)) < 0) { - if(errno != ENOBUFS) { + if(errno != ENOBUFS && errno != ENOSYS) { log_msg(LOG_ERR, "setsockopt(..., SO_RCVBUF, " "...) failed: %s", strerror(errno)); return -1; @@ -443,7 +444,7 @@ server_init(struct nsd *nsd) # endif /* SO_SNDBUFFORCE */ if(setsockopt(nsd->udp[i].s, SOL_SOCKET, SO_SNDBUF, (void*)&snd, (socklen_t)sizeof(snd)) < 0) { - if(errno != ENOBUFS) { + if(errno != ENOBUFS && errno != ENOSYS) { log_msg(LOG_ERR, "setsockopt(..., SO_SNDBUF, " "...) failed: %s", strerror(errno)); return -1; @@ -678,7 +679,8 @@ server_prepare(struct nsd *nsd) /* check if zone files have been modified */ /* NULL for taskudb because we send soainfo in a moment, batched up, * for all zones */ - if(nsd->options->zonefiles_check) + if(nsd->options->zonefiles_check || (nsd->options->database == NULL || + nsd->options->database[0] == 0)) namedb_check_zonefiles(nsd, nsd->options, NULL, NULL); compression_table_capacity = 0; @@ -841,7 +843,7 @@ server_start_xfrd(struct nsd *nsd, int del_db, int reload_active) /* use other task than I am using, since if xfrd died and is * restarted, the reload is using nsd->mytask */ nsd->mytask = 1 - nsd->mytask; - xfrd_init(sockets[1], nsd, del_db, reload_active); + xfrd_init(sockets[1], nsd, del_db, reload_active, pid); /* ENOTREACH */ break; case 0: @@ -888,12 +890,30 @@ server_send_soa_xfrd(struct nsd* nsd, int shortsoa) * (xfrd will wait for current running reload to finish if any). */ sig_atomic_t cmd = 0; -#ifdef BIND8_STATS pid_t mypid; -#endif int xfrd_sock = nsd->xfrd_listener->fd; struct udb_base* taskudb = nsd->task[nsd->mytask]; udb_ptr t; + if(!shortsoa) { + if(nsd->signal_hint_shutdown) { + shutdown: + log_msg(LOG_WARNING, "signal received, shutting down..."); + server_close_all_sockets(nsd->udp, nsd->ifs); + server_close_all_sockets(nsd->tcp, nsd->ifs); +#ifdef HAVE_SSL + daemon_remote_close(nsd->rc); +#endif + /* Unlink it if possible... */ + unlinkpid(nsd->pidfile); + unlink(nsd->task[0]->fname); + unlink(nsd->task[1]->fname); + /* write the nsd.db to disk, wait for it to complete */ + udb_base_sync(nsd->db->udb, 1); + udb_base_close(nsd->db->udb); + server_shutdown(nsd); + exit(0); + } + } if(shortsoa) { /* put SOA in xfrd task because mytask may be in use */ taskudb = nsd->task[1-nsd->mytask]; @@ -907,6 +927,9 @@ server_send_soa_xfrd(struct nsd* nsd, int shortsoa) log_msg(LOG_ERR, "did not get start signal from xfrd"); exit(1); } + if(nsd->signal_hint_shutdown) { + goto shutdown; + } } /* give xfrd our task, signal it with RELOAD_DONE */ task_process_sync(taskudb); @@ -915,13 +938,11 @@ server_send_soa_xfrd(struct nsd* nsd, int shortsoa) log_msg(LOG_ERR, "problems sending soa end from reload %d to xfrd: %s", (int)nsd->pid, strerror(errno)); } -#ifdef BIND8_STATS mypid = getpid(); if(!write_socket(nsd->xfrd_listener->fd, &mypid, sizeof(mypid))) { log_msg(LOG_ERR, "problems sending reloadpid to xfrd: %s", strerror(errno)); } -#endif if(!shortsoa) { /* process the xfrd task works (expiry data) */ @@ -1075,7 +1096,7 @@ reload_do_stats(int cmdfd, struct nsd* nsd, udb_ptr* last) log_msg(LOG_ERR, "could not read stats from oldpar"); return; } - s.db_disk = nsd->db->udb->base_size; + s.db_disk = (nsd->db->udb?nsd->db->udb->base_size:0); s.db_mem = region_get_mem(nsd->db->region); p = (stc_t*)task_new_stat_info(nsd->task[nsd->mytask], last, &s, nsd->child_count); @@ -1095,17 +1116,23 @@ static void server_reload(struct nsd *nsd, region_type* server_region, netio_type* netio, int cmdsocket) { -#ifdef BIND8_STATS pid_t mypid; -#endif sig_atomic_t cmd = NSD_QUIT_SYNC; int ret; udb_ptr last_task; + struct sigaction old_sigchld, ign_sigchld; + /* ignore SIGCHLD from the previous server_main that used this pid */ + memset(&ign_sigchld, 0, sizeof(ign_sigchld)); + ign_sigchld.sa_handler = SIG_IGN; + sigaction(SIGCHLD, &ign_sigchld, &old_sigchld); /* see what tasks we got from xfrd */ task_remap(nsd->task[nsd->mytask]); udb_ptr_init(&last_task, nsd->task[nsd->mytask]); + udb_compact_inhibited(nsd->db->udb, 1); reload_process_tasks(nsd, &last_task, cmdsocket); + udb_compact_inhibited(nsd->db->udb, 0); + udb_compact(nsd->db->udb); #ifndef NDEBUG if(nsd_debug_level >= 1) @@ -1122,6 +1149,8 @@ server_reload(struct nsd *nsd, region_type* server_region, netio_type* netio, set_bind8_alarm(nsd); #endif + /* listen for the signals of failed children again */ + sigaction(SIGCHLD, &old_sigchld, NULL); /* Start new child processes */ if (server_start_children(nsd, server_region, netio, &nsd-> xfrd_listener->fd) != 0) { @@ -1179,13 +1208,11 @@ server_reload(struct nsd *nsd, region_type* server_region, netio_type* netio, log_msg(LOG_ERR, "problems sending reload_done xfrd: %s", strerror(errno)); } -#ifdef BIND8_STATS mypid = getpid(); if(!write_socket(nsd->xfrd_listener->fd, &mypid, sizeof(mypid))) { log_msg(LOG_ERR, "problems sending reloadpid to xfrd: %s", strerror(errno)); } -#endif /* try to reopen file */ if (nsd->file_rotation_ok) @@ -1278,7 +1305,7 @@ server_main(struct nsd *nsd) switch (mode) { case NSD_RUN: /* see if any child processes terminated */ - while((child_pid = waitpid(0, &status, WNOHANG)) != -1 && child_pid != 0) { + while((child_pid = waitpid(-1, &status, WNOHANG)) != -1 && child_pid != 0) { int is_child = delete_child_pid(nsd, child_pid); if (is_child != -1 && nsd->children[is_child].need_to_exit) { if(nsd->children[is_child].child_fd == -1) @@ -1292,9 +1319,7 @@ server_main(struct nsd *nsd) &nsd->xfrd_listener->fd); } else if (child_pid == reload_pid) { sig_atomic_t cmd = NSD_RELOAD_DONE; -#ifdef BIND8_STATS pid_t mypid; -#endif log_msg(LOG_WARNING, "Reload process %d failed with status %d, continuing with old database", (int) child_pid, status); @@ -1310,16 +1335,19 @@ server_main(struct nsd *nsd) "sending SOAEND to xfrd: %s", strerror(errno)); } -#ifdef BIND8_STATS mypid = getpid(); if(!write_socket(nsd->xfrd_listener->fd, &mypid, sizeof(mypid))) { log_msg(LOG_ERR, "problems sending reloadpid to xfrd: %s", strerror(errno)); } -#endif - } else { + } else if(status != 0) { + /* check for status, because we get + * the old-servermain because reload + * is the process-parent of old-main, + * and we get older server-processes + * that are exiting after a reload */ log_msg(LOG_WARNING, - "Unknown child %d terminated with status %d", + "process %d terminated with status %d", (int) child_pid, status); } } @@ -1327,7 +1355,8 @@ server_main(struct nsd *nsd) if (errno == EINTR) { continue; } - log_msg(LOG_WARNING, "wait failed: %s", strerror(errno)); + if (errno != ECHILD) + log_msg(LOG_WARNING, "wait failed: %s", strerror(errno)); } if (nsd->mode != NSD_RUN) break; @@ -1342,6 +1371,36 @@ server_main(struct nsd *nsd) log_msg(LOG_ERR, "netio_dispatch failed: %s", strerror(errno)); } } + if(nsd->restart_children) { + restart_child_servers(nsd, server_region, netio, + &nsd->xfrd_listener->fd); + nsd->restart_children = 0; + } + if(nsd->reload_failed) { + sig_atomic_t cmd = NSD_RELOAD_DONE; + pid_t mypid; + nsd->reload_failed = 0; + log_msg(LOG_WARNING, + "Reload process %d failed, continuing with old database", + (int) reload_pid); + reload_pid = -1; + if(reload_listener.fd != -1) close(reload_listener.fd); + reload_listener.fd = -1; + reload_listener.event_types = NETIO_EVENT_NONE; + task_process_sync(nsd->task[nsd->mytask]); + /* inform xfrd reload attempt ended */ + if(!write_socket(nsd->xfrd_listener->fd, + &cmd, sizeof(cmd))) { + log_msg(LOG_ERR, "problems " + "sending SOAEND to xfrd: %s", + strerror(errno)); + } + mypid = getpid(); + if(!write_socket(nsd->xfrd_listener->fd, &mypid, sizeof(mypid))) { + log_msg(LOG_ERR, "problems sending reloadpid to xfrd: %s", + strerror(errno)); + } + } break; case NSD_RELOAD_REQ: { @@ -1380,8 +1439,8 @@ server_main(struct nsd *nsd) case -1: log_msg(LOG_ERR, "fork failed: %s", strerror(errno)); break; - case 0: - /* CHILD */ + default: + /* PARENT */ close(reload_sockets[0]); server_reload(nsd, server_region, netio, reload_sockets[1]); @@ -1397,10 +1456,10 @@ server_main(struct nsd *nsd) reload_listener.event_types = NETIO_EVENT_NONE; DEBUG(DEBUG_IPC,2, (LOG_INFO, "Reload resetup; run")); break; - default: - /* PARENT, keep running until NSD_QUIT_SYNC - * received from CHILD. - */ + case 0: + /* CHILD */ + /* server_main keep running until NSD_QUIT_SYNC + * received from reload. */ close(reload_sockets[1]); reload_listener.fd = reload_sockets[0]; reload_listener.timeout = NULL; @@ -1408,6 +1467,7 @@ server_main(struct nsd *nsd) reload_listener.event_types = NETIO_EVENT_READ; reload_listener.event_handler = parent_handle_reload_command; /* listens to Quit */ netio_add_handler(netio, &reload_listener); + reload_pid = getppid(); break; } break; @@ -1456,7 +1516,6 @@ server_main(struct nsd *nsd) /* ENOTREACH */ break; case NSD_SHUTDOWN: - log_msg(LOG_WARNING, "signal received, shutting down..."); break; case NSD_REAP_CHILDREN: /* continue; wait for child in run loop */ @@ -1474,6 +1533,7 @@ server_main(struct nsd *nsd) break; } } + log_msg(LOG_WARNING, "signal received, shutting down..."); /* close opened ports to avoid race with restart of nsd */ server_close_all_sockets(nsd->udp, nsd->ifs); @@ -1722,7 +1782,7 @@ server_child(struct nsd *nsd) (int) nsd->this_child->pid, strerror(errno)); } } else /* no parent, so reap 'em */ - while (waitpid(0, NULL, WNOHANG) > 0) ; + while (waitpid(-1, NULL, WNOHANG) > 0) ; nsd->mode = NSD_RUN; } else if(mode == NSD_RUN) { diff --git a/usr.sbin/nsd/util.c b/usr.sbin/nsd/util.c index 6b58b7472b5..7d93f54b55b 100644 --- a/usr.sbin/nsd/util.c +++ b/usr.sbin/nsd/util.c @@ -51,6 +51,7 @@ int verbosity = 0; static const char *global_ident = NULL; static log_function_type *current_log_function = log_file; static FILE *current_log_file = NULL; +int log_time_asc = 1; void log_init(const char *ident) @@ -135,7 +136,24 @@ log_file(int priority, const char *message) } /* Bug #104, add time_t timestamp */ - fprintf(current_log_file, "[%d] %s[%d]: %s: %s", +#if defined(HAVE_STRFTIME) && defined(HAVE_LOCALTIME_R) + if(log_time_asc) { + struct timeval tv; + char tmbuf[32]; + tmbuf[0]=0; + tv.tv_usec = 0; + if(gettimeofday(&tv, NULL) == 0) { + struct tm tm; + time_t now = (time_t)tv.tv_sec; + strftime(tmbuf, sizeof(tmbuf), "%Y-%m-%d %H:%M:%S", + localtime_r(&now, &tm)); + } + fprintf(current_log_file, "[%s.%3.3d] %s[%d]: %s: %s", + tmbuf, (int)tv.tv_usec/1000, + global_ident, (int) getpid(), priority_text, message); + } else +#endif /* have time functions */ + fprintf(current_log_file, "[%d] %s[%d]: %s: %s", (int)time(NULL), global_ident, (int) getpid(), priority_text, message); length = strlen(message); if (length == 0 || message[length - 1] != '\n') { @@ -855,9 +873,8 @@ compare_serial(uint32_t a, uint32_t b) uint16_t qid_generate(void) { -#ifdef HAVE_ARC4RANDOM_UNIFORM - return (uint16_t) arc4random_uniform(65536); -#elif HAVE_ARC4RANDOM + /* arc4random_uniform not needed because range is a power of 2 */ +#ifdef HAVE_ARC4RANDOM return (uint16_t) arc4random(); #else return (uint16_t) random(); @@ -908,59 +925,59 @@ set_previous_owner(struct state_pretty_rr *state, const dname_type *dname) int print_rr(FILE *out, struct state_pretty_rr *state, - rr_type *record) + rr_type *record, + region_type* rr_region, + buffer_type* output) { - region_type *region = region_create(xalloc, free); - buffer_type *output = buffer_create(region, MAX_RDLENGTH); rrtype_descriptor_type *descriptor = rrtype_descriptor_by_type(record->type); int result; const dname_type *owner = domain_dname(record->owner); - const dname_type *owner_origin - = dname_origin(region, owner); + buffer_clear(output); if (state) { - if (!state->previous_owner - || dname_compare(state->previous_owner, owner) != 0) { - int origin_changed = (!state->previous_owner_origin - || dname_compare(state->previous_owner_origin, - owner_origin) != 0); - if (origin_changed) { - buffer_printf(output, "$ORIGIN %s\n", - dname_to_string(owner_origin, NULL)); - } - - set_previous_owner(state, owner); - buffer_printf(output, "%s", - dname_to_string(owner, - state->previous_owner_origin)); + if (!state->previous_owner + || dname_compare(state->previous_owner, owner) != 0) { + const dname_type *owner_origin + = dname_origin(rr_region, owner); + int origin_changed = (!state->previous_owner_origin + || dname_compare(state->previous_owner_origin, + owner_origin) != 0); + if (origin_changed) { + buffer_printf(output, "$ORIGIN %s\n", + dname_to_string(owner_origin, NULL)); } - } else { - buffer_printf(output, "%s", dname_to_string(owner, NULL)); - } - - buffer_printf(output, "\t%lu\t%s\t%s", - (unsigned long) record->ttl, - rrclass_to_string(record->klass), - rrtype_to_string(record->type)); - result = print_rdata(output, descriptor, record); - if (!result) { - /* - * Some RDATA failed to print, so print the record's - * RDATA in unknown format. - */ - result = rdata_atoms_to_unknown_string(output, - descriptor, record->rdata_count, record->rdatas); + set_previous_owner(state, owner); + buffer_printf(output, "%s", + dname_to_string(owner, + state->previous_owner_origin)); + region_free_all(rr_region); } + } else { + buffer_printf(output, "%s", dname_to_string(owner, NULL)); + } + + buffer_printf(output, "\t%lu\t%s\t%s", + (unsigned long) record->ttl, + rrclass_to_string(record->klass), + rrtype_to_string(record->type)); - if (result) { - buffer_printf(output, "\n"); - buffer_flip(output); - result = write_data(out, buffer_current(output), - buffer_remaining(output)); + result = print_rdata(output, descriptor, record); + if (!result) { + /* + * Some RDATA failed to print, so print the record's + * RDATA in unknown format. + */ + result = rdata_atoms_to_unknown_string(output, + descriptor, record->rdata_count, record->rdatas); } - region_destroy(region); + if (result) { + buffer_printf(output, "\n"); + buffer_flip(output); + result = write_data(out, buffer_current(output), + buffer_remaining(output)); + } return result; } diff --git a/usr.sbin/nsd/util.h b/usr.sbin/nsd/util.h index 69dd72f2c35..e8100bd724b 100644 --- a/usr.sbin/nsd/util.h +++ b/usr.sbin/nsd/util.h @@ -15,6 +15,8 @@ #include <stdio.h> #include <time.h> struct rr; +struct buffer; +struct region; #ifdef HAVE_SYSLOG_H # include <syslog.h> @@ -247,6 +249,8 @@ extern int nsd_debug_level; } while (0) #endif +/* set to true to log time prettyprinted, or false to print epoch */ +extern int log_time_asc; /* * Timespec functions. @@ -353,7 +357,8 @@ struct state_pretty_rr { }; struct state_pretty_rr* create_pretty_rr(struct region* region); /* print rr to file, returns 0 on failure(nothing is written) */ -int print_rr(FILE *out, struct state_pretty_rr* state, struct rr *record); +int print_rr(FILE *out, struct state_pretty_rr* state, struct rr *record, + struct region* tmp_region, struct buffer* tmp_buffer); /* * Convert a numeric rcode value to a human readable string diff --git a/usr.sbin/nsd/xfrd-disk.c b/usr.sbin/nsd/xfrd-disk.c index 94ac93e3133..a095bbfacf9 100644 --- a/usr.sbin/nsd/xfrd-disk.c +++ b/usr.sbin/nsd/xfrd-disk.c @@ -189,6 +189,12 @@ xfrd_read_state(struct xfrd_state* xfrd) xfrd_soa_t incoming_soa; time_t incoming_acquired; + if(nsd.signal_hint_shutdown) { + fclose(in); + region_destroy(tempregion); + return; + } + memset(&soa_nsd_read, 0, sizeof(soa_nsd_read)); memset(&soa_disk_read, 0, sizeof(soa_disk_read)); memset(&soa_notified_read, 0, sizeof(soa_notified_read)); @@ -275,6 +281,19 @@ xfrd_read_state(struct xfrd_state* xfrd) { zone->state = xfrd_zone_expired; xfrd_set_refresh_now(zone); + } + + /* there is a zone read and it matches what we had before */ + if(zone->soa_nsd_acquired && zone->state != xfrd_zone_expired + && zone->soa_nsd.serial == soa_nsd_read.serial) { + xfrd_deactivate_zone(zone); + zone->state = state; + xfrd_set_timer(zone, timeout); + } + if(zone->soa_nsd_acquired == 0 && soa_nsd_acquired_read == 0 && + soa_disk_acquired_read == 0) { + /* continue expon backoff where we were + check now */ + zone->fresh_xfr_timeout = timeout; } /* handle as an incoming SOA. */ diff --git a/usr.sbin/nsd/xfrd-tcp.c b/usr.sbin/nsd/xfrd-tcp.c index 0b7d7b4cafe..a317857afdb 100644 --- a/usr.sbin/nsd/xfrd-tcp.c +++ b/usr.sbin/nsd/xfrd-tcp.c @@ -894,7 +894,11 @@ xfrd_tcp_release(xfrd_tcp_set_t* set, xfrd_zone_t* zone) /* if pipe was full, but no more, then see if waiting element is * for the same master, and can fill the unused ID */ if(tp->num_unused == 1 && set->tcp_waiting_first) { +#ifdef INET6 struct sockaddr_storage to; +#else + struct sockaddr_in to; +#endif socklen_t to_len = xfrd_acl_sockaddr_to( set->tcp_waiting_first->master, &to); if(to_len == tp->ip_len && memcmp(&to, &tp->ip, to_len) == 0) { diff --git a/usr.sbin/nsd/xfrd.c b/usr.sbin/nsd/xfrd.c index 997b6b8658c..0ea9ea651d3 100644 --- a/usr.sbin/nsd/xfrd.c +++ b/usr.sbin/nsd/xfrd.c @@ -31,7 +31,7 @@ #include "remote.h" #define XFRD_TRANSFER_TIMEOUT_START 10 /* empty zone timeout is between x and 2*x seconds */ -#define XFRD_TRANSFER_TIMEOUT_MAX 14400 /* empty zone timeout max expbackoff */ +#define XFRD_TRANSFER_TIMEOUT_MAX 86400 /* empty zone timeout max expbackoff */ #define XFRD_UDP_TIMEOUT 10 /* seconds, before a udp request times out */ #define XFRD_NO_IXFR_CACHE 172800 /* 48h before retrying ixfr's after notimpl */ #define XFRD_LOWERBOUND_REFRESH 1 /* seconds, smallest refresh timeout */ @@ -39,18 +39,21 @@ #define XFRD_MAX_ROUNDS 3 /* max number of rounds along the masters */ #define XFRD_TSIG_MAX_UNSIGNED 103 /* max number of packets without tsig in a tcp stream. */ /* rfc recommends 100, +3 for offbyone errors/interoperability. */ +#define XFRD_CHILD_REAP_TIMEOUT 60 /* seconds to wakeup and reap lost children */ + /* these are reload processes that SIGCHILDed but the signal + * was lost, and need waitpid to remove their process entry. */ /* the daemon state */ xfrd_state_t* xfrd = 0; /* main xfrd loop */ -static void xfrd_main(); +static void xfrd_main(void); /* shut down xfrd, close sockets. */ -static void xfrd_shutdown(); +static void xfrd_shutdown(void); /* delete pending task xfr files in tmp */ static void xfrd_clean_pending_tasks(struct nsd* nsd, udb_base* u); /* create zone rbtree at start */ -static void xfrd_init_zones(); +static void xfrd_init_zones(void); /* initial handshake with SOAINFO from main and send expire to main */ static void xfrd_receive_soa(int socket, int shortsoa); @@ -67,9 +70,11 @@ static void xfrd_set_timer_retry(xfrd_zone_t* zone); static void xfrd_set_timer_refresh(xfrd_zone_t* zone); /* set reload timeout */ -static void xfrd_set_reload_timeout(); +static void xfrd_set_reload_timeout(void); /* handle reload timeout */ static void xfrd_handle_reload(int fd, short event, void* arg); +/* handle child timeout */ +static void xfrd_handle_child_timer(int fd, short event, void* arg); /* send expiry notifications to nsd */ static void xfrd_send_expire_notification(xfrd_zone_t* zone); @@ -84,6 +89,9 @@ static void xfrd_udp_read(xfrd_zone_t* zone); /* find master by notify number */ static int find_same_master_notify(xfrd_zone_t* zone, int acl_num_nfy); +/* set the write timer to activate */ +static void xfrd_write_timer_set(void); + static void xfrd_signal_callback(int sig, short event, void* ATTR_UNUSED(arg)) { @@ -107,7 +115,8 @@ xfrd_sigsetup(int sig) } void -xfrd_init(int socket, struct nsd* nsd, int shortsoa, int reload_active) +xfrd_init(int socket, struct nsd* nsd, int shortsoa, int reload_active, + pid_t nsd_pid) { region_type* region; @@ -127,14 +136,6 @@ xfrd_init(int socket, struct nsd* nsd, int shortsoa, int reload_active) exit(1); } xfrd->nsd = nsd; - xfrd_sigsetup(SIGHUP); - xfrd_sigsetup(SIGTERM); - xfrd_sigsetup(SIGQUIT); - xfrd_sigsetup(SIGCHLD); - xfrd_sigsetup(SIGALRM); - xfrd_sigsetup(SIGILL); - xfrd_sigsetup(SIGUSR1); - xfrd_sigsetup(SIGINT); xfrd->packet = buffer_create(xfrd->region, QIOBUFSZ); xfrd->udp_waiting_first = NULL; xfrd->udp_waiting_last = NULL; @@ -152,7 +153,8 @@ xfrd_init(int socket, struct nsd* nsd, int shortsoa, int reload_active) xfrd->reload_timeout.tv_sec = 0; xfrd->reload_cmd_last_sent = xfrd->xfrd_start_time; xfrd->can_send_reload = !reload_active; - xfrd->reload_pid = -1; + xfrd->reload_pid = nsd_pid; + xfrd->child_timer_added = 0; xfrd->ipc_send_blocked = 0; event_set(&xfrd->ipc_handler, socket, EV_PERSIST|EV_READ, @@ -170,6 +172,10 @@ xfrd_init(int socket, struct nsd* nsd, int shortsoa, int reload_active) xfrd->need_to_send_shutdown = 0; xfrd->need_to_send_stats = 0; + xfrd->write_zonefile_needed = 0; + if(nsd->options->zonefiles_write) + xfrd_write_timer_set(); + xfrd->notify_waiting_first = NULL; xfrd->notify_waiting_last = NULL; xfrd->notify_udp_num = 0; @@ -187,7 +193,27 @@ xfrd_init(int socket, struct nsd* nsd, int shortsoa, int reload_active) DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd pre-startup")); xfrd_init_zones(); xfrd_receive_soa(socket, shortsoa); - xfrd_read_state(xfrd); + if(nsd->options->xfrdfile != NULL && nsd->options->xfrdfile[0]!=0) + xfrd_read_state(xfrd); + + /* did we get killed before startup was successful? */ + if(nsd->signal_hint_shutdown) { + kill(nsd_pid, SIGTERM); + xfrd_shutdown(); + return; + } + + /* init libevent signals now, so that in the previous init scripts + * the normal sighandler is called, and can set nsd->signal_hint.. + * these are also looked at in sig_process before we run the main loop*/ + xfrd_sigsetup(SIGHUP); + xfrd_sigsetup(SIGTERM); + xfrd_sigsetup(SIGQUIT); + xfrd_sigsetup(SIGCHLD); + xfrd_sigsetup(SIGALRM); + xfrd_sigsetup(SIGILL); + xfrd_sigsetup(SIGUSR1); + xfrd_sigsetup(SIGINT); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd startup")); xfrd_main(); @@ -214,6 +240,9 @@ xfrd_process_activated(void) static void xfrd_sig_process(void) { + int status; + pid_t child_pid; + if(xfrd->nsd->signal_hint_quit || xfrd->nsd->signal_hint_shutdown) { xfrd->nsd->signal_hint_quit = 0; xfrd->nsd->signal_hint_shutdown = 0; @@ -235,17 +264,28 @@ xfrd_sig_process(void) if(!(xfrd->ipc_handler_flags&EV_WRITE)) { ipc_xfrd_set_listening(xfrd, EV_PERSIST|EV_READ|EV_WRITE); } - } else if(xfrd->nsd->signal_hint_child) { - int status; - pid_t child_pid; - xfrd->nsd->signal_hint_child = 0; - while((child_pid = waitpid(0, &status, WNOHANG)) != -1 && child_pid != 0) { - if(status != 0) { - log_msg(LOG_ERR, "process serverparent %d exited with status %d", - (int)child_pid, status); - } + } + + /* collect children that exited. */ + xfrd->nsd->signal_hint_child = 0; + while((child_pid = waitpid(-1, &status, WNOHANG)) != -1 && child_pid != 0) { + if(status != 0) { + log_msg(LOG_ERR, "process %d exited with status %d", + (int)child_pid, status); } } + if(!xfrd->child_timer_added) { + struct timeval tv; + tv.tv_sec = XFRD_CHILD_REAP_TIMEOUT; + tv.tv_usec = 0; + event_set(&xfrd->child_timer, -1, EV_TIMEOUT, + xfrd_handle_child_timer, xfrd); + if(event_base_set(xfrd->event_base, &xfrd->child_timer) != 0) + log_msg(LOG_ERR, "xfrd child timer: event_base_set failed"); + if(event_add(&xfrd->child_timer, &tv) != 0) + log_msg(LOG_ERR, "xfrd child timer: event_add failed"); + xfrd->child_timer_added = 1; + } } static void @@ -280,11 +320,19 @@ xfrd_shutdown() DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd shutdown")); event_del(&xfrd->ipc_handler); close(xfrd->ipc_handler.ev_fd); /* notifies parent we stop */ - xfrd_write_state(xfrd); + if(xfrd->nsd->options->xfrdfile != NULL && xfrd->nsd->options->xfrdfile[0]!=0) + xfrd_write_state(xfrd); if(xfrd->reload_added) { event_del(&xfrd->reload_handler); xfrd->reload_added = 0; } + if(xfrd->child_timer_added) { + event_del(&xfrd->child_timer); + xfrd->child_timer_added = 0; + } + if(xfrd->nsd->options->zonefiles_write) { + event_del(&xfrd->write_timer); + } #ifdef HAVE_SSL daemon_remote_close(xfrd->nsd->rc); /* close sockets of rc */ #endif @@ -485,7 +533,7 @@ xfrd_process_soa_info_task(struct task_list_d* task) xfrd_handle_incoming_soa(zone, soa_ptr, xfrd_time()); } -void +static void xfrd_receive_soa(int socket, int shortsoa) { sig_atomic_t cmd; @@ -513,17 +561,17 @@ xfrd_receive_soa(int socket, int shortsoa) } /* receive RELOAD_DONE to get SOAINFO tasklist */ - if(block_read(NULL, socket, &cmd, sizeof(cmd), -1) != sizeof(cmd) || + if(block_read(&nsd, socket, &cmd, sizeof(cmd), -1) != sizeof(cmd) || cmd != NSD_RELOAD_DONE) { + if(nsd.signal_hint_shutdown) + return; log_msg(LOG_ERR, "did not get start signal from main"); exit(1); } -#ifdef BIND8_STATS if(block_read(NULL, socket, &xfrd->reload_pid, sizeof(pid_t), -1) != sizeof(pid_t)) { log_msg(LOG_ERR, "xfrd cannot get reload_pid"); } -#endif /* BIND8_STATS */ /* process tasklist (SOAINFO data) */ udb_ptr_unlink(xfrd->last_task, xtask); @@ -673,6 +721,8 @@ xfrd_set_timer_retry(xfrd_zone_t* zone) /* set timer for next retry or expire timeout if earlier. */ if(zone->soa_disk_acquired == 0) { /* if no information, use reasonable timeout */ + if(zone->fresh_xfr_timeout == 0) + zone->fresh_xfr_timeout = XFRD_TRANSFER_TIMEOUT_START; #ifdef HAVE_ARC4RANDOM xfrd_set_timer(zone, zone->fresh_xfr_timeout + arc4random()%zone->fresh_xfr_timeout); @@ -1033,11 +1083,12 @@ xfrd_handle_incoming_soa(xfrd_zone_t* zone, if(zone->soa_disk_acquired && soa->serial == zone->soa_disk.serial) { /* soa in disk has been loaded in memory */ - log_msg(LOG_INFO, "Zone %s serial %u is updated to %u.", + log_msg(LOG_INFO, "zone %s serial %u is updated to %u.", zone->apex_str, (unsigned)ntohl(zone->soa_nsd.serial), (unsigned)ntohl(soa->serial)); zone->soa_nsd = zone->soa_disk; zone->soa_nsd_acquired = zone->soa_disk_acquired; + xfrd->write_zonefile_needed = 1; if(xfrd_time() - zone->soa_disk_acquired < (time_t)ntohl(zone->soa_disk.refresh)) { @@ -1078,7 +1129,7 @@ xfrd_handle_incoming_soa(xfrd_zone_t* zone, /* user must have manually provided zone data */ DEBUG(DEBUG_XFRD,1, (LOG_INFO, - "xfrd: zone %s serial %u from unknown source. refreshing", + "xfrd: zone %s serial %u from zonefile. refreshing", zone->apex_str, (unsigned)ntohl(soa->serial))); zone->soa_nsd = *soa; zone->soa_disk = *soa; @@ -1672,7 +1723,7 @@ xfrd_parse_received_xfr_packet(xfrd_zone_t* zone, buffer_type* packet, } if (RCODE(packet) != RCODE_NOTAUTH) { /* RFC 2845: If NOTAUTH, client should do TSIG checking */ - return xfrd_packet_bad; + return xfrd_packet_drop; } } /* check TSIG */ @@ -1684,7 +1735,7 @@ xfrd_parse_received_xfr_packet(xfrd_zone_t* zone, buffer_type* packet, } } if (RCODE(packet) == RCODE_NOTAUTH) { - return xfrd_packet_bad; + return xfrd_packet_drop; } buffer_skip(packet, QHEADERSZ); @@ -2285,3 +2336,50 @@ void xfrd_set_reload_now(xfrd_state_t* xfrd) ipc_xfrd_set_listening(xfrd, EV_PERSIST|EV_READ|EV_WRITE); } } + +static void +xfrd_handle_write_timer(int ATTR_UNUSED(fd), short event, void* ATTR_UNUSED(arg)) +{ + /* timeout for write events */ + assert(event & EV_TIMEOUT); + (void)event; + if(xfrd->nsd->options->zonefiles_write == 0) + return; + /* call reload to write changed zonefiles */ + if(!xfrd->write_zonefile_needed) { + DEBUG(DEBUG_XFRD,2, (LOG_INFO, "zonefiles write timer (nothing)")); + xfrd_write_timer_set(); + return; + } + DEBUG(DEBUG_XFRD,1, (LOG_INFO, "zonefiles write timer")); + task_new_write_zonefiles(xfrd->nsd->task[xfrd->nsd->mytask], + xfrd->last_task, NULL); + xfrd_set_reload_now(xfrd); + xfrd->write_zonefile_needed = 0; + xfrd_write_timer_set(); +} + +static void xfrd_write_timer_set() +{ + struct timeval tv; + if(xfrd->nsd->options->zonefiles_write == 0) + return; + tv.tv_sec = xfrd->nsd->options->zonefiles_write; + tv.tv_usec = 0; + event_set(&xfrd->write_timer, -1, EV_TIMEOUT, + xfrd_handle_write_timer, xfrd); + if(event_base_set(xfrd->event_base, &xfrd->write_timer) != 0) + log_msg(LOG_ERR, "xfrd write timer: event_base_set failed"); + if(event_add(&xfrd->write_timer, &tv) != 0) + log_msg(LOG_ERR, "xfrd write timer: event_add failed"); +} + +static void xfrd_handle_child_timer(int ATTR_UNUSED(fd), short event, + void* ATTR_UNUSED(arg)) +{ + assert(event & EV_TIMEOUT); + (void)event; + /* only used to wakeup the process to reap children, note the + * event is no longer registered */ + xfrd->child_timer_added = 0; +} diff --git a/usr.sbin/nsd/zparser.y b/usr.sbin/nsd/zparser.y index 63c40d5e188..4855784f7e2 100644 --- a/usr.sbin/nsd/zparser.y +++ b/usr.sbin/nsd/zparser.y @@ -336,13 +336,11 @@ wire_rel_dname: wire_label } ; - - -str_seq: STR +str_seq: dotted_str { zadd_rdata_txt_wireformat(zparser_conv_text(parser->rr_region, $1.str, $1.len), 1); } - | str_seq sp STR + | str_seq sp dotted_str { zadd_rdata_txt_wireformat(zparser_conv_text(parser->rr_region, $3.str, $3.len), 0); } |