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:
@@ -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;
|
||||
}
|
||||
|
@@ -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 {
|
||||
|
3
bin/tests/.gitignore
vendored
3
bin/tests/.gitignore
vendored
@@ -8,3 +8,6 @@ dlopen
|
||||
keycreate
|
||||
keydelete
|
||||
gssapi_krb
|
||||
/wire_test
|
||||
/test_client
|
||||
/test_server
|
||||
|
@@ -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
428
bin/tests/test_client.c
Normal 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
305
bin/tests/test_server.c
Normal 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);
|
||||
}
|
@@ -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@
|
||||
|
14
configure.ac
14
configure.ac
@@ -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
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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 \
|
||||
|
@@ -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
54
lib/isc/include/isc/tls.h
Normal 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.
|
||||
*/
|
@@ -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);
|
||||
|
@@ -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:
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
899
lib/isc/tests/tlsdns_test.c
Normal 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
296
lib/isc/tls.c
Normal 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);
|
||||
}
|
@@ -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
|
||||
|
@@ -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>
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
};
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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));
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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";
|
||||
}
|
||||
|
Reference in New Issue
Block a user