Re: DoT on the Auth side?

"A. Schulze" <[email protected]>
Newsgroups gmane.network.dns.nsd.general
Message-ID <[email protected]>

Am 15.03.19 um 11:10 schrieb Anand Buddhdev:
> DoT is most useful between stub resolvers and their upstream recursive
> resolvers, because this is the path that is most often snooped and
> mangled by men-in-the-middle.

it's correct. DoT between resolver and authoritative DNS servers is not finally specified.
But there is desire to use similar technology.

Attached a patch that enable TLS support in unbound. I'm currently unsure about the author (not my self)
Maybe the maintainer like to give that patch a chance.

Andreas

_______________________________________________
nsd-users mailing list
[email protected]
https://open.nlnetlabs.nl/mailman/listinfo/nsd-users
nsd-tls-4.1.26.patch (text/x-patch, 38.8 KB)
Index: nsd-4.1.26/config.h.in
===================================================================
--- nsd-4.1.26.orig/config.h.in
+++ nsd-4.1.26/config.h.in
@@ -550,6 +550,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.26/configlexer.lex
===================================================================
--- nsd-4.1.26.orig/configlexer.lex
+++ nsd-4.1.26/configlexer.lex
@@ -291,6 +291,10 @@ min-refresh-time{COLON}	{ LEXOUT(("v(%s)
 max-retry-time{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_MAX_RETRY_TIME;}
 min-retry-time{COLON}	{ LEXOUT(("v(%s) ", yytext)); return VAR_MIN_RETRY_TIME;}
 multi-master-check{COLON}      { LEXOUT(("v(%s) ", yytext)); return VAR_MULTI_MASTER_CHECK;}
+tls-service-key{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_SERVICE_KEY;}
+tls-service-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.26/configure.ac
===================================================================
--- nsd-4.1.26.orig/configure.ac
+++ nsd-4.1.26/configure.ac
@@ -871,6 +871,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]))
@@ -953,6 +954,32 @@ dt_DNSTAP([${localstatedir}/run/nsd-dnst
 sinclude(systemd.m4)
 # Include systemd.m4 - end
 
+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.26/edns.c
===================================================================
--- nsd-4.1.26.orig/edns.c
+++ nsd-4.1.26/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.26/edns.h
===================================================================
--- nsd-4.1.26.orig/edns.h
+++ nsd-4.1.26/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.26/nsd-checkconf.c
===================================================================
--- nsd-4.1.26.orig/nsd-checkconf.c
+++ nsd-4.1.26/nsd-checkconf.c
@@ -371,6 +371,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);
@@ -385,6 +386,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);
@@ -536,6 +540,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");
 
 #ifdef USE_DNSTAP
 	printf("\ndnstap:\n");
Index: nsd-4.1.26/nsd.c
===================================================================
--- nsd-4.1.26.orig/nsd.c
+++ nsd-4.1.26/nsd.c
@@ -659,6 +659,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)
 	{
@@ -945,6 +948,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.26/nsd.conf.5.in
===================================================================
--- nsd-4.1.26.orig/nsd.conf.5.in
+++ nsd-4.1.26/nsd.conf.5.in
@@ -436,6 +436,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.26/nsd.conf.sample.in
===================================================================
--- nsd-4.1.26.orig/nsd.conf.sample.in
+++ nsd-4.1.26/nsd.conf.sample.in
@@ -189,6 +189,16 @@ server:
 	# dnstap-log-auth-query-messages: no
 	# dnstap-log-auth-response-messages: no
 
+	# Service clients over TLS (on the TCP sockets), with plain DNS inside
+	# the TLS stream. Give the certificate to use and private key.
+	# Default is "" (disabled). Requires restart to take effect.
+	# tls-service-key: "path/to/privatekeyfile.key"
+	# tls-service-pem: "path/to/publiccertfile.pem"
+	# tls-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.26/nsd.h
===================================================================
--- nsd-4.1.26.orig/nsd.h
+++ nsd-4.1.26/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"
@@ -276,6 +279,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;
@@ -311,6 +319,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.26/options.c
===================================================================
--- nsd-4.1.26.orig/options.c
+++ nsd-4.1.26/options.c
@@ -113,6 +113,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.26/options.h
===================================================================
--- nsd-4.1.26.orig/options.h
+++ nsd-4.1.26/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.26/query.c
===================================================================
--- nsd-4.1.26.orig/query.c
+++ nsd-4.1.26/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);
 		}
@@ -1518,6 +1583,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)) {
@@ -1541,6 +1611,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.26/query.h
===================================================================
--- nsd-4.1.26.orig/query.h
+++ nsd-4.1.26/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.26/server.c
===================================================================
--- nsd-4.1.26.orig/server.c
+++ nsd-4.1.26/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>
@@ -71,6 +80,11 @@
 
 #define RELOAD_SYNC_TIMEOUT 25 /* seconds */
 
+#ifdef USE_TCP_FASTOPEN
+  #define TCP_FASTOPEN_FILE "/proc/sys/net/ipv4/tcp_fastopen"
+  #define TCP_FASTOPEN_SERVER_BIT_MASK 0x2
+#endif
+
 /*
  * Data for the UDP handlers.
  */
@@ -86,6 +100,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
 };
 
 /*
@@ -170,6 +188,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
 };
 
 /*
@@ -202,6 +231,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.
  */
@@ -224,6 +276,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.
@@ -796,6 +876,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 */
@@ -930,6 +1014,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));
@@ -1101,6 +1192,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 */
@@ -1333,6 +1426,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_chain_file(ctx, pem)) {
+		log_msg(LOG_ERR, "error for cert file: %s", pem);
+		log_crypto_err("error in SSL_CTX use_certificate_chain_file");
+		SSL_CTX_free(ctx);
+		return NULL;
+	}
+	if(!SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM)) {
+		log_msg(LOG_ERR, "error for private key file: %s", key);
+		log_crypto_err("Error in SSL_CTX use_PrivateKey_file");
+		SSL_CTX_free(ctx);
+		return NULL;
+	}
+	if(!SSL_CTX_check_private_key(ctx)) {
+		log_msg(LOG_ERR, "error for key file: %s", key);
+		log_crypto_err("Error in SSL_CTX check_private_key");
+		SSL_CTX_free(ctx);
+		return NULL;
+	}
+
+	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)
@@ -2139,6 +2324,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)
@@ -2504,11 +2698,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);
 
 	/*
@@ -2734,8 +2956,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)
@@ -2905,6 +3148,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),
@@ -3022,8 +3637,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);
Index: nsd-4.1.26/doc/ChangeLog
===================================================================
--- nsd-4.1.26.orig/doc/ChangeLog
+++ nsd-4.1.26/doc/ChangeLog
@@ -148,6 +148,11 @@
 	- Use accept4 to speed up answer of TCP queries, on Linux and FreeBSD
 	  and OpenBSD.
 
+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
+
 22 May 2018: Wouter
 	- Fix nsec3 hash of parent and child co-hosted nsec3 enabled zones.
 
Index: nsd-4.1.26/configparser.y
===================================================================
--- nsd-4.1.26.orig/configparser.y
+++ nsd-4.1.26/configparser.y
@@ -76,6 +76,7 @@ extern config_parser_state_type* cfg_par
 %token VAR_DNSTAP_SEND_IDENTITY VAR_DNSTAP_SEND_VERSION VAR_DNSTAP_IDENTITY
 %token VAR_DNSTAP_VERSION VAR_DNSTAP_LOG_AUTH_QUERY_MESSAGES
 %token VAR_DNSTAP_LOG_AUTH_RESPONSE_MESSAGES
+%token VAR_TLS_SERVICE_KEY VAR_TLS_SERVICE_PEM VAR_TLS_PORT VAR_DO_STARTTLS
 
 %%
 toplevelvars: /* empty */ | toplevelvars toplevelvar ;
@@ -107,6 +108,7 @@ 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_tls_service_key | server_tls_service_pem | server_tls_port | server_do_starttls |
 	server_minimal_responses | server_refuse_any | server_use_systemd;
 server_ip_address: VAR_IP_ADDRESS STRING 
 	{ 
@@ -529,7 +531,32 @@ server_zonefiles_write: VAR_ZONEFILES_WR
 		else cfg_parser->opt->zonefiles_write = atoi($2);
 	}
 	;
-
+server_tls_service_key: VAR_TLS_SERVICE_KEY STRING
+	{
+		OUTYY(("P(server_tls_service_key:%s)\n", $2));
+		cfg_parser->opt->tls_service_key = region_strdup(cfg_parser->opt->region, $2);
+	}
+	;
+server_tls_service_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"));
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.