NSD 4.2.2

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

NSD 4.2.2

Stuart Henderson
Any comments, test reports, objections or OKs?

Changes since the version we have:

4.2.2 - Bug fixes only:

Fix #20: CVE-2019-13207 Stack-based Buffer Overflow in the dname_concatenate() function. Reported by Frederic Cambus. It causes the zone parser to crash on a malformed zone file, with assertions enabled, an assertion catches it.
Fix #19: Out-of-bounds read caused by improper validation of array index. Reported by Frederic Cambus. The zone parser fails on type SIG because of mismatched definition with RRSIG.
PR #23: Fix typo in nsd.conf man-page.
Fix that NSD warns for wrong length of the hash in SSHFP records.
Fix #25: NSD doesn't refresh zones after extended downtime, it refreshes the old zones.
Set no renegotiation on the SSL context to stop client session renegotiation.
Fix #29: SSHFP check NULL pointer dereference.
Fix #30: SSHFP check failure due to missing domain name.
Fix to timeval_add in minievent for remaining second in microseconds.
PR #31: nsd-control: Add missing stdio header.
PR #32: tsig: Fix compilation without HAVE_SSL.
Cleanup tls context on xfrd exit.
Fix #33: Fix segfault in service of remaining streams on exit.
Fix error message for out of zone data to have more information.

4.2.1 -

Features:

Added num.tls and num.tls6 stat counters.
PR #12: send-buffer-size, receive-buffer-size, tcp-reject-overflow options for nsd.conf, from Jeroen Koekkoek.
Fix #14, tcp connections have 1/10 to be active and have to work every second, and then they get time to complete during a reload, this is a process that lingers with the old version during a version update.

Bug Fixes:

Fix #13: Stray dot at the end of some log entries, removes dot after updated serial number in log entry.
Fix TLS cipher selection, the previous was redundant, prefers CHACHA20-POLY1305 over AESGCM and was not as readable as it could be.
Consolidate server tls context create and remote control context create, with hardening for the remote control tls context too.
Fix to init event structure for reassignment.
Fix to init event not pointer, in reassignment.
Fix #15: crash in SSL library, initialize variables for TCP access when TLS is configured.
Fix tls handshake event callback function mistake, reported by Mykhailo Danylenko.
Initialize event structures before event_set, to stop uninitialized values from setting event library lists and assertions, that would sometimes also show after event_del.
Do not use symbol from libc, instead use own replacement, if not available, for accept4.
Fix output of nsd-checkconf -h.

4.2.0 -

Features:

Print IP address when bind socket fails with error.
Fix #4249: The option hide-identity: yes stops NSD from responding with the hostname for chaos class queries. Implements the RFC4892 security considerations.
Patch to add support for TCP Fast Open, from Sara Dickinson (Sinodun).
Patch to add support for tls service on a specified tls port, from Sara Dickinson (Sinodun).
Use travis for build check, initial unit test and clang analysis.
TLS OCSP stapling support, enabled with tls-service-ocsp: filename, patch from Andreas Schulze.

Bug Fixes:

Fix to delete unused zparser.default_apex member.
Fix that the TLS handshake routine sets the correct event to continue when done.
Fix that TLS renegotiation calls the read and write routines again with the same parameters when the desired event has been satisfied.
Fix that TCP Fastopen has better error message and supports OSX.
Fix to avoid buffer alloc with global buffer in tls write handler.
Fix to initialize event structure when accepting TCP connection.
Disable TLS1.0, TLS1.1 and weak ciphers, enable CIPHER_SERVER_PREFERENCE, patch from Andreas Schulze.
further setup ssl ctx after the keys are loaded, for ECDH.
Fix #10: Fix memory leaks caused by duplicate rr and include instructions.
Fix to define _OPENBSD_SOURCE to get reallocarray on NetBSD.


 config.h.in        |   25 +
 configlexer.lex    |    8
 configparser.y     |   81 +++
 configure          |  181 ++++++--
 configure.ac       |   65 ++
 dns.c              |    8
 ipc.c              |    9
 mini_event.c       |    5
 nsd-checkconf.8.in |    2
 nsd-checkconf.c    |   21
 nsd-checkzone.8.in |    2
 nsd-checkzone.c    |    4
 nsd-control.8.in   |   10
 nsd-control.c      |    8
 nsd.8.in           |    4
 nsd.c              |   12
 nsd.conf.5.in      |   51 ++
 nsd.conf.sample.in |   24 +
 nsd.h              |   15
 options.c          |    8
 options.h          |   13
 query.c            |   10
 remote.c           |   87 ---
 server.c           | 1183 ++++++++++++++++++++++++++++++++++++++++++++++++++---
 tsig.c             |   55 ++
 util.c             |   29 +
 util.h             |    9
 xfrd-disk.c        |    7
 xfrd-notify.c      |    6
 xfrd-tcp.c         |    2
 xfrd.c             |   13
 zlexer.lex         |    4
 zonec.c            |   49 ++
 zonec.h            |    3
 zparser.y          |    9
 35 files changed, 1818 insertions(+), 204 deletions(-)



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 12 Sep 2019 11:25:03 -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 12 Sep 2019 11:25:03 -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 12 Sep 2019 11:25:03 -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 12 Sep 2019 11:25:03 -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.2.
 #
 # 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.2'
