NSD 4.2.1

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

NSD 4.2.1

Stuart Henderson
Here's an update to NSD 4.2.1 (we're currently at 4.1.7 so see entries
from 21 March onwards in changelog).

https://github.com/NLnetLabs/nsd/blob/NSD_4_2_1_REL/doc/ChangeLog

I haven't read it thoroughly yet but thought I'd send it out early to
save anyone doing duplicate work. (There is also 4.2.2rc1 now, with
some fixes relating to fuzzing done by fcambus@, I haven't looked at
that at all yet).

Index: config.h.in
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/config.h.in,v
retrieving revision 1.29
diff -u -p -r1.29 config.h.in
--- config.h.in 30 Mar 2019 01:20:29 -0000 1.29
+++ config.h.in 6 Aug 2019 11:53:07 -0000
@@ -76,6 +76,14 @@
 /* if time.h provides ctime_r prototype */
 #undef HAVE_CTIME_R_PROTO
 
+/* Define to 1 if you have the declaration of `SSL_CTX_set_ecdh_auto', and to
+   0 if you don't. */
+#undef HAVE_DECL_SSL_CTX_SET_ECDH_AUTO
+
+/* Define to 1 if you have the declaration of `SSL_CTX_set_tmp_ecdh', and to 0
+   if you don't. */
+#undef HAVE_DECL_SSL_CTX_SET_TMP_ECDH
+
 /* Define to 1 if you have the `dup2' function. */
 #undef HAVE_DUP2
 
@@ -221,6 +229,9 @@
 /* Define to 1 if you have the `OPENSSL_init_ssl' function. */
 #undef HAVE_OPENSSL_INIT_SSL
 
+/* Define to 1 if you have the <openssl/ocsp.h> header file. */
+#undef HAVE_OPENSSL_OCSP_H
+
 /* Define to 1 if you have the <openssl/rand.h> header file. */
 #undef HAVE_OPENSSL_RAND_H
 
@@ -239,7 +250,7 @@
 /* Define to 1 if you have the `pwrite' function. */
 #undef HAVE_PWRITE
 
-/* Define to 1 if you have the `reallocarray' function. */
+/* If we have reallocarray(3) */
 #undef HAVE_REALLOCARRAY
 
 /* Define if recvmmsg is implemented */
@@ -281,6 +292,9 @@
 /* Define if you have the SSL libraries installed. */
 #undef HAVE_SSL
 
+/* Define to 1 if you have the `SSL_CTX_set_security_level' function. */
+#undef HAVE_SSL_CTX_SET_SECURITY_LEVEL
+
 /* Define to 1 if you have the <stdarg.h> header file. */
 #undef HAVE_STDARG_H
 
@@ -507,6 +521,9 @@
 /* Define to the default tcp timeout. */
 #undef TCP_TIMEOUT
 
+/* Define to the default DNS over TLS port. */
+#undef TLS_PORT
+
 /* Define to the default maximum udp message length. */
 #undef UDP_MAX_MESSAGE_LEN
 
@@ -550,6 +567,9 @@
 #endif
 
 
+/* Define this to enable TCP fast open. */
+#undef USE_TCP_FASTOPEN
+
 /* Define this to enable per-zone statistics gathering. */
 #undef USE_ZONE_STATS
 
@@ -687,6 +707,9 @@
 #  endif
 #  ifndef _BSD_SOURCE
 #    define _BSD_SOURCE 1
+#  endif
+#  ifndef _OPENBSD_SOURCE
+#    define _OPENBSD_SOURCE 1
 #  endif
 #  ifndef _DEFAULT_SOURCE
 #    define _DEFAULT_SOURCE 1
