diff --git a/lib/isc/Makefile.am b/lib/isc/Makefile.am index 7b025e1d0d..67408322cc 100644 --- a/lib/isc/Makefile.am +++ b/lib/isc/Makefile.am @@ -127,6 +127,7 @@ libisc_la_SOURCES = \ netmgr/netmgr.c \ netmgr/tcp.c \ netmgr/tcpdns.c \ + netmgr/tls.c \ netmgr/udp.c \ netmgr/uv-compat.c \ netmgr/uv-compat.h \ diff --git a/lib/isc/include/isc/netmgr.h b/lib/isc/include/isc/netmgr.h index 2cd65eb99a..349fb2f681 100644 --- a/lib/isc/include/isc/netmgr.h +++ b/lib/isc/include/isc/netmgr.h @@ -16,6 +16,8 @@ #include #include +typedef struct ssl_ctx_st isc_ssl_ctx_t; + /* * Replacement for isc_sockettype_t provided by socket.h. */ @@ -351,6 +353,16 @@ isc_nm_listentcpdns(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb, * 'quota' is passed to isc_nm_listentcp() when opening the raw TCP socket. */ +isc_result_t +isc_nm_listentlsdns(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb, + void *cbarg, isc_nm_accept_cb_t accept_cb, + void *accept_cbarg, size_t extrahandlesize, int backlog, + isc_quota_t *quota, isc_ssl_ctx_t *sslctx, + isc_nmsocket_t **sockp); +/*%< + * Same as isc_nm_listentcpdns but for an SSL (DoT) socket. + */ + void isc_nm_tcpdns_sequential(isc_nmhandle_t *handle); /*%< @@ -405,6 +417,17 @@ isc_nm_tcp_gettimeouts(isc_nm_t *mgr, uint32_t *initial, uint32_t *idle, * \li 'mgr' is a valid netmgr. */ +isc_result_t +isc_nm_listentls(isc_nm_t *mgr, isc_nmiface_t *iface, + isc_nm_accept_cb_t accept_cb, void *accept_cbarg, + size_t extrahandlesize, int backlog, isc_quota_t *quota, + isc_ssl_ctx_t *sslctx, isc_nmsocket_t **sockp); + +isc_result_t +isc_nm_tlsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, + isc_nm_cb_t cb, void *cbarg, isc_ssl_ctx_t *ctx, + unsigned int timeout, size_t extrahandlesize); + void isc_nm_maxudp(isc_nm_t *mgr, uint32_t maxudp); /*%< @@ -428,9 +451,13 @@ isc_result_t isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, isc_nm_cb_t cb, void *cbarg, unsigned int timeout, size_t extrahandlesize); -/*% - * Establish a DNS client connection over a TCP socket, bound to the - * address 'local', and connected to the address 'peer'. +isc_result_t +isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, + isc_nm_cb_t cb, void *cbarg, unsigned int timeout, + size_t extrahandlesize); +/*%< + * Establish a DNS client connection via a TCP or TLS connection, bound to + * the address 'local' and connected to the address 'peer'. * * When the connection is complete or has timed out, call 'cb' with * argument 'cbarg'. Allocate 'extrahandlesize' additional bytes along @@ -441,3 +468,7 @@ isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, * The connected socket can only be accessed via the handle passed to * 'cb'. */ + +isc_result_t +isc_nm_tls_create_server_ctx(const char *keyfile, const char *certfile, + isc_ssl_ctx_t **ctxp); diff --git a/lib/isc/include/isc/result.h b/lib/isc/include/isc/result.h index 99c55a32f2..cfc3f03ad7 100644 --- a/lib/isc/include/isc/result.h +++ b/lib/isc/include/isc/result.h @@ -88,9 +88,10 @@ #define ISC_R_DISCFULL 67 /*%< disc full */ #define ISC_R_DEFAULT 68 /*%< default */ #define ISC_R_IPV4PREFIX 69 /*%< IPv4 prefix */ +#define ISC_R_TLSERROR 70 /*%< TLS error */ /*% Not a result code: the number of results. */ -#define ISC_R_NRESULTS 70 +#define ISC_R_NRESULTS 71 ISC_LANG_BEGINDECLS diff --git a/lib/isc/netmgr/netmgr-int.h b/lib/isc/netmgr/netmgr-int.h index 053ad7fc63..5b63dfc98d 100644 --- a/lib/isc/netmgr/netmgr-int.h +++ b/lib/isc/netmgr/netmgr-int.h @@ -14,6 +14,9 @@ #include #include +#include +#include + #include #include #include @@ -158,6 +161,12 @@ typedef enum isc__netievent_type { netievent_tcpdnsclose, netievent_tcpdnsstop, + netievent_tlsclose, + netievent_tlssend, + netievent_tlsstartread, + netievent_tlsconnect, + netievent_tlsdobio, + netievent_closecb, netievent_shutdown, netievent_stop, @@ -188,7 +197,8 @@ typedef union { #define UVREQ_MAGIC ISC_MAGIC('N', 'M', 'U', 'R') #define VALID_UVREQ(t) ISC_MAGIC_VALID(t, UVREQ_MAGIC) -typedef struct isc__nm_uvreq { +typedef struct isc__nm_uvreq isc__nm_uvreq_t; +struct isc__nm_uvreq { int magic; isc_nmsocket_t *sock; isc_nmhandle_t *handle; @@ -212,7 +222,8 @@ typedef struct isc__nm_uvreq { uv_fs_t fs; uv_work_t work; } uv_req; -} isc__nm_uvreq_t; + ISC_LINK(isc__nm_uvreq_t) link; +}; typedef struct isc__netievent__socket { isc__netievent_type type; @@ -224,14 +235,19 @@ typedef isc__netievent__socket_t isc__netievent_udpread_t; typedef isc__netievent__socket_t isc__netievent_udpstop_t; typedef isc__netievent__socket_t isc__netievent_udpclose_t; typedef isc__netievent__socket_t isc__netievent_tcpstop_t; + typedef isc__netievent__socket_t isc__netievent_tcpclose_t; typedef isc__netievent__socket_t isc__netievent_startread_t; typedef isc__netievent__socket_t isc__netievent_pauseread_t; typedef isc__netievent__socket_t isc__netievent_closecb_t; + typedef isc__netievent__socket_t isc__netievent_tcpdnsclose_t; typedef isc__netievent__socket_t isc__netievent_tcpdnsread_t; typedef isc__netievent__socket_t isc__netievent_tcpdnsstop_t; +typedef isc__netievent__socket_t isc__netievent_tlsclose_t; +typedef isc__netievent__socket_t isc__netievent_tlsdobio_t; + typedef struct isc__netievent__socket_req { isc__netievent_type type; isc_nmsocket_t *sock; @@ -280,6 +296,14 @@ typedef struct isc__netievent_udpsend { isc__nm_uvreq_t *req; } isc__netievent_udpsend_t; +typedef struct isc__netievent_tlsconnect { + isc__netievent_type type; + isc_nmsocket_t *sock; + SSL_CTX *ctx; + isc_sockaddr_t local; /* local address */ + isc_sockaddr_t peer; /* peer address */ +} isc__netievent_tlsconnect_t; + typedef struct isc__netievent { isc__netievent_type type; } isc__netievent_t; @@ -294,6 +318,7 @@ typedef union { isc__netievent_udpsend_t nius; isc__netievent__socket_quota_t nisq; isc__netievent__socket_streaminfo_quota_t nissq; + isc__netievent_tlsconnect_t nitc; } isc__netievent_storage_t; /* @@ -361,6 +386,8 @@ typedef enum isc_nmsocket_type { isc_nm_tcplistener, isc_nm_tcpdnslistener, isc_nm_tcpdnssocket, + isc_nm_tlslistener, + isc_nm_tlssocket } isc_nmsocket_type; /*% @@ -398,6 +425,24 @@ struct isc_nmsocket { /*% Self, for self-contained unreferenced sockets (tcpdns) */ isc_nmsocket_t *self; + /*% TLS stuff */ + struct tls { + bool server; + BIO *app_bio; + SSL *ssl; + SSL_CTX *ctx; + BIO *ssl_bio; + enum { TLS_INIT, + TLS_HANDSHAKE, + TLS_IO, + TLS_ERROR, + TLS_CLOSING } state; + isc_region_t senddata; + bool sending; + /* List of active send requests. */ + ISC_LIST(isc__nm_uvreq_t) sends; + } tls; + /*% * quota is the TCP client, attached when a TCP connection * is established. pquota is a non-attached pointer to the @@ -861,6 +906,25 @@ isc__nm_async_tcpclose(isc__networker_t *worker, isc__netievent_t *ev0); * stoplisten, send, read, pause, close). */ +void +isc__nm_async_tlsclose(isc__networker_t *worker, isc__netievent_t *ev0); + +void +isc__nm_async_tlssend(isc__networker_t *worker, isc__netievent_t *ev0); + +void +isc__nm_async_tlsconnect(isc__networker_t *worker, isc__netievent_t *ev0); + +void +isc__nm_async_tls_startread(isc__networker_t *worker, isc__netievent_t *ev0); + +void +isc__nm_async_tls_do_bio(isc__networker_t *worker, isc__netievent_t *ev0); + +/*%< + * Callback handlers for asynchronouse TLS events. + */ + void isc__nm_tcpdns_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb, void *cbarg); @@ -908,6 +972,35 @@ isc__nm_tcpdns_cancelread(isc_nmhandle_t *handle); * Stop reading on a connected TCPDNS handle. */ +void +isc__nm_tls_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb, + void *cbarg); + +void +isc__nm_tls_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg); + +void +isc__nm_tls_close(isc_nmsocket_t *sock); +/*%< + * Close a TLS socket. + */ + +void +isc__nm_tls_pauseread(isc_nmsocket_t *sock); +/*%< + * Pause reading on this socket, while still remembering the callback. + */ + +void +isc__nm_tls_resumeread(isc_nmsocket_t *sock); +/*%< + * Resume reading from socket. + * + */ + +void +isc__nm_tls_stoplistening(isc_nmsocket_t *sock); + #define isc__nm_uverr2result(x) \ isc___nm_uverr2result(x, true, __FILE__, __LINE__) isc_result_t @@ -985,3 +1078,9 @@ isc__nm_socket_dontfrag(uv_os_sock_t fd, sa_family_t sa_family); /*%< * Set the SO_IP_DONTFRAG (or equivalent) socket option of the fd if available */ + +void +isc__nm_tls_initialize(void); +/*%< + * Initialize OpenSSL library, idempotent. + */ diff --git a/lib/isc/netmgr/netmgr.c b/lib/isc/netmgr/netmgr.c index ffadb43182..b7a8a29d8c 100644 --- a/lib/isc/netmgr/netmgr.c +++ b/lib/isc/netmgr/netmgr.c @@ -168,6 +168,8 @@ isc_nm_start(isc_mem_t *mctx, uint32_t workers) { isc_nm_t *mgr = NULL; char name[32]; + isc__nm_tls_initialize(); + mgr = isc_mem_get(mctx, sizeof(*mgr)); *mgr = (isc_nm_t){ .nworkers = workers }; @@ -669,7 +671,6 @@ process_queue(isc__networker_t *worker, isc_queue_t *queue) { case netievent_tcpclose: isc__nm_async_tcpclose(worker, ievent); break; - case netievent_tcpdnscancel: isc__nm_async_tcpdnscancel(worker, ievent); break; @@ -683,6 +684,22 @@ process_queue(isc__networker_t *worker, isc_queue_t *queue) { isc__nm_async_tcpdnsstop(worker, ievent); break; + case netievent_tlsstartread: + isc__nm_async_tls_startread(worker, ievent); + break; + case netievent_tlssend: + isc__nm_async_tlssend(worker, ievent); + break; + case netievent_tlsclose: + isc__nm_async_tlsclose(worker, ievent); + break; + case netievent_tlsconnect: + isc__nm_async_tlsconnect(worker, ievent); + break; + case netievent_tlsdobio: + isc__nm_async_tls_do_bio(worker, ievent); + break; + case netievent_closecb: isc__nm_async_closecb(worker, ievent); break; @@ -966,6 +983,9 @@ isc__nmsocket_prep_destroy(isc_nmsocket_t *sock) { case isc_nm_tcpdnssocket: isc__nm_tcpdns_close(sock); return; + case isc_nm_tlssocket: + isc__nm_tls_close(sock); + break; default: break; } @@ -1163,16 +1183,16 @@ isc__nmhandle_get(isc_nmsocket_t *sock, isc_sockaddr_t *peer, #endif if (peer != NULL) { - memcpy(&handle->peer, peer, sizeof(isc_sockaddr_t)); + memmove(&handle->peer, peer, sizeof(isc_sockaddr_t)); } else { - memcpy(&handle->peer, &sock->peer, sizeof(isc_sockaddr_t)); + memmove(&handle->peer, &sock->peer, sizeof(isc_sockaddr_t)); } if (local != NULL) { - memcpy(&handle->local, local, sizeof(isc_sockaddr_t)); + memmove(&handle->local, local, sizeof(isc_sockaddr_t)); } else if (sock->iface != NULL) { - memcpy(&handle->local, &sock->iface->addr, - sizeof(isc_sockaddr_t)); + memmove(&handle->local, &sock->iface->addr, + sizeof(isc_sockaddr_t)); } else { INSIST(0); ISC_UNREACHABLE(); @@ -1207,7 +1227,7 @@ isc__nmhandle_get(isc_nmsocket_t *sock, isc_sockaddr_t *peer, #endif UNLOCK(&sock->lock); - if (sock->type == isc_nm_tcpsocket || + if (sock->type == isc_nm_tcpsocket || sock->type == isc_nm_tlssocket || (sock->type == isc_nm_udpsocket && atomic_load(&sock->client)) || (sock->type == isc_nm_tcpdnssocket && atomic_load(&sock->client))) { @@ -1453,6 +1473,7 @@ isc__nm_uvreq_get(isc_nm_t *mgr, isc_nmsocket_t *sock) { } *req = (isc__nm_uvreq_t){ .magic = 0 }; + ISC_LINK_INIT(req, link); req->uv_req.req.data = req; isc__nmsocket_attach(sock, &req->sock); req->magic = UVREQ_MAGIC; @@ -1510,6 +1531,9 @@ isc_nm_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb, case isc_nm_tcpdnssocket: isc__nm_tcpdns_send(handle, region, cb, cbarg); break; + case isc_nm_tlssocket: + isc__nm_tls_send(handle, region, cb, cbarg); + break; default: INSIST(0); ISC_UNREACHABLE(); @@ -1530,6 +1554,9 @@ isc_nm_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) { case isc_nm_tcpdnssocket: isc__nm_tcpdns_read(handle, cb, cbarg); break; + case isc_nm_tlssocket: + isc__nm_tls_read(handle, cb, cbarg); + break; default: INSIST(0); ISC_UNREACHABLE(); @@ -1566,6 +1593,9 @@ isc_nm_pauseread(isc_nmhandle_t *handle) { case isc_nm_tcpsocket: isc__nm_tcp_pauseread(sock); break; + case isc_nm_tlssocket: + isc__nm_tls_pauseread(sock); + break; default: INSIST(0); ISC_UNREACHABLE(); @@ -1582,6 +1612,9 @@ isc_nm_resumeread(isc_nmhandle_t *handle) { case isc_nm_tcpsocket: isc__nm_tcp_resumeread(sock); break; + case isc_nm_tlssocket: + isc__nm_tls_resumeread(sock); + break; default: INSIST(0); ISC_UNREACHABLE(); @@ -1602,6 +1635,9 @@ isc_nm_stoplistening(isc_nmsocket_t *sock) { case isc_nm_tcplistener: isc__nm_tcp_stoplistening(sock); break; + case isc_nm_tlslistener: + isc__nm_tls_stoplistening(sock); + break; default: INSIST(0); ISC_UNREACHABLE(); @@ -1948,6 +1984,10 @@ nmsocket_type_totext(isc_nmsocket_type type) { return ("isc_nm_tcpdnslistener"); case isc_nm_tcpdnssocket: return ("isc_nm_tcpdnssocket"); + case isc_nm_tlssocket: + return ("isc_nm_tlssocket"); + case isc_nm_tlslistener: + return ("isc_nm_tlslistener"); default: INSIST(0); ISC_UNREACHABLE(); diff --git a/lib/isc/netmgr/tcpdns.c b/lib/isc/netmgr/tcpdns.c index aa2003ea79..8004124a85 100644 --- a/lib/isc/netmgr/tcpdns.c +++ b/lib/isc/netmgr/tcpdns.c @@ -393,11 +393,6 @@ isc_nm_listentcpdns(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb, dnslistensock->accept_cbarg = accept_cbarg; dnslistensock->extrahandlesize = extrahandlesize; - /* - * dnslistensock will be a DNS 'wrapper' around a connected - * stream. We set dnslistensock->outer to a socket listening - * for a TCP connection. - */ result = isc_nm_listentcp(mgr, iface, dnslisten_acceptcb, dnslistensock, extrahandlesize, backlog, quota, &dnslistensock->outer); @@ -412,6 +407,43 @@ isc_nm_listentcpdns(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb, } } +/* + * isc_nm_listentlsdns works exactly as listentcpdns but on an SSL socket. + */ +isc_result_t +isc_nm_listentlsdns(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb, + void *cbarg, isc_nm_accept_cb_t accept_cb, + void *accept_cbarg, size_t extrahandlesize, int backlog, + isc_quota_t *quota, SSL_CTX *sslctx, + isc_nmsocket_t **sockp) { + isc_nmsocket_t *dnslistensock = isc_mem_get(mgr->mctx, + sizeof(*dnslistensock)); + isc_result_t result; + + REQUIRE(VALID_NM(mgr)); + REQUIRE(sslctx != NULL); + + isc__nmsocket_init(dnslistensock, mgr, isc_nm_tcpdnslistener, iface); + dnslistensock->recv_cb = cb; + dnslistensock->recv_cbarg = cbarg; + dnslistensock->accept_cb = accept_cb; + dnslistensock->accept_cbarg = accept_cbarg; + dnslistensock->extrahandlesize = extrahandlesize; + + result = isc_nm_listentls(mgr, iface, dnslisten_acceptcb, dnslistensock, + extrahandlesize, backlog, quota, sslctx, + &dnslistensock->outer); + if (result == ISC_R_SUCCESS) { + atomic_store(&dnslistensock->listening, true); + *sockp = dnslistensock; + return (ISC_R_SUCCESS); + } else { + atomic_store(&dnslistensock->closed, true); + isc__nmsocket_detach(&dnslistensock); + return (result); + } +} + void isc__nm_async_tcpdnsstop(isc__networker_t *worker, isc__netievent_t *ev0) { isc__netievent_tcpstop_t *ievent = (isc__netievent_tcpdnsstop_t *)ev0; @@ -430,7 +462,16 @@ isc__nm_async_tcpdnsstop(isc__networker_t *worker, isc__netievent_t *ev0) { isc__nmsocket_clearcb(sock); if (sock->outer != NULL) { - isc__nm_tcp_stoplistening(sock->outer); + switch (sock->outer->type) { + case isc_nm_tcplistener: + isc__nm_tcp_stoplistening(sock->outer); + break; + case isc_nm_tlslistener: + isc__nm_tls_stoplistening(sock->outer); + break; + default: + INSIST(0); + } isc__nmsocket_detach(&sock->outer); } @@ -559,6 +600,7 @@ resume_processing(void *arg) { static void tcpdnssend_cb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) { isc__nm_uvreq_t *req = (isc__nm_uvreq_t *)cbarg; + REQUIRE(VALID_UVREQ(req)); UNUSED(handle); @@ -805,6 +847,25 @@ isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, timeout, 0)); } +isc_result_t +isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, + isc_nm_cb_t cb, void *cbarg, unsigned int timeout, + size_t extrahandlesize) { + tcpconnect_t *conn = isc_mem_get(mgr->mctx, sizeof(tcpconnect_t)); + SSL_CTX *ctx = NULL; + + *conn = (tcpconnect_t){ .cb = cb, + .cbarg = cbarg, + .extrahandlesize = extrahandlesize }; + isc_mem_attach(mgr->mctx, &conn->mctx); + + ctx = SSL_CTX_new(SSLv23_client_method()); + isc_result_t result = isc_nm_tlsconnect( + mgr, local, peer, tcpdnsconnect_cb, conn, ctx, timeout, 0); + SSL_CTX_free(ctx); + return (result); +} + void isc__nm_tcpdns_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) { isc_nmsocket_t *sock = handle->sock; diff --git a/lib/isc/netmgr/tls.c b/lib/isc/netmgr/tls.c new file mode 100644 index 0000000000..df0a1a1a94 --- /dev/null +++ b/lib/isc/netmgr/tls.c @@ -0,0 +1,747 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "netmgr-int.h" +#include "uv-compat.h" + +#define TLS_BUF_SIZE 65536 + +static isc_result_t +tls_error_to_result(int tls_err) { + switch (tls_err) { + case SSL_ERROR_ZERO_RETURN: + return (ISC_R_EOF); + default: + return (ISC_R_UNEXPECTED); + } +} + +static void +tls_do_bio(isc_nmsocket_t *sock); + +static void +tls_close_direct(isc_nmsocket_t *sock); + +static void +async_tls_do_bio(isc_nmsocket_t *sock); + +static void +tls_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) { + isc_nmsocket_t *sock = (isc_nmsocket_t *)cbarg; + + UNUSED(handle); + /* XXXWPK TODO */ + UNUSED(eresult); + isc_mem_put(sock->mgr->mctx, sock->tls.senddata.base, + sock->tls.senddata.length); + sock->tls.senddata = (isc_region_t){ NULL, 0 }; + sock->tls.sending = false; + + async_tls_do_bio(sock); +} + +static void +async_tls_do_bio(isc_nmsocket_t *sock) { + isc__netievent_tlsdobio_t *ievent = + isc__nm_get_ievent(sock->mgr, netievent_tlsdobio); + ievent->sock = sock; + isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid], + (isc__netievent_t *)ievent); +} + +static void +tls_do_bio(isc_nmsocket_t *sock) { + isc_result_t result = ISC_R_SUCCESS; + int pending, tls_err = 0; + int rv; + isc__nm_uvreq_t *req; + + REQUIRE(sock->tid == isc_nm_tid()); + /* We will resume read if TLS layer wants us to */ + isc_nm_pauseread(sock->outerhandle); + + if (sock->tls.state == TLS_INIT) { + (void)SSL_do_handshake(sock->tls.ssl); + sock->tls.state = TLS_HANDSHAKE; + } + + if (sock->tls.state == TLS_ERROR) { + result = ISC_R_FAILURE; + goto error; + } + + /* Data from TLS to client */ + char buf[1]; + if (sock->tls.state == TLS_IO && sock->recv_cb != NULL && + !atomic_load(&sock->readpaused)) + { + (void)SSL_peek(sock->tls.ssl, buf, 1); + while ((pending = SSL_pending(sock->tls.ssl)) > 0) { + if (pending > TLS_BUF_SIZE) { + pending = TLS_BUF_SIZE; + } + isc_region_t region = { + isc_mem_get(sock->mgr->mctx, pending), pending + }; + isc_region_t dregion; + memset(region.base, 0, region.length); + rv = SSL_read(sock->tls.ssl, region.base, + region.length); + /* Pending succeded, so should read */ + RUNTIME_CHECK(rv == pending); + dregion = (isc_region_t){ region.base, rv }; + sock->recv_cb(sock->statichandle, ISC_R_SUCCESS, + &dregion, sock->recv_cbarg); + isc_mem_put(sock->mgr->mctx, region.base, + region.length); + } + } + + /* Peek to move the session forward */ + (void)SSL_peek(sock->tls.ssl, buf, 1); + + /* Data from TLS to network */ + pending = BIO_pending(sock->tls.app_bio); + if (!sock->tls.sending && pending > 0) { + if (pending > TLS_BUF_SIZE) { + pending = TLS_BUF_SIZE; + } + sock->tls.sending = true; + sock->tls.senddata.base = isc_mem_get(sock->mgr->mctx, pending); + sock->tls.senddata.length = pending; + rv = BIO_read(sock->tls.app_bio, sock->tls.senddata.base, + pending); + /* There's something pending, read must succed */ + RUNTIME_CHECK(rv == pending); + isc_nm_send(sock->outerhandle, &sock->tls.senddata, + tls_senddone, sock); + /* We'll continue in tls_senddone */ + return; + } + + /* Get the potential error code */ + rv = SSL_peek(sock->tls.ssl, buf, 1); + + if (rv < 0) { + tls_err = SSL_get_error(sock->tls.ssl, rv); + } + + /* Only after doing the IO we can check if SSL handshake is done */ + if (sock->tls.state == TLS_HANDSHAKE && + SSL_is_init_finished(sock->tls.ssl) == 1) + { + isc_nmhandle_t *tlshandle = isc__nmhandle_get(sock, NULL, NULL); + if (sock->tls.server) { + sock->listener->accept_cb(sock->statichandle, + ISC_R_SUCCESS, + sock->listener->accept_cbarg); + } else { + sock->connect_cb(tlshandle, ISC_R_SUCCESS, + sock->connect_cbarg); + } + isc_nmhandle_detach(&tlshandle); + sock->tls.state = TLS_IO; + async_tls_do_bio(sock); + return; + } + + if (tls_err == 0) { + return; + } + + if (tls_err == SSL_ERROR_WANT_WRITE) { + if (!sock->tls.sending) { + /* + * Launch tls_do_bio asynchronously. If we're sending + * already the send callback will call it. + */ + async_tls_do_bio(sock); + } else { + return; + } + } else if (tls_err == SSL_ERROR_WANT_READ) { + isc_nm_resumeread(sock->outerhandle); + } else if (tls_err != 0) { + result = tls_error_to_result(tls_err); + goto error; + } + + while ((req = ISC_LIST_HEAD(sock->tls.sends)) != NULL) { + INSIST(VALID_UVREQ(req)); + rv = SSL_write(sock->tls.ssl, req->uvbuf.base, req->uvbuf.len); + if (rv < 0) { + if (!sock->tls.sending) { + async_tls_do_bio(sock); + } + return; + } + if (rv != (int)req->uvbuf.len) { + sock->tls.state = TLS_ERROR; + async_tls_do_bio(sock); + return; + } + ISC_LIST_UNLINK(sock->tls.sends, req, link); + req->cb.send(sock->statichandle, ISC_R_SUCCESS, req->cbarg); + isc__nm_uvreq_put(&req, sock); + } + + return; + +error: + isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_NETMGR, + ISC_LOG_ERROR, "SSL error in BIO: %d %s", tls_err, + isc_result_totext(result)); + if (ISC_LIST_HEAD(sock->tls.sends) != NULL) { + while ((req = ISC_LIST_HEAD(sock->tls.sends)) != NULL) { + req->cb.send(sock->statichandle, result, req->cbarg); + ISC_LIST_UNLINK(sock->tls.sends, req, link); + isc__nm_uvreq_put(&req, sock); + } + } else if (sock->recv_cb != NULL) { + sock->recv_cb(sock->statichandle, result, NULL, + sock->recv_cbarg); + } else { + tls_close_direct(sock); + } +} + +static void +tls_readcb(isc_nmhandle_t *handle, isc_result_t result, isc_region_t *region, + void *cbarg) { + isc_nmsocket_t *tlssock = (isc_nmsocket_t *)cbarg; + int rv; + + REQUIRE(VALID_NMSOCK(tlssock)); + REQUIRE(VALID_NMHANDLE(handle)); + REQUIRE(tlssock->tid == isc_nm_tid()); + if (result != ISC_R_SUCCESS) { + /* Connection closed */ + /* + * TODO accept_cb should be called if we're not + * initialized yet! + */ + if (tlssock->recv_cb != NULL) { + tlssock->recv_cb(tlssock->statichandle, result, region, + tlssock->recv_cbarg); + } + isc__nm_tls_close(tlssock); + return; + } + rv = BIO_write(tlssock->tls.app_bio, region->base, region->length); + + if (rv != (int)region->length) { + /* XXXWPK log it? */ + tlssock->tls.state = TLS_ERROR; + } + tls_do_bio(tlssock); +} + +static isc_result_t +initialize_tls(isc_nmsocket_t *sock, bool server) { + REQUIRE(sock->tid == isc_nm_tid()); + + if (BIO_new_bio_pair(&(sock->tls.ssl_bio), TLS_BUF_SIZE, + &(sock->tls.app_bio), TLS_BUF_SIZE) != 1) + { + SSL_free(sock->tls.ssl); + return (ISC_R_TLSERROR); + } + + SSL_set_bio(sock->tls.ssl, sock->tls.ssl_bio, sock->tls.ssl_bio); + if (server) { + SSL_set_accept_state(sock->tls.ssl); + } else { + SSL_set_connect_state(sock->tls.ssl); + } + isc_nm_read(sock->outerhandle, tls_readcb, sock); + tls_do_bio(sock); + return (ISC_R_SUCCESS); +} + +static isc_result_t +tlslisten_acceptcb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) { + isc_nmsocket_t *tlslistensock = (isc_nmsocket_t *)cbarg; + isc_nmsocket_t *tlssock = NULL; + + REQUIRE(VALID_NMSOCK(tlslistensock)); + REQUIRE(tlslistensock->type == isc_nm_tlslistener); + + /* If accept() was unsuccessful we can't do anything */ + if (result != ISC_R_SUCCESS) { + return (result); + } + + /* + * We need to create a 'wrapper' tlssocket for this connection. + */ + tlssock = isc_mem_get(handle->sock->mgr->mctx, sizeof(*tlssock)); + isc__nmsocket_init(tlssock, handle->sock->mgr, isc_nm_tlssocket, + handle->sock->iface); + + tlssock->extrahandlesize = tlslistensock->extrahandlesize; + isc__nmsocket_attach(tlslistensock, &tlssock->listener); + isc_nmhandle_attach(handle, &tlssock->outerhandle); + tlssock->peer = handle->sock->peer; + tlssock->read_timeout = handle->sock->mgr->init; + tlssock->tid = isc_nm_tid(); + tlssock->tls.server = true; + tlssock->tls.state = TLS_INIT; + tlssock->tls.ctx = tlslistensock->tls.ctx; + /* We need to initialize SSL now to reference SSL_CTX properly */ + tlssock->tls.ssl = SSL_new(tlssock->tls.ctx); + ISC_LIST_INIT(tlssock->tls.sends); + if (tlssock->tls.ssl == NULL) { + atomic_store(&tlssock->closed, true); + isc__nmsocket_detach(&tlssock); + return (ISC_R_TLSERROR); + } + + uv_timer_init(&tlssock->mgr->workers[isc_nm_tid()].loop, + &tlssock->timer); + tlssock->timer.data = tlssock; + tlssock->timer_initialized = true; + tlssock->tls.ctx = tlslistensock->tls.ctx; + + result = initialize_tls(tlssock, true); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + /* TODO: catch failure code, detach tlssock, and log the error */ + + return (result); +} + +isc_result_t +isc_nm_listentls(isc_nm_t *mgr, isc_nmiface_t *iface, + isc_nm_accept_cb_t accept_cb, void *accept_cbarg, + size_t extrahandlesize, int backlog, isc_quota_t *quota, + SSL_CTX *sslctx, isc_nmsocket_t **sockp) { + isc_result_t result; + isc_nmsocket_t *tlssock = isc_mem_get(mgr->mctx, sizeof(*tlssock)); + + isc__nmsocket_init(tlssock, mgr, isc_nm_tlslistener, iface); + tlssock->accept_cb = accept_cb; + tlssock->accept_cbarg = accept_cbarg; + tlssock->extrahandlesize = extrahandlesize; + tlssock->tls.ctx = sslctx; + /* We need to initialize SSL now to reference SSL_CTX properly */ + tlssock->tls.ssl = SSL_new(tlssock->tls.ctx); + if (tlssock->tls.ssl == NULL) { + atomic_store(&tlssock->closed, true); + isc__nmsocket_detach(&tlssock); + return (ISC_R_TLSERROR); + } + + /* + * tlssock will be a TLS 'wrapper' around an unencrypted stream. + * We set tlssock->outer to a socket listening for a TCP connection. + */ + result = isc_nm_listentcp(mgr, iface, tlslisten_acceptcb, tlssock, + extrahandlesize, backlog, quota, + &tlssock->outer); + if (result == ISC_R_SUCCESS) { + atomic_store(&tlssock->listening, true); + *sockp = tlssock; + return (ISC_R_SUCCESS); + } else { + atomic_store(&tlssock->closed, true); + isc__nmsocket_detach(&tlssock); + return (result); + } +} + +void +isc__nm_async_tlssend(isc__networker_t *worker, isc__netievent_t *ev0) { + int rv; + isc__netievent_tcpsend_t *ievent = (isc__netievent_tcpsend_t *)ev0; + isc__nm_uvreq_t *req = ievent->req; + ievent->req = NULL; + REQUIRE(VALID_UVREQ(req)); + REQUIRE(worker->id == ievent->sock->tid); + + if (!atomic_load(&ievent->sock->active)) { + return; + } + if (!ISC_LIST_EMPTY(ievent->sock->tls.sends)) { + /* We're not the first */ + ISC_LIST_APPEND(ievent->sock->tls.sends, req, link); + tls_do_bio(ievent->sock); + return; + } + + rv = SSL_write(ievent->sock->tls.ssl, req->uvbuf.base, req->uvbuf.len); + if (rv < 0) { + /* + * We might need to read, we might need to write, or the + * TLS socket might be dead - in any case, we need to + * enqueue the uvreq and let the TLS BIO layer do the rest. + */ + ISC_LIST_APPEND(ievent->sock->tls.sends, req, link); + tls_do_bio(ievent->sock); + return; + } + if (rv != (int)req->uvbuf.len) { + ievent->sock->tls.state = TLS_ERROR; + async_tls_do_bio(ievent->sock); + return; + } + req->cb.send(ievent->sock->statichandle, ISC_R_SUCCESS, req->cbarg); + isc__nm_uvreq_put(&req, ievent->sock); + tls_do_bio(ievent->sock); + return; +} + +void +isc__nm_tls_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb, + void *cbarg) { + isc_nmsocket_t *sock = handle->sock; + isc__netievent_tcpsend_t *ievent = NULL; + isc__nm_uvreq_t *uvreq = NULL; + + REQUIRE(sock->type == isc_nm_tlssocket); + + uvreq = isc__nm_uvreq_get(sock->mgr, sock); + uvreq->uvbuf.base = (char *)region->base; + uvreq->uvbuf.len = region->length; + isc_nmhandle_attach(handle, &uvreq->handle); + uvreq->cb.send = cb; + uvreq->cbarg = cbarg; + + /* + * We need to create an event and pass it using async channel + */ + ievent = isc__nm_get_ievent(sock->mgr, netievent_tlssend); + ievent->sock = sock; + ievent->req = uvreq; + isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid], + (isc__netievent_t *)ievent); +} + +void +isc__nm_async_tls_startread(isc__networker_t *worker, isc__netievent_t *ev0) { + isc__netievent_startread_t *ievent = (isc__netievent_startread_t *)ev0; + isc_nmsocket_t *sock = ievent->sock; + + REQUIRE(worker->id == isc_nm_tid()); + + tls_do_bio(sock); +} + +void +isc__nm_tls_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) { + isc_nmsocket_t *sock = NULL; + isc__netievent_startread_t *ievent = NULL; + + REQUIRE(VALID_NMHANDLE(handle)); + REQUIRE(VALID_NMSOCK(handle->sock)); + + sock = handle->sock; + sock->recv_cb = cb; + sock->recv_cbarg = cbarg; + + ievent = isc__nm_get_ievent(sock->mgr, netievent_tlsstartread); + ievent->sock = sock; + + isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid], + (isc__netievent_t *)ievent); +} + +void +isc__nm_tls_pauseread(isc_nmsocket_t *sock) { + atomic_store(&sock->readpaused, true); +} + +void +isc__nm_tls_resumeread(isc_nmsocket_t *sock) { + atomic_store(&sock->readpaused, false); + async_tls_do_bio(sock); +} + +static void +timer_close_cb(uv_handle_t *handle) { + isc_nmsocket_t *sock = (isc_nmsocket_t *)uv_handle_get_data(handle); + INSIST(VALID_NMSOCK(sock)); + isc__nmsocket_detach(&sock); +} + +static void +tls_close_direct(isc_nmsocket_t *sock) { + REQUIRE(sock->tid == isc_nm_tid()); + + /* We don't need atomics here, it's all in single network thread */ + if (sock->timer_initialized) { + /* + * We need to fire the timer callback to clean it up, + * it will then call us again (via detach) so that we + * can finally close the socket. + */ + sock->timer_initialized = false; + uv_timer_stop(&sock->timer); + uv_close((uv_handle_t *)&sock->timer, timer_close_cb); + } else { + /* + * At this point we're certain that there are no external + * references, we can close everything. + */ + if (sock->outerhandle != NULL) { + isc_nm_pauseread(sock->outerhandle); + isc_nmhandle_detach(&sock->outerhandle); + } + if (sock->listener != NULL) { + isc__nmsocket_detach(&sock->listener); + } + if (sock->tls.ssl != NULL) { + SSL_free(sock->tls.ssl); + sock->tls.ssl = NULL; + /* These are destroyed when we free SSL* */ + sock->tls.ctx = NULL; + sock->tls.ssl_bio = NULL; + } + if (sock->tls.app_bio != NULL) { + BIO_free(sock->tls.app_bio); + sock->tls.app_bio = NULL; + } + atomic_store(&sock->closed, true); + } +} + +void +isc__nm_tls_close(isc_nmsocket_t *sock) { + REQUIRE(VALID_NMSOCK(sock)); + REQUIRE(sock->type == isc_nm_tlssocket); + + if (sock->tid == isc_nm_tid()) { + tls_close_direct(sock); + } else { + isc__netievent_tlsclose_t *ievent = + isc__nm_get_ievent(sock->mgr, netievent_tlsclose); + + ievent->sock = sock; + isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid], + (isc__netievent_t *)ievent); + } +} + +void +isc__nm_async_tlsclose(isc__networker_t *worker, isc__netievent_t *ev0) { + isc__netievent_tlsclose_t *ievent = (isc__netievent_tlsclose_t *)ev0; + + REQUIRE(worker->id == ievent->sock->tid); + + tls_close_direct(ievent->sock); +} + +void +isc__nm_tls_stoplistening(isc_nmsocket_t *sock) { + REQUIRE(VALID_NMSOCK(sock)); + REQUIRE(sock->type == isc_nm_tlslistener); + + atomic_store(&sock->listening, false); + atomic_store(&sock->closed, true); + sock->recv_cb = NULL; + sock->recv_cbarg = NULL; + if (sock->tls.ssl != NULL) { + SSL_free(sock->tls.ssl); + sock->tls.ssl = NULL; + sock->tls.ctx = NULL; + } + + if (sock->outer != NULL) { + isc_nm_stoplistening(sock->outer); + isc__nmsocket_detach(&sock->outer); + } +} + +isc_result_t +isc_nm_tlsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer, + isc_nm_cb_t cb, void *cbarg, SSL_CTX *ctx, + unsigned int timeout, size_t extrahandlesize) { + isc_nmsocket_t *nsock = NULL, *tmp = NULL; + isc__netievent_tlsconnect_t *ievent = NULL; + isc_result_t result = ISC_R_SUCCESS; + + REQUIRE(VALID_NM(mgr)); + + nsock = isc_mem_get(mgr->mctx, sizeof(*nsock)); + isc__nmsocket_init(nsock, mgr, isc_nm_tlssocket, local); + nsock->extrahandlesize = extrahandlesize; + atomic_init(&nsock->result, ISC_R_SUCCESS); + nsock->connect_cb = cb; + nsock->connect_cbarg = cbarg; + nsock->connect_timeout = timeout; + nsock->tls.ctx = ctx; + /* We need to initialize SSL now to reference SSL_CTX properly */ + nsock->tls.ssl = SSL_new(nsock->tls.ctx); + if (nsock->tls.ssl == NULL) { + atomic_store(&nsock->closed, true); + isc__nmsocket_detach(&nsock); + return (ISC_R_TLSERROR); + } + + ievent = isc__nm_get_ievent(mgr, netievent_tlsconnect); + ievent->sock = nsock; + ievent->local = local->addr; + ievent->peer = peer->addr; + ievent->ctx = ctx; + + /* + * Async callbacks can dereference the socket in the meantime, + * we need to hold an additional reference to it. + */ + isc__nmsocket_attach(nsock, &tmp); + + if (isc__nm_in_netthread()) { + nsock->tid = isc_nm_tid(); + isc__nm_async_tlsconnect(&mgr->workers[nsock->tid], + (isc__netievent_t *)ievent); + isc__nm_put_ievent(mgr, ievent); + } else { + nsock->tid = isc_random_uniform(mgr->nworkers); + isc__nm_enqueue_ievent(&mgr->workers[nsock->tid], + (isc__netievent_t *)ievent); + } + + isc__nmsocket_detach(&tmp); + + return (result); +} + +static void +tls_connect_cb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) { + isc_nmsocket_t *tlssock = (isc_nmsocket_t *)cbarg; + + REQUIRE(VALID_NMSOCK(tlssock)); + + if (result != ISC_R_SUCCESS) { + tlssock->connect_cb(NULL, result, tlssock->connect_cbarg); + atomic_store(&tlssock->result, result); + atomic_store(&tlssock->connect_error, true); + tls_close_direct(tlssock); + return; + } + + INSIST(VALID_NMHANDLE(handle)); + + isc_nmhandle_attach(handle, &tlssock->outerhandle); + result = initialize_tls(tlssock, false); + if (result != ISC_R_SUCCESS) { + tlssock->connect_cb(NULL, result, tlssock->connect_cbarg); + atomic_store(&tlssock->result, result); + atomic_store(&tlssock->connect_error, true); + tls_close_direct(tlssock); + return; + } +} +void +isc__nm_async_tlsconnect(isc__networker_t *worker, isc__netievent_t *ev0) { + isc__netievent_tlsconnect_t *ievent = + (isc__netievent_tlsconnect_t *)ev0; + isc_nmsocket_t *tlssock = ievent->sock; + isc_result_t result; + + UNUSED(worker); + + tlssock->tid = isc_nm_tid(); + uv_timer_init(&tlssock->mgr->workers[isc_nm_tid()].loop, + &tlssock->timer); + tlssock->timer.data = tlssock; + tlssock->timer_initialized = true; + tlssock->tls.state = TLS_INIT; + + result = isc_nm_tcpconnect(worker->mgr, (isc_nmiface_t *)&ievent->local, + (isc_nmiface_t *)&ievent->peer, + tls_connect_cb, tlssock, + tlssock->connect_timeout, 0); + if (result != ISC_R_SUCCESS) { + tlssock->connect_cb(NULL, result, tlssock->connect_cbarg); + atomic_store(&tlssock->result, result); + atomic_store(&tlssock->connect_error, true); + tls_close_direct(tlssock); + return; + } +} + +void +isc__nm_async_tls_do_bio(isc__networker_t *worker, isc__netievent_t *ev0) { + UNUSED(worker); + isc__netievent_tlsdobio_t *ievent = (isc__netievent_tlsdobio_t *)ev0; + tls_do_bio(ievent->sock); +} + +isc_result_t +isc_nm_tls_create_server_ctx(const char *keyfile, const char *certfile, + SSL_CTX **ctxp) { + INSIST(ctxp != NULL); + INSIST(*ctxp == NULL); + int rv; + unsigned long err; + +#ifdef HAVE_TLS_SERVER_METHOD + const SSL_METHOD *method = TLS_server_method(); +#else + const SSL_METHOD *method = SSLv23_server_method(); +#endif + + SSL_CTX *ctx = SSL_CTX_new(method); + RUNTIME_CHECK(ctx != NULL); + rv = SSL_CTX_use_certificate_file(ctx, certfile, SSL_FILETYPE_PEM); + if (rv != 1) { + goto ssl_error; + } + rv = SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM); + if (rv != 1) { + goto ssl_error; + } + *ctxp = ctx; + return (ISC_R_SUCCESS); + +ssl_error: + err = ERR_get_error(); + char errbuf[256]; + ERR_error_string_n(err, errbuf, 256); + isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_NETMGR, + ISC_LOG_ERROR, "Error initializing TLS context: %s", + errbuf); + SSL_CTX_free(ctx); + return (ISC_R_TLSERROR); +} + +void +isc__nm_tls_initialize() { +#if OPENSSL_VERSION_NUMBER < 0x10100000L + SSL_library_init(); +#else + OPENSSL_init_ssl(0, NULL); +#endif +} diff --git a/lib/isc/result.c b/lib/isc/result.c index 8b2258c036..e5f8c1f5ee 100644 --- a/lib/isc/result.c +++ b/lib/isc/result.c @@ -101,6 +101,7 @@ static const char *description[ISC_R_NRESULTS] = { "disc full", /*%< 67 */ "default", /*%< 68 */ "IPv4 prefix", /*%< 69 */ + "TLS error", /*%< 70 */ }; static const char *identifier[ISC_R_NRESULTS] = { @@ -174,6 +175,7 @@ static const char *identifier[ISC_R_NRESULTS] = { "ISC_R_DISCFULL", "ISC_R_DEFAULT", "ISC_R_IPV4PREFIX", + "ISC_R_TLSERROR", }; #define ISC_RESULT_RESULTSET 2 diff --git a/lib/isc/sockaddr.c b/lib/isc/sockaddr.c index 424112fe41..dbd1c10d79 100644 --- a/lib/isc/sockaddr.c +++ b/lib/isc/sockaddr.c @@ -506,7 +506,7 @@ isc_sockaddr_fromsockaddr(isc_sockaddr_t *isa, const struct sockaddr *sa) { } memset(isa, 0, sizeof(isc_sockaddr_t)); - memcpy(isa, sa, length); + memmove(isa, sa, length); isa->length = length; return (ISC_R_SUCCESS); diff --git a/lib/isc/win32/libisc.def.in b/lib/isc/win32/libisc.def.in index d696169ea7..69ebcb56e6 100644 --- a/lib/isc/win32/libisc.def.in +++ b/lib/isc/win32/libisc.def.in @@ -449,7 +449,9 @@ isc_nm_closedown isc_nm_destroy isc_nm_detach isc_nm_listentcpdns +isc_nm_listentlsdns isc_nm_listentcp +isc_nm_listentls isc_nm_listenudp isc_nm_maxudp isc_nm_pauseread @@ -466,6 +468,9 @@ isc_nm_tcp_settimeouts isc_nm_tcpdns_keepalive isc_nm_tcpdns_sequential isc_nm_tid +isc_nm_tls_create_server_ctx +isc_nm_tlsconnect +isc_nm_tlsdnsconnect isc_nm_udpconnect isc_nmsocket_close isc__nm_acquire_interlocked diff --git a/lib/isc/win32/libisc.vcxproj.in b/lib/isc/win32/libisc.vcxproj.in index e785ed73cf..10952b2293 100644 --- a/lib/isc/win32/libisc.vcxproj.in +++ b/lib/isc/win32/libisc.vcxproj.in @@ -413,6 +413,7 @@ copy InstallFiles ..\Build\Release\ + diff --git a/util/copyrights b/util/copyrights index e20188b9d5..f23232e659 100644 --- a/util/copyrights +++ b/util/copyrights @@ -1879,6 +1879,7 @@ ./lib/isc/netmgr/netmgr.c C 2019,2020 ./lib/isc/netmgr/tcp.c C 2019,2020 ./lib/isc/netmgr/tcpdns.c C 2019,2020 +./lib/isc/netmgr/tls.c C 2020 ./lib/isc/netmgr/udp.c C 2019,2020 ./lib/isc/netmgr/uv-compat.c C 2020 ./lib/isc/netmgr/uv-compat.h C 2019,2020