+PACKAGE_STRING='NSD 4.2.2'
 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.2 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.2:";;
    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.2
 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.2, 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.2, 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.2
 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 12 Sep 2019 11:25:03 -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.2,[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: dns.c
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/dns.c,v
retrieving revision 1.18
diff -u -p -r1.18 dns.c
--- dns.c 16 Aug 2018 17:56:18 -0000 1.18
+++ dns.c 12 Sep 2019 11:25:03 -0000
@@ -121,10 +121,10 @@ static rrtype_descriptor_type rrtype_des
  { TYPE_SIG, "SIG", T_SIG, 9, 9,
   { RDATA_WF_SHORT, RDATA_WF_BYTE, RDATA_WF_BYTE, RDATA_WF_LONG,
     RDATA_WF_LONG, RDATA_WF_LONG, RDATA_WF_SHORT,
-    RDATA_WF_UNCOMPRESSED_DNAME, RDATA_WF_BINARY },
-  { RDATA_ZF_RRTYPE, RDATA_ZF_BYTE, RDATA_ZF_BYTE, RDATA_ZF_PERIOD,
-    RDATA_ZF_TIME, RDATA_ZF_TIME, RDATA_ZF_SHORT, RDATA_ZF_DNAME,
-    RDATA_ZF_BASE64 } },
+    RDATA_WF_LITERAL_DNAME, RDATA_WF_BINARY },
+  { RDATA_ZF_RRTYPE, RDATA_ZF_ALGORITHM, RDATA_ZF_BYTE, RDATA_ZF_PERIOD,
+    RDATA_ZF_TIME, RDATA_ZF_TIME, RDATA_ZF_SHORT,
+    RDATA_ZF_LITERAL_DNAME, RDATA_ZF_BASE64 } },
  /* 25 */
  { TYPE_KEY, "KEY", T_KEY, 4, 4,
   { RDATA_WF_SHORT, RDATA_WF_BYTE, RDATA_WF_BYTE, RDATA_WF_BINARY },
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 12 Sep 2019 11:25:03 -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: mini_event.c
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/mini_event.c,v
retrieving revision 1.2
diff -u -p -r1.2 mini_event.c
--- mini_event.c 17 Feb 2017 20:04:45 -0000 1.2
+++ mini_event.c 12 Sep 2019 11:25:03 -0000
@@ -304,8 +304,7 @@ event_base_free(struct event_base* base)
 {
  if(!base)
  return;
- if(base->times)
- free(base->times);
+ /* base->times is allocated in region and is freed with the region */
  if(base->fds)
  free(base->fds);
  if(base->signals)
@@ -362,7 +361,7 @@ event_add(struct event* ev, struct timev
  struct timeval* now = ev->ev_base->time_tv;
  ev->ev_timeout.tv_sec = tv->tv_sec + now->tv_sec;
  ev->ev_timeout.tv_usec = tv->tv_usec + now->tv_usec;
- while(ev->ev_timeout.tv_usec > 1000000) {
+ while(ev->ev_timeout.tv_usec >= 1000000) {
  ev->ev_timeout.tv_usec -= 1000000;
  ev->ev_timeout.tv_sec++;
  }
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 12 Sep 2019 11:25:03 -0000
@@ -1,4 +1,4 @@
-.TH "nsd\-checkconf" "8" "Mar 25, 2019" "NLnet Labs" "nsd 4.1.27"
+.TH "nsd\-checkconf" "8" "Aug 19, 2019" "NLnet Labs" "nsd 4.2.2"
 .\" 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 12 Sep 2019 11:25:03 -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 12 Sep 2019 11:25:03 -0000
@@ -1,4 +1,4 @@
-.TH "nsd\-checkzone" "8" "Mar 25, 2019" "NLnet Labs" "nsd 4.1.27"
+.TH "nsd\-checkzone" "8" "Aug 19, 2019" "NLnet Labs" "nsd 4.2.2"
 .\" Copyright (c) 2014, NLnet Labs. All rights reserved.
 .\" See LICENSE for the license.
 .SH "NAME"
Index: nsd-checkzone.c
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/nsd-checkzone.c,v
retrieving revision 1.3
diff -u -p -r1.3 nsd-checkzone.c
--- nsd-checkzone.c 29 Sep 2018 17:17:54 -0000 1.3
+++ nsd-checkzone.c 12 Sep 2019 11:25:03 -0000
@@ -61,6 +61,10 @@ check_zone(struct nsd* nsd, const char*
  errors = zonec_read(name, fname, zone);
  if(errors > 0) {
  printf("zone %s file %s has %u errors\n", name, fname, errors);
+#ifdef MEMCLEAN /* otherwise, the OS collects memory pages */
+ namedb_close(nsd->db);
+ region_destroy(nsd->options->region);
+#endif
  exit(1);
  }
  printf("zone %s is ok\n", 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 12 Sep 2019 11:25:03 -0000
@@ -1,4 +1,4 @@
-.TH "nsd\-control" "8" "Mar 25, 2019" "NLnet Labs" "nsd 4.1.27"
+.TH "nsd\-control" "8" "Aug 19, 2019" "NLnet Labs" "nsd 4.2.2"
 .\" 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-control.c
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/nsd-control.c,v
retrieving revision 1.8
diff -u -p -r1.8 nsd-control.c
--- nsd-control.c 30 Mar 2019 01:20:29 -0000 1.8
+++ nsd-control.c 12 Sep 2019 11:25:03 -0000
@@ -42,8 +42,8 @@
  */
 
 #include "config.h"
+#include <stdio.h>
 #ifdef HAVE_SSL
-
 #include <sys/types.h>
 #include <unistd.h>
 #include <string.h>
@@ -163,6 +163,12 @@ setup_ctx(struct nsd_options* cfg)
         if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3)
  != SSL_OP_NO_SSLv3)
  ssl_err("could not set SSL_OP_NO_SSLv3");
+#if defined(SSL_OP_NO_RENEGOTIATION)
+ /* disable client renegotiation */
+ if((SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION) &
+ SSL_OP_NO_RENEGOTIATION) != SSL_OP_NO_RENEGOTIATION)
+ ssl_err("could not set SSL_OP_NO_RENEGOTIATION");
+#endif
  if(!SSL_CTX_use_certificate_file(ctx,c_cert,SSL_FILETYPE_PEM))
  ssl_path_err("Error setting up SSL_CTX client cert", c_cert);
  if(!SSL_CTX_use_PrivateKey_file(ctx,c_key,SSL_FILETYPE_PEM))
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 12 Sep 2019 11:25:03 -0000
@@ -1,9 +1,9 @@
-.TH "NSD" "8" "Mar 25, 2019" "NLnet Labs" "NSD 4.1.27"
+.TH "NSD" "8" "Aug 19, 2019" "NLnet Labs" "NSD 4.2.2"
 .\" 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.2.
 .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 12 Sep 2019 11:25:03 -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 12 Sep 2019 11:25:03 -0000
@@ -1,4 +1,4 @@
-.TH "nsd.conf" "5" "Mar 25, 2019" "NLnet Labs" "nsd 4.1.27"
+.TH "nsd.conf" "5" "Aug 19, 2019" "NLnet Labs" "nsd 4.2.2"
 .\" Copyright (c) 2001\-2008, NLnet Labs. All rights reserved.
 .\" See LICENSE for the license.
 .SH "NAME"
@@ -149,7 +149,7 @@ clause. There may only be one
 clause.
 .TP
 .B ip\-address:\fR <ip4 or ip6>[@port]
-NSD will bind to the listed ip\-address. Can be give multiple times
+NSD will bind to the listed ip\-address. Can be given multiple times
 to bind multiple ip\-addresses. Optionally, a port number can be given.
 If none are given NSD listens to the wildcard interface. Same as commandline option
 .BR \-a.
@@ -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 12 Sep 2019 11:25:03 -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 12 Sep 2019 11:25:03 -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 12 Sep 2019 11:25:03 -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 12 Sep 2019 11:25:03 -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 12 Sep 2019 11:25:03 -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 12 Sep 2019 11:25:03 -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 12 Sep 2019 11:25:03 -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));
@@ -1039,9 +1173,12 @@ server_prepare(struct nsd *nsd)
 #else
  uint32_t v = getpid() ^ time(NULL);
  srandom((unsigned long)v);
+#  ifdef HAVE_SSL
  if(RAND_status() && RAND_bytes((unsigned char*)&v, sizeof(v)) > 0)
  hash_set_raninit(v);
- else hash_set_raninit(random());
+ else
+#  endif
+ hash_set_raninit(random());
 #endif
  rrl_mmap_init(nsd->child_count, nsd->options->rrl_size,
  nsd->options->rrl_ratelimit,
@@ -1149,6 +1286,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 +1520,306 @@ 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(SSL_OP_NO_RENEGOTIATION)
+ /* disable client renegotiation */
+ if((SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION) &
+ SSL_OP_NO_RENEGOTIATION) != SSL_OP_NO_RENEGOTIATION) {
+ log_crypto_err("could not set SSL_OP_NO_RENEGOTIATION");
+ 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 +2547,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 +2602,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 +2628,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 +2702,7 @@ server_child(struct nsd *nsd)
  }
  }
 
