bind/bind-9.20-nsupdate-tls.patch
Petr Menšík 95523016c1 Updates to nsupdate TLS backport fixing memory
Properly release memory when TLS is used.

Resolves: RHEL-77354
2025-02-11 12:50:46 +01:00

1605 lines
52 KiB
Diff

From b44dc4ed5c34445511f06d4b972407d539f8e9da Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
Date: Mon, 11 Nov 2024 18:09:07 +0100
Subject: [PATCH] Backport nsupdate TLS support into 9.18
Attempt to support TLS from nsupdate even in 9.18 release.
Create few dispatch calls with 2 suffix with tls
Keep original functions without changes and add new functions with
additional tlsctx and transport pointers passed.
Convert xfrin.c:get_create_tlsctx() into a library function
In order to make xfrin.c:get_create_tlsctx() reusable, move the function
into transport.c, and make changes into its prototype to not use the
'dns_xfrin_ctx_t' type, thus making it more universal.
This change prepares ground for adding transport support into the
dispatch manager.
Also, move the typedefs for 'dns_transport_t' and 'dns_transport_list_t'
from transport.h into types.h.
(cherry picked from commit 881747218ba0ad411f6f1bf361c2c09c805d4aa8)
Update calls inside libdns
Add remaining transport additions to request and dispatch calls. Add
mctx into dispentry.
Compilable nsupdate
Implement DoT support for nsupdate
Implement DNS-over-TLS support for nsupdate. Use DiG's DoT
implementation as a model for the newly added features.
(cherry picked from commit 13000c28c2e0ab2754f0f37ab8d6edb8249a1370)
[pemensik] Adapted to previous 9.18 changes.
Add usage and command line parsing
Fixup tls initialization from nsupdate
Detach transport also on dispatch_destroy properly.
Adapted to 9.18.33.
---
bin/nsupdate/nsupdate.c | 192 ++++++++++++++++++++----
lib/dns/dispatch.c | 128 ++++++++++++++--
lib/dns/include/dns/dispatch.h | 22 +++
lib/dns/include/dns/request.h | 23 +++
lib/dns/include/dns/transport.h | 45 +++++-
lib/dns/include/dns/types.h | 2 +
lib/dns/request.c | 63 ++++++--
lib/dns/transport.c | 253 ++++++++++++++++++++++++++++++++
lib/dns/xfrin.c | 232 +----------------------------
9 files changed, 668 insertions(+), 292 deletions(-)
diff --git a/bin/nsupdate/nsupdate.c b/bin/nsupdate/nsupdate.c
index 293ed28..819925e 100644
--- a/bin/nsupdate/nsupdate.c
+++ b/bin/nsupdate/nsupdate.c
@@ -45,6 +45,7 @@
#include <isc/stdio.h>
#include <isc/string.h>
#include <isc/task.h>
+#include <isc/tls.h>
#include <isc/types.h>
#include <isc/util.h>
@@ -67,6 +68,7 @@
#include <dns/rdatatype.h>
#include <dns/request.h>
#include <dns/tkey.h>
+#include <dns/transport.h>
#include <dns/tsig.h>
#include <dst/dst.h>
@@ -118,6 +120,7 @@ static bool memdebugging = false;
static bool have_ipv4 = false;
static bool have_ipv6 = false;
static bool is_dst_up = false;
+static bool use_tls = false;
static bool usevc = false;
static bool usegsstsig = false;
static bool use_win2k_gsstsig = false;
@@ -145,6 +148,14 @@ static dns_tsigkey_t *tsigkey = NULL;
static dst_key_t *sig0key = NULL;
static isc_sockaddr_t *servers = NULL;
static isc_sockaddr_t *primary_servers = NULL;
+static dns_transport_list_t *transport_list = NULL;
+static dns_transport_t *transport = NULL;
+static isc_tlsctx_cache_t *tls_ctx_cache = NULL;
+static char *tls_hostname = NULL;
+static char *tls_client_key_file = NULL;
+static char *tls_client_cert_file = NULL;
+static char *tls_ca_file = NULL;
+static bool tls_always_verify_remote = true;
static bool default_servers = true;
static int ns_inuse = 0;
static int primary_inuse = 0;
@@ -790,6 +801,19 @@ set_source_ports(dns_dispatchmgr_t *manager) {
isc_portset_destroy(gmctx, &v6portset);
}
+static isc_result_t
+create_name(const char *str, char *namedata, size_t len, dns_name_t *name) {
+ isc_buffer_t namesrc, namebuf;
+
+ dns_name_init(name, NULL);
+ isc_buffer_constinit(&namesrc, str, strlen(str));
+ isc_buffer_add(&namesrc, strlen(str));
+ isc_buffer_init(&namebuf, namedata, len);
+
+ return dns_name_fromtext(name, &namesrc, dns_rootname,
+ DNS_NAME_DOWNCASE, &namebuf);
+}
+
static void
setup_system(void) {
isc_result_t result;
@@ -797,6 +821,8 @@ setup_system(void) {
isc_sockaddrlist_t *nslist;
isc_logconfig_t *logconfig = NULL;
irs_resconf_t *resconf = NULL;
+ dns_name_t tlsname;
+ char namedata[DNS_NAME_FORMATSIZE + 1];
ddebug("setup_system()");
@@ -942,6 +968,31 @@ setup_system(void) {
check_result(result, "dns_dispatch_createudp (v4)");
}
+ transport_list = dns_transport_list_new(gmctx);
+ isc_tlsctx_cache_create(gmctx, &tls_ctx_cache);
+
+ if (tls_client_key_file == NULL) {
+ result = create_name("tls-non-auth-client", namedata,
+ sizeof(namedata), &tlsname);
+ check_result(result, "create_name (tls-non-auth-client)");
+ transport = dns_transport_new(&tlsname, DNS_TRANSPORT_TLS,
+ transport_list);
+ dns_transport_set_tlsname(transport, "tls-non-auth-client");
+ } else {
+ result = create_name("tls-auth-client", namedata,
+ sizeof(namedata), &tlsname);
+ check_result(result, "create_name (tls-auth-client)");
+ transport = dns_transport_new(&tlsname, DNS_TRANSPORT_TLS,
+ transport_list);
+ dns_transport_set_tlsname(transport, "tls-auth-client");
+ dns_transport_set_keyfile(transport, tls_client_key_file);
+ dns_transport_set_certfile(transport, tls_client_cert_file);
+ }
+ dns_transport_set_cafile(transport, tls_ca_file);
+ dns_transport_set_remote_hostname(transport, tls_hostname);
+ dns_transport_set_always_verify_remote(transport,
+ tls_always_verify_remote);
+
result = dns_requestmgr_create(gmctx, taskmgr, dispatchmgr, dispatchv4,
dispatchv6, &requestmgr);
check_result(result, "dns_requestmgr_create");
@@ -982,7 +1033,7 @@ version(void) {
fprintf(stderr, "nsupdate %s\n", PACKAGE_VERSION);
}
-#define PARSE_ARGS_FMT "46C:dDghilL:Mok:p:Pr:R:t:Tu:vVy:"
+#define PARSE_ARGS_FMT "46A:C:dDE:ghH:iK:lL:MoOk:p:Pr:R:St:Tu:vVy:"
static void
pre_parse_args(int argc, char **argv) {
@@ -1025,7 +1076,9 @@ pre_parse_args(int argc, char **argv) {
fprintf(stderr, "usage: nsupdate [-CdDi] [-L level] "
"[-l] [-g | -o | -y keyname:secret "
"| -k keyfile] [-p port] "
- "[-v] [-V] [-P] [-T] [-4 | -6] "
+ "[ -S [-K tlskeyfile] [-E tlscertfile] "
+ "[-A tlscafile] [-H tlshostname] "
+ "[-O] ] [-v] [-V] [-P] [-T] [-4 | -6] "
"[filename]\n");
exit(EXIT_FAILURE);
@@ -1097,6 +1150,10 @@ parse_args(int argc, char **argv) {
fatal("can't find IPv6 networking");
}
break;
+ case 'A':
+ use_tls = true;
+ tls_ca_file = isc_commandline_argument;
+ break;
case 'C':
resolvconf = isc_commandline_argument;
break;
@@ -1107,12 +1164,27 @@ parse_args(int argc, char **argv) {
debugging = true;
ddebugging = true;
break;
+ case 'E':
+ use_tls = true;
+ usevc = true;
+ tls_client_cert_file = isc_commandline_argument;
+ break;
+ case 'H':
+ use_tls = true;
+ usevc = true;
+ tls_hostname = isc_commandline_argument;
+ break;
case 'M':
break;
case 'i':
force_interactive = true;
interactive = true;
break;
+ case 'K':
+ use_tls = true;
+ usevc = true;
+ tls_client_key_file = isc_commandline_argument;
+ break;
case 'l':
local_only = true;
break;
@@ -1145,6 +1217,11 @@ parse_args(int argc, char **argv) {
usegsstsig = true;
use_win2k_gsstsig = true;
break;
+ case 'O':
+ use_tls = true;
+ usevc = true;
+ tls_always_verify_remote = false;
+ break;
case 'p':
result = isc_parse_uint16(&dnsport,
isc_commandline_argument, 10);
@@ -1156,6 +1233,10 @@ parse_args(int argc, char **argv) {
exit(EXIT_FAILURE);
}
break;
+ case 'S':
+ use_tls = true;
+ usevc = true;
+ break;
case 't':
result = isc_parse_uint32(&timeout,
isc_commandline_argument, 10);
@@ -1218,6 +1299,26 @@ parse_args(int argc, char **argv) {
}
#endif /* HAVE_GSSAPI */
+ if (use_tls) {
+ usevc = true;
+ if ((tls_client_key_file == NULL) !=
+ (tls_client_cert_file == NULL))
+ {
+ fprintf(stderr,
+ "%s: cannot specify the -K option without"
+ "the -E option, and vice versa.\n",
+ argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ if (tls_ca_file != NULL && tls_always_verify_remote == false) {
+ fprintf(stderr,
+ "%s: cannot specify the -A option in "
+ "conjuction with the -O option.\n",
+ argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ }
+
if (argv[isc_commandline_index] != NULL) {
if (strcmp(argv[isc_commandline_index], "-") == 0) {
input = stdin;
@@ -2468,8 +2569,10 @@ static void
send_update(dns_name_t *zone, isc_sockaddr_t *primary) {
isc_result_t result;
dns_request_t *request = NULL;
- unsigned int options = DNS_REQUESTOPT_CASE;
isc_sockaddr_t *srcaddr;
+ unsigned int options = DNS_REQUESTOPT_CASE;
+ dns_transport_t *req_transport = NULL;
+ isc_tlsctx_cache_t *req_tls_ctx_cache = NULL;
ddebug("send_update()");
@@ -2477,7 +2580,12 @@ send_update(dns_name_t *zone, isc_sockaddr_t *primary) {
if (usevc) {
options |= DNS_REQUESTOPT_TCP;
+ if (use_tls) {
+ req_transport = transport;
+ req_tls_ctx_cache = tls_ctx_cache;
+ }
}
+
if (tsigkey == NULL && sig0key != NULL) {
result = dns_message_setsig0key(updatemsg, sig0key);
check_result(result, "dns_message_setsig0key");
@@ -2500,11 +2608,11 @@ send_update(dns_name_t *zone, isc_sockaddr_t *primary) {
updatemsg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
}
- result = dns_request_create(requestmgr, updatemsg, srcaddr, primary,
- options, tsigkey, timeout, udp_timeout,
- udp_retries, global_task, update_completed,
- NULL, &request);
- check_result(result, "dns_request_create");
+ result = dns_request_create2(
+ requestmgr, updatemsg, srcaddr, primary, req_transport,
+ req_tls_ctx_cache, options, tsigkey, timeout, udp_timeout,
+ udp_retries, global_task, update_completed, NULL, &request);
+ check_result(result, "dns_request_create2");
if (debugging) {
show_message(stdout, updatemsg, "Outgoing update query:");
@@ -2594,7 +2702,9 @@ recvsoa(isc_task_t *task, isc_event_t *event) {
result = dns_request_getresponse(request, rcvmsg,
DNS_MESSAGEPARSE_PRESERVEORDER);
if (result == DNS_R_TSIGERRORSET && servers != NULL) {
- unsigned int options = 0;
+ unsigned int options = DNS_REQUESTOPT_CASE;
+ dns_transport_t *req_transport = NULL;
+ isc_tlsctx_cache_t *req_tls_ctx_cache = NULL;
dns_message_detach(&rcvmsg);
ddebug("Destroying request [%p]", request);
@@ -2605,8 +2715,12 @@ recvsoa(isc_task_t *task, isc_event_t *event) {
dns_message_renderreset(soaquery);
ddebug("retrying soa request without TSIG");
- if (!default_servers && usevc) {
+ if (usevc) {
options |= DNS_REQUESTOPT_TCP;
+ if (!default_servers && use_tls) {
+ req_transport = transport;
+ req_tls_ctx_cache = tls_ctx_cache;
+ }
}
if (isc_sockaddr_pf(addr) == AF_INET6) {
@@ -2615,10 +2729,10 @@ recvsoa(isc_task_t *task, isc_event_t *event) {
srcaddr = localaddr4;
}
- result = dns_request_create(requestmgr, soaquery, srcaddr, addr,
- options, NULL, timeout, udp_timeout,
- udp_retries, global_task, recvsoa,
- reqinfo, &request);
+ result = dns_request_create2(
+ requestmgr, soaquery, srcaddr, addr, req_transport,
+ req_tls_ctx_cache, options, NULL, timeout, udp_timeout,
+ udp_retries, global_task, recvsoa, reqinfo, &request);
check_result(result, "dns_request_create");
requests++;
return;
@@ -2831,10 +2945,16 @@ sendrequest(isc_sockaddr_t *destaddr, dns_message_t *msg,
isc_result_t result;
nsu_requestinfo_t *reqinfo;
isc_sockaddr_t *srcaddr;
- unsigned int options = 0;
+ unsigned int options = DNS_REQUESTOPT_CASE;
+ dns_transport_t *req_transport = NULL;
+ isc_tlsctx_cache_t *req_tls_ctx_cache = NULL;
- if (!default_servers && usevc) {
+ if (usevc) {
options |= DNS_REQUESTOPT_TCP;
+ if (!default_servers && use_tls) {
+ req_transport = transport;
+ req_tls_ctx_cache = tls_ctx_cache;
+ }
}
reqinfo = isc_mem_get(gmctx, sizeof(nsu_requestinfo_t));
@@ -2847,11 +2967,12 @@ sendrequest(isc_sockaddr_t *destaddr, dns_message_t *msg,
srcaddr = localaddr4;
}
- result = dns_request_create(requestmgr, msg, srcaddr, destaddr, options,
- default_servers ? NULL : tsigkey, timeout,
- udp_timeout, udp_retries, global_task,
- recvsoa, reqinfo, request);
- check_result(result, "dns_request_create");
+ result = dns_request_create2(requestmgr, msg, srcaddr, destaddr,
+ req_transport, req_tls_ctx_cache, options,
+ default_servers ? NULL : tsigkey, timeout,
+ udp_timeout, udp_retries, global_task,
+ recvsoa, reqinfo, request);
+ check_result(result, "dns_request_create2");
requests++;
}
@@ -2934,7 +3055,6 @@ start_gssrequest(dns_name_t *primary) {
char namestr[DNS_NAME_FORMATSIZE];
char mykeystr[DNS_NAME_FORMATSIZE];
char *err_message = NULL;
-
debug("start_gssrequest");
usevc = true;
@@ -3030,8 +3150,15 @@ send_gssrequest(isc_sockaddr_t *destaddr, dns_message_t *msg,
dns_request_t **request, gss_ctx_id_t context) {
isc_result_t result;
nsu_gssinfo_t *reqinfo;
- unsigned int options = 0;
isc_sockaddr_t *srcaddr;
+ unsigned int options = DNS_REQUESTOPT_CASE | DNS_REQUESTOPT_TCP;
+ dns_transport_t *req_transport = NULL;
+ isc_tlsctx_cache_t *req_tls_ctx_cache = NULL;
+
+ if (!default_servers && use_tls) {
+ req_transport = transport;
+ req_tls_ctx_cache = tls_ctx_cache;
+ }
debug("send_gssrequest");
REQUIRE(destaddr != NULL);
@@ -3041,18 +3168,17 @@ send_gssrequest(isc_sockaddr_t *destaddr, dns_message_t *msg,
reqinfo->addr = destaddr;
reqinfo->context = context;
- options |= DNS_REQUESTOPT_TCP;
-
if (isc_sockaddr_pf(destaddr) == AF_INET6) {
srcaddr = localaddr6;
} else {
srcaddr = localaddr4;
}
- result = dns_request_create(requestmgr, msg, srcaddr, destaddr, options,
- tsigkey, timeout, udp_timeout, udp_retries,
- global_task, recvgss, reqinfo, request);
- check_result(result, "dns_request_create");
+ result = dns_request_create2(requestmgr, msg, srcaddr, destaddr,
+ req_transport, req_tls_ctx_cache, options,
+ tsigkey, timeout, udp_timeout, udp_retries,
+ global_task, recvgss, reqinfo, request);
+ check_result(result, "dns_request_create2");
if (debugging) {
show_message(stdout, msg, "Outgoing update query:");
}
@@ -3321,6 +3447,14 @@ static void
cleanup(void) {
ddebug("cleanup()");
+ if (tls_ctx_cache != NULL) {
+ isc_tlsctx_cache_detach(&tls_ctx_cache);
+ }
+
+ if (transport_list != NULL) {
+ dns_transport_list_detach(&transport_list);
+ }
+
LOCK(&answer_lock);
if (answer != NULL) {
dns_message_detach(&answer);
diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c
index eb37198..8273c32 100644
--- a/lib/dns/dispatch.c
+++ b/lib/dns/dispatch.c
@@ -30,6 +30,7 @@
#include <isc/stats.h>
#include <isc/string.h>
#include <isc/time.h>
+#include <isc/tls.h>
#include <isc/util.h>
#include <dns/acl.h>
@@ -83,6 +84,10 @@ struct dns_dispentry {
dns_dispatch_t *disp;
isc_nmhandle_t *handle; /*%< netmgr handle for UDP connection */
dns_dispatchstate_t state;
+ /* TLS support for nsupdate. */
+ isc_mem_t *mctx;
+ dns_transport_t *transport;
+ isc_tlsctx_cache_t *tlsctx_cache;
unsigned int bucket;
unsigned int retries;
unsigned int timeout;
@@ -107,11 +112,12 @@ struct dns_dispatch {
/* Unlocked. */
unsigned int magic; /*%< magic */
int tid;
- dns_dispatchmgr_t *mgr; /*%< dispatch manager */
- isc_nmhandle_t *handle; /*%< netmgr handle for TCP connection */
- isc_sockaddr_t local; /*%< local address */
- in_port_t localport; /*%< local UDP port */
- isc_sockaddr_t peer; /*%< peer address (TCP) */
+ dns_dispatchmgr_t *mgr; /*%< dispatch manager */
+ isc_nmhandle_t *handle; /*%< netmgr handle for TCP connection */
+ isc_sockaddr_t local; /*%< local address */
+ in_port_t localport; /*%< local UDP port */
+ isc_sockaddr_t peer; /*%< peer address (TCP) */
+ dns_transport_t *transport; /*%< TCP transport parameters */
/*% Locked by mgr->lock. */
ISC_LINK(dns_dispatch_t) link;
@@ -119,6 +125,7 @@ struct dns_dispatch {
/* Locked by "lock". */
isc_mutex_t lock; /*%< locks all below */
isc_socktype_t socktype;
+ dns_dispatchopt_t options;
dns_dispatchstate_t state;
isc_refcount_t references;
@@ -220,13 +227,27 @@ udp_dispatch_getnext(dns_dispentry_t *resp, int32_t timeout);
static const char *
socktype2str(dns_dispentry_t *resp) {
+ dns_transport_type_t transport_type = DNS_TRANSPORT_UDP;
dns_dispatch_t *disp = resp->disp;
- switch (disp->socktype) {
- case isc_socktype_udp:
+ if (disp->socktype == isc_socktype_tcp) {
+ if (resp->transport != NULL) {
+ transport_type =
+ dns_transport_get_type(resp->transport);
+ } else {
+ transport_type = DNS_TRANSPORT_TCP;
+ }
+ }
+
+ switch (transport_type) {
+ case DNS_TRANSPORT_UDP:
return "UDP";
- case isc_socktype_tcp:
+ case DNS_TRANSPORT_TCP:
return "TCP";
+ case DNS_TRANSPORT_TLS:
+ return "TLS";
+ case DNS_TRANSPORT_HTTP:
+ return "HTTP";
default:
return "<unexpected>";
}
@@ -457,6 +478,14 @@ dispentry_destroy(dns_dispentry_t *resp) {
isc_nmhandle_detach(&resp->handle);
}
+ if (resp->tlsctx_cache != NULL) {
+ isc_tlsctx_cache_detach(&resp->tlsctx_cache);
+ }
+
+ if (resp->transport != NULL) {
+ dns_transport_detach(&resp->transport);
+ }
+
isc_mem_put(disp->mgr->mctx, resp, sizeof(*resp));
dns_dispatch_detach(&disp); /* DISPATCH001 */
@@ -1161,6 +1190,15 @@ dispatch_allocate(dns_dispatchmgr_t *mgr, isc_socktype_t type,
isc_result_t
dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
const isc_sockaddr_t *destaddr, dns_dispatch_t **dispp) {
+ return dns_dispatch_createtcp2(mgr, localaddr, destaddr, NULL, 0,
+ dispp);
+}
+
+isc_result_t
+dns_dispatch_createtcp2(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
+ const isc_sockaddr_t *destaddr,
+ dns_transport_t *transport, dns_dispatchopt_t options,
+ dns_dispatch_t **dispp) {
dns_dispatch_t *disp = NULL;
REQUIRE(VALID_DISPATCHMGR(mgr));
@@ -1170,7 +1208,11 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
dispatch_allocate(mgr, isc_socktype_tcp, &disp);
+ disp->options = options;
disp->peer = *destaddr;
+ if (transport != NULL) {
+ dns_transport_attach(transport, &disp->transport);
+ }
if (localaddr != NULL) {
disp->local = *localaddr;
@@ -1185,6 +1227,7 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
* Append it to the dispatcher list.
*/
+ /* TODO: DNS_DISPATCHOPT_UNSHARED is not backported */
/* FIXME: There should be a lookup hashtable here */
ISC_LIST_APPEND(mgr->list, disp, link);
UNLOCK(&mgr->lock);
@@ -1208,6 +1251,13 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
isc_result_t
dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr,
const isc_sockaddr_t *localaddr, dns_dispatch_t **dispp) {
+ return dns_dispatch_gettcp2(mgr, destaddr, localaddr, NULL, dispp);
+}
+
+isc_result_t
+dns_dispatch_gettcp2(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr,
+ const isc_sockaddr_t *localaddr,
+ dns_transport_t *transport, dns_dispatch_t **dispp) {
dns_dispatch_t *disp_connected = NULL;
dns_dispatch_t *disp_fallback = NULL;
isc_result_t result = ISC_R_NOTFOUND;
@@ -1248,8 +1298,10 @@ dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr,
if (disp->socktype != isc_socktype_tcp ||
!isc_sockaddr_equal(destaddr, &peeraddr) ||
(localaddr != NULL &&
- !isc_sockaddr_eqaddr(localaddr, &sockname)))
+ !isc_sockaddr_eqaddr(localaddr, &sockname)) ||
+ (transport != disp->transport))
{
+ // dispatch_match alternative
UNLOCK(&disp->lock);
continue;
}
@@ -1403,6 +1455,9 @@ dispatch_destroy(dns_dispatch_t *disp) {
disp->handle, &disp->handle);
isc_nmhandle_detach(&disp->handle);
}
+ if (disp->transport != NULL) {
+ dns_transport_detach(&disp->transport);
+ }
isc_mutex_destroy(&disp->lock);
@@ -1426,7 +1481,18 @@ dns_dispatch_add(dns_dispatch_t *disp, unsigned int options,
unsigned int timeout, const isc_sockaddr_t *dest,
dispatch_cb_t connected, dispatch_cb_t sent,
dispatch_cb_t response, void *arg, dns_messageid_t *idp,
- dns_dispentry_t **respp) {
+ dns_dispentry_t **resp) {
+ return dns_dispatch_add2(disp, options, timeout, dest, NULL, NULL,
+ connected, sent, response, arg, idp, resp);
+}
+
+isc_result_t
+dns_dispatch_add2(dns_dispatch_t *disp, unsigned int options,
+ unsigned int timeout, const isc_sockaddr_t *dest,
+ dns_transport_t *transport, isc_tlsctx_cache_t *tlsctx_cache,
+ dispatch_cb_t connected, dispatch_cb_t sent,
+ dispatch_cb_t response, void *arg, dns_messageid_t *idp,
+ dns_dispentry_t **respp) {
dns_dispentry_t *resp = NULL;
dns_qid_t *qid = NULL;
in_port_t localport;
@@ -1444,6 +1510,7 @@ dns_dispatch_add(dns_dispatch_t *disp, unsigned int options,
REQUIRE(connected != NULL);
REQUIRE(response != NULL);
REQUIRE(sent != NULL);
+ REQUIRE(disp->transport == transport);
LOCK(&disp->lock);
@@ -1471,6 +1538,7 @@ dns_dispatch_add(dns_dispatch_t *disp, unsigned int options,
.rlink = ISC_LINK_INITIALIZER,
.magic = RESPONSE_MAGIC,
};
+ isc_mem_attach(disp->mgr->mctx, &resp->mctx);
#if DNS_DISPATCH_TRACE
fprintf(stderr, "dns_dispentry__init:%s:%s:%d:%p->references = 1\n",
@@ -1530,6 +1598,14 @@ dns_dispatch_add(dns_dispatch_t *disp, unsigned int options,
return ISC_R_NOMORE;
}
+ if (transport != NULL) {
+ dns_transport_attach(transport, &resp->transport);
+ }
+
+ if (tlsctx_cache != NULL) {
+ isc_tlsctx_cache_attach(tlsctx_cache, &resp->tlsctx_cache);
+ }
+
dns_dispatch_attach(disp, &resp->disp); /* DISPATCH001 */
disp->requests++;
@@ -1779,6 +1855,7 @@ dns_dispatch_done(dns_dispentry_t **respp) {
*respp = NULL;
dispentry_cancel(resp, ISC_R_CANCELED);
+ isc_mem_detach(&resp->mctx); ///< FIXME: is this ok?
dns_dispentry_detach(&resp); /* DISPENTRY000 */
}
@@ -1970,6 +2047,27 @@ udp_dispatch_connect(dns_dispatch_t *disp, dns_dispentry_t *resp) {
static isc_result_t
tcp_dispatch_connect(dns_dispatch_t *disp, dns_dispentry_t *resp) {
+ dns_transport_type_t transport_type = DNS_TRANSPORT_TCP;
+ isc_tlsctx_t *tlsctx = NULL;
+ isc_tlsctx_client_session_cache_t *sess_cache = NULL;
+
+ if (resp->transport != NULL) {
+ transport_type = dns_transport_get_type(resp->transport);
+ }
+
+ if (transport_type == DNS_TRANSPORT_TLS) {
+ isc_result_t result;
+
+ result = dns_transport_get_tlsctx(
+ resp->transport, &resp->peer, resp->tlsctx_cache,
+ resp->mctx, &tlsctx, &sess_cache);
+
+ if (result != ISC_R_SUCCESS) {
+ return result;
+ }
+ INSIST(tlsctx != NULL);
+ }
+
/* Check whether the dispatch is already connecting or connected. */
LOCK(&disp->lock);
switch (disp->state) {
@@ -1995,8 +2093,14 @@ tcp_dispatch_connect(dns_dispatch_t *disp, dns_dispentry_t *resp) {
"connecting from %s to %s, timeout %u", localbuf,
peerbuf, resp->timeout);
- isc_nm_tcpdnsconnect(disp->mgr->nm, &disp->local, &disp->peer,
- tcp_connected, disp, resp->timeout, 0);
+ if (tlsctx != NULL) {
+ isc_nm_tlsdnsconnect(disp->mgr->nm, &disp->local, &disp->peer,
+ tcp_connected, disp, resp->timeout, 0,
+ tlsctx, sess_cache);
+ } else {
+ isc_nm_tcpdnsconnect(disp->mgr->nm, &disp->local, &disp->peer,
+ tcp_connected, disp, resp->timeout, 0);
+ }
break;
case DNS_DISPATCHSTATE_CONNECTING:
diff --git a/lib/dns/include/dns/dispatch.h b/lib/dns/include/dns/dispatch.h
index ad377f0..cfdc374 100644
--- a/lib/dns/include/dns/dispatch.h
+++ b/lib/dns/include/dns/dispatch.h
@@ -56,6 +56,7 @@
#include <isc/refcount.h>
#include <isc/types.h>
+#include <dns/transport.h>
#include <dns/types.h>
/* Add -DDNS_DISPATCH_TRACE=1 to CFLAGS for detailed reference tracing */
@@ -74,6 +75,11 @@ struct dns_dispatchset {
isc_mutex_t lock;
};
+typedef enum dns_dispatchopt {
+ DNS_DISPATCHOPT_FIXEDID = 1 << 0,
+ DNS_DISPATCHOPT_UNSHARED = 1 << 1, /* Don't share this connection */
+} dns_dispatchopt_t;
+
/*
*/
#define DNS_DISPATCHOPT_FIXEDID 0x00000001U
@@ -199,6 +205,11 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
*
*\li Anything else -- failure.
*/
+isc_result_t
+dns_dispatch_createtcp2(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
+ const isc_sockaddr_t *destaddr,
+ dns_transport_t *transport, dns_dispatchopt_t options,
+ dns_dispatch_t **dispp);
#if DNS_DISPATCH_TRACE
#define dns_dispatch_ref(ptr) \
@@ -258,6 +269,10 @@ dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr,
/*
* Attempt to connect to a existing TCP connection.
*/
+isc_result_t
+dns_dispatch_gettcp2(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr,
+ const isc_sockaddr_t *localaddr,
+ dns_transport_t *transport, dns_dispatch_t **dispp);
typedef void (*dispatch_cb_t)(isc_result_t eresult, isc_region_t *region,
void *cbarg);
@@ -268,6 +283,13 @@ dns_dispatch_add(dns_dispatch_t *disp, unsigned int options,
dispatch_cb_t connected, dispatch_cb_t sent,
dispatch_cb_t response, void *arg, dns_messageid_t *idp,
dns_dispentry_t **resp);
+isc_result_t
+dns_dispatch_add2(dns_dispatch_t *disp, unsigned int options,
+ unsigned int timeout, const isc_sockaddr_t *dest,
+ dns_transport_t *transport, isc_tlsctx_cache_t *tlsctx_cache,
+ dispatch_cb_t connected, dispatch_cb_t sent,
+ dispatch_cb_t response, void *arg, dns_messageid_t *idp,
+ dns_dispentry_t **respp);
/*%<
* Add a response entry for this dispatch.
*
diff --git a/lib/dns/include/dns/request.h b/lib/dns/include/dns/request.h
index d00574f..17bcbf6 100644
--- a/lib/dns/include/dns/request.h
+++ b/lib/dns/include/dns/request.h
@@ -44,6 +44,7 @@
#define DNS_REQUESTOPT_TCP 0x00000001U
#define DNS_REQUESTOPT_CASE 0x00000002U
#define DNS_REQUESTOPT_FIXEDID 0x00000004U
+#define DNS_REQUESTOPT_LARGE 0x00000008U
typedef struct dns_requestevent {
ISC_EVENT_COMMON(struct dns_requestevent);
@@ -161,6 +162,17 @@ dns_request_create(dns_requestmgr_t *requestmgr, dns_message_t *message,
unsigned int udptimeout, unsigned int udpretries,
isc_task_t *task, isc_taskaction_t action, void *arg,
dns_request_t **requestp);
+isc_result_t
+dns_request_create2(dns_requestmgr_t *requestmgr, dns_message_t *message,
+ const isc_sockaddr_t *srcaddr,
+ const isc_sockaddr_t *destaddr,
+ dns_transport_t *req_transport,
+ isc_tlsctx_cache_t *req_tls_ctx_cache,
+ unsigned int options,
+ dns_tsigkey_t *key, unsigned int timeout,
+ unsigned int udptimeout, unsigned int udpretries,
+ isc_task_t *task, isc_taskaction_t action, void *arg,
+ dns_request_t **requestp);
/*%<
* Create and send a request.
*
@@ -204,6 +216,17 @@ dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
unsigned int udpretries, isc_task_t *task,
isc_taskaction_t action, void *arg,
dns_request_t **requestp);
+isc_result_t
+dns_request_createraw2(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
+ const isc_sockaddr_t *srcaddr,
+ const isc_sockaddr_t *destaddr,
+ dns_transport_t *transport,
+ isc_tlsctx_cache_t *tlsctx_cache,
+ unsigned int options,
+ unsigned int timeout, unsigned int udptimeout,
+ unsigned int udpretries, isc_task_t *task,
+ isc_taskaction_t action, void *arg,
+ dns_request_t **requestp);
/*!<
* \brief Create and send a request.
*
diff --git a/lib/dns/include/dns/transport.h b/lib/dns/include/dns/transport.h
index e74ccd7..e6499a9 100644
--- a/lib/dns/include/dns/transport.h
+++ b/lib/dns/include/dns/transport.h
@@ -13,7 +13,9 @@
#pragma once
-#include <dns/name.h>
+#include <isc/tls.h>
+
+#include <dns/types.h>
typedef enum {
DNS_TRANSPORT_NONE = 0,
@@ -29,9 +31,6 @@ typedef enum {
DNS_HTTP_POST = 1,
} dns_http_mode_t;
-typedef struct dns_transport dns_transport_t;
-typedef struct dns_transport_list dns_transport_list_t;
-
dns_transport_t *
dns_transport_new(const dns_name_t *name, dns_transport_type_t type,
dns_transport_list_t *list);
@@ -63,15 +62,44 @@ dns_transport_get_tls_versions(const dns_transport_t *transport);
bool
dns_transport_get_prefer_server_ciphers(const dns_transport_t *transport,
bool *preferp);
+bool
+dns_transport_get_always_verify_remote(dns_transport_t *transport);
/*%<
* Getter functions: return the type, cert file, key file, CA file,
- * hostname, HTTP endpoint, or HTTP mode (GET or POST) for 'transport'.
+ * hostname, HTTP endpoint, HTTP mode (GET or POST), ciphers, TLS name,
+ * TLS version, server ciphers preference mode, and always enabling
+ * authentication mode for 'transport'.
*
* dns_transport_get_prefer_server_ciphers() returns 'true' is value
* was set, 'false' otherwise. The actual value is returned via
* 'preferp' pointer.
*/
+isc_result_t
+dns_transport_get_tlsctx(dns_transport_t *transport, const isc_sockaddr_t *peer,
+ isc_tlsctx_cache_t *tlsctx_cache, isc_mem_t *mctx,
+ isc_tlsctx_t **pctx,
+ isc_tlsctx_client_session_cache_t **psess_cache);
+/*%<
+ * Get the transport's TLS Context and the TLS Client Session Cache associated
+ * with it.
+ *
+ * When neither the TLS hostname, nor the TLS certificates authorities (CA)
+ * file are set for the 'transport', then Opportunistic TLS (no authentication
+ * of the remote peer) will be used, unless the 'always_verify_remote' mode is
+ * enabled on the 'transport', in which case the remote peer will be
+ * authenticated by its IP address using the system's default certificates
+ * authorities store.
+ *
+ * Requires:
+ *\li 'transport' is a valid, 'DNS_TRANSPORT_TLS' type transport.
+ *\li 'peer' is not NULL.
+ *\li 'tlsctx_cache' is not NULL.
+ *\li 'mctx' is not NULL.
+ *\li 'pctx' is not NULL and '*pctx' is NULL.
+ *\li 'psess_cache' is not NULL and '*psess_cache' is NULL.
+ */
+
void
dns_transport_set_certfile(dns_transport_t *transport, const char *certfile);
void
@@ -96,9 +124,14 @@ dns_transport_set_tls_versions(dns_transport_t *transport,
void
dns_transport_set_prefer_server_ciphers(dns_transport_t *transport,
const bool prefer);
+void
+dns_transport_set_always_verify_remote(dns_transport_t *transport,
+ const bool always_verify_remote);
/*%<
* Setter functions: set the type, cert file, key file, CA file,
- * hostname, HTTP endpoint, or HTTP mode (GET or POST) for 'transport'.
+ * hostname, HTTP endpoint, HTTP mode (GET or POST), ciphers, TLS name,
+ * TLS version, server ciphers preference mode, and always enabling
+ * authentication mode for 'transport'.
*
* Requires:
*\li 'transport' is valid.
diff --git a/lib/dns/include/dns/types.h b/lib/dns/include/dns/types.h
index 6465962..f0aaa24 100644
--- a/lib/dns/include/dns/types.h
+++ b/lib/dns/include/dns/types.h
@@ -141,6 +141,8 @@ typedef struct dns_ssutable dns_ssutable_t;
typedef struct dns_stats dns_stats_t;
typedef uint32_t dns_rdatastatstype_t;
typedef struct dns_tkeyctx dns_tkeyctx_t;
+typedef struct dns_transport dns_transport_t;
+typedef struct dns_transport_list dns_transport_list_t;
typedef uint16_t dns_trust_t;
typedef struct dns_tsec dns_tsec_t;
typedef struct dns_tsig_keyring dns_tsig_keyring_t;
diff --git a/lib/dns/request.c b/lib/dns/request.c
index 8aaa29f..badedab 100644
--- a/lib/dns/request.c
+++ b/lib/dns/request.c
@@ -399,12 +399,12 @@ isblackholed(dns_dispatchmgr_t *dispatchmgr, const isc_sockaddr_t *destaddr) {
static isc_result_t
tcp_dispatch(bool newtcp, dns_requestmgr_t *requestmgr,
const isc_sockaddr_t *srcaddr, const isc_sockaddr_t *destaddr,
- dns_dispatch_t **dispatchp) {
+ dns_transport_t *transport, dns_dispatch_t **dispatchp) {
isc_result_t result;
if (!newtcp) {
- result = dns_dispatch_gettcp(requestmgr->dispatchmgr, destaddr,
- srcaddr, dispatchp);
+ result = dns_dispatch_gettcp2(requestmgr->dispatchmgr, destaddr,
+ srcaddr, transport, dispatchp);
if (result == ISC_R_SUCCESS) {
char peer[ISC_SOCKADDR_FORMATSIZE];
@@ -415,8 +415,8 @@ tcp_dispatch(bool newtcp, dns_requestmgr_t *requestmgr,
}
}
- result = dns_dispatch_createtcp(requestmgr->dispatchmgr, srcaddr,
- destaddr, dispatchp);
+ result = dns_dispatch_createtcp2(requestmgr->dispatchmgr, srcaddr,
+ destaddr, transport, 0, dispatchp);
return result;
}
@@ -452,12 +452,12 @@ udp_dispatch(dns_requestmgr_t *requestmgr, const isc_sockaddr_t *srcaddr,
static isc_result_t
get_dispatch(bool tcp, bool newtcp, dns_requestmgr_t *requestmgr,
const isc_sockaddr_t *srcaddr, const isc_sockaddr_t *destaddr,
- dns_dispatch_t **dispatchp) {
+ dns_transport_t *transport, dns_dispatch_t **dispatchp) {
isc_result_t result;
if (tcp) {
result = tcp_dispatch(newtcp, requestmgr, srcaddr, destaddr,
- dispatchp);
+ transport, dispatchp);
} else {
result = udp_dispatch(requestmgr, srcaddr, destaddr, dispatchp);
}
@@ -472,6 +472,21 @@ dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
unsigned int udpretries, isc_task_t *task,
isc_taskaction_t action, void *arg,
dns_request_t **requestp) {
+ return dns_request_createraw2(requestmgr, msgbuf, srcaddr, destaddr,
+ NULL, NULL, options, timeout, udptimeout,
+ udpretries, task, action, arg, requestp);
+}
+
+isc_result_t
+dns_request_createraw2(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
+ const isc_sockaddr_t *srcaddr,
+ const isc_sockaddr_t *destaddr,
+ dns_transport_t *transport,
+ isc_tlsctx_cache_t *tlsctx_cache, unsigned int options,
+ unsigned int timeout, unsigned int udptimeout,
+ unsigned int udpretries, isc_task_t *task,
+ isc_taskaction_t action, void *arg,
+ dns_request_t **requestp) {
dns_request_t *request = NULL;
isc_result_t result;
isc_mem_t *mctx = NULL;
@@ -553,7 +568,7 @@ dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
again:
result = get_dispatch(tcp, newtcp, requestmgr, srcaddr, destaddr,
- &request->dispatch);
+ transport, &request->dispatch);
if (result != ISC_R_SUCCESS) {
goto detach;
}
@@ -563,10 +578,10 @@ again:
dispopt |= DNS_DISPATCHOPT_FIXEDID;
}
- result = dns_dispatch_add(request->dispatch, dispopt, request->timeout,
- destaddr, req_connected, req_senddone,
- req_response, request, &id,
- &request->dispentry);
+ result = dns_dispatch_add2(request->dispatch, dispopt, request->timeout,
+ destaddr, transport, tlsctx_cache,
+ req_connected, req_senddone, req_response,
+ request, &id, &request->dispentry);
if (result != ISC_R_SUCCESS) {
if ((options & DNS_REQUESTOPT_FIXEDID) != 0 && !newtcp) {
newtcp = true;
@@ -630,6 +645,21 @@ dns_request_create(dns_requestmgr_t *requestmgr, dns_message_t *message,
unsigned int udptimeout, unsigned int udpretries,
isc_task_t *task, isc_taskaction_t action, void *arg,
dns_request_t **requestp) {
+ return dns_request_create2(requestmgr, message, srcaddr, destaddr, NULL,
+ NULL, options, key, timeout, udptimeout,
+ udpretries, task, action, arg, requestp);
+}
+
+isc_result_t
+dns_request_create2(dns_requestmgr_t *requestmgr, dns_message_t *message,
+ const isc_sockaddr_t *srcaddr,
+ const isc_sockaddr_t *destaddr,
+ dns_transport_t *req_transport,
+ isc_tlsctx_cache_t *req_tls_ctx_cache, unsigned int options,
+ dns_tsigkey_t *key, unsigned int timeout,
+ unsigned int udptimeout, unsigned int udpretries,
+ isc_task_t *task, isc_taskaction_t action, void *arg,
+ dns_request_t **requestp) {
dns_request_t *request = NULL;
isc_result_t result;
isc_mem_t *mctx = NULL;
@@ -707,14 +737,15 @@ dns_request_create(dns_requestmgr_t *requestmgr, dns_message_t *message,
again:
result = get_dispatch(tcp, false, requestmgr, srcaddr, destaddr,
- &request->dispatch);
+ req_transport, &request->dispatch);
if (result != ISC_R_SUCCESS) {
goto detach;
}
- result = dns_dispatch_add(
- request->dispatch, 0, request->timeout, destaddr, req_connected,
- req_senddone, req_response, request, &id, &request->dispentry);
+ result = dns_dispatch_add2(request->dispatch, 0, request->timeout,
+ destaddr, req_transport, req_tls_ctx_cache,
+ req_connected, req_senddone, req_response,
+ request, &id, &request->dispentry);
if (result != ISC_R_SUCCESS) {
goto detach;
}
diff --git a/lib/dns/transport.c b/lib/dns/transport.c
index 88a3df4..2a779ba 100644
--- a/lib/dns/transport.c
+++ b/lib/dns/transport.c
@@ -15,9 +15,11 @@
#include <isc/list.h>
#include <isc/mem.h>
+#include <isc/netaddr.h>
#include <isc/refcount.h>
#include <isc/result.h>
#include <isc/rwlock.h>
+#include <isc/sockaddr.h>
#include <isc/util.h>
#include <dns/name.h>
@@ -54,6 +56,7 @@ struct dns_transport {
char *ciphers;
uint32_t protocol_versions;
ternary_t prefer_server_ciphers;
+ bool always_verify_remote;
} tls;
struct {
char *endpoint;
@@ -332,6 +335,256 @@ dns_transport_get_prefer_server_ciphers(const dns_transport_t *transport,
return false;
}
+void
+dns_transport_set_always_verify_remote(dns_transport_t *transport,
+ const bool always_verify_remote) {
+ REQUIRE(VALID_TRANSPORT(transport));
+ REQUIRE(transport->type == DNS_TRANSPORT_TLS ||
+ transport->type == DNS_TRANSPORT_HTTP);
+
+ transport->tls.always_verify_remote = always_verify_remote;
+}
+
+bool
+dns_transport_get_always_verify_remote(dns_transport_t *transport) {
+ REQUIRE(VALID_TRANSPORT(transport));
+ REQUIRE(transport->type == DNS_TRANSPORT_TLS ||
+ transport->type == DNS_TRANSPORT_HTTP);
+
+ return transport->tls.always_verify_remote;
+}
+
+isc_result_t
+dns_transport_get_tlsctx(dns_transport_t *transport, const isc_sockaddr_t *peer,
+ isc_tlsctx_cache_t *tlsctx_cache, isc_mem_t *mctx,
+ isc_tlsctx_t **pctx,
+ isc_tlsctx_client_session_cache_t **psess_cache) {
+ isc_result_t result = ISC_R_FAILURE;
+ isc_tlsctx_t *tlsctx = NULL, *found = NULL;
+ isc_tls_cert_store_t *store = NULL, *found_store = NULL;
+ isc_tlsctx_client_session_cache_t *sess_cache = NULL;
+ isc_tlsctx_client_session_cache_t *found_sess_cache = NULL;
+ uint32_t tls_versions;
+ const char *ciphers = NULL;
+ bool prefer_server_ciphers;
+ uint16_t family;
+ const char *tlsname = NULL;
+
+ REQUIRE(VALID_TRANSPORT(transport));
+ REQUIRE(transport->type == DNS_TRANSPORT_TLS);
+ REQUIRE(peer != NULL);
+ REQUIRE(tlsctx_cache != NULL);
+ REQUIRE(mctx != NULL);
+ REQUIRE(pctx != NULL && *pctx == NULL);
+ REQUIRE(psess_cache != NULL && *psess_cache == NULL);
+
+ family = (isc_sockaddr_pf(peer) == PF_INET6) ? AF_INET6 : AF_INET;
+
+ tlsname = dns_transport_get_tlsname(transport);
+ INSIST(tlsname != NULL && *tlsname != '\0');
+
+ /*
+ * Let's try to re-use the already created context. This way
+ * we have a chance to resume the TLS session, bypassing the
+ * full TLS handshake procedure, making establishing
+ * subsequent TLS connections faster.
+ */
+ result = isc_tlsctx_cache_find(tlsctx_cache, tlsname,
+ isc_tlsctx_cache_tls, family, &found,
+ &found_store, &found_sess_cache);
+ if (result != ISC_R_SUCCESS) {
+ const char *hostname =
+ dns_transport_get_remote_hostname(transport);
+ const char *ca_file = dns_transport_get_cafile(transport);
+ const char *cert_file = dns_transport_get_certfile(transport);
+ const char *key_file = dns_transport_get_keyfile(transport);
+ const bool always_verify_remote =
+ dns_transport_get_always_verify_remote(transport);
+ char peer_addr_str[INET6_ADDRSTRLEN] = { 0 };
+ isc_netaddr_t peer_netaddr = { 0 };
+ bool hostname_ignore_subject;
+
+ /*
+ * So, no context exists. Let's create one using the
+ * parameters from the configuration file and try to
+ * store it for further reuse.
+ */
+ result = isc_tlsctx_createclient(&tlsctx);
+ if (result != ISC_R_SUCCESS) {
+ goto failure;
+ }
+ tls_versions = dns_transport_get_tls_versions(transport);
+ if (tls_versions != 0) {
+ isc_tlsctx_set_protocols(tlsctx, tls_versions);
+ }
+ ciphers = dns_transport_get_ciphers(transport);
+ if (ciphers != NULL) {
+ isc_tlsctx_set_cipherlist(tlsctx, ciphers);
+ }
+
+ if (dns_transport_get_prefer_server_ciphers(
+ transport, &prefer_server_ciphers))
+ {
+ isc_tlsctx_prefer_server_ciphers(tlsctx,
+ prefer_server_ciphers);
+ }
+
+ if (always_verify_remote || hostname != NULL || ca_file != NULL)
+ {
+ /*
+ * The situation when 'found_store != NULL' while
+ * 'found == NULL' may occur as there is a one-to-many
+ * relation between cert stores and per-transport TLS
+ * contexts. That is, there could be one store
+ * shared between multiple contexts.
+ */
+ if (found_store == NULL) {
+ /*
+ * 'ca_file' can equal 'NULL' here, in
+ * which case the store with system-wide
+ * CA certificates will be created.
+ */
+ result = isc_tls_cert_store_create(ca_file,
+ &store);
+
+ if (result != ISC_R_SUCCESS) {
+ goto failure;
+ }
+ } else {
+ store = found_store;
+ }
+
+ INSIST(store != NULL);
+ if (hostname == NULL) {
+ /*
+ * If hostname is not specified, then use the
+ * peer IP address for validation.
+ */
+ isc_netaddr_fromsockaddr(&peer_netaddr, peer);
+ isc_netaddr_format(&peer_netaddr, peer_addr_str,
+ sizeof(peer_addr_str));
+ hostname = peer_addr_str;
+ }
+
+ /*
+ * According to RFC 8310, Subject field MUST NOT
+ * be inspected when verifying hostname for DoT.
+ * Only SubjectAltName must be checked.
+ */
+ hostname_ignore_subject = true;
+ result = isc_tlsctx_enable_peer_verification(
+ tlsctx, false, store, hostname,
+ hostname_ignore_subject);
+ if (result != ISC_R_SUCCESS) {
+ goto failure;
+ }
+
+ /*
+ * Let's load client certificate and enable
+ * Mutual TLS. We do that only in the case when
+ * Strict TLS is enabled, because Mutual TLS is
+ * an extension of it.
+ */
+ if (cert_file != NULL) {
+ INSIST(key_file != NULL);
+
+ result = isc_tlsctx_load_certificate(
+ tlsctx, key_file, cert_file);
+ if (result != ISC_R_SUCCESS) {
+ goto failure;
+ }
+ }
+ }
+
+ isc_tlsctx_enable_dot_client_alpn(tlsctx);
+
+ isc_tlsctx_client_session_cache_create(
+ mctx, tlsctx,
+ ISC_TLSCTX_CLIENT_SESSION_CACHE_DEFAULT_SIZE,
+ &sess_cache);
+
+ found_store = NULL;
+ result = isc_tlsctx_cache_add(tlsctx_cache, tlsname,
+ isc_tlsctx_cache_tls, family,
+ tlsctx, store, sess_cache, &found,
+ &found_store, &found_sess_cache);
+ if (result == ISC_R_EXISTS) {
+ /*
+ * It seems the entry has just been created from
+ * within another thread while we were initialising
+ * ours. Although this is unlikely, it could happen
+ * after startup/re-initialisation. In such a case,
+ * discard the new context and associated data and use
+ * the already established one from now on.
+ *
+ * Such situation will not occur after the
+ * initial 'warm-up', so it is not critical
+ * performance-wise.
+ */
+ INSIST(found != NULL);
+ isc_tlsctx_free(&tlsctx);
+ /*
+ * The 'store' variable can be 'NULL' when remote server
+ * verification is not enabled (that is, when Strict or
+ * Mutual TLS are not used).
+ *
+ * The 'found_store' might be equal to 'store' as there
+ * is one-to-many relation between a store and
+ * per-transport TLS contexts. In that case, the call to
+ * 'isc_tlsctx_cache_find()' above could have returned a
+ * store via the 'found_store' variable, whose value we
+ * can assign to 'store' later. In that case,
+ * 'isc_tlsctx_cache_add()' will return the same value.
+ * When that happens, we should not free the store
+ * object, as it is managed by the TLS context cache.
+ */
+ if (store != NULL && store != found_store) {
+ isc_tls_cert_store_free(&store);
+ }
+ isc_tlsctx_client_session_cache_detach(&sess_cache);
+ /* Let's return the data from the cache. */
+ *psess_cache = found_sess_cache;
+ *pctx = found;
+ } else {
+ /*
+ * Adding the fresh values into the cache has been
+ * successful, let's return them
+ */
+ INSIST(result == ISC_R_SUCCESS);
+ *psess_cache = sess_cache;
+ *pctx = tlsctx;
+ }
+ } else {
+ /*
+ * The cache lookup has been successful, let's return the
+ * results.
+ */
+ INSIST(result == ISC_R_SUCCESS);
+ *psess_cache = found_sess_cache;
+ *pctx = found;
+ }
+
+ return ISC_R_SUCCESS;
+
+failure:
+ if (tlsctx != NULL) {
+ isc_tlsctx_free(&tlsctx);
+ }
+
+ /*
+ * The 'found_store' is being managed by the TLS context
+ * cache. Thus, we should keep it as it is, as it will get
+ * destroyed alongside the cache. As there is one store per
+ * multiple TLS contexts, we need to handle store deletion in a
+ * special way.
+ */
+ if (store != NULL && store != found_store) {
+ isc_tls_cert_store_free(&store);
+ }
+
+ return result;
+}
+
static void
transport_destroy(dns_transport_t *transport) {
isc_refcount_destroy(&transport->references);
diff --git a/lib/dns/xfrin.c b/lib/dns/xfrin.c
index 3a4f761..3695815 100644
--- a/lib/dns/xfrin.c
+++ b/lib/dns/xfrin.c
@@ -962,234 +962,6 @@ xfrin_create(isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db, isc_nm_t *netmgr,
*xfrp = xfr;
}
-static isc_result_t
-get_create_tlsctx(const dns_xfrin_ctx_t *xfr, isc_tlsctx_t **pctx,
- isc_tlsctx_client_session_cache_t **psess_cache) {
- isc_result_t result = ISC_R_FAILURE;
- isc_tlsctx_t *tlsctx = NULL, *found = NULL;
- isc_tls_cert_store_t *store = NULL, *found_store = NULL;
- isc_tlsctx_client_session_cache_t *sess_cache = NULL,
- *found_sess_cache = NULL;
- uint32_t tls_versions;
- const char *ciphers = NULL;
- bool prefer_server_ciphers;
- const uint16_t family = isc_sockaddr_pf(&xfr->primaryaddr) == PF_INET6
- ? AF_INET6
- : AF_INET;
- const char *tlsname = NULL;
-
- REQUIRE(psess_cache != NULL && *psess_cache == NULL);
- REQUIRE(pctx != NULL && *pctx == NULL);
-
- INSIST(xfr->transport != NULL);
- tlsname = dns_transport_get_tlsname(xfr->transport);
- INSIST(tlsname != NULL && *tlsname != '\0');
-
- /*
- * Let's try to re-use the already created context. This way
- * we have a chance to resume the TLS session, bypassing the
- * full TLS handshake procedure, making establishing
- * subsequent TLS connections for XoT faster.
- */
- result = isc_tlsctx_cache_find(xfr->tlsctx_cache, tlsname,
- isc_tlsctx_cache_tls, family, &found,
- &found_store, &found_sess_cache);
- if (result != ISC_R_SUCCESS) {
- const char *hostname =
- dns_transport_get_remote_hostname(xfr->transport);
- const char *ca_file = dns_transport_get_cafile(xfr->transport);
- const char *cert_file =
- dns_transport_get_certfile(xfr->transport);
- const char *key_file =
- dns_transport_get_keyfile(xfr->transport);
- char primary_addr_str[INET6_ADDRSTRLEN] = { 0 };
- isc_netaddr_t primary_netaddr = { 0 };
- bool hostname_ignore_subject;
- /*
- * So, no context exists. Let's create one using the
- * parameters from the configuration file and try to
- * store it for further reuse.
- */
- result = isc_tlsctx_createclient(&tlsctx);
- if (result != ISC_R_SUCCESS) {
- goto failure;
- }
- tls_versions = dns_transport_get_tls_versions(xfr->transport);
- if (tls_versions != 0) {
- isc_tlsctx_set_protocols(tlsctx, tls_versions);
- }
- ciphers = dns_transport_get_ciphers(xfr->transport);
- if (ciphers != NULL) {
- isc_tlsctx_set_cipherlist(tlsctx, ciphers);
- }
-
- if (dns_transport_get_prefer_server_ciphers(
- xfr->transport, &prefer_server_ciphers))
- {
- isc_tlsctx_prefer_server_ciphers(tlsctx,
- prefer_server_ciphers);
- }
-
- if (hostname != NULL || ca_file != NULL) {
- /*
- * The situation when 'found_store != NULL' while 'found
- * == NULL' might appear as there is one to many
- * relation between per transport TLS contexts and cert
- * stores. That is, there could be one store shared
- * between multiple contexts.
- */
- if (found_store == NULL) {
- /*
- * 'ca_file' can equal 'NULL' here, in
- * that case the store with system-wide
- * CA certificates will be created, just
- * as planned.
- */
- result = isc_tls_cert_store_create(ca_file,
- &store);
-
- if (result != ISC_R_SUCCESS) {
- goto failure;
- }
- } else {
- store = found_store;
- }
-
- INSIST(store != NULL);
- if (hostname == NULL) {
- /*
- * If CA bundle file is specified, but
- * hostname is not, then use the primary
- * IP address for validation, just like
- * dig does.
- */
- INSIST(ca_file != NULL);
- isc_netaddr_fromsockaddr(&primary_netaddr,
- &xfr->primaryaddr);
- isc_netaddr_format(&primary_netaddr,
- primary_addr_str,
- sizeof(primary_addr_str));
- hostname = primary_addr_str;
- }
- /*
- * According to RFC 8310, Subject field MUST NOT
- * be inspected when verifying hostname for DoT.
- * Only SubjectAltName must be checked.
- */
- hostname_ignore_subject = true;
- result = isc_tlsctx_enable_peer_verification(
- tlsctx, false, store, hostname,
- hostname_ignore_subject);
- if (result != ISC_R_SUCCESS) {
- goto failure;
- }
-
- /*
- * Let's load client certificate and enable
- * Mutual TLS. We do that only in the case when
- * Strict TLS is enabled, because Mutual TLS is
- * an extension of it.
- */
- if (cert_file != NULL) {
- INSIST(key_file != NULL);
-
- result = isc_tlsctx_load_certificate(
- tlsctx, key_file, cert_file);
- if (result != ISC_R_SUCCESS) {
- goto failure;
- }
- }
- }
-
- isc_tlsctx_enable_dot_client_alpn(tlsctx);
-
- isc_tlsctx_client_session_cache_create(
- xfr->mctx, tlsctx,
- ISC_TLSCTX_CLIENT_SESSION_CACHE_DEFAULT_SIZE,
- &sess_cache);
-
- found_store = NULL;
- result = isc_tlsctx_cache_add(xfr->tlsctx_cache, tlsname,
- isc_tlsctx_cache_tls, family,
- tlsctx, store, sess_cache, &found,
- &found_store, &found_sess_cache);
- if (result == ISC_R_EXISTS) {
- /*
- * It seems the entry has just been created from within
- * another thread while we were initialising
- * ours. Although this is unlikely, it could happen
- * after startup/re-initialisation. In such a case,
- * discard the new context and associated data and use
- * the already established one from now on.
- *
- * Such situation will not occur after the
- * initial 'warm-up', so it is not critical
- * performance-wise.
- */
- INSIST(found != NULL);
- isc_tlsctx_free(&tlsctx);
- /*
- * The 'store' variable can be 'NULL' when remote server
- * verification is not enabled (that is, when Strict or
- * Mutual TLS are not used).
- *
- * The 'found_store' might be equal to 'store' as there
- * is one-to-many relation between a store and
- * per-transport TLS contexts. In that case, the call to
- * 'isc_tlsctx_cache_find()' above could have returned a
- * store via the 'found_store' variable, whose value we
- * can assign to 'store' later. In that case,
- * 'isc_tlsctx_cache_add()' will return the same value.
- * When that happens, we should not free the store
- * object, as it is managed by the TLS context cache.
- */
- if (store != NULL && store != found_store) {
- isc_tls_cert_store_free(&store);
- }
- isc_tlsctx_client_session_cache_detach(&sess_cache);
- /* Let's return the data from the cache. */
- *psess_cache = found_sess_cache;
- *pctx = found;
- } else {
- /*
- * Adding the fresh values into the cache has been
- * successful, let's return them
- */
- INSIST(result == ISC_R_SUCCESS);
- *psess_cache = sess_cache;
- *pctx = tlsctx;
- }
- } else {
- /*
- * The cache lookup has been successful, let's return the
- * results.
- */
- INSIST(result == ISC_R_SUCCESS);
- *psess_cache = found_sess_cache;
- *pctx = found;
- }
-
- return ISC_R_SUCCESS;
-
-failure:
- if (tlsctx != NULL) {
- isc_tlsctx_free(&tlsctx);
- }
-
- /*
- * The 'found_store' is being managed by the TLS context
- * cache. Thus, we should keep it as it is, as it will get
- * destroyed alongside the cache. As there is one store per
- * multiple TLS contexts, we need to handle store deletion in a
- * special way.
- */
- if (store != NULL && store != found_store) {
- isc_tls_cert_store_free(&store);
- }
-
- return result;
-}
-
static isc_result_t
xfrin_start(dns_xfrin_ctx_t *xfr) {
isc_result_t result;
@@ -1232,7 +1004,9 @@ xfrin_start(dns_xfrin_ctx_t *xfr) {
connect_xfr, 30000, 0);
break;
case DNS_TRANSPORT_TLS: {
- result = get_create_tlsctx(xfr, &tlsctx, &sess_cache);
+ result = dns_transport_get_tlsctx(
+ xfr->transport, &xfr->primaryaddr, xfr->tlsctx_cache,
+ xfr->mctx, &tlsctx, &sess_cache);
if (result != ISC_R_SUCCESS) {
goto failure;
}
--
2.48.1