Am 23.05.2018 um 18:28 schrieb Sara Dickinson:
> We did create a basic patch back in 2015 to add TLS to NSD - it can be found 
> here:
> https://portal.sinodun.com/stash/projects/TDNS/repos/dns-over-tls_patches/browse
> 
> I’ve been meaning to work on porting this to the latest NSD for a while now 
> but if anyone else wants to take a look at this then feel free.

Hello Sara,

the attached version work with the latest NSD 4.1.21.
It compiles and nsd run for a very first test here.

But as the patch was manually re-applied diff by diff I'm not sure I've done 
everything right.
Wouter will have more "context" at the patched code paths. Review is required.

Anyway: thanks for pointing to that work, Sara!

Andreas
Index: nsd-4.1.21/config.h.in
===================================================================
--- nsd-4.1.21.orig/config.h.in
+++ nsd-4.1.21/config.h.in
@@ -529,6 +529,9 @@
 /* Define this to enable per-zone statistics gathering. */
 #undef USE_ZONE_STATS
 
+/* Define this to enable TCP fast open. */
+#undef USE_TCP_FASTOPEN
+
 /* Define to the NSD version to answer version.server query. */
 #undef VERSION
 
Index: nsd-4.1.21/configlexer.lex
===================================================================
--- nsd-4.1.21.orig/configlexer.lex
+++ nsd-4.1.21/configlexer.lex
@@ -282,6 +282,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-pem{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_SERVICE_PEM;}
+tls-port{COLON}        { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_PORT;}
+do-starttls{COLON}     { LEXOUT(("v(%s) ", yytext)); return VAR_DO_STARTTLS;}
 {NEWLINE}		{ LEXOUT(("NL\n")); cfg_parser->line++;}
 
 	/* Quoted strings. Strip leading and ending quotes */
Index: nsd-4.1.21/configparser.y
===================================================================
--- nsd-4.1.21.orig/configparser.y
+++ nsd-4.1.21/configparser.y
@@ -72,6 +72,7 @@ extern config_parser_state_type* cfg_par
 %token VAR_MAX_REFRESH_TIME VAR_MIN_REFRESH_TIME
 %token VAR_MAX_RETRY_TIME VAR_MIN_RETRY_TIME
 %token VAR_MULTI_MASTER_CHECK VAR_MINIMAL_RESPONSES VAR_REFUSE_ANY
+%token VAR_TLS_SERVICE_KEY VAR_TLS_SERVICE_PEM VAR_TLS_PORT VAR_DO_STARTTLS
 
 %%
 toplevelvars: /* empty */ | toplevelvars toplevelvar ;
@@ -103,7 +104,8 @@ 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_minimal_responses | server_refuse_any |
+	server_tls_service_key | server_tls_service_pem | server_tls_port | server_do_starttls;
 server_ip_address: VAR_IP_ADDRESS STRING 
 	{ 
 		OUTYY(("P(server_ip_address:%s)\n", $2)); 
@@ -521,6 +523,32 @@ server_zonefiles_write: VAR_ZONEFILES_WR
 	}
 	;
 
+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_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);
+       }
+       ;
+server_do_starttls: VAR_DO_STARTTLS STRING
+       {
+               OUTYY(("P(server_do_starttls:%s)\n", $2));
+               if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+                       yyerror("expected yes or no.");
+               else cfg_parser->opt->do_starttls = (strcmp($2, "yes")==0);
+       }
+       ;
 rcstart: VAR_REMOTE_CONTROL
 	{
 		OUTYY(("\nP(remote-control:)\n"));
Index: nsd-4.1.21/configure.ac
===================================================================
--- nsd-4.1.21.orig/configure.ac
+++ nsd-4.1.21/configure.ac
@@ -841,6 +841,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]))
@@ -899,6 +900,32 @@ case "$enable_packed" in
 	;;
 esac
 