+ service_remaining_tcp(nsd);
 #ifdef BIND8_STATS
  bind8_stats(nsd);
 #endif /* BIND8_STATS */
@@ -2261,6 +2717,114 @@ 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;
+ }
+ }
+#ifdef MEMCLEAN
+ event_base_free(event_base);
+#endif
+ /* 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 +3116,48 @@ handle_udp(int fd, short event, void* ar
 }
 #endif /* defined(HAVE_SENDMMSG) && !defined(NONBLOCKING_IS_BROKEN) && defined(HAVE_RECVMMSG) */
 
+#ifdef HAVE_SSL
+/*
+ * 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");
+}
+#endif /* HAVE_SSL */
 
 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 +3193,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 +3370,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 +3391,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 +3524,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 +3556,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 +3565,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 +3998,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 +4029,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 +4045,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 +4068,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 +4092,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 +4110,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 +4127,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 +4162,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 +4255,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: tsig.c
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/tsig.c,v
retrieving revision 1.5
diff -u -p -r1.5 tsig.c
--- tsig.c 30 Jul 2018 08:57:09 -0000 1.5
+++ tsig.c 12 Sep 2019 11:25:03 -0000
@@ -19,6 +19,61 @@
 #include "query.h"
 #include "rbtree.h"
 
+#ifndef HAVE_SSL
+/* we need fixed time compare */
+#define CRYPTO_memcmp memcmp_fixedtime
+int memcmp_fixedtime(const void *s1, const void *s2, size_t n)
+{
+ size_t i;
+ const uint8_t* u1 = (const uint8_t*)s1;
+ const uint8_t* u2 = (const uint8_t*)s2;
+ int ret = 0, haveit = 0, bret = 0, bhaveit = 0;
+ /* this routine loops for every byte in the strings.
+ * every loop, it tests ==, < and >.  All three.  One succeeds,
+ * as every time it must be equal, smaller or larger.  The one
+ * that succeeds has one if-comparison and two assignments. */
+ for(i=0; i<n; i++) {
+ if(u1[i] == u2[i]) {
+ /* waste time equal to < and > statements */
+ if(haveit) {
+ bret = -1; /* waste time */
+ bhaveit = 1;
+ } else {
+ bret = 1; /* waste time */
+ bhaveit = 1;
+ }
+ }
+ if(u1[i] < u2[i]) {
+ if(haveit) {
+ bret = -1; /* waste time equal to the else */
+ bhaveit = 1;
+ } else {
+ ret = -1;
+ haveit = 1;
+ }
+ }
+ if(u1[i] > u2[i]) {
+ if(haveit) {
+ bret = 1; /* waste time equal to the else */
+ bhaveit = 1;
+ } else {
+ ret = 1;
+ haveit = 1;
+ }
+ }
+ }
+ /* use the variables to stop the compiler from excluding them */
+ if(bhaveit) {
+ if(bret == -2)
+ ret = 0; /* never happens */
+ } else {
+ if(bret == -2)
+ ret = 0; /* never happens */
+ }
+ return ret;
+}
+#endif
+
 static region_type *tsig_region;
 
 struct tsig_key_table
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 12 Sep 2019 11:25:03 -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 12 Sep 2019 11:25:03 -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-disk.c
===================================================================
RCS file: /cvs/src/usr.sbin/nsd/xfrd-disk.c,v
retrieving revision 1.12
diff -u -p -r1.12 xfrd-disk.c
--- xfrd-disk.c 17 May 2018 18:58:40 -0000 1.12
+++ xfrd-disk.c 12 Sep 2019 11:25:03 -0000
@@ -289,6 +289,13 @@ xfrd_read_state(struct xfrd_state* xfrd)
  zone->state = xfrd_zone_refreshing;
  xfrd_set_refresh_now(zone);
  }
+ if(timeout != 0 && filetime + timeout < (uint32_t)xfrd_time()) {
+ /* timeout is in the past, refresh the zone */
+ timeout = 0;
+ if(zone->state == xfrd_zone_ok)
+ zone->state = xfrd_zone_refreshing;
+ xfrd_set_refresh_now(zone);
+ }
 
  /* There is a soa && current time is past expiry point */
  if(soa_disk_acquired_read!=0 &&
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 12 Sep 2019 11:25:03 -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 12 Sep 2019 11:25:03 -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 12 Sep 2019 11:25:03 -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)
@@ -400,6 +402,8 @@ xfrd_shutdown()
  xfrd_del_tempdir(xfrd->nsd);
 #ifdef HAVE_SSL
  daemon_remote_delete(xfrd->nsd->rc); /* ssl-delete secret keys */