Index: configlexer.lex
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/configlexer.lex,v
retrieving revision 1.11
diff -u -p -r1.11 configlexer.lex
--- configlexer.lex 10 Dec 2018 16:09:11 -0000 1.11
+++ configlexer.lex 6 Aug 2019 11:53:07 -0000
@@ -201,9 +201,12 @@ ip-address{COLON} { LEXOUT(("v(%s) ", yy
 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;}
+send-buffer-size{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_SEND_BUFFER_SIZE;}
+receive-buffer-size{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_RECEIVE_BUFFER_SIZE;}
 debug-mode{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DEBUG_MODE;}
 use-systemd{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_USE_SYSTEMD;}
 hide-version{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_HIDE_VERSION;}
+hide-identity{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_HIDE_IDENTITY;}
 ip4-only{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_IP4_ONLY;}
 ip6-only{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_IP6_ONLY;}
 do-ip4{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DO_IP4;}
@@ -215,6 +218,7 @@ nsid{COLON} { LEXOUT(("v(%s) ", yytext)
 logfile{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_LOGFILE;}
 server-count{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_SERVER_COUNT;}
 tcp-count{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TCP_COUNT;}
+tcp-reject-overflow{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TCP_REJECT_OVERFLOW;}
 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;}
@@ -287,6 +291,10 @@ min-refresh-time{COLON} { LEXOUT(("v(%s)
 max-retry-time{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_MAX_RETRY_TIME;}
 min-retry-time{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_MIN_RETRY_TIME;}
 multi-master-check{COLON}      { LEXOUT(("v(%s) ", yytext)); return VAR_MULTI_MASTER_CHECK;}
+tls-service-key{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_SERVICE_KEY;}
+tls-service-ocsp{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_SERVICE_OCSP;}
+tls-service-pem{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_SERVICE_PEM;}
+tls-port{COLON}        { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_PORT;}
 {NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++;}
 
  /* Quoted strings. Strip leading and ending quotes */
Index: configparser.y
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/configparser.y,v
retrieving revision 1.23
diff -u -p -r1.23 configparser.y
--- configparser.y 10 Dec 2018 16:09:11 -0000 1.23
+++ configparser.y 6 Aug 2019 11:53:07 -0000
@@ -59,7 +59,7 @@ extern config_parser_state_type* cfg_par
 %token VAR_KEY
 %token VAR_ALGORITHM VAR_SECRET
 %token VAR_AXFR VAR_UDP
-%token VAR_VERBOSITY VAR_HIDE_VERSION
+%token VAR_VERBOSITY VAR_HIDE_VERSION VAR_HIDE_IDENTITY
 %token VAR_PATTERN VAR_INCLUDEPATTERN VAR_ZONELISTFILE
 %token VAR_REMOTE_CONTROL VAR_CONTROL_ENABLE VAR_CONTROL_INTERFACE
 %token VAR_CONTROL_PORT VAR_SERVER_KEY_FILE VAR_SERVER_CERT_FILE
@@ -76,6 +76,9 @@ extern config_parser_state_type* cfg_par
 %token VAR_DNSTAP_SEND_IDENTITY VAR_DNSTAP_SEND_VERSION VAR_DNSTAP_IDENTITY
 %token VAR_DNSTAP_VERSION VAR_DNSTAP_LOG_AUTH_QUERY_MESSAGES
 %token VAR_DNSTAP_LOG_AUTH_RESPONSE_MESSAGES
+%token VAR_TLS_SERVICE_KEY VAR_TLS_SERVICE_OCSP VAR_TLS_SERVICE_PEM VAR_TLS_PORT
+%token VAR_SEND_BUFFER_SIZE VAR_RECEIVE_BUFFER_SIZE
+%token VAR_TCP_REJECT_OVERFLOW
 
 %%
 toplevelvars: /* empty */ | toplevelvars toplevelvar ;
@@ -107,7 +110,11 @@ content_server: server_ip_address | serv
  server_zonefiles_check | server_do_ip4 | server_do_ip6 |
  server_zonefiles_write | server_log_time_ascii | server_round_robin |
  server_reuseport | server_version | server_ip_freebind |
- server_minimal_responses | server_refuse_any | server_use_systemd;
+ server_tls_service_key | server_tls_service_pem | server_tls_port |
+ server_minimal_responses | server_refuse_any | server_use_systemd |
+ server_hide_identity | server_tls_service_ocsp |
+ server_send_buffer_size | server_receive_buffer_size |
+ server_tcp_reject_overflow;
 server_ip_address: VAR_IP_ADDRESS STRING
  {
  OUTYY(("P(server_ip_address:%s)\n", $2));
@@ -138,14 +145,32 @@ server_ip_transparent: VAR_IP_TRANSPAREN
  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));
+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_send_buffer_size: VAR_SEND_BUFFER_SIZE STRING
+ {
+ int sz = atoi($2);
+ OUTYY(("P(server_send_buffer_size:%s)\n", $2));
+ if(sz < 0)
+ yyerror("non-negative number expected");
+ else cfg_parser->opt->send_buffer_size = sz;
+ }
+ ;
+server_receive_buffer_size: VAR_RECEIVE_BUFFER_SIZE STRING
+ {
+ int sz = atoi($2);
+ OUTYY(("P(server_receive_buffer_size:%s)\n", $2));
+ if(sz < 0)
+ yyerror("non-negative number expected");
+ else cfg_parser->opt->receive_buffer_size = sz;
+ }
+ ;
 server_debug_mode: VAR_DEBUG_MODE STRING
  {
  OUTYY(("P(server_debug_mode:%s)\n", $2));
@@ -175,6 +200,14 @@ server_hide_version: VAR_HIDE_VERSION ST
  else cfg_parser->opt->hide_version = (strcmp($2, "yes")==0);
  }
  ;
+server_hide_identity: VAR_HIDE_IDENTITY STRING
+ {
+ OUTYY(("P(server_hide_identity:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->opt->hide_identity = (strcmp($2, "yes")==0);
+ }
+ ;
 server_ip4_only: VAR_IP4_ONLY STRING
  {
  /* for backwards compatibility in config file with NSD3 */
@@ -339,6 +372,17 @@ server_tcp_count: VAR_TCP_COUNT STRING
  else cfg_parser->opt->tcp_count = atoi($2);
  }
  ;
+server_tcp_reject_overflow: VAR_TCP_REJECT_OVERFLOW STRING
+ {
+ OUTYY(("P(server_reject_overflow_tcp:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) {
+ yyerror("tcp-reject-overflow: expected yes or no.");
+ } else {
+ cfg_parser->opt->tcp_reject_overflow =
+ (strcmp($2, "yes")==0);
+ }
+ }
+ ;
 server_pidfile: VAR_PIDFILE STRING
  {
  OUTYY(("P(server_pidfile:%s)\n", $2));
@@ -529,7 +573,30 @@ server_zonefiles_write: VAR_ZONEFILES_WR
  else cfg_parser->opt->zonefiles_write = atoi($2);
  }
  ;
-
+server_tls_service_key: VAR_TLS_SERVICE_KEY STRING
+ {
+ OUTYY(("P(server_tls_service_key:%s)\n", $2));
+ cfg_parser->opt->tls_service_key = region_strdup(cfg_parser->opt->region, $2);
+ }
+ ;
+server_tls_service_ocsp: VAR_TLS_SERVICE_OCSP STRING
+ {
+ OUTYY(("P(server_tls_service_ocsp:%s)\n", $2));
+ cfg_parser->opt->tls_service_ocsp = region_strdup(cfg_parser->opt->region, $2);
+ }
+ ;
+server_tls_service_pem: VAR_TLS_SERVICE_PEM STRING
+ {
+ OUTYY(("P(server_tls_service_pem:%s)\n", $2));
+ cfg_parser->opt->tls_service_pem = region_strdup(cfg_parser->opt->region, $2);
+ }
+ ;
+server_tls_port: VAR_TLS_PORT STRING
+ {
+ OUTYY(("P(server_tls_port:%s)\n", $2));
+ cfg_parser->opt->tls_port = region_strdup(cfg_parser->opt->region, $2);
+ }
+ ;
 rcstart: VAR_REMOTE_CONTROL
  {
  OUTYY(("\nP(remote-control:)\n"));
@@ -714,7 +781,7 @@ zone_config_item: zone_zonefile | zone_a
  zone_outgoing_interface | zone_allow_axfr_fallback | include_pattern |
  zone_rrl_whitelist | zone_zonestats | zone_max_refresh_time |
  zone_min_refresh_time | zone_max_retry_time | zone_min_retry_time |
-       zone_size_limit_xfr | zone_multi_master_check;
+ zone_size_limit_xfr | zone_multi_master_check;
 pattern_name: VAR_NAME STRING
  {
  OUTYY(("P(pattern_name:%s)\n", $2));
Index: configure
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/configure,v
retrieving revision 1.42
diff -u -p -r1.42 configure
--- configure 30 Mar 2019 01:20:29 -0000 1.42
+++ configure 6 Aug 2019 11:53:07 -0000
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for NSD 4.1.27.
+# Generated by GNU Autoconf 2.69 for NSD 4.2.1.
 #
 # Report bugs to <[hidden email]>.
 #
@@ -580,8 +580,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='NSD'
 PACKAGE_TARNAME='nsd'
-PACKAGE_VERSION='4.1.27'
-PACKAGE_STRING='NSD 4.1.27'
+PACKAGE_VERSION='4.2.1'
+PACKAGE_STRING='NSD 4.2.1'
 PACKAGE_BUGREPORT='[hidden email]'
 PACKAGE_URL=''
 
@@ -744,6 +744,7 @@ with_dnstap_socket_path
 with_protobuf_c
 with_libfstrm
 enable_systemd
+enable_tcp_fastopen
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1296,7 +1297,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures NSD 4.1.27 to adapt to many kinds of systems.
+\`configure' configures NSD 4.2.1 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1357,7 +1358,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of NSD 4.1.27:";;
+     short | recursive ) echo "Configuration of NSD 4.2.1:";;
    esac
   cat <<\_ACEOF
 
@@ -1398,6 +1399,7 @@ Optional Features:
                           but unaligned reads.
   --enable-dnstap         Enable dnstap support (requires fstrm, protobuf-c)
   --enable-systemd        compile with systemd support
+  --enable-tcp-fastopen   Enable TCP Fast Open
 
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
@@ -1512,7 +1514,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-NSD configure 4.1.27
+NSD configure 4.2.1
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2221,7 +2223,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by NSD $as_me 4.1.27, which was
+It was created by NSD $as_me 4.2.1, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -8340,20 +8342,44 @@ esac
 fi
 
 
-ac_fn_c_check_func "$LINENO" "reallocarray" "ac_cv_func_reallocarray"
-if test "x$ac_cv_func_reallocarray" = xyes; then :
-  $as_echo "#define HAVE_REALLOCARRAY 1" >>confdefs.h
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for reallocarray" >&5
+$as_echo_n "checking for reallocarray... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$ac_includes_default
+
+#ifndef _OPENBSD_SOURCE
+#define _OPENBSD_SOURCE 1
+#endif
+#include <stdlib.h>
+int main(void) {
+ void* p = reallocarray(NULL, 10, 100);
+ free(p);
+ return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+$as_echo "#define HAVE_REALLOCARRAY 1" >>confdefs.h
+
 
 else
-  case " $LIBOBJS " in
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ case " $LIBOBJS " in
   *" reallocarray.$ac_objext "* ) ;;
   *) LIBOBJS="$LIBOBJS reallocarray.$ac_objext"
  ;;
 esac
 
-fi
-
 
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
 
 #
 # Check for b64_ntop (and assume result applies to b64_pton as well).
@@ -8536,6 +8562,11 @@ _ACEOF
 
 
 cat >>confdefs.h <<_ACEOF
+#define TLS_PORT "853"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
 #define MAXSYSLOGMSGLEN 512
 _ACEOF
 
@@ -9104,56 +9135,93 @@ fi
  fi
  SSL_LIBS="-lssl"
 
- for ac_header in openssl/ssl.h
+ for ac_header in openssl/ssl.h openssl/err.h openssl/rand.h openssl/ocsp.h
 do :
-  ac_fn_c_check_header_compile "$LINENO" "openssl/ssl.h" "ac_cv_header_openssl_ssl_h" "$ac_includes_default
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
 "
-if test "x$ac_cv_header_openssl_ssl_h" = xyes; then :
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
   cat >>confdefs.h <<_ACEOF
-#define HAVE_OPENSSL_SSL_H 1
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
 _ACEOF
 
 fi
 
 done
 
- for ac_header in openssl/err.h
+ for ac_func in HMAC_CTX_reset HMAC_CTX_new EVP_cleanup ERR_load_crypto_strings OPENSSL_init_crypto SSL_CTX_set_security_level
 do :
-  ac_fn_c_check_header_compile "$LINENO" "openssl/err.h" "ac_cv_header_openssl_err_h" "$ac_includes_default
-"
-if test "x$ac_cv_header_openssl_err_h" = xyes; then :
+  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
   cat >>confdefs.h <<_ACEOF
-#define HAVE_OPENSSL_ERR_H 1
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
 _ACEOF
 
 fi
-
 done
 
- for ac_header in openssl/rand.h
-do :
-  ac_fn_c_check_header_compile "$LINENO" "openssl/rand.h" "ac_cv_header_openssl_rand_h" "$ac_includes_default
+ ac_fn_c_check_decl "$LINENO" "SSL_CTX_set_ecdh_auto" "ac_cv_have_decl_SSL_CTX_set_ecdh_auto" "
+$ac_includes_default
+#ifdef HAVE_OPENSSL_ERR_H
+#include <openssl/err.h>
+#endif
+
+#ifdef HAVE_OPENSSL_RAND_H
+#include <openssl/rand.h>
+#endif
+
+#ifdef HAVE_OPENSSL_CONF_H
+#include <openssl/conf.h>
+#endif
+
+#ifdef HAVE_OPENSSL_ENGINE_H
+#include <openssl/engine.h>
+#endif
+#include <openssl/ssl.h>
+#include <openssl/evp.h>
+
 "
-if test "x$ac_cv_header_openssl_rand_h" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_OPENSSL_RAND_H 1
+if test "x$ac_cv_have_decl_SSL_CTX_set_ecdh_auto" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_SSL_CTX_SET_ECDH_AUTO $ac_have_decl
 _ACEOF
+ac_fn_c_check_decl "$LINENO" "SSL_CTX_set_tmp_ecdh" "ac_cv_have_decl_SSL_CTX_set_tmp_ecdh" "
+$ac_includes_default
+#ifdef HAVE_OPENSSL_ERR_H
+#include <openssl/err.h>
+#endif
 
-fi
+#ifdef HAVE_OPENSSL_RAND_H
+#include <openssl/rand.h>
+#endif
 
-done
+#ifdef HAVE_OPENSSL_CONF_H
+#include <openssl/conf.h>
+#endif
 
- for ac_func in HMAC_CTX_reset HMAC_CTX_new EVP_cleanup ERR_load_crypto_strings OPENSSL_init_crypto
-do :
-  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
+#ifdef HAVE_OPENSSL_ENGINE_H
+#include <openssl/engine.h>
+#endif
+#include <openssl/ssl.h>
+#include <openssl/evp.h>
 
+"
+if test "x$ac_cv_have_decl_SSL_CTX_set_tmp_ecdh" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
 fi
-done
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_SSL_CTX_SET_TMP_ECDH $ac_have_decl
+_ACEOF
+
 
 
  BAKLIBS="$LIBS"
@@ -9174,6 +9242,8 @@ done
 else
  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: No SSL, therefore remote-control is disabled" >&5
 $as_echo "$as_me: WARNING: No SSL, therefore remote-control is disabled" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: No SSL, therefore TLS is disabled" >&5
+$as_echo "$as_me: WARNING: No SSL, therefore TLS is disabled" >&2;}
 fi
 
 # Check whether --enable-nsec3 was given.
@@ -9648,6 +9718,33 @@ fi
 
 # Include systemd.m4 - end
 
+# Check whether --enable-tcp-fastopen was given.
+if test "${enable_tcp_fastopen+set}" = set; then :
+  enableval=$enable_tcp_fastopen;
+fi
+
+case "$enable_tcp_fastopen" in
+       yes)
+             ac_fn_c_check_decl "$LINENO" "TCP_FASTOPEN" "ac_cv_have_decl_TCP_FASTOPEN" "$ac_includes_default
+#include <netinet/tcp.h>
+
+"
+if test "x$ac_cv_have_decl_TCP_FASTOPEN" = xyes; then :
+
+else
+  as_fn_error $? "TCP Fast Open is not available: please rerun without --enable-tcp-fastopen" "$LINENO" 5
+fi
+
+
+cat >>confdefs.h <<_ACEOF
+#define USE_TCP_FASTOPEN 1
+_ACEOF
+
+               ;;
+       no|*)
+               ;;
+esac
+
 
 
 
@@ -10194,7 +10291,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_wri
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by NSD $as_me 4.1.27, which was
+This file was extended by NSD $as_me 4.2.1, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -10256,7 +10353,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-NSD config.status 4.1.27
+NSD config.status 4.2.1
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
Index: configure.ac
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/configure.ac,v
retrieving revision 1.42
diff -u -p -r1.42 configure.ac
--- configure.ac 30 Mar 2019 01:20:29 -0000 1.42
+++ configure.ac 6 Aug 2019 11:53:07 -0000
@@ -5,7 +5,7 @@ dnl
 sinclude(acx_nlnetlabs.m4)
 sinclude(dnstap/dnstap.m4)
 
-AC_INIT(NSD,4.1.27,[hidden email])
+AC_INIT(NSD,4.2.1,[hidden email])
 AC_CONFIG_HEADER([config.h])
 
 CFLAGS="$CFLAGS"
@@ -689,7 +689,24 @@ AC_REPLACE_FUNCS(strlcpy)
 AC_REPLACE_FUNCS(strptime)
 AC_REPLACE_FUNCS(pselect)
 AC_REPLACE_FUNCS(memmove)
-AC_REPLACE_FUNCS(reallocarray)
+AC_MSG_CHECKING([for reallocarray])
+AC_LINK_IFELSE([AC_LANG_SOURCE(AC_INCLUDES_DEFAULT
+[[
+#ifndef _OPENBSD_SOURCE
+#define _OPENBSD_SOURCE 1
+#endif
+#include <stdlib.h>
+int main(void) {
+ void* p = reallocarray(NULL, 10, 100);
+ free(p);
+ return 0;
+}
+]])], [AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_REALLOCARRAY, 1, [If we have reallocarray(3)])
+], [
+ AC_MSG_RESULT(no)
+ AC_LIBOBJ(reallocarray)
+])
 
 #
 # Check for b64_ntop (and assume result applies to b64_pton as well).
@@ -755,6 +772,7 @@ AC_DEFINE_UNQUOTED([TCP_MAX_MESSAGE_LEN]
 AC_DEFINE_UNQUOTED([UDP_PORT], ["53"], [Define to the default udp port.])
 AC_DEFINE_UNQUOTED([UDP_MAX_MESSAGE_LEN], [512], [Define to the default maximum udp message length.])
 AC_DEFINE_UNQUOTED([EDNS_MAX_MESSAGE_LEN], [4096], [Define to the default maximum message length with EDNS.])
+AC_DEFINE_UNQUOTED([TLS_PORT], ["853"], [Define to the default DNS over TLS port.])
 AC_DEFINE_UNQUOTED([MAXSYSLOGMSGLEN], [512], [Define to the maximum message length to pass to syslog.])
 AC_DEFINE_UNQUOTED([NSD_CONTROL_PORT], [8952], [Define to the default nsd-control port.])
 AC_DEFINE_UNQUOTED([NSD_CONTROL_VERSION], [1], [Define to nsd-control proto version.])
@@ -893,10 +911,29 @@ if test x$HAVE_SSL = x"yes"; then
  fi
  SSL_LIBS="-lssl"
  AC_SUBST(SSL_LIBS)
- 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 EVP_cleanup ERR_load_crypto_strings OPENSSL_init_crypto])
+ AC_CHECK_HEADERS([openssl/ssl.h openssl/err.h openssl/rand.h openssl/ocsp.h],,, [AC_INCLUDES_DEFAULT])
+ AC_CHECK_FUNCS([HMAC_CTX_reset HMAC_CTX_new EVP_cleanup ERR_load_crypto_strings OPENSSL_init_crypto SSL_CTX_set_security_level])
+ AC_CHECK_DECLS([SSL_CTX_set_ecdh_auto,SSL_CTX_set_tmp_ecdh], [], [], [
+AC_INCLUDES_DEFAULT
+#ifdef HAVE_OPENSSL_ERR_H
+#include <openssl/err.h>
+#endif
+
+#ifdef HAVE_OPENSSL_RAND_H
+#include <openssl/rand.h>
+#endif
+
+#ifdef HAVE_OPENSSL_CONF_H
+#include <openssl/conf.h>
+#endif
+
+#ifdef HAVE_OPENSSL_ENGINE_H
+#include <openssl/engine.h>
+#endif
+#include <openssl/ssl.h>
+#include <openssl/evp.h>
+])
+
 
  BAKLIBS="$LIBS"
  LIBS="-lssl $LIBS"
@@ -905,6 +942,7 @@ if test x$HAVE_SSL = x"yes"; then
 
 else
  AC_MSG_WARN([No SSL, therefore remote-control is disabled])
+ AC_MSG_WARN([No SSL, therefore TLS is disabled])
 fi
 
 AC_ARG_ENABLE(nsec3, AC_HELP_STRING([--disable-nsec3], [Disable NSEC3 support]))
@@ -987,6 +1025,18 @@ dt_DNSTAP([${localstatedir}/run/nsd-dnst
 sinclude(systemd.m4)
 # Include systemd.m4 - end
 
+AC_ARG_ENABLE(tcp-fastopen, AC_HELP_STRING([--enable-tcp-fastopen], [Enable TCP Fast Open]))
+case "$enable_tcp_fastopen" in
+       yes)
+             AC_CHECK_DECL([TCP_FASTOPEN], [], [AC_MSG_ERROR([TCP Fast Open is not available: please rerun without --enable-tcp-fastopen])], [AC_INCLUDES_DEFAULT
+#include <netinet/tcp.h>
+             ])
+               AC_DEFINE_UNQUOTED([USE_TCP_FASTOPEN], [1], [Define this to enable TCP fast open.])
+               ;;
+       no|*)
+               ;;
+esac
+
 AH_BOTTOM([
 /* define before includes as it specifies what standard to use. */
 #if (defined(HAVE_PSELECT) && !defined (HAVE_PSELECT_PROTO)) \
@@ -1000,6 +1050,9 @@ AH_BOTTOM([
 #  endif
 #  ifndef _BSD_SOURCE
 #    define _BSD_SOURCE 1
+#  endif
+#  ifndef _OPENBSD_SOURCE
+#    define _OPENBSD_SOURCE 1
 #  endif
 #  ifndef _DEFAULT_SOURCE
 #    define _DEFAULT_SOURCE 1
Index: ipc.c
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/ipc.c,v
retrieving revision 1.6
diff -u -p -r1.6 ipc.c
--- ipc.c 10 Dec 2018 16:09:11 -0000 1.6
+++ ipc.c 6 Aug 2019 11:53:07 -0000
@@ -37,6 +37,7 @@ ipc_child_quit(struct nsd* nsd)
 {
  /* call shutdown and quit routines */
  nsd->mode = NSD_QUIT;
+ service_remaining_tcp(nsd);
 #ifdef BIND8_STATS
  bind8_stats(nsd);
 #endif /* BIND8_STATS */
@@ -267,6 +268,8 @@ stats_add(struct nsdst* total, struct ns
  total->qudp6 += s->qudp6;
  total->ctcp += s->ctcp;
  total->ctcp6 += s->ctcp6;
+ total->ctls += s->ctls;
+ total->ctls6 += s->ctls6;
  for(i=0; i<sizeof(total->rcode)/sizeof(stc_type); i++)
  total->rcode[i] += s->rcode[i];
  for(i=0; i<sizeof(total->opcode)/sizeof(stc_type); i++)
@@ -298,6 +301,8 @@ stats_subtract(struct nsdst* total, stru
  total->qudp6 -= s->qudp6;
  total->ctcp -= s->ctcp;
  total->ctcp6 -= s->ctcp6;
+ total->ctls -= s->ctls;
+ total->ctls6 -= s->ctls6;
  for(i=0; i<sizeof(total->rcode)/sizeof(stc_type); i++)
  total->rcode[i] -= s->rcode[i];
  for(i=0; i<sizeof(total->opcode)/sizeof(stc_type); i++)
@@ -324,7 +329,8 @@ read_child_stats(struct nsd* nsd, struct
  "%d: %s", (int)child->pid, strerror(errno));
  } else {
  stats_add(&nsd->st, &s);
- child->query_count = s.qudp + s.qudp6 + s.ctcp + s.ctcp6;
+ child->query_count = s.qudp + s.qudp6 + s.ctcp + s.ctcp6
+ + s.ctls + s.ctls6;
  /* we know that the child is going to close the connection
  * now (this is an ACK of the QUIT_W_STATS so we know the
  * child is done, no longer sending e.g. NOTIFY contents) */
@@ -593,6 +599,7 @@ ipc_xfrd_set_listening(struct xfrd_state
  int fd = xfrd->ipc_handler.ev_fd;
  struct event_base* base = xfrd->event_base;
  event_del(&xfrd->ipc_handler);
+ memset(&xfrd->ipc_handler, 0, sizeof(xfrd->ipc_handler));
  event_set(&xfrd->ipc_handler, fd, mode, xfrd_handle_ipc, xfrd);
  if(event_base_set(base, &xfrd->ipc_handler) != 0)
  log_msg(LOG_ERR, "ipc: cannot set event_base");
Index: nsd-checkconf.8.in
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/nsd-checkconf.8.in,v
retrieving revision 1.25
diff -u -p -r1.25 nsd-checkconf.8.in
--- nsd-checkconf.8.in 30 Mar 2019 01:20:29 -0000 1.25
+++ nsd-checkconf.8.in 6 Aug 2019 11:53:07 -0000
@@ -1,4 +1,4 @@
-.TH "nsd\-checkconf" "8" "Mar 25, 2019" "NLnet Labs" "nsd 4.1.27"
+.TH "nsd\-checkconf" "8" "Jul  9, 2019" "NLnet Labs" "nsd 4.2.1"
 .\" Copyright (c) 2001\-2008, NLnet Labs. All rights reserved.
 .\" See LICENSE for the license.
 .SH "NAME"
Index: nsd-checkconf.c
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/nsd-checkconf.c,v
retrieving revision 1.23
diff -u -p -r1.23 nsd-checkconf.c
--- nsd-checkconf.c 10 Dec 2018 16:09:11 -0000 1.23
+++ nsd-checkconf.c 6 Aug 2019 11:53:07 -0000
@@ -366,11 +366,13 @@ config_print_zone(nsd_options_type* opt,
  SERV_GET_BIN(do_ip6, o);
  SERV_GET_BIN(reuseport, o);
  SERV_GET_BIN(hide_version, o);
+ SERV_GET_BIN(hide_identity, o);
  SERV_GET_BIN(zonefiles_check, o);
  SERV_GET_BIN(log_time_ascii, o);
  SERV_GET_BIN(round_robin, o);
  SERV_GET_BIN(minimal_responses, o);
  SERV_GET_BIN(refuse_any, o);
+ SERV_GET_BIN(tcp_reject_overflow, o);
  /* str */
  SERV_GET_PATH(final, database, o);
  SERV_GET_STR(identity, o);
@@ -385,6 +387,10 @@ config_print_zone(nsd_options_type* opt,
  SERV_GET_PATH(final, xfrdir, o);
  SERV_GET_PATH(final, zonelistfile, o);
  SERV_GET_STR(port, o);
+ SERV_GET_STR(tls_service_key, o);
+ SERV_GET_STR(tls_service_ocsp, o);
+ SERV_GET_STR(tls_service_pem, o);
+ SERV_GET_STR(tls_port, o);
  /* int */
  SERV_GET_INT(server_count, o);
  SERV_GET_INT(tcp_count, o);
@@ -397,6 +403,8 @@ config_print_zone(nsd_options_type* opt,
  SERV_GET_INT(statistics, o);
  SERV_GET_INT(xfrd_reload_timeout, o);
  SERV_GET_INT(verbosity, o);
+ SERV_GET_INT(send_buffer_size, o);
+ SERV_GET_INT(receive_buffer_size, o);
 #ifdef RATELIMIT
  SERV_GET_INT(rrl_size, o);
  SERV_GET_INT(rrl_ratelimit, o);
@@ -493,7 +501,12 @@ config_test_print_server(nsd_options_typ
  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");
+ printf("\tsend-buffer-size: %d\n", opt->send_buffer_size);
+ printf("\treceive-buffer-size: %d\n", opt->receive_buffer_size);
  printf("\thide-version: %s\n", opt->hide_version?"yes":"no");
+ printf("\thide-identity: %s\n", opt->hide_identity?"yes":"no");
+ printf("\ttcp-reject-overflow: %s\n",
+ opt->tcp_reject_overflow ? "yes" : "no");
  print_string_var("database:", opt->database);
  print_string_var("identity:", opt->identity);
  print_string_var("version:", opt->version);
@@ -536,6 +549,10 @@ config_test_print_server(nsd_options_typ
 #endif
  printf("\tzonefiles-check: %s\n", opt->zonefiles_check?"yes":"no");
  printf("\tzonefiles-write: %d\n", opt->zonefiles_write);
+ print_string_var("tls-service-key:", opt->tls_service_key);
+ print_string_var("tls-service-pem:", opt->tls_service_pem);
+ print_string_var("tls-service-ocsp:", opt->tls_service_ocsp);
+ print_string_var("tls-port:", opt->tls_port);
 
 #ifdef USE_DNSTAP
  printf("\ndnstap:\n");
@@ -581,7 +598,6 @@ config_test_print_server(nsd_options_typ
  print_string_var("name:", zone->name);
  print_zone_content_elems(zone->pattern);
  }
-
 }
 
 static int
@@ -720,7 +736,7 @@ main(int argc, char* argv[])
  log_init("nsd-checkconf");
 
  /* Parse the command line... */
- while ((c = getopt(argc, argv, "vfo:a:p:s:z:")) != -1) {
+ while ((c = getopt(argc, argv, "vfho:a:p:s:z:")) != -1) {
  switch (c) {
  case 'v':
  verbose = 1;
@@ -753,6 +769,7 @@ main(int argc, char* argv[])
  case 'z':
  conf_zone = optarg;
  break;
+ case 'h':
  default:
  usage();
  };
Index: nsd-checkzone.8.in
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/nsd-checkzone.8.in,v
retrieving revision 1.9
diff -u -p -r1.9 nsd-checkzone.8.in
--- nsd-checkzone.8.in 30 Mar 2019 01:20:29 -0000 1.9
+++ nsd-checkzone.8.in 6 Aug 2019 11:53:07 -0000
@@ -1,4 +1,4 @@
-.TH "nsd\-checkzone" "8" "Mar 25, 2019" "NLnet Labs" "nsd 4.1.27"
+.TH "nsd\-checkzone" "8" "Jul  9, 2019" "NLnet Labs" "nsd 4.2.1"
 .\" Copyright (c) 2014, NLnet Labs. All rights reserved.
 .\" See LICENSE for the license.
 .SH "NAME"
Index: nsd-control.8.in
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/nsd-control.8.in,v
retrieving revision 1.13
diff -u -p -r1.13 nsd-control.8.in
--- nsd-control.8.in 30 Mar 2019 01:20:29 -0000 1.13
+++ nsd-control.8.in 6 Aug 2019 11:53:07 -0000
@@ -1,4 +1,4 @@
-.TH "nsd\-control" "8" "Mar 25, 2019" "NLnet Labs" "nsd 4.1.27"
+.TH "nsd\-control" "8" "Jul  9, 2019" "NLnet Labs" "nsd 4.2.1"
 .\" Copyright (c) 2011, NLnet Labs. All rights reserved.
 .\" See LICENSE for the license.
 .SH "NAME"
@@ -192,7 +192,7 @@ After running the script as root, turn o
 The \fIstats\fR command shows a number of statistic counters.
 .TP
 .I num.queries
-number of queries received (the tcp and udp queries added up).
+number of queries received (the tls, tcp and udp queries added up).
 .TP
 .I serverX.queries
 number of queries handled by the server process.  The number of
@@ -252,6 +252,12 @@ number of connections over TCP ip4.
 .TP
 .I num.tcp6
 number of connections over TCP ip6.
+.TP
+.I num.tls
+number of connections over TLS ip4.  TLS queries are not part of num.tcp.
+.TP
+.I num.tls6
+number of connections over TLS ip6.  TLS queries are not part of num.tcp6.
 .TP
 .I num.answer_wo_aa
 number of answers with NOERROR rcode and without AA flag, this includes the referrals.
Index: nsd.8.in
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/nsd.8.in,v
retrieving revision 1.26
diff -u -p -r1.26 nsd.8.in
--- nsd.8.in 30 Mar 2019 01:20:29 -0000 1.26
+++ nsd.8.in 6 Aug 2019 11:53:07 -0000
@@ -1,9 +1,9 @@
-.TH "NSD" "8" "Mar 25, 2019" "NLnet Labs" "NSD 4.1.27"
+.TH "NSD" "8" "Jul  9, 2019" "NLnet Labs" "NSD 4.2.1"
 .\" 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.27.
+\- Name Server Daemon (NSD) version 4.2.1.
 .SH "SYNOPSIS"
 .B nsd
 .RB [ \-4 ]
Index: nsd.c
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/nsd.c,v
retrieving revision 1.33
diff -u -p -r1.33 nsd.c
--- nsd.c 30 Mar 2019 01:20:29 -0000 1.33
+++ nsd.c 6 Aug 2019 11:53:07 -0000
@@ -661,6 +661,9 @@ main(int argc, char *argv[])
  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;
+#ifdef HAVE_SSL
+ nsd.tls_ctx = NULL;
+#endif
 
  if(udp_port == 0)
  {
@@ -942,10 +945,19 @@ main(int argc, char *argv[])
  "not be started", argv0);
  }
 #if defined(HAVE_SSL)
+ if(nsd.options->control_enable || (nsd.options->tls_service_key && nsd.options->tls_service_key[0])) {
+ perform_openssl_init();
+ }
  if(nsd.options->control_enable) {
  /* read ssl keys while superuser and outside chroot */
  if(!(nsd.rc = daemon_remote_create(nsd.options)))
  error("could not perform remote control setup");
+ }
+ if(nsd.options->tls_service_key && nsd.options->tls_service_key[0]
+   && nsd.options->tls_service_pem && nsd.options->tls_service_pem[0]) {
+ if(!(nsd.tls_ctx = server_tls_ctx_create(&nsd, NULL,
+ nsd.options->tls_service_ocsp)))
+ error("could not set up tls SSL_CTX");
  }
 #endif /* HAVE_SSL */
 
Index: nsd.conf.5.in
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/nsd.conf.5.in,v
retrieving revision 1.31
diff -u -p -r1.31 nsd.conf.5.in
--- nsd.conf.5.in 30 Mar 2019 01:20:29 -0000 1.31
+++ nsd.conf.5.in 6 Aug 2019 11:53:07 -0000
@@ -1,4 +1,4 @@
-.TH "nsd.conf" "5" "Mar 25, 2019" "NLnet Labs" "nsd 4.1.27"
+.TH "nsd.conf" "5" "Jul  9, 2019" "NLnet Labs" "nsd 4.2.1"
 .\" Copyright (c) 2001\-2008, NLnet Labs. All rights reserved.
 .\" See LICENSE for the license.
 .SH "NAME"
@@ -181,6 +181,12 @@ than 1 (such as, equal to the number of
 It works on Linux, but does not work on FreeBSD, and likely does not
 work on other systems.
 .TP
+.B send\-buffer\-size:\fR <number>
+Set the send buffer size for query-servicing sockets.  Set to 0 to use the default settings.
+.TP
+.B receive\-buffer\-size:\fR <number>
+Set the receive buffer size for query-servicing sockets.  Set to 0 to use the default settings.
+.TP
 .B debug\-mode:\fR <yes or no>
 Turns on debugging mode for nsd, does not fork a daemon process.
 Default is no. Same as commandline option
@@ -217,6 +223,7 @@ Returns the specified identity when aske
 Default is the name as returned by gethostname(3). Same as
 commandline option
 .BR \-i .
+See hide\-identity to set the server to not respond to such queries.
 .TP
 .B version:\fR <string>
 Returns the specified version string when asked for CH TXT version.server,
@@ -244,6 +251,10 @@ The maximum number of concurrent, active
 Default is 100. Same as commandline option
 .BR \-n .
 .TP
+.B tcp\-reject\-overflow:\fR <yes or no>
+If set to yes, TCP connections made beyond the maximum set by tcp-count will
+be dropped immediately (accepted and closed).  Default is no.
+.TP
 .B tcp\-query\-count:\fR <number>
 The maximum number of queries served on a single TCP connection.
 Default is 0, meaning there is no maximum.
@@ -359,6 +370,10 @@ And notify refusal, and axfr request ref
 Prevent NSD from replying with the version string on CHAOS class
 queries.  Default is no.
 .TP
+.B hide\-identity:\fR <yes or no>
+Prevent NSD from replying with the identity string on CHAOS class
+queries.  Default is no.
+.TP
 .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
@@ -436,6 +451,38 @@ whitelisted. Default @ratelimit_default@
 specific queries to receive this qps limit instead of the normal limit.
 With the value 0 the rate is unlimited.
 .\" rrlend
+.TP
+.B tls\-service\-key:\fR <filename>
+If enabled, the server provides TLS service on TCP sockets with the TLS
+service port number.  The port number (853) is configured with tls\-port.
+To turn it on, create an interface: option line in config with @port
+appended to the IP-address.  This creates the extra socket on which the
+DNS over TLS service is provided.
+.IP
+The file is the private key for the TLS session. The public certificate is
+in the tls-service-pem file. Default is "", turned off. Requires a
+restart (a reload is not enough) if changed, because the private key is
+read while root permissions are held and before chroot (if any).
+.TP
+.B tls\-service\-pem:\fR <filename>
+The public key certificate pem file for the tls service. Default is "", turned off.
+.TP
+.B tls\-service\-ocsp:\fR <filename>
+The ocsp pem file for the tls service, for OCSP stapling.  Default is "",
+turned off.  An external process prepares and updates the OCSP stapling data.
+Like this,
+.RS 9
+openssl ocsp -no_nonce \\
+   -respout /path/to/ocsp.pem \\
+   -CAfile /path/to/ca_and_any_intermediate.pem \\
+   -issuer /path/to/direct_issuer.pem \\
+   -cert /path/to/cert.pem \\
+   -url "$( openssl x509 -noout -text -in /path/to/cert.pem | grep 'OCSP - URI:' | cut -d: -f2,3 )"
+.RE
+.TP
+.B tls\-port:\fR <number>
+The port number on which to provide TCP TLS service, default is 853, only
+interfaces configured with that port number as @number get DNS over TLS service.
 .SS "Remote Control"
 The
 .B remote\-control:
Index: nsd.conf.sample.in
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/nsd.conf.sample.in,v
retrieving revision 1.10
diff -u -p -r1.10 nsd.conf.sample.in
--- nsd.conf.sample.in 10 Dec 2018 16:09:11 -0000 1.10
+++ nsd.conf.sample.in 6 Aug 2019 11:53:07 -0000
@@ -33,6 +33,14 @@ server:
  # use the reuseport socket option for performance. Default no.
  # reuseport: no
 
+ # override maximum socket send buffer size.  Default of 0 results in
+ # send buffer size being set to 1048576 (bytes).
+ # send-buffer-size: 1048576
+
+ # override maximum socket receive buffer size. Default of 0 results in
+ # receive buffer size being set to 1048576 (bytes).
+ # receive-buffer-size: 1048576
+
  # enable debug mode, does not fork daemon process into the background.
  # debug-mode: no
 
@@ -85,6 +93,9 @@ server:
  # don't answer VERSION.BIND and VERSION.SERVER CHAOS class queries
  # hide-version: no
 
+ # don't answer HOSTNAME.BIND and ID.SERVER CHAOS class queries
+ # hide-identity: no
+
  # version string the server responds with for chaos queries.
  # default is 'NSD x.y.z' with the server's version number.
  # version: "NSD"
@@ -98,6 +109,11 @@ server:
  # Maximum number of concurrent TCP connections per server.
  # tcp-count: 100
 
+ # Accept (and immediately close) TCP connections after maximum number
+ # of connections is reached to prevent kernel connection queue from
+ # growing.
+ # tcp-reject-overflow: no
+
  # Maximum number of queries served on a single TCP connection.
  # By default 0, which means no maximum.
  # tcp-query-count: 0
@@ -188,6 +204,14 @@ server:
  # dnstap-version: ""
  # dnstap-log-auth-query-messages: no
  # dnstap-log-auth-response-messages: no
+
+ # Service clients over TLS (on the TCP sockets), with plain DNS inside
+ # the TLS stream. Give the certificate to use and private key.
+ # Default is "" (disabled). Requires restart to take effect.
+ # tls-service-key: "path/to/privatekeyfile.key"
+ # tls-service-pem: "path/to/publiccertfile.pem"
+ # tls-service-ocsp: "path/to/ocsp.pem"
+ # tls-port: 853
 
 # Remote control config section.
 remote-control:
Index: nsd.h
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/nsd.h,v
retrieving revision 1.6
diff -u -p -r1.6 nsd.h
--- nsd.h 10 Dec 2018 16:09:11 -0000 1.6
+++ nsd.h 6 Aug 2019 11:53:07 -0000
@@ -11,6 +11,9 @@
 #define _NSD_H_
 
 #include <signal.h>
+#ifdef HAVE_OPENSSL_SSL_H
+#include <openssl/ssl.h>
+#endif
 
 #include "dns.h"
 #include "edns.h"
@@ -244,6 +247,7 @@ struct nsd
  stc_type qclass[4]; /* Class IN or Class CH or other */
  stc_type qudp, qudp6; /* Number of queries udp and udp6 */
  stc_type ctcp, ctcp6; /* Number of tcp and tcp6 connections */
+ stc_type ctls, ctls6; /* Number of tls and tls6 connections */
  stc_type rcode[17], opcode[6]; /* Rcodes & opcodes */
  /* Dropped, truncated, queries for nonconfigured zone, tx errors */
  stc_type dropped, truncated, wrongzone, txerr, rxerr;
@@ -276,6 +280,11 @@ struct nsd
  unsigned int err_limit_count;
 
  struct nsd_options* options;
+
+#ifdef HAVE_SSL
+ /* TLS specific configuration */
+ SSL_CTX *tls_ctx;
+#endif
 };
 
 extern struct nsd nsd;
@@ -295,6 +304,7 @@ void server_child(struct nsd *nsd);
 void server_shutdown(struct nsd *nsd) ATTR_NORETURN;
 void server_close_all_sockets(struct nsd_socket sockets[], size_t n);
 struct event_base* nsd_child_event_base(void);
+void service_remaining_tcp(struct nsd* nsd);
 /* extra domain numbers for temporary domains */
 #define EXTRA_DOMAIN_NUMBERS 1024
 #define SLOW_ACCEPT_TIMEOUT 2 /* in seconds */
@@ -311,6 +321,11 @@ void server_prepare_xfrd(struct nsd *nsd
 void server_start_xfrd(struct nsd *nsd, int del_db, int reload_active);
 /* send SOA serial numbers to xfrd */
 void server_send_soa_xfrd(struct nsd *nsd, int shortsoa);
+#ifdef HAVE_SSL
+SSL_CTX* server_tls_ctx_setup(char* key, char* pem, char* verifypem);
+SSL_CTX* server_tls_ctx_create(struct nsd *nsd, char* verifypem, char* ocspfile);
+void perform_openssl_init(void);
+#endif
 ssize_t block_read(struct nsd* nsd, int s, void* p, ssize_t sz, int timeout);
 
 #endif /* _NSD_H_ */
Index: options.c
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/options.c,v
retrieving revision 1.15
diff -u -p -r1.15 options.c
--- options.c 10 Dec 2018 16:09:11 -0000 1.15
+++ options.c 6 Aug 2019 11:53:07 -0000
@@ -52,9 +52,12 @@ nsd_options_create(region_type* region)
  opt->ip_addresses = NULL;
  opt->ip_transparent = 0;
  opt->ip_freebind = 0;
+ opt->send_buffer_size = 0;
+ opt->receive_buffer_size = 0;
  opt->debug_mode = 0;
  opt->verbosity = 0;
  opt->hide_version = 0;
+ opt->hide_identity = 0;
  opt->do_ip4 = 1;
  opt->do_ip6 = 1;
  opt->database = DBFILE;
@@ -68,6 +71,7 @@ nsd_options_create(region_type* region)
  opt->refuse_any = 1;
  opt->server_count = 1;
  opt->tcp_count = 100;
+ opt->tcp_reject_overflow = 0;
  opt->tcp_query_count = 0;
  opt->tcp_timeout = TCP_TIMEOUT;
  opt->tcp_mss = 0;
@@ -113,6 +117,10 @@ nsd_options_create(region_type* region)
  opt->zonefiles_write = ZONEFILES_WRITE_INTERVAL;
  else opt->zonefiles_write = 0;
  opt->xfrd_reload_timeout = 1;
+ opt->tls_service_key = NULL;
+ opt->tls_service_ocsp = NULL;
+ opt->tls_service_pem = NULL;
+ opt->tls_port = TLS_PORT;
  opt->control_enable = 0;
  opt->control_interface = NULL;
  opt->control_port = NSD_CONTROL_PORT;
Index: options.h
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/options.h,v
retrieving revision 1.14
diff -u -p -r1.14 options.h
--- options.h 30 Mar 2019 01:20:29 -0000 1.14
+++ options.h 6 Aug 2019 11:53:07 -0000
@@ -61,9 +61,12 @@ struct nsd_options {
 
  int ip_transparent;
  int ip_freebind;
+ int send_buffer_size;
+ int receive_buffer_size;
  int debug_mode;
  int verbosity;
  int hide_version;
+ int hide_identity;
  int do_ip4;
  int do_ip6;
  const char* database;
@@ -72,6 +75,7 @@ struct nsd_options {
  const char* logfile;
  int server_count;
  int tcp_count;
+ int tcp_reject_overflow;
  int tcp_query_count;
  int tcp_timeout;
  int tcp_mss;
@@ -96,6 +100,15 @@ struct nsd_options {
  int minimal_responses;
  int refuse_any;
  int reuseport;
+
+ /* private key file for TLS */
+ char* tls_service_key;
+ /* ocsp stapling file for TLS */
+ char* tls_service_ocsp;
+ /* certificate file for TLS */
+ char* tls_service_pem;
+ /* TLS dedicated port */
+ const char* tls_port;
 
         /** remote control section. enable toggle. */
  int control_enable;
Index: query.c
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/query.c,v
retrieving revision 1.31
diff -u -p -r1.31 query.c
--- query.c 30 Mar 2019 01:22:12 -0000 1.31
+++ query.c 6 Aug 2019 11:53:07 -0000
@@ -530,13 +530,17 @@ answer_chaos(struct nsd *nsd, query_type
     (q->qname->name_size ==  15
      && memcmp(dname_name(q->qname), "\010hostname\004bind", 15) == 0))
  {
- /* Add ID */
- query_addtxt(q,
+ if(!nsd->options->hide_identity) {
+ /* Add ID */
+ query_addtxt(q,
      buffer_begin(q->packet) + QHEADERSZ,
      CLASS_CH,
      0,
      nsd->identity);
- ANCOUNT_SET(q->packet, ANCOUNT(q->packet) + 1);
+ ANCOUNT_SET(q->packet, ANCOUNT(q->packet) + 1);
+ } else {
+ RCODE_SET(q->packet, RCODE_REFUSE);
+ }
  } else if ((q->qname->name_size == 16
     && memcmp(dname_name(q->qname), "\007version\006server", 16) == 0) ||
    (q->qname->name_size == 14
Index: remote.c
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/remote.c,v
retrieving revision 1.17
diff -u -p -r1.17 remote.c
--- remote.c 30 Mar 2019 01:20:29 -0000 1.17
+++ remote.c 6 Aug 2019 11:53:07 -0000
@@ -252,48 +252,13 @@ timeval_subtract(struct timeval* d, cons
 static int
 remote_setup_ctx(struct daemon_remote* rc, struct nsd_options* cfg)
 {
- char* s_cert;
- char* s_key;
- rc->ctx = SSL_CTX_new(SSLv23_server_method());
+ char* s_cert = cfg->server_cert_file;
+ char* s_key = cfg->server_key_file;
+ rc->ctx = server_tls_ctx_setup(s_key, s_cert, s_cert);
  if(!rc->ctx) {
- log_crypto_err("could not SSL_CTX_new");
+ log_msg(LOG_ERR, "could not setup remote control TLS context");
  return 0;
  }
- /* no SSLv2, SSLv3 because has defects */
- if((SSL_CTX_set_options(rc->ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2)
- != SSL_OP_NO_SSLv2){
- log_crypto_err("could not set SSL_OP_NO_SSLv2");
- return 0;
- }
- if((SSL_CTX_set_options(rc->ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3)
- != SSL_OP_NO_SSLv3){
- log_crypto_err("could not set SSL_OP_NO_SSLv3");
- return 0;
- }
- s_cert = cfg->server_cert_file;
- s_key = cfg->server_key_file;
- VERBOSITY(2, (LOG_INFO, "setup SSL certificates"));
- if (!SSL_CTX_use_certificate_file(rc->ctx,s_cert,SSL_FILETYPE_PEM)) {
- log_msg(LOG_ERR, "Error for server-cert-file: %s", s_cert);
- log_crypto_err("Error in SSL_CTX use_certificate_file");
- return 0;
- }
- if(!SSL_CTX_use_PrivateKey_file(rc->ctx,s_key,SSL_FILETYPE_PEM)) {
- log_msg(LOG_ERR, "Error for server-key-file: %s", s_key);
- log_crypto_err("Error in SSL_CTX use_PrivateKey_file");
- return 0;
- }
- if(!SSL_CTX_check_private_key(rc->ctx)) {
- log_msg(LOG_ERR, "Error for server-key-file: %s", s_key);
- log_crypto_err("Error in SSL_CTX check_private_key");
- return 0;
- }
- if(!SSL_CTX_load_verify_locations(rc->ctx, s_cert, NULL)) {
- log_crypto_err("Error setting up SSL_CTX verify locations");
- return 0;
- }
- SSL_CTX_set_client_CA_list(rc->ctx, SSL_load_client_CA_file(s_cert));
- SSL_CTX_set_verify(rc->ctx, SSL_VERIFY_PEER, NULL);
  return 1;
 }
 
@@ -305,38 +270,6 @@ daemon_remote_create(struct nsd_options*
  rc->max_active = 10;
  assert(cfg->control_enable);
 
- /* init SSL library */
-#ifdef HAVE_ERR_LOAD_CRYPTO_STRINGS
- ERR_load_crypto_strings();
-#endif
- ERR_load_SSL_strings();
-#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO)
- OpenSSL_add_all_algorithms();
-#else
- OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
- | OPENSSL_INIT_ADD_ALL_DIGESTS
- | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
-#endif
-#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
- (void)SSL_library_init();
-#else
- OPENSSL_init_ssl(0, NULL);
-#endif
-
- if(!RAND_status()) {
- /* try to seed it */
- unsigned char buf[256];
- unsigned int v, seed=(unsigned)time(NULL) ^ (unsigned)getpid();
- size_t i;
- v = seed;
- for(i=0; i<256/sizeof(v); i++) {
- memmove(buf+i*sizeof(v), &v, sizeof(v));
- v = v*seed + (unsigned int)i;
- }
- RAND_seed(buf, 256);
- log_msg(LOG_WARNING, "warning: no entropy, seeding openssl PRNG with time");
- }
-
  if(options_remote_is_address(cfg)) {
  if(!remote_setup_ctx(rc, cfg)) {
  daemon_remote_delete(rc);
@@ -593,6 +526,7 @@ daemon_remote_attach(struct daemon_remot
  for(p = rc->accept_list; p; p = p->next) {
  /* add event */
  fd = p->c.ev_fd;
+ memset(&p->c, 0, sizeof(p->c));
  event_set(&p->c, fd, EV_PERSIST|EV_READ, remote_accept_callback,
  p);
  if(event_base_set(xfrd->event_base, &p->c) != 0)
@@ -670,6 +604,7 @@ remote_accept_callback(int fd, short eve
  n->tval.tv_usec = 0L;
  n->fd = newfd;
 
+ memset(&n->c, 0, sizeof(n->c));
  event_set(&n->c, newfd, EV_PERSIST|EV_TIMEOUT|EV_READ,
  remote_control_callback, n);
  if(event_base_set(xfrd->event_base, &n->c) != 0) {
@@ -2372,6 +2307,7 @@ remote_handshake_later(struct daemon_rem
  }
  s->shake_state = rc_hs_read;
  event_del(&s->c);
+ memset(&s->c, 0, sizeof(s->c));
  event_set(&s->c, fd, EV_PERSIST|EV_TIMEOUT|EV_READ,
  remote_control_callback, s);
  if(event_base_set(xfrd->event_base, &s->c) != 0)
@@ -2386,6 +2322,7 @@ remote_handshake_later(struct daemon_rem
  }
  s->shake_state = rc_hs_write;
  event_del(&s->c);
+ memset(&s->c, 0, sizeof(s->c));
  event_set(&s->c, fd, EV_PERSIST|EV_TIMEOUT|EV_WRITE,
  remote_control_callback, s);
  if(event_base_set(xfrd->event_base, &s->c) != 0)
@@ -2553,6 +2490,12 @@ print_stat_block(RES* ssl, char* n, char
  /* ctcp6 */
  if(!ssl_printf(ssl, "%s%snum.tcp6=%lu\n", n, d, (unsigned long)st->ctcp6))
  return;
+ /* ctls */
+ if(!ssl_printf(ssl, "%s%snum.tls=%lu\n", n, d, (unsigned long)st->ctls))
+ return;
+ /* ctls6 */
+ if(!ssl_printf(ssl, "%s%snum.tls6=%lu\n", n, d, (unsigned long)st->ctls6))
+ return;
 
  /* nona */
  if(!ssl_printf(ssl, "%s%snum.answer_wo_aa=%lu\n", n, d,
@@ -2640,7 +2583,7 @@ zonestat_print(RES* ssl, xfrd_state_type
  /* stat0 contains the details that we want to print */
  if(!ssl_printf(ssl, "%s%snum.queries=%lu\n", name, ".",
  (unsigned long)(stat0.qudp + stat0.qudp6 + stat0.ctcp +
- stat0.ctcp6)))
+ stat0.ctcp6 + stat0.ctls + stat0.ctls6)))
  return;
  print_stat_block(ssl, name, ".", &stat0);
  }
Index: server.c
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/server.c,v
retrieving revision 1.35
diff -u -p -r1.35 server.c
--- server.c 30 Mar 2019 01:20:29 -0000 1.35
+++ server.c 6 Aug 2019 11:53:07 -0000
@@ -16,6 +16,9 @@
 #include <sys/wait.h>
 
 #include <netinet/in.h>
+#ifdef USE_TCP_FASTOPEN
+  #include <netinet/tcp.h>
+#endif
 #include <arpa/inet.h>
 
 #include <assert.h>
@@ -40,6 +43,15 @@
 #ifdef HAVE_OPENSSL_RAND_H
 #include <openssl/rand.h>
 #endif
+#ifdef HAVE_OPENSSL_SSL_H
+#include <openssl/ssl.h>
+#endif
+#ifdef HAVE_OPENSSL_ERR_H
+#include <openssl/err.h>
+#endif
+#ifdef HAVE_OPENSSL_OCSP_H
+#include <openssl/ocsp.h>
+#endif
 #ifndef USE_MINI_EVENT
 #  ifdef HAVE_EVENT_H
 #    include <event.h>
@@ -71,6 +83,11 @@
 
 #define RELOAD_SYNC_TIMEOUT 25 /* seconds */
 
+#ifdef USE_TCP_FASTOPEN
+  #define TCP_FASTOPEN_FILE "/proc/sys/net/ipv4/tcp_fastopen"
+  #define TCP_FASTOPEN_SERVER_BIT_MASK 0x2
+#endif
+
 /*
  * Data for the UDP handlers.
  */
@@ -86,6 +103,10 @@ struct tcp_accept_handler_data {
  struct nsd_socket  *socket;
  int event_added;
  struct event       event;
+#ifdef HAVE_SSL
+ /* handler accepts TLS connections on the dedicated port */
+ int tls_accept;
+#endif
 };
 
 /*
@@ -99,6 +120,11 @@ static struct tcp_accept_handler_data* t
 static struct event slowaccept_event;
 static int slowaccept;
 
+#ifdef HAVE_SSL
+static unsigned char *ocspdata = NULL;
+static long ocspdata_len = 0;
+#endif
+
 #ifndef NONBLOCKING_IS_BROKEN
 #  define NUM_RECV_PER_SELECT 100
 #endif
@@ -170,7 +196,23 @@ struct tcp_handler_data
  * The timeout in msec for this tcp connection
  */
  int tcp_timeout;
+#ifdef HAVE_SSL
+ /*
+ * TLS object.
+ */
+ SSL* tls;
+
+ /*
+ * TLS handshake state.
+ */
+ enum { tls_hs_none, tls_hs_read, tls_hs_write,
+ tls_hs_read_event, tls_hs_write_event } shake_state;
+#endif
+ /* list of connections, for service of remaining tcp channels */
+ struct tcp_handler_data *prev, *next;
 };
+/* global that is the list of active tcp channels */
+static struct tcp_handler_data *tcp_active_list = NULL;
 
 /*
  * Handle incoming queries on the UDP server sockets.
@@ -202,6 +244,29 @@ static void handle_tcp_reading(int fd, s
  */
 static void handle_tcp_writing(int fd, short event, void* arg);
 
+#ifdef HAVE_SSL
+/* Create SSL object and associate fd */
+static SSL* incoming_ssl_fd(SSL_CTX* ctx, int fd);
+/*
+ * Handle TLS handshake. May be called multiple times if incomplete.
+ */
+static int tls_handshake(struct tcp_handler_data* data, int fd, int writing);
+
+/*
+ * Handle incoming queries on a TLS over TCP connection.  The TLS
+ * connections are configured to be non-blocking and the handler may
+ * be called multiple times before a complete query is received.
+ */
+static void handle_tls_reading(int fd, short event, void* arg);
+
+/*
+ * Handle outgoing responses on a TLS over TCP connection.  The TLS
+ * connections are configured to be non-blocking and the handler may
+ * be called multiple times before a complete response is sent.
+ */
+static void handle_tls_writing(int fd, short event, void* arg);
+#endif
+
 /*
  * Send all children the quit nonblocking, then close pipe.
  */
@@ -224,6 +289,34 @@ static uint32_t compression_table_capaci
 static uint32_t compression_table_size = 0;
 static domain_type* compressed_dnames[MAXRRSPP];
 
+#ifdef USE_TCP_FASTOPEN
+/* Checks to see if the kernel value must be manually changed in order for
+   TCP Fast Open to support server mode */
+static void report_tcp_fastopen_config() {
+
+ int tcp_fastopen_fp;
+ uint8_t tcp_fastopen_value;
+
+ if ( (tcp_fastopen_fp = open(TCP_FASTOPEN_FILE, O_RDONLY)) == -1 ) {
+ log_msg(LOG_INFO,"Error opening " TCP_FASTOPEN_FILE ": %s\n", strerror(errno));
+ }
+ if (read(tcp_fastopen_fp, &tcp_fastopen_value, 1) == -1 ) {
+ log_msg(LOG_INFO,"Error reading " TCP_FASTOPEN_FILE ": %s\n", strerror(errno));
+ close(tcp_fastopen_fp);
+ }
+ if (!(tcp_fastopen_value & TCP_FASTOPEN_SERVER_BIT_MASK)) {
+ log_msg(LOG_WARNING, "Error: TCP Fast Open support is available and configured in NSD by default.\n");
+ log_msg(LOG_WARNING, "However the kernel paramenters are not configured to support TCP_FASTOPEN in server mode.\n");
+ log_msg(LOG_WARNING, "To enable TFO use the command:");
+ log_msg(LOG_WARNING, "  'sudo sysctl -w net.ipv4.tcp_fastopen=2' for pure server mode or\n");
+ log_msg(LOG_WARNING, "  'sudo sysctl -w net.ipv4.tcp_fastopen=3' for both client and server mode\n");
+ log_msg(LOG_WARNING, "NSD will not have TCP Fast Open available until this change is made.\n");
+ close(tcp_fastopen_fp);
+ }
+ close(tcp_fastopen_fp);
+}
+#endif
+
 /*
  * Remove the specified pid from the list of child pids.  Returns -1 if
  * the pid is not in the list, child_num otherwise.  The field is set to 0.
@@ -577,6 +670,9 @@ server_init_ifs(struct nsd *nsd, size_t
 #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) || defined(SO_BINDANY))
  int on = 1;
 #endif
+#ifdef USE_TCP_FASTOPEN
+ int qlen;
+#endif
 
  /* UDP */
 
@@ -638,60 +734,62 @@ server_init_ifs(struct nsd *nsd, size_t
 #else
  (void)reuseport_works;
 #endif /* SO_REUSEPORT */
-#if defined(SO_RCVBUF) || defined(SO_SNDBUF)
- if(1) {
- int rcv = 1*1024*1024;
- int snd = 1*1024*1024;
-
-#ifdef SO_RCVBUF
+#if defined(SO_RCVBUF)
+ {
+ int rcv = 1*1024*1024;
+ if (nsd->options->receive_buffer_size > 0) {
+ rcv = nsd->options->receive_buffer_size;
+ }
 #  ifdef SO_RCVBUFFORCE
- if(setsockopt(nsd->udp[i].s, SOL_SOCKET, SO_RCVBUFFORCE, (void*)&rcv,
- (socklen_t)sizeof(rcv)) < 0) {
- if(errno != EPERM && errno != ENOBUFS) {
- log_msg(LOG_ERR, "setsockopt(..., SO_RCVBUFFORCE, "
+ if(setsockopt(nsd->udp[i].s, SOL_SOCKET, SO_RCVBUFFORCE, (void*)&rcv,
+ (socklen_t)sizeof(rcv)) < 0) {
+ if(errno != EPERM && errno != ENOBUFS) {
+ log_msg(LOG_ERR, "setsockopt(..., SO_RCVBUFFORCE, "
                                         "...) failed: %s", strerror(errno));
- return -1;
- }
+ return -1;
+ }
+ }
 #  else
- if(1) {
-#  endif /* SO_RCVBUFFORCE */
  if(setsockopt(nsd->udp[i].s, SOL_SOCKET, SO_RCVBUF, (void*)&rcv,
- (socklen_t)sizeof(rcv)) < 0) {
+ (socklen_t)sizeof(rcv)) < 0) {
  if(errno != ENOBUFS && errno != ENOSYS) {
  log_msg(LOG_ERR, "setsockopt(..., SO_RCVBUF, "
                                         "...) failed: %s", strerror(errno));
  return -1;
  }
  }
+#  endif /* SO_RCVBUFFORCE */
  }
 #endif /* SO_RCVBUF */
 
 #ifdef SO_SNDBUF
+ {
+ int snd = 1*1024*1024;
+ if (nsd->options->send_buffer_size > 0) {
+ snd = nsd->options->send_buffer_size;
+ }
 #  ifdef SO_SNDBUFFORCE
- if(setsockopt(nsd->udp[i].s, SOL_SOCKET, SO_SNDBUFFORCE, (void*)&snd,
- (socklen_t)sizeof(snd)) < 0) {
- if(errno != EPERM && errno != ENOBUFS) {
- log_msg(LOG_ERR, "setsockopt(..., SO_SNDBUFFORCE, "
+ if(setsockopt(nsd->udp[i].s, SOL_SOCKET, SO_SNDBUFFORCE, (void*)&snd,
+ (socklen_t)sizeof(snd)) < 0) {
+ if(errno != EPERM && errno != ENOBUFS) {
+ log_msg(LOG_ERR, "setsockopt(..., SO_SNDBUFFORCE, "
                                         "...) failed: %s", strerror(errno));
- return -1;
- }
+ return -1;
+ }
+ }
 #  else
- if(1) {
-#  endif /* SO_SNDBUFFORCE */
  if(setsockopt(nsd->udp[i].s, SOL_SOCKET, SO_SNDBUF, (void*)&snd,
- (socklen_t)sizeof(snd)) < 0) {
+ (socklen_t)sizeof(snd)) < 0) {
  if(errno != ENOBUFS && errno != ENOSYS) {
  log_msg(LOG_ERR, "setsockopt(..., SO_SNDBUF, "
                                         "...) failed: %s", strerror(errno));
  return -1;
  }
  }
+#  endif /* SO_SNDBUFFFORCE */
  }
 #endif /* SO_SNDBUF */
 
- }
-#endif /* defined(SO_RCVBUF) || defined(SO_SNDBUF) */
-
 #if defined(INET6)
  if (addr->ai_family == AF_INET6) {
 # if defined(IPV6_V6ONLY)
@@ -837,13 +935,19 @@ server_init_ifs(struct nsd *nsd, size_t
 
  if (
  bind(nsd->udp[i].s, (struct sockaddr *) addr->ai_addr, addr->ai_addrlen) != 0) {
- log_msg(LOG_ERR, "can't bind udp socket: %s", strerror(errno));
+ char buf[256];
+ addrport2str((void*)addr->ai_addr, buf, sizeof(buf));
+ log_msg(LOG_ERR, "can't bind udp socket %s: %s", buf, strerror(errno));
  return -1;
  }
  }
 
  /* TCP */
 
+#ifdef USE_TCP_FASTOPEN
+ report_tcp_fastopen_config();
+#endif
+
  /* Make a socket... */
  for (i = from; i < to; i++) {
  /* for reuseports copy socket specs of first entries */
@@ -974,10 +1078,40 @@ server_init_ifs(struct nsd *nsd, size_t
 
  if(
  bind(nsd->tcp[i].s, (struct sockaddr *) addr->ai_addr, addr->ai_addrlen) != 0) {
- log_msg(LOG_ERR, "can't bind tcp socket: %s", strerror(errno));
+ char buf[256];
+ addrport2str((void*)addr->ai_addr, buf, sizeof(buf));
+ log_msg(LOG_ERR, "can't bind tcp socket %s: %s", buf, strerror(errno));
  return -1;
  }
 
+#ifdef USE_TCP_FASTOPEN
+ /* qlen specifies how many outstanding TFO requests to allow. Limit is a defense
+   against IP spoofing attacks as suggested in RFC7413 */
+#ifdef __APPLE__
+ /* OS X implementation only supports qlen of 1 via this call. Actual
+   value is configured by the net.inet.tcp.fastopen_backlog kernel parm. */
+ qlen = 1;
+#else
+ /* 5 is recommended on linux */
+ qlen = 5;
+#endif
+ if ((setsockopt(nsd->tcp[i].s, IPPROTO_TCP, TCP_FASTOPEN, &qlen, sizeof(qlen))) == -1 ) {
+#ifdef ENOPROTOOPT
+                /* squelch ENOPROTOOPT: freebsd server mode with kernel support
+                   disabled, except when verbosity enabled for debugging */
+                    if(errno != ENOPROTOOPT || verbosity >= 3) {
+#endif
+ if(errno == EPERM) {
+ log_msg(LOG_ERR, "Setting TCP Fast Open as server failed: %s ; this could likely be because sysctl net.inet.tcp.fastopen.enabled, net.inet.tcp.fastopen.server_enable, or net.ipv4.tcp_fastopen is disabled", strerror(errno));
+ } else {
+ log_msg(LOG_ERR, "Setting TCP Fast Open as server failed: %s", strerror(errno));
+ }
+#ifdef ENOPROTOOPT
+    }
+#endif
+ }
+#endif
+
  /* Listen to it... */
  if (listen(nsd->tcp[i].s, TCP_BACKLOG) == -1) {
  log_msg(LOG_ERR, "can't listen: %s", strerror(errno));
@@ -1149,6 +1283,8 @@ server_shutdown(struct nsd *nsd)
  tsig_finalize();
 #ifdef HAVE_SSL
  daemon_remote_delete(nsd->rc); /* ssl-delete secret keys */
+ if (nsd->tls_ctx)
+ SSL_CTX_free(nsd->tls_ctx);
 #endif
 
 #ifdef MEMCLEAN /* OS collects memory pages */
@@ -1381,6 +1517,297 @@ server_send_soa_xfrd(struct nsd* nsd, in
  }
 }
 
+#ifdef HAVE_SSL
+void
+log_crypto_err(const char* str)
+{
+ /* error:[error code]:[library name]:[function name]:[reason string] */
+ char buf[128];
+ unsigned long e;
+ ERR_error_string_n(ERR_get_error(), buf, sizeof(buf));
+ log_msg(LOG_ERR, "%s crypto %s", str, buf);
+ while( (e=ERR_get_error()) ) {
+ ERR_error_string_n(e, buf, sizeof(buf));
+ log_msg(LOG_ERR, "and additionally crypto %s", buf);
+ }
+}
+
+void
+perform_openssl_init(void)
+{
+ /* init SSL library */
+#ifdef HAVE_ERR_LOAD_CRYPTO_STRINGS
+ ERR_load_crypto_strings();
+#endif
+ ERR_load_SSL_strings();
+#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO)
+ OpenSSL_add_all_algorithms();
+#else
+ OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
+ | OPENSSL_INIT_ADD_ALL_DIGESTS
+ | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
+#endif
+#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
+ (void)SSL_library_init();
+#else
+ OPENSSL_init_ssl(0, NULL);
+#endif
+
+ if(!RAND_status()) {
+ /* try to seed it */
+ unsigned char buf[256];
+ unsigned int v, seed=(unsigned)time(NULL) ^ (unsigned)getpid();
+ size_t i;
+ v = seed;
+ for(i=0; i<256/sizeof(v); i++) {
+ memmove(buf+i*sizeof(v), &v, sizeof(v));
+ v = v*seed + (unsigned int)i;
+ }
+ RAND_seed(buf, 256);
+ log_msg(LOG_WARNING, "warning: no entropy, seeding openssl PRNG with time");
+ }
+}
+
+static int
+get_ocsp(char *filename, unsigned char **ocsp)
+{
+ BIO *bio;
+ OCSP_RESPONSE *response;
+ int len = -1;
+ unsigned char *p, *buf;
+ assert(filename);
+
+ if ((bio = BIO_new_file(filename, "r")) == NULL) {
+ log_crypto_err("get_ocsp: BIO_new_file failed");
+ return -1;
+ }
+
+ if ((response = d2i_OCSP_RESPONSE_bio(bio, NULL)) == NULL) {
+ log_crypto_err("get_ocsp: d2i_OCSP_RESPONSE_bio failed");
+ BIO_free(bio);
+ return -1;
+ }
+
+ if ((len = i2d_OCSP_RESPONSE(response, NULL)) <= 0) {
+ log_crypto_err("get_ocsp: i2d_OCSP_RESPONSE #1 failed");
+ OCSP_RESPONSE_free(response);
+ BIO_free(bio);
+ return -1;
+ }
+
+ if ((buf = malloc((size_t) len)) == NULL) {
+ log_msg(LOG_ERR, "get_ocsp: malloc failed");
+ OCSP_RESPONSE_free(response);
+ BIO_free(bio);
+ return -1;
+ }
+
+ p = buf;
+ if ((len = i2d_OCSP_RESPONSE(response, &p)) <= 0) {
+ log_crypto_err("get_ocsp: i2d_OCSP_RESPONSE #2 failed");
+ free(buf);
+ OCSP_RESPONSE_free(response);
+ BIO_free(bio);
+ return -1;
+ }
+
+ OCSP_RESPONSE_free(response);
+ BIO_free(bio);
+
+ *ocsp = buf;
+ return len;
+}
+
+/* further setup ssl ctx after the keys are loaded */
+static void
+listen_sslctx_setup_2(void* ctxt)
+{
+ SSL_CTX* ctx = (SSL_CTX*)ctxt;
+ (void)ctx;
+#if HAVE_DECL_SSL_CTX_SET_ECDH_AUTO
+ if(!SSL_CTX_set_ecdh_auto(ctx,1)) {
+ log_crypto_err("Error in SSL_CTX_ecdh_auto, not enabling ECDHE");
+ }
+#elif defined(HAVE_DECL_SSL_CTX_SET_TMP_ECDH) && defined(NID_X9_62_prime256v1)
+ if(1) {
+ EC_KEY *ecdh = EC_KEY_new_by_curve_name (NID_X9_62_prime256v1);
+ if (!ecdh) {
+ log_crypto_err("could not find p256, not enabling ECDHE");
+ } else {
+ if (1 != SSL_CTX_set_tmp_ecdh (ctx, ecdh)) {
+ log_crypto_err("Error in SSL_CTX_set_tmp_ecdh, not enabling ECDHE");
+ }
+ EC_KEY_free (ecdh);
+ }
+ }
+#endif
+}
+
+static int
+add_ocsp_data_cb(SSL *s, void* ATTR_UNUSED(arg))
+{
+ if(ocspdata) {
+ unsigned char *p;
+ if ((p=malloc(ocspdata_len)) == NULL) {
+ log_msg(LOG_ERR, "add_ocsp_data_cb: malloc failure");
+ return SSL_TLSEXT_ERR_NOACK;
+ }
+ memcpy(p, ocspdata, ocspdata_len);
+ if ((SSL_set_tlsext_status_ocsp_resp(s, p, ocspdata_len)) != 1) {
+ log_crypto_err("Error in SSL_set_tlsext_status_ocsp_resp");
+ free(p);
+ return SSL_TLSEXT_ERR_NOACK;
+ }
+ return SSL_TLSEXT_ERR_OK;
+ } else {
+ return SSL_TLSEXT_ERR_NOACK;
+ }
+}
+
+SSL_CTX*
+server_tls_ctx_setup(char* key, char* pem, char* verifypem)
+{
+ SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method());
+ if(!ctx) {
+ log_crypto_err("could not SSL_CTX_new");
+ return NULL;
+ }
+ /* no SSLv2, SSLv3 because has defects */
+ if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2) != SSL_OP_NO_SSLv2){
+ log_crypto_err("could not set SSL_OP_NO_SSLv2");
+ SSL_CTX_free(ctx);
+ return NULL;
+ }
+ if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3)
+ != SSL_OP_NO_SSLv3){
+ log_crypto_err("could not set SSL_OP_NO_SSLv3");
+ SSL_CTX_free(ctx);
+ return 0;
+ }
+#if defined(SSL_OP_NO_TLSv1) && defined(SSL_OP_NO_TLSv1_1)
+ /* if we have tls 1.1 disable 1.0 */
+ if((SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1) & SSL_OP_NO_TLSv1)
+ != SSL_OP_NO_TLSv1){
+ log_crypto_err("could not set SSL_OP_NO_TLSv1");
+ SSL_CTX_free(ctx);
+ return 0;
+ }
+#endif
+#if defined(SSL_OP_NO_TLSv1_1) && defined(SSL_OP_NO_TLSv1_2)
+ /* if we have tls 1.2 disable 1.1 */
+ if((SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1_1) & SSL_OP_NO_TLSv1_1)
+ != SSL_OP_NO_TLSv1_1){
+ log_crypto_err("could not set SSL_OP_NO_TLSv1_1");
+ SSL_CTX_free(ctx);
+ return 0;
+ }
+#endif
+#if defined(SHA256_DIGEST_LENGTH) && defined(SSL_TXT_CHACHA20)
+ /* if we have sha256, set the cipher list to have no known vulns */
+ if(!SSL_CTX_set_cipher_list(ctx, "ECDHE+AESGCM:ECDHE+CHACHA20"))
+ log_crypto_err("could not set cipher list with SSL_CTX_set_cipher_list");
+#endif
+ if((SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE) &
+ SSL_OP_CIPHER_SERVER_PREFERENCE) !=
+ SSL_OP_CIPHER_SERVER_PREFERENCE) {
+ log_crypto_err("could not set SSL_OP_CIPHER_SERVER_PREFERENCE");
+ SSL_CTX_free(ctx);
+ return 0;
+ }
+#ifdef HAVE_SSL_CTX_SET_SECURITY_LEVEL
+ SSL_CTX_set_security_level(ctx, 0);
+#endif
+ if(!SSL_CTX_use_certificate_chain_file(ctx, pem)) {
+ log_msg(LOG_ERR, "error for cert file: %s", pem);
+ log_crypto_err("error in SSL_CTX use_certificate_chain_file");
+ SSL_CTX_free(ctx);
+ return NULL;
+ }
+ if(!SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM)) {
+ log_msg(LOG_ERR, "error for private key file: %s", key);
+ log_crypto_err("Error in SSL_CTX use_PrivateKey_file");
+ SSL_CTX_free(ctx);
+ return NULL;
+ }
+ if(!SSL_CTX_check_private_key(ctx)) {
+ log_msg(LOG_ERR, "error for key file: %s", key);
+ log_crypto_err("Error in SSL_CTX check_private_key");
+ SSL_CTX_free(ctx);
+ return NULL;
+ }
+ listen_sslctx_setup_2(ctx);
+ if(verifypem && verifypem[0]) {
+ if(!SSL_CTX_load_verify_locations(ctx, verifypem, NULL)) {
+ log_crypto_err("Error in SSL_CTX verify locations");
+ SSL_CTX_free(ctx);
+ return NULL;
+ }
+ SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(verifypem));
+ SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
+ }
+ return ctx;
+}
+
+SSL_CTX*
+server_tls_ctx_create(struct nsd* nsd, char* verifypem, char* ocspfile)
+{
+ char *key, *pem;
+ SSL_CTX *ctx;
+
+ key = nsd->options->tls_service_key;
+ pem = nsd->options->tls_service_pem;
+ if(!key || key[0] == 0) {
+ log_msg(LOG_ERR, "error: no tls-service-key file specified");
+ return NULL;
+ }
+ if(!pem || pem[0] == 0) {
+ log_msg(LOG_ERR, "error: no tls-service-pem file specified");
+ return NULL;
+ }
+
+ /* NOTE:This mimics the existing code in Unbound 1.5.1 by supporting SSL but
+ * raft-ietf-uta-tls-bcp-08 recommends only using TLSv1.2*/
+ ctx = server_tls_ctx_setup(key, pem, verifypem);
+ if(!ctx) {
+ log_msg(LOG_ERR, "could not setup server TLS context");
+ return NULL;
+ }
+ if(ocspfile && ocspfile[0]) {
+ if ((ocspdata_len = get_ocsp(ocspfile, &ocspdata)) < 0) {
+ log_crypto_err("Error reading OCSPfile");
+ SSL_CTX_free(ctx);
+ return NULL;
+ } else {
+ VERBOSITY(2, (LOG_INFO, "ocspfile %s loaded", ocspfile));
+ if(!SSL_CTX_set_tlsext_status_cb(ctx, add_ocsp_data_cb)) {
+ log_crypto_err("Error in SSL_CTX_set_tlsext_status_cb");
+ SSL_CTX_free(ctx);
+ return NULL;
+ }
+ }
+ }
+ return ctx;
+}
+
+/* check if tcp_handler_accept_data created for TLS dedicated port */
+int
+using_tls_port(struct sockaddr* addr, const char* tls_port)
+{
+ in_port_t port = 0;
+
+ if (addr->sa_family == AF_INET)
+ port = ((struct sockaddr_in*)addr)->sin_port;
+#ifndef HAVE_STRUCT_SOCKADDR_IN6
+ else
+ port = ((struct sockaddr_in6*)addr)->sin6_port;
+#endif /* HAVE_STRUCT_SOCKADDR_IN6 */
+ if (atoi(tls_port) == ntohs(port))
+ return 1;
+
+ return 0;
+}
+#endif
+
 /* pass timeout=-1 for blocking. Returns size, 0, -1(err), or -2(timeout) */
 ssize_t
 block_read(struct nsd* nsd, int s, void* p, ssize_t sz, int timeout)
@@ -2108,6 +2535,7 @@ server_child(struct nsd *nsd)
 
  handler = (struct event*) region_alloc(
  server_region, sizeof(*handler));
+ memset(handler, 0, sizeof(*handler));
  event_set(handler, nsd->this_child->parent_fd, EV_PERSIST|
  EV_READ, child_handle_parent_command, user_data);
  if(event_base_set(event_base, handler) != 0)
@@ -2162,6 +2590,7 @@ server_child(struct nsd *nsd)
 
  handler = (struct event*) region_alloc(
  server_region, sizeof(*handler));
+ memset(handler, 0, sizeof(*handler));
  event_set(handler, nsd->udp[i].s, EV_PERSIST|EV_READ,
  handle_udp, data);
  if(event_base_set(event_base, handler) != 0)
@@ -2187,6 +2616,20 @@ server_child(struct nsd *nsd)
  &tcp_accept_handlers[i-from];
  data->nsd = nsd;
  data->socket = &nsd->tcp[i];
+#ifdef HAVE_SSL
+ if (nsd->tls_ctx && nsd->options->tls_port && using_tls_port(
+    data->socket->addr->ai_addr, nsd->options->tls_port)) {
+ data->tls_accept = 1;
+ if(verbosity >= 2) {
+ char buf[48];
+ addrport2str((struct sockaddr_storage*)data->socket->addr->ai_addr, buf, sizeof(buf));
+ VERBOSITY(2, (LOG_NOTICE, "setup TCP for TLS service on interface %s", buf));
+ }
+ }
+ else
+ data->tls_accept = 0;
+#endif
+ memset(handler, 0, sizeof(*handler));
  event_set(handler, nsd->tcp[i].s, EV_PERSIST|EV_READ,
  handle_tcp_accept, data);
  if(event_base_set(event_base, handler) != 0)
@@ -2247,6 +2690,7 @@ server_child(struct nsd *nsd)
  }
  }
 
+ service_remaining_tcp(nsd);
 #ifdef BIND8_STATS
  bind8_stats(nsd);
 #endif /* BIND8_STATS */
@@ -2261,6 +2705,112 @@ server_child(struct nsd *nsd)
  server_shutdown(nsd);
 }
 
+static void remaining_tcp_timeout(int ATTR_UNUSED(fd), short event, void* arg)
+{
+ int* timed_out = (int*)arg;
+        assert(event & EV_TIMEOUT);
+ /* wake up the service tcp thread, note event is no longer
+ * registered */
+ *timed_out = 1;
+}
+
+void
+service_remaining_tcp(struct nsd* nsd)
+{
+ struct tcp_handler_data* p;
+ struct event_base* event_base;
+ /* check if it is needed */
+ if(nsd->current_tcp_count == 0 || tcp_active_list == NULL)
+ return;
+ VERBOSITY(4, (LOG_INFO, "service remaining TCP connections"));
+
+ /* setup event base */
+ event_base = nsd_child_event_base();
+ if(!event_base) {
+ log_msg(LOG_ERR, "nsd remain tcp could not create event base");
+ return;
+ }
+ /* register tcp connections */
+ for(p = tcp_active_list; p != NULL; p = p->next) {
+ struct timeval timeout;
+ int fd = p->event.ev_fd;
+#ifdef USE_MINI_EVENT
+ short event = p->event.ev_flags & (EV_READ|EV_WRITE);
+#else
+ short event = p->event.ev_events & (EV_READ|EV_WRITE);
+#endif
+ void (*fn)(int, short, void*);
+#ifdef HAVE_SSL
+ if(p->tls) {
+ if((event&EV_READ))
+ fn = handle_tls_reading;
+ else fn = handle_tls_writing;
+ } else {
+#endif
+ if((event&EV_READ))
+ fn = handle_tcp_reading;
+ else fn = handle_tcp_writing;
+#ifdef HAVE_SSL
+ }
+#endif
+
+ /* set timeout to 1/10 second */
+ if(p->tcp_timeout > 100)
+ p->tcp_timeout = 100;
+ timeout.tv_sec = p->tcp_timeout / 1000;
+ timeout.tv_usec = (p->tcp_timeout % 1000)*1000;
+ event_del(&p->event);
+ memset(&p->event, 0, sizeof(p->event));
+ event_set(&p->event, fd, EV_PERSIST | event | EV_TIMEOUT,
+ fn, p);
+ if(event_base_set(event_base, &p->event) != 0)
+ log_msg(LOG_ERR, "event base set failed");
+ if(event_add(&p->event, &timeout) != 0)
+ log_msg(LOG_ERR, "event add failed");
+ }
+
+ /* handle it */
+ while(nsd->current_tcp_count > 0) {
+ mode_t m = server_signal_mode(nsd);
+ struct event timeout;
+ struct timeval tv;
+ int timed_out = 0;
+ if(m == NSD_QUIT || m == NSD_SHUTDOWN ||
+ m == NSD_REAP_CHILDREN) {
+ /* quit */
+ break;
+ }
+ /* timer */
+ /* have to do something every second */
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+ memset(&timeout, 0, sizeof(timeout));
+ event_set(&timeout, -1, EV_TIMEOUT, remaining_tcp_timeout,
+ &timed_out);
+ if(event_base_set(event_base, &timeout) != 0)
+ log_msg(LOG_ERR, "remaintcp timer: event_base_set failed");
+ if(event_add(&timeout, &tv) != 0)
+ log_msg(LOG_ERR, "remaintcp timer: event_add failed");
+
+ /* service loop */
+ if(event_base_loop(event_base, EVLOOP_ONCE) == -1) {
+ if (errno != EINTR) {
+ log_msg(LOG_ERR, "dispatch failed: %s", strerror(errno));
+ break;
+ }
+ }
+ if(!timed_out) {
+ event_del(&timeout);
+ } else {
+ /* timed out, quit */
+ VERBOSITY(4, (LOG_INFO, "service remaining TCP connections: timed out, quit"));
+ break;
+ }
+ }
+ event_base_free(event_base);
+ /* continue to quit after return */
+}
+
 #if defined(HAVE_SENDMMSG) && !defined(NONBLOCKING_IS_BROKEN) && defined(HAVE_RECVMMSG)
 static void
 handle_udp(int fd, short event, void* arg)
@@ -2552,12 +3102,46 @@ handle_udp(int fd, short event, void* ar
 }
 #endif /* defined(HAVE_SENDMMSG) && !defined(NONBLOCKING_IS_BROKEN) && defined(HAVE_RECVMMSG) */
 
+/*
+ * Setup an event for the tcp handler.
+ */
+static void
+tcp_handler_setup_event(struct tcp_handler_data* data, void (*fn)(int, short, void *),
+       int fd, short event)
+{
+ struct timeval timeout;
+ struct event_base* ev_base;
+
+ timeout.tv_sec = data->nsd->tcp_timeout;
+ timeout.tv_usec = 0L;
+
+ ev_base = data->event.ev_base;
+ event_del(&data->event);
+ memset(&data->event, 0, sizeof(data->event));
+ event_set(&data->event, fd, event, fn, data);
+ if(event_base_set(ev_base, &data->event) != 0)
+ log_msg(LOG_ERR, "event base set failed");
+ if(event_add(&data->event, &timeout) != 0)
+ log_msg(LOG_ERR, "event add failed");
+}
 
 static void
 cleanup_tcp_handler(struct tcp_handler_data* data)
 {
  event_del(&data->event);
+#ifdef HAVE_SSL
+ if(data->tls) {
+ SSL_shutdown(data->tls);
+ SSL_free(data->tls);
+ data->tls = NULL;
+ }
+#endif
  close(data->event.ev_fd);
+ if(data->prev)
+ data->prev->next = data->next;
+ else tcp_active_list = data->next;
+ if(data->next)
+ data->next->prev = data->prev;
 
  /*
  * Enable the TCP accept handlers when the current number of
@@ -2593,7 +3177,7 @@ handle_tcp_reading(int fd, short event,
 
  if (data->nsd->tcp_query_count > 0 &&
  data->query_count >= data->nsd->tcp_query_count) {
- /* No more queries allowed on this tcp connection.  */
+ /* No more queries allowed on this tcp connection. */
  cleanup_tcp_handler(data);
  return;
  }
@@ -2770,6 +3354,15 @@ handle_tcp_reading(int fd, short event,
  /* Switch to the tcp write handler.  */
  buffer_flip(data->query->packet);
  data->query->tcplen = buffer_remaining(data->query->packet);
+#ifdef BIND8_STATS
+ /* Account the rcode & TC... */
+ STATUP2(data->nsd, rcode, RCODE(data->query->packet));
+ ZTATUP2(data->nsd, data->query->zone, rcode, RCODE(data->query->packet));
+ if (TC(data->query->packet)) {
+ STATUP(data->nsd, truncated);
+ ZTATUP(data->nsd, data->query->zone, truncated);
+ }
+#endif /* BIND8_STATS */
 #ifdef USE_DNSTAP
  dt_collector_submit_auth_response(data->nsd, &data->query->addr,
  data->query->addrlen, data->query->tcp, data->query->packet,
@@ -2782,8 +3375,9 @@ handle_tcp_reading(int fd, short event,
 
  ev_base = data->event.ev_base;
  event_del(&data->event);
- event_set(&data->event, fd, EV_PERSIST | EV_WRITE | EV_TIMEOUT,
- handle_tcp_writing, data);
+ memset(&data->event, 0, sizeof(data->event));
+ event_set(&data->event, fd, EV_PERSIST | EV_READ | EV_TIMEOUT,
+ handle_tcp_reading, data);
  if(event_base_set(ev_base, &data->event) != 0)
  log_msg(LOG_ERR, "event base set tcpr failed");
  if(event_add(&data->event, &timeout) != 0)
@@ -2914,6 +3508,7 @@ handle_tcp_writing(int fd, short event,
  timeout.tv_usec = (data->tcp_timeout % 1000)*1000;
  ev_base = data->event.ev_base;
  event_del(&data->event);
+ memset(&data->event, 0, sizeof(data->event));
  event_set(&data->event, fd, EV_PERSIST | EV_WRITE | EV_TIMEOUT,
  handle_tcp_writing, data);
  if(event_base_set(ev_base, &data->event) != 0)
@@ -2945,6 +3540,7 @@ handle_tcp_writing(int fd, short event,
  timeout.tv_usec = (data->tcp_timeout % 1000)*1000;
  ev_base = data->event.ev_base;
  event_del(&data->event);
+ memset(&data->event, 0, sizeof(data->event));
  event_set(&data->event, fd, EV_PERSIST | EV_READ | EV_TIMEOUT,
  handle_tcp_reading, data);
  if(event_base_set(ev_base, &data->event) != 0)
@@ -2953,6 +3549,428 @@ handle_tcp_writing(int fd, short event,
  log_msg(LOG_ERR, "event add tcpw failed");
 }
 
+#ifdef HAVE_SSL
+/** create SSL object and associate fd */
+static SSL*
+incoming_ssl_fd(SSL_CTX* ctx, int fd)
+{
+ SSL* ssl = SSL_new((SSL_CTX*)ctx);
+ if(!ssl) {
+ log_crypto_err("could not SSL_new");
+ return NULL;
+ }
+ SSL_set_accept_state(ssl);
+ (void)SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
+ if(!SSL_set_fd(ssl, fd)) {
+ log_crypto_err("could not SSL_set_fd");
+ SSL_free(ssl);
+ return NULL;
+ }
+ return ssl;
+}
+
+/** TLS handshake to upgrade TCP connection */
+static int
+tls_handshake(struct tcp_handler_data* data, int fd, int writing)
+{
+ int r;
+ if(data->shake_state == tls_hs_read_event) {
+ /* read condition satisfied back to writing */
+ tcp_handler_setup_event(data, handle_tls_writing, fd, EV_PERSIST|EV_TIMEOUT|EV_WRITE);
+ data->shake_state = tls_hs_none;
+ return 1;
+ }
+ if(data->shake_state == tls_hs_write_event) {
+ /* write condition satisfied back to reading */
+ tcp_handler_setup_event(data, handle_tls_reading, fd, EV_PERSIST|EV_TIMEOUT|EV_READ);
+ data->shake_state = tls_hs_none;
+ return 1;
+ }
+
+ /* (continue to) setup the TLS connection */
+ ERR_clear_error();
+ r = SSL_do_handshake(data->tls);
+
+ if(r != 1) {
+ int want = SSL_get_error(data->tls, r);
+ if(want == SSL_ERROR_WANT_READ) {
+ if(data->shake_state == tls_hs_read) {
+ /* try again later */
+ return 1;
+ }
+ data->shake_state = tls_hs_read;
+ /* switch back to reading mode */
+ tcp_handler_setup_event(data, handle_tls_reading, fd, EV_PERSIST|EV_TIMEOUT|EV_READ);
+ return 1;
+ } else if(want == SSL_ERROR_WANT_WRITE) {
+ if(data->shake_state == tls_hs_write) {
+ /* try again later */
+ return 1;
+ }
+ data->shake_state = tls_hs_write;
+ /* switch back to writing mode */
+ tcp_handler_setup_event(data, handle_tls_writing, fd, EV_PERSIST|EV_TIMEOUT|EV_WRITE);
+ return 1;
+ } else {
+ if(r == 0)
+ VERBOSITY(3, (LOG_ERR, "TLS handshake: connection closed prematurely"));
+ cleanup_tcp_handler(data);
+ VERBOSITY(3, (LOG_ERR, "TLS handshake failed"));
+ return 0;
+ }
+ }
+
+ /* Use to log successful upgrade for testing - could be removed*/
+ VERBOSITY(3, (LOG_INFO, "TLS handshake succeeded."));
+ /* set back to the event we need to have when reading (or writing) */
+ if(data->shake_state == tls_hs_read && writing) {
+ tcp_handler_setup_event(data, handle_tls_writing, fd, EV_PERSIST|EV_TIMEOUT|EV_WRITE);
+ } else if(data->shake_state == tls_hs_write && !writing) {
+ tcp_handler_setup_event(data, handle_tls_reading, fd, EV_PERSIST|EV_TIMEOUT|EV_READ);
+ }
+ data->shake_state = tls_hs_none;
+ return 1;
+}
+
+/** handle TLS reading of incoming query */
+static void
+handle_tls_reading(int fd, short event, void* arg)
+{
+ struct tcp_handler_data *data = (struct tcp_handler_data *) arg;
+ ssize_t received;
+
+ if ((event & EV_TIMEOUT)) {
+ /* Connection timed out.  */
+ cleanup_tcp_handler(data);
+ return;
+ }
+
+ if (data->nsd->tcp_query_count > 0 &&
+    data->query_count >= data->nsd->tcp_query_count) {
+ /* No more queries allowed on this tcp connection. */
+ cleanup_tcp_handler(data);
+ return;
+ }
+
+ assert((event & EV_READ));
+
+ if (data->bytes_transmitted == 0) {
+ query_reset(data->query, TCP_MAX_MESSAGE_LEN, 1);
+ }
+
+ if(data->shake_state != tls_hs_none) {
+ if(!tls_handshake(data, fd, 0))
+ return;
+ if(data->shake_state != tls_hs_none)
+ return;
+ }
+
+ /*
+ * Check if we received the leading packet length bytes yet.
+ */
+ if(data->bytes_transmitted < sizeof(uint16_t)) {
+ ERR_clear_error();
+ if((received=SSL_read(data->tls, (char *) &data->query->tcplen
+    + data->bytes_transmitted,
+    sizeof(uint16_t) - data->bytes_transmitted)) <= 0) {
+ int want = SSL_get_error(data->tls, received);
+ if(want == SSL_ERROR_ZERO_RETURN) {
+ cleanup_tcp_handler(data);
+ return; /* shutdown, closed */
+ } else if(want == SSL_ERROR_WANT_READ) {
+ /* wants to be called again */
+ return;
+ }
+ else if(want == SSL_ERROR_WANT_WRITE) {
+ /* switch to writing */
+ data->shake_state = tls_hs_write_event;
+ tcp_handler_setup_event(data, handle_tls_writing, fd, EV_PERSIST | EV_WRITE | EV_TIMEOUT);
+ return;
+ }
+ cleanup_tcp_handler(data);
+ log_crypto_err("could not SSL_read");
+ return;
+ }
+
+ data->bytes_transmitted += received;
+ if (data->bytes_transmitted < sizeof(uint16_t)) {
+ /*
+ * Not done with the tcplen yet, wait for more
+ * data to become available.
+ */
+ return;
+ }
+
+ assert(data->bytes_transmitted == sizeof(uint16_t));
+
+ data->query->tcplen = ntohs(data->query->tcplen);
+
+ /*
+ * Minimum query size is:
+ *
+ *     Size of the header (12)
+ *   + Root domain name   (1)
+ *   + Query class        (2)
+ *   + Query type         (2)
+ */
+ if (data->query->tcplen < QHEADERSZ + 1 + sizeof(uint16_t) + sizeof(uint16_t)) {
+ VERBOSITY(2, (LOG_WARNING, "packet too small, dropping tcp connection"));
+ cleanup_tcp_handler(data);
+ return;
+ }
+
+ if (data->query->tcplen > data->query->maxlen) {
+ VERBOSITY(2, (LOG_WARNING, "insufficient tcp buffer, dropping connection"));
+ cleanup_tcp_handler(data);
+ return;
+ }
+
+ buffer_set_limit(data->query->packet, data->query->tcplen);
+ }
+
+ assert(buffer_remaining(data->query->packet) > 0);
+
+ /* Read the (remaining) query data.  */
+ ERR_clear_error();
+ received = SSL_read(data->tls, (void*)buffer_current(data->query->packet),
+    (int)buffer_remaining(data->query->packet));
+ if(received <= 0) {
+ int want = SSL_get_error(data->tls, received);
+ if(want == SSL_ERROR_ZERO_RETURN) {
+ cleanup_tcp_handler(data);
+ return; /* shutdown, closed */
+ } else if(want == SSL_ERROR_WANT_READ) {
+ /* wants to be called again */
+ return;
+ }
+ else if(want == SSL_ERROR_WANT_WRITE) {
+ /* switch back writing */
+ data->shake_state = tls_hs_write_event;
+ tcp_handler_setup_event(data, handle_tls_writing, fd, EV_PERSIST | EV_WRITE | EV_TIMEOUT);
+ return;
+ }
+ cleanup_tcp_handler(data);
+ log_crypto_err("could not SSL_read");
+ return;
+ }
+
+ data->bytes_transmitted += received;
+ buffer_skip(data->query->packet, received);
+ if (buffer_remaining(data->query->packet) > 0) {
+ /*
+ * Message not yet complete, wait for more data to
+ * become available.
+ */
+ return;
+ }
+
+ assert(buffer_position(data->query->packet) == data->query->tcplen);
+
+ /* Account... */
+#ifndef INET6
+ STATUP(data->nsd, ctls);
+#else
+ if (data->query->addr.ss_family == AF_INET) {
+ STATUP(data->nsd, ctls);
+ } else if (data->query->addr.ss_family == AF_INET6) {
+ STATUP(data->nsd, ctls6);
+ }
+#endif
+
+ /* We have a complete query, process it.  */
+
+ /* tcp-query-count: handle query counter ++ */
+ data->query_count++;
+
+ buffer_flip(data->query->packet);
+#ifdef USE_DNSTAP
+ dt_collector_submit_auth_query(data->nsd, &data->query->addr,
+ data->query->addrlen, data->query->tcp, data->query->packet);
+#endif /* USE_DNSTAP */
+ data->query_state = server_process_query(data->nsd, data->query);
+ if (data->query_state == QUERY_DISCARDED) {
+ /* Drop the packet and the entire connection... */
+ STATUP(data->nsd, dropped);
+ ZTATUP(data->nsd, data->query->zone, dropped);
+ cleanup_tcp_handler(data);
+ return;
+ }
+
+#ifdef BIND8_STATS
+ if (RCODE(data->query->packet) == RCODE_OK
+    && !AA(data->query->packet))
+ {
+ STATUP(data->nsd, nona);
+ ZTATUP(data->nsd, data->query->zone, nona);
+ }
+#endif /* BIND8_STATS */
+
+#ifdef USE_ZONE_STATS
+#ifndef INET6
+ ZTATUP(data->nsd, data->query->zone, ctls);
+#else
+ if (data->query->addr.ss_family == AF_INET) {
+ ZTATUP(data->nsd, data->query->zone, ctls);
+ } else if (data->query->addr.ss_family == AF_INET6) {
+ ZTATUP(data->nsd, data->query->zone, ctls6);
+ }
+#endif
+#endif /* USE_ZONE_STATS */
+
+ query_add_optional(data->query, data->nsd);
+
+ /* Switch to the tcp write handler.  */
+ buffer_flip(data->query->packet);
+ data->query->tcplen = buffer_remaining(data->query->packet);
+#ifdef BIND8_STATS
+ /* Account the rcode & TC... */
+ STATUP2(data->nsd, rcode, RCODE(data->query->packet));
+ ZTATUP2(data->nsd, data->query->zone, rcode, RCODE(data->query->packet));
+ if (TC(data->query->packet)) {
+ STATUP(data->nsd, truncated);
+ ZTATUP(data->nsd, data->query->zone, truncated);
+ }
+#endif /* BIND8_STATS */
+#ifdef USE_DNSTAP
+ dt_collector_submit_auth_response(data->nsd, &data->query->addr,
+ data->query->addrlen, data->query->tcp, data->query->packet,
+ data->query->zone);
+#endif /* USE_DNSTAP */
+ data->bytes_transmitted = 0;
+
+ tcp_handler_setup_event(data, handle_tls_writing, fd, EV_PERSIST | EV_WRITE | EV_TIMEOUT);
+
+ /* see if we can write the answer right away(usually so,EAGAIN ifnot)*/
+ handle_tls_writing(fd, EV_WRITE, data);
+}
+
+/** handle TLS writing of outgoing response */
+static void
+handle_tls_writing(int fd, short event, void* arg)
+{
+ struct tcp_handler_data *data = (struct tcp_handler_data *) arg;
+ ssize_t sent;
+ struct query *q = data->query;
+ /* static variable that holds reassembly buffer used to put the
+ * TCP length in front of the packet, like writev. */
+ static buffer_type* global_tls_temp_buffer = NULL;
+ buffer_type* write_buffer;
+
+ if ((event & EV_TIMEOUT)) {
+ /* Connection timed out.  */
+ cleanup_tcp_handler(data);
+ return;
+ }
+
+ assert((event & EV_WRITE));
+
+ if(data->shake_state != tls_hs_none) {
+ if(!tls_handshake(data, fd, 1))
+ return;
+ if(data->shake_state != tls_hs_none)
+ return;
+ }
+
+ (void)SSL_set_mode(data->tls, SSL_MODE_ENABLE_PARTIAL_WRITE);
+
+ /* If we are writing the start of a message, we must include the length
+ * this is done with a copy into write_buffer. */
+ write_buffer = NULL;
+ if (data->bytes_transmitted == 0) {
+ if(!global_tls_temp_buffer) {
+ /* gets deallocated when nsd shuts down from
+ * nsd.region */
+ global_tls_temp_buffer = buffer_create(nsd.region,
+ QIOBUFSZ + sizeof(q->tcplen));
+ if (!global_tls_temp_buffer) {
+ return;
+ }
+ }
+ write_buffer = global_tls_temp_buffer;
+ buffer_clear(write_buffer);
+ buffer_write_u16(write_buffer, q->tcplen);
+ buffer_write(write_buffer, buffer_current(q->packet),
+ (int)buffer_remaining(q->packet));
+ buffer_flip(write_buffer);
+ } else {
+ write_buffer = q->packet;
+ }
+
+ /* Write the response */
+ ERR_clear_error();
+ sent = SSL_write(data->tls, buffer_current(write_buffer), buffer_remaining(write_buffer));
+ if(sent <= 0) {
+ int want = SSL_get_error(data->tls, sent);
+ if(want == SSL_ERROR_ZERO_RETURN) {
+ cleanup_tcp_handler(data);
+ /* closed */
+ } else if(want == SSL_ERROR_WANT_READ) {
+ /* switch back to reading */
+ data->shake_state = tls_hs_read_event;
+ tcp_handler_setup_event(data, handle_tls_reading, fd, EV_PERSIST | EV_READ | EV_TIMEOUT);
+ } else if(want != SSL_ERROR_WANT_WRITE) {
+ cleanup_tcp_handler(data);
+ log_crypto_err("could not SSL_write");
+ }
+ return;
+ }
+
+ buffer_skip(write_buffer, sent);
+ if(buffer_remaining(write_buffer) != 0) {
+ /* If not all sent, sync up the real buffer if it wasn't used.*/
+ if (data->bytes_transmitted == 0 && (ssize_t)sent > (ssize_t)sizeof(q->tcplen)) {
+ buffer_skip(q->packet, (ssize_t)sent - (ssize_t)sizeof(q->tcplen));
+ }
+ }
+
+ data->bytes_transmitted += sent;
+ if (data->bytes_transmitted < q->tcplen + sizeof(q->tcplen)) {
+ /*
+ * Still more data to write when socket becomes
+ * writable again.
+ */
+ return;
+ }
+
+ assert(data->bytes_transmitted == q->tcplen + sizeof(q->tcplen));
+
+ if (data->query_state == QUERY_IN_AXFR) {
+ /* Continue processing AXFR and writing back results.  */
+ buffer_clear(q->packet);
+ data->query_state = query_axfr(data->nsd, q);
+ if (data->query_state != QUERY_PROCESSED) {
+ query_add_optional(data->query, data->nsd);
+
+ /* Reset data. */
+ buffer_flip(q->packet);
+ q->tcplen = buffer_remaining(q->packet);
+ data->bytes_transmitted = 0;
+ /* Reset to writing mode.  */
+ tcp_handler_setup_event(data, handle_tls_writing, fd, EV_PERSIST | EV_WRITE | EV_TIMEOUT);
+
+ /*
+ * Write data if/when the socket is writable
+ * again.
+ */
+ return;
+ }
+ }
+
+ /*
+ * Done sending, wait for the next request to arrive on the
+ * TCP socket by installing the TCP read handler.
+ */
+ if (data->nsd->tcp_query_count > 0 &&
+ data->query_count >= data->nsd->tcp_query_count) {
+
+ (void) shutdown(fd, SHUT_WR);
+ }
+
+ data->bytes_transmitted = 0;
+
+ tcp_handler_setup_event(data, handle_tls_reading, fd, EV_PERSIST | EV_READ | EV_TIMEOUT);
+}
+#endif
 
 static void
 handle_slowaccept_timeout(int ATTR_UNUSED(fd), short ATTR_UNUSED(event),
@@ -2964,6 +3982,26 @@ handle_slowaccept_timeout(int ATTR_UNUSE
  }
 }
 
+static int perform_accept(int fd, struct sockaddr *addr, socklen_t *addrlen)
+{
+#ifndef HAVE_ACCEPT4
+ int s = accept(fd, addr, addrlen);
+ if (s != -1) {
+ if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) {
+ log_msg(LOG_ERR, "fcntl failed: %s", strerror(errno));
+ close(s);
+ s = -1;
+ errno=EINTR; /* stop error printout as error in accept4
+ by setting this errno, it omits printout, in
+ later code that calls nsd_accept4 */
+ }
+ }
+ return s;
+#else
+ return accept4(fd, addr, addrlen, SOCK_NONBLOCK);
+#endif /* HAVE_ACCEPT4 */
+}
+
 /*
  * Handle an incoming TCP connection.  The connection is accepted and
  * a new TCP reader event handler is added.  The TCP handler
@@ -2975,6 +4013,7 @@ handle_tcp_accept(int fd, short event, v
  struct tcp_accept_handler_data *data
  = (struct tcp_accept_handler_data *) arg;
  int s;
+ int reject = 0;
  struct tcp_handler_data *tcp_data;
  region_type *tcp_region;
 #ifdef INET6
@@ -2990,16 +4029,15 @@ handle_tcp_accept(int fd, short event, v
  }
 
  if (data->nsd->current_tcp_count >= data->nsd->maximum_tcp_count) {
- return;
+ reject = data->nsd->options->tcp_reject_overflow;
+ if (!reject) {
+ return;
+ }
  }
 
  /* Accept it... */
  addrlen = sizeof(addr);
-#ifndef HAVE_ACCEPT4
- s = accept(fd, (struct sockaddr *) &addr, &addrlen);
-#else
- s = accept4(fd, (struct sockaddr *) &addr, &addrlen, SOCK_NONBLOCK);
-#endif
+ s = perform_accept(fd, (struct sockaddr *) &addr, &addrlen);
  if (s == -1) {
  /**
  * EMFILE and ENFILE is a signal that the limit of open
@@ -3014,6 +4052,8 @@ handle_tcp_accept(int fd, short event, v
  configure_handler_event_types(0);
  tv.tv_sec = SLOW_ACCEPT_TIMEOUT;
  tv.tv_usec = 0L;
+ memset(&slowaccept_event, 0,
+ sizeof(slowaccept_event));
  event_set(&slowaccept_event, -1, EV_TIMEOUT,
  handle_slowaccept_timeout, NULL);
  (void)event_base_set(data->event.ev_base,
@@ -3036,13 +4076,11 @@ handle_tcp_accept(int fd, short event, v
  return;
  }
 
-#ifndef HAVE_ACCEPT4
- if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) {
- log_msg(LOG_ERR, "fcntl failed: %s", strerror(errno));
+ if (reject) {
+ shutdown(s, SHUT_RDWR);
  close(s);
  return;
  }
-#endif
 
  /*
  * This region is deallocated when the TCP connection is
@@ -3056,6 +4094,12 @@ handle_tcp_accept(int fd, short event, v
  compression_table_size, compressed_dnames);
  tcp_data->nsd = data->nsd;
  tcp_data->query_count = 0;
+#ifdef HAVE_SSL
+ tcp_data->shake_state = tls_hs_none;
+ tcp_data->tls = NULL;
+#endif
+ tcp_data->prev = NULL;
+ tcp_data->next = NULL;
 
  tcp_data->query_state = QUERY_PROCESSED;
  tcp_data->bytes_transmitted = 0;
@@ -3067,11 +4111,29 @@ handle_tcp_accept(int fd, short event, v
  /* very busy, give smaller timeout */
  tcp_data->tcp_timeout = 200;
  }
+ memset(&tcp_data->event, 0, sizeof(tcp_data->event));
  timeout.tv_sec = tcp_data->tcp_timeout / 1000;
  timeout.tv_usec = (tcp_data->tcp_timeout % 1000)*1000;
 
- event_set(&tcp_data->event, s, EV_PERSIST | EV_READ | EV_TIMEOUT,
- handle_tcp_reading, tcp_data);
+#ifdef HAVE_SSL
+ if (data->tls_accept) {
+ tcp_data->tls = incoming_ssl_fd(tcp_data->nsd->tls_ctx, s);
+ if(!tcp_data->tls) {
+ close(s);
+ return;
+ }
+ tcp_data->shake_state = tls_hs_read;
+ memset(&tcp_data->event, 0, sizeof(tcp_data->event));
+ event_set(&tcp_data->event, s, EV_PERSIST | EV_READ | EV_TIMEOUT,
+  handle_tls_reading, tcp_data);
+ } else {
+#endif
+ memset(&tcp_data->event, 0, sizeof(tcp_data->event));
+ event_set(&tcp_data->event, s, EV_PERSIST | EV_READ | EV_TIMEOUT,
+  handle_tcp_reading, tcp_data);
+#ifdef HAVE_SSL
+ }
+#endif
  if(event_base_set(data->event.ev_base, &tcp_data->event) != 0) {
  log_msg(LOG_ERR, "cannot set tcp event base");
  close(s);
@@ -3084,14 +4146,26 @@ handle_tcp_accept(int fd, short event, v
  region_destroy(tcp_region);
  return;
  }
+ if(tcp_active_list) {
+ tcp_active_list->prev = tcp_data;
+ tcp_data->next = tcp_active_list;
+ }
+ tcp_active_list = tcp_data;
 
  /*
  * Keep track of the total number of TCP handlers installed so
  * we can stop accepting connections when the maximum number
  * of simultaneous TCP connections is reached.
+ *
+ * If tcp-reject-overflow is enabled, however, then we do not
+ * change the handler event type; we keep it as-is and accept
+ * overflow TCP connections only so that we can forcibly kill
+ * them off.
  */
  ++data->nsd->current_tcp_count;
- if (data->nsd->current_tcp_count == data->nsd->maximum_tcp_count) {
+ if (!data->nsd->options->tcp_reject_overflow &&
+     data->nsd->current_tcp_count == data->nsd->maximum_tcp_count)
+ {
  configure_handler_event_types(0);
  }
 }
@@ -3165,6 +4239,7 @@ configure_handler_event_types(short even
  struct event_base* base = handler->ev_base;
  if(tcp_accept_handlers[i].event_added)
  event_del(handler);
+ memset(handler, 0, sizeof(*handler));
  event_set(handler, fd, event_types,
  handle_tcp_accept, &tcp_accept_handlers[i]);
  if(event_base_set(base, handler) != 0)
Index: util.c
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/util.c,v
retrieving revision 1.21
diff -u -p -r1.21 util.c
--- util.c 29 Sep 2018 17:17:54 -0000 1.21
+++ util.c 6 Aug 2019 11:53:07 -0000
@@ -1087,6 +1087,35 @@ addr2str(
 }
 
 void
+addrport2str(
+#ifdef INET6
+ struct sockaddr_storage *addr
+#else
+ struct sockaddr_in *addr
+#endif
+ , char* str, size_t len)
+{
+ char ip[256];
+#ifdef INET6
+ if (addr->ss_family == AF_INET6) {
+ if (!inet_ntop(AF_INET6,
+ &((struct sockaddr_in6 *)addr)->sin6_addr, ip, sizeof(ip)))
+ strlcpy(ip, "[unknown ip6, inet_ntop failed]", sizeof(ip));
+ /* append port number */
+ snprintf(str, len, "%s@%u", ip,
+ (unsigned)ntohs(((struct sockaddr_in6 *)addr)->sin6_port));
+ return;
+ } else
+#endif
+ if (!inet_ntop(AF_INET, &((struct sockaddr_in *)addr)->sin_addr,
+ ip, sizeof(ip)))
+ strlcpy(ip, "[unknown ip4, inet_ntop failed]", sizeof(ip));
+ /* append port number */
+ snprintf(str, len, "%s@%u", ip,
+ (unsigned)ntohs(((struct sockaddr_in *)addr)->sin_port));
+}
+
+void
 append_trailing_slash(const char** dirname, region_type* region)
 {
  int l = strlen(*dirname);
Index: util.h
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/util.h,v
retrieving revision 1.13
diff -u -p -r1.13 util.h
--- util.h 29 Sep 2018 17:17:54 -0000 1.13
+++ util.h 6 Aug 2019 11:53:07 -0000
@@ -410,6 +410,15 @@ void addr2str(
 #endif
  , char* str, size_t len);
 
+/* print addr@port */
+void addrport2str(
+#ifdef INET6
+ struct sockaddr_storage *addr
+#else
+ struct sockaddr_in *addr
+#endif
+ , char* str, size_t len);
+
 /** copy dirname string and append slash.  Previous dirname is leaked,
  * but it is to be used once, at startup, for chroot */
 void append_trailing_slash(const char** dirname, struct region* region);
Index: xfrd-notify.c
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/xfrd-notify.c,v
retrieving revision 1.3
diff -u -p -r1.3 xfrd-notify.c
--- xfrd-notify.c 3 Feb 2018 11:03:51 -0000 1.3
+++ xfrd-notify.c 6 Aug 2019 11:53:07 -0000
@@ -382,6 +382,8 @@ notify_setup_event(struct notify_zone* z
  event_del(&zone->notify_send_handler);
  }
  zone->notify_timeout.tv_sec = XFRD_NOTIFY_RETRY_TIMOUT;
+ memset(&zone->notify_send_handler, 0,
+ sizeof(zone->notify_send_handler));
  event_set(&zone->notify_send_handler, fd, EV_READ | EV_TIMEOUT,
  xfrd_handle_notify_send, zone);
  if(event_base_set(xfrd->event_base, &zone->notify_send_handler) != 0)
@@ -396,6 +398,8 @@ notify_setup_event(struct notify_zone* z
  event_del(&zone->notify_send6_handler);
  }
  zone->notify_timeout.tv_sec = XFRD_NOTIFY_RETRY_TIMOUT;
+ memset(&zone->notify_send6_handler, 0,
+ sizeof(zone->notify_send6_handler));
  event_set(&zone->notify_send6_handler, fd, EV_READ | EV_TIMEOUT,
  xfrd_handle_notify_send, zone);
  if(event_base_set(xfrd->event_base, &zone->notify_send6_handler) != 0)
@@ -465,6 +469,8 @@ setup_notify_active(struct notify_zone*
 
  if(zone->notify_send_enable)
  notify_send_disable(zone);
+ memset(&zone->notify_send_handler, 0,
+ sizeof(zone->notify_send_handler));
  event_set(&zone->notify_send_handler, -1, EV_TIMEOUT,
  xfrd_handle_notify_send, zone);
  if(event_base_set(xfrd->event_base, &zone->notify_send_handler) != 0)
Index: xfrd-tcp.c
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/xfrd-tcp.c,v
retrieving revision 1.20
diff -u -p -r1.20 xfrd-tcp.c
--- xfrd-tcp.c 3 Feb 2018 11:03:51 -0000 1.20
+++ xfrd-tcp.c 6 Aug 2019 11:53:07 -0000
@@ -330,6 +330,7 @@ tcp_pipe_reset_timeout(struct xfrd_tcp_p
  tv.tv_usec = 0;
  if(tp->handler_added)
  event_del(&tp->handler);
+ memset(&tp->handler, 0, sizeof(tp->handler));
  event_set(&tp->handler, fd, EV_PERSIST|EV_TIMEOUT|EV_READ|
  (tp->tcp_send_first?EV_WRITE:0), xfrd_handle_tcp_pipe, tp);
  if(event_base_set(xfrd->event_base, &tp->handler) != 0)
@@ -575,6 +576,7 @@ xfrd_tcp_open(struct xfrd_tcp_set* set,
  /* set the tcp pipe event */
  if(tp->handler_added)
  event_del(&tp->handler);
+ memset(&tp->handler, 0, sizeof(tp->handler));
  event_set(&tp->handler, fd, EV_PERSIST|EV_TIMEOUT|EV_READ|EV_WRITE,
  xfrd_handle_tcp_pipe, tp);
  if(event_base_set(xfrd->event_base, &tp->handler) != 0)
Index: xfrd.c
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/xfrd.c,v
retrieving revision 1.20
diff -u -p -r1.20 xfrd.c
--- xfrd.c 10 Dec 2018 16:09:11 -0000 1.20
+++ xfrd.c 6 Aug 2019 11:53:07 -0000
@@ -170,6 +170,7 @@ xfrd_init(int socket, struct nsd* nsd, i
  xfrd->child_timer_added = 0;
 
  xfrd->ipc_send_blocked = 0;
+ memset(&xfrd->ipc_handler, 0, sizeof(xfrd->ipc_handler));
  event_set(&xfrd->ipc_handler, socket, EV_PERSIST|EV_READ,
  xfrd_handle_ipc, xfrd);
  if(event_base_set(xfrd->event_base, &xfrd->ipc_handler) != 0)
@@ -294,6 +295,7 @@ xfrd_sig_process(void)
  struct timeval tv;
  tv.tv_sec = XFRD_CHILD_REAP_TIMEOUT;
  tv.tv_usec = 0;
+ memset(&xfrd->child_timer, 0, sizeof(xfrd->child_timer));
  event_set(&xfrd->child_timer, -1, EV_TIMEOUT,
  xfrd_handle_child_timer, xfrd);
  if(event_base_set(xfrd->event_base, &xfrd->child_timer) != 0)
@@ -1038,6 +1040,8 @@ xfrd_udp_obtain(xfrd_zone_type* zone)
  else {
  if(zone->event_added)
  event_del(&zone->zone_handler);
+ memset(&zone->zone_handler, 0,
+ sizeof(zone->zone_handler));
  event_set(&zone->zone_handler, fd,
  EV_PERSIST|EV_READ|EV_TIMEOUT,
  xfrd_handle_zone, zone);
@@ -1174,6 +1178,7 @@ xfrd_set_timer(xfrd_zone_type* zone, tim
  else fd = -1;
  zone->timeout.tv_sec = t;
  zone->timeout.tv_usec = 0;
+ memset(&zone->zone_handler, 0, sizeof(zone->zone_handler));
  event_set(&zone->zone_handler, fd, fl, xfrd_handle_zone, zone);
  if(event_base_set(xfrd->event_base, &zone->zone_handler) != 0)
  log_msg(LOG_ERR, "xfrd timer: event_base_set failed");
@@ -1200,7 +1205,7 @@ xfrd_handle_incoming_soa(xfrd_zone_type*
  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;
@@ -1324,6 +1329,8 @@ xfrd_udp_release(xfrd_zone_type* zone)
  if(fd != -1) {
  if(wz->event_added)
  event_del(&wz->zone_handler);
+ memset(&wz->zone_handler, 0,
+ sizeof(wz->zone_handler));
  event_set(&wz->zone_handler, fd,
  EV_READ|EV_TIMEOUT|EV_PERSIST,
  xfrd_handle_zone, wz);
@@ -2216,6 +2223,7 @@ xfrd_set_reload_timeout()
  tv.tv_usec = 0;
  if(tv.tv_sec > xfrd->nsd->options->xfrd_reload_timeout)
  tv.tv_sec = xfrd->nsd->options->xfrd_reload_timeout;
+ memset(&xfrd->reload_handler, 0, sizeof(xfrd->reload_handler));
  event_set(&xfrd->reload_handler, -1, EV_TIMEOUT,
  xfrd_handle_reload, xfrd);
  if(event_base_set(xfrd->event_base, &xfrd->reload_handler) != 0)
@@ -2567,6 +2575,7 @@ static void xfrd_write_timer_set()
  return;
  tv.tv_sec = xfrd->nsd->options->zonefiles_write;
  tv.tv_usec = 0;
+ memset(&xfrd->write_timer, 0, sizeof(xfrd->write_timer));
  event_set(&xfrd->write_timer, -1, EV_TIMEOUT,
  xfrd_handle_write_timer, xfrd);
  if(event_base_set(xfrd->event_base, &xfrd->write_timer) != 0)
Index: zlexer.lex
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/zlexer.lex,v
retrieving revision 1.5
diff -u -p -r1.5 zlexer.lex
--- zlexer.lex 3 Feb 2018 11:03:51 -0000 1.5
+++ zlexer.lex 6 Aug 2019 11:53:07 -0000
@@ -58,6 +58,10 @@ push_parser_state(FILE *input)
 static void
 pop_parser_state(void)
 {
+ if (parser->filename)
+ region_recycle(parser->region, (void *)parser->filename,
+ strlen(parser->filename)+1);
+
  --include_stack_ptr;
  parser->filename = zparser_stack[include_stack_ptr].filename;
  parser->line = zparser_stack[include_stack_ptr].line;
Index: zonec.c
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/zonec.c,v
retrieving revision 1.25
diff -u -p -r1.25 zonec.c
--- zonec.c 17 May 2018 18:58:40 -0000 1.25
+++ zonec.c 6 Aug 2019 11:53:07 -0000
@@ -1464,6 +1464,16 @@ process_rr(void)
 
  /* Discard the duplicates... */
  if (i < rrset->rr_count) {
+ /* add rdatas to recycle bin. */
+ size_t i;
+ for (i = 0; i < rr->rdata_count; i++) {
+ if(!rdata_atom_is_domain(rr->type, i))
+ region_recycle(parser->region, rr->rdatas[i].data,
+ rdata_atom_size(rr->rdatas[i])
+ + sizeof(uint16_t));
+ }
+ region_recycle(parser->region, rr->rdatas,
+ sizeof(rdata_atom_type)*rr->rdata_count);
  return 0;
  }
  if(rrset->rr_count == 65535) {
Index: zonec.h
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/zonec.h,v
retrieving revision 1.8
diff -u -p -r1.8 zonec.h
--- zonec.h 3 Feb 2018 11:03:51 -0000 1.8
+++ zonec.h 6 Aug 2019 11:53:07 -0000
@@ -47,7 +47,6 @@ struct zparser {
  zone_type *current_zone;
  domain_type *origin;
  domain_type *prev_dname;
- domain_type *default_apex;
 
  int error_occurred;
  unsigned int errors;
Index: zparser.y
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/zparser.y,v
retrieving revision 1.20
diff -u -p -r1.20 zparser.y
--- zparser.y 10 Dec 2018 16:09:11 -0000 1.20
+++ zparser.y 6 Aug 2019 11:53:07 -0000
@@ -1157,7 +1157,6 @@ zparser_create(region_type *region, regi
  result->current_zone = NULL;
  result->origin = NULL;
  result->prev_dname = NULL;
- result->default_apex = NULL;
 
  result->temporary_rdatas = (rdata_atom_type *) region_alloc_array(
  result->region, MAXRDATALEN, sizeof(rdata_atom_type));
@@ -1181,7 +1180,6 @@ zparser_init(const char *filename, uint3
  parser->current_zone = NULL;
  parser->origin = domain_table_insert(parser->db->domains, origin);
  parser->prev_dname = parser->origin;
- parser->default_apex = parser->origin;
  parser->error_occurred = 0;
  parser->errors = 0;
  parser->line = 1;