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 <[email protected]>.
> #
> @@ -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='[email protected]'
> 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,[email protected])
> +AC_INIT(NSD,4.2.2,[email protected])
> 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.