+ if (xfrd->nsd->tls_ctx)
+ SSL_CTX_free(xfrd->nsd->tls_ctx);
 #endif
 #ifdef USE_DNSTAP
  dt_collector_close(nsd.dt_collector, &nsd);
@@ -1038,6 +1042,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 +1180,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 +1207,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 +1331,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 +2225,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 +2577,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 12 Sep 2019 11:25:03 -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 12 Sep 2019 11:25:03 -0000
@@ -1409,8 +1409,10 @@ process_rr(void)
  assert(zone);
  if (rr->type == TYPE_SOA) {
  if (rr->owner != zone->apex) {
+ char s[MAXDOMAINLEN*5];
+ snprintf(s, sizeof(s), "%s", domain_to_string(zone->apex));
  zc_error_prev_line(
- "SOA record with invalid domain name");
+ "SOA record with invalid domain name, '%s' is not '%s'", domain_to_string(rr->owner), s);
  return 0;
  }
  if(has_soa(rr->owner)) {
@@ -1425,10 +1427,12 @@ process_rr(void)
 
  if (!domain_is_subdomain(rr->owner, zone->apex))
  {
+ char s[MAXDOMAINLEN*5];
+ snprintf(s, sizeof(s), "%s", domain_to_string(zone->apex));
  if(zone_is_slave(zone->opts))
- zc_warning_prev_line("out of zone data");
+ zc_warning_prev_line("out of zone data: %s is outside the zone for fqdn %s", domain_to_string(rr->owner), s);
  else
- zc_error_prev_line("out of zone data");
+ zc_error_prev_line("out of zone data: %s is outside the zone for fqdn %s", domain_to_string(rr->owner), s);
  return 0;
  }
 
@@ -1464,6 +1468,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) {
@@ -1731,4 +1745,33 @@ zonec_parse_string(region_type* region,
  zonec_desetup_string_parser();
  parser_flush();
  return errors;
+}
+
+/** check SSHFP type for failures and emit warnings */
+void check_sshfp(void)
+{
+ uint8_t hash;
+ uint16_t size;
+ if(parser->current_rr.rdata_count < 3)
+ return; /* cannot check it, too few rdata elements */
+ if(!parser->current_rr.rdatas[0].data ||
+ !parser->current_rr.rdatas[1].data ||
+ !parser->current_rr.rdatas[2].data ||
+ !parser->current_rr.owner)
+ return; /* cannot check, NULLs (due to earlier errors) */
+ if(rdata_atom_size(parser->current_rr.rdatas[1]) != 1)
+ return; /* wrong size of the hash type rdata element */
+ hash = rdata_atom_data(parser->current_rr.rdatas[1])[0];
+ size = rdata_atom_size(parser->current_rr.rdatas[2]);
+ if(hash == 1 && size != 20) {
+ zc_warning_prev_line("SSHFP %s of type SHA1 has hash of "
+ "wrong length, %d bytes, should be 20",
+ domain_to_string(parser->current_rr.owner),
+ (int)size);
+ } else if(hash == 2 && size != 32) {
+ zc_warning_prev_line("SSHFP %s of type SHA256 has hash of "
+ "wrong length, %d bytes, should be 32",
+ domain_to_string(parser->current_rr.owner),
+ (int)size);
+ }
 }
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 12 Sep 2019 11:25:03 -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;
@@ -143,5 +142,7 @@ unsigned int zonec_read(const char *name
  * The string must end with a newline after the RR. */
 int zonec_parse_string(region_type* region, domain_table_type* domains,
  zone_type* zone, char* str, domain_type** parsed, int* num_rrs);
+/** check SSHFP type for failures and emit warnings */
+void check_sshfp(void);
 
 #endif /* _ZONEC_H_ */
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 12 Sep 2019 11:25:03 -0000
@@ -633,7 +633,7 @@ type_and_rdata:
     | T_DLV sp rdata_dlv { if (dlv_warn) { dlv_warn = 0; zc_warning_prev_line("DLV is experimental"); } }
     | T_DLV sp rdata_unknown { if (dlv_warn) { dlv_warn = 0; zc_warning_prev_line("DLV is experimental"); } $$ = $1; parse_unknown_rdata($1, $3); }
     | T_SSHFP sp rdata_sshfp
-    | T_SSHFP sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+    | T_SSHFP sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); check_sshfp(); }
     | T_RRSIG sp rdata_rrsig
     | T_RRSIG sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
     | T_NSEC sp rdata_nsec
@@ -906,6 +906,7 @@ rdata_sshfp: STR sp STR sp str_sp_seq tr
     zadd_rdata_wireformat(zparser_conv_byte(parser->region, $1.str)); /* alg */
     zadd_rdata_wireformat(zparser_conv_byte(parser->region, $3.str)); /* fp type */
     zadd_rdata_wireformat(zparser_conv_hex(parser->region, $5.str, $5.len)); /* hash */
+    check_sshfp();
     }
     ;
 
@@ -1020,6 +1021,10 @@ rdata_ipsec_base: STR sp STR sp STR sp d
  if(parser->origin == error_domain) {
      zc_error("cannot concatenate origin to domain name, because origin failed to parse");
  break;
+ } else if(name->name_size + domain_dname(parser->origin)->name_size - 1 > MAXDOMAINLEN) {
+ zc_error("ipsec gateway name exceeds %d character limit",
+ MAXDOMAINLEN);
+ break;
  }
  name = dname_concatenate(parser->rr_region, name,
  domain_dname(parser->origin));
@@ -1157,7 +1162,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 +1185,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;

Reply | Threaded
Open this post in threaded view
|

Re: NSD 4.2.2

Florian Obser-2
The TLS code is scaring me and I don't trust it.

Hopefully the impact it had on non-tls code has been shaken out.
(There was at least one bug / crash due to this, since been fixed.)

That being said, I'm running this in production since some time
without issues.

OK florian

On Thu, Sep 12, 2019 at 12:26:40PM +0100, Stuart Henderson wrote:

> Any comments, test reports, objections or OKs?
>
> Changes since the version we have:
>
> 4.2.2 - Bug fixes only:
>
> Fix #20: CVE-2019-13207 Stack-based Buffer Overflow in the dname_concatenate() function. Reported by Frederic Cambus. It causes the zone parser to crash on a malformed zone file, with assertions enabled, an assertion catches it.
> Fix #19: Out-of-bounds read caused by improper validation of array index. Reported by Frederic Cambus. The zone parser fails on type SIG because of mismatched definition with RRSIG.
> PR #23: Fix typo in nsd.conf man-page.
> Fix that NSD warns for wrong length of the hash in SSHFP records.
> Fix #25: NSD doesn't refresh zones after extended downtime, it refreshes the old zones.
> Set no renegotiation on the SSL context to stop client session renegotiation.
> Fix #29: SSHFP check NULL pointer dereference.
> Fix #30: SSHFP check failure due to missing domain name.
> Fix to timeval_add in minievent for remaining second in microseconds.
> PR #31: nsd-control: Add missing stdio header.
> PR #32: tsig: Fix compilation without HAVE_SSL.
> Cleanup tls context on xfrd exit.
> Fix #33: Fix segfault in service of remaining streams on exit.
> Fix error message for out of zone data to have more information.
>
> 4.2.1 -
>
> Features:
>
> Added num.tls and num.tls6 stat counters.
> PR #12: send-buffer-size, receive-buffer-size, tcp-reject-overflow options for nsd.conf, from Jeroen Koekkoek.
> Fix #14, tcp connections have 1/10 to be active and have to work every second, and then they get time to complete during a reload, this is a process that lingers with the old version during a version update.
>
> Bug Fixes:
>
> Fix #13: Stray dot at the end of some log entries, removes dot after updated serial number in log entry.
> Fix TLS cipher selection, the previous was redundant, prefers CHACHA20-POLY1305 over AESGCM and was not as readable as it could be.
> Consolidate server tls context create and remote control context create, with hardening for the remote control tls context too.
> Fix to init event structure for reassignment.
> Fix to init event not pointer, in reassignment.
> Fix #15: crash in SSL library, initialize variables for TCP access when TLS is configured.
> Fix tls handshake event callback function mistake, reported by Mykhailo Danylenko.
> Initialize event structures before event_set, to stop uninitialized values from setting event library lists and assertions, that would sometimes also show after event_del.
> Do not use symbol from libc, instead use own replacement, if not available, for accept4.
> Fix output of nsd-checkconf -h.
>
> 4.2.0 -
>
> Features:
>
> Print IP address when bind socket fails with error.
> Fix #4249: The option hide-identity: yes stops NSD from responding with the hostname for chaos class queries. Implements the RFC4892 security considerations.
> Patch to add support for TCP Fast Open, from Sara Dickinson (Sinodun).
> Patch to add support for tls service on a specified tls port, from Sara Dickinson (Sinodun).
> Use travis for build check, initial unit test and clang analysis.
> TLS OCSP stapling support, enabled with tls-service-ocsp: filename, patch from Andreas Schulze.
>
> Bug Fixes:
>
> Fix to delete unused zparser.default_apex member.
> Fix that the TLS handshake routine sets the correct event to continue when done.
> Fix that TLS renegotiation calls the read and write routines again with the same parameters when the desired event has been satisfied.
> Fix that TCP Fastopen has better error message and supports OSX.
> Fix to avoid buffer alloc with global buffer in tls write handler.
> Fix to initialize event structure when accepting TCP connection.
> Disable TLS1.0, TLS1.1 and weak ciphers, enable CIPHER_SERVER_PREFERENCE, patch from Andreas Schulze.
> further setup ssl ctx after the keys are loaded, for ECDH.
> Fix #10: Fix memory leaks caused by duplicate rr and include instructions.
> Fix to define _OPENBSD_SOURCE to get reallocarray on NetBSD.
>
>
>  config.h.in        |   25 +
>  configlexer.lex    |    8
>  configparser.y     |   81 +++
>  configure          |  181 ++++++--
>  configure.ac       |   65 ++
>  dns.c              |    8
>  ipc.c              |    9
>  mini_event.c       |    5
>  nsd-checkconf.8.in |    2
>  nsd-checkconf.c    |   21
>  nsd-checkzone.8.in |    2
>  nsd-checkzone.c    |    4
>  nsd-control.8.in   |   10
>  nsd-control.c      |    8
>  nsd.8.in           |    4
>  nsd.c              |   12
>  nsd.conf.5.in      |   51 ++
>  nsd.conf.sample.in |   24 +
>  nsd.h              |   15
>  options.c          |    8
>  options.h          |   13
>  query.c            |   10
>  remote.c           |   87 ---
>  server.c           | 1183 ++++++++++++++++++++++++++++++++++++++++++++++++++---
>  tsig.c             |   55 ++
>  util.c             |   29 +
>  util.h             |    9
>  xfrd-disk.c        |    7
>  xfrd-notify.c      |    6
>  xfrd-tcp.c         |    2
>  xfrd.c             |   13
>  zlexer.lex         |    4
>  zonec.c            |   49 ++
>  zonec.h            |    3
>  zparser.y          |    9
>  35 files changed, 1818 insertions(+), 204 deletions(-)
>
>
>
> 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 12 Sep 2019 11:25:03 -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 12 Sep 2019 11:25:03 -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 12 Sep 2019 11:25:03 -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 12 Sep 2019 11:25:03 -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.2.
>  #
>  # 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.2'
> +PACKAGE_STRING='NSD 4.2.2'
>  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.2 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.2:";;
>     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.2
>  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.2, 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.2, 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.2
>  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 12 Sep 2019 11:25:03 -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.2,[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: dns.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/nsd/dns.c,v
> retrieving revision 1.18
> diff -u -p -r1.18 dns.c
> --- dns.c 16 Aug 2018 17:56:18 -0000 1.18
> +++ dns.c 12 Sep 2019 11:25:03 -0000
> @@ -121,10 +121,10 @@ static rrtype_descriptor_type rrtype_des
>   { TYPE_SIG, "SIG", T_SIG, 9, 9,
>    { RDATA_WF_SHORT, RDATA_WF_BYTE, RDATA_WF_BYTE, RDATA_WF_LONG,
>      RDATA_WF_LONG, RDATA_WF_LONG, RDATA_WF_SHORT,
> -    RDATA_WF_UNCOMPRESSED_DNAME, RDATA_WF_BINARY },
> -  { RDATA_ZF_RRTYPE, RDATA_ZF_BYTE, RDATA_ZF_BYTE, RDATA_ZF_PERIOD,
> -    RDATA_ZF_TIME, RDATA_ZF_TIME, RDATA_ZF_SHORT, RDATA_ZF_DNAME,
> -    RDATA_ZF_BASE64 } },
> +    RDATA_WF_LITERAL_DNAME, RDATA_WF_BINARY },
> +  { RDATA_ZF_RRTYPE, RDATA_ZF_ALGORITHM, RDATA_ZF_BYTE, RDATA_ZF_PERIOD,
> +    RDATA_ZF_TIME, RDATA_ZF_TIME, RDATA_ZF_SHORT,
> +    RDATA_ZF_LITERAL_DNAME, RDATA_ZF_BASE64 } },
>   /* 25 */
>   { TYPE_KEY, "KEY", T_KEY, 4, 4,
>    { RDATA_WF_SHORT, RDATA_WF_BYTE, RDATA_WF_BYTE, RDATA_WF_BINARY },
> 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 12 Sep 2019 11:25:03 -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: mini_event.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/nsd/mini_event.c,v
> retrieving revision 1.2
> diff -u -p -r1.2 mini_event.c
> --- mini_event.c 17 Feb 2017 20:04:45 -0000 1.2
> +++ mini_event.c 12 Sep 2019 11:25:03 -0000
> @@ -304,8 +304,7 @@ event_base_free(struct event_base* base)
>  {
>   if(!base)
>   return;
> - if(base->times)
> - free(base->times);
> + /* base->times is allocated in region and is freed with the region */
>   if(base->fds)
>   free(base->fds);
>   if(base->signals)
> @@ -362,7 +361,7 @@ event_add(struct event* ev, struct timev
>   struct timeval* now = ev->ev_base->time_tv;
>   ev->ev_timeout.tv_sec = tv->tv_sec + now->tv_sec;
>   ev->ev_timeout.tv_usec = tv->tv_usec + now->tv_usec;
> - while(ev->ev_timeout.tv_usec > 1000000) {
> + while(ev->ev_timeout.tv_usec >= 1000000) {
>   ev->ev_timeout.tv_usec -= 1000000;
>   ev->ev_timeout.tv_sec++;
>   }
> 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 12 Sep 2019 11:25:03 -0000
> @@ -1,4 +1,4 @@
> -.TH "nsd\-checkconf" "8" "Mar 25, 2019" "NLnet Labs" "nsd 4.1.27"
> +.TH "nsd\-checkconf" "8" "Aug 19, 2019" "NLnet Labs" "nsd 4.2.2"
>  .\" 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 12 Sep 2019 11:25:03 -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 12 Sep 2019 11:25:03 -0000
> @@ -1,4 +1,4 @@
> -.TH "nsd\-checkzone" "8" "Mar 25, 2019" "NLnet Labs" "nsd 4.1.27"
> +.TH "nsd\-checkzone" "8" "Aug 19, 2019" "NLnet Labs" "nsd 4.2.2"
>  .\" Copyright (c) 2014, NLnet Labs. All rights reserved.
>  .\" See LICENSE for the license.
>  .SH "NAME"
> Index: nsd-checkzone.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/nsd/nsd-checkzone.c,v
> retrieving revision 1.3
> diff -u -p -r1.3 nsd-checkzone.c
> --- nsd-checkzone.c 29 Sep 2018 17:17:54 -0000 1.3
> +++ nsd-checkzone.c 12 Sep 2019 11:25:03 -0000
> @@ -61,6 +61,10 @@ check_zone(struct nsd* nsd, const char*
>   errors = zonec_read(name, fname, zone);
>   if(errors > 0) {
>   printf("zone %s file %s has %u errors\n", name, fname, errors);
> +#ifdef MEMCLEAN /* otherwise, the OS collects memory pages */
> + namedb_close(nsd->db);
> + region_destroy(nsd->options->region);
> +#endif
>   exit(1);
>   }
>   printf("zone %s is ok\n", 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 12 Sep 2019 11:25:03 -0000
> @@ -1,4 +1,4 @@
> -.TH "nsd\-control" "8" "Mar 25, 2019" "NLnet Labs" "nsd 4.1.27"
> +.TH "nsd\-control" "8" "Aug 19, 2019" "NLnet Labs" "nsd 4.2.2"
>  .\" 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-control.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/nsd/nsd-control.c,v
> retrieving revision 1.8
> diff -u -p -r1.8 nsd-control.c
> --- nsd-control.c 30 Mar 2019 01:20:29 -0000 1.8
> +++ nsd-control.c 12 Sep 2019 11:25:03 -0000
> @@ -42,8 +42,8 @@
>   */
>  
>  #include "config.h"
> +#include <stdio.h>
>  #ifdef HAVE_SSL
> -
>  #include <sys/types.h>
>  #include <unistd.h>
>  #include <string.h>
> @@ -163,6 +163,12 @@ setup_ctx(struct nsd_options* cfg)
>          if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3)
>   != SSL_OP_NO_SSLv3)
>   ssl_err("could not set SSL_OP_NO_SSLv3");
> +#if defined(SSL_OP_NO_RENEGOTIATION)
> + /* disable client renegotiation */
> + if((SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION) &
> + SSL_OP_NO_RENEGOTIATION) != SSL_OP_NO_RENEGOTIATION)
> + ssl_err("could not set SSL_OP_NO_RENEGOTIATION");
> +#endif
>   if(!SSL_CTX_use_certificate_file(ctx,c_cert,SSL_FILETYPE_PEM))
>   ssl_path_err("Error setting up SSL_CTX client cert", c_cert);
>   if(!SSL_CTX_use_PrivateKey_file(ctx,c_key,SSL_FILETYPE_PEM))
> 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 12 Sep 2019 11:25:03 -0000
> @@ -1,9 +1,9 @@
> -.TH "NSD" "8" "Mar 25, 2019" "NLnet Labs" "NSD 4.1.27"
> +.TH "NSD" "8" "Aug 19, 2019" "NLnet Labs" "NSD 4.2.2"
>  .\" 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.2.
>  .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 12 Sep 2019 11:25:03 -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 12 Sep 2019 11:25:03 -0000
> @@ -1,4 +1,4 @@
> -.TH "nsd.conf" "5" "Mar 25, 2019" "NLnet Labs" "nsd 4.1.27"
> +.TH "nsd.conf" "5" "Aug 19, 2019" "NLnet Labs" "nsd 4.2.2"
>  .\" Copyright (c) 2001\-2008, NLnet Labs. All rights reserved.
>  .\" See LICENSE for the license.
>  .SH "NAME"
> @@ -149,7 +149,7 @@ clause. There may only be one
>  clause.
>  .TP
>  .B ip\-address:\fR <ip4 or ip6>[@port]
> -NSD will bind to the listed ip\-address. Can be give multiple times
> +NSD will bind to the listed ip\-address. Can be given multiple times
>  to bind multiple ip\-addresses. Optionally, a port number can be given.
>  If none are given NSD listens to the wildcard interface. Same as commandline option
>  .BR \-a.
> @@ -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 12 Sep 2019 11:25:03 -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 12 Sep 2019 11:25:03 -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 12 Sep 2019 11:25:03 -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 12 Sep 2019 11:25:03 -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 12 Sep 2019 11:25:03 -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 12 Sep 2019 11:25:03 -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 12 Sep 2019 11:25:03 -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));
> @@ -1039,9 +1173,12 @@ server_prepare(struct nsd *nsd)
>  #else
>   uint32_t v = getpid() ^ time(NULL);
>   srandom((unsigned long)v);
> +#  ifdef HAVE_SSL
>   if(RAND_status() && RAND_bytes((unsigned char*)&v, sizeof(v)) > 0)
>   hash_set_raninit(v);
> - else hash_set_raninit(random());
> + else
> +#  endif
> + hash_set_raninit(random());
>  #endif
>   rrl_mmap_init(nsd->child_count, nsd->options->rrl_size,
>   nsd->options->rrl_ratelimit,
> @@ -1149,6 +1286,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 +1520,306 @@ 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(SSL_OP_NO_RENEGOTIATION)
> + /* disable client renegotiation */
> + if((SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION) &
> + SSL_OP_NO_RENEGOTIATION) != SSL_OP_NO_RENEGOTIATION) {
> + log_crypto_err("could not set SSL_OP_NO_RENEGOTIATION");
> + 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 +2547,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 +2602,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 +2628,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 +2702,7 @@ server_child(struct nsd *nsd)
>   }
>   }
>  
> + service_remaining_tcp(nsd);
>  #ifdef BIND8_STATS
>   bind8_stats(nsd);
>  #endif /* BIND8_STATS */
> @@ -2261,6 +2717,114 @@ 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;
> + }
> + }
> +#ifdef MEMCLEAN
> + event_base_free(event_base);
> +#endif
> + /* 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 +3116,48 @@ handle_udp(int fd, short event, void* ar
>  }
>  #endif /* defined(HAVE_SENDMMSG) && !defined(NONBLOCKING_IS_BROKEN) && defined(HAVE_RECVMMSG) */
>  
> +#ifdef HAVE_SSL
> +/*
> + * 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");
> +}
> +#endif /* HAVE_SSL */
>  
>  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 +3193,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 +3370,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 +3391,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 +3524,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 +3556,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 +3565,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 +3998,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 +4029,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 +4045,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 +4068,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 +4092,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 +4110,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 +4127,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 +4162,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 +4255,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: tsig.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/nsd/tsig.c,v
> retrieving revision 1.5
> diff -u -p -r1.5 tsig.c
> --- tsig.c 30 Jul 2018 08:57:09 -0000 1.5
> +++ tsig.c 12 Sep 2019 11:25:03 -0000
> @@ -19,6 +19,61 @@
>  #include "query.h"
>  #include "rbtree.h"
>  
> +#ifndef HAVE_SSL
> +/* we need fixed time compare */
> +#define CRYPTO_memcmp memcmp_fixedtime
> +int memcmp_fixedtime(const void *s1, const void *s2, size_t n)
> +{
> + size_t i;
> + const uint8_t* u1 = (const uint8_t*)s1;
> + const uint8_t* u2 = (const uint8_t*)s2;
> + int ret = 0, haveit = 0, bret = 0, bhaveit = 0;
> + /* this routine loops for every byte in the strings.
> + * every loop, it tests ==, < and >.  All three.  One succeeds,
> + * as every time it must be equal, smaller or larger.  The one
> + * that succeeds has one if-comparison and two assignments. */
> + for(i=0; i<n; i++) {
> + if(u1[i] == u2[i]) {
> + /* waste time equal to < and > statements */
> + if(haveit) {
> + bret = -1; /* waste time */
> + bhaveit = 1;
> + } else {
> + bret = 1; /* waste time */
> + bhaveit = 1;
> + }
> + }
> + if(u1[i] < u2[i]) {
> + if(haveit) {
> + bret = -1; /* waste time equal to the else */
> + bhaveit = 1;
> + } else {
> + ret = -1;
> + haveit = 1;
> + }
> + }
> + if(u1[i] > u2[i]) {
> + if(haveit) {
> + bret = 1; /* waste time equal to the else */
> + bhaveit = 1;
> + } else {
> + ret = 1;
> + haveit = 1;
> + }
> + }
> + }
> + /* use the variables to stop the compiler from excluding them */
> + if(bhaveit) {
> + if(bret == -2)
> + ret = 0; /* never happens */
> + } else {
> + if(bret == -2)
> + ret = 0; /* never happens */
> + }
> + return ret;
> +}
> +#endif
> +
>  static region_type *tsig_region;
>  
>  struct tsig_key_table
> 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 12 Sep 2019 11:25:03 -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 12 Sep 2019 11:25:03 -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-disk.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/nsd/xfrd-disk.c,v
> retrieving revision 1.12
> diff -u -p -r1.12 xfrd-disk.c
> --- xfrd-disk.c 17 May 2018 18:58:40 -0000 1.12
> +++ xfrd-disk.c 12 Sep 2019 11:25:03 -0000
> @@ -289,6 +289,13 @@ xfrd_read_state(struct xfrd_state* xfrd)
>   zone->state = xfrd_zone_refreshing;
>   xfrd_set_refresh_now(zone);
>   }
> + if(timeout != 0 && filetime + timeout < (uint32_t)xfrd_time()) {
> + /* timeout is in the past, refresh the zone */
> + timeout = 0;
> + if(zone->state == xfrd_zone_ok)
> + zone->state = xfrd_zone_refreshing;
> + xfrd_set_refresh_now(zone);
> + }
>  
>   /* There is a soa && current time is past expiry point */
>   if(soa_disk_acquired_read!=0 &&
> 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 12 Sep 2019 11:25:03 -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 12 Sep 2019 11:25:03 -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 12 Sep 2019 11:25:03 -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)
> @@ -400,6 +402,8 @@ xfrd_shutdown()
>   xfrd_del_tempdir(xfrd->nsd);
>  #ifdef HAVE_SSL
>   daemon_remote_delete(xfrd->nsd->rc); /* ssl-delete secret keys */
> + if (xfrd->nsd->tls_ctx)
> + SSL_CTX_free(xfrd->nsd->tls_ctx);
>  #endif
>  #ifdef USE_DNSTAP
>   dt_collector_close(nsd.dt_collector, &nsd);
> @@ -1038,6 +1042,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 +1180,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 +1207,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 +1331,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 +2225,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 +2577,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 12 Sep 2019 11:25:03 -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 12 Sep 2019 11:25:03 -0000
> @@ -1409,8 +1409,10 @@ process_rr(void)
>   assert(zone);
>   if (rr->type == TYPE_SOA) {
>   if (rr->owner != zone->apex) {
> + char s[MAXDOMAINLEN*5];
> + snprintf(s, sizeof(s), "%s", domain_to_string(zone->apex));
>   zc_error_prev_line(
> - "SOA record with invalid domain name");
> + "SOA record with invalid domain name, '%s' is not '%s'", domain_to_string(rr->owner), s);
>   return 0;
>   }
>   if(has_soa(rr->owner)) {
> @@ -1425,10 +1427,12 @@ process_rr(void)
>  
>   if (!domain_is_subdomain(rr->owner, zone->apex))
>   {
> + char s[MAXDOMAINLEN*5];
> + snprintf(s, sizeof(s), "%s", domain_to_string(zone->apex));
>   if(zone_is_slave(zone->opts))
> - zc_warning_prev_line("out of zone data");
> + zc_warning_prev_line("out of zone data: %s is outside the zone for fqdn %s", domain_to_string(rr->owner), s);
>   else
> - zc_error_prev_line("out of zone data");
> + zc_error_prev_line("out of zone data: %s is outside the zone for fqdn %s", domain_to_string(rr->owner), s);
>   return 0;
>   }
>  
> @@ -1464,6 +1468,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) {
> @@ -1731,4 +1745,33 @@ zonec_parse_string(region_type* region,
>   zonec_desetup_string_parser();
>   parser_flush();
>   return errors;
> +}
> +
> +/** check SSHFP type for failures and emit warnings */
> +void check_sshfp(void)
> +{
> + uint8_t hash;
> + uint16_t size;
> + if(parser->current_rr.rdata_count < 3)
> + return; /* cannot check it, too few rdata elements */
> + if(!parser->current_rr.rdatas[0].data ||
> + !parser->current_rr.rdatas[1].data ||
> + !parser->current_rr.rdatas[2].data ||
> + !parser->current_rr.owner)
> + return; /* cannot check, NULLs (due to earlier errors) */
> + if(rdata_atom_size(parser->current_rr.rdatas[1]) != 1)
> + return; /* wrong size of the hash type rdata element */
> + hash = rdata_atom_data(parser->current_rr.rdatas[1])[0];
> + size = rdata_atom_size(parser->current_rr.rdatas[2]);
> + if(hash == 1 && size != 20) {
> + zc_warning_prev_line("SSHFP %s of type SHA1 has hash of "
> + "wrong length, %d bytes, should be 20",
> + domain_to_string(parser->current_rr.owner),
> + (int)size);
> + } else if(hash == 2 && size != 32) {
> + zc_warning_prev_line("SSHFP %s of type SHA256 has hash of "
> + "wrong length, %d bytes, should be 32",
> + domain_to_string(parser->current_rr.owner),
> + (int)size);
> + }
>  }
> 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 12 Sep 2019 11:25:03 -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;
> @@ -143,5 +142,7 @@ unsigned int zonec_read(const char *name
>   * The string must end with a newline after the RR. */
>  int zonec_parse_string(region_type* region, domain_table_type* domains,
>   zone_type* zone, char* str, domain_type** parsed, int* num_rrs);
> +/** check SSHFP type for failures and emit warnings */
> +void check_sshfp(void);
>  
>  #endif /* _ZONEC_H_ */
> 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 12 Sep 2019 11:25:03 -0000
> @@ -633,7 +633,7 @@ type_and_rdata:
>      | T_DLV sp rdata_dlv { if (dlv_warn) { dlv_warn = 0; zc_warning_prev_line("DLV is experimental"); } }
>      | T_DLV sp rdata_unknown { if (dlv_warn) { dlv_warn = 0; zc_warning_prev_line("DLV is experimental"); } $$ = $1; parse_unknown_rdata($1, $3); }
>      | T_SSHFP sp rdata_sshfp
> -    | T_SSHFP sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
> +    | T_SSHFP sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); check_sshfp(); }
>      | T_RRSIG sp rdata_rrsig
>      | T_RRSIG sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
>      | T_NSEC sp rdata_nsec
> @@ -906,6 +906,7 @@ rdata_sshfp: STR sp STR sp str_sp_seq tr
>      zadd_rdata_wireformat(zparser_conv_byte(parser->region, $1.str)); /* alg */
>      zadd_rdata_wireformat(zparser_conv_byte(parser->region, $3.str)); /* fp type */
>      zadd_rdata_wireformat(zparser_conv_hex(parser->region, $5.str, $5.len)); /* hash */
> +    check_sshfp();
>      }
>      ;
>  
> @@ -1020,6 +1021,10 @@ rdata_ipsec_base: STR sp STR sp STR sp d
>   if(parser->origin == error_domain) {
>       zc_error("cannot concatenate origin to domain name, because origin failed to parse");
>   break;
> + } else if(name->name_size + domain_dname(parser->origin)->name_size - 1 > MAXDOMAINLEN) {
> + zc_error("ipsec gateway name exceeds %d character limit",
> + MAXDOMAINLEN);
> + break;
>   }
>   name = dname_concatenate(parser->rr_region, name,
>   domain_dname(parser->origin));
> @@ -1157,7 +1162,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 +1185,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;
>


--
I'm not entirely sure you are real.