]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
WiP1
authorWitold Kręcicki <wpk@isc.org>
Fri, 2 Nov 2018 20:30:56 +0000 (20:30 +0000)
committerWitold Kręcicki <wpk@isc.org>
Wed, 7 Nov 2018 12:42:25 +0000 (12:42 +0000)
aclocal.m4
bin/dig/dig.c
bin/dig/dighost.c
bin/dig/include/dig/dig.h
configure
lib/isc/include/isc/socket.h
lib/isc/tests/socket_test.c
lib/isc/unix/socket.c
m4/ax_check_openssl.m4

index 5a16166751adc92f9b57e193b1727cf24e5eba09..4d850813d6bc54361f2db00567e5b353848df44d 100644 (file)
@@ -1,6 +1,6 @@
-# generated automatically by aclocal 1.16.1 -*- Autoconf -*-
+# generated automatically by aclocal 1.15.1 -*- Autoconf -*-
 
-# Copyright (C) 1996-2018 Free Software Foundation, Inc.
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
 
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -12,9 +12,9 @@
 # PARTICULAR PURPOSE.
 
 m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
-# pkg.m4 - Macros to locate and utilise pkg-config.   -*- Autoconf -*-
-# serial 12 (pkg-config-0.29.2)
-
+dnl pkg.m4 - Macros to locate and utilise pkg-config.   -*- Autoconf -*-
+dnl serial 11 (pkg-config-0.29.1)
+dnl
 dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
 dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
 dnl
@@ -55,7 +55,7 @@ dnl
 dnl See the "Since" comment for each macro you use to see what version
 dnl of the macros you require.
 m4_defun([PKG_PREREQ],
-[m4_define([PKG_MACROS_VERSION], [0.29.2])
+[m4_define([PKG_MACROS_VERSION], [0.29.1])
 m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
     [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
 ])dnl PKG_PREREQ
@@ -156,7 +156,7 @@ AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
 AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
 
 pkg_failed=no
-AC_MSG_CHECKING([for $2])
+AC_MSG_CHECKING([for $1])
 
 _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
 _PKG_CONFIG([$1][_LIBS], [libs], [$2])
@@ -166,11 +166,11 @@ and $1[]_LIBS to avoid the need to call pkg-config.
 See the pkg-config man page for more details.])
 
 if test $pkg_failed = yes; then
-        AC_MSG_RESULT([no])
+       AC_MSG_RESULT([no])
         _PKG_SHORT_ERRORS_SUPPORTED
         if test $_pkg_short_errors_supported = yes; then
                $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
-        else
+        else 
                $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
         fi
        # Put the nasty error message in config.log where it belongs
@@ -187,7 +187,7 @@ installed software in a non-standard prefix.
 _PKG_TEXT])[]dnl
         ])
 elif test $pkg_failed = untried; then
-        AC_MSG_RESULT([no])
+       AC_MSG_RESULT([no])
        m4_default([$4], [AC_MSG_FAILURE(
 [The pkg-config script could not be found or is too old.  Make sure it
 is in your PATH or set the PKG_CONFIG environment variable to the full
index 47d18ae331bfba60081ae3b8507e27d7be7e5cc7..6926dd4d48ecf5f10985b167b21bda01184e9400 100644 (file)
@@ -263,6 +263,9 @@ received(unsigned int bytes, isc_sockaddr_t *from, dig_query_t *query) {
                else
                        printf(";; Query time: %ld msec\n", (long) diff / 1000);
                printf(";; SERVER: %s(%s)\n", fromtext, query->servname);
+               if (query->servssldigest != NULL) {
+                       printf(";; DNSoTLS cert digest: %s\n", query->servssldigest);
+               }
                time(&tnow);
 #if !defined(WIN32)
                (void)localtime_r(&tnow, &tmnow);
@@ -920,6 +923,18 @@ plus_option(char *option, bool is_batchfile,
                case 'o': /* domain ... but treat "do" as synonym for dnssec */
                        if (cmd[2] == '\0')
                                goto dnssec;
+                       if (cmd[2] == 't') {
+                               FULLCHECK("dot");
+                               if (!is_batchfile) {
+                                       lookup->tcp_mode = true;
+                                       lookup->dot_mode = state;
+                                       lookup->dot_mode_set = true;
+                                       if (!explicit_port) {
+                                               port = 853;
+                                       }
+                               }
+                               break;
+                       }
                        FULLCHECK("domain");
                        if (value == NULL)
                                goto need_value;
@@ -1692,6 +1707,7 @@ dash_option(char *option, char *next, dig_lookup_t **lookup,
                result = parse_uint(&num, value, MAXPORT, "port number");
                if (result != ISC_R_SUCCESS)
                        fatal("Couldn't parse port number");
+               explicit_port = true;
                port = num;
                return (value_from_next);
        case 'q':
index 4daddbda7e3a9e61693e4482a730e158373058d2..b1344886354fa442c5f45e94ebf70e520921de7b 100644 (file)
@@ -114,7 +114,8 @@ bool
        showsearch = false,
        is_dst_up = false,
        keep_open = false,
-       verbose = false;
+       verbose = false,
+       explicit_port = false;
 in_port_t port = 53;
 unsigned int timeout = 0;
 unsigned int extrabytes;
@@ -649,6 +650,8 @@ make_empty_lookup(void) {
        looknew->nsfound = 0;
        looknew->tcp_mode = false;
        looknew->tcp_mode_set = false;
+       looknew->dot_mode = false;
+       looknew->dot_mode_set = false;
        looknew->comments = true;
        looknew->stats = true;
        looknew->section_question = true;
@@ -787,6 +790,8 @@ clone_lookup(dig_lookup_t *lookold, bool servers) {
        looknew->ns_search_only = lookold->ns_search_only;
        looknew->tcp_mode = lookold->tcp_mode;
        looknew->tcp_mode_set = lookold->tcp_mode_set;
+       looknew->dot_mode = lookold->dot_mode;
+       looknew->dot_mode_set = lookold->dot_mode_set;
        looknew->comments = lookold->comments;
        looknew->stats = lookold->stats;
        looknew->section_question = lookold->section_question;
@@ -1541,7 +1546,11 @@ clear_query(dig_query_t *query) {
        isc_mempool_put(commctx, query->tmpsendspace);
        isc_buffer_invalidate(&query->recvbuf);
        isc_buffer_invalidate(&query->lengthbuf);
-       if (query->waiting_senddone)
+       if (query->servssldigest != NULL) {
+               isc_mem_free(mctx, query->servssldigest);
+       }
+
+       if (query->waiting_senddone) {
                query->pending_free = true;
        else
                isc_mem_free(mctx, query);
@@ -2474,6 +2483,7 @@ setup_lookup(dig_lookup_t *lookup) {
                query->first_rr_serial = 0;
                query->second_rr_serial = 0;
                query->servname = serv->servername;
+               query->servssldigest = NULL;
                query->userarg = serv->userarg;
                query->rr_count = 0;
                query->msg_count = 0;
@@ -2717,6 +2727,7 @@ send_tcp_connect(dig_query_t *query) {
 
        result = isc_socket_create(socketmgr,
                                   isc_sockaddr_pf(&query->sockaddr),
+                                  query->lookup->dot_mode ? isc_sockettype_tls :
                                   isc_sockettype_tcp, &query->sock);
        check_result(result, "isc_socket_create");
        sockcount++;
@@ -3163,6 +3174,11 @@ connect_done(isc_task_t *task, isc_event_t *event) {
                return;
        }
        exitcode = 0;
+       query->servssldigest = isc_mem_allocate(mctx, 4096);
+       if (isc_socket_getsslhexdigest(query->sock, query->servssldigest, 4096) != ISC_R_SUCCESS) {
+               isc_mem_free(mctx, query->servssldigest);
+               query->servssldigest = NULL;
+       }
        if (keep_open) {
                if (keep != NULL)
                        isc_socket_detach(&keep);
index a224c705a311ae6d00213e42caab10905c647c06..d901aaedaa5a5e6ad01591d36a17384dcb9ab802 100644 (file)
@@ -101,6 +101,8 @@ struct dig_lookup {
                zflag,
                trace, /*% dig +trace */
                trace_root, /*% initial query for either +trace or +nssearch */
+               dot_mode,
+               dot_mode_set,
                tcp_mode,
                tcp_mode_set,
                comments,
@@ -201,6 +203,7 @@ struct dig_query {
        uint32_t rr_count;
        bool ixfr_axfr;
        char *servname;
+       char *servssldigest;
        char *userarg;
        isc_buffer_t recvbuf,
                lengthbuf,
@@ -242,7 +245,7 @@ extern dig_searchlistlist_t search_list;
 extern unsigned int extrabytes;
 
 extern bool check_ra, have_ipv4, have_ipv6, specified_source,
-       usesearch, showsearch;
+       usesearch, showsearch, explicit_port;
 extern in_port_t port;
 extern unsigned int timeout;
 extern isc_mem_t *mctx;
index b6a780f78f879cdc804740ba676872d5c38069bd..a258f9213bc5247e176b8a7c9d9817cf2db0314e 100755 (executable)
--- a/configure
+++ b/configure
@@ -15407,8 +15407,8 @@ else
             # then use that information and don't search ssldirs
 
 pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for crypto" >&5
-$as_echo_n "checking for crypto... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OPENSSL" >&5
+$as_echo_n "checking for OPENSSL... " >&6; }
 
 if test -n "$OPENSSL_CFLAGS"; then
     pkg_cv_OPENSSL_CFLAGS="$OPENSSL_CFLAGS"
@@ -15448,7 +15448,7 @@ fi
 
 
 if test $pkg_failed = yes; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 
 if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
@@ -15466,7 +15466,7 @@ fi
 
        ssldirs="$default_ssldirs"
 elif test $pkg_failed = untried; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
        ssldirs="$default_ssldirs"
 else
@@ -15495,7 +15495,7 @@ $as_echo_n "checking for openssl/ssl.h in $ssldir... " >&6; }
            if test -f "$ssldir/include/openssl/ssl.h"; then :
 
                    OPENSSL_INCLUDES="-I$ssldir/include"
-                    OPENSSL_LIBS="-L$ssldir/lib -lcrypto"
+                    OPENSSL_LIBS="-L$ssldir/lib -lcrypto -lssl"
                     found=true
                     { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
@@ -19420,8 +19420,8 @@ case $with_libidn2 in #(
   yes) :
 
 pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libidn2" >&5
-$as_echo_n "checking for libidn2... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBIDN2" >&5
+$as_echo_n "checking for LIBIDN2... " >&6; }
 
 if test -n "$LIBIDN2_CFLAGS"; then
     pkg_cv_LIBIDN2_CFLAGS="$LIBIDN2_CFLAGS"
@@ -19461,7 +19461,7 @@ fi
 
 
 if test $pkg_failed = yes; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 
 if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
@@ -19488,7 +19488,7 @@ Alternatively, you may set the environment variables LIBIDN2_CFLAGS
 and LIBIDN2_LIBS to avoid the need to call pkg-config.
 See the pkg-config man page for more details." "$LINENO" 5
 elif test $pkg_failed = untried; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
        { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
@@ -19628,8 +19628,8 @@ case $with_cmocka in #(
   yes) :
 
 pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for cmocka >= 1.0.0" >&5
-$as_echo_n "checking for cmocka >= 1.0.0... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for CMOCKA" >&5
+$as_echo_n "checking for CMOCKA... " >&6; }
 
 if test -n "$CMOCKA_CFLAGS"; then
     pkg_cv_CMOCKA_CFLAGS="$CMOCKA_CFLAGS"
@@ -19669,7 +19669,7 @@ fi
 
 
 if test $pkg_failed = yes; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 
 if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
@@ -19696,7 +19696,7 @@ Alternatively, you may set the environment variables CMOCKA_CFLAGS
 and CMOCKA_LIBS to avoid the need to call pkg-config.
 See the pkg-config man page for more details." "$LINENO" 5
 elif test $pkg_failed = untried; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
        { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
index 98fa51bfd6ceb72b3d8f8471ddbb3c08103843b2..8a3c96b14d2a978fee1b04ada21b10def9574fee 100644 (file)
@@ -243,7 +243,8 @@ typedef enum {
        isc_sockettype_udp = 1,
        isc_sockettype_tcp = 2,
        isc_sockettype_unix = 3,
-       isc_sockettype_raw = 4
+       isc_sockettype_raw = 4,
+       isc_sockettype_tls = 5
 } isc_sockettype_t;
 
 /*@{*/
@@ -1040,4 +1041,7 @@ typedef isc_result_t
 
 ISC_LANG_ENDDECLS
 
+isc_result_t
+isc_socket_getsslhexdigest(isc_socket_t *sock0, char *dest, unsigned int len);
+
 #endif /* ISC_SOCKET_H */
index 1bfe65f3a2aa34835072ec8ce3b16f7cd2ae38bb..68ebffbe7f29973fd28ff6f4a2c354ff312d14de 100644 (file)
@@ -879,6 +879,96 @@ ATF_TC_BODY(udp_trunc, tc) {
        isc_test_end();
 }
 
+/* Test TCP ssl sendto/recv */
+ATF_TC(tls);
+ATF_TC_HEAD(tls, tc) {
+       atf_tc_set_md_var(tc, "descr", "tls");
+}
+ATF_TC_BODY(tls, tc) {
+       isc_result_t result;
+       isc_sockaddr_t addr1;
+       struct in_addr in;
+       isc_socket_t *s1 = NULL, *s2 = NULL, *s3 = NULL;
+       isc_task_t *task = NULL;
+       char sendbuf[BUFSIZ], recvbuf[BUFSIZ];
+       completion_t completion, completion2;
+       isc_region_t r;
+
+       UNUSED(tc);
+
+       result = isc_test_begin(NULL, true, 0);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       in.s_addr = inet_addr("127.0.0.1");
+       isc_sockaddr_fromin(&addr1, &in, 0);
+
+       result = isc_socket_create(socketmgr, PF_INET, isc_sockettype_tls, &s1);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       result = isc_socket_bind(s1, &addr1, 0);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+       result = isc_socket_getsockname(s1, &addr1);
+       ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s",
+                        isc_result_totext(result));
+       ATF_REQUIRE(isc_sockaddr_getport(&addr1) != 0);
+
+       result = isc_socket_listen(s1, 3);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       result = isc_socket_create(socketmgr, PF_INET, isc_sockettype_tls, &s2);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       result = isc_task_create(taskmgr, 0, &task);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       completion_init(&completion2);
+       result = isc_socket_accept(s1, task, accept_done, &completion2);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       completion_init(&completion);
+       result = isc_socket_connect(s2, &addr1, task, event_done, &completion);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+       waitfor2(&completion, &completion2);
+       ATF_CHECK(completion.done);
+       ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS);
+       ATF_CHECK(completion2.done);
+       ATF_CHECK_EQ(completion2.result, ISC_R_SUCCESS);
+       s3 = completion2.socket;
+
+       snprintf(sendbuf, sizeof(sendbuf), "Hello");
+       r.base = (void *) sendbuf;
+       r.length = strlen(sendbuf) + 1;
+
+       recv_dscp = false;
+       recv_dscp_value = 0;
+
+       completion_init(&completion);
+       result = isc_socket_sendto(s2, &r, task, event_done, &completion,
+                                  NULL, NULL);
+       ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+       waitfor(&completion);
+       ATF_CHECK(completion.done);
+       ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS);
+
+       r.base = (void *) recvbuf;
+       r.length = BUFSIZ;
+       completion_init(&completion);
+       result = isc_socket_recv(s3, &r, 1, task, event_done, &completion);
+       ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+       waitfor(&completion);
+       ATF_CHECK(completion.done);
+       ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS);
+       ATF_CHECK_STREQ(recvbuf, "Hello");
+
+       isc_task_detach(&task);
+
+       isc_socket_detach(&s1);
+       isc_socket_detach(&s2);
+       isc_socket_detach(&s3);
+
+       isc_test_end();
+}
+
 /*
  * Main
  */
@@ -891,6 +981,7 @@ ATF_TP_ADD_TCS(tp) {
        ATF_TP_ADD_TC(tp, udp_dscp_v6);
        ATF_TP_ADD_TC(tp, net_probedscp);
        ATF_TP_ADD_TC(tp, udp_trunc);
+       ATF_TP_ADD_TC(tp, tls);
 
        return (atf_no_error());
 }
index 6bad341a2e035110d5450f901a0934b8d4bf5dd6..6d2d78f445156dd8e5d52cf5474933b2557ac960 100644 (file)
@@ -31,6 +31,8 @@
 #include <linux/rtnetlink.h>
 #endif
 
+#include <openssl/ssl.h>
+
 #include <errno.h>
 #include <fcntl.h>
 #include <stddef.h>
@@ -41,6 +43,7 @@
 #include <isc/buffer.h>
 #include <isc/condition.h>
 #include <isc/formatcheck.h>
+#include <isc/hex.h>
 #include <isc/json.h>
 #include <isc/list.h>
 #include <isc/log.h>
@@ -331,6 +334,20 @@ typedef struct isc__socketthread isc__socketthread_t;
 
 #define NEWCONNSOCK(ev) ((isc__socket_t *)(ev)->newsocket)
 
+/*
+ * When using TLS read() might require write() on the underlying
+ * socket, and write() might require read() on the underlying socket.
+ * To trace this properly we have a 'tlsstate' field in the socket
+ * that's a combination of the fields below.
+ * 'write' here also includes SSL_connect, and 'read' includes SSL_accept.
+ */
+
+#define TLSSTATE_RWR   0x0001  /* Read Wants to Read */
+#define TLSSTATE_RWW   0x0002  /* Read Wants to Write */
+#define TLSSTATE_WWR   0x0004  /* Write Wants to Read */
+#define TLSSTATE_WWW   0x0008  /* Write Wants to Write */
+
+
 struct isc__socket {
        /* Not locked. */
        isc_socket_t            common;
@@ -353,15 +370,21 @@ struct isc__socket {
        ISC_LIST(isc_socket_newconnev_t)        accept_list;
        ISC_LIST(isc_socket_connev_t)           connect_list;
 
-       isc_sockaddr_t          peer_address;       /* remote address */
+       SSL *                   ssl;
+
+       isc_sockaddr_t          peer_address;      /* remote address */
 
-       unsigned int            listener : 1,       /* listener socket */
+       unsigned int            listener : 1,      /* listener socket */
                                connected : 1,
-                               connecting : 1,     /* connect pending */
-                               bound : 1,          /* bound to local addr */
+                               connecting : 1,    /* connect pending */
+                               bound : 1,         /* bound to local addr */
                                dupped : 1,
-                               active : 1,         /* currently active */
-                               pktdscp : 1;        /* per packet dscp */
+                               active : 1,        /* currently active */
+                               pktdscp : 1,       /* per packet dscp */
+                               tlsconnecting : 1, /* waiting for TLS conn */
+                               tlsaccepting : 1;  /* waiting for TLS accept */
+
+       int                     tlsstate;
 
 #ifdef ISC_PLATFORM_RECVOVERFLOW
        unsigned char           overflow; /* used for MSG_TRUNC fake */
@@ -464,6 +487,10 @@ static void build_msghdr_recv(isc__socket_t *, char *, isc_socketevent_t *,
                              struct msghdr *, struct iovec *, size_t *);
 static bool process_ctlfd(isc__socketthread_t *thread);
 static void setdscp(isc__socket_t *sock, isc_dscp_t dscp);
+static void internal_tls_accept(isc__socket_t *);
+static void internal_tls_connect(isc__socket_t *);
+static void internal_tls_recv(isc__socket_t *);
+static void internal_tls_send(isc__socket_t *);
 
 #define SELECT_POKE_SHUTDOWN           (-1)
 #define SELECT_POKE_NOTHING            (-2)
@@ -1776,6 +1803,104 @@ doio_send(isc__socket_t *sock, isc_socketevent_t *dev) {
        return (DOIO_SUCCESS);
 }
 
+static int
+doio_tls_recv(isc__socket_t *sock, isc_socketevent_t *dev) {
+       int cc;
+       size_t read_count;
+       void *read_base;
+
+       read_count = dev->region.length - dev->n;
+       read_base = (void *)(dev->region.base + dev->n);
+       dev->address = sock->peer_address;
+
+       cc = SSL_read(sock->ssl, read_base, read_count);
+       printf("SSL read res %d\n", cc);
+       if (cc <= 0) {
+               int err = SSL_get_error(sock->ssl, cc);
+               printf("err %d\n", err);
+               if (err == SSL_ERROR_WANT_READ) {
+                       sock->tlsstate |= TLSSTATE_RWR;
+                       dev->result = ISC_R_WOULDBLOCK;
+                       return (DOIO_SOFT);
+               } else if (err == SSL_ERROR_WANT_WRITE) {
+                       sock->tlsstate |= TLSSTATE_RWW;
+                       dev->result = ISC_R_WOULDBLOCK;
+                       return (DOIO_SOFT);
+               } else {
+                       printf("Hard err in read %d\n", cc);
+                       return (DOIO_HARD);
+               }
+       }
+       if (cc == 0) {
+               return (DOIO_EOF);
+       }
+
+       dev->n += cc;
+       /*
+        * If we have a partial read we need to watch the socket
+        */
+       if (((size_t)cc != read_count) && (dev->n < dev->minimum)) {
+               sock->tlsstate |= TLSSTATE_RWR;
+               return (DOIO_SOFT);
+       }
+
+       /*
+        * Full reads are posted, or partials if partials are ok.
+        */
+       dev->result = ISC_R_SUCCESS;
+       return (DOIO_SUCCESS);
+}
+
+/*
+ * Returns:
+ *     DOIO_SUCCESS    The operation succeeded.  dev->result contains
+ *                     ISC_R_SUCCESS.
+ *
+ *     DOIO_HARD       A hard or unexpected I/O error was encountered.
+ *                     dev->result contains the appropriate error.
+ *
+ *     DOIO_SOFT       A soft I/O error was encountered.  No senddone
+ *                     event was sent.  The operation should be retried.
+ *
+ *     No other return values are possible.
+ */
+static int
+doio_tls_send(isc__socket_t *sock, isc_socketevent_t *dev) {
+       int cc;
+       size_t write_count;
+       char *send_base;
+
+       write_count = dev->region.length - dev->n;
+       send_base = (void *) (dev->region.base + dev->n);
+
+       cc = SSL_write(sock->ssl, send_base, write_count);
+       printf("SSL write res %d\n", cc);
+       if (cc <= 0) {
+               int err = SSL_get_error(sock->ssl, cc);
+               printf("err %d\n", err);
+               if (err == SSL_ERROR_WANT_READ) {
+                       sock->tlsstate |= TLSSTATE_WWR;
+                       dev->result = ISC_R_WOULDBLOCK;
+                       return (DOIO_SOFT);
+               } else if (err == SSL_ERROR_WANT_WRITE) {
+                       sock->tlsstate |= TLSSTATE_WWW;
+                       dev->result = ISC_R_WOULDBLOCK;
+                       return (DOIO_SOFT);
+               } else {
+                       /* XXXWPK TODO log specific error */
+                       return (DOIO_HARD);
+               }
+       }
+       /*
+        * With SSL with no SSL_MODE_ENABLE_PARTIAL_WRITE writes are
+        * always complete.
+        */
+       dev->n += cc;
+
+       dev->result = ISC_R_SUCCESS;
+       return (DOIO_SUCCESS);
+}
+
 /*
  * Kill.
  *
@@ -1892,6 +2017,11 @@ allocate_socket(isc__socketmgr_t *manager, isc_sockettype_t type,
        sock->statsindex = NULL;
        sock->active = 0;
 
+       sock->tlsconnecting = 0;
+       sock->tlsaccepting = 0;
+       sock->tlsstate = 0;
+       sock->ssl = NULL;
+
        ISC_LINK_INIT(sock, link);
 
 
@@ -2171,6 +2301,7 @@ opensocket(isc__socketmgr_t *manager, isc__socket_t *sock,
                        sock->fd = socket(sock->pf, SOCK_DGRAM, IPPROTO_UDP);
                        break;
                case isc_sockettype_tcp:
+               case isc_sockettype_tls:
                        sock->fd = socket(sock->pf, SOCK_STREAM, IPPROTO_TCP);
                        break;
                case isc_sockettype_unix:
@@ -2561,6 +2692,7 @@ socket_create(isc_socketmgr_t *manager0, int pf, isc_sockettype_t type,
                sock->pktdscp = (isc_net_probedscp() & DCSPPKT(pf)) != 0;
                break;
        case isc_sockettype_tcp:
+       case isc_sockettype_tls: /* XXXWPK TODO */
                sock->statsindex =
                        (pf == AF_INET) ? tcp4statsindex : tcp6statsindex;
                break;
@@ -3113,6 +3245,8 @@ internal_accept(isc__socket_t *sock) {
        return;
 }
 
+static void internal_tls_accept(isc__socket_t *sock) { UNUSED(sock); abort(); };
+
 static void
 internal_recv(isc__socket_t *sock) {
        isc_socketevent_t *dev;
@@ -3207,6 +3341,124 @@ internal_send(isc__socket_t *sock) {
        UNLOCK(&sock->lock);
 }
 
+static void
+watch_unwatch(isc__socket_t *sock, bool wanted_read, bool wanted_write) {
+       if (wanted_read && !(sock->tlsstate & (TLSSTATE_RWR | TLSSTATE_WWR))) {
+               unwatch_fd(&sock->manager->threads[sock->threadid], sock->fd,
+                          SELECT_POKE_READ);
+       } else if (!wanted_read && (sock->tlsstate & (TLSSTATE_RWR | TLSSTATE_WWR))) {
+               watch_fd(&sock->manager->threads[sock->threadid], sock->fd,
+                        SELECT_POKE_READ);
+       }
+
+       if (wanted_write && !(sock->tlsstate & (TLSSTATE_RWW | TLSSTATE_WWW))) {
+               unwatch_fd(&sock->manager->threads[sock->threadid], sock->fd,
+                          SELECT_POKE_WRITE);
+       } else if (!wanted_write && (sock->tlsstate & (TLSSTATE_RWW | TLSSTATE_WWW))) {
+               watch_fd(&sock->manager->threads[sock->threadid], sock->fd,
+                        SELECT_POKE_READ);
+       }
+}
+
+static void
+internal_tls_recv(isc__socket_t *sock) {
+       isc_socketevent_t *dev = NULL;
+
+       INSIST(VALID_SOCKET(sock));
+
+       LOCK(&sock->lock);
+       bool wanted_read = sock->tlsstate & (TLSSTATE_RWR | TLSSTATE_WWR);
+       bool wanted_write = sock->tlsstate & (TLSSTATE_RWW | TLSSTATE_WWW);
+       sock->tlsstate &= ~(TLSSTATE_RWR | TLSSTATE_RWW);
+
+       dev = ISC_LIST_HEAD(sock->recv_list);
+
+       if (dev == NULL) {
+               goto finish;
+               return;
+       }
+
+       socket_log(sock, NULL, IOEVENT,
+                  isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALRECV,
+                  "internal_recv: event %p -> task %p", dev, dev->ev_sender);
+
+       /*
+        * Try to do as much I/O as possible on this socket.  There are no
+        * limits here, currently.
+        */
+       while (dev != NULL) {
+               switch (doio_tls_recv(sock, dev)) {
+               case DOIO_SOFT:
+                       goto finish;
+
+               case DOIO_EOF:
+                       /*
+                        * read of 0 means the remote end was closed.
+                        * Run through the event queue and dispatch all
+                        * the events with an EOF result code.
+                        */
+                       do {
+                               dev->result = ISC_R_EOF;
+                               send_recvdone_event(sock, &dev);
+                               dev = ISC_LIST_HEAD(sock->recv_list);
+                       } while (dev != NULL);
+                       goto finish;
+
+               case DOIO_SUCCESS:
+               case DOIO_HARD:
+                       send_recvdone_event(sock, &dev);
+                       break;
+               }
+
+               dev = ISC_LIST_HEAD(sock->recv_list);
+       }
+
+ finish:
+       watch_unwatch(sock, wanted_read, wanted_write);
+       UNLOCK(&sock->lock);
+}
+
+static void
+internal_tls_send(isc__socket_t *sock) {
+       isc_socketevent_t *dev;
+
+       INSIST(VALID_SOCKET(sock));
+
+       LOCK(&sock->lock);
+       bool wanted_read = sock->tlsstate & (TLSSTATE_RWR | TLSSTATE_WWR);
+       bool wanted_write = sock->tlsstate & (TLSSTATE_RWW | TLSSTATE_WWW);
+       sock->tlsstate &= ~(TLSSTATE_WWR | TLSSTATE_WWW);
+       dev = ISC_LIST_HEAD(sock->send_list);
+       if (dev == NULL) {
+               goto finish;
+       }
+       socket_log(sock, NULL, EVENT, NULL, 0, 0,
+                  "internal_send:  event %p -> task %p",
+                  dev, dev->ev_sender);
+
+       /*
+        * Try to do as much I/O as possible on this socket.  There are no
+        * limits here, currently.
+        */
+       while (dev != NULL) {
+               switch (doio_tls_send(sock, dev)) {
+               case DOIO_SOFT:
+                       goto finish;
+
+               case DOIO_HARD:
+               case DOIO_SUCCESS:
+                       send_senddone_event(sock, &dev);
+                       break;
+               }
+
+               dev = ISC_LIST_HEAD(sock->send_list);
+       }
+
+ finish:
+       watch_unwatch(sock, wanted_read, wanted_write);
+       UNLOCK(&sock->lock);
+}
+
 /*
  * Process read/writes on each fd here.  Avoid locking
  * and unlocking twice if both reads and writes are possible.
@@ -3241,18 +3493,49 @@ process_fd(isc__socketthread_t *thread, int fd, bool readable,
 
        isc_refcount_increment(&sock->references);
 
+       printf("process_fd sock->type %d readable %d writeable %d connecting %d\n", sock->type, readable, writeable, sock->connecting);
+       if (!sock->listener && !sock->connecting && sock->type == isc_sockettype_tls) {
+               if (readable) {
+                       if (sock->tlsstate & TLSSTATE_RWR) {
+                               if (sock->tlsaccepting) {
+                                       internal_tls_accept(sock);
+                               } else {
+                                       internal_tls_recv(sock);
+                               }
+                       }
+                       if (sock->tlsstate & TLSSTATE_WWR) {
+                               if (sock->tlsconnecting) {
+                                       internal_tls_connect(sock);
+                               } else {
+                                       internal_tls_send(sock);
+                               }
+                       }
+               }
+               if (writeable) {
+                       if (sock->tlsstate & TLSSTATE_RWW) {
+                               internal_tls_recv(sock);
+                       }
+                       if (sock->tlsstate & TLSSTATE_WWW) {
+                               internal_tls_send(sock);
+                       }
+               }
+               goto unlock_fd;
+       }
+
        if (readable) {
-               if (sock->listener)
+               if (sock->listener) {
                        internal_accept(sock);
-               else
+               } else {
                        internal_recv(sock);
+               }
        }
 
        if (writeable) {
-               if (sock->connecting)
+               if (sock->connecting) {
                        internal_connect(sock);
-               else
+               } else {
                        internal_send(sock);
+               }
        }
 
  unlock_fd:
@@ -4075,6 +4358,7 @@ static isc_result_t
 socket_recv(isc__socket_t *sock, isc_socketevent_t *dev, isc_task_t *task,
            unsigned int flags)
 {
+       printf("socket recv\n");
        int io_state;
        bool have_lock = false;
        isc_task_t *ntask = NULL;
@@ -4088,14 +4372,21 @@ socket_recv(isc__socket_t *sock, isc_socketevent_t *dev, isc_task_t *task,
                LOCK(&sock->lock);
                have_lock = true;
 
-               if (ISC_LIST_EMPTY(sock->recv_list))
-                       io_state = doio_recv(sock, dev);
-               else
+               if (ISC_LIST_EMPTY(sock->recv_list)) {
+                       if (sock->type == isc_sockettype_tls) {
+                               printf("Direct recv\n");
+                               io_state = doio_tls_recv(sock, dev);
+                       } else {
+                               io_state = doio_recv(sock, dev);
+                       }
+               } else {
                        io_state = DOIO_SOFT;
+               }
        }
 
        switch (io_state) {
        case DOIO_SOFT:
+               printf("Soft\n");
                /*
                 * We couldn't read all or part of the request right now, so
                 * queue it.
@@ -4114,12 +4405,19 @@ socket_recv(isc__socket_t *sock, isc_socketevent_t *dev, isc_task_t *task,
                 * Enqueue the request.  If the socket was previously not being
                 * watched, poke the watcher to start paying attention to it.
                 */
-               bool do_poke = ISC_LIST_EMPTY(sock->recv_list);
+               bool do_poke_read = sock->type == isc_sockettype_tls ?
+                                   sock->tlsstate & (TLSSTATE_RWR | TLSSTATE_WWR)  :
+                                   ISC_LIST_EMPTY(sock->recv_list);
+               bool do_poke_write = sock->tlsstate & (TLSSTATE_RWW | TLSSTATE_WWW);
                ISC_LIST_ENQUEUE(sock->recv_list, dev, ev_link);
-               if (do_poke) {
+               if (do_poke_read) {
                        select_poke(sock->manager, sock->threadid, sock->fd,
                                    SELECT_POKE_READ);
                }
+               if (do_poke_write) {
+                       select_poke(sock->manager, sock->threadid, sock->fd,
+                                   SELECT_POKE_WRITE);
+               }
 
                socket_log(sock, NULL, EVENT, NULL, 0, 0,
                           "socket_recv: event %p -> task %p",
@@ -4135,6 +4433,7 @@ socket_recv(isc__socket_t *sock, isc_socketevent_t *dev, isc_task_t *task,
 
        case DOIO_HARD:
        case DOIO_SUCCESS:
+               printf("Succ\n");
                if ((flags & ISC_SOCKFLAG_IMMEDIATE) == 0)
                        send_recvdone_event(sock, &dev);
                break;
@@ -4232,16 +4531,21 @@ socket_send(isc__socket_t *sock, isc_socketevent_t *dev, isc_task_t *task,
                }
        }
 
-       if (sock->type == isc_sockettype_udp)
+       if (sock->type == isc_sockettype_udp) {
                io_state = doio_send(sock, dev);
-       else {
+       else {
                LOCK(&sock->lock);
                have_lock = true;
 
-               if (ISC_LIST_EMPTY(sock->send_list))
-                       io_state = doio_send(sock, dev);
-               else
+               if (ISC_LIST_EMPTY(sock->send_list)) {
+                       if (sock->type == isc_sockettype_tls) {
+                               io_state = doio_tls_send(sock, dev);
+                       } else {
+                               io_state = doio_send(sock, dev);
+                       }
+               } else {
                        io_state = DOIO_SOFT;
+               }
        }
 
        switch (io_state) {
@@ -4263,14 +4567,26 @@ socket_send(isc__socket_t *sock, isc_socketevent_t *dev, isc_task_t *task,
                         * Enqueue the request.  If the socket was previously
                         * not being watched, poke the watcher to start
                         * paying attention to it.
+                        * For TLS sockets it's the TLS code that handles
+                        * poking, as we don't know whether TLS wants to read
+                        * or write.
                         */
-                       bool do_poke = ISC_LIST_EMPTY(sock->send_list);
+                       bool do_poke_write = sock->type == isc_sockettype_tls ?
+                                            sock->tlsstate & (TLSSTATE_RWW | TLSSTATE_WWW) :
+                                            ISC_LIST_EMPTY(sock->send_list);
+                       bool do_poke_read = sock->tlsstate & (TLSSTATE_WWR | TLSSTATE_RWR);
+
                        ISC_LIST_ENQUEUE(sock->send_list, dev, ev_link);
-                       if (do_poke) {
+                       if (do_poke_write) {
                                select_poke(sock->manager, sock->threadid,
                                            sock->fd,
                                            SELECT_POKE_WRITE);
                        }
+                       if (do_poke_read) {
+                               select_poke(sock->manager, sock->threadid,
+                                           sock->fd,
+                                           SELECT_POKE_READ);
+                       }
                        socket_log(sock, NULL, EVENT, NULL, 0, 0,
                                   "socket_send: event %p -> task %p",
                                   dev, ntask);
@@ -4743,7 +5059,8 @@ isc_socket_listen(isc_socket_t *sock0, unsigned int backlog) {
        REQUIRE(!sock->listener);
        REQUIRE(sock->bound);
        REQUIRE(sock->type == isc_sockettype_tcp ||
-               sock->type == isc_sockettype_unix);
+               sock->type == isc_sockettype_unix ||
+               sock->type == isc_sockettype_tls);
 
        if (backlog == 0)
                backlog = SOMAXCONN;
@@ -4964,14 +5281,25 @@ isc_socket_connect(isc_socket_t *sock0, const isc_sockaddr_t *addr,
        if (cc == 0) {
                sock->connected = 1;
                sock->bound = 1;
-               dev->result = ISC_R_SUCCESS;
-               isc_task_sendto(task, ISC_EVENT_PTR(&dev), sock->threadid);
+               /*
+                * If socket is TLS we need to negiotate TLS before
+                * returning the socket as connected
+                */
+               if (sock->type == isc_sockettype_tls) {
+                       isc_task_attach(task, &ntask);
+                       dev->ev_sender = ntask;
+                       ISC_LIST_ENQUEUE(sock->connect_list, dev, ev_link);
+                       internal_tls_connect(sock);
+               } else {
+                       dev->result = ISC_R_SUCCESS;
+                       isc_task_sendto(task, ISC_EVENT_PTR(&dev), sock->threadid);
+               }
 
                UNLOCK(&sock->lock);
-
                inc_stats(sock->manager->stats,
                          sock->statsindex[STATID_CONNECT]);
 
+
                return (ISC_R_SUCCESS);
        }
 
@@ -5024,6 +5352,8 @@ internal_connect(isc__socket_t *sock) {
        dev = ISC_LIST_HEAD(sock->connect_list);
        if (dev == NULL) {
                INSIST(!sock->connecting);
+               unwatch_fd(&sock->manager->threads[sock->threadid], sock->fd,
+                          SELECT_POKE_CONNECT);
                goto finish;
        }
 
@@ -5047,8 +5377,7 @@ internal_connect(isc__socket_t *sock) {
                 */
                if (SOFT_ERROR(errno) || errno == EINPROGRESS) {
                        sock->connecting = 1;
-                       UNLOCK(&sock->lock);
-                       return;
+                       goto finish;
                }
 
                inc_stats(sock->manager->stats,
@@ -5091,17 +5420,84 @@ internal_connect(isc__socket_t *sock) {
                sock->bound = 1;
        }
 
+       unwatch_fd(&sock->manager->threads[sock->threadid], sock->fd,
+                  SELECT_POKE_CONNECT);
+
+       if (sock->type == isc_sockettype_tls) {
+               internal_tls_connect(sock);
+       } else {
+               do {
+                       dev->result = result;
+                       send_connectdone_event(sock, &dev);
+                       dev = ISC_LIST_HEAD(sock->connect_list);
+               } while (dev != NULL);
+       }
+
+ finish:
+       UNLOCK(&sock->lock);
+}
+
+static void
+internal_tls_connect(isc__socket_t *sock) {
+       isc_socket_connev_t *dev;
+       isc_result_t result;
+       sock->tlsconnecting = 1;
+       bool wanted_read = sock->tlsstate & (TLSSTATE_RWR | TLSSTATE_WWR);
+       bool wanted_write = sock->tlsstate & (TLSSTATE_RWW | TLSSTATE_WWW);
+       sock->tlsstate &= ~(TLSSTATE_RWR | TLSSTATE_RWW);
+
+       if (sock->ssl == NULL) {
+               const SSL_METHOD *meth;
+               SSL_CTX* ctx;
+               SSL_load_error_strings();
+               OpenSSL_add_ssl_algorithms();
+               meth = TLS_client_method();
+               ctx = SSL_CTX_new(meth);
+               sock->ssl = SSL_new(ctx);
+               SSL_set_fd(sock->ssl, sock->fd);
+               SSL_set_connect_state(sock->ssl);
+       }
+       dev = ISC_LIST_HEAD(sock->connect_list);
+       if (dev == NULL) {
+               abort();
+       }
+       int cc = SSL_connect(sock->ssl);
+       printf("SSL_Connect returned %d\n", cc);
+       if (cc < 0) {
+               int err = SSL_get_error(sock->ssl, cc);
+               if (err == SSL_ERROR_WANT_READ) {
+                       printf("Want read\n");
+                       if (!wanted_read) {
+                               watch_fd(&sock->manager->threads[sock->threadid], sock->fd,
+                                        SELECT_POKE_READ);
+                       }
+                       sock->tlsstate |= TLSSTATE_WWR;
+                       goto finish;
+               } else if (err == SSL_ERROR_WANT_WRITE) {
+                       printf("Want write\n");
+                       if (!wanted_write) {
+                               watch_fd(&sock->manager->threads[sock->threadid], sock->fd,
+                                        SELECT_POKE_WRITE);
+                       }
+                       sock->tlsstate |= TLSSTATE_WWW;
+                       goto finish;
+               } else {
+                       printf("Other SSL error in connect %d %d\n", cc, err);
+                       result = ISC_R_CONNECTIONRESET;
+               }
+       } else {
+               result = ISC_R_SUCCESS;
+       }
        do {
+               printf("Send connectdone\n");
+               sock->tlsconnecting = 0;
                dev->result = result;
                send_connectdone_event(sock, &dev);
                dev = ISC_LIST_HEAD(sock->connect_list);
        } while (dev != NULL);
 
  finish:
-       unwatch_fd(&sock->manager->threads[sock->threadid], sock->fd,
-                  SELECT_POKE_CONNECT);
-
-       UNLOCK(&sock->lock);
+       watch_unwatch(sock, wanted_read, wanted_write);
 }
 
 isc_result_t
@@ -5715,3 +6111,40 @@ isc_socketmgr_createinctx(isc_mem_t *mctx, isc_appctx_t *actx,
 
        return (result);
 }
+
+isc_result_t
+isc_socket_getsslhexdigest(isc_socket_t *sock0, char *dest, unsigned int len) {
+       isc__socket_t *sock = (isc__socket_t*) sock0;
+       isc_result_t result;
+       isc_region_t r;
+       isc_buffer_t buf;
+       unsigned char digest[EVP_MAX_MD_SIZE];
+       unsigned int dlen;
+       X509* x509;
+       if (sock->ssl == NULL) { 
+               return (ISC_R_UNSET);
+       }
+       x509 = SSL_get_peer_certificate(sock->ssl);
+       if (x509 == NULL) {
+               return (ISC_R_UNEXPECTED);
+       }
+       
+        if (X509_pubkey_digest(x509, EVP_sha256(), digest, &dlen) != 1) {
+               return (ISC_R_UNEXPECTED);
+       }
+       
+       if (len < 2*dlen + 1) {
+               return (ISC_R_NOSPACE);
+       }
+       
+       r.base = digest;
+       r.length = dlen;
+       isc_buffer_init(&buf, dest, len);
+       result = isc_hex_totext(&r, 4096, "", &buf);
+       if (result != ISC_R_SUCCESS) {
+               return (result);
+       }
+       isc_buffer_putuint8(&buf, 0);
+       return (ISC_R_SUCCESS);
+}
+       
index fd308476e4f0380d504178038960671cbefe7e4b..c7db8e0f60f17d840305a7edb04812163fe27104 100644 (file)
@@ -68,7 +68,7 @@ AC_DEFUN([AX_CHECK_OPENSSL], [
            AS_IF([test -f "$ssldir/include/openssl/ssl.h"],
                [
                    OPENSSL_INCLUDES="-I$ssldir/include"
-                    OPENSSL_LIBS="-L$ssldir/lib -lcrypto"
+                    OPENSSL_LIBS="-L$ssldir/lib -lcrypto -lssl"
                     found=true
                     AC_MSG_RESULT([yes])
                     break