Subject: [dns-privacy] Still interested in recursive-to-authoritative

From: "Paul Hoffman" <[email-masked]>
Date: Wed, 16 May 2018 13:03:36 -0700

While we wait for the charter update, I'd still like to find out who is 
interested in pursuing draft-bortzmeyer-dprive-resolver-to-auth. 
Personally, I think it is a good start on an important topic, but I 
don't hear others supporting it on the list...

--Paul Hoffman

---

From: Stephen Farrell <[email-masked]>
Date: Wed, 16 May 2018 21:06:05 +0100

> don't hear others supporting it on the list...

I do. But I don't implement a recursive or run a large
authoritative. I do run some teeny-weeny authoritative
servers, and would definitely deploy on those whenever
possible.

S.

> 
> --Paul Hoffman
> 
> _______________________________________________
> dns-privacy mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/dns-privacy
>

---

From: Gene Hightower <[email-masked]>
Date: Wed, 16 May 2018 14:03:41 -0700

On 2018-05-16 13:03, Paul Hoffman wrote:

> […] I'd still like to find out who is interested in pursuing
> draft-bortzmeyer-dprive-resolver-to-auth.

I am.

Of course, I am just some guy; not a mover or shaker in any sense.

I can write C code and would be willing to contribute to any FLOSS
resolvers to support this.

---

From: "A. Schulze" <[email-masked]>
Date: Thu, 17 May 2018 09:12:51 +0200

> resolvers to support this.

me too.

since IETF 101 Hackathon my nameservers do answer on 853 and support
the features mentioned at  
https://github.com/andreasschulze/openssl-demo-server

Andreas

---

From: Tony Finch <[email-masked]>
Date: Thu, 17 May 2018 12:46:38 +0100

> interested in pursuing draft-bortzmeyer-dprive-resolver-to-auth.

Me!

Tony.
-- 
f.anthony.n.finch  <[email-masked]>  http://dotat.at/
North Utsire, South Utsire: Northwesterly 5 to 7, decreasing 4 later. Moderate
or rough. Fair. Good.

---

From: Sara Dickinson <[email-masked]>
Date: Thu, 17 May 2018 16:07:04 +0200

> On 17 May 2018, at 13:46, Tony Finch <[email-masked]> wrote:
> 

+1

Sara.

---

From: Warren Kumari <[email-masked]>
Date: Thu, 17 May 2018 16:24:17 +0200

Me too, but I don't know if my views count,
Wy

-- 
I don't think the execution is relevant when it was obviously a bad idea in
the first place.
This is like putting rabid weasels in your pants, and later expressing
regret at having chosen those particular rabid weasels and that pair of
pants.
    ---maf

---

From: Ian Maddison <[email-masked]>
Date: Thu, 17 May 2018 18:43:47 +0200

On Thu, 17 May 2018, Warren Kumari wrote:
>>>> While we wait for the charter update, I'd still like to find out
>>>> who is>>>> interested in pursuing draft-bortzmeyer-dprive-resolver-to-auth.
>>> 
>>> Me!
> Me too, but I don't know if my views count

Moi aussi...

---

From: Ask Bjørn Hansen <[email-masked]>
Date: Thu, 17 May 2018 09:44:18 -0700

> On May 16, 2018, at 13:03 , Paul Hoffman <[email-masked]> wrote:
> 
> While we wait for the charter update, I'd still like to find out who is interested in pursuing draft-bortzmeyer-dprive-resolver-to-auth.

I am interested, too.  (And would push to deploy it on the domains I have influence on).

Ask

---

From: James Cloos <[email-masked]>
Date: Thu, 17 May 2018 15:03:51 -0400

I also would like to see this discussed here and the result deployed.

-JimC
-- 
James Cloos <[email-masked]>         OpenPGP: 0x997A9F17ED7DAEA6

---

From: Bill Woodcock <[email-masked]>
Date: Fri, 18 May 2018 04:03:05 +0200

>> interested in pursuing draft-bortzmeyer-dprive-resolver-to-auth.

We (PCH and Quad9) strongly support it.

                                -Bill

---

From: Brian Haberman <[email-masked]>
Date: Fri, 18 May 2018 09:21:17 -0400

Hi All,

> don't hear others supporting it on the list...

First, thanks to Paul for starting this query. The list has been quite
silent since the London meeting.

Second, thanks to all the folks who have chimed in voicing support for
an existing document.

What I will ask now is that those who are interested in the current
draft to start providing detailed reviews of the draft to see if we can
find some consensus on the approach. It is critical that these reviews
come from both an implementation and an operational/deployment point of
view.

Regards,
Brian

---

From: Bill Woodcock <[email-masked]>
Date: Fri, 18 May 2018 19:25:28 +0200

Speaking again for PCH and Quad9, we have, and the current draft incorporates our views. 

                -Bill

> On May 18, 2018, at 15:21, Brian Haberman <[email-masked]> wrote:
> 
> Hi All,
>

---

From: James Cloos <[email-masked]>
Date: Fri, 18 May 2018 14:25:25 -0400

>>>>> "BH" == Brian Haberman <[email-masked]> writes:

BH> What I will ask now is that those who are interested in the current
BH> draft to start providing detailed reviews ...

The draft asks whether tls 1.3 should be the minimum version.

It would be better for this document to specify >= 1.2.  It will be much
easier in the short term to add 1.2 support to existing machines than 1.3
and that would allow much more real testing during the draft state.

The draft's choice to use DANE to authenticate the auth server seems to
be the best option available.  That it cannot be spoofed w/o altering
the parent zone's DS RR is suficient.

The happy eyeballs reference looks to be the right thing to do.

The draft states:

> If it is a concern that the same authoritative name servers are used
> for ordinary DNS and for encrypted DNS,

I don't know that should be, but if so it probably should discuss why
some may find it to be a concern.

I think we should discuss whether an EDNS option to signal a successful
authentication or failure really is out of scope, as the draft says.

The strict vs opportunistic paragraph looks exactly right.

I'll let those with more time review whether any of the references need
updating.

-JimC

---

From: Gene Hightower <[email-masked]>
Date: Wed, 16 May 2018 13:55:43 -0700

I am.

---

From: Sara Dickinson <[email-masked]>
Date: Wed, 23 May 2018 17:28:14 +0100

> On 16 May 2018, at 21:55, Gene Hightower <[email-masked]> wrote:
> 

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.

Sara.

---

From: "A. Schulze" <[email-masked]>
Date: Wed, 23 May 2018 22:56:40 +0200

> 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);

---

From: Lanlan Pan <[email-masked]>
Date: Thu, 24 May 2018 13:12:21 -0500

Support, :-)

*”Encryption does not protect against a rogue server that will capture you
requests and use them for evil purposes.It must therefore be combined with
data minimization techniques.“*

-- 
致礼  Best Regards

潘蓝兰  Pan Lanlan

---

From: Sara Dickinson <[email-masked]>
Date: Fri, 25 May 2018 16:08:44 +0100

> On 18 May 2018, at 19:25, James Cloos <[email-masked]> wrote:
> 
> BH> draft to start providing detailed reviews …

I’ve read the draft again - comments below. 

> and that would allow much more real testing during the draft state.

I agree with this. At this stage TLS 1.2 is much more practical and I think just referencing BCP7525 is enough. 

> The happy eyeballs reference looks to be the right thing to do.

Section 3: I’d like to see a bit more discussion around this proposal:
"A resolver working in opportunistic mode should try ports 53 and 853 in parallel.”

I see the obvious latency win here but the downside with this mode (as currently described) is that it _always_ leaks the query in cleartext so it seems to defeat the point of using TLS. Unless the should (SHOULD?) here is allowing for resolver behaviour where it has some cached knowledge of this authoritative's capabilities and so could choose to probe all addresses over 853 before falling back to 53? If so I think that should be spelled out more clearly.

I’d always seen opportunistic as ‘try for the best but be willing to fallback to the worst case’ which isn’t exactly the same as ‘happy eyeballs’ which I see as try everything in parallel? 

> some may find it to be a concern.

Is this related to the monitoring/data retention/privacy policies by the operator?  In other words that the concern is they treat all the data as if it were unencrypted….

> authentication or failure really is out of scope, as the draft says.

Interesting yes, but rogue or broken clients could easily send false responses so I’m unsure of how useful this is? What would the specific use case be?

One other comment - in RFC8310 there is discussion of the possible attacks on meta queries (used here to obtain the TLSA records) - it seems the same concerns apply here too and should be mentioned in the Security Considerations?

Regards

Sara.

---

From: Ted Hardie <[email-masked]>
Date: Fri, 25 May 2018 10:18:30 -0700

> "A resolver working in opportunistic mode should try ports 53 and 853 in
In addition to the privacy concern that Sara makes below (and with which I
agree), it's actually not what the current specification of Happy Eyballs
says.  RFC 8305 says instead:

   Once the list of addresses received up to this point has been
   constructed, the client will attempt to make connections.  In order
   to avoid unreasonable network load, connection attempts SHOULD NOT be
   made simultaneously.

Presuming we treat the "address" here as a tuple of IP address and port and
give a preference for 853 in the sorting algorithm, you'd end up starting
with it and then going to 53 only after the default delay expired.

I think that's better than concurrent attempts on several fronts.

regards,

Ted

> I see the obvious latency win here but the downside with this mode (as
> currently described) is that it _always_ leaks the query in cleartext so it
> seems to defeat the point of using TLS. Unless the should (SHOULD?) here is
> allowing for resolver behaviour where it has some cached knowledge of this
> authoritative's capabilities and so could choose to probe all addresses
> over 853 before falling back to 53? If so I think that should be spelled
> out more clearly.
>
> I’d always seen opportunistic as ‘try for the best but be willing to
> fallback to the worst case’ which isn’t exactly the same as ‘happy
> eyeballs’ which I see as try everything in parallel?
>
> >
> > The draft states:
> >
> Is this related to the monitoring/data retention/privacy policies by the
> operator?  In other words that the concern is they treat all the data as if
> it were unencrypted….
>
> >
> Interesting yes, but rogue or broken clients could easily send false
> responses so I’m unsure of how useful this is? What would the specific use
> case be?
>
>
> One other comment - in RFC8310 there is discussion of the possible attacks
> on meta queries (used here to obtain the TLSA records) - it seems the same
> concerns apply here too and should be mentioned in the Security
> Considerations?
>
> Regards
>
> Sara.
>
>
>
>

---

From: James Cloos <[email-masked]>
Date: Fri, 25 May 2018 18:13:47 -0400

>>>>> "SD" == Sara Dickinson <[email-masked]> writes:

>>>>>>> "BH" == Brian Haberman <[email-masked]> writes:

JC>> The happy eyeballs reference looks to be the right thing to do.

SD> Section 3: I’d like to see a bit more discussion around this proposal:
SD> "A resolver working in opportunistic mode should try ports 53 and 853 in parallel.”

SD> I see the obvious latency win here but the downside with this mode (as
SD> currently described) is that it _always_ leaks the query in cleartext
SD> so it seems to defeat the point of using TLS.

I read thru my reply again, and I think this was the only point I didn't
properly consider.  But testing shows that a short timeout is required
to ensure that auth's which do not support 853 do not dos resolvers
which try it.

-JimC