2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-09-03 16:15:27 +00:00

Refactor TLSDNS module to work with libuv/ssl directly

* Following the example set in 634bdfb16d, the tlsdns netmgr
  module now uses libuv and SSL primitives directly, rather than
  opening a TLS socket which opens a TCP socket, as the previous
  model was difficult to debug.  Closes #2335.

* Remove the netmgr tls layer (we will have to re-add it for DoH)

* Add isc_tls API to wrap the OpenSSL SSL_CTX object into libisc
  library; move the OpenSSL initialization/deinitialization from dstapi
  needed for OpenSSL 1.0.x to the isc_tls_{initialize,destroy}()

* Add couple of new shims needed for OpenSSL 1.0.x

* When LibreSSL is used, require at least version 2.7.0 that
  has the best OpenSSL 1.1.x compatibility and auto init/deinit

* Enforce OpenSSL 1.1.x usage on Windows

* Added a TLSDNS unit test and implemented a simple TLSDNS echo
  server and client.
This commit is contained in:
Ondřej Surý
2020-12-17 11:40:29 +01:00
parent 8f73c70d23
commit e493e04c0f
32 changed files with 4376 additions and 1983 deletions

View File

@@ -2828,10 +2828,13 @@ start_tcp(dig_query_t *query) {
REQUIRE(query != NULL);
if (query->lookup->tls_mode) {
result = isc_tlsctx_createclient(&query->tlsctx);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
result = isc_nm_tlsdnsconnect(
netmgr, (isc_nmiface_t *)&localaddr,
(isc_nmiface_t *)&query->sockaddr,
tcp_connected, query, local_timeout, 0);
tcp_connected, query, local_timeout, 0,
query->tlsctx);
check_result(result, "isc_nm_tcpdnsconnect");
} else {
result = isc_nm_tcpdnsconnect(
@@ -3240,6 +3243,10 @@ tcp_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) {
LOCK_LOOKUP;
lookup_attach(query->lookup, &l);
if (query->tlsctx != NULL) {
isc_tlsctx_free(&query->tlsctx);
}
if (eresult == ISC_R_CANCELED) {
debug("in cancel handler");
isc_sockaddr_format(&query->sockaddr, sockstr, sizeof(sockstr));
@@ -3306,10 +3313,6 @@ tcp_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) {
launch_next_query(query);
query_detach(&query);
if (l->tls_mode) {
/* FIXME: This is a accounting bug in TLSDNS */
isc_nmhandle_detach(&handle);
}
lookup_detach(&l);
UNLOCK_LOOKUP;
}

View File

@@ -24,6 +24,7 @@
#include <isc/list.h>
#include <isc/magic.h>
#include <isc/mem.h>
#include <isc/netmgr.h>
#include <isc/print.h>
#include <isc/refcount.h>
#include <isc/sockaddr.h>
@@ -199,6 +200,7 @@ struct dig_query {
uint64_t byte_count;
isc_timer_t *timer;
uint8_t tries;
isc_tlsctx_t *tlsctx;
};
struct dig_server {

View File

@@ -8,3 +8,6 @@ dlopen
keycreate
keydelete
gssapi_krb
/wire_test
/test_client
/test_server

View File

@@ -2,13 +2,33 @@ include $(top_srcdir)/Makefile.top
SUBDIRS = system
noinst_PROGRAMS = wire_test
noinst_PROGRAMS = \
test_client \
test_server \
wire_test
AM_CPPFLAGS += \
test_client_CPPFLAGS = \
$(AM_CPPFLAGS) \
$(LIBISC_CFLAGS)
test_client_LDADD = \
$(LIBISC_LIBS) \
$(LIBDNS_LIBS)
test_server_CPPFLAGS = \
$(AM_CPPFLAGS) \
$(LIBISC_CFLAGS)
test_server_LDADD = \
$(LIBISC_LIBS) \
$(LIBDNS_LIBS)
wire_test_CPPFLAGS = \
$(AM_CPPFLAGS) \
$(LIBISC_CFLAGS) \
$(LIBDNS_CFLAGS)
LDADD = \
wire_test_LDADD = \
$(LIBISC_LIBS) \
$(LIBDNS_LIBS)

428
bin/tests/test_client.c Normal file
View File

@@ -0,0 +1,428 @@
/*
* 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 <fcntl.h>
#include <getopt.h>
#include <netdb.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <isc/mem.h>
#include <isc/netaddr.h>
#include <isc/netmgr.h>
#include <isc/os.h>
#include <isc/sockaddr.h>
#include <isc/string.h>
#include <isc/util.h>
typedef enum { UDP, TCP, DOT, DOH } protocol_t;
static const char *protocols[] = { "udp", "tcp", "dot", "doh" };
static isc_mem_t *mctx = NULL;
static isc_nm_t *netmgr = NULL;
static protocol_t protocol;
static const char *address;
static const char *port;
static int family = AF_UNSPEC;
static isc_sockaddr_t sockaddr_local;
static isc_sockaddr_t sockaddr_remote;
static int workers;
static int timeout;
static uint8_t messagebuf[2 * 65536];
static isc_region_t message = { .length = 0, .base = messagebuf };
static int out = -1;
static isc_result_t
parse_port(const char *input) {
char *endptr = NULL;
long val = strtol(input, &endptr, 10);
if ((*endptr != '\0') || (val <= 0) || (val >= 65536)) {
return (ISC_R_BADNUMBER);
}
port = input;
return (ISC_R_SUCCESS);
}
static isc_result_t
parse_protocol(const char *input) {
for (size_t i = 0; i < ARRAY_SIZE(protocols); i++) {
if (!strcasecmp(input, protocols[i])) {
protocol = i;
return (ISC_R_SUCCESS);
}
}
return (ISC_R_BADNUMBER);
}
static isc_result_t
parse_address(const char *input) {
struct in6_addr in6;
struct in_addr in;
if (inet_pton(AF_INET6, input, &in6) == 1) {
family = AF_INET6;
address = input;
return (ISC_R_SUCCESS);
}
if (inet_pton(AF_INET, input, &in) == 1) {
family = AF_INET;
address = input;
return (ISC_R_SUCCESS);
}
return (ISC_R_BADADDRESSFORM);
}
static int
parse_workers(const char *input) {
char *endptr = NULL;
long val = strtol(input, &endptr, 10);
if ((*endptr != '\0') || (val <= 0) || (val >= 128)) {
return (ISC_R_BADNUMBER);
}
workers = val;
return (ISC_R_SUCCESS);
}
static isc_result_t
parse_timeout(const char *input) {
char *endptr = NULL;
long val = strtol(input, &endptr, 10);
if ((*endptr != '\0') || (val <= 0) || (val >= 120)) {
return (ISC_R_BADNUMBER);
}
timeout = (in_port_t)val * 1000;
return (ISC_R_SUCCESS);
}
static isc_result_t
parse_input(const char *input) {
int in = -1;
if (!strcmp(input, "-")) {
in = 0;
} else {
in = open(input, O_RDONLY);
}
RUNTIME_CHECK(in >= 0);
message.length = read(in, message.base, sizeof(messagebuf));
close(in);
return (ISC_R_SUCCESS);
}
static isc_result_t
parse_output(const char *input) {
if (!strcmp(input, "-")) {
out = 1;
} else {
out = open(input, O_WRONLY | O_CREAT,
S_IRUSR | S_IRGRP | S_IROTH);
}
RUNTIME_CHECK(out >= 0);
return (ISC_R_SUCCESS);
}
static void
parse_options(int argc, char **argv) {
char buf[ISC_NETADDR_FORMATSIZE];
/* Set defaults */
RUNTIME_CHECK(parse_protocol("UDP") == ISC_R_SUCCESS);
RUNTIME_CHECK(parse_port("53000") == ISC_R_SUCCESS);
RUNTIME_CHECK(parse_address("::0") == ISC_R_SUCCESS);
workers = isc_os_ncpus();
while (true) {
int c;
int option_index = 0;
static struct option long_options[] = {
{ "port", required_argument, NULL, 'p' },
{ "address", required_argument, NULL, 'a' },
{ "protocol", required_argument, NULL, 'P' },
{ "workers", required_argument, NULL, 'w' },
{ "timeout", required_argument, NULL, 't' },
{ "input", required_argument, NULL, 'i' },
{ "output", required_argument, NULL, 'o' },
{ 0, 0, NULL, 0 }
};
c = getopt_long(argc, argv, "a:p:P:w:t:i:o:", long_options,
&option_index);
if (c == -1) {
break;
}
switch (c) {
case 'a':
RUNTIME_CHECK(parse_address(optarg) == ISC_R_SUCCESS);
break;
case 'p':
RUNTIME_CHECK(parse_port(optarg) == ISC_R_SUCCESS);
break;
case 'P':
RUNTIME_CHECK(parse_protocol(optarg) == ISC_R_SUCCESS);
break;
case 'w':
RUNTIME_CHECK(parse_workers(optarg) == ISC_R_SUCCESS);
break;
case 't':
RUNTIME_CHECK(parse_timeout(optarg) == ISC_R_SUCCESS);
break;
case 'i':
RUNTIME_CHECK(parse_input(optarg) == ISC_R_SUCCESS);
break;
case 'o':
RUNTIME_CHECK(parse_output(optarg) == ISC_R_SUCCESS);
break;
default:
INSIST(0);
}
}
INSIST(optind < argc);
{
struct addrinfo hints = {
.ai_family = family,
.ai_socktype = (protocol == UDP) ? SOCK_DGRAM
: SOCK_STREAM,
};
struct addrinfo *result = NULL;
int r = getaddrinfo(address, NULL, &hints, &result);
RUNTIME_CHECK(r == 0);
for (struct addrinfo *rp = result; rp != NULL; rp = rp->ai_next)
{
RUNTIME_CHECK(isc_sockaddr_fromsockaddr(&sockaddr_local,
rp->ai_addr) ==
ISC_R_SUCCESS);
}
}
{
struct addrinfo hints = {
.ai_family = family,
.ai_socktype = (protocol == UDP) ? SOCK_DGRAM
: SOCK_STREAM,
};
struct addrinfo *result = NULL;
int r = getaddrinfo(argv[optind], port, &hints, &result);
RUNTIME_CHECK(r == 0);
for (struct addrinfo *rp = result; rp != NULL; rp = rp->ai_next)
{
RUNTIME_CHECK(isc_sockaddr_fromsockaddr(
&sockaddr_remote, rp->ai_addr) ==
ISC_R_SUCCESS);
}
}
isc_sockaddr_format(&sockaddr_local, buf, sizeof(buf));
printf("Will connect from %s://%s", protocols[protocol], buf);
isc_sockaddr_format(&sockaddr_remote, buf, sizeof(buf));
printf("to %s, %d workers\n", buf, workers);
}
static void
_signal(int sig, void (*handler)(int)) {
struct sigaction sa = { .sa_handler = handler };
RUNTIME_CHECK(sigfillset(&sa.sa_mask) == 0);
RUNTIME_CHECK(sigaction(sig, &sa, NULL) >= 0);
}
static void
setup(void) {
sigset_t sset;
_signal(SIGPIPE, SIG_IGN);
_signal(SIGHUP, SIG_DFL);
_signal(SIGTERM, SIG_DFL);
_signal(SIGINT, SIG_DFL);
RUNTIME_CHECK(sigemptyset(&sset) == 0);
RUNTIME_CHECK(sigaddset(&sset, SIGHUP) == 0);
RUNTIME_CHECK(sigaddset(&sset, SIGINT) == 0);
RUNTIME_CHECK(sigaddset(&sset, SIGTERM) == 0);
RUNTIME_CHECK(pthread_sigmask(SIG_BLOCK, &sset, NULL) == 0);
isc_mem_create(&mctx);
netmgr = isc_nm_start(mctx, workers);
}
static void
teardown(void) {
if (out > 0) {
close(out);
}
isc_nm_destroy(&netmgr);
isc_mem_destroy(&mctx);
}
static void
yield(void) {
sigset_t sset;
int sig;
RUNTIME_CHECK(sigemptyset(&sset) == 0);
RUNTIME_CHECK(sigaddset(&sset, SIGHUP) == 0);
RUNTIME_CHECK(sigaddset(&sset, SIGINT) == 0);
RUNTIME_CHECK(sigaddset(&sset, SIGTERM) == 0);
RUNTIME_CHECK(sigwait(&sset, &sig) == 0);
fprintf(stderr, "Shutting down...\n");
}
static void
read_cb(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
void *cbarg) {
isc_nmhandle_t *readhandle = cbarg;
REQUIRE(handle != NULL);
REQUIRE(eresult == ISC_R_SUCCESS || eresult == ISC_R_CANCELED ||
eresult == ISC_R_EOF);
REQUIRE(cbarg != NULL);
fprintf(stderr, "%s(..., %s, ...)\n", __func__,
isc_result_totext(eresult));
if (eresult == ISC_R_SUCCESS) {
printf("RECEIVED %u bytes\n", region->length);
if (out >= 0) {
ssize_t len = write(out, region->base, region->length);
close(out);
REQUIRE((size_t)len == region->length);
}
}
isc_nmhandle_detach(&readhandle);
kill(getpid(), SIGTERM);
}
static void
send_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) {
REQUIRE(handle != NULL);
REQUIRE(eresult == ISC_R_SUCCESS || eresult == ISC_R_CANCELED ||
eresult == ISC_R_EOF);
REQUIRE(cbarg == NULL);
}
static void
connect_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) {
isc_nmhandle_t *readhandle = NULL;
REQUIRE(handle != NULL);
REQUIRE(eresult == ISC_R_SUCCESS);
UNUSED(cbarg);
if (eresult != ISC_R_SUCCESS) {
kill(getpid(), SIGTERM);
return;
}
fprintf(stderr, "ECHO_CLIENT:%s\n", __func__);
isc_nmhandle_attach(handle, &readhandle);
isc_nm_read(handle, read_cb, readhandle);
isc_nm_send(handle, &message, send_cb, NULL);
}
static void
run(void) {
isc_result_t result;
switch (protocol) {
case UDP:
result = isc_nm_udpconnect(netmgr,
(isc_nmiface_t *)&sockaddr_local,
(isc_nmiface_t *)&sockaddr_remote,
connect_cb, NULL, timeout, 0);
break;
case TCP:
result = isc_nm_tcpdnsconnect(netmgr,
(isc_nmiface_t *)&sockaddr_local,
(isc_nmiface_t *)&sockaddr_remote,
connect_cb, NULL, timeout, 0);
break;
case DOT: {
isc_tlsctx_t *tlsdns_ctx = NULL;
isc_tlsctx_createclient(&tlsdns_ctx);
result = isc_nm_tlsdnsconnect(
netmgr, (isc_nmiface_t *)&sockaddr_local,
(isc_nmiface_t *)&sockaddr_remote, connect_cb, NULL,
timeout, 0, tlsdns_ctx);
break;
}
case DOH:
INSIST(0);
ISC_UNREACHABLE();
break;
default:
INSIST(0);
ISC_UNREACHABLE();
}
REQUIRE(result == ISC_R_SUCCESS);
yield();
isc_nm_closedown(netmgr);
}
int
main(int argc, char **argv) {
parse_options(argc, argv);
setup();
run();
teardown();
exit(EXIT_SUCCESS);
}

305
bin/tests/test_server.c Normal file
View File