+AC_ARG_ENABLE(TObit, AC_HELP_STRING([--enable-TObit], [(Experimental) Enables TO bit during STARTTLS negotiation. NOTE WELL: The TO bit is NOT assigned by IANA - USE FOR TESTING ONLY! DO NOT DEPLOY TO PRODUCTION ENVIRONMENTS!]))
+case "$enable_TObit" in
+       yes)
+       if test x$HAVE_SSL = x"yes"; then
+               AC_DEFINE_UNQUOTED([USE_TO_BIT], [], [Define this to enable use of the TO bit.])
+       else
+               AC_MSG_WARN([No SSL, therefore TO bit is disabled])
+       fi
+               ;;
+       no|*)
+               ;;
+esac
+
+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)) \
Index: nsd-4.1.21/doc/ChangeLog
===================================================================
--- nsd-4.1.21.orig/doc/ChangeLog
+++ nsd-4.1.21/doc/ChangeLog
@@ -1,3 +1,8 @@
+23 May 2018: Andreas via Sara
+	- Patch to add support for experimental STARTTLS implementation
+	- Patch to add support for experimental TCP Fast Open
+	- Patch to add support for tls service on a specified tls port
+
 7 May 2018: Wouter
 	- Tag for 4.1.21rc1 release.
 
Index: nsd-4.1.21/edns.c
===================================================================
--- nsd-4.1.21.orig/edns.c
+++ nsd-4.1.21/edns.c
@@ -57,6 +57,9 @@ edns_init_record(edns_record_type *edns)
 	edns->maxlen = 0;
 	edns->opt_reserved_space = 0;
 	edns->dnssec_ok = 0;
+#ifdef USE_TO_BIT
+	edns->tls_ok = 0;
+#endif
 	edns->nsid = 0;
 }
 
@@ -146,6 +149,9 @@ edns_parse_record(edns_record_type *edns
 	edns->status = EDNS_OK;
 	edns->maxlen = opt_class;
 	edns->dnssec_ok = opt_flags & DNSSEC_OK_MASK;
+#ifdef USE_TO_BIT
+	edns->tls_ok = opt_flags & TLS_OK_MASK;
+#endif
 	return 1;
 }
 
Index: nsd-4.1.21/edns.h
===================================================================
--- nsd-4.1.21.orig/edns.h
+++ nsd-4.1.21/edns.h
@@ -19,6 +19,10 @@ struct query;
 #define OPT_HDR 4U                      /* NSID opt header length */
 #define NSID_CODE       3               /* nsid option code */
 #define DNSSEC_OK_MASK  0x8000U         /* do bit mask */
+#ifdef USE_TO_BIT
+#define TLS_OK_MASK  0x4000U            /* to bit mask */
+#endif
+
 
 struct edns_data
 {
Index: nsd-4.1.21/nsd-checkconf.c
===================================================================
--- nsd-4.1.21.orig/nsd-checkconf.c
+++ nsd-4.1.21/nsd-checkconf.c
@@ -370,6 +370,7 @@ config_print_zone(nsd_options_type* opt,
 		SERV_GET_BIN(round_robin, o);
 		SERV_GET_BIN(minimal_responses, o);
 		SERV_GET_BIN(refuse_any, o);
+		SERV_GET_BIN(do_starttls, o);
 		/* str */
 		SERV_GET_PATH(final, database, o);
 		SERV_GET_STR(identity, o);
@@ -384,6 +385,9 @@ 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_pem, o);
+		SERV_GET_STR(tls_port, o);
 		/* int */
 		SERV_GET_INT(server_count, o);
 		SERV_GET_INT(tcp_count, o);
@@ -525,6 +529,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-port:", opt->tls_port);
+	printf("\tdo_starttls: %s\n", opt->do_starttls?"yes":"no");
 
 	printf("\nremote-control:\n");
 	printf("\tcontrol-enable: %s\n", opt->control_enable?"yes":"no");
Index: nsd-4.1.21/nsd.c
===================================================================
--- nsd-4.1.21.orig/nsd.c
+++ nsd-4.1.21/nsd.c
@@ -692,6 +692,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)
 	{
@@ -978,6 +981,13 @@ main(int argc, char *argv[])
 		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)))
+			error("could not set up tls SSL_CTX");
+		if (nsd.options->do_starttls)
+			log_msg(LOG_NOTICE, "STARTTLS enabled");
+	}
 #endif /* HAVE_SSL */
 
 	/* Unless we're debugging, fork... */
Index: nsd-4.1.21/nsd.conf.5.in
===================================================================
--- nsd-4.1.21.orig/nsd.conf.5.in
+++ nsd-4.1.21/nsd.conf.5.in
@@ -435,6 +435,26 @@ 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 its TCP sockets.
+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). Normal DNS TCP service is not provided and gives
+errors, this service is best run with a different port: config or @port suffixes in the
+interface config.
+.TP
+.B tls\-service\-pem:\fR <filename>
+The public key certificate pem file for the tls service. Default is "", turned off.
+.TP
+.B tls\-port:\fR <number>
+The port number on which to provide TCP TLS service, default is turned off, only
+interfaces configured with that port number as @number get the TLS service.
+.TP
+.B do\-starttls:\fR <yes or no>
+Allow upgrade to TLS on regular TCP connections via STARTTLS.
+Uses the tls\-service\-key and tls\-service\-pem for the key and certificate.
 .SS "Remote Control"
 The
 .B remote\-control:
Index: nsd-4.1.21/nsd.conf.sample.in
===================================================================
--- nsd-4.1.21.orig/nsd.conf.sample.in
+++ nsd-4.1.21/nsd.conf.sample.in
@@ -177,6 +177,16 @@ server:
 	# rrl-whitelist-ratelimit: 2000
 	# RRLend
 
+	# 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-port: <port-number>
+
+	# Do we allow tls upgrade on tcp connections after STARTTLS?
+	# do-starttls
+
 # Remote control config section. 
 remote-control:
 	# Enable remote control with nsd-control(8) here.
Index: nsd-4.1.21/nsd.h
===================================================================
--- nsd-4.1.21.orig/nsd.h
+++ nsd-4.1.21/nsd.h
@@ -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"
@@ -266,6 +269,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;
@@ -301,6 +309,9 @@ 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_create(struct nsd *nsd, char* verifypem);
+#endif
 ssize_t block_read(struct nsd* nsd, int s, void* p, ssize_t sz, int timeout);
 
 #endif	/* _NSD_H_ */
Index: nsd-4.1.21/options.c
===================================================================
--- nsd-4.1.21.orig/options.c
+++ nsd-4.1.21/options.c
@@ -103,6 +103,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_pem = NULL;
+	opt->tls_port = NULL;
+	opt->do_starttls = 0;
 	opt->control_enable = 0;
 	opt->control_interface = NULL;
 	opt->control_port = NSD_CONTROL_PORT;
Index: nsd-4.1.21/options.h
===================================================================
--- nsd-4.1.21.orig/options.h
+++ nsd-4.1.21/options.h
@@ -97,6 +97,15 @@ struct nsd_options {
 	int refuse_any;
 	int reuseport;
 
+	/* private key file for TLS */
+	char* tls_service_key;
+	/* certificate file for TLS */
+	char* tls_service_pem;
+	/* TLS dedicated port */
+	const char* tls_port;
+	/* Allow upgrade to TLS after STARTTLS negotiation*/
+	int do_starttls;
+
         /** remote control section. enable toggle. */
 	int control_enable;
 	/** the interfaces the remote control should listen on */
Index: nsd-4.1.21/query.c
===================================================================
--- nsd-4.1.21.orig/query.c
+++ nsd-4.1.21/query.c
@@ -37,6 +37,11 @@
 #include "nsec3.h"
 #include "tsig.h"
 
+#ifdef HAVE_SSL
+#define STARTTLS_STR "STARTTLS"
+#define NO_TLS_STR   "NO_TLS"
+#endif
+
 /* [Bug #253] Adding unnecessary NS RRset may lead to undesired truncation.
  * This function determines if the final response packet needs the NS RRset
  * included. Currently, it will only return negative if QTYPE == DNSKEY|DS.
@@ -200,6 +205,10 @@ query_create(region_type *region, uint16
 	query->tsig_prepare_it = 1;
 	query->tsig_update_it = 1;
 	query->tsig_sign_it = 1;
+#ifdef HAVE_SSL
+	query->first_query = 1;
+	query->tls_ok = 0;
+#endif
 	return query;
 }
 
@@ -362,6 +371,22 @@ process_edns(nsd_type* nsd, struct query
 #endif
 		}
 
+#ifdef USE_TO_BIT
+	/* Change the value of the tls_ok bit depending on whether or not the
+	 * connection should be upgraded to TLS based on this query. The value is
+	 * used later to trigger the upgrade and also to construct the response.
+	 */
+	if (q->edns.tls_ok) {
+		/* Logs for testing */
+		VERBOSITY(3, (LOG_INFO, "TO bit recieved"));
+		if (!(q->tcp && q->first_query && nsd->tls_ctx
+		    && nsd->options->do_starttls)) {
+			VERBOSITY(3, (LOG_INFO, "TO bit rejected"));
+			q->edns.tls_ok = 0;
+		}
+	}
+#endif
+
 		/* Strip the OPT resource record off... */
 		buffer_set_position(q->packet, q->edns.position);
 		buffer_set_limit(q->packet, q->edns.position);
@@ -553,6 +578,46 @@ answer_chaos(struct nsd *nsd, query_type
 			} else {
 				RCODE_SET(q->packet, RCODE_REFUSE);
 			}
+#ifdef HAVE_SSL
+		} else if (q->qname->name_size == 10
+			   && memcmp(dname_name(q->qname), "\010starttls", 10) == 0) {
+			if (q->tcp) {
+				if (q->first_query) {
+					if (nsd->tls_ctx
+#ifdef USE_TO_BIT
+					    && q->edns.tls_ok
+#endif
+					    && nsd->options->do_starttls ) {
+						/* Add STARTTLS answer */
+						query_addtxt(q,
+							buffer_begin(q->packet) + QHEADERSZ,
+							CLASS_CH,
+							0,
+							STARTTLS_STR);
+						ANCOUNT_SET(q->packet, ANCOUNT(q->packet) + 1);
+						/* Not required if TO bit assigned and used.*/
+						q->tls_ok = 1;
+						/* Logs here are for testing */
+						VERBOSITY(3, (LOG_INFO, "STARTTLS received and sent in response"));
+					} else {
+						/* Add NO_TLS answer */
+						query_addtxt(q,
+							buffer_begin(q->packet) + QHEADERSZ,
+							CLASS_CH,
+							0,
+							NO_TLS_STR);
+						ANCOUNT_SET(q->packet, ANCOUNT(q->packet) + 1);
+						VERBOSITY(3, (LOG_INFO, "STARTTLS received and but NO_TLS sent in response"));
+					}
+				} else {
+					RCODE_SET(q->packet, RCODE_REFUSE);
+					VERBOSITY(3, (LOG_INFO, "STARTTLS ignored as not first query on tcp connection"));
+				}
+			} else {
+				RCODE_SET(q->packet, RCODE_REFUSE);
+			}
+#endif
+		/* Back port of fix in 4.1.1 for noname CH TXT queries */
 		} else {
 			RCODE_SET(q->packet, RCODE_REFUSE);
 		}
@@ -1516,6 +1581,11 @@ query_add_optional(query_type *q, nsd_ty
 	case EDNS_OK:
 		if (q->edns.dnssec_ok)	edns->ok[7] = 0x80;
 		else			edns->ok[7] = 0x00;
+#ifdef USE_TO_BIT
+		if (q->edns.tls_ok) {
+			edns->ok[7] = edns->ok[7] | ((TLS_OK_MASK >> 8) & 0xFF);
+		}
+#endif
 		buffer_write(q->packet, edns->ok, OPT_LEN);
 		if(q->edns.opt_reserved_space == 0 || !buffer_available(
 			q->packet, 2+q->edns.opt_reserved_space)) {
@@ -1539,6 +1609,11 @@ query_add_optional(query_type *q, nsd_ty
 	case EDNS_ERROR:
 		if (q->edns.dnssec_ok)	edns->error[7] = 0x80;
 		else			edns->error[7] = 0x00;
+#ifdef USE_TO_BIT
+		if (q->edns.tls_ok) {
+			edns->ok[7] = edns->ok[7] | ((TLS_OK_MASK >> 8) & 0xFF);
+		}
+#endif
 		buffer_write(q->packet, edns->error, OPT_LEN);
 		buffer_write(q->packet, edns->rdata_none, OPT_RDATA);
 		ARCOUNT_SET(q->packet, ARCOUNT(q->packet) + 1);
Index: nsd-4.1.21/query.h
===================================================================
--- nsd-4.1.21.orig/query.h
+++ nsd-4.1.21/query.h
@@ -63,6 +63,13 @@ struct query {
 
 	int tcp;
 	uint16_t tcplen;
+#ifdef HAVE_SSL
+	int first_query;
+	/* This tls_ok variable is needed for the case where the TO bit is not used
+	 * and upgrade is triggered based only on the STARTTLS query content. It can
+	 * be removed if the TO bit is assigned by IANA and the logic is revised. */
+	int tls_ok;
+#endif
 
 	buffer_type *packet;
 
Index: nsd-4.1.21/server.c
===================================================================
--- nsd-4.1.21.orig/server.c
+++ nsd-4.1.21/server.c
@@ -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,12 @@
 #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
 #ifndef USE_MINI_EVENT
 #  ifdef HAVE_EVENT_H
 #    include <event.h>
@@ -68,6 +77,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.
  */
@@ -83,6 +97,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
 };
 
 /*
@@ -167,6 +185,17 @@ 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 } shake_state;
+#endif
 };
 
 /*
@@ -199,6 +228,29 @@ static void handle_tcp_reading(int fd, s
  */
 static void handle_tcp_writing(int fd, short event, void* arg);
 
+#ifdef HAVE_SSL
+/*Comment*/
+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);
+
+/*
+ * 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.
  */
@@ -221,6 +273,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 kernal 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_ERR,"Error: TCP Fast Open support is available and configure in NSD by default.\n");
+		log_msg(LOG_ERR,"However the kernal paramenters are not configured to support TCP_FASTOPEN in server mode.\n");
+		log_msg(LOG_ERR,"To enable TFO use the command:");
+		log_msg(LOG_ERR,"  'sudo sysctl -w net.ipv4.tcp_fastopen=2' for pure server mode or\n");
+		log_msg(LOG_ERR,"  'sudo sysctl -w net.ipv4.tcp_fastopen=3' for both client and server mode\n");
+		log_msg(LOG_ERR,"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.
@@ -771,6 +851,10 @@ server_init_ifs(struct nsd *nsd, size_t
 
 	/* 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 */
@@ -904,6 +988,13 @@ server_init_ifs(struct nsd *nsd, size_t
 			return -1;
 		}
 
+#ifdef USE_TCP_FASTOPEN
+		int backlog = TCP_BACKLOG;
+		if ((setsockopt(nsd->tcp[i].s, IPPROTO_TCP, TCP_FASTOPEN, &backlog, sizeof(backlog))) == -1 ) {
+			log_msg(LOG_ERR, "Setting TCP Fast Open Failed: %s", strerror(errno));
+		}
+#endif
+
 		/* Listen to it... */
 		if (listen(nsd->tcp[i].s, TCP_BACKLOG) == -1) {
 			log_msg(LOG_ERR, "can't listen: %s", strerror(errno));
@@ -1075,6 +1166,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 */
@@ -1304,6 +1397,98 @@ 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);
+	}
+}
+
+SSL_CTX*
+server_tls_ctx_create(struct nsd* nsd, char* verifypem)
+{
+	char *key, *pem;
+	SSL_CTX *ctx;
+
+	ERR_load_crypto_strings();
+	ERR_load_SSL_strings();
+	OpenSSL_add_all_algorithms();
+	(void)SSL_library_init();
+
+	key = nsd->options->tls_service_key;
+	pem = nsd->options->tls_service_pem;
+
+	/* 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 = SSL_CTX_new(SSLv23_server_method());
+	if(!ctx) {
+		log_crypto_err("could not SSL_CTX_new");
+		return NULL;
+	}
+	/* no SSLv2 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_use_certificate_file(ctx, pem, SSL_FILETYPE_PEM)) {
+		log_msg(LOG_ERR, "error for cert file: %s", pem);
+		log_crypto_err("error in SSL_CTX use_certificate_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;
+	}
+
+	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;
+}
+
+/* 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;
+
+	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)
@@ -2107,6 +2292,15 @@ 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;
+				log_msg(LOG_NOTICE, "setup TCP for TLS service on interface %d", (int)i);
+			}
+			else
+				data->tls_accept = 0;
+#endif
 			event_set(handler, nsd->tcp[i].s, EV_PERSIST|EV_READ,
 				handle_tcp_accept, data);
 			if(event_base_set(event_base, handler) != 0)
@@ -2446,11 +2640,39 @@ handle_udp(int fd, short event, void* ar
 }
 #endif /* defined(HAVE_SENDMMSG) && !defined(NONBLOCKING_IS_BROKEN) && defined(HAVE_RECVMMSG) */
 
+/*
+ * Setup an event for the tcp handler.
+ */
+static void
+tcp_handler_setup_event(struct tcp_handler_data* data, void (*fn)(int, short, void *),
+       int fd, short event)
+{
+	struct timeval timeout;
+	struct event_base* ev_base;
+
+	timeout.tv_sec = data->nsd->tcp_timeout;
+	timeout.tv_usec = 0L;
+
+	ev_base = data->event.ev_base;
+	event_del(&data->event);
+	event_set(&data->event, fd, event, fn, data);
+	if(event_base_set(ev_base, &data->event) != 0)
+		log_msg(LOG_ERR, "event base set failed");
+	if(event_add(&data->event, &timeout) != 0)
+		log_msg(LOG_ERR, "event add failed");
+}
 
 static void
 cleanup_tcp_handler(struct tcp_handler_data* data)
 {
 	event_del(&data->event);
+#ifdef HAVE_SSL
+	if(data->tls) {
+		SSL_shutdown(data->tls);
+		SSL_free(data->tls);
+		data->tls = NULL;
+	}
+#endif
 	close(data->event.ev_fd);
 
 	/*
@@ -2667,8 +2889,29 @@ 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);
+#ifdef HAVE_SSL
+	data->query->first_query = 0;
+#ifdef USE_TO_BIT
+	if (data->nsd->tls_ctx && data->query->edns.tls_ok) {
+#else
+	if (data->nsd->tls_ctx && data->query->tls_ok) {
+#endif
+		data->tls = incoming_ssl_fd(data->nsd->tls_ctx, fd);
+		if(!data->tls) {
+			close(fd);
+			return;
+		}
+		data->shake_state = tls_hs_read;
+		event_set(&data->event, fd, EV_PERSIST | EV_READ | EV_TIMEOUT,
+			  handle_tls_reading, data);
+		data->query_state = QUERY_PROCESSED;
+	} else {
+#endif
+		event_set(&data->event, fd, EV_PERSIST | EV_READ | EV_TIMEOUT,
+			handle_tcp_reading, data);
+#ifdef HAVE_SSL
+	}
+#endif
 	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)
@@ -2838,6 +3081,378 @@ 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 r;
+
+	/* (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)
+				log_msg(LOG_ERR, "connection closed prematurely");
+			cleanup_tcp_handler(data);
+			log_msg(LOG_ERR, "TLS failed");
+			return 0;
+		}
+	}
+
+	/* Use to log successful upgrade for testing - could be removed*/
+	VERBOSITY(3, (LOG_INFO, "TLS handshake succeeded."));
+	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))
+			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;
+				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;
+			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, ctcp);
+#else
+	if (data->query->addr.ss_family == AF_INET) {
+		STATUP(data->nsd, ctcp);
+	} else if (data->query->addr.ss_family == AF_INET6) {
+		STATUP(data->nsd, ctcp6);
+	}
+#endif
+
+	/* We have a complete query, process it.  */
+
+	/* tcp-query-count: handle query counter ++ */
+	data->query_count++;
+
+	buffer_flip(data->query->packet);
+	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);
+		cleanup_tcp_handler(data);
+		return;
+	}
+
+	if (RCODE(data->query->packet) == RCODE_OK
+	    && !AA(data->query->packet))
+	{
+		STATUP(data->nsd, nona);
+	}
+
+	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);
+	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;
+	buffer_type* write_buffer;
+	region_type* region;
+
+	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))
+			return;
+		if(data->shake_state != tls_hs_none)
+			return;
+	}
+
+	(void)SSL_set_mode(data->tls, SSL_MODE_ENABLE_PARTIAL_WRITE);
+
+	/* If we are writng the start of a message, we must include the length
+	 * For now, create a new buffer with the length prepended. This is very
+	 * inefficient and should be optimised. This could be done best by creating
+	 * a wrapper for the underlying message buffer.*/
+	write_buffer = NULL;
+	region = NULL;
+	if (data->bytes_transmitted == 0) {
+		region = region_create(xalloc, free);
+		write_buffer = buffer_create(region, buffer_limit(q->packet) + sizeof(q->tcplen));
+		if (!write_buffer) {
+			return;
+		}
+		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;
+			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");
+		}
+		if (data->bytes_transmitted == 0 && write_buffer != NULL) {
+			region_destroy(region);
+		}
+		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 > sizeof(q->tcplen)) {
+			buffer_skip(q->packet, (ssize_t)sent - sizeof(q->tcplen));
+		}
+	}
+
+	if (data->bytes_transmitted == 0 && write_buffer != NULL)
+		region_destroy(region);
+
+	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;
+	data->query->first_query = 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),
@@ -2949,8 +3564,23 @@ handle_tcp_accept(int fd, short event, v
 	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;
+		event_set(&tcp_data->event, s, EV_PERSIST | EV_READ | EV_TIMEOUT,
+			  handle_tls_reading, tcp_data);
+	} else {
+#endif
+		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);
_______________________________________________
dns-privacy mailing list
[email protected]
https://www.ietf.org/mailman/listinfo/dns-privacy

Reply via email to