Am 23.05.2018 um 18:28 schrieb Sara Dickinson:
> We did create a basic patch back in 2015 to add TLS to NSD - it can be found
> here:
> https://portal.sinodun.com/stash/projects/TDNS/repos/dns-over-tls_patches/browse
>
> I’ve been meaning to work on porting this to the latest NSD for a while now
> but if anyone else wants to take a look at this then feel free.
Hello Sara,
the attached version work with the latest NSD 4.1.21.
It compiles and nsd run for a very first test here.
But as the patch was manually re-applied diff by diff I'm not sure I've done
everything right.
Wouter will have more "context" at the patched code paths. Review is required.
Anyway: thanks for pointing to that work, Sara!
Andreas
Index: nsd-4.1.21/config.h.in
===================================================================
--- nsd-4.1.21.orig/config.h.in
+++ nsd-4.1.21/config.h.in
@@ -529,6 +529,9 @@
/* Define this to enable per-zone statistics gathering. */
#undef USE_ZONE_STATS
+/* Define this to enable TCP fast open. */
+#undef USE_TCP_FASTOPEN
+
/* Define to the NSD version to answer version.server query. */
#undef VERSION
Index: nsd-4.1.21/configlexer.lex
===================================================================
--- nsd-4.1.21.orig/configlexer.lex
+++ nsd-4.1.21/configlexer.lex
@@ -282,6 +282,10 @@ min-refresh-time{COLON} { LEXOUT(("v(%s)
max-retry-time{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_MAX_RETRY_TIME;}
min-retry-time{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_MIN_RETRY_TIME;}
multi-master-check{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_MULTI_MASTER_CHECK;}
+tls-service-key{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_SERVICE_KEY;}
+tls-service-pem{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_SERVICE_PEM;}
+tls-port{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_PORT;}
+do-starttls{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_DO_STARTTLS;}
{NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++;}
/* Quoted strings. Strip leading and ending quotes */
Index: nsd-4.1.21/configparser.y
===================================================================
--- nsd-4.1.21.orig/configparser.y
+++ nsd-4.1.21/configparser.y
@@ -72,6 +72,7 @@ extern config_parser_state_type* cfg_par
%token VAR_MAX_REFRESH_TIME VAR_MIN_REFRESH_TIME
%token VAR_MAX_RETRY_TIME VAR_MIN_RETRY_TIME
%token VAR_MULTI_MASTER_CHECK VAR_MINIMAL_RESPONSES VAR_REFUSE_ANY
+%token VAR_TLS_SERVICE_KEY VAR_TLS_SERVICE_PEM VAR_TLS_PORT VAR_DO_STARTTLS
%%
toplevelvars: /* empty */ | toplevelvars toplevelvar ;
@@ -103,7 +104,8 @@ content_server: server_ip_address | serv
server_zonefiles_check | server_do_ip4 | server_do_ip6 |
server_zonefiles_write | server_log_time_ascii | server_round_robin |
server_reuseport | server_version | server_ip_freebind |
- server_minimal_responses | server_refuse_any;
+ server_minimal_responses | server_refuse_any |
+ server_tls_service_key | server_tls_service_pem | server_tls_port | server_do_starttls;
server_ip_address: VAR_IP_ADDRESS STRING
{
OUTYY(("P(server_ip_address:%s)\n", $2));
@@ -521,6 +523,32 @@ server_zonefiles_write: VAR_ZONEFILES_WR
}
;
+server_tls_service_key: VAR_TLS_SERVICE_KEY STRING
+ {
+ OUTYY(("P(server_tls_service_key:%s)\n", $2));
+ cfg_parser->opt->tls_service_key = region_strdup(cfg_parser->opt->region, $2);
+ }
+ ;
+server_tls_service_pem: VAR_TLS_SERVICE_PEM STRING
+ {
+ OUTYY(("P(server_tls_service_pem:%s)\n", $2));
+ cfg_parser->opt->tls_service_pem = region_strdup(cfg_parser->opt->region, $2);
+ }
+ ;
+server_tls_port: VAR_TLS_PORT STRING
+ {
+ OUTYY(("P(server_tls_port:%s)\n", $2));
+ cfg_parser->opt->tls_port = region_strdup(cfg_parser->opt->region, $2);
+ }
+ ;
+server_do_starttls: VAR_DO_STARTTLS STRING
+ {
+ OUTYY(("P(server_do_starttls:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->opt->do_starttls = (strcmp($2, "yes")==0);
+ }
+ ;
rcstart: VAR_REMOTE_CONTROL
{
OUTYY(("\nP(remote-control:)\n"));
Index: nsd-4.1.21/configure.ac
===================================================================
--- nsd-4.1.21.orig/configure.ac
+++ nsd-4.1.21/configure.ac
@@ -841,6 +841,7 @@ if test x$HAVE_SSL = x"yes"; then
else
AC_MSG_WARN([No SSL, therefore remote-control is disabled])
+ AC_MSG_WARN([No SSL, therefore TLS is disabled])
fi
AC_ARG_ENABLE(nsec3, AC_HELP_STRING([--disable-nsec3], [Disable NSEC3 support]))
@@ -899,6 +900,32 @@ case "$enable_packed" in
;;
esac
+AC_ARG_ENABLE(TObit, AC_HELP_STRING([--enable-TObit], [(Experimental) Enables TO bit during STARTTLS negotiation. NOTE WELL: The TO bit is NOT assigned by IANA - USE FOR TESTING ONLY! DO NOT DEPLOY TO PRODUCTION ENVIRONMENTS!]))
+case "$enable_TObit" in
+ yes)
+ if test x$HAVE_SSL = x"yes"; then
+ AC_DEFINE_UNQUOTED([USE_TO_BIT], [], [Define this to enable use of the TO bit.])
+ else
+ AC_MSG_WARN([No SSL, therefore TO bit is disabled])
+ fi
+ ;;
+ no|*)
+ ;;
+esac
+
+AC_ARG_ENABLE(tcp-fastopen, AC_HELP_STRING([--enable-tcp-fastopen], [Enable TCP Fast Open]))
+case "$enable_tcp_fastopen" in
+ yes)
+ AC_CHECK_DECL([TCP_FASTOPEN], [], [AC_MSG_ERROR([TCP Fast Open is not available: please rerun without --enable-tcp-fastopen])], [AC_INCLUDES_DEFAULT
+#include <netinet/tcp.h>
+ ])
+ AC_DEFINE_UNQUOTED([USE_TCP_FASTOPEN], [1], [Define this to enable TCP fast open.])
+ ;;
+ no|*)
+ ;;
+esac
+
+
AH_BOTTOM([
/* define before includes as it specifies what standard to use. */
#if (defined(HAVE_PSELECT) && !defined (HAVE_PSELECT_PROTO)) \
Index: nsd-4.1.21/doc/ChangeLog
===================================================================
--- nsd-4.1.21.orig/doc/ChangeLog
+++ nsd-4.1.21/doc/ChangeLog
@@ -1,3 +1,8 @@
+23 May 2018: Andreas via Sara
+ - Patch to add support for experimental STARTTLS implementation
+ - Patch to add support for experimental TCP Fast Open
+ - Patch to add support for tls service on a specified tls port
+
7 May 2018: Wouter
- Tag for 4.1.21rc1 release.
Index: nsd-4.1.21/edns.c
===================================================================
--- nsd-4.1.21.orig/edns.c
+++ nsd-4.1.21/edns.c
@@ -57,6 +57,9 @@ edns_init_record(edns_record_type *edns)
edns->maxlen = 0;
edns->opt_reserved_space = 0;
edns->dnssec_ok = 0;
+#ifdef USE_TO_BIT
+ edns->tls_ok = 0;
+#endif
edns->nsid = 0;
}
@@ -146,6 +149,9 @@ edns_parse_record(edns_record_type *edns
edns->status = EDNS_OK;
edns->maxlen = opt_class;
edns->dnssec_ok = opt_flags & DNSSEC_OK_MASK;
+#ifdef USE_TO_BIT
+ edns->tls_ok = opt_flags & TLS_OK_MASK;
+#endif
return 1;
}
Index: nsd-4.1.21/edns.h
===================================================================
--- nsd-4.1.21.orig/edns.h
+++ nsd-4.1.21/edns.h
@@ -19,6 +19,10 @@ struct query;
#define OPT_HDR 4U /* NSID opt header length */
#define NSID_CODE 3 /* nsid option code */
#define DNSSEC_OK_MASK 0x8000U /* do bit mask */
+#ifdef USE_TO_BIT
+#define TLS_OK_MASK 0x4000U /* to bit mask */
+#endif
+
struct edns_data
{
Index: nsd-4.1.21/nsd-checkconf.c
===================================================================
--- nsd-4.1.21.orig/nsd-checkconf.c
+++ nsd-4.1.21/nsd-checkconf.c
@@ -370,6 +370,7 @@ config_print_zone(nsd_options_type* opt,
SERV_GET_BIN(round_robin, o);
SERV_GET_BIN(minimal_responses, o);
SERV_GET_BIN(refuse_any, o);
+ SERV_GET_BIN(do_starttls, o);
/* str */
SERV_GET_PATH(final, database, o);
SERV_GET_STR(identity, o);
@@ -384,6 +385,9 @@ config_print_zone(nsd_options_type* opt,
SERV_GET_PATH(final, xfrdir, o);
SERV_GET_PATH(final, zonelistfile, o);
SERV_GET_STR(port, o);
+ SERV_GET_STR(tls_service_key, o);
+ SERV_GET_STR(tls_service_pem, o);
+ SERV_GET_STR(tls_port, o);
/* int */
SERV_GET_INT(server_count, o);
SERV_GET_INT(tcp_count, o);
@@ -525,6 +529,10 @@ config_test_print_server(nsd_options_typ
#endif
printf("\tzonefiles-check: %s\n", opt->zonefiles_check?"yes":"no");
printf("\tzonefiles-write: %d\n", opt->zonefiles_write);
+ print_string_var("tls-service-key:", opt->tls_service_key);
+ print_string_var("tls-service-pem:", opt->tls_service_pem);
+ print_string_var("tls-port:", opt->tls_port);
+ printf("\tdo_starttls: %s\n", opt->do_starttls?"yes":"no");
printf("\nremote-control:\n");
printf("\tcontrol-enable: %s\n", opt->control_enable?"yes":"no");
Index: nsd-4.1.21/nsd.c
===================================================================
--- nsd-4.1.21.orig/nsd.c
+++ nsd-4.1.21/nsd.c
@@ -692,6 +692,9 @@ main(int argc, char *argv[])
nsd.outgoing_tcp_mss = nsd.options->outgoing_tcp_mss;
nsd.ipv4_edns_size = nsd.options->ipv4_edns_size;
nsd.ipv6_edns_size = nsd.options->ipv6_edns_size;
+#ifdef HAVE_SSL
+ nsd.tls_ctx = NULL;
+#endif
if(udp_port == 0)
{
@@ -978,6 +981,13 @@ main(int argc, char *argv[])
if(!(nsd.rc = daemon_remote_create(nsd.options)))
error("could not perform remote control setup");
}
+ if(nsd.options->tls_service_key && nsd.options->tls_service_key[0]
+ && nsd.options->tls_service_pem && nsd.options->tls_service_pem[0]) {
+ if(!(nsd.tls_ctx = server_tls_ctx_create(&nsd, NULL)))
+ error("could not set up tls SSL_CTX");
+ if (nsd.options->do_starttls)
+ log_msg(LOG_NOTICE, "STARTTLS enabled");
+ }
#endif /* HAVE_SSL */
/* Unless we're debugging, fork... */
Index: nsd-4.1.21/nsd.conf.5.in
===================================================================
--- nsd-4.1.21.orig/nsd.conf.5.in
+++ nsd-4.1.21/nsd.conf.5.in
@@ -435,6 +435,26 @@ whitelisted. Default @ratelimit_default@
specific queries to receive this qps limit instead of the normal limit.
With the value 0 the rate is unlimited.
.\" rrlend
+.TP
+.B tls\-service\-key:\fR <filename>
+If enabled, the server provides TLS service on its TCP sockets.
+The file is the private key for the TLS session. The public certificate is in the
+tls-service-pem file. Default is "", turned off. Requires a restart (a reload is
+not enough) if changed, because the private key is read while root permissions
+are held and before chroot (if any). Normal DNS TCP service is not provided and gives
+errors, this service is best run with a different port: config or @port suffixes in the
+interface config.
+.TP
+.B tls\-service\-pem:\fR <filename>
+The public key certificate pem file for the tls service. Default is "", turned off.
+.TP
+.B tls\-port:\fR <number>
+The port number on which to provide TCP TLS service, default is turned off, only
+interfaces configured with that port number as @number get the TLS service.
+.TP
+.B do\-starttls:\fR <yes or no>
+Allow upgrade to TLS on regular TCP connections via STARTTLS.
+Uses the tls\-service\-key and tls\-service\-pem for the key and certificate.
.SS "Remote Control"
The
.B remote\-control:
Index: nsd-4.1.21/nsd.conf.sample.in
===================================================================
--- nsd-4.1.21.orig/nsd.conf.sample.in
+++ nsd-4.1.21/nsd.conf.sample.in
@@ -177,6 +177,16 @@ server:
# rrl-whitelist-ratelimit: 2000
# RRLend
+ # Service clients over TLS (on the TCP sockets), with plain DNS inside
+ # the TLS stream. Give the certificate to use and private key.
+ # Default is "" (disabled). Requires restart to take effect.
+ # tls-service-key: "path/to/privatekeyfile.key"
+ # tls-service-pem: "path/to/publiccertfile.pem"
+ # tls-port: <port-number>
+
+ # Do we allow tls upgrade on tcp connections after STARTTLS?
+ # do-starttls
+
# Remote control config section.
remote-control:
# Enable remote control with nsd-control(8) here.
Index: nsd-4.1.21/nsd.h
===================================================================
--- nsd-4.1.21.orig/nsd.h
+++ nsd-4.1.21/nsd.h
@@ -11,6 +11,9 @@
#define _NSD_H_
#include <signal.h>
+#ifdef HAVE_OPENSSL_SSL_H
+#include <openssl/ssl.h>
+#endif
#include "dns.h"
#include "edns.h"
@@ -266,6 +269,11 @@ struct nsd
unsigned int err_limit_count;
struct nsd_options* options;
+
+#ifdef HAVE_SSL
+ /* TLS specific configuration */
+ SSL_CTX *tls_ctx;
+#endif
};
extern struct nsd nsd;
@@ -301,6 +309,9 @@ void server_prepare_xfrd(struct nsd *nsd
void server_start_xfrd(struct nsd *nsd, int del_db, int reload_active);
/* send SOA serial numbers to xfrd */
void server_send_soa_xfrd(struct nsd *nsd, int shortsoa);
+#ifdef HAVE_SSL
+SSL_CTX* server_tls_ctx_create(struct nsd *nsd, char* verifypem);
+#endif
ssize_t block_read(struct nsd* nsd, int s, void* p, ssize_t sz, int timeout);
#endif /* _NSD_H_ */
Index: nsd-4.1.21/options.c
===================================================================
--- nsd-4.1.21.orig/options.c
+++ nsd-4.1.21/options.c
@@ -103,6 +103,10 @@ nsd_options_create(region_type* region)
opt->zonefiles_write = ZONEFILES_WRITE_INTERVAL;
else opt->zonefiles_write = 0;
opt->xfrd_reload_timeout = 1;
+ opt->tls_service_key = NULL;
+ opt->tls_service_pem = NULL;
+ opt->tls_port = NULL;
+ opt->do_starttls = 0;
opt->control_enable = 0;
opt->control_interface = NULL;
opt->control_port = NSD_CONTROL_PORT;
Index: nsd-4.1.21/options.h
===================================================================
--- nsd-4.1.21.orig/options.h
+++ nsd-4.1.21/options.h
@@ -97,6 +97,15 @@ struct nsd_options {
int refuse_any;
int reuseport;
+ /* private key file for TLS */
+ char* tls_service_key;
+ /* certificate file for TLS */
+ char* tls_service_pem;
+ /* TLS dedicated port */
+ const char* tls_port;
+ /* Allow upgrade to TLS after STARTTLS negotiation*/
+ int do_starttls;
+
/** remote control section. enable toggle. */
int control_enable;
/** the interfaces the remote control should listen on */
Index: nsd-4.1.21/query.c
===================================================================
--- nsd-4.1.21.orig/query.c
+++ nsd-4.1.21/query.c
@@ -37,6 +37,11 @@
#include "nsec3.h"
#include "tsig.h"
+#ifdef HAVE_SSL
+#define STARTTLS_STR "STARTTLS"
+#define NO_TLS_STR "NO_TLS"
+#endif
+
/* [Bug #253] Adding unnecessary NS RRset may lead to undesired truncation.
* This function determines if the final response packet needs the NS RRset
* included. Currently, it will only return negative if QTYPE == DNSKEY|DS.
@@ -200,6 +205,10 @@ query_create(region_type *region, uint16
query->tsig_prepare_it = 1;
query->tsig_update_it = 1;
query->tsig_sign_it = 1;
+#ifdef HAVE_SSL
+ query->first_query = 1;
+ query->tls_ok = 0;
+#endif
return query;
}
@@ -362,6 +371,22 @@ process_edns(nsd_type* nsd, struct query
#endif
}
+#ifdef USE_TO_BIT
+ /* Change the value of the tls_ok bit depending on whether or not the
+ * connection should be upgraded to TLS based on this query. The value is
+ * used later to trigger the upgrade and also to construct the response.
+ */
+ if (q->edns.tls_ok) {
+ /* Logs for testing */
+ VERBOSITY(3, (LOG_INFO, "TO bit recieved"));
+ if (!(q->tcp && q->first_query && nsd->tls_ctx
+ && nsd->options->do_starttls)) {
+ VERBOSITY(3, (LOG_INFO, "TO bit rejected"));
+ q->edns.tls_ok = 0;
+ }
+ }
+#endif
+
/* Strip the OPT resource record off... */
buffer_set_position(q->packet, q->edns.position);
buffer_set_limit(q->packet, q->edns.position);
@@ -553,6 +578,46 @@ answer_chaos(struct nsd *nsd, query_type
} else {
RCODE_SET(q->packet, RCODE_REFUSE);
}
+#ifdef HAVE_SSL
+ } else if (q->qname->name_size == 10
+ && memcmp(dname_name(q->qname), "\010starttls", 10) == 0) {
+ if (q->tcp) {
+ if (q->first_query) {
+ if (nsd->tls_ctx
+#ifdef USE_TO_BIT
+ && q->edns.tls_ok
+#endif
+ && nsd->options->do_starttls ) {
+ /* Add STARTTLS answer */
+ query_addtxt(q,
+ buffer_begin(q->packet) + QHEADERSZ,
+ CLASS_CH,
+ 0,
+ STARTTLS_STR);
+ ANCOUNT_SET(q->packet, ANCOUNT(q->packet) + 1);
+ /* Not required if TO bit assigned and used.*/
+ q->tls_ok = 1;
+ /* Logs here are for testing */
+ VERBOSITY(3, (LOG_INFO, "STARTTLS received and sent in response"));
+ } else {
+ /* Add NO_TLS answer */
+ query_addtxt(q,
+ buffer_begin(q->packet) + QHEADERSZ,
+ CLASS_CH,
+ 0,
+ NO_TLS_STR);
+ ANCOUNT_SET(q->packet, ANCOUNT(q->packet) + 1);
+ VERBOSITY(3, (LOG_INFO, "STARTTLS received and but NO_TLS sent in response"));
+ }
+ } else {
+ RCODE_SET(q->packet, RCODE_REFUSE);
+ VERBOSITY(3, (LOG_INFO, "STARTTLS ignored as not first query on tcp connection"));
+ }
+ } else {
+ RCODE_SET(q->packet, RCODE_REFUSE);
+ }
+#endif
+ /* Back port of fix in 4.1.1 for noname CH TXT queries */
} else {
RCODE_SET(q->packet, RCODE_REFUSE);
}
@@ -1516,6 +1581,11 @@ query_add_optional(query_type *q, nsd_ty
case EDNS_OK:
if (q->edns.dnssec_ok) edns->ok[7] = 0x80;
else edns->ok[7] = 0x00;
+#ifdef USE_TO_BIT
+ if (q->edns.tls_ok) {
+ edns->ok[7] = edns->ok[7] | ((TLS_OK_MASK >> 8) & 0xFF);
+ }
+#endif
buffer_write(q->packet, edns->ok, OPT_LEN);
if(q->edns.opt_reserved_space == 0 || !buffer_available(
q->packet, 2+q->edns.opt_reserved_space)) {
@@ -1539,6 +1609,11 @@ query_add_optional(query_type *q, nsd_ty
case EDNS_ERROR:
if (q->edns.dnssec_ok) edns->error[7] = 0x80;
else edns->error[7] = 0x00;
+#ifdef USE_TO_BIT
+ if (q->edns.tls_ok) {
+ edns->ok[7] = edns->ok[7] | ((TLS_OK_MASK >> 8) & 0xFF);
+ }
+#endif
buffer_write(q->packet, edns->error, OPT_LEN);
buffer_write(q->packet, edns->rdata_none, OPT_RDATA);
ARCOUNT_SET(q->packet, ARCOUNT(q->packet) + 1);
Index: nsd-4.1.21/query.h
===================================================================
--- nsd-4.1.21.orig/query.h
+++ nsd-4.1.21/query.h
@@ -63,6 +63,13 @@ struct query {
int tcp;
uint16_t tcplen;
+#ifdef HAVE_SSL
+ int first_query;
+ /* This tls_ok variable is needed for the case where the TO bit is not used
+ * and upgrade is triggered based only on the STARTTLS query content. It can
+ * be removed if the TO bit is assigned by IANA and the logic is revised. */
+ int tls_ok;
+#endif
buffer_type *packet;
Index: nsd-4.1.21/server.c
===================================================================
--- nsd-4.1.21.orig/server.c
+++ nsd-4.1.21/server.c
@@ -16,6 +16,9 @@
#include <sys/wait.h>
#include <netinet/in.h>
+#ifdef USE_TCP_FASTOPEN
+ #include <netinet/tcp.h>
+#endif
#include <arpa/inet.h>
#include <assert.h>
@@ -40,6 +43,12 @@
#ifdef HAVE_OPENSSL_RAND_H
#include <openssl/rand.h>
#endif
+#ifdef HAVE_OPENSSL_SSL_H
+#include <openssl/ssl.h>
+#endif
+#ifdef HAVE_OPENSSL_ERR_H
+#include <openssl/err.h>
+#endif
#ifndef USE_MINI_EVENT
# ifdef HAVE_EVENT_H
# include <event.h>
@@ -68,6 +77,11 @@
#define RELOAD_SYNC_TIMEOUT 25 /* seconds */
+#ifdef USE_TCP_FASTOPEN
+ #define TCP_FASTOPEN_FILE "/proc/sys/net/ipv4/tcp_fastopen"
+ #define TCP_FASTOPEN_SERVER_BIT_MASK 0x2
+#endif
+
/*
* Data for the UDP handlers.
*/
@@ -83,6 +97,10 @@ struct tcp_accept_handler_data {
struct nsd_socket *socket;
int event_added;
struct event event;
+#ifdef HAVE_SSL
+ /* handler accepts TLS connections on the dedicated port */
+ int tls_accept;
+#endif
};
/*
@@ -167,6 +185,17 @@ struct tcp_handler_data
* The timeout in msec for this tcp connection
*/
int tcp_timeout;
+#ifdef HAVE_SSL
+ /*
+ * TLS object.
+ */
+ SSL* tls;
+
+ /*
+ * TLS handshake state.
+ */
+ enum { tls_hs_none, tls_hs_read, tls_hs_write } shake_state;
+#endif
};
/*
@@ -199,6 +228,29 @@ static void handle_tcp_reading(int fd, s
*/
static void handle_tcp_writing(int fd, short event, void* arg);
+#ifdef HAVE_SSL
+/*Comment*/
+static SSL* incoming_ssl_fd(SSL_CTX* ctx, int fd);
+/*
+ * Handle TLS handshake. May be called multiple times if incomplete.
+ */
+static int tls_handshake(struct tcp_handler_data* data, int fd);
+
+/*
+ * Handle incoming queries on a TLS over TCP connection. The TLS
+ * connections are configured to be non-blocking and the handler may
+ * be called multiple times before a complete query is received.
+ */
+static void handle_tls_reading(int fd, short event, void* arg);
+
+/*
+ * Handle outgoing responses on a TLS over TCP connection. The TLS
+ * connections are configured to be non-blocking and the handler may
+ * be called multiple times before a complete response is sent.
+ */
+static void handle_tls_writing(int fd, short event, void* arg);
+#endif
+
/*
* Send all children the quit nonblocking, then close pipe.
*/
@@ -221,6 +273,34 @@ static uint32_t compression_table_capaci
static uint32_t compression_table_size = 0;
static domain_type* compressed_dnames[MAXRRSPP];
+#ifdef USE_TCP_FASTOPEN
+/* Checks to see if the kernal value must be manually changed in order for
+ TCP Fast Open to support server mode */
+static void report_tcp_fastopen_config() {
+
+ int tcp_fastopen_fp;
+ uint8_t tcp_fastopen_value;
+
+ if ( (tcp_fastopen_fp = open(TCP_FASTOPEN_FILE, O_RDONLY)) == -1 ) {
+ log_msg(LOG_INFO,"Error opening " TCP_FASTOPEN_FILE ": %s\n", strerror(errno));
+ }
+ if (read(tcp_fastopen_fp, &tcp_fastopen_value, 1) == -1 ) {
+ log_msg(LOG_INFO,"Error reading " TCP_FASTOPEN_FILE ": %s\n", strerror(errno));
+ close(tcp_fastopen_fp);
+ }
+ if (!(tcp_fastopen_value & TCP_FASTOPEN_SERVER_BIT_MASK)) {
+ log_msg(LOG_ERR,"Error: TCP Fast Open support is available and configure in NSD by default.\n");
+ log_msg(LOG_ERR,"However the kernal paramenters are not configured to support TCP_FASTOPEN in server mode.\n");
+ log_msg(LOG_ERR,"To enable TFO use the command:");
+ log_msg(LOG_ERR," 'sudo sysctl -w net.ipv4.tcp_fastopen=2' for pure server mode or\n");
+ log_msg(LOG_ERR," 'sudo sysctl -w net.ipv4.tcp_fastopen=3' for both client and server mode\n");
+ log_msg(LOG_ERR,"NSD will not have TCP Fast Open available until this change is made.\n");
+ close(tcp_fastopen_fp);
+ }
+ close(tcp_fastopen_fp);
+}
+#endif
+
/*
* Remove the specified pid from the list of child pids. Returns -1 if
* the pid is not in the list, child_num otherwise. The field is set to 0.
@@ -771,6 +851,10 @@ server_init_ifs(struct nsd *nsd, size_t
/* TCP */
+#ifdef USE_TCP_FASTOPEN
+ report_tcp_fastopen_config();
+#endif
+
/* Make a socket... */
for (i = from; i < to; i++) {
/* for reuseports copy socket specs of first entries */
@@ -904,6 +988,13 @@ server_init_ifs(struct nsd *nsd, size_t
return -1;
}
+#ifdef USE_TCP_FASTOPEN
+ int backlog = TCP_BACKLOG;
+ if ((setsockopt(nsd->tcp[i].s, IPPROTO_TCP, TCP_FASTOPEN, &backlog, sizeof(backlog))) == -1 ) {
+ log_msg(LOG_ERR, "Setting TCP Fast Open Failed: %s", strerror(errno));
+ }
+#endif
+
/* Listen to it... */
if (listen(nsd->tcp[i].s, TCP_BACKLOG) == -1) {
log_msg(LOG_ERR, "can't listen: %s", strerror(errno));
@@ -1075,6 +1166,8 @@ server_shutdown(struct nsd *nsd)
tsig_finalize();
#ifdef HAVE_SSL
daemon_remote_delete(nsd->rc); /* ssl-delete secret keys */
+ if (nsd->tls_ctx)
+ SSL_CTX_free(nsd->tls_ctx);
#endif
#ifdef MEMCLEAN /* OS collects memory pages */
@@ -1304,6 +1397,98 @@ server_send_soa_xfrd(struct nsd* nsd, in
}
}
+#ifdef HAVE_SSL
+void
+log_crypto_err(const char* str)
+{
+ /* error:[error code]:[library name]:[function name]:[reason string] */
+ char buf[128];
+ unsigned long e;
+ ERR_error_string_n(ERR_get_error(), buf, sizeof(buf));
+ log_msg(LOG_ERR, "%s crypto %s", str, buf);
+ while( (e=ERR_get_error()) ) {
+ ERR_error_string_n(e, buf, sizeof(buf));
+ log_msg(LOG_ERR, "and additionally crypto %s", buf);
+ }
+}
+
+SSL_CTX*
+server_tls_ctx_create(struct nsd* nsd, char* verifypem)
+{
+ char *key, *pem;
+ SSL_CTX *ctx;
+
+ ERR_load_crypto_strings();
+ ERR_load_SSL_strings();
+ OpenSSL_add_all_algorithms();
+ (void)SSL_library_init();
+
+ key = nsd->options->tls_service_key;
+ pem = nsd->options->tls_service_pem;
+
+ /* NOTE:This mimics the existing code in Unbound 1.5.1 by supporting SSL but
+ * raft-ietf-uta-tls-bcp-08 recommends only using TLSv1.2*/
+ ctx = SSL_CTX_new(SSLv23_server_method());
+ if(!ctx) {
+ log_crypto_err("could not SSL_CTX_new");
+ return NULL;
+ }
+ /* no SSLv2 because has defects */
+ if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2) != SSL_OP_NO_SSLv2){
+ log_crypto_err("could not set SSL_OP_NO_SSLv2");
+ SSL_CTX_free(ctx);
+ return NULL;
+ }
+ if(!SSL_CTX_use_certificate_file(ctx, pem, SSL_FILETYPE_PEM)) {
+ log_msg(LOG_ERR, "error for cert file: %s", pem);
+ log_crypto_err("error in SSL_CTX use_certificate_file");
+ SSL_CTX_free(ctx);
+ return NULL;
+ }
+ if(!SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM)) {
+ log_msg(LOG_ERR, "error for private key file: %s", key);
+ log_crypto_err("Error in SSL_CTX use_PrivateKey_file");
+ SSL_CTX_free(ctx);
+ return NULL;
+ }
+ if(!SSL_CTX_check_private_key(ctx)) {
+ log_msg(LOG_ERR, "error for key file: %s", key);
+ log_crypto_err("Error in SSL_CTX check_private_key");
+ SSL_CTX_free(ctx);
+ return NULL;
+ }
+
+ if(verifypem && verifypem[0]) {
+ if(!SSL_CTX_load_verify_locations(ctx, verifypem, NULL)) {
+ log_crypto_err("Error in SSL_CTX verify locations");
+ SSL_CTX_free(ctx);
+ return NULL;
+ }
+ SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(verifypem));
+ SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
+ }
+ return ctx;
+}
+
+/* check if tcp_handler_accept_data created for TLS dedicated port */
+int
+using_tls_port(struct sockaddr* addr, const char* tls_port)
+{
+ in_port_t port;
+
+ if (addr->sa_family == AF_INET)
+ port = ((struct sockaddr_in*)addr)->sin_port;
+#ifndef HAVE_STRUCT_SOCKADDR_IN6
+ else
+ port = ((struct sockaddr_in6*)addr)->sin6_port;
+#endif /* HAVE_STRUCT_SOCKADDR_IN6 */
+ if (atoi(tls_port) == ntohs(port))
+ return 1;
+
+ return 0;
+}
+#endif
+
/* pass timeout=-1 for blocking. Returns size, 0, -1(err), or -2(timeout) */
ssize_t
block_read(struct nsd* nsd, int s, void* p, ssize_t sz, int timeout)
@@ -2107,6 +2292,15 @@ server_child(struct nsd *nsd)
&tcp_accept_handlers[i-from];
data->nsd = nsd;
data->socket = &nsd->tcp[i];
+#ifdef HAVE_SSL
+ if (nsd->tls_ctx && nsd->options->tls_port && using_tls_port(
+ data->socket->addr->ai_addr, nsd->options->tls_port)) {
+ data->tls_accept = 1;
+ log_msg(LOG_NOTICE, "setup TCP for TLS service on interface %d", (int)i);
+ }
+ else
+ data->tls_accept = 0;
+#endif
event_set(handler, nsd->tcp[i].s, EV_PERSIST|EV_READ,
handle_tcp_accept, data);
if(event_base_set(event_base, handler) != 0)
@@ -2446,11 +2640,39 @@ handle_udp(int fd, short event, void* ar
}
#endif /* defined(HAVE_SENDMMSG) && !defined(NONBLOCKING_IS_BROKEN) && defined(HAVE_RECVMMSG) */
+/*
+ * Setup an event for the tcp handler.
+ */
+static void
+tcp_handler_setup_event(struct tcp_handler_data* data, void (*fn)(int, short, void *),
+ int fd, short event)
+{
+ struct timeval timeout;
+ struct event_base* ev_base;
+
+ timeout.tv_sec = data->nsd->tcp_timeout;
+ timeout.tv_usec = 0L;
+
+ ev_base = data->event.ev_base;
+ event_del(&data->event);
+ event_set(&data->event, fd, event, fn, data);
+ if(event_base_set(ev_base, &data->event) != 0)
+ log_msg(LOG_ERR, "event base set failed");
+ if(event_add(&data->event, &timeout) != 0)
+ log_msg(LOG_ERR, "event add failed");
+}
static void
cleanup_tcp_handler(struct tcp_handler_data* data)
{
event_del(&data->event);
+#ifdef HAVE_SSL
+ if(data->tls) {
+ SSL_shutdown(data->tls);
+ SSL_free(data->tls);
+ data->tls = NULL;
+ }
+#endif
close(data->event.ev_fd);
/*
@@ -2667,8 +2889,29 @@ handle_tcp_reading(int fd, short event,
ev_base = data->event.ev_base;
event_del(&data->event);
- event_set(&data->event, fd, EV_PERSIST | EV_WRITE | EV_TIMEOUT,
- handle_tcp_writing, data);
+#ifdef HAVE_SSL
+ data->query->first_query = 0;
+#ifdef USE_TO_BIT
+ if (data->nsd->tls_ctx && data->query->edns.tls_ok) {
+#else
+ if (data->nsd->tls_ctx && data->query->tls_ok) {
+#endif
+ data->tls = incoming_ssl_fd(data->nsd->tls_ctx, fd);
+ if(!data->tls) {
+ close(fd);
+ return;
+ }
+ data->shake_state = tls_hs_read;
+ event_set(&data->event, fd, EV_PERSIST | EV_READ | EV_TIMEOUT,
+ handle_tls_reading, data);
+ data->query_state = QUERY_PROCESSED;
+ } else {
+#endif
+ event_set(&data->event, fd, EV_PERSIST | EV_READ | EV_TIMEOUT,
+ handle_tcp_reading, data);
+#ifdef HAVE_SSL
+ }
+#endif
if(event_base_set(ev_base, &data->event) != 0)
log_msg(LOG_ERR, "event base set tcpr failed");
if(event_add(&data->event, &timeout) != 0)
@@ -2838,6 +3081,378 @@ handle_tcp_writing(int fd, short event,
log_msg(LOG_ERR, "event add tcpw failed");
}
+#ifdef HAVE_SSL
+/** create SSL object and associate fd */
+static SSL*
+incoming_ssl_fd(SSL_CTX* ctx, int fd)
+{
+ SSL* ssl = SSL_new((SSL_CTX*)ctx);
+ if(!ssl) {
+ log_crypto_err("could not SSL_new");
+ return NULL;
+ }
+ SSL_set_accept_state(ssl);
+ (void)SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
+ if(!SSL_set_fd(ssl, fd)) {
+ log_crypto_err("could not SSL_set_fd");
+ SSL_free(ssl);
+ return NULL;
+ }
+ return ssl;
+}
+
+/** TLS handshake to upgrade TCP connection */
+static int
+tls_handshake(struct tcp_handler_data* data, int fd)
+{
+ int r;
+
+ /* (continue to) setup the TLS connection */
+ ERR_clear_error();
+ r = SSL_do_handshake(data->tls);
+
+ if(r != 1) {
+ int want = SSL_get_error(data->tls, r);
+ if(want == SSL_ERROR_WANT_READ) {
+ if(data->shake_state == tls_hs_read) {
+ /* try again later */
+ return 1;
+ }
+ data->shake_state = tls_hs_read;
+ /* switch back to reading mode */
+ tcp_handler_setup_event(data, handle_tls_reading, fd, EV_PERSIST|EV_TIMEOUT|EV_READ);
+ return 1;
+ } else if(want == SSL_ERROR_WANT_WRITE) {
+ if(data->shake_state == tls_hs_write) {
+ /* try again later */
+ return 1;
+ }
+ data->shake_state = tls_hs_write;
+ /* switch back to writing mode */
+ tcp_handler_setup_event(data, handle_tls_writing, fd, EV_PERSIST|EV_TIMEOUT|EV_WRITE);
+ return 1;
+ } else {
+ if(r == 0)
+ log_msg(LOG_ERR, "connection closed prematurely");
+ cleanup_tcp_handler(data);
+ log_msg(LOG_ERR, "TLS failed");
+ return 0;
+ }
+ }
+
+ /* Use to log successful upgrade for testing - could be removed*/
+ VERBOSITY(3, (LOG_INFO, "TLS handshake succeeded."));
+ data->shake_state = tls_hs_none;
+ return 1;
+}
+
+/** handle TLS reading of incoming query */
+static void
+handle_tls_reading(int fd, short event, void* arg)
+{
+ struct tcp_handler_data *data = (struct tcp_handler_data *) arg;
+ ssize_t received;
+
+ if ((event & EV_TIMEOUT)) {
+ /* Connection timed out. */
+ cleanup_tcp_handler(data);
+ return;
+ }
+
+ if (data->nsd->tcp_query_count > 0 &&
+ data->query_count >= data->nsd->tcp_query_count) {
+ /* No more queries allowed on this tcp connection. */
+ cleanup_tcp_handler(data);
+ return;
+ }
+
+ assert((event & EV_READ));
+
+ if (data->bytes_transmitted == 0) {
+ query_reset(data->query, TCP_MAX_MESSAGE_LEN, 1);
+ }
+
+ if(data->shake_state != tls_hs_none) {
+ if(!tls_handshake(data, fd))
+ return;
+ if(data->shake_state != tls_hs_none)
+ return;
+ }
+
+ /*
+ * Check if we received the leading packet length bytes yet.
+ */
+ if(data->bytes_transmitted < sizeof(uint16_t)) {
+ ERR_clear_error();
+ if((received=SSL_read(data->tls, (char *) &data->query->tcplen
+ + data->bytes_transmitted,
+ sizeof(uint16_t) - data->bytes_transmitted)) <= 0) {
+ int want = SSL_get_error(data->tls, received);
+ if(want == SSL_ERROR_ZERO_RETURN) {
+ cleanup_tcp_handler(data);
+ return; /* shutdown, closed */
+ } else if(want == SSL_ERROR_WANT_READ) {
+ /* wants to be called again */
+ return;
+ }
+ else if(want == SSL_ERROR_WANT_WRITE) {
+ /* switch to writing */
+ data->shake_state = tls_hs_write;
+ tcp_handler_setup_event(data, handle_tls_writing, fd, EV_PERSIST | EV_WRITE | EV_TIMEOUT);
+ return;
+ }
+ cleanup_tcp_handler(data);
+ log_crypto_err("could not SSL_read");
+ return;
+ }
+
+ data->bytes_transmitted += received;
+ if (data->bytes_transmitted < sizeof(uint16_t)) {
+ /*
+ * Not done with the tcplen yet, wait for more
+ * data to become available.
+ */
+ return;
+ }
+
+ assert(data->bytes_transmitted == sizeof(uint16_t));
+
+ data->query->tcplen = ntohs(data->query->tcplen);
+
+ /*
+ * Minimum query size is:
+ *
+ * Size of the header (12)
+ * + Root domain name (1)
+ * + Query class (2)
+ * + Query type (2)
+ */
+ if (data->query->tcplen < QHEADERSZ + 1 + sizeof(uint16_t) + sizeof(uint16_t)) {
+ VERBOSITY(2, (LOG_WARNING, "packet too small, dropping tcp connection"));
+ cleanup_tcp_handler(data);
+ return;
+ }
+
+ if (data->query->tcplen > data->query->maxlen) {
+ VERBOSITY(2, (LOG_WARNING, "insufficient tcp buffer, dropping connection"));
+ cleanup_tcp_handler(data);
+ return;
+ }
+
+ buffer_set_limit(data->query->packet, data->query->tcplen);
+ }
+
+ assert(buffer_remaining(data->query->packet) > 0);
+
+ /* Read the (remaining) query data. */
+ ERR_clear_error();
+ received = SSL_read(data->tls, (void*)buffer_current(data->query->packet),
+ (int)buffer_remaining(data->query->packet));
+ if(received <= 0) {
+ int want = SSL_get_error(data->tls, received);
+ if(want == SSL_ERROR_ZERO_RETURN) {
+ cleanup_tcp_handler(data);
+ return; /* shutdown, closed */
+ } else if(want == SSL_ERROR_WANT_READ) {
+ /* wants to be called again */
+ return;
+ }
+ else if(want == SSL_ERROR_WANT_WRITE) {
+ /* switch back writing */
+ data->shake_state = tls_hs_write;
+ tcp_handler_setup_event(data, handle_tls_writing, fd, EV_PERSIST | EV_WRITE | EV_TIMEOUT);
+ return;
+ }
+ cleanup_tcp_handler(data);
+ log_crypto_err("could not SSL_read");
+ return;
+ }
+
+ data->bytes_transmitted += received;
+ buffer_skip(data->query->packet, received);
+ if (buffer_remaining(data->query->packet) > 0) {
+ /*
+ * Message not yet complete, wait for more data to
+ * become available.
+ */
+ return;
+ }
+
+ assert(buffer_position(data->query->packet) == data->query->tcplen);
+
+ /* Account... */
+#ifndef INET6
+ STATUP(data->nsd, ctcp);
+#else
+ if (data->query->addr.ss_family == AF_INET) {
+ STATUP(data->nsd, ctcp);
+ } else if (data->query->addr.ss_family == AF_INET6) {
+ STATUP(data->nsd, ctcp6);
+ }
+#endif
+
+ /* We have a complete query, process it. */
+
+ /* tcp-query-count: handle query counter ++ */
+ data->query_count++;
+
+ buffer_flip(data->query->packet);
+ data->query_state = server_process_query(data->nsd, data->query);
+ if (data->query_state == QUERY_DISCARDED) {
+ /* Drop the packet and the entire connection... */
+ STATUP(data->nsd, dropped);
+ cleanup_tcp_handler(data);
+ return;
+ }
+
+ if (RCODE(data->query->packet) == RCODE_OK
+ && !AA(data->query->packet))
+ {
+ STATUP(data->nsd, nona);
+ }
+
+ query_add_optional(data->query, data->nsd);
+
+ /* Switch to the tcp write handler. */
+ buffer_flip(data->query->packet);
+ data->query->tcplen = buffer_remaining(data->query->packet);
+ data->bytes_transmitted = 0;
+
+ tcp_handler_setup_event(data, handle_tls_writing, fd, EV_PERSIST | EV_WRITE | EV_TIMEOUT);
+
+ /* see if we can write the answer right away(usually so,EAGAIN ifnot)*/
+ handle_tls_writing(fd, EV_WRITE, data);
+}
+
+/** handle TLS writing of outgoing response */
+static void
+handle_tls_writing(int fd, short event, void* arg)
+{
+ struct tcp_handler_data *data = (struct tcp_handler_data *) arg;
+ ssize_t sent;
+ struct query *q = data->query;
+ buffer_type* write_buffer;
+ region_type* region;
+
+ if ((event & EV_TIMEOUT)) {
+ /* Connection timed out. */
+ cleanup_tcp_handler(data);
+ return;
+ }
+
+ assert((event & EV_WRITE));
+
+ if(data->shake_state != tls_hs_none) {
+ if(!tls_handshake(data, fd))
+ return;
+ if(data->shake_state != tls_hs_none)
+ return;
+ }
+
+ (void)SSL_set_mode(data->tls, SSL_MODE_ENABLE_PARTIAL_WRITE);
+
+ /* If we are writng the start of a message, we must include the length
+ * For now, create a new buffer with the length prepended. This is very
+ * inefficient and should be optimised. This could be done best by creating
+ * a wrapper for the underlying message buffer.*/
+ write_buffer = NULL;
+ region = NULL;
+ if (data->bytes_transmitted == 0) {
+ region = region_create(xalloc, free);
+ write_buffer = buffer_create(region, buffer_limit(q->packet) + sizeof(q->tcplen));
+ if (!write_buffer) {
+ return;
+ }
+ buffer_write_u16(write_buffer, q->tcplen);
+ buffer_write(write_buffer, buffer_current(q->packet),
+ (int)buffer_remaining(q->packet));
+ buffer_flip(write_buffer);
+ } else {
+ write_buffer = q->packet;
+ }
+
+ /* Write the response */
+ ERR_clear_error();
+ sent = SSL_write(data->tls, buffer_current(write_buffer), buffer_remaining(write_buffer));
+ if(sent <= 0) {
+ int want = SSL_get_error(data->tls, sent);
+ if(want == SSL_ERROR_ZERO_RETURN) {
+ cleanup_tcp_handler(data);
+ /* closed */
+ } else if(want == SSL_ERROR_WANT_READ) {
+ /* switch back to reading */
+ data->shake_state = tls_hs_read;
+ tcp_handler_setup_event(data, handle_tls_reading, fd, EV_PERSIST | EV_READ | EV_TIMEOUT);
+ } else if(want != SSL_ERROR_WANT_WRITE) {
+ cleanup_tcp_handler(data);
+ log_crypto_err("could not SSL_write");
+ }
+ if (data->bytes_transmitted == 0 && write_buffer != NULL) {
+ region_destroy(region);
+ }
+ return;
+ }
+
+ buffer_skip(write_buffer, sent);
+ if(buffer_remaining(write_buffer) != 0) {
+ /* If not all sent, sync up the real buffer if it wasn't used.*/
+ if (data->bytes_transmitted == 0 && (ssize_t)sent > sizeof(q->tcplen)) {
+ buffer_skip(q->packet, (ssize_t)sent - sizeof(q->tcplen));
+ }
+ }
+
+ if (data->bytes_transmitted == 0 && write_buffer != NULL)
+ region_destroy(region);
+
+ data->bytes_transmitted += sent;
+ if (data->bytes_transmitted < q->tcplen + sizeof(q->tcplen)) {
+ /*
+ * Still more data to write when socket becomes
+ * writable again.
+ */
+ return;
+ }
+
+ assert(data->bytes_transmitted == q->tcplen + sizeof(q->tcplen));
+
+ if (data->query_state == QUERY_IN_AXFR) {
+ /* Continue processing AXFR and writing back results. */
+ buffer_clear(q->packet);
+ data->query_state = query_axfr(data->nsd, q);
+ if (data->query_state != QUERY_PROCESSED) {
+ query_add_optional(data->query, data->nsd);
+
+ /* Reset data. */
+ buffer_flip(q->packet);
+ q->tcplen = buffer_remaining(q->packet);
+ data->bytes_transmitted = 0;
+ /* Reset to writing mode. */
+ tcp_handler_setup_event(data, handle_tls_writing, fd, EV_PERSIST | EV_WRITE | EV_TIMEOUT);
+
+ /*
+ * Write data if/when the socket is writable
+ * again.
+ */
+ return;
+ }
+ }
+
+ /*
+ * Done sending, wait for the next request to arrive on the
+ * TCP socket by installing the TCP read handler.
+ */
+ if (data->nsd->tcp_query_count > 0 &&
+ data->query_count >= data->nsd->tcp_query_count) {
+
+ (void) shutdown(fd, SHUT_WR);
+ }
+
+ data->bytes_transmitted = 0;
+ data->query->first_query = 0;
+
+ tcp_handler_setup_event(data, handle_tls_reading, fd, EV_PERSIST | EV_READ | EV_TIMEOUT);
+}
+#endif
static void
handle_slowaccept_timeout(int ATTR_UNUSED(fd), short ATTR_UNUSED(event),
@@ -2949,8 +3564,23 @@ handle_tcp_accept(int fd, short event, v
timeout.tv_sec = tcp_data->tcp_timeout / 1000;
timeout.tv_usec = (tcp_data->tcp_timeout % 1000)*1000;
- event_set(&tcp_data->event, s, EV_PERSIST | EV_READ | EV_TIMEOUT,
- handle_tcp_reading, tcp_data);
+#ifdef HAVE_SSL
+ if (data->tls_accept) {
+ tcp_data->tls = incoming_ssl_fd(tcp_data->nsd->tls_ctx, s);
+ if(!tcp_data->tls) {
+ close(s);
+ return;
+ }
+ tcp_data->shake_state = tls_hs_read;
+ event_set(&tcp_data->event, s, EV_PERSIST | EV_READ | EV_TIMEOUT,
+ handle_tls_reading, tcp_data);
+ } else {
+#endif
+ event_set(&tcp_data->event, s, EV_PERSIST | EV_READ | EV_TIMEOUT,
+ handle_tcp_reading, tcp_data);
+#ifdef HAVE_SSL
+ }
+#endif
if(event_base_set(data->event.ev_base, &tcp_data->event) != 0) {
log_msg(LOG_ERR, "cannot set tcp event base");
close(s);
_______________________________________________
dns-privacy mailing list
[email protected]
https://www.ietf.org/mailman/listinfo/dns-privacy