@@ -0,0 +1,305 @@
/*
* 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 <getopt.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <isc/mem.h>
#include <isc/netaddr.h>
#include <isc/netmgr.h>
#include <isc/os.h>
#include <isc/sockaddr.h>
#include <isc/string.h>
#include <isc/util.h>
typedef enum { UDP, TCP, DOT, DOH } protocol_t;
static const char *protocols[] = { "udp", "tcp", "dot", "doh" };
static isc_mem_t *mctx = NULL;
static isc_nm_t *netmgr = NULL;
static protocol_t protocol;
static in_port_t port;
static isc_netaddr_t netaddr;
static isc_sockaddr_t sockaddr __attribute__((unused));
static int workers;
static void
read_cb(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
void *cbarg);
static void
send_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg);
static isc_result_t
parse_port(const char *input) {
char *endptr = NULL;
long val = strtol(input, &endptr, 10);
if ((*endptr != '\0') || (val <= 0) || (val >= 65536)) {
return (ISC_R_BADNUMBER);
}
port = (in_port_t)val;
return (ISC_R_SUCCESS);
}
static isc_result_t
parse_protocol(const char *input) {
for (size_t i = 0; i < ARRAY_SIZE(protocols); i++) {
if (!strcasecmp(input, protocols[i])) {
protocol = i;
return (ISC_R_SUCCESS);
}
}
return (ISC_R_BADNUMBER);
}
static isc_result_t
parse_address(const char *input) {
struct in6_addr in6;
struct in_addr in;
if (inet_pton(AF_INET6, input, &in6) == 1) {
isc_netaddr_fromin6(&netaddr, &in6);
return (ISC_R_SUCCESS);
}
if (inet_pton(AF_INET, input, &in) == 1) {
isc_netaddr_fromin(&netaddr, &in);
return (ISC_R_SUCCESS);
}
return (ISC_R_BADADDRESSFORM);
}
static int
parse_workers(const char *input) {
char *endptr = NULL;
long val = strtol(input, &endptr, 10);
if ((*endptr != '\0') || (val <= 0) || (val >= 128)) {
return (ISC_R_BADNUMBER);
}
workers = val;
return (ISC_R_SUCCESS);
}
static void
parse_options(int argc, char **argv) {
char buf[ISC_NETADDR_FORMATSIZE];
/* Set defaults */
RUNTIME_CHECK(parse_protocol("UDP") == ISC_R_SUCCESS);
RUNTIME_CHECK(parse_port("53000") == ISC_R_SUCCESS);
RUNTIME_CHECK(parse_address("::1") == ISC_R_SUCCESS);
workers = isc_os_ncpus();
while (true) {
int c;
int option_index = 0;
static struct option long_options[] = {
{ "port", required_argument, NULL, 'p' },
{ "address", required_argument, NULL, 'a' },
{ "protocol", required_argument, NULL, 'P' },
{ "workers", required_argument, NULL, 'w' },
{ 0, 0, NULL, 0 }
};
c = getopt_long(argc, argv, "a:p:P:w:", long_options,
&option_index);
if (c == -1) {
break;
}
switch (c) {
case 'a':
RUNTIME_CHECK(parse_address(optarg) == ISC_R_SUCCESS);
break;
case 'p':
RUNTIME_CHECK(parse_port(optarg) == ISC_R_SUCCESS);
break;
case 'P':
RUNTIME_CHECK(parse_protocol(optarg) == ISC_R_SUCCESS);
break;
case 'w':
RUNTIME_CHECK(parse_workers(optarg) == ISC_R_SUCCESS);
break;
default:
INSIST(0);
}
}
isc_sockaddr_fromnetaddr(&sockaddr, &netaddr, port);
isc_sockaddr_format(&sockaddr, buf, sizeof(buf));
printf("Will listen at %s://%s, %d workers\n", protocols[protocol], buf,
workers);
}
static void
_signal(int sig, void (*handler)(int)) {
struct sigaction sa = { .sa_handler = handler };
RUNTIME_CHECK(sigfillset(&sa.sa_mask) == 0);
RUNTIME_CHECK(sigaction(sig, &sa, NULL) >= 0);
}
static void
setup(void) {
sigset_t sset;
_signal(SIGPIPE, SIG_IGN);
_signal(SIGHUP, SIG_DFL);
_signal(SIGTERM, SIG_DFL);
_signal(SIGINT, SIG_DFL);
RUNTIME_CHECK(sigemptyset(&sset) == 0);
RUNTIME_CHECK(sigaddset(&sset, SIGHUP) == 0);
RUNTIME_CHECK(sigaddset(&sset, SIGINT) == 0);
RUNTIME_CHECK(sigaddset(&sset, SIGTERM) == 0);
RUNTIME_CHECK(pthread_sigmask(SIG_BLOCK, &sset, NULL) == 0);
isc_mem_create(&mctx);
netmgr = isc_nm_start(mctx, workers);
}
static void
teardown(void) {
isc_nm_destroy(&netmgr);
isc_mem_destroy(&mctx);
}
static void
yield(void) {
sigset_t sset;
int sig;
RUNTIME_CHECK(sigemptyset(&sset) == 0);
RUNTIME_CHECK(sigaddset(&sset, SIGHUP) == 0);
RUNTIME_CHECK(sigaddset(&sset, SIGINT) == 0);
RUNTIME_CHECK(sigaddset(&sset, SIGTERM) == 0);
RUNTIME_CHECK(sigwait(&sset, &sig) == 0);
fprintf(stderr, "Shutting down...\n");
}
static void
read_cb(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
void *cbarg) {
isc_region_t *reply = NULL;
REQUIRE(handle != NULL);
REQUIRE(eresult == ISC_R_SUCCESS);
UNUSED(cbarg);
fprintf(stderr, "RECEIVED %u bytes\n", region->length);
if (region->length >= 12) {
/* long enough to be a DNS header, set QR bit */
((uint8_t *)region->base)[2] ^= 0x80;
}
reply = isc_mem_get(mctx, sizeof(isc_region_t) + region->length);
reply->length = region->length;
reply->base = (uint8_t *)reply + sizeof(isc_region_t);
memmove(reply->base, region->base, region->length);
isc_nm_send(handle, reply, send_cb, reply);
return;
}
static void
send_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) {
isc_region_t *reply = cbarg;
REQUIRE(handle != NULL);
REQUIRE(eresult == ISC_R_SUCCESS);
isc_mem_put(mctx, cbarg, sizeof(isc_region_t) + reply->length);
}
static isc_result_t
accept_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) {
REQUIRE(handle != NULL);
REQUIRE(eresult == ISC_R_SUCCESS);
UNUSED(cbarg);
return (ISC_R_SUCCESS);
}
static void
run(void) {
isc_result_t result;
isc_nmsocket_t *sock = NULL;
switch (protocol) {
case UDP:
result = isc_nm_listenudp(netmgr, (isc_nmiface_t *)&sockaddr,
read_cb, NULL, 0, &sock);
break;
case TCP:
result = isc_nm_listentcpdns(netmgr, (isc_nmiface_t *)&sockaddr,
read_cb, NULL, accept_cb, NULL, 0,
0, NULL, &sock);
break;
case DOT: {
isc_tlsctx_t *tlsdns_ctx = NULL;
isc_tlsctx_createserver(NULL, NULL, &tlsdns_ctx);
result = isc_nm_listentlsdns(netmgr, (isc_nmiface_t *)&sockaddr,
read_cb, NULL, accept_cb, NULL, 0,
0, NULL, tlsdns_ctx, &sock);
break;
}
case DOH:
INSIST(0);
ISC_UNREACHABLE();
break;
default:
INSIST(0);
ISC_UNREACHABLE();
}
REQUIRE(result == ISC_R_SUCCESS);
yield();
isc_nm_stoplistening(sock);
isc_nmsocket_close(&sock);
}
int
main(int argc, char **argv) {
parse_options(argc, argv);
setup();
run();
teardown();
exit(EXIT_SUCCESS);
}

View File

@@ -277,19 +277,19 @@ typedef __int64 off_t;
@DNS_RDATASET_FIXED@
/* Define if OpenSSL includes Ed25519 support */
@HAVE_OPENSSL_ED25519@
#define HAVE_OPENSSL_ED25519 1
/* Define if OpenSSL includes Ed448 support */
@HAVE_OPENSSL_ED448@
#define HAVE_OPENSSL_ED448 1
/* Define if your OpenSSL version supports DH functions. */
@HAVE_DH_GET0_KEY@
#define HAVE_DH_GET0_KEY 1
/* Define if your OpenSSL version supports ECDSA functions. */
@HAVE_ECDSA_SIG_GET0@
#define HAVE_ECDSA_SIG_GET0 1
/* Define if your OpenSSL version supports RSA functions. */
@HAVE_RSA_SET0_KEY@
#define HAVE_RSA_SET0_KEY 1
/* define if OpenSSL is used for Public-Key Cryptography */
@USE_OPENSSL@
@@ -297,9 +297,6 @@ typedef __int64 off_t;
/* Define if native PKCS#11 is used as cryptographic library provider */
@USE_PKCS11@
/* HMAC_*() return ints */
@HMAC_RETURN_INT@
/* Define to 1 if you have the `readline' function. */
@HAVE_READLINE@
@@ -328,34 +325,64 @@ typedef __int64 off_t;
@WANT_QUERYTRACE@
/* Define to 1 if you have the `CRYPTO_zalloc' function. */
@HAVE_CRYPTO_ZALLOC@
#define HAVE_CRYPTO_ZALLOC 1
/* Define to 1 if you have the `EVP_CIPHER_CTX_free' function. */
@HAVE_EVP_CIPHER_CTX_FREE@
#define HAVE_EVP_CIPHER_CTX_FREE 1
/* Define to 1 if you have the `EVP_CIPHER_CTX_new' function. */
@HAVE_EVP_CIPHER_CTX_NEW@
#define HAVE_EVP_CIPHER_CTX_NEW 1
/* Define to 1 if you have the `EVP_MD_CTX_free' function. */
@HAVE_EVP_MD_CTX_FREE@
#define HAVE_EVP_MD_CTX_FREE 1
/* Define to 1 if you have the `EVP_MD_CTX_new' function. */
@HAVE_EVP_MD_CTX_NEW@
#define HAVE_EVP_MD_CTX_NEW 1
/* Define to 1 if you have the `EVP_MD_CTX_reset' function. */
@HAVE_EVP_MD_CTX_RESET@
#define HAVE_EVP_MD_CTX_RESET 1
/* Define to 1 if you have the `HMAC_CTX_free' function. */
@HAVE_HMAC_CTX_FREE@
#define HAVE_HMAC_CTX_FREE 1
/* Define to 1 if you have the `HMAC_CTX_get_md' function. */
@HAVE_HMAC_CTX_GET_MD@
#define HAVE_HMAC_CTX_GET_MD 1
/* Define to 1 if you have the `HMAC_CTX_new' function. */
@HAVE_HMAC_CTX_NEW@
#define HAVE_HMAC_CTX_NEW 1
/* Define to 1 if you have the `HMAC_CTX_reset' function. */
@HAVE_HMAC_CTX_RESET@
#define HAVE_HMAC_CTX_RESET 1
/* Define to 1 if you have the `SSL_read_ex' function. */
#define HAVE_SSL_READ_EX 1
/* Define to 1 if you have the `SSL_peek_ex' function. */
#define HAVE_SSL_PEEK_EX 1
/* Define to 1 if you have the `SSL_write_ex' function. */
#define HAVE_SSL_WRITE_EX 1
/* Define to 1 if you have the `BIO_read_ex' function. */
#define HAVE_BIO_READ_EX 1
/* Define to 1 if you have the `BIO_write_ex' function. */
#define HAVE_BIO_WRITE_EX 1
/* Define to 1 if you have the `OPENSSL_init_crypto' function. */
#define HAVE_OPENSSL_INIT_CRYPTO 1
/* Define to 1 if you have the `OPENSSL_init_ssl' function. */
#define HAVE_OPENSSL_INIT_SSL 1
/* Define to 1 if you have the `TLS_client_method' function. */
#define HAVE_TLS_CLIENT_METHOD 1
/* Define to 1 if you have the `TLS_server_method' function. */
#define HAVE_TLS_SERVER_METHOD 1
/* Define to 1 if you have the `SSL_CTX_up_ref' function. */
#define SSL_CTX_UP_REF 1
/* Define to 1 if you have the `uv_handle_get_data' function. */
@HAVE_UV_HANDLE_GET_DATA@

View File

@@ -623,11 +623,12 @@ AX_SAVE_FLAGS([openssl])
CFLAGS="$CFLAGS $OPENSSL_CFLAGS"
LIBS="$LIBS $OPENSSL_LIBS"
AC_MSG_CHECKING([for OpenSSL >= 1.0.0 or LibreSSL])
AC_MSG_CHECKING([for OpenSSL >= 1.0.0 or LibreSSL >= 2.7.0])
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM([[#include <openssl/opensslv.h>]],
[[#if !defined(LIBRESSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER < 0x1000000fL)
#error OpenSSL >= 1.0.0 or LibreSSL required
[[#if (!defined(LIBRESSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER < 0x1000000fL)) || \\
(defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER < 0x02070000fL))
#error OpenSSL >= 1.0.0 or LibreSSL >= 2.7.0 required
#endif
]])],
[AC_MSG_RESULT([yes])],
@@ -637,10 +638,15 @@ AC_COMPILE_IFELSE(
# Check for functions added in OpenSSL or LibreSSL
#
AC_CHECK_FUNCS([OPENSSL_init_ssl OPENSSL_init_crypto])
AC_CHECK_FUNCS([CRYPTO_zalloc])
AC_CHECK_FUNCS([EVP_CIPHER_CTX_new EVP_CIPHER_CTX_free])
AC_CHECK_FUNCS([EVP_MD_CTX_new EVP_MD_CTX_free EVP_MD_CTX_reset])
AC_CHECK_FUNCS([HMAC_CTX_new HMAC_CTX_free HMAC_CTX_reset HMAC_CTX_get_md])
AC_CHECK_FUNCS([SSL_read_ex SSL_peek_ex SSL_write_ex])
AC_CHECK_FUNCS([BIO_read_ex BIO_write_ex])
AC_CHECK_FUNCS([SSL_CTX_up_ref])
AC_CHECK_FUNCS([SSL_CTX_set_min_proto_version])
#
# Check for algorithm support in OpenSSL
@@ -706,7 +712,7 @@ AC_CHECK_FUNCS([EVP_aes_128_ecb EVP_aes_192_ecb EVP_aes_256_ecb], [:],
#
AC_CHECK_FUNCS([DH_get0_key ECDSA_SIG_get0 RSA_set0_key])
AC_CHECK_FUNCS([TLS_server_method])
AC_CHECK_FUNCS([TLS_server_method TLS_client_method])
#
# Check whether FIPS mode is available and whether we should enable it

View File

@@ -29,6 +29,7 @@
#include <isc/platform.h>
#include <isc/string.h>
#include <isc/thread.h>
#include <isc/tls.h>
#include <isc/util.h>
#include <dns/log.h>
@@ -44,12 +45,6 @@ static isc_mem_t *dst__mctx = NULL;
#include <openssl/engine.h>
#endif /* if !defined(OPENSSL_NO_ENGINE) */
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
static isc_mutex_t *locks = NULL;
static int nlocks;
#endif /* if OPENSSL_VERSION_NUMBER < 0x10100000L || \
* defined(LIBRESSL_VERSION_NUMBER) */
#if !defined(OPENSSL_NO_ENGINE)
static ENGINE *e = NULL;
#endif /* if !defined(OPENSSL_NO_ENGINE) */
@@ -71,34 +66,6 @@ enable_fips_mode(void) {
#endif /* HAVE_FIPS_MODE */
}
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
static void
lock_callback(int mode, int type, const char *file, int line) {
UNUSED(file);
UNUSED(line);
if ((mode & CRYPTO_LOCK) != 0) {
LOCK(&locks[type]);
} else {
UNLOCK(&locks[type]);
}
}
#endif /* if OPENSSL_VERSION_NUMBER < 0x10100000L || \
* defined(LIBRESSL_VERSION_NUMBER) */
#if defined(LIBRESSL_VERSION_NUMBER)
static unsigned long
id_callback(void) {
return ((unsigned long)isc_thread_self());
}
#endif /* if defined(LIBRESSL_VERSION_NUMBER) */
#if OPENSSL_VERSION_NUMBER < 0x10100000L
static void
_set_thread_id(CRYPTO_THREADID *id) {
CRYPTO_THREADID_set_numeric(id, (unsigned long)isc_thread_self());
}
#endif /* if OPENSSL_VERSION_NUMBER < 0x10100000L */
isc_result_t
dst__openssl_init(isc_mem_t *mctx, const char *engine) {
isc_result_t result;
@@ -112,19 +79,7 @@ dst__openssl_init(isc_mem_t *mctx, const char *engine) {
enable_fips_mode();
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
nlocks = CRYPTO_num_locks();
locks = isc_mem_allocate(dst__mctx, sizeof(isc_mutex_t) * nlocks);
isc_mutexblock_init(locks, nlocks);
CRYPTO_set_locking_callback(lock_callback);
#if defined(LIBRESSL_VERSION_NUMBER)
CRYPTO_set_id_callback(id_callback);
#elif OPENSSL_VERSION_NUMBER < 0x10100000L
CRYPTO_THREADID_set_callback(_set_thread_id);
#endif /* if defined(LIBRESSL_VERSION_NUMBER) */
ERR_load_crypto_strings();
#endif /* if OPENSSL_VERSION_NUMBER < 0x10100000L || \
* defined(LIBRESSL_VERSION_NUMBER) */
isc_tls_initialize();
#if !defined(OPENSSL_NO_ENGINE)
#if !defined(CONF_MFLAGS_DEFAULT_SECTION)
@@ -178,13 +133,6 @@ cleanup_rm:
}
e = NULL;
#endif /* if !defined(OPENSSL_NO_ENGINE) */
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
CRYPTO_set_locking_callback(NULL);
isc_mutexblock_destroy(locks, nlocks);
isc_mem_free(dst__mctx, locks);
locks = NULL;
#endif /* if OPENSSL_VERSION_NUMBER < 0x10100000L || \
* defined(LIBRESSL_VERSION_NUMBER) */
return (result);
}
@@ -206,25 +154,13 @@ dst__openssl_destroy(void) {
#endif /* if !defined(OPENSSL_NO_ENGINE) */
CRYPTO_cleanup_all_ex_data();
ERR_clear_error();
#if OPENSSL_VERSION_NUMBER < 0x10100000L
ERR_remove_thread_state(NULL);
#elif defined(LIBRESSL_VERSION_NUMBER)
ERR_remove_state(0);
#endif /* if OPENSSL_VERSION_NUMBER < 0x10100000L */
ERR_free_strings();
#ifdef DNS_CRYPTO_LEAKS
CRYPTO_mem_leaks_fp(stderr);
#endif /* ifdef DNS_CRYPTO_LEAKS */
if (locks != NULL) {
CRYPTO_set_locking_callback(NULL);
isc_mutexblock_destroy(locks, nlocks);
isc_mem_free(dst__mctx, locks);
locks = NULL;
}
#endif /* if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
* defined(LIBRESSL_VERSION_NUMBER) */
#endif
isc_tls_destroy();
isc_mem_detach(&dst__mctx);
}

View File

@@ -87,6 +87,7 @@ libisc_la_HEADERS = \
include/isc/task.h \
include/isc/taskpool.h \
include/isc/timer.h \
include/isc/tls.h \
include/isc/tm.h \
include/isc/types.h \
include/isc/utf8.h \
@@ -128,7 +129,6 @@ libisc_la_SOURCES = \
netmgr/tcp.c \
netmgr/tcpdns.c \
netmgr/tlsdns.c \
netmgr/tls.c \
netmgr/udp.c \
netmgr/uv-compat.c \
netmgr/uv-compat.h \
@@ -209,6 +209,7 @@ libisc_la_SOURCES = \
task.c \
taskpool.c \
timer.c \
tls.c \
tm.c \
utf8.c \
pthreads/condition.c \

View File

@@ -14,10 +14,9 @@
#include <isc/mem.h>
#include <isc/region.h>
#include <isc/result.h>
#include <isc/tls.h>
#include <isc/types.h>
typedef struct ssl_ctx_st isc_ssl_ctx_t;
/*
* Replacement for isc_sockettype_t provided by socket.h.
*/
@@ -365,11 +364,11 @@ isc_nm_listentcpdns(isc_nm_t *mgr, isc_nmiface_t *iface,
*/
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);
isc_nm_listentlsdns(isc_nm_t *mgr, isc_nmiface_t *iface,
isc_nm_recv_cb_t recv_cb, void *recv_cbarg,
isc_nm_accept_cb_t accept_cb, void *accept_cbarg,
size_t extrahandlesize, int backlog, isc_quota_t *quota,
isc_tlsctx_t *sslctx, isc_nmsocket_t **sockp);
/*%<
* Same as isc_nm_listentcpdns but for an SSL (DoT) socket.
*/
@@ -455,17 +454,6 @@ isc_nm_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);
/*%<
@@ -492,7 +480,7 @@ isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *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);
size_t extrahandlesize, isc_tlsctx_t *sslctx);
/*%<
* Establish a DNS client connection via a TCP or TLS connection, bound to
* the address 'local' and connected to the address 'peer'.
@@ -506,7 +494,3 @@ isc_nm_tlsdnsconnect(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);

54
lib/isc/include/isc/tls.h Normal file
View File

@@ -0,0 +1,54 @@
/*
* 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.
*/
#pragma once
#include <isc/mem.h>
#include <isc/region.h>
#include <isc/result.h>
#include <isc/tls.h>
#include <isc/types.h>
typedef struct ssl_ctx_st isc_tlsctx_t;
void
isc_tls_initialize(void);
void
isc_tls_destroy(void);
void
isc_tlsctx_free(isc_tlsctx_t **ctpx);
/*%
* Free the TLS client/server context.
*
* Require:
*\li 'ctxp' != NULL and '*ctxp' != NULL.
*/
isc_result_t
isc_tlsctx_createserver(const char *keyfile, const char *certfile,
isc_tlsctx_t **ctxp);
/*%
* Set up TLS server context.
*
* Require:
*\li 'ctxp' != NULL and '*ctxp' == NULL.
*/
isc_result_t
isc_tlsctx_createclient(isc_tlsctx_t **ctxp);
/*%
* Set up TLS client context.
*
* Require:
*\li 'ctxp' != NULL and '*ctxp' == NULL.
*/

View File

@@ -52,6 +52,21 @@
#define ISC_NETMGR_RECVBUF_SIZE (65536)
#endif
#define ISC_NETMGR_SENDBUF_SIZE (sizeof(uint16_t) + UINT16_MAX)
/*%
* Regular TCP buffer size.
*/
#define NM_REG_BUF 4096
/*%
* Larger buffer for when the regular one isn't enough; this will
* hold two full DNS packets with lengths. netmgr receives 64k at
* most in TCPDNS or TLSDNS connections, so there's no risk of overrun
* when using a buffer this size.
*/
#define NM_BIG_BUF (65535 + 2) * 2
#if defined(SO_REUSEPORT_LB) || (defined(SO_REUSEPORT) && defined(__linux__))
#define HAVE_SO_REUSEPORT_LB 1
#endif
@@ -162,6 +177,7 @@ typedef struct isc__networker {
isc_refcount_t references;
atomic_int_fast64_t pktcount;
char *recvbuf;
char *sendbuf;
bool recvbuf_inuse;
} isc__networker_t;
@@ -236,12 +252,6 @@ typedef enum isc__netievent_type {
netievent_tcpdnsclose,
netievent_tcpdnsstop,
netievent_tlsclose,
netievent_tlssend,
netievent_tlsstartread,
netievent_tlsconnect,
netievent_tlsdobio,
netievent_tlsdnsaccept,
netievent_tlsdnsconnect,
netievent_tlsdnssend,
@@ -249,6 +259,8 @@ typedef enum isc__netievent_type {
netievent_tlsdnscancel,
netievent_tlsdnsclose,
netievent_tlsdnsstop,
netievent_tlsdnscycle,
netievent_tlsdnsshutdown,
netievent_close,
netievent_shutdown,
@@ -267,6 +279,7 @@ typedef enum isc__netievent_type {
netievent_udplisten,
netievent_tcplisten,
netievent_tcpdnslisten,
netievent_tlsdnslisten,
netievent_resume,
netievent_detach,
} isc__netievent_type;
@@ -629,8 +642,6 @@ typedef enum isc_nmsocket_type {
isc_nm_tcplistener,
isc_nm_tcpdnslistener,
isc_nm_tcpdnssocket,
isc_nm_tlslistener,
isc_nm_tlssocket,
isc_nm_tlsdnslistener,
isc_nm_tlsdnssocket
} isc_nmsocket_type;
@@ -674,22 +685,24 @@ struct isc_nmsocket {
/*% TLS stuff */
struct tls {
bool server;
BIO *app_bio;
SSL *ssl;
SSL_CTX *ctx;
BIO *ssl_bio;
BIO *app_rbio;
BIO *app_wbio;
BIO *ssl_rbio;
BIO *ssl_wbio;
enum {
TLS_INIT,
TLS_HANDSHAKE,
TLS_IO,
TLS_ERROR,
TLS_CLOSING
TLS_STATE_NONE,
TLS_STATE_HANDSHAKE,
TLS_STATE_IO,
TLS_STATE_ERROR,
TLS_STATE_CLOSING
} state;
isc_region_t senddata;
bool sending;
uv_buf_t senddata;
bool cycle;
isc_result_t pending_error;
/* List of active send requests. */
ISC_LIST(isc__nm_uvreq_t) sends;
isc__nm_uvreq_t *pending_req;
} tls;
/*%
@@ -1027,13 +1040,6 @@ isc__nm_async_connectcb(isc__networker_t *worker, isc__netievent_t *ev0);
*/
isc_result_t
isc__nm_acceptcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq,
isc_result_t eresult);
/*%<
* Issue a synchronous accept callback on the socket.
*/
void
isc__nm_readcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq,
isc_result_t eresult);
@@ -1214,25 +1220,6 @@ 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_tlsstartread(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_tlsdobio(isc__networker_t *worker, isc__netievent_t *ev0);
/*%<
* Callback handlers for asynchronouse TLS events.
*/
void
isc__nm_async_tcpdnsaccept(isc__networker_t *worker, isc__netievent_t *ev0);
void
@@ -1293,6 +1280,14 @@ isc__nm_tcpdns_cancelread(isc_nmhandle_t *handle);
* Stop reading on a connected TCPDNS handle.
*/
void
isc__nm_async_tlsdnscycle(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_tlsdnsaccept(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_tlsdnsconnect(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_tlsdnslisten(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_tlsdns_send(isc_nmhandle_t *handle, isc_region_t *region,
isc_nm_cb_t cb, void *cbarg);
@@ -1322,6 +1317,10 @@ isc__nm_tlsdns_settimeout(isc_nmhandle_t *handle, uint32_t timeout);
* associated with 'handle', and the TCP socket it wraps around.
*/
void
isc__nm_async_tlsdnslisten(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_tlsdnsaccept(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_tlsdnscancel(isc__networker_t *worker, isc__netievent_t *ev0);
void
@@ -1330,6 +1329,8 @@ void
isc__nm_async_tlsdnssend(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_tlsdnsstop(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_tlsdnsshutdown(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_tlsdnsread(isc__networker_t *worker, isc__netievent_t *ev0);
@@ -1343,35 +1344,6 @@ isc__nm_tlsdns_cancelread(isc_nmhandle_t *handle);
* Stop reading on a connected TLSDNS 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_nmhandle_t *handle);
/*%<
* Pause reading on this handle, while still remembering the callback.
*/
void
isc__nm_tls_resumeread(isc_nmhandle_t *handle);
/*%<
* Resume reading from the handle.
*
*/
void
isc__nm_tls_stoplistening(isc_nmsocket_t *sock);
#define isc__nm_uverr2result(x) \
isc___nm_uverr2result(x, true, __FILE__, __LINE__, __func__)
isc_result_t
@@ -1463,12 +1435,6 @@ isc__nm_socket_connectiontimeout(uv_os_sock_t fd, int timeout_ms);
* the minimum value must be at least 1000 (1 second).
*/
void
isc__nm_tls_initialize(void);
/*%<
* Initialize OpenSSL library, idempotent.
*/
/*
* typedef all the netievent types
*/
@@ -1478,11 +1444,6 @@ NETIEVENT_SOCKET_TYPE(tcpclose);
NETIEVENT_SOCKET_TYPE(tcplisten);
NETIEVENT_SOCKET_TYPE(tcppauseread);
NETIEVENT_SOCKET_TYPE(tcpstop);
NETIEVENT_SOCKET_TYPE(tlsclose);
/* NETIEVENT_SOCKET_TYPE(tlsconnect); */ /* unique type, defined independently
*/
NETIEVENT_SOCKET_TYPE(tlsdobio);
NETIEVENT_SOCKET_TYPE(tlsstartread);
NETIEVENT_SOCKET_TYPE(udpclose);
NETIEVENT_SOCKET_TYPE(udplisten);
NETIEVENT_SOCKET_TYPE(udpread);
@@ -1501,13 +1462,17 @@ NETIEVENT_SOCKET_QUOTA_TYPE(tcpdnsaccept);
NETIEVENT_SOCKET_TYPE(tlsdnsclose);
NETIEVENT_SOCKET_TYPE(tlsdnsread);
NETIEVENT_SOCKET_TYPE(tlsdnsstop);
NETIEVENT_SOCKET_TYPE(tlsdnsshutdown);
NETIEVENT_SOCKET_TYPE(tlsdnslisten);
NETIEVENT_SOCKET_REQ_TYPE(tlsdnsconnect);
NETIEVENT_SOCKET_REQ_TYPE(tlsdnssend);
NETIEVENT_SOCKET_HANDLE_TYPE(tlsdnscancel);
NETIEVENT_SOCKET_QUOTA_TYPE(tlsdnsaccept);
NETIEVENT_SOCKET_TYPE(tlsdnscycle);
NETIEVENT_SOCKET_REQ_TYPE(tcpconnect);
NETIEVENT_SOCKET_REQ_TYPE(tcpsend);
NETIEVENT_SOCKET_TYPE(tcpstartread);
NETIEVENT_SOCKET_REQ_TYPE(tlssend);
NETIEVENT_SOCKET_REQ_TYPE(udpconnect);
NETIEVENT_SOCKET_REQ_RESULT_TYPE(connectcb);
@@ -1533,10 +1498,6 @@ NETIEVENT_SOCKET_DECL(tcplisten);
NETIEVENT_SOCKET_DECL(tcppauseread);
NETIEVENT_SOCKET_DECL(tcpstartread);
NETIEVENT_SOCKET_DECL(tcpstop);
NETIEVENT_SOCKET_DECL(tlsclose);
NETIEVENT_SOCKET_DECL(tlsconnect);
NETIEVENT_SOCKET_DECL(tlsdobio);
NETIEVENT_SOCKET_DECL(tlsstartread);
NETIEVENT_SOCKET_DECL(udpclose);
NETIEVENT_SOCKET_DECL(udplisten);
NETIEVENT_SOCKET_DECL(udpread);
@@ -1555,12 +1516,16 @@ NETIEVENT_SOCKET_QUOTA_DECL(tcpdnsaccept);
NETIEVENT_SOCKET_DECL(tlsdnsclose);
NETIEVENT_SOCKET_DECL(tlsdnsread);
NETIEVENT_SOCKET_DECL(tlsdnsstop);
NETIEVENT_SOCKET_DECL(tlsdnsshutdown);
NETIEVENT_SOCKET_DECL(tlsdnslisten);
NETIEVENT_SOCKET_REQ_DECL(tlsdnsconnect);
NETIEVENT_SOCKET_REQ_DECL(tlsdnssend);
NETIEVENT_SOCKET_HANDLE_DECL(tlsdnscancel);
NETIEVENT_SOCKET_QUOTA_DECL(tlsdnsaccept);
NETIEVENT_SOCKET_DECL(tlsdnscycle);
NETIEVENT_SOCKET_REQ_DECL(tcpconnect);
NETIEVENT_SOCKET_REQ_DECL(tcpsend);
NETIEVENT_SOCKET_REQ_DECL(tlssend);
NETIEVENT_SOCKET_REQ_DECL(udpconnect);
NETIEVENT_SOCKET_REQ_RESULT_DECL(connectcb);

View File

@@ -17,6 +17,7 @@
#include <isc/buffer.h>
#include <isc/condition.h>
#include <isc/errno.h>
#include <isc/log.h>
#include <isc/magic.h>
#include <isc/mem.h>
#include <isc/netmgr.h>
@@ -30,9 +31,11 @@
#include <isc/stats.h>
#include <isc/strerr.h>
#include <isc/thread.h>
#include <isc/tls.h>
#include <isc/util.h>
#include "netmgr-int.h"
#include "openssl_shim.h"
#include "uv-compat.h"
#ifdef NETMGR_TRACE
@@ -213,7 +216,7 @@ isc_nm_start(isc_mem_t *mctx, uint32_t workers) {
isc__nm_winsock_initialize();
#endif /* WIN32 */
isc__nm_tls_initialize();
isc_tls_initialize();
mgr = isc_mem_get(mctx, sizeof(*mgr));
*mgr = (isc_nm_t){ .nworkers = workers };
@@ -276,6 +279,7 @@ isc_nm_start(isc_mem_t *mctx, uint32_t workers) {
worker->ievents = isc_queue_new(mgr->mctx, 128);
worker->ievents_prio = isc_queue_new(mgr->mctx, 128);
worker->recvbuf = isc_mem_get(mctx, ISC_NETMGR_RECVBUF_SIZE);
worker->sendbuf = isc_mem_get(mctx, ISC_NETMGR_SENDBUF_SIZE);
/*
* We need to do this here and not in nm_thread to avoid a
@@ -346,6 +350,8 @@ nm_destroy(isc_nm_t **mgr0) {
isc_mutex_destroy(&worker->lock);
isc_condition_destroy(&worker->cond);
isc_mem_put(mgr->mctx, worker->sendbuf,
ISC_NETMGR_SENDBUF_SIZE);
isc_mem_put(mgr->mctx, worker->recvbuf,
ISC_NETMGR_RECVBUF_SIZE);
isc_thread_join(worker->thread, NULL);
@@ -368,6 +374,8 @@ nm_destroy(isc_nm_t **mgr0) {
mgr->nworkers * sizeof(isc__networker_t));
isc_mem_putanddetach(&mgr->mctx, mgr, sizeof(*mgr));
isc_tls_destroy();
#ifdef WIN32
isc__nm_winsock_destroy();
#endif /* WIN32 */
@@ -708,17 +716,16 @@ process_netievent(isc__networker_t *worker, isc__netievent_t *ievent) {
NETIEVENT_CASE(tcpdnsread);
NETIEVENT_CASE(tcpdnsstop);
NETIEVENT_CASE(tlsstartread);
NETIEVENT_CASE(tlssend);
NETIEVENT_CASE(tlsclose);
NETIEVENT_CASE(tlsconnect);
NETIEVENT_CASE(tlsdobio);
NETIEVENT_CASE(tlsdnscycle);
NETIEVENT_CASE(tlsdnsaccept);
NETIEVENT_CASE(tlsdnslisten);
NETIEVENT_CASE(tlsdnsconnect);
NETIEVENT_CASE(tlsdnssend);
NETIEVENT_CASE(tlsdnscancel);
NETIEVENT_CASE(tlsdnsclose);
NETIEVENT_CASE(tlsdnsread);
NETIEVENT_CASE(tlsdnsstop);
NETIEVENT_CASE(tlsdnsshutdown);
NETIEVENT_CASE(connectcb);
NETIEVENT_CASE(readcb);
@@ -769,10 +776,6 @@ NETIEVENT_SOCKET_DEF(tcplisten);
NETIEVENT_SOCKET_DEF(tcppauseread);
NETIEVENT_SOCKET_DEF(tcpstartread);
NETIEVENT_SOCKET_DEF(tcpstop);
NETIEVENT_SOCKET_DEF(tlsclose);
NETIEVENT_SOCKET_DEF(tlsconnect);
NETIEVENT_SOCKET_DEF(tlsdobio);
NETIEVENT_SOCKET_DEF(tlsstartread);
NETIEVENT_SOCKET_DEF(udpclose);
NETIEVENT_SOCKET_DEF(udplisten);
NETIEVENT_SOCKET_DEF(udpread);
@@ -791,12 +794,16 @@ NETIEVENT_SOCKET_QUOTA_DEF(tcpdnsaccept);
NETIEVENT_SOCKET_DEF(tlsdnsclose);
NETIEVENT_SOCKET_DEF(tlsdnsread);
NETIEVENT_SOCKET_DEF(tlsdnsstop);
NETIEVENT_SOCKET_DEF(tlsdnslisten);
NETIEVENT_SOCKET_REQ_DEF(tlsdnsconnect);
NETIEVENT_SOCKET_REQ_DEF(tlsdnssend);
NETIEVENT_SOCKET_HANDLE_DEF(tlsdnscancel);
NETIEVENT_SOCKET_QUOTA_DEF(tlsdnsaccept);
NETIEVENT_SOCKET_DEF(tlsdnscycle);
NETIEVENT_SOCKET_DEF(tlsdnsshutdown);
NETIEVENT_SOCKET_REQ_DEF(tcpconnect);
NETIEVENT_SOCKET_REQ_DEF(tcpsend);
NETIEVENT_SOCKET_REQ_DEF(tlssend);
NETIEVENT_SOCKET_REQ_DEF(udpconnect);
NETIEVENT_SOCKET_REQ_RESULT_DEF(connectcb);
@@ -1087,9 +1094,6 @@ isc___nmsocket_prep_destroy(isc_nmsocket_t *sock FLARG) {
case isc_nm_tcpdnssocket:
isc__nm_tcpdns_close(sock);
return;
case isc_nm_tlssocket:
isc__nm_tls_close(sock);
break;
case isc_nm_tlsdnssocket:
isc__nm_tlsdns_close(sock);
return;
@@ -1349,7 +1353,7 @@ isc___nmhandle_get(isc_nmsocket_t *sock, isc_sockaddr_t *peer,
#endif
UNLOCK(&sock->lock);
if (sock->type == isc_nm_tcpsocket || sock->type == isc_nm_tlssocket ||
if (sock->type == isc_nm_tcpsocket ||
(sock->type == isc_nm_udpsocket && atomic_load(&sock->client)) ||
(sock->type == isc_nm_tcpdnssocket && atomic_load(&sock->client)) ||
(sock->type == isc_nm_tlsdnssocket && atomic_load(&sock->client)))
@@ -1386,7 +1390,6 @@ isc_nmhandle_is_stream(isc_nmhandle_t *handle) {
return (handle->sock->type == isc_nm_tcpsocket ||
handle->sock->type == isc_nm_tcpdnssocket ||
handle->sock->type == isc_nm_tlssocket ||
handle->sock->type == isc_nm_tlsdnssocket);
}
@@ -1664,9 +1667,6 @@ 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;
case isc_nm_tlsdnssocket:
isc__nm_tlsdns_send(handle, region, cb, cbarg);
break;
@@ -1697,9 +1697,6 @@ 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;
case isc_nm_tlsdnssocket:
isc__nm_tlsdns_read(handle, cb, cbarg);
break;
@@ -1742,9 +1739,6 @@ isc_nm_pauseread(isc_nmhandle_t *handle) {
case isc_nm_tcpsocket:
isc__nm_tcp_pauseread(handle);
break;
case isc_nm_tlssocket:
isc__nm_tls_pauseread(handle);
break;
default:
INSIST(0);
ISC_UNREACHABLE();
@@ -1761,9 +1755,6 @@ isc_nm_resumeread(isc_nmhandle_t *handle) {
case isc_nm_tcpsocket:
isc__nm_tcp_resumeread(handle);
break;
case isc_nm_tlssocket:
isc__nm_tls_resumeread(handle);
break;
default:
INSIST(0);
ISC_UNREACHABLE();
@@ -1784,9 +1775,6 @@ 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;
case isc_nm_tlsdnslistener:
isc__nm_tlsdns_stoplistening(sock);
break;
@@ -1975,7 +1963,7 @@ shutdown_walk_cb(uv_handle_t *handle, void *arg) {
isc__nm_tcpdns_shutdown(sock);
break;
case isc_nm_tlsdnssocket:
/* dummy now */
isc__nm_tlsdns_shutdown(sock);
break;
case isc_nm_udplistener:
case isc_nm_tcplistener:
@@ -2334,10 +2322,6 @@ 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");
case isc_nm_tlsdnslistener:
return ("isc_nm_tlsdnslistener");
case isc_nm_tlsdnssocket:

View File

@@ -113,16 +113,6 @@ stop_reading(isc_nmsocket_t *sock);
static isc__nm_uvreq_t *
get_read_req(isc_nmsocket_t *sock);
/*
* Regular TCP buffer, should suffice in most cases.
*/
#define NM_REG_BUF 4096
/*
* Two full DNS packets with lengths.
* netmgr receives 64k at most so there's no risk
* of overrun.
*/
#define NM_BIG_BUF (65535 + 2) * 2
static inline void
alloc_dnsbuf(isc_nmsocket_t *sock, size_t len) {
REQUIRE(len <= NM_BIG_BUF);
@@ -790,7 +780,7 @@ get_read_req(isc_nmsocket_t *sock) {
req->handle = isc__nmhandle_get(sock, NULL, NULL);
}
return req;
return (req);
}
static void
@@ -813,25 +803,26 @@ start_sock_timer(isc_nmsocket_t *sock) {
if (sock->read_timeout > 0) {
int r = uv_timer_start(&sock->timer, readtimeout_cb,
sock->read_timeout, 0);
REQUIRE(r == 0);
RUNTIME_CHECK(r == 0);
}
}
static void
stop_sock_timer(isc_nmsocket_t *sock) {
int r = uv_timer_stop(&sock->timer);
REQUIRE(r == 0);
RUNTIME_CHECK(r == 0);
}
static void
start_reading(isc_nmsocket_t *sock) {
int r;
if (sock->reading) {
return;
}
int r = uv_read_start(&sock->uv_handle.stream, tcpdns_alloc_cb,
read_cb);
REQUIRE(r == 0);
r = uv_read_start(&sock->uv_handle.stream, tcpdns_alloc_cb, read_cb);
RUNTIME_CHECK(r == 0);
sock->reading = true;
start_sock_timer(sock);
@@ -839,12 +830,14 @@ start_reading(isc_nmsocket_t *sock) {
static void
stop_reading(isc_nmsocket_t *sock) {
int r;
if (!sock->reading) {
return;
}
int r = uv_read_stop(&sock->uv_handle.stream);
REQUIRE(r == 0);
r = uv_read_stop(&sock->uv_handle.stream);
RUNTIME_CHECK(r == 0);
sock->reading = false;
stop_sock_timer(sock);
@@ -898,10 +891,11 @@ tcpdns_alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf) {
isc_nmsocket_t *sock = uv_handle_get_data(handle);
isc__networker_t *worker = NULL;
UNUSED(size);
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->type == isc_nm_tcpdnssocket);
REQUIRE(isc__nm_in_netthread());
UNUSED(size);
worker = &sock->mgr->workers[sock->tid];
INSIST(!worker->recvbuf_inuse);
@@ -917,9 +911,10 @@ isc__nm_async_tcpdnsread(isc__networker_t *worker, isc__netievent_t *ev0) {
(isc__netievent_tcpdnsread_t *)ev0;
isc_nmsocket_t *sock = ievent->sock;
UNUSED(worker);
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->tid == isc_nm_tid());
UNUSED(worker);
if (inactive(sock)) {
sock->reading = true;
@@ -1303,9 +1298,10 @@ isc__nm_async_tcpdnssend(isc__networker_t *worker, isc__netievent_t *ev0) {
isc_nmsocket_t *sock = ievent->sock;
isc__nm_uvreq_t *uvreq = ievent->req;
UNUSED(worker);
REQUIRE(sock->type == isc_nm_tcpdnssocket);
REQUIRE(sock->tid == isc_nm_tid());
UNUSED(worker);
result = tcpdns_send_direct(sock, uvreq);
if (result != ISC_R_SUCCESS) {
@@ -1316,12 +1312,13 @@ isc__nm_async_tcpdnssend(isc__networker_t *worker, isc__netievent_t *ev0) {
static isc_result_t
tcpdns_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
int r;
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(VALID_UVREQ(req));
REQUIRE(sock->tid == isc_nm_tid());
REQUIRE(sock->type == isc_nm_tcpdnssocket);
int r;
uv_buf_t bufs[2] = { { .base = req->tcplen, .len = 2 },
{ .base = req->uvbuf.base,
.len = req->uvbuf.len } };
@@ -1342,12 +1339,13 @@ tcpdns_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
static void
tcpdns_stop_cb(uv_handle_t *handle) {
isc_nmsocket_t *sock = uv_handle_get_data(handle);
uv_handle_set_data(handle, NULL);
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->tid == isc_nm_tid());
REQUIRE(atomic_load(&sock->closing));
uv_handle_set_data(handle, NULL);
if (!atomic_compare_exchange_strong(&sock->closed, &(bool){ false },
true)) {
INSIST(0);
@@ -1364,6 +1362,7 @@ tcpdns_stop_cb(uv_handle_t *handle) {
static void
tcpdns_close_cb(uv_handle_t *handle) {
isc_nmsocket_t *sock = uv_handle_get_data(handle);
uv_handle_set_data(handle, NULL);
REQUIRE(VALID_NMSOCK(sock));
@@ -1498,11 +1497,11 @@ isc__nm_async_tcpdnsclose(isc__networker_t *worker, isc__netievent_t *ev0) {
(isc__netievent_tcpdnsclose_t *)ev0;
isc_nmsocket_t *sock = ievent->sock;
UNUSED(worker);
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->tid == isc_nm_tid());
UNUSED(worker);
tcpdns_close_direct(sock);
}
@@ -1560,19 +1559,22 @@ isc__nm_async_tcpdnscancel(isc__networker_t *worker, isc__netievent_t *ev0) {
(isc__netievent_tcpdnscancel_t *)ev0;
isc_nmsocket_t *sock = ievent->sock;
UNUSED(worker);
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->tid == isc_nm_tid());
UNUSED(worker);
failed_read_cb(sock, ISC_R_EOF);
}
void
isc__nm_tcpdns_settimeout(isc_nmhandle_t *handle, uint32_t timeout) {
isc_nmsocket_t *sock = NULL;
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(VALID_NMSOCK(handle->sock));
isc_nmsocket_t *sock = handle->sock;
sock = handle->sock;
sock->read_timeout = timeout;
if (uv_is_active((uv_handle_t *)&sock->timer)) {
@@ -1582,11 +1584,13 @@ isc__nm_tcpdns_settimeout(isc_nmhandle_t *handle, uint32_t timeout) {
void
isc_nm_tcpdns_sequential(isc_nmhandle_t *handle) {
isc_nmsocket_t *sock = NULL;
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(VALID_NMSOCK(handle->sock));
REQUIRE(handle->sock->type == isc_nm_tcpdnssocket);
isc_nmsocket_t *sock = handle->sock;
sock = handle->sock;
/*
* We don't want pipelining on this connection. That means
@@ -1603,11 +1607,13 @@ isc_nm_tcpdns_sequential(isc_nmhandle_t *handle) {
void
isc_nm_tcpdns_keepalive(isc_nmhandle_t *handle, bool value) {
isc_nmsocket_t *sock = NULL;
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(VALID_NMSOCK(handle->sock));
REQUIRE(handle->sock->type != isc_nm_tcpdnssocket);
isc_nmsocket_t *sock = handle->sock;
sock = handle->sock;
atomic_store(&sock->keepalive, value);
}

View File

@@ -1,907 +0,0 @@
/*
* 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 <libgen.h>
#include <unistd.h>
#include <uv.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <isc/atomic.h>
#include <isc/buffer.h>
#include <isc/condition.h>
#include <isc/log.h>
#include <isc/magic.h>
#include <isc/mem.h>
#include <isc/netmgr.h>
#include <isc/once.h>
#include <isc/quota.h>
#include <isc/random.h>
#include <isc/refcount.h>
#include <isc/region.h>
#include <isc/result.h>
#include <isc/sockaddr.h>
#include <isc/stdtime.h>
#include <isc/thread.h>
#include <isc/util.h>
#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);
/*
* The socket is closing, outerhandle has been detached, listener is
* inactive, or the netmgr is closing: any operation on it should abort
* with ISC_R_CANCELED.
*/
static bool
inactive(isc_nmsocket_t *sock) {
return (!isc__nmsocket_active(sock) || atomic_load(&sock->closing) ||
sock->outerhandle == NULL ||
(sock->listener != NULL &&
!isc__nmsocket_active(sock->listener)) ||
atomic_load(&sock->mgr->closing));
}
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_netievent_tlsdobio(sock->mgr, 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 (inactive(sock)) {
result = ISC_R_CANCELED;
goto error;
}
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;
}
switch (tls_err) {
case 0:
return;
case 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;
}
break;
case SSL_ERROR_WANT_READ:
isc_nm_resumeread(sock->outerhandle);
break;
default:
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) {
REQUIRE(VALID_NMSOCK(cbarg));
isc_nmsocket_t *tlslistensock = (isc_nmsocket_t *)cbarg;
isc_nmsocket_t *tlssock = NULL;
int r;
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 = atomic_load(&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);
}
r = uv_timer_init(&tlssock->mgr->workers[isc_nm_tid()].loop,
&tlssock->timer);
RUNTIME_CHECK(r == 0);
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_nmsocket_t *sock = ievent->sock;
isc__nm_uvreq_t *req = ievent->req;
ievent->req = NULL;
REQUIRE(VALID_UVREQ(req));
REQUIRE(sock->tid == isc_nm_tid());
UNUSED(worker);
if (inactive(sock)) {
req->cb.send(req->handle, ISC_R_CANCELED, req->cbarg);
isc__nm_uvreq_put(&req, sock);
return;
}
if (!ISC_LIST_EMPTY(sock->tls.sends)) {
/* We're not the first */
ISC_LIST_APPEND(sock->tls.sends, req, link);
tls_do_bio(sock);
return;
}
rv = SSL_write(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(sock->tls.sends, req, link);
tls_do_bio(sock);
return;
}
if (rv != (int)req->uvbuf.len) {
sock->tls.state = TLS_ERROR;
async_tls_do_bio(sock);
return;
}
req->cb.send(sock->statichandle, ISC_R_SUCCESS, req->cbarg);
isc__nm_uvreq_put(&req, sock);
tls_do_bio(sock);
return;
}
void
isc__nm_tls_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
void *cbarg) {
isc__netievent_tlssend_t *ievent = NULL;
isc__nm_uvreq_t *uvreq = NULL;
isc_nmsocket_t *sock = NULL;
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(VALID_NMSOCK(handle->sock));
sock = handle->sock;
REQUIRE(sock->type == isc_nm_tlssocket);
if (inactive(sock)) {
cb(handle, ISC_R_CANCELED, cbarg);
return;
}
uvreq = isc__nm_uvreq_get(sock->mgr, sock);
isc_nmhandle_attach(handle, &uvreq->handle);
uvreq->cb.send = cb;
uvreq->cbarg = cbarg;
uvreq->uvbuf.base = (char *)region->base;
uvreq->uvbuf.len = region->length;
/*
* We need to create an event and pass it using async channel
*/
ievent = isc__nm_get_netievent_tlssend(sock->mgr, sock, uvreq);
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
(isc__netievent_t *)ievent);
}
void
isc__nm_async_tlsstartread(isc__networker_t *worker, isc__netievent_t *ev0) {
isc__netievent_tlsstartread_t *ievent =
(isc__netievent_tlsstartread_t *)ev0;
isc_nmsocket_t *sock = ievent->sock;
REQUIRE(sock->tid == isc_nm_tid());
UNUSED(worker);
tls_do_bio(sock);
}
void
isc__nm_tls_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(VALID_NMSOCK(handle->sock));
REQUIRE(handle->sock->statichandle == handle);
REQUIRE(handle->sock->tid == isc_nm_tid());
isc__netievent_tlsstartread_t *ievent = NULL;
isc_nmsocket_t *sock = handle->sock;
if (inactive(sock)) {
cb(handle, ISC_R_NOTCONNECTED, NULL, cbarg);
return;
}
sock->recv_cb = cb;
sock->recv_cbarg = cbarg;
ievent = isc__nm_get_netievent_tlsstartread(sock->mgr, sock);
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
(isc__netievent_t *)ievent);
}
void
isc__nm_tls_pauseread(isc_nmhandle_t *handle) {
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(VALID_NMSOCK(handle->sock));
isc_nmsocket_t *sock = handle->sock;
atomic_store(&sock->readpaused, true);
}
void
isc__nm_tls_resumeread(isc_nmhandle_t *handle) {
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(VALID_NMSOCK(handle->sock));
isc_nmsocket_t *sock = handle->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);
tls_close_direct(sock);
}
static void
tls_close_direct(isc_nmsocket_t *sock) {
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->tid == isc_nm_tid());
if (sock->timer_running) {
uv_timer_stop(&sock->timer);
sock->timer_running = false;
}
/* 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);
isc__nmsocket_detach(&sock);
}
}
void
isc__nm_tls_close(isc_nmsocket_t *sock) {
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->type == isc_nm_tlssocket);
if (!atomic_compare_exchange_strong(&sock->closing, &(bool){ false },
true)) {
return;
}
if (sock->tid == isc_nm_tid()) {
tls_close_direct(sock);
} else {
isc__netievent_tlsclose_t *ievent =
isc__nm_get_netievent_tlsclose(sock->mgr, 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(ievent->sock->tid == isc_nm_tid());
UNUSED(worker);
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;
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;
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_netievent_tlsconnect(mgr, nsock);
ievent->local = local->addr;
ievent->peer = peer->addr;
ievent->ctx = ctx;
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_netievent_tlsconnect(mgr, ievent);
} else {
nsock->tid = isc_random_uniform(mgr->nworkers);
isc__nm_enqueue_ievent(&mgr->workers[nsock->tid],
(isc__netievent_t *)ievent);
}
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(handle, result, tlssock->connect_cbarg);
LOCK(&tlssock->parent->lock);
tlssock->parent->result = result;
UNLOCK(&tlssock->parent->lock);
tls_close_direct(tlssock);
return;
}
INSIST(VALID_NMHANDLE(handle));
tlssock->peer = isc_nmhandle_peeraddr(handle);
isc_nmhandle_attach(handle, &tlssock->outerhandle);
result = initialize_tls(tlssock, false);
if (result != ISC_R_SUCCESS) {
tlssock->connect_cb(handle, result, tlssock->connect_cbarg);
LOCK(&tlssock->parent->lock);
tlssock->parent->result = result;
UNLOCK(&tlssock->parent->lock);
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;
int r;
UNUSED(worker);
tlssock->tid = isc_nm_tid();
r = uv_timer_init(&tlssock->mgr->workers[isc_nm_tid()].loop,
&tlssock->timer);
RUNTIME_CHECK(r == 0);
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) {
/* FIXME: We need to pass valid handle */
tlssock->connect_cb(NULL, result, tlssock->connect_cbarg);
LOCK(&tlssock->parent->lock);
tlssock->parent->result = result;
UNLOCK(&tlssock->parent->lock);
tls_close_direct(tlssock);
return;
}
}
void
isc__nm_async_tlsdobio(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;
bool ephemeral = (keyfile == NULL && certfile == NULL);
X509 *cert = NULL;
EVP_PKEY *pkey = NULL;
BIGNUM *bn = NULL;
RSA *rsa = NULL;
if (ephemeral) {
INSIST(keyfile == NULL);
INSIST(certfile == NULL);
} else {
INSIST(keyfile != NULL);
INSIST(certfile != NULL);
}
#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);
if (ephemeral) {
rsa = RSA_new();
if (rsa == NULL) {
goto ssl_error;
}
bn = BN_new();
if (bn == NULL) {
goto ssl_error;
}
BN_set_word(bn, RSA_F4);
rv = RSA_generate_key_ex(rsa, 4096, bn, NULL);
if (rv != 1) {
goto ssl_error;
}
cert = X509_new();
if (cert == NULL) {
goto ssl_error;
}
pkey = EVP_PKEY_new();
if (pkey == NULL) {
goto ssl_error;
}
/*
* EVP_PKEY_assign_*() set the referenced key to key
* however these use the supplied key internally and so
* key will be freed when the parent pkey is freed.
*/
EVP_PKEY_assign(pkey, EVP_PKEY_RSA, rsa);
rsa = NULL;
ASN1_INTEGER_set(X509_get_serialNumber(cert), 1);
X509_gmtime_adj(X509_get_notBefore(cert), 0);
/*
* We set the vailidy for 10 years.
*/
X509_gmtime_adj(X509_get_notAfter(cert), 3650 * 24 * 3600);
X509_set_pubkey(cert, pkey);
X509_NAME *name = X509_get_subject_name(cert);
X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC,
(const unsigned char *)"AQ", -1, -1,
0);
X509_NAME_add_entry_by_txt(
name, "O", MBSTRING_ASC,
(const unsigned char *)"BIND9 ephemeral "
"certificate",
-1, -1, 0);
X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
(const unsigned char *)"bind9.local",
-1, -1, 0);
X509_set_issuer_name(cert, name);
X509_sign(cert, pkey, EVP_sha256());
rv = SSL_CTX_use_certificate(ctx, cert);
if (rv != 1) {
goto ssl_error;
}
rv = SSL_CTX_use_PrivateKey(ctx, pkey);
if (rv != 1) {
goto ssl_error;
}
X509_free(cert);
EVP_PKEY_free(pkey);
BN_free(bn);
} else {
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);
if (ctx != NULL) {
SSL_CTX_free(ctx);
}
if (cert != NULL) {
X509_free(cert);
}
if (pkey != NULL) {
EVP_PKEY_free(pkey);
}
if (bn != NULL) {
BN_free(bn);
}
if (rsa != NULL) {
RSA_free(rsa);
}
return (ISC_R_TLSERROR);
}
void
isc__nm_tls_initialize() {
#if OPENSSL_VERSION_NUMBER < 0x10100000L
SSL_library_init();
#else
OPENSSL_init_ssl(0, NULL);
#endif
}

File diff suppressed because it is too large Load Diff

View File

@@ -9,7 +9,7 @@
* information regarding copyright ownership.
*/
#include "openssl_shim.h"
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
@@ -18,13 +18,16 @@
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/opensslv.h>
#include <openssl/ssl.h>
#include "openssl_shim.h"
#if !HAVE_CRYPTO_ZALLOC
void *
CRYPTO_zalloc(size_t size) {
void *ret = OPENSSL_malloc(size);
CRYPTO_zalloc(size_t num, const char *file, int line) {
void *ret = CRYPTO_malloc(num, file, line);
if (ret != NULL) {
memset(ret, 0, size);
memset(ret, 0, num);
}
return (ret);
}
@@ -114,3 +117,106 @@ HMAC_CTX_get_md(const HMAC_CTX *ctx) {
return (ctx->md);
}
#endif /* if !HAVE_HMAC_CTX_GET_MD */
#if !HAVE_SSL_READ_EX
int
SSL_read_ex(SSL *ssl, void *buf, size_t num, size_t *readbytes) {
int rv = SSL_read(ssl, buf, num);
if (rv > 0) {
*readbytes = rv;
rv = 1;
}
return (rv);
}
#endif
#if !HAVE_SSL_PEEK_EX
int
SSL_peek_ex(SSL *ssl, void *buf, size_t num, size_t *readbytes) {
int rv = SSL_peek(ssl, buf, num);
if (rv > 0) {
*readbytes = rv;
rv = 1;
}
return (rv);
}
#endif
#if !HAVE_SSL_WRITE_EX
int
SSL_write_ex(SSL *ssl, const void *buf, size_t num, size_t *written) {
int rv = SSL_write(ssl, buf, num);
if (rv > 0) {
*written = rv;
rv = 1;
}
return (rv);
}
#endif
#if !HAVE_BIO_READ_EX
int
BIO_read_ex(BIO *b, void *data, size_t dlen, size_t *readbytes) {
int rv = BIO_read(b, data, dlen);
if (rv > 0) {
*readbytes = rv;
rv = 1;
}
return (rv);
}
#endif
#if !HAVE_BIO_WRITE_EX
int
BIO_write_ex(BIO *b, const void *data, size_t dlen, size_t *written) {
int rv = BIO_write(b, data, dlen);
if (rv > 0) {
*written = rv;
rv = 1;
}
return (rv);
}
#endif
#if !HAVE_OPENSSL_INIT_CRYPTO
int
OPENSSL_init_crypto(uint64_t opts, const void *settings) {
(void)settings;
if ((opts & OPENSSL_INIT_NO_LOAD_CRYPTO_STRINGS) == 0) {
ERR_load_crypto_strings();
}
if ((opts & (OPENSSL_INIT_NO_ADD_ALL_CIPHERS |
OPENSSL_INIT_NO_ADD_ALL_CIPHERS)) == 0)
{
OpenSSL_add_all_algorithms();
} else if ((opts & OPENSSL_INIT_NO_ADD_ALL_CIPHERS) == 0) {
OpenSSL_add_all_digests();
} else if ((opts & OPENSSL_INIT_NO_ADD_ALL_CIPHERS) == 0) {
OpenSSL_add_all_ciphers();
}
return (1);
}
#endif
#if !HAVE_OPENSSL_INIT_SSL
int
OPENSSL_init_ssl(uint64_t opts, const void *settings) {
OPENSSL_init_crypto(opts, settings);
SSL_library_init();
if ((opts & OPENSSL_INIT_NO_LOAD_SSL_STRINGS) == 0) {
SSL_load_error_strings();
}
return (1);
}
#endif

View File

@@ -16,13 +16,17 @@
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/opensslv.h>
#include <openssl/ssl.h>
#if !HAVE_CRYPTO_ZALLOC
void *
CRYPTO_zalloc(size_t size);
#define OPENSSL_zalloc(num) CRYPTO_zalloc(num)
CRYPTO_zalloc(size_t num, const char *file, int line);
#endif /* if !HAVE_CRYPTO_ZALLOC */
#if !defined(OPENSSL_zalloc)
#define OPENSSL_zalloc(num) CRYPTO_zalloc(num, __FILE__, __LINE__)
#endif
#if !HAVE_EVP_CIPHER_CTX_NEW
EVP_CIPHER_CTX *
EVP_CIPHER_CTX_new(void);
@@ -67,3 +71,58 @@ HMAC_CTX_reset(HMAC_CTX *ctx);
const EVP_MD *
HMAC_CTX_get_md(const HMAC_CTX *ctx);
#endif /* if !HAVE_HMAC_CTX_GET_MD */
#if !HAVE_SSL_READ_EX
int
SSL_read_ex(SSL *ssl, void *buf, size_t num, size_t *readbytes);
#endif
#if !HAVE_SSL_PEEK_EX
int
SSL_peek_ex(SSL *ssl, void *buf, size_t num, size_t *readbytes);
#endif
#if !HAVE_SSL_WRITE_EX
int
SSL_write_ex(SSL *ssl, const void *buf, size_t num, size_t *written);
#endif
#if !HAVE_BIO_READ_EX
int
BIO_read_ex(BIO *b, void *data, size_t dlen, size_t *readbytes);
#endif
#if !HAVE_BIO_WRITE_EX
int
BIO_write_ex(BIO *b, const void *data, size_t dlen, size_t *written);
#endif
#if !HAVE_OPENSSL_INIT_CRYPTO
#define OPENSSL_INIT_NO_LOAD_CRYPTO_STRINGS 0x00000001L
#define OPENSSL_INIT_LOAD_CRYPTO_STRINGS 0x00000002L
#define OPENSSL_INIT_ADD_ALL_CIPHERS 0x00000004L
#define OPENSSL_INIT_ADD_ALL_DIGESTS 0x00000008L
#define OPENSSL_INIT_NO_ADD_ALL_CIPHERS 0x00000010L
#define OPENSSL_INIT_NO_ADD_ALL_DIGESTS 0x00000020L
int
OPENSSL_init_crypto(uint64_t opts, const void *settings);
#endif
#if !HAVE_OPENSSL_INIT_SSL
#define OPENSSL_INIT_NO_LOAD_SSL_STRINGS 0x00100000L
#define OPENSSL_INIT_LOAD_SSL_STRINGS 0x00200000L
int
OPENSSL_init_ssl(uint64_t opts, const void *settings);
#endif
#if !HAVE_TLS_SERVER_METHOD
#define TLS_server_method SSLv23_server_method
#endif
#if !HAVE_TLS_CLIENT_METHOD
#define TLS_client_method SSLv23_client_method
#endif

View File

@@ -15,7 +15,7 @@ libisctest_la_SOURCES = \
isctest.h \
uv_wrap.h
check_PROGRAMS = \
TESTS = \
aes_test \
buffer_test \
counter_test \
@@ -47,11 +47,13 @@ check_PROGRAMS = \
tcp_test \
tcp_quota_test \
tcpdns_test \
tlsdns_test \
time_test \
timer_test \
udp_test
TESTS = $(check_PROGRAMS)
check_PROGRAMS = \
$(TESTS)
hmac_test_CPPFLAGS = \
$(AM_CPPFLAGS) \
@@ -100,6 +102,15 @@ tcpdns_test_LDADD = \
$(LDADD) \
$(LIBUV_LIBS)
tlsdns_test_CPPFLAGS = \
$(AM_CPPFLAGS) \
$(OPENSSL_CFLAGS) \
$(LIBUV_CFLAGS)
tlsdns_test_LDADD = \
$(LDADD) \
$(LIBUV_LIBS)
udp_test_CPPFLAGS = \
$(AM_CPPFLAGS) \
$(OPENSSL_CFLAGS) \

899
lib/isc/tests/tlsdns_test.c Normal file
View File

@@ -0,0 +1,899 @@
/*
* 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.
*/
#if HAVE_CMOCKA
#include <sched.h> /* IWYU pragma: keep */
#include <setjmp.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <uv.h>
#define UNIT_TESTING
#include <cmocka.h>
#include <isc/atomic.h>
#include <isc/buffer.h>
#include <isc/condition.h>
#include <isc/mutex.h>
#include <isc/netmgr.h>
#include <isc/nonce.h>
#include <isc/os.h>
#include <isc/refcount.h>
#include <isc/sockaddr.h>
#include <isc/thread.h>
#include "../netmgr/netmgr-int.h"
#include "isctest.h"
#define MAX_NM 2
static isc_sockaddr_t tlsdns_listen_addr;
static isc_tlsctx_t *tlsdns_listen_ctx = NULL;
static isc_tlsctx_t *tlsdns_connect_ctx = NULL;
static uint64_t send_magic = 0;
static uint64_t stop_magic = 0;
static uv_buf_t send_msg = { .base = (char *)&send_magic,
.len = sizeof(send_magic) };
static uv_buf_t stop_msg = { .base = (char *)&stop_magic,
.len = sizeof(stop_magic) };
static atomic_uint_fast64_t nsends;
static atomic_uint_fast64_t ssends;
static atomic_uint_fast64_t sreads;
static atomic_uint_fast64_t cconnects;
static atomic_uint_fast64_t csends;
static atomic_uint_fast64_t creads;
static atomic_uint_fast64_t ctimeouts;
static unsigned int workers = 1;
static bool reuse_supported = true;
#define NSENDS 100
#define NWRITES 10
#define CHECK_RANGE_FULL(v) \
{ \
int __v = atomic_load(&v); \
assert_true(__v > 1); \
assert_true(__v <= NSENDS * NWRITES * 110 / 100); \
}
#define CHECK_RANGE_HALF(v) \
{ \
int __v = atomic_load(&v); \
assert_true(__v > 1); \
assert_true(__v <= NSENDS * NWRITES * 60 / 100); \
}
/* Enable this to print values while running tests */
#undef PRINT_DEBUG
#ifdef PRINT_DEBUG
#define X(v) fprintf(stderr, #v " = %" PRIu64 "\n", atomic_load(&v))
#else
#define X(v)
#endif
static int
setup_ephemeral_port(isc_sockaddr_t *addr, sa_family_t family) {
isc_result_t result;
socklen_t addrlen = sizeof(*addr);
int fd;
int r;
isc_sockaddr_fromin6(addr, &in6addr_loopback, 0);
fd = socket(AF_INET6, family, 0);
if (fd < 0) {
perror("setup_ephemeral_port: socket()");
return (-1);
}
r = bind(fd, (const struct sockaddr *)&addr->type.sa,
sizeof(addr->type.sin6));
if (r != 0) {
perror("setup_ephemeral_port: bind()");
close(fd);
return (r);
}
r = getsockname(fd, (struct sockaddr *)&addr->type.sa, &addrlen);
if (r != 0) {
perror("setup_ephemeral_port: getsockname()");
close(fd);
return (r);
}
result = isc__nm_socket_reuse(fd);
if (result != ISC_R_SUCCESS && result != ISC_R_NOTIMPLEMENTED) {
fprintf(stderr,
"setup_ephemeral_port: isc__nm_socket_reuse(): %s",
isc_result_totext(result));
close(fd);
return (-1);
}
result = isc__nm_socket_reuse_lb(fd);
if (result != ISC_R_SUCCESS && result != ISC_R_NOTIMPLEMENTED) {
fprintf(stderr,
"setup_ephemeral_port: isc__nm_socket_reuse_lb(): %s",
isc_result_totext(result));
close(fd);
return (-1);
}
if (result == ISC_R_NOTIMPLEMENTED) {
reuse_supported = false;
}
#if IPV6_RECVERR
#define setsockopt_on(socket, level, name) \
setsockopt(socket, level, name, &(int){ 1 }, sizeof(int))
r = setsockopt_on(fd, IPPROTO_IPV6, IPV6_RECVERR);
if (r != 0) {
perror("setup_ephemeral_port");
close(fd);
return (r);
}
#endif
return (fd);
}
static int
_setup(void **state) {
UNUSED(state);
/* workers = isc_os_ncpus(); */
if (isc_test_begin(NULL, true, workers) != ISC_R_SUCCESS) {
return (-1);
}
signal(SIGPIPE, SIG_IGN);
return (0);
}
static int
_teardown(void **state) {
UNUSED(state);
isc_test_end();
return (0);
}
/* Generic */
static void
noop_recv_cb(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
void *cbarg) {
UNUSED(handle);
UNUSED(eresult);
UNUSED(region);
UNUSED(cbarg);
}
static unsigned int
noop_accept_cb(isc_nmhandle_t *handle, unsigned int result, void *cbarg) {
UNUSED(handle);
UNUSED(result);
UNUSED(cbarg);
return (0);
}
static void
noop_connect_cb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
UNUSED(handle);
UNUSED(result);
UNUSED(cbarg);
}
thread_local uint8_t tlsdns_buffer_storage[4096];
thread_local size_t tlsdns_buffer_length = 0;
static int
nm_setup(void **state) {
size_t nworkers = ISC_MAX(ISC_MIN(workers, 32), 1);
int tlsdns_listen_sock = -1;
isc_nm_t **nm = NULL;
isc_tlsctx_createserver(NULL, NULL, &tlsdns_listen_ctx);
isc_tlsctx_createclient(&tlsdns_connect_ctx);
tlsdns_listen_addr = (isc_sockaddr_t){ .length = 0 };
tlsdns_listen_sock = setup_ephemeral_port(&tlsdns_listen_addr,
SOCK_STREAM);
if (tlsdns_listen_sock < 0) {
return (-1);
}
close(tlsdns_listen_sock);
tlsdns_listen_sock = -1;
atomic_store(&nsends, NSENDS * NWRITES);
atomic_store(&csends, 0);
atomic_store(&creads, 0);
atomic_store(&sreads, 0);
atomic_store(&ssends, 0);
atomic_store(&ctimeouts, 0);
atomic_store(&cconnects, 0);
isc_nonce_buf(&send_magic, sizeof(send_magic));
isc_nonce_buf(&stop_magic, sizeof(stop_magic));
if (send_magic == stop_magic) {
return (-1);
}
nm = isc_mem_get(test_mctx, MAX_NM * sizeof(nm[0]));
for (size_t i = 0; i < MAX_NM; i++) {
nm[i] = isc_nm_start(test_mctx, nworkers);
assert_non_null(nm[i]);
isc_nm_settimeouts(nm[i], 1000, 1000, 1000, 1000);
}
*state = nm;
return (0);
}
static int
nm_teardown(void **state) {
isc_nm_t **nm = (isc_nm_t **)*state;
for (size_t i = 0; i < MAX_NM; i++) {
isc_nm_destroy(&nm[i]);
assert_null(nm[i]);
}
isc_mem_put(test_mctx, nm, MAX_NM * sizeof(nm[0]));
isc_tlsctx_free(&tlsdns_connect_ctx);
isc_tlsctx_free(&tlsdns_listen_ctx);
return (0);
}
thread_local size_t nwrites = NWRITES;
/* TLSDNS */
static void
tlsdns_connect_send_cb(isc_nmhandle_t *handle, isc_result_t eresult,
void *cbarg);
static void
tlsdns_connect_send(isc_nmhandle_t *handle);
static void
tlsdns_connect_send_cb(isc_nmhandle_t *handle, isc_result_t eresult,
void *cbarg) {
assert_non_null(handle);
UNUSED(cbarg);
if (eresult == ISC_R_SUCCESS) {
atomic_fetch_add(&csends, 1);
} else {
/* Send failed, we need to stop reading too */
isc_nm_cancelread(handle);
}
}
static void
tlsdns_connect_send(isc_nmhandle_t *handle) {
uint_fast64_t sends = atomic_load(&nsends);
/* Continue until we subtract or we are sent them all */
while (sends > 0) {
if (atomic_compare_exchange_weak(&nsends, &sends, sends - 1)) {
sends--;
break;
}
}
if (sends == 0) {
isc_nm_send(handle, (isc_region_t *)&stop_msg,
tlsdns_connect_send_cb, NULL);
} else {
isc_nm_send(handle, (isc_region_t *)&send_msg,
tlsdns_connect_send_cb, NULL);
}
}
static void
tlsdns_connect_read_cb(isc_nmhandle_t *handle, isc_result_t eresult,
isc_region_t *region, void *cbarg) {
uint64_t magic = 0;
UNUSED(cbarg);
assert_non_null(handle);
if (eresult != ISC_R_SUCCESS) {
goto unref;
}
assert_int_equal(region->length, sizeof(magic));
atomic_fetch_add(&creads, 1);
magic = *(uint64_t *)region->base;
assert_true(magic == stop_magic || magic == send_magic);
unref:
isc_nmhandle_detach(&handle);
}
static void
tlsdns_connect_connect_cb(isc_nmhandle_t *handle, isc_result_t eresult,
void *cbarg) {
isc_nmhandle_t *readhandle = NULL;
UNUSED(cbarg);
if (eresult != ISC_R_SUCCESS) {
uint_fast64_t sends = atomic_load(&nsends);
/* We failed to connect; try again */
while (sends > 0) {
/* Continue until we subtract or we are done */
if (atomic_compare_exchange_weak(&nsends, &sends,
sends - 1)) {
sends--;
break;
}
}
return;
}
atomic_fetch_add(&cconnects, 1);
isc_nmhandle_attach(handle, &readhandle);
isc_nm_read(handle, tlsdns_connect_read_cb, NULL);
tlsdns_connect_send(handle);
}
static void
tlsdns_noop(void **state) {
isc_nm_t **nm = (isc_nm_t **)*state;
isc_nm_t *listen_nm = nm[0];
isc_nm_t *connect_nm = nm[1];
isc_result_t result = ISC_R_SUCCESS;
isc_nmsocket_t *listen_sock = NULL;
isc_sockaddr_t tlsdns_connect_addr;
tlsdns_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tlsdns_connect_addr, &in6addr_loopback, 0);
result = isc_nm_listentlsdns(
listen_nm, (isc_nmiface_t *)&tlsdns_listen_addr, noop_recv_cb,
NULL, noop_accept_cb, NULL, 0, 0, NULL, tlsdns_listen_ctx,
&listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
isc_nm_stoplistening(listen_sock);
isc_nmsocket_close(&listen_sock);
assert_null(listen_sock);
(void)isc_nm_tlsdnsconnect(
connect_nm, (isc_nmiface_t *)&tlsdns_connect_addr,
(isc_nmiface_t *)&tlsdns_listen_addr, noop_connect_cb, NULL,
1000, 0, tlsdns_connect_ctx);
isc_nm_closedown(connect_nm);
assert_int_equal(0, atomic_load(&cconnects));
assert_int_equal(0, atomic_load(&csends));
assert_int_equal(0, atomic_load(&creads));
assert_int_equal(0, atomic_load(&ctimeouts));
assert_int_equal(0, atomic_load(&sreads));
assert_int_equal(0, atomic_load(&ssends));
}
static void
tlsdns_noresponse(void **state) {
isc_nm_t **nm = (isc_nm_t **)*state;
isc_nm_t *listen_nm = nm[0];
isc_nm_t *connect_nm = nm[1];
isc_result_t result = ISC_R_SUCCESS;
isc_nmsocket_t *listen_sock = NULL;
isc_sockaddr_t tlsdns_connect_addr;
tlsdns_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tlsdns_connect_addr, &in6addr_loopback, 0);
result = isc_nm_listentlsdns(
listen_nm, (isc_nmiface_t *)&tlsdns_listen_addr, noop_recv_cb,
NULL, noop_accept_cb, NULL, 0, 0, NULL, tlsdns_listen_ctx,
&listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
(void)isc_nm_tlsdnsconnect(
connect_nm, (isc_nmiface_t *)&tlsdns_connect_addr,
(isc_nmiface_t *)&tlsdns_listen_addr, tlsdns_connect_connect_cb,
NULL, 1000, 0, tlsdns_connect_ctx);
isc_nm_stoplistening(listen_sock);
isc_nmsocket_close(&listen_sock);
assert_null(listen_sock);
isc_nm_closedown(connect_nm);
X(cconnects);
X(csends);
X(creads);
X(ctimeouts);
X(sreads);
X(ssends);
assert_true(atomic_load(&cconnects) <= 1);
assert_true(atomic_load(&csends) <= 1);
assert_int_equal(0, atomic_load(&creads));
assert_int_equal(0, atomic_load(&ctimeouts));
assert_int_equal(0, atomic_load(&sreads));
assert_int_equal(0, atomic_load(&ssends));
}
static void
tlsdns_listen_read_cb(isc_nmhandle_t *handle, isc_result_t eresult,
isc_region_t *region, void *cbarg);
static void
tlsdns_listen_send_cb(isc_nmhandle_t *handle, isc_result_t eresult,
void *cbarg) {
UNUSED(cbarg);
UNUSED(eresult);
assert_non_null(handle);
if (eresult != ISC_R_SUCCESS) {
return;
}
atomic_fetch_add(&ssends, 1);
}
static void
tlsdns_listen_read_cb(isc_nmhandle_t *handle, isc_result_t eresult,
isc_region_t *region, void *cbarg) {
uint64_t magic = 0;
UNUSED(cbarg);
assert_non_null(handle);
if (eresult != ISC_R_SUCCESS) {
return;
}
atomic_fetch_add(&sreads, 1);
assert_int_equal(region->length, sizeof(magic));
magic = *(uint64_t *)region->base;
assert_true(magic == stop_magic || magic == send_magic);
if (magic == send_magic) {
isc_nm_send(handle, region, tlsdns_listen_send_cb, NULL);
return;
} else if (magic == stop_magic) {
/* We are done, we don't send anything back */
}
}
static isc_result_t
tlsdns_listen_accept_cb(isc_nmhandle_t *handle, isc_result_t eresult,
void *cbarg) {
UNUSED(handle);
UNUSED(cbarg);
return (eresult);
}
static isc_threadresult_t
tlsdns_connect_thread(isc_threadarg_t arg) {
isc_nm_t *connect_nm = (isc_nm_t *)arg;
isc_sockaddr_t tlsdns_connect_addr;
tlsdns_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tlsdns_connect_addr, &in6addr_loopback, 0);
while (atomic_load(&nsends) > 0) {
(void)isc_nm_tlsdnsconnect(
connect_nm, (isc_nmiface_t *)&tlsdns_connect_addr,
(isc_nmiface_t *)&tlsdns_listen_addr,
tlsdns_connect_connect_cb, NULL, 1000, 0,
tlsdns_connect_ctx);
}
return ((isc_threadresult_t)0);
}
static void
tlsdns_recv_one(void **state) {
isc_nm_t **nm = (isc_nm_t **)*state;
isc_nm_t *listen_nm = nm[0];
isc_nm_t *connect_nm = nm[1];
isc_result_t result = ISC_R_SUCCESS;
isc_nmsocket_t *listen_sock = NULL;
isc_sockaddr_t tlsdns_connect_addr;
tlsdns_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tlsdns_connect_addr, &in6addr_loopback, 0);
atomic_store(&nsends, 1);
result = isc_nm_listentlsdns(
listen_nm, (isc_nmiface_t *)&tlsdns_listen_addr,
tlsdns_listen_read_cb, NULL, tlsdns_listen_accept_cb, NULL, 0,
0, NULL, tlsdns_listen_ctx, &listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
(void)isc_nm_tlsdnsconnect(
connect_nm, (isc_nmiface_t *)&tlsdns_connect_addr,
(isc_nmiface_t *)&tlsdns_listen_addr, tlsdns_connect_connect_cb,
NULL, 1000, 0, tlsdns_connect_ctx);
while (atomic_load(&nsends) > 0) {
isc_thread_yield();
}
while (atomic_load(&cconnects) != 1 || atomic_load(&ssends) != 0 ||
atomic_load(&sreads) != 1 || atomic_load(&creads) != 0 ||
atomic_load(&csends) != 1)
{
isc_thread_yield();
}
isc_nm_stoplistening(listen_sock);
isc_nmsocket_close(&listen_sock);
assert_null(listen_sock);
isc_nm_closedown(connect_nm);
X(cconnects);
X(csends);
X(creads);
X(ctimeouts);
X(sreads);
X(ssends);
assert_int_equal(atomic_load(&cconnects), 1);
assert_int_equal(atomic_load(&csends), 1);
assert_int_equal(atomic_load(&creads), 0);
assert_int_equal(atomic_load(&ctimeouts), 0);
assert_int_equal(atomic_load(&sreads), 1);
assert_int_equal(atomic_load(&ssends), 0);
}
static void
tlsdns_recv_two(void **state) {
isc_nm_t **nm = (isc_nm_t **)*state;
isc_nm_t *listen_nm = nm[0];
isc_nm_t *connect_nm = nm[1];
isc_result_t result = ISC_R_SUCCESS;
isc_nmsocket_t *listen_sock = NULL;
isc_sockaddr_t tlsdns_connect_addr;
if (!reuse_supported) {
skip();
return;
}
tlsdns_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tlsdns_connect_addr, &in6addr_loopback, 0);
atomic_store(&nsends, 2);
result = isc_nm_listentlsdns(
listen_nm, (isc_nmiface_t *)&tlsdns_listen_addr,
tlsdns_listen_read_cb, NULL, tlsdns_listen_accept_cb, NULL, 0,
0, NULL, tlsdns_listen_ctx, &listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
result = isc_nm_tlsdnsconnect(
connect_nm, (isc_nmiface_t *)&tlsdns_connect_addr,
(isc_nmiface_t *)&tlsdns_listen_addr, tlsdns_connect_connect_cb,
NULL, 1000, 0, tlsdns_connect_ctx);
assert_int_equal(result, ISC_R_SUCCESS);
isc_nm_settimeouts(connect_nm, 1000, 1000, 1000, 1000);
result = isc_nm_tlsdnsconnect(
connect_nm, (isc_nmiface_t *)&tlsdns_connect_addr,
(isc_nmiface_t *)&tlsdns_listen_addr, tlsdns_connect_connect_cb,
NULL, 1000, 0, tlsdns_connect_ctx);
assert_int_equal(result, ISC_R_SUCCESS);
while (atomic_load(&nsends) > 0) {
isc_thread_yield();
}
while (atomic_load(&sreads) != 2 || atomic_load(&ssends) != 1 ||
atomic_load(&csends) != 2 || atomic_load(&creads) != 1)
{
isc_thread_yield();
}
isc_nm_stoplistening(listen_sock);
isc_nmsocket_close(&listen_sock);
assert_null(listen_sock);
isc_nm_closedown(connect_nm);
X(cconnects);
X(csends);
X(creads);
X(ctimeouts);
X(sreads);
X(ssends);
assert_int_equal(atomic_load(&cconnects), 2);
assert_int_equal(atomic_load(&csends), 2);
assert_int_equal(atomic_load(&creads), 1);
assert_int_equal(atomic_load(&ctimeouts), 0);
assert_int_equal(atomic_load(&sreads), 2);
assert_int_equal(atomic_load(&ssends), 1);
}
static void
tlsdns_recv_send(void **state) {
isc_nm_t **nm = (isc_nm_t **)*state;
isc_nm_t *listen_nm = nm[0];
isc_nm_t *connect_nm = nm[1];
isc_result_t result = ISC_R_SUCCESS;
isc_nmsocket_t *listen_sock = NULL;
size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1);
isc_thread_t threads[32] = { 0 };
if (!reuse_supported) {
skip();
return;
}
result = isc_nm_listentlsdns(
listen_nm, (isc_nmiface_t *)&tlsdns_listen_addr,
tlsdns_listen_read_cb, NULL, tlsdns_listen_accept_cb, NULL, 0,
0, NULL, tlsdns_listen_ctx, &listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
for (size_t i = 0; i < nthreads; i++) {
isc_thread_create(tlsdns_connect_thread, connect_nm,
&threads[i]);
}
for (size_t i = 0; i < nthreads; i++) {
isc_thread_join(threads[i], NULL);
}
isc_nm_closedown(connect_nm);
isc_nm_stoplistening(listen_sock);
isc_nmsocket_close(&listen_sock);
assert_null(listen_sock);
X(cconnects);
X(csends);
X(creads);
X(ctimeouts);
X(sreads);
X(ssends);
CHECK_RANGE_FULL(csends);
CHECK_RANGE_FULL(creads);
CHECK_RANGE_FULL(sreads);
CHECK_RANGE_FULL(ssends);
}
#if 0
static void
tlsdns_recv_half_send(void **state) {
isc_nm_t **nm = (isc_nm_t **)*state;
isc_nm_t *listen_nm = nm[0];
isc_nm_t *connect_nm = nm[1];
isc_result_t result = ISC_R_SUCCESS;
isc_nmsocket_t *listen_sock = NULL;
size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1);
isc_thread_t threads[32] = { 0 };
if (!reuse_supported) {
skip();
return;
}
result = isc_nm_listentlsdns(
listen_nm, (isc_nmiface_t *)&tlsdns_listen_addr,
tlsdns_listen_read_cb, NULL, tlsdns_listen_accept_cb, NULL, 0,
0, NULL, tlsdns_listen_ctx, &listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
for (size_t i = 0; i < nthreads; i++) {
isc_thread_create(tlsdns_connect_thread, connect_nm,
&threads[i]);
}
while (atomic_load(&nsends) >= (NSENDS * NWRITES) / 2) {
isc_thread_yield();
}
isc_nm_closedown(connect_nm);
for (size_t i = 0; i < nthreads; i++) {
isc_thread_join(threads[i], NULL);
}
isc_nm_stoplistening(listen_sock);
isc_nmsocket_close(&listen_sock);
assert_null(listen_sock);
X(cconnects);
X(csends);
X(creads);
X(ctimeouts);
X(sreads);
X(ssends);
CHECK_RANGE_HALF(csends);
CHECK_RANGE_HALF(creads);
CHECK_RANGE_HALF(sreads);
CHECK_RANGE_HALF(ssends);
}
static void
tlsdns_half_recv_send(void **state) {
isc_nm_t **nm = (isc_nm_t **)*state;
isc_nm_t *listen_nm = nm[0];
isc_nm_t *connect_nm = nm[1];
isc_result_t result = ISC_R_SUCCESS;
isc_nmsocket_t *listen_sock = NULL;
size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1);
isc_thread_t threads[32] = { 0 };
if (!reuse_supported) {
skip();
return;
}
result = isc_nm_listentlsdns(
listen_nm, (isc_nmiface_t *)&tlsdns_listen_addr,
tlsdns_listen_read_cb, NULL, tlsdns_listen_accept_cb, NULL, 0,
0, NULL, tlsdns_listen_ctx, &listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
for (size_t i = 0; i < nthreads; i++) {
isc_thread_create(tlsdns_connect_thread, connect_nm,
&threads[i]);
}
while (atomic_load(&nsends) >= (NSENDS * NWRITES) / 2) {
isc_thread_yield();
}
isc_nm_stoplistening(listen_sock);
isc_nmsocket_close(&listen_sock);
assert_null(listen_sock);
for (size_t i = 0; i < nthreads; i++) {
isc_thread_join(threads[i], NULL);
}
isc_nm_closedown(connect_nm);
X(cconnects);
X(csends);
X(creads);
X(ctimeouts);
X(sreads);
X(ssends);
CHECK_RANGE_HALF(csends);
CHECK_RANGE_HALF(creads);
CHECK_RANGE_HALF(sreads);
CHECK_RANGE_HALF(ssends);
}
static void
tlsdns_half_recv_half_send(void **state) {
isc_nm_t **nm = (isc_nm_t **)*state;
isc_nm_t *listen_nm = nm[0];
isc_nm_t *connect_nm = nm[1];
isc_result_t result = ISC_R_SUCCESS;
isc_nmsocket_t *listen_sock = NULL;
size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1);
isc_thread_t threads[32] = { 0 };
if (!reuse_supported) {
skip();
return;
}
result = isc_nm_listentlsdns(
listen_nm, (isc_nmiface_t *)&tlsdns_listen_addr,
tlsdns_listen_read_cb, NULL, tlsdns_listen_accept_cb, NULL, 0,
0, NULL, tlsdns_listen_ctx, &listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
for (size_t i = 0; i < nthreads; i++) {
isc_thread_create(tlsdns_connect_thread, connect_nm,
&threads[i]);
}
while (atomic_load(&nsends) >= (NSENDS * NWRITES) / 2) {
isc_thread_yield();
}
isc_nm_closedown(connect_nm);
isc_nm_stoplistening(listen_sock);
isc_nmsocket_close(&listen_sock);
assert_null(listen_sock);
for (size_t i = 0; i < nthreads; i++) {
isc_thread_join(threads[i], NULL);
}
X(cconnects);
X(csends);
X(creads);
X(ctimeouts);
X(sreads);
X(ssends);
CHECK_RANGE_HALF(csends);
CHECK_RANGE_HALF(creads);
CHECK_RANGE_HALF(sreads);
CHECK_RANGE_HALF(ssends);
}
#endif
int
main(void) {
const struct CMUnitTest tests[] = {
cmocka_unit_test_setup_teardown(tlsdns_recv_one, nm_setup,
nm_teardown),
cmocka_unit_test_setup_teardown(tlsdns_recv_two, nm_setup,
nm_teardown),
cmocka_unit_test_setup_teardown(tlsdns_noop, nm_setup,
nm_teardown),
cmocka_unit_test_setup_teardown(tlsdns_noresponse, nm_setup,
nm_teardown),
cmocka_unit_test_setup_teardown(tlsdns_recv_send, nm_setup,
nm_teardown),
#if 0
cmocka_unit_test_setup_teardown(tlsdns_recv_half_send, nm_setup,
nm_teardown),
cmocka_unit_test_setup_teardown(tlsdns_half_recv_send, nm_setup,
nm_teardown),
cmocka_unit_test_setup_teardown(tlsdns_half_recv_half_send,
nm_setup, nm_teardown),
#endif
};
return (cmocka_run_group_tests(tests, _setup, _teardown));
}
#else /* HAVE_CMOCKA */
#include <stdio.h>
int
main(void) {
printf("1..0 # Skipped: cmocka not available\n");
return (0);
}
#endif /* if HAVE_CMOCKA */

296
lib/isc/tls.c Normal file
View File

@@ -0,0 +1,296 @@
/*
* 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 <openssl/err.h>
#include <openssl/opensslv.h>
#include <isc/atomic.h>
#include <isc/log.h>
#include <isc/mutex.h>
#include <isc/mutexblock.h>
#include <isc/once.h>
#include <isc/thread.h>
#include <isc/tls.h>
#include <isc/util.h>
#include "openssl_shim.h"
static isc_once_t init_once = ISC_ONCE_INIT;
static atomic_bool init_done = ATOMIC_VAR_INIT(false);
#if OPENSSL_VERSION_NUMBER < 0x10100000L
static isc_mem_t *isc__tls_mctx = NULL;
static isc_mutex_t *locks = NULL;
static int nlocks;
static void
isc__tls_lock_callback(int mode, int type, const char *file, int line) {
UNUSED(file);
UNUSED(line);
if ((mode & CRYPTO_LOCK) != 0) {
LOCK(&locks[type]);
} else {
UNLOCK(&locks[type]);
}
}
static void
isc__tls_set_thread_id(CRYPTO_THREADID *id) {
CRYPTO_THREADID_set_numeric(id, (unsigned long)isc_thread_self());
}
#endif
static void
isc__tls_initialize(void) {
REQUIRE(!atomic_load(&init_done));
RUNTIME_CHECK(OPENSSL_init_ssl(0, NULL) == 1);
#if OPENSSL_VERSION_NUMBER < 0x10100000L
isc_mem_create(&isc__tls_mctx);
nlocks = CRYPTO_num_locks();
locks = isc_mem_get(isc__tls_mctx, nlocks * sizeof(locks[0]));
isc_mutexblock_init(locks, nlocks);
CRYPTO_set_locking_callback(isc__tls_lock_callback);
CRYPTO_THREADID_set_callback(isc__tls_set_thread_id);
ERR_load_crypto_strings();
#endif
atomic_store(&init_done, true);
}
void
isc_tls_initialize(void) {
isc_result_t result = isc_once_do(&init_once, isc__tls_initialize);
REQUIRE(result == ISC_R_SUCCESS);
REQUIRE(atomic_load(&init_done));
}
void
isc_tls_destroy(void) {
REQUIRE(atomic_load(&init_done));
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
ERR_free_strings();
ERR_remove_thread_state(NULL);
CRYPTO_set_locking_callback(NULL);
if (locks != NULL) {
INSIST(isc__tls_mctx != NULL);
isc_mutexblock_destroy(locks, nlocks);
isc_mem_put(isc__tls_mctx, locks, nlocks * sizeof(locks[0]));
locks = NULL;
}
if (isc__tls_mctx != NULL) {
isc_mem_detach(&isc__tls_mctx);
}
#endif
}
void
isc_tlsctx_free(isc_tlsctx_t **ctxp) {
SSL_CTX *ctx = NULL;
REQUIRE(ctxp != NULL && *ctxp != NULL);
ctx = *ctxp;
*ctxp = NULL;
SSL_CTX_free(ctx);
}
isc_result_t
isc_tlsctx_createclient(isc_tlsctx_t **ctxp) {
unsigned long err;
char errbuf[256];
SSL_CTX *ctx = NULL;
const SSL_METHOD *method = NULL;
REQUIRE(ctxp != NULL && *ctxp == NULL);
method = TLS_client_method();
if (method == NULL) {
goto ssl_error;
}
ctx = SSL_CTX_new(method);
if (ctx == NULL) {
goto ssl_error;
}
#if HAVE_SSL_CTX_SET_MIN_PROTO_VERSION
SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
#else
SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1);
#endif
*ctxp = ctx;
return (ISC_R_SUCCESS);
ssl_error:
err = ERR_get_error();
ERR_error_string_n(err, errbuf, sizeof(errbuf));
isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_NETMGR,
ISC_LOG_ERROR, "Error initializing TLS context: %s",
errbuf);
return (ISC_R_TLSERROR);
}
isc_result_t
isc_tlsctx_createserver(const char *keyfile, const char *certfile,
isc_tlsctx_t **ctxp) {
int rv;
unsigned long err;
bool ephemeral = (keyfile == NULL && certfile == NULL);
X509 *cert = NULL;
EVP_PKEY *pkey = NULL;
BIGNUM *bn = NULL;
SSL_CTX *ctx = NULL;
RSA *rsa = NULL;
char errbuf[256];
const SSL_METHOD *method = NULL;
REQUIRE(ctxp != NULL && *ctxp == NULL);
if (ephemeral) {
INSIST(keyfile == NULL);
INSIST(certfile == NULL);
} else {
INSIST(keyfile != NULL);
INSIST(certfile != NULL);
}
method = TLS_server_method();
if (method == NULL) {
goto ssl_error;
}
ctx = SSL_CTX_new(method);
if (ctx == NULL) {
goto ssl_error;
}
RUNTIME_CHECK(ctx != NULL);
#if HAVE_SSL_CTX_SET_MIN_PROTO_VERSION
SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
#else
SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1);
#endif
if (ephemeral) {
rsa = RSA_new();
if (rsa == NULL) {
goto ssl_error;
}
bn = BN_new();
if (bn == NULL) {
goto ssl_error;
}
BN_set_word(bn, RSA_F4);
rv = RSA_generate_key_ex(rsa, 4096, bn, NULL);
if (rv != 1) {
goto ssl_error;
}
cert = X509_new();
if (cert == NULL) {
goto ssl_error;
}
pkey = EVP_PKEY_new();
if (pkey == NULL) {
goto ssl_error;
}
/*
* EVP_PKEY_assign_*() set the referenced key to key
* however these use the supplied key internally and so
* key will be freed when the parent pkey is freed.
*/
EVP_PKEY_assign(pkey, EVP_PKEY_RSA, rsa);
rsa = NULL;
ASN1_INTEGER_set(X509_get_serialNumber(cert), 1);
X509_gmtime_adj(X509_get_notBefore(cert), 0);
/*
* We set the vailidy for 10 years.
*/
X509_gmtime_adj(X509_get_notAfter(cert), 3650 * 24 * 3600);
X509_set_pubkey(cert, pkey);
X509_NAME *name = X509_get_subject_name(cert);
X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC,
(const unsigned char *)"AQ", -1, -1,
0);
X509_NAME_add_entry_by_txt(
name, "O", MBSTRING_ASC,
(const unsigned char *)"BIND9 ephemeral "
"certificate",
-1, -1, 0);
X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
(const unsigned char *)"bind9.local",
-1, -1, 0);
X509_set_issuer_name(cert, name);
X509_sign(cert, pkey, EVP_sha256());
rv = SSL_CTX_use_certificate(ctx, cert);
if (rv != 1) {
goto ssl_error;
}
rv = SSL_CTX_use_PrivateKey(ctx, pkey);
if (rv != 1) {
goto ssl_error;
}
X509_free(cert);
EVP_PKEY_free(pkey);
BN_free(bn);
} else {
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();
ERR_error_string_n(err, errbuf, sizeof(errbuf));
isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_NETMGR,
ISC_LOG_ERROR, "Error initializing TLS context: %s",
errbuf);
if (ctx != NULL) {
SSL_CTX_free(ctx);
}
if (cert != NULL) {
X509_free(cert);
}
if (pkey != NULL) {
EVP_PKEY_free(pkey);
}
if (bn != NULL) {
BN_free(bn);
}
if (rsa != NULL) {
RSA_free(rsa);
}
return (ISC_R_TLSERROR);
}

View File

@@ -451,7 +451,6 @@ isc_nm_detach
isc_nm_listentcpdns
isc_nm_listentlsdns
isc_nm_listentcp
isc_nm_listentls
isc_nm_listenudp
isc_nm_maxudp
isc_nm_pauseread
@@ -468,8 +467,6 @@ isc_nm_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
@@ -702,6 +699,11 @@ isc_timermgr_create
isc_timermgr_createinctx
isc_timermgr_destroy
isc_timermgr_poke
isc_tls_initialize
isc_tls_destroy
isc_tlsctx_createclient
isc_tlsctx_createserver
isc_tlsctx_free
isc_tm_timegm
isc_tm_strptime
isc_utf8_bom

View File

@@ -251,6 +251,9 @@
<ClInclude Include="..\include\isc\timer.h">
<Filter>Library Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\isc\tls.h">
<Filter>Library Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\isc\tm.h">
<Filter>Library Header Files</Filter>
</ClInclude>
@@ -605,6 +608,9 @@
<ClCompile Include="..\timer.c">
<Filter>Library Source Files</Filter>
</ClCompile>
<ClCompile Include="..\tls.c">
<Filter>Library Source Files</Filter>
</ClCompile>
<ClCompile Include="..\tm.c">
<Filter>Library Source Files</Filter>
</ClCompile>

View File

@@ -62,11 +62,11 @@
@IF PKCS11
<PreprocessorDefinitions>BIND9;@PK11_LIB_LOCATION@WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBISC_EXPORTS;%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ForcedIncludeFiles>..\..\..\config.h</ForcedIncludeFiles>
<AdditionalIncludeDirectories>.\;..\..\..\;@LIBXML2_INC@@LIBUV_INC@@OPENSSL_INC@@ZLIB_INC@include;..\include;win32;..\..\isccfg\include;..\..\dns\win32\include;..\..\dns\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>.\;..\..\..\;@LIBXML2_INC@@LIBUV_INC@@OPENSSL_INC@@ZLIB_INC@include;..\include;..\;win32;..\..\isccfg\include;..\..\dns\win32\include;..\..\dns\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
@ELSE PKCS11
<PreprocessorDefinitions>BIND9;WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBISC_EXPORTS;%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ForcedIncludeFiles>..\..\..\config.h</ForcedIncludeFiles>
<AdditionalIncludeDirectories>.\;..\..\..\;@LIBXML2_INC@@LIBUV_INC@@OPENSSL_INC@@ZLIB_INC@include;..\include;win32;..\..\isccfg\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>.\;..\..\..\;@LIBXML2_INC@@LIBUV_INC@@OPENSSL_INC@@ZLIB_INC@include;..\include;..\;win32;..\..\isccfg\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
@END PKCS11
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeaderOutputFile>.\$(Configuration)\$(TargetName).pch</PrecompiledHeaderOutputFile>
@@ -163,11 +163,11 @@ copy InstallFiles ..\Build\Debug\
@IF PKCS11
<PreprocessorDefinitions>BIND9;@PK11_LIB_LOCATION@WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBISC_EXPORTS;%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ForcedIncludeFiles>..\..\..\config.h</ForcedIncludeFiles>
<AdditionalIncludeDirectories>.\;..\..\..\;@LIBXML2_INC@@LIBUV_INC@@OPENSSL_INC@@ZLIB_INC@include;..\include;win32;..\..\isccfg\include;..\..\dns\win32\include;..\..\dns\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>.\;..\..\..\;@LIBXML2_INC@@LIBUV_INC@@OPENSSL_INC@@ZLIB_INC@include;..\include;..\;win32;..\..\isccfg\include;..\..\dns\win32\include;..\..\dns\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
@ELSE PKCS11
<PreprocessorDefinitions>BIND9;WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBISC_EXPORTS;%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ForcedIncludeFiles>..\..\..\config.h</ForcedIncludeFiles>
<AdditionalIncludeDirectories>.\;..\..\..\;@LIBXML2_INC@@LIBUV_INC@@OPENSSL_INC@@ZLIB_INC@include;..\include;win32;..\..\isccfg\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>.\;..\..\..\;@LIBXML2_INC@@LIBUV_INC@@OPENSSL_INC@@ZLIB_INC@include;..\include;..\;win32;..\..\isccfg\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
@END PKCS11
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<WholeProgramOptimization>false</WholeProgramOptimization>
@@ -334,6 +334,7 @@ copy InstallFiles ..\Build\Release\
<ClInclude Include="..\include\isc\task.h" />
<ClInclude Include="..\include\isc\taskpool.h" />
<ClInclude Include="..\include\isc\timer.h" />
<ClInclude Include="..\include\isc\tls.h" />
<ClInclude Include="..\include\isc\tm.h" />
<ClInclude Include="..\include\isc\types.h" />
<ClInclude Include="..\include\isc\utf8.h" />
@@ -413,7 +414,6 @@ copy InstallFiles ..\Build\Release\
<ClCompile Include="..\netmgr\uverr2result.c" />
<ClCompile Include="..\netmgr\uv-compat.c" />
<ClCompile Include="..\netmgr\tcpdns.c" />
<ClCompile Include="..\netmgr\tls.c" />
<ClCompile Include="..\netmgr\tlsdns.c" />
<ClCompile Include="..\netscope.c" />
<ClCompile Include="..\nonce.c" />
@@ -440,6 +440,7 @@ copy InstallFiles ..\Build\Release\
<ClCompile Include="..\task.c" />
<ClCompile Include="..\taskpool.c" />
<ClCompile Include="..\timer.c" />
<ClCompile Include="..\tls.c" />
<ClCompile Include="..\tm.c" />
<ClCompile Include="..\utf8.c" />
@IF PKCS11

View File

@@ -28,11 +28,10 @@
#include <stdbool.h>
#include <isc/net.h>
#include <isc/tls.h>
#include <dns/types.h>
#include <openssl/ssl.h>
/***
*** Types
***/
@@ -41,11 +40,11 @@ typedef struct ns_listenelt ns_listenelt_t;
typedef struct ns_listenlist ns_listenlist_t;
struct ns_listenelt {
isc_mem_t *mctx;
isc_mem_t * mctx;
in_port_t port;
isc_dscp_t dscp; /* -1 = not set, 0..63 */
dns_acl_t *acl;
SSL_CTX * sslctx;
dns_acl_t * acl;
isc_tlsctx_t *sslctx;
ISC_LINK(ns_listenelt_t) link;
};

View File

@@ -507,9 +507,8 @@ ns_interface_listentcp(ns_interface_t *ifp) {
* TLS related options.
*/
static isc_result_t
ns_interface_listentls(ns_interface_t *ifp, SSL_CTX *sslctx) {
ns_interface_listentls(ns_interface_t *ifp, isc_tlsctx_t *sslctx) {
isc_result_t result;
SSL_CTX *ctx = NULL;
result = isc_nm_listentlsdns(
ifp->mgr->nm, (isc_nmiface_t *)&ifp->addr, ns__client_request,
@@ -521,7 +520,7 @@ ns_interface_listentls(ns_interface_t *ifp, SSL_CTX *sslctx) {
isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
"creating TLS socket: %s",
isc_result_totext(result));
SSL_CTX_free(ctx);
isc_tlsctx_free(&sslctx);
return (result);
}

View File

@@ -39,7 +39,7 @@ ns_listenelt_create(isc_mem_t *mctx, in_port_t port, isc_dscp_t dscp,
elt->acl = acl;
elt->sslctx = NULL;
if (tls) {
result = isc_nm_tls_create_server_ctx(key, cert, &elt->sslctx);
result = isc_tlsctx_createserver(key, cert, &elt->sslctx);
if (result != ISC_R_SUCCESS) {
return (result);
}
@@ -54,8 +54,7 @@ ns_listenelt_destroy(ns_listenelt_t *elt) {
dns_acl_detach(&elt->acl);
}
if (elt->sslctx != NULL) {
SSL_CTX_free(elt->sslctx);
elt->sslctx = NULL;
isc_tlsctx_free(&elt->sslctx);
}
isc_mem_put(elt->mctx, elt, sizeof(*elt));
}

View File

@@ -78,7 +78,7 @@ atomic_uint_fast32_t client_refs[32];
atomic_uintptr_t client_addrs[32];
void
isc_nmhandle_attach(isc_nmhandle_t *source, isc_nmhandle_t **targetp) {
isc__nmhandle_attach(isc_nmhandle_t *source, isc_nmhandle_t **targetp FLARG) {
ns_client_t *client = (ns_client_t *)source;
int i;
@@ -97,7 +97,7 @@ isc_nmhandle_attach(isc_nmhandle_t *source, isc_nmhandle_t **targetp) {
}
void
isc_nmhandle_detach(isc_nmhandle_t **handlep) {
isc__nmhandle_detach(isc_nmhandle_t **handlep FLARG) {
isc_nmhandle_t *handle = *handlep;
ns_client_t *client = (ns_client_t *)handle;
int i;

View File

@@ -62,6 +62,15 @@ extern bool app_running;
extern int ncpus;
extern bool debug_mem_record;
#ifdef NETMGR_TRACE
#define FLARG \
, const char *file __attribute__((unused)), \
unsigned int line __attribute__((unused)), \
const char *func __attribute__((unused))
#else
#define FLARG
#endif
isc_result_t
ns_test_begin(FILE *logfile, bool create_managers);

View File

@@ -977,6 +977,8 @@
./bin/tests/system/zonechecks/clean.sh SH 2004,2007,2012,2014,2015,2016,2018,2019,2020,2021
./bin/tests/system/zonechecks/setup.sh SH 2012,2013,2014,2015,2016,2017,2018,2019,2020,2021
./bin/tests/system/zonechecks/tests.sh SH 2004,2007,2009,2012,2013,2014,2015,2016,2018,2019,2020,2021
./bin/tests/test_client.c C 2021
./bin/tests/test_server.c C 2021
./bin/tests/testdata/wire/wire_test.data X 1999,2000,2001,2018,2019
./bin/tests/testdata/wire/wire_test.data2 X 1999,2000,2001,2018,2019
./bin/tests/testdata/wire/wire_test.data3 X 1999,2000,2001,2018,2019
@@ -1877,6 +1879,7 @@
./lib/isc/include/isc/task.h C 1998,1999,2000,2001,2003,2004,2005,2006,2007,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021
./lib/isc/include/isc/taskpool.h C 1999,2000,2001,2004,2005,2006,2007,2011,2012,2016,2018,2019,2020,2021
./lib/isc/include/isc/timer.h C 1998,1999,2000,2001,2002,2004,2005,2006,2007,2008,2009,2012,2013,2014,2016,2018,2019,2020,2021
./lib/isc/include/isc/tls.h C 2021
./lib/isc/include/isc/tm.h C 2014,2016,2018,2019,2020,2021
./lib/isc/include/isc/types.h C 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2012,2013,2014,2016,2017,2018,2019,2020,2021
./lib/isc/include/isc/utf8.h C 2020,2021
@@ -1980,6 +1983,7 @@
./lib/isc/tests/udp_test.c C 2020,2021
./lib/isc/tests/uv_wrap.h C 2020,2021
./lib/isc/timer.c C 1998,1999,2000,2001,2002,2004,2005,2007,2008,2009,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021
./lib/isc/tls.c C 2021
./lib/isc/tm.c C 2014,2016,2018,2019,2020,2021
./lib/isc/unix/dir.c C 1999,2000,2001,2004,2005,2007,2008,2009,2011,2012,2016,2017,2018,2019,2020,2021
./lib/isc/unix/errno.c C 2016,2018,2019,2020,2021

View File

@@ -169,11 +169,6 @@ my @substdefh = ("PACKAGE_VERSION_MAJOR",
"HAVE_GSSAPI_GSSAPI_KRB5_H",
"HAVE_KRB5_KRB5_H",
"HAVE_LIBXML2",
"HAVE_OPENSSL_ED25519",
"HAVE_OPENSSL_ED448",
"HAVE_DH_GET0_KEY",
"HAVE_ECDSA_SIG_GET0",
"HAVE_RSA_SET0_KEY",
"USE_BACKTRACE",
"USE_OPENSSL",
"USE_PKCS11",
@@ -185,16 +180,6 @@ my @substdefh = ("PACKAGE_VERSION_MAJOR",
"WITH_IDN",
"CPU_RELAX",
"VALIDATION_DEFAULT",
"HAVE_CRYPTO_ZALLOC",
"HAVE_EVP_CIPHER_CTX_FREE",
"HAVE_EVP_CIPHER_CTX_NEW",
"HAVE_EVP_MD_CTX_FREE",
"HAVE_EVP_MD_CTX_NEW",
"HAVE_EVP_MD_CTX_RESET",
"HAVE_HMAC_CTX_FREE",
"HAVE_HMAC_CTX_GET_MD",
"HAVE_HMAC_CTX_NEW",
"HAVE_HMAC_CTX_RESET",
"HAVE_UV_HANDLE_GET_DATA",
"HAVE_UV_HANDLE_SET_DATA",
"HAVE_UV_IMPORT",
@@ -1530,12 +1515,12 @@ EOF
#include <openssl/opensslv.h>
int main() {
if (OPENSSL_VERSION_NUMBER >= 0x10000000L) {
if (OPENSSL_VERSION_NUMBER >= 0x10101000L) {
return (0);
}
printf("\n\nFound OPENSSL_VERSION_NUMBER %#010x\n",
OPENSSL_VERSION_NUMBER);
printf("Require OPENSSL_VERSION_NUMBER 0x10000000L or greater (1.0.0)\n\n");
printf("Require OPENSSL_VERSION_NUMBER 0x10101000L or greater (1.1.1)\n\n");
return (1);
}
EOF
@@ -1551,47 +1536,6 @@ EOF
die "can't compile OpenSSL version test: $compret\n";
}
# check OpenSSL built-in support for DH/ECDSA/RSA/CRYPTO_ZALLOC/EVP_CIPHER_CTX/EVP_MD_CTX/HMAC_CTX functions
if ($verbose) {
printf "checking OpenSSL built-in support for DH/ECDSA/RSA/CRYPTO_ZALLOC/EVP_CIPHER_CTX/EVP_MD_CTX/HMAC_CTX functions\n";
}
open F, ">testosslfunc.c" || die $!;
print F << 'EOF';
#include <stdio.h>
#include <openssl/opensslv.h>
int main() {
if (OPENSSL_VERSION_NUMBER >= 0x10100000L) {
return (0);
}
printf("\n\nFound OPENSSL_VERSION_NUMBER %#010x\n",
OPENSSL_VERSION_NUMBER);
printf("This version has no built-in support for DH/ECDSA/RSA/CRYPTO_ZALLOC/EVP_CIPHER_CTX/EVP_MD_CTX/HMAC_CTX functions.\n\n");
return (1);
}
EOF
close F;
$compret = `cl /nologo /MD /I "$include" testosslfunc.c "$libcrypto"`;
if (grep { -f and -x } "./testosslfunc.exe") {
`./testosslfunc.exe`;
if ($? == 0) {
$configdefh{"HAVE_DH_GET0_KEY"} = 1;
$configdefh{"HAVE_ECDSA_SIG_GET0"} = 1;
$configdefh{"HAVE_RSA_SET0_KEY"} = 1;
$configdefh{"HAVE_CRYPTO_ZALLOC"} = 1;
$configdefh{"HAVE_EVP_CIPHER_CTX_FREE"} = 1;
$configdefh{"HAVE_EVP_CIPHER_CTX_NEW"} = 1;
$configdefh{"HAVE_EVP_MD_CTX_FREE"} = 1;
$configdefh{"HAVE_EVP_MD_CTX_NEW"} = 1;
$configdefh{"HAVE_EVP_MD_CTX_RESET"} = 1;
$configdefh{"HAVE_HMAC_CTX_FREE"} = 1;
$configdefh{"HAVE_HMAC_CTX_GET_MD"} = 1;
$configdefh{"HAVE_HMAC_CTX_NEW"} = 1;
$configdefh{"HAVE_HMAC_CTX_RESET"} = 1;
}
}
if ($verbose) {
print "checking for OpenSSL Ed25519 support\n";
}