2021-01-14 06:51:25 -05:00
|
|
|
/*
|
|
|
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
|
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: MPL-2.0
|
2021-06-03 02:37:05 -04:00
|
|
|
*
|
2021-01-14 06:51:25 -05:00
|
|
|
* 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 <inttypes.h>
|
|
|
|
|
|
2023-08-16 00:04:54 -04:00
|
|
|
#include <isc/hashmap.h>
|
2021-01-14 06:51:25 -05:00
|
|
|
#include <isc/list.h>
|
|
|
|
|
#include <isc/mem.h>
|
2022-09-19 06:24:20 -04:00
|
|
|
#include <isc/netaddr.h>
|
2021-01-14 06:51:25 -05:00
|
|
|
#include <isc/refcount.h>
|
|
|
|
|
#include <isc/result.h>
|
|
|
|
|
#include <isc/rwlock.h>
|
2022-09-19 06:24:20 -04:00
|
|
|
#include <isc/sockaddr.h>
|
2021-01-14 06:51:25 -05:00
|
|
|
#include <isc/util.h>
|
|
|
|
|
|
2023-08-16 00:04:54 -04:00
|
|
|
#include <dns/fixedname.h>
|
2021-01-14 06:51:25 -05:00
|
|
|
#include <dns/name.h>
|
|
|
|
|
#include <dns/transport.h>
|
|
|
|
|
|
|
|
|
|
#define TRANSPORT_MAGIC ISC_MAGIC('T', 'r', 'n', 's')
|
|
|
|
|
#define VALID_TRANSPORT(ptr) ISC_MAGIC_VALID(ptr, TRANSPORT_MAGIC)
|
|
|
|
|
|
|
|
|
|
#define TRANSPORT_LIST_MAGIC ISC_MAGIC('T', 'r', 'L', 's')
|
|
|
|
|
#define VALID_TRANSPORT_LIST(ptr) ISC_MAGIC_VALID(ptr, TRANSPORT_LIST_MAGIC)
|
|
|
|
|
|
|
|
|
|
struct dns_transport_list {
|
|
|
|
|
unsigned int magic;
|
|
|
|
|
isc_refcount_t references;
|
|
|
|
|
isc_mem_t *mctx;
|
|
|
|
|
isc_rwlock_t lock;
|
2023-08-16 00:04:54 -04:00
|
|
|
isc_hashmap_t *transports[DNS_TRANSPORT_COUNT];
|
2021-01-14 06:51:25 -05:00
|
|
|
};
|
|
|
|
|
|
2021-11-29 16:09:51 -05:00
|
|
|
typedef enum ternary { ter_none = 0, ter_true = 1, ter_false = 2 } ternary_t;
|
|
|
|
|
|
2021-01-14 06:51:25 -05:00
|
|
|
struct dns_transport {
|
|
|
|
|
unsigned int magic;
|
|
|
|
|
isc_refcount_t references;
|
|
|
|
|
isc_mem_t *mctx;
|
|
|
|
|
dns_transport_type_t type;
|
2023-08-16 00:04:54 -04:00
|
|
|
dns_fixedname_t fn;
|
|
|
|
|
dns_name_t *name;
|
2021-01-14 06:51:25 -05:00
|
|
|
struct {
|
2021-12-23 09:08:41 -05:00
|
|
|
char *tlsname;
|
2021-01-14 06:51:25 -05:00
|
|
|
char *certfile;
|
|
|
|
|
char *keyfile;
|
|
|
|
|
char *cafile;
|
2022-05-03 09:51:33 -04:00
|
|
|
char *remote_hostname;
|
2021-11-29 16:09:51 -05:00
|
|
|
char *ciphers;
|
2023-11-30 15:26:53 -05:00
|
|
|
char *cipher_suites;
|
2021-11-29 16:09:51 -05:00
|
|
|
uint32_t protocol_versions;
|
|
|
|
|
ternary_t prefer_server_ciphers;
|
2022-09-21 04:20:22 -04:00
|
|
|
bool always_verify_remote;
|
2021-01-14 06:51:25 -05:00
|
|
|
} tls;
|
|
|
|
|
struct {
|
|
|
|
|
char *endpoint;
|
refactor outgoing HTTP connection support
- style, cleanup, and removal of unnecessary code.
- combined isc_nm_http_add_endpoint() and isc_nm_http_add_doh_endpoint()
into one function, renamed isc_http_endpoint().
- moved isc_nm_http_connect_send_request() into doh_test.c as a helper
function; remove it from the public API.
- renamed isc_http2 and isc_nm_http2 types and functions to just isc_http
and isc_nm_http, for consistency with other existing names.
- shortened a number of long names.
- the caller is now responsible for determining the peer address.
in isc_nm_httpconnect(); this eliminates the need to parse the URI
and the dependency on an external resolver.
- the caller is also now responsible for creating the SSL client context,
for consistency with isc_nm_tlsdnsconnect().
- added setter functions for HTTP/2 ALPN. instead of setting up ALPN in
isc_tlsctx_createclient(), we now have a function
isc_tlsctx_enable_http2client_alpn() that can be run from
isc_nm_httpconnect().
- refactored isc_nm_httprequest() into separate read and send functions.
isc_nm_send() or isc_nm_read() is called on an http socket, it will
be stored until a corresponding isc_nm_read() or _send() arrives; when
we have both halves of the pair the HTTP request will be initiated.
- isc_nm_httprequest() is renamed isc__nm_http_request() for use as an
internal helper function by the DoH unit test. (eventually doh_test
should be rewritten to use read and send, and this function should
be removed.)
- added implementations of isc__nm_tls_settimeout() and
isc__nm_http_settimeout().
- increased NGHTTP2 header block length for client connections to 128K.
- use isc_mem_t for internal memory allocations inside nghttp2, to
help track memory leaks.
- send "Cache-Control" header in requests and responses. (note:
currently we try to bypass HTTP caching proxies, but ideally we should
interact with them: https://tools.ietf.org/html/rfc8484#section-5.1)
2021-02-03 19:59:49 -05:00
|
|
|
dns_http_mode_t mode;
|
2021-01-14 06:51:25 -05:00
|
|
|
} doh;
|
|
|
|
|
};
|
|
|
|
|
|
2023-08-28 04:08:59 -04:00
|
|
|
static bool
|
|
|
|
|
transport_match(void *node, const void *key) {
|
|
|
|
|
dns_transport_t *transport = node;
|
|
|
|
|
|
|
|
|
|
return dns_name_equal(transport->name, key);
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-14 06:51:25 -05:00
|
|
|
static isc_result_t
|
|
|
|
|
list_add(dns_transport_list_t *list, const dns_name_t *name,
|
|
|
|
|
const dns_transport_type_t type, dns_transport_t *transport) {
|
|
|
|
|
isc_result_t result;
|
2023-08-16 00:04:54 -04:00
|
|
|
isc_hashmap_t *hm = NULL;
|
2021-01-14 06:51:25 -05:00
|
|
|
|
|
|
|
|
RWLOCK(&list->lock, isc_rwlocktype_write);
|
2023-08-16 00:04:54 -04:00
|
|
|
hm = list->transports[type];
|
|
|
|
|
INSIST(hm != NULL);
|
2021-01-14 06:51:25 -05:00
|
|
|
|
2023-08-16 00:04:54 -04:00
|
|
|
transport->name = dns_fixedname_initname(&transport->fn);
|
|
|
|
|
dns_name_copy(name, transport->name);
|
2023-08-28 04:08:59 -04:00
|
|
|
result = isc_hashmap_add(hm, dns_name_hash(name), transport_match, name,
|
|
|
|
|
transport, NULL);
|
2021-01-14 06:51:25 -05:00
|
|
|
RWUNLOCK(&list->lock, isc_rwlocktype_write);
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dns_transport_type_t
|
2023-05-30 10:32:02 -04:00
|
|
|
dns_transport_get_type(const dns_transport_t *transport) {
|
2021-01-14 06:51:25 -05:00
|
|
|
REQUIRE(VALID_TRANSPORT(transport));
|
|
|
|
|
|
|
|
|
|
return transport->type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *
|
2023-05-30 10:32:02 -04:00
|
|
|
dns_transport_get_certfile(const dns_transport_t *transport) {
|
2021-01-14 06:51:25 -05:00
|
|
|
REQUIRE(VALID_TRANSPORT(transport));
|
|
|
|
|
|
|
|
|
|
return transport->tls.certfile;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *
|
2023-05-30 10:32:02 -04:00
|
|
|
dns_transport_get_keyfile(const dns_transport_t *transport) {
|
2021-01-14 06:51:25 -05:00
|
|
|
REQUIRE(VALID_TRANSPORT(transport));
|
|
|
|
|
|
|
|
|
|
return transport->tls.keyfile;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *
|
2023-05-30 10:32:02 -04:00
|
|
|
dns_transport_get_cafile(const dns_transport_t *transport) {
|
2021-01-14 06:51:25 -05:00
|
|
|
REQUIRE(VALID_TRANSPORT(transport));
|
|
|
|
|
|
|
|
|
|
return transport->tls.cafile;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *
|
2023-05-30 10:32:02 -04:00
|
|
|
dns_transport_get_remote_hostname(const dns_transport_t *transport) {
|
2021-01-14 06:51:25 -05:00
|
|
|
REQUIRE(VALID_TRANSPORT(transport));
|
|
|
|
|
|
2022-05-03 09:51:33 -04:00
|
|
|
return transport->tls.remote_hostname;
|
2021-01-14 06:51:25 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *
|
2023-05-30 10:32:02 -04:00
|
|
|
dns_transport_get_endpoint(const dns_transport_t *transport) {
|
2021-01-14 06:51:25 -05:00
|
|
|
REQUIRE(VALID_TRANSPORT(transport));
|
|
|
|
|
|
|
|
|
|
return transport->doh.endpoint;
|
|
|
|
|
}
|
|
|
|
|
|
refactor outgoing HTTP connection support
- style, cleanup, and removal of unnecessary code.
- combined isc_nm_http_add_endpoint() and isc_nm_http_add_doh_endpoint()
into one function, renamed isc_http_endpoint().
- moved isc_nm_http_connect_send_request() into doh_test.c as a helper
function; remove it from the public API.
- renamed isc_http2 and isc_nm_http2 types and functions to just isc_http
and isc_nm_http, for consistency with other existing names.
- shortened a number of long names.
- the caller is now responsible for determining the peer address.
in isc_nm_httpconnect(); this eliminates the need to parse the URI
and the dependency on an external resolver.
- the caller is also now responsible for creating the SSL client context,
for consistency with isc_nm_tlsdnsconnect().
- added setter functions for HTTP/2 ALPN. instead of setting up ALPN in
isc_tlsctx_createclient(), we now have a function
isc_tlsctx_enable_http2client_alpn() that can be run from
isc_nm_httpconnect().
- refactored isc_nm_httprequest() into separate read and send functions.
isc_nm_send() or isc_nm_read() is called on an http socket, it will
be stored until a corresponding isc_nm_read() or _send() arrives; when
we have both halves of the pair the HTTP request will be initiated.
- isc_nm_httprequest() is renamed isc__nm_http_request() for use as an
internal helper function by the DoH unit test. (eventually doh_test
should be rewritten to use read and send, and this function should
be removed.)
- added implementations of isc__nm_tls_settimeout() and
isc__nm_http_settimeout().
- increased NGHTTP2 header block length for client connections to 128K.
- use isc_mem_t for internal memory allocations inside nghttp2, to
help track memory leaks.
- send "Cache-Control" header in requests and responses. (note:
currently we try to bypass HTTP caching proxies, but ideally we should
interact with them: https://tools.ietf.org/html/rfc8484#section-5.1)
2021-02-03 19:59:49 -05:00
|
|
|
dns_http_mode_t
|
2023-05-30 10:32:02 -04:00
|
|
|
dns_transport_get_mode(const dns_transport_t *transport) {
|
2021-01-14 06:51:25 -05:00
|
|
|
REQUIRE(VALID_TRANSPORT(transport));
|
|
|
|
|
|
|
|
|
|
return transport->doh.mode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dns_transport_t *
|
|
|
|
|
dns_transport_new(const dns_name_t *name, dns_transport_type_t type,
|
|
|
|
|
dns_transport_list_t *list) {
|
|
|
|
|
dns_transport_t *transport = isc_mem_get(list->mctx,
|
|
|
|
|
sizeof(*transport));
|
|
|
|
|
*transport = (dns_transport_t){ .type = type };
|
|
|
|
|
isc_refcount_init(&transport->references, 1);
|
|
|
|
|
isc_mem_attach(list->mctx, &transport->mctx);
|
|
|
|
|
transport->magic = TRANSPORT_MAGIC;
|
|
|
|
|
|
|
|
|
|
list_add(list, name, type, transport);
|
|
|
|
|
|
|
|
|
|
return transport;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
dns_transport_set_certfile(dns_transport_t *transport, const char *certfile) {
|
|
|
|
|
REQUIRE(VALID_TRANSPORT(transport));
|
|
|
|
|
REQUIRE(transport->type == DNS_TRANSPORT_TLS ||
|
refactor outgoing HTTP connection support
- style, cleanup, and removal of unnecessary code.
- combined isc_nm_http_add_endpoint() and isc_nm_http_add_doh_endpoint()
into one function, renamed isc_http_endpoint().
- moved isc_nm_http_connect_send_request() into doh_test.c as a helper
function; remove it from the public API.
- renamed isc_http2 and isc_nm_http2 types and functions to just isc_http
and isc_nm_http, for consistency with other existing names.
- shortened a number of long names.
- the caller is now responsible for determining the peer address.
in isc_nm_httpconnect(); this eliminates the need to parse the URI
and the dependency on an external resolver.
- the caller is also now responsible for creating the SSL client context,
for consistency with isc_nm_tlsdnsconnect().
- added setter functions for HTTP/2 ALPN. instead of setting up ALPN in
isc_tlsctx_createclient(), we now have a function
isc_tlsctx_enable_http2client_alpn() that can be run from
isc_nm_httpconnect().
- refactored isc_nm_httprequest() into separate read and send functions.
isc_nm_send() or isc_nm_read() is called on an http socket, it will
be stored until a corresponding isc_nm_read() or _send() arrives; when
we have both halves of the pair the HTTP request will be initiated.
- isc_nm_httprequest() is renamed isc__nm_http_request() for use as an
internal helper function by the DoH unit test. (eventually doh_test
should be rewritten to use read and send, and this function should
be removed.)
- added implementations of isc__nm_tls_settimeout() and
isc__nm_http_settimeout().
- increased NGHTTP2 header block length for client connections to 128K.
- use isc_mem_t for internal memory allocations inside nghttp2, to
help track memory leaks.
- send "Cache-Control" header in requests and responses. (note:
currently we try to bypass HTTP caching proxies, but ideally we should
interact with them: https://tools.ietf.org/html/rfc8484#section-5.1)
2021-02-03 19:59:49 -05:00
|
|
|
transport->type == DNS_TRANSPORT_HTTP);
|
2021-01-14 06:51:25 -05:00
|
|
|
|
2021-11-29 16:09:51 -05:00
|
|
|
if (transport->tls.certfile != NULL) {
|
|
|
|
|
isc_mem_free(transport->mctx, transport->tls.certfile);
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-14 06:51:25 -05:00
|
|
|
if (certfile != NULL) {
|
|
|
|
|
transport->tls.certfile = isc_mem_strdup(transport->mctx,
|
|
|
|
|
certfile);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
dns_transport_set_keyfile(dns_transport_t *transport, const char *keyfile) {
|
|
|
|
|
REQUIRE(VALID_TRANSPORT(transport));
|
|
|
|
|
REQUIRE(transport->type == DNS_TRANSPORT_TLS ||
|
refactor outgoing HTTP connection support
- style, cleanup, and removal of unnecessary code.
- combined isc_nm_http_add_endpoint() and isc_nm_http_add_doh_endpoint()
into one function, renamed isc_http_endpoint().
- moved isc_nm_http_connect_send_request() into doh_test.c as a helper
function; remove it from the public API.
- renamed isc_http2 and isc_nm_http2 types and functions to just isc_http
and isc_nm_http, for consistency with other existing names.
- shortened a number of long names.
- the caller is now responsible for determining the peer address.
in isc_nm_httpconnect(); this eliminates the need to parse the URI
and the dependency on an external resolver.
- the caller is also now responsible for creating the SSL client context,
for consistency with isc_nm_tlsdnsconnect().
- added setter functions for HTTP/2 ALPN. instead of setting up ALPN in
isc_tlsctx_createclient(), we now have a function
isc_tlsctx_enable_http2client_alpn() that can be run from
isc_nm_httpconnect().
- refactored isc_nm_httprequest() into separate read and send functions.
isc_nm_send() or isc_nm_read() is called on an http socket, it will
be stored until a corresponding isc_nm_read() or _send() arrives; when
we have both halves of the pair the HTTP request will be initiated.
- isc_nm_httprequest() is renamed isc__nm_http_request() for use as an
internal helper function by the DoH unit test. (eventually doh_test
should be rewritten to use read and send, and this function should
be removed.)
- added implementations of isc__nm_tls_settimeout() and
isc__nm_http_settimeout().
- increased NGHTTP2 header block length for client connections to 128K.
- use isc_mem_t for internal memory allocations inside nghttp2, to
help track memory leaks.
- send "Cache-Control" header in requests and responses. (note:
currently we try to bypass HTTP caching proxies, but ideally we should
interact with them: https://tools.ietf.org/html/rfc8484#section-5.1)
2021-02-03 19:59:49 -05:00
|
|
|
transport->type == DNS_TRANSPORT_HTTP);
|
2021-01-14 06:51:25 -05:00
|
|
|
|
2021-11-29 16:09:51 -05:00
|
|
|
if (transport->tls.keyfile != NULL) {
|
|
|
|
|
isc_mem_free(transport->mctx, transport->tls.keyfile);
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-14 06:51:25 -05:00
|
|
|
if (keyfile != NULL) {
|
|
|
|
|
transport->tls.keyfile = isc_mem_strdup(transport->mctx,
|
|
|
|
|
keyfile);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
dns_transport_set_cafile(dns_transport_t *transport, const char *cafile) {
|
|
|
|
|
REQUIRE(VALID_TRANSPORT(transport));
|
|
|
|
|
REQUIRE(transport->type == DNS_TRANSPORT_TLS ||
|
refactor outgoing HTTP connection support
- style, cleanup, and removal of unnecessary code.
- combined isc_nm_http_add_endpoint() and isc_nm_http_add_doh_endpoint()
into one function, renamed isc_http_endpoint().
- moved isc_nm_http_connect_send_request() into doh_test.c as a helper
function; remove it from the public API.
- renamed isc_http2 and isc_nm_http2 types and functions to just isc_http
and isc_nm_http, for consistency with other existing names.
- shortened a number of long names.
- the caller is now responsible for determining the peer address.
in isc_nm_httpconnect(); this eliminates the need to parse the URI
and the dependency on an external resolver.
- the caller is also now responsible for creating the SSL client context,
for consistency with isc_nm_tlsdnsconnect().
- added setter functions for HTTP/2 ALPN. instead of setting up ALPN in
isc_tlsctx_createclient(), we now have a function
isc_tlsctx_enable_http2client_alpn() that can be run from
isc_nm_httpconnect().
- refactored isc_nm_httprequest() into separate read and send functions.
isc_nm_send() or isc_nm_read() is called on an http socket, it will
be stored until a corresponding isc_nm_read() or _send() arrives; when
we have both halves of the pair the HTTP request will be initiated.
- isc_nm_httprequest() is renamed isc__nm_http_request() for use as an
internal helper function by the DoH unit test. (eventually doh_test
should be rewritten to use read and send, and this function should
be removed.)
- added implementations of isc__nm_tls_settimeout() and
isc__nm_http_settimeout().
- increased NGHTTP2 header block length for client connections to 128K.
- use isc_mem_t for internal memory allocations inside nghttp2, to
help track memory leaks.
- send "Cache-Control" header in requests and responses. (note:
currently we try to bypass HTTP caching proxies, but ideally we should
interact with them: https://tools.ietf.org/html/rfc8484#section-5.1)
2021-02-03 19:59:49 -05:00
|
|
|
transport->type == DNS_TRANSPORT_HTTP);
|
2021-01-14 06:51:25 -05:00
|
|
|
|
2021-11-29 16:09:51 -05:00
|
|
|
if (transport->tls.cafile != NULL) {
|
|
|
|
|
isc_mem_free(transport->mctx, transport->tls.cafile);
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-14 06:51:25 -05:00
|
|
|
if (cafile != NULL) {
|
|
|
|
|
transport->tls.cafile = isc_mem_strdup(transport->mctx, cafile);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2022-05-03 09:51:33 -04:00
|
|
|
dns_transport_set_remote_hostname(dns_transport_t *transport,
|
|
|
|
|
const char *hostname) {
|
2021-01-14 06:51:25 -05:00
|
|
|
REQUIRE(VALID_TRANSPORT(transport));
|
|
|
|
|
REQUIRE(transport->type == DNS_TRANSPORT_TLS ||
|
refactor outgoing HTTP connection support
- style, cleanup, and removal of unnecessary code.
- combined isc_nm_http_add_endpoint() and isc_nm_http_add_doh_endpoint()
into one function, renamed isc_http_endpoint().
- moved isc_nm_http_connect_send_request() into doh_test.c as a helper
function; remove it from the public API.
- renamed isc_http2 and isc_nm_http2 types and functions to just isc_http
and isc_nm_http, for consistency with other existing names.
- shortened a number of long names.
- the caller is now responsible for determining the peer address.
in isc_nm_httpconnect(); this eliminates the need to parse the URI
and the dependency on an external resolver.
- the caller is also now responsible for creating the SSL client context,
for consistency with isc_nm_tlsdnsconnect().
- added setter functions for HTTP/2 ALPN. instead of setting up ALPN in
isc_tlsctx_createclient(), we now have a function
isc_tlsctx_enable_http2client_alpn() that can be run from
isc_nm_httpconnect().
- refactored isc_nm_httprequest() into separate read and send functions.
isc_nm_send() or isc_nm_read() is called on an http socket, it will
be stored until a corresponding isc_nm_read() or _send() arrives; when
we have both halves of the pair the HTTP request will be initiated.
- isc_nm_httprequest() is renamed isc__nm_http_request() for use as an
internal helper function by the DoH unit test. (eventually doh_test
should be rewritten to use read and send, and this function should
be removed.)
- added implementations of isc__nm_tls_settimeout() and
isc__nm_http_settimeout().
- increased NGHTTP2 header block length for client connections to 128K.
- use isc_mem_t for internal memory allocations inside nghttp2, to
help track memory leaks.
- send "Cache-Control" header in requests and responses. (note:
currently we try to bypass HTTP caching proxies, but ideally we should
interact with them: https://tools.ietf.org/html/rfc8484#section-5.1)
2021-02-03 19:59:49 -05:00
|
|
|
transport->type == DNS_TRANSPORT_HTTP);
|
2021-01-14 06:51:25 -05:00
|
|
|
|
2022-05-03 09:51:33 -04:00
|
|
|
if (transport->tls.remote_hostname != NULL) {
|
|
|
|
|
isc_mem_free(transport->mctx, transport->tls.remote_hostname);
|
2021-11-29 16:09:51 -05:00
|
|
|
}
|
|
|
|
|
|
2021-01-14 06:51:25 -05:00
|
|
|
if (hostname != NULL) {
|
2022-05-03 09:51:33 -04:00
|
|
|
transport->tls.remote_hostname = isc_mem_strdup(transport->mctx,
|
|
|
|
|
hostname);
|
2021-01-14 06:51:25 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
dns_transport_set_endpoint(dns_transport_t *transport, const char *endpoint) {
|
|
|
|
|
REQUIRE(VALID_TRANSPORT(transport));
|
refactor outgoing HTTP connection support
- style, cleanup, and removal of unnecessary code.
- combined isc_nm_http_add_endpoint() and isc_nm_http_add_doh_endpoint()
into one function, renamed isc_http_endpoint().
- moved isc_nm_http_connect_send_request() into doh_test.c as a helper
function; remove it from the public API.
- renamed isc_http2 and isc_nm_http2 types and functions to just isc_http
and isc_nm_http, for consistency with other existing names.
- shortened a number of long names.
- the caller is now responsible for determining the peer address.
in isc_nm_httpconnect(); this eliminates the need to parse the URI
and the dependency on an external resolver.
- the caller is also now responsible for creating the SSL client context,
for consistency with isc_nm_tlsdnsconnect().
- added setter functions for HTTP/2 ALPN. instead of setting up ALPN in
isc_tlsctx_createclient(), we now have a function
isc_tlsctx_enable_http2client_alpn() that can be run from
isc_nm_httpconnect().
- refactored isc_nm_httprequest() into separate read and send functions.
isc_nm_send() or isc_nm_read() is called on an http socket, it will
be stored until a corresponding isc_nm_read() or _send() arrives; when
we have both halves of the pair the HTTP request will be initiated.
- isc_nm_httprequest() is renamed isc__nm_http_request() for use as an
internal helper function by the DoH unit test. (eventually doh_test
should be rewritten to use read and send, and this function should
be removed.)
- added implementations of isc__nm_tls_settimeout() and
isc__nm_http_settimeout().
- increased NGHTTP2 header block length for client connections to 128K.
- use isc_mem_t for internal memory allocations inside nghttp2, to
help track memory leaks.
- send "Cache-Control" header in requests and responses. (note:
currently we try to bypass HTTP caching proxies, but ideally we should
interact with them: https://tools.ietf.org/html/rfc8484#section-5.1)
2021-02-03 19:59:49 -05:00
|
|
|
REQUIRE(transport->type == DNS_TRANSPORT_HTTP);
|
2021-01-14 06:51:25 -05:00
|
|
|
|
2021-11-29 16:09:51 -05:00
|
|
|
if (transport->doh.endpoint != NULL) {
|
|
|
|
|
isc_mem_free(transport->mctx, transport->doh.endpoint);
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-14 06:51:25 -05:00
|
|
|
if (endpoint != NULL) {
|
|
|
|
|
transport->doh.endpoint = isc_mem_strdup(transport->mctx,
|
|
|
|
|
endpoint);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
refactor outgoing HTTP connection support
- style, cleanup, and removal of unnecessary code.
- combined isc_nm_http_add_endpoint() and isc_nm_http_add_doh_endpoint()
into one function, renamed isc_http_endpoint().
- moved isc_nm_http_connect_send_request() into doh_test.c as a helper
function; remove it from the public API.
- renamed isc_http2 and isc_nm_http2 types and functions to just isc_http
and isc_nm_http, for consistency with other existing names.
- shortened a number of long names.
- the caller is now responsible for determining the peer address.
in isc_nm_httpconnect(); this eliminates the need to parse the URI
and the dependency on an external resolver.
- the caller is also now responsible for creating the SSL client context,
for consistency with isc_nm_tlsdnsconnect().
- added setter functions for HTTP/2 ALPN. instead of setting up ALPN in
isc_tlsctx_createclient(), we now have a function
isc_tlsctx_enable_http2client_alpn() that can be run from
isc_nm_httpconnect().
- refactored isc_nm_httprequest() into separate read and send functions.
isc_nm_send() or isc_nm_read() is called on an http socket, it will
be stored until a corresponding isc_nm_read() or _send() arrives; when
we have both halves of the pair the HTTP request will be initiated.
- isc_nm_httprequest() is renamed isc__nm_http_request() for use as an
internal helper function by the DoH unit test. (eventually doh_test
should be rewritten to use read and send, and this function should
be removed.)
- added implementations of isc__nm_tls_settimeout() and
isc__nm_http_settimeout().
- increased NGHTTP2 header block length for client connections to 128K.
- use isc_mem_t for internal memory allocations inside nghttp2, to
help track memory leaks.
- send "Cache-Control" header in requests and responses. (note:
currently we try to bypass HTTP caching proxies, but ideally we should
interact with them: https://tools.ietf.org/html/rfc8484#section-5.1)
2021-02-03 19:59:49 -05:00
|
|
|
dns_transport_set_mode(dns_transport_t *transport, dns_http_mode_t mode) {
|
2021-01-14 06:51:25 -05:00
|
|
|
REQUIRE(VALID_TRANSPORT(transport));
|
refactor outgoing HTTP connection support
- style, cleanup, and removal of unnecessary code.
- combined isc_nm_http_add_endpoint() and isc_nm_http_add_doh_endpoint()
into one function, renamed isc_http_endpoint().
- moved isc_nm_http_connect_send_request() into doh_test.c as a helper
function; remove it from the public API.
- renamed isc_http2 and isc_nm_http2 types and functions to just isc_http
and isc_nm_http, for consistency with other existing names.
- shortened a number of long names.
- the caller is now responsible for determining the peer address.
in isc_nm_httpconnect(); this eliminates the need to parse the URI
and the dependency on an external resolver.
- the caller is also now responsible for creating the SSL client context,
for consistency with isc_nm_tlsdnsconnect().
- added setter functions for HTTP/2 ALPN. instead of setting up ALPN in
isc_tlsctx_createclient(), we now have a function
isc_tlsctx_enable_http2client_alpn() that can be run from
isc_nm_httpconnect().
- refactored isc_nm_httprequest() into separate read and send functions.
isc_nm_send() or isc_nm_read() is called on an http socket, it will
be stored until a corresponding isc_nm_read() or _send() arrives; when
we have both halves of the pair the HTTP request will be initiated.
- isc_nm_httprequest() is renamed isc__nm_http_request() for use as an
internal helper function by the DoH unit test. (eventually doh_test
should be rewritten to use read and send, and this function should
be removed.)
- added implementations of isc__nm_tls_settimeout() and
isc__nm_http_settimeout().
- increased NGHTTP2 header block length for client connections to 128K.
- use isc_mem_t for internal memory allocations inside nghttp2, to
help track memory leaks.
- send "Cache-Control" header in requests and responses. (note:
currently we try to bypass HTTP caching proxies, but ideally we should
interact with them: https://tools.ietf.org/html/rfc8484#section-5.1)
2021-02-03 19:59:49 -05:00
|
|
|
REQUIRE(transport->type == DNS_TRANSPORT_HTTP);
|
2021-01-14 06:51:25 -05:00
|
|
|
|
|
|
|
|
transport->doh.mode = mode;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-29 16:09:51 -05:00
|
|
|
void
|
|
|
|
|
dns_transport_set_tls_versions(dns_transport_t *transport,
|
|
|
|
|
const uint32_t tls_versions) {
|
|
|
|
|
REQUIRE(VALID_TRANSPORT(transport));
|
|
|
|
|
REQUIRE(transport->type == DNS_TRANSPORT_HTTP ||
|
|
|
|
|
transport->type == DNS_TRANSPORT_TLS);
|
|
|
|
|
|
|
|
|
|
transport->tls.protocol_versions = tls_versions;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t
|
|
|
|
|
dns_transport_get_tls_versions(const dns_transport_t *transport) {
|
|
|
|
|
REQUIRE(VALID_TRANSPORT(transport));
|
|
|
|
|
|
|
|
|
|
return transport->tls.protocol_versions;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
dns_transport_set_ciphers(dns_transport_t *transport, const char *ciphers) {
|
|
|
|
|
REQUIRE(VALID_TRANSPORT(transport));
|
|
|
|
|
REQUIRE(transport->type == DNS_TRANSPORT_TLS ||
|
|
|
|
|
transport->type == DNS_TRANSPORT_HTTP);
|
|
|
|
|
|
|
|
|
|
if (transport->tls.ciphers != NULL) {
|
|
|
|
|
isc_mem_free(transport->mctx, transport->tls.ciphers);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ciphers != NULL) {
|
|
|
|
|
transport->tls.ciphers = isc_mem_strdup(transport->mctx,
|
|
|
|
|
ciphers);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-23 09:08:41 -05:00
|
|
|
void
|
|
|
|
|
dns_transport_set_tlsname(dns_transport_t *transport, const char *tlsname) {
|
|
|
|
|
REQUIRE(VALID_TRANSPORT(transport));
|
|
|
|
|
REQUIRE(transport->type == DNS_TRANSPORT_TLS ||
|
|
|
|
|
transport->type == DNS_TRANSPORT_HTTP);
|
|
|
|
|
|
|
|
|
|
if (transport->tls.tlsname != NULL) {
|
|
|
|
|
isc_mem_free(transport->mctx, transport->tls.tlsname);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (tlsname != NULL) {
|
|
|
|
|
transport->tls.tlsname = isc_mem_strdup(transport->mctx,
|
|
|
|
|
tlsname);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-29 16:09:51 -05:00
|
|
|
char *
|
2023-05-30 10:32:02 -04:00
|
|
|
dns_transport_get_ciphers(const dns_transport_t *transport) {
|
2021-11-29 16:09:51 -05:00
|
|
|
REQUIRE(VALID_TRANSPORT(transport));
|
|
|
|
|
|
|
|
|
|
return transport->tls.ciphers;
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-30 15:26:53 -05:00
|
|
|
void
|
|
|
|
|
dns_transport_set_cipher_suites(dns_transport_t *transport,
|
|
|
|
|
const char *cipher_suites) {
|
|
|
|
|
REQUIRE(VALID_TRANSPORT(transport));
|
|
|
|
|
REQUIRE(transport->type == DNS_TRANSPORT_TLS ||
|
|
|
|
|
transport->type == DNS_TRANSPORT_HTTP);
|
|
|
|
|
|
|
|
|
|
if (transport->tls.cipher_suites != NULL) {
|
|
|
|
|
isc_mem_free(transport->mctx, transport->tls.cipher_suites);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cipher_suites != NULL) {
|
|
|
|
|
transport->tls.cipher_suites = isc_mem_strdup(transport->mctx,
|
|
|
|
|
cipher_suites);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
dns_transport_get_cipher_suites(const dns_transport_t *transport) {
|
|
|
|
|
REQUIRE(VALID_TRANSPORT(transport));
|
|
|
|
|
|
|
|
|
|
return transport->tls.cipher_suites;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-23 09:08:41 -05:00
|
|
|
char *
|
2023-05-30 10:32:02 -04:00
|
|
|
dns_transport_get_tlsname(const dns_transport_t *transport) {
|
2021-12-23 09:08:41 -05:00
|
|
|
REQUIRE(VALID_TRANSPORT(transport));
|
|
|
|
|
|
|
|
|
|
return transport->tls.tlsname;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-29 16:09:51 -05:00
|
|
|
void
|
|
|
|
|
dns_transport_set_prefer_server_ciphers(dns_transport_t *transport,
|
|
|
|
|
const bool prefer) {
|
|
|
|
|
REQUIRE(VALID_TRANSPORT(transport));
|
|
|
|
|
REQUIRE(transport->type == DNS_TRANSPORT_TLS ||
|
|
|
|
|
transport->type == DNS_TRANSPORT_HTTP);
|
|
|
|
|
|
|
|
|
|
transport->tls.prefer_server_ciphers = prefer ? ter_true : ter_false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
dns_transport_get_prefer_server_ciphers(const dns_transport_t *transport,
|
|
|
|
|
bool *preferp) {
|
|
|
|
|
REQUIRE(VALID_TRANSPORT(transport));
|
|
|
|
|
REQUIRE(preferp != NULL);
|
|
|
|
|
if (transport->tls.prefer_server_ciphers == ter_none) {
|
|
|
|
|
return false;
|
|
|
|
|
} else if (transport->tls.prefer_server_ciphers == ter_true) {
|
|
|
|
|
*preferp = true;
|
|
|
|
|
return true;
|
|
|
|
|
} else if (transport->tls.prefer_server_ciphers == ter_false) {
|
|
|
|
|
*preferp = false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-11 06:50:17 -04:00
|
|
|
UNREACHABLE();
|
2024-10-17 16:22:48 -04:00
|
|
|
return false;
|
2021-11-29 16:09:51 -05:00
|
|
|
}
|
|
|
|
|
|
2022-09-21 04:20:22 -04:00
|
|
|
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);
|
|
|
|
|
|
2024-10-17 16:22:48 -04:00
|
|
|
return transport->tls.always_verify_remote;
|
2022-09-21 04:20:22 -04:00
|
|
|
}
|
|
|
|
|
|
2022-09-19 06:24:20 -04:00
|
|
|
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;
|
2023-11-30 15:26:53 -05:00
|
|
|
const char *cipher_suites = NULL;
|
2022-09-19 06:24:20 -04:00
|
|
|
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);
|
2022-09-21 04:20:22 -04:00
|
|
|
const bool always_verify_remote =
|
|
|
|
|
dns_transport_get_always_verify_remote(transport);
|
2022-09-19 06:24:20 -04:00
|
|
|
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);
|
|
|
|
|
}
|
2023-11-30 15:26:53 -05:00
|
|
|
cipher_suites = dns_transport_get_cipher_suites(transport);
|
|
|
|
|
if (cipher_suites != NULL) {
|
|
|
|
|
isc_tlsctx_set_cipher_suites(tlsctx, cipher_suites);
|
|
|
|
|
}
|
2022-09-19 06:24:20 -04:00
|
|
|
|
|
|
|
|
if (dns_transport_get_prefer_server_ciphers(
|
2022-11-02 14:33:14 -04:00
|
|
|
transport, &prefer_server_ciphers))
|
|
|
|
|
{
|
2022-09-19 06:24:20 -04:00
|
|
|
isc_tlsctx_prefer_server_ciphers(tlsctx,
|
|
|
|
|
prefer_server_ciphers);
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-21 04:20:22 -04:00
|
|
|
if (always_verify_remote || hostname != NULL || ca_file != NULL)
|
|
|
|
|
{
|
2022-09-19 06:24:20 -04:00
|
|
|
/*
|
|
|
|
|
* 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) {
|
|
|
|
|
/*
|
2022-09-21 04:20:22 -04:00
|
|
|
* If hostname is not specified, then use the
|
|
|
|
|
* peer IP address for validation.
|
2022-09-19 06:24:20 -04:00
|
|
|
*/
|
|
|
|
|
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);
|
|
|
|
|
|
2022-12-22 13:04:22 -05:00
|
|
|
isc_tlsctx_client_session_cache_create(
|
2022-09-19 06:24:20 -04:00
|
|
|
mctx, tlsctx,
|
2022-12-22 13:04:22 -05:00
|
|
|
ISC_TLSCTX_CLIENT_SESSION_CACHE_DEFAULT_SIZE,
|
|
|
|
|
&sess_cache);
|
2022-09-19 06:24:20 -04:00
|
|
|
|
|
|
|
|
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);
|
2023-12-04 07:28:28 -05:00
|
|
|
/*
|
|
|
|
|
* 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);
|
|
|
|
|
}
|
2022-09-19 06:24:20 -04:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-14 06:51:25 -05:00
|
|
|
static void
|
|
|
|
|
transport_destroy(dns_transport_t *transport) {
|
|
|
|
|
isc_refcount_destroy(&transport->references);
|
|
|
|
|
transport->magic = 0;
|
|
|
|
|
|
|
|
|
|
if (transport->doh.endpoint != NULL) {
|
|
|
|
|
isc_mem_free(transport->mctx, transport->doh.endpoint);
|
|
|
|
|
}
|
2022-05-03 09:51:33 -04:00
|
|
|
if (transport->tls.remote_hostname != NULL) {
|
|
|
|
|
isc_mem_free(transport->mctx, transport->tls.remote_hostname);
|
2021-01-14 06:51:25 -05:00
|
|
|
}
|
|
|
|
|
if (transport->tls.cafile != NULL) {
|
|
|
|
|
isc_mem_free(transport->mctx, transport->tls.cafile);
|
|
|
|
|
}
|
|
|
|
|
if (transport->tls.keyfile != NULL) {
|
|
|
|
|
isc_mem_free(transport->mctx, transport->tls.keyfile);
|
|
|
|
|
}
|
|
|
|
|
if (transport->tls.certfile != NULL) {
|
|
|
|
|
isc_mem_free(transport->mctx, transport->tls.certfile);
|
|
|
|
|
}
|
2021-11-29 16:09:51 -05:00
|
|
|
if (transport->tls.ciphers != NULL) {
|
|
|
|
|
isc_mem_free(transport->mctx, transport->tls.ciphers);
|
|
|
|
|
}
|
2023-11-30 15:26:53 -05:00
|
|
|
if (transport->tls.cipher_suites != NULL) {
|
|
|
|
|
isc_mem_free(transport->mctx, transport->tls.cipher_suites);
|
|
|
|
|
}
|
2021-01-14 06:51:25 -05:00
|
|
|
|
2021-12-23 09:08:41 -05:00
|
|
|
if (transport->tls.tlsname != NULL) {
|
|
|
|
|
isc_mem_free(transport->mctx, transport->tls.tlsname);
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-14 06:51:25 -05:00
|
|
|
isc_mem_putanddetach(&transport->mctx, transport, sizeof(*transport));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
dns_transport_attach(dns_transport_t *source, dns_transport_t **targetp) {
|
|
|
|
|
REQUIRE(source != NULL);
|
|
|
|
|
REQUIRE(targetp != NULL && *targetp == NULL);
|
|
|
|
|
|
|
|
|
|
isc_refcount_increment(&source->references);
|
|
|
|
|
|
|
|
|
|
*targetp = source;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
dns_transport_detach(dns_transport_t **transportp) {
|
|
|
|
|
dns_transport_t *transport = NULL;
|
|
|
|
|
|
|
|
|
|
REQUIRE(transportp != NULL);
|
|
|
|
|
REQUIRE(VALID_TRANSPORT(*transportp));
|
|
|
|
|
|
|
|
|
|
transport = *transportp;
|
|
|
|
|
*transportp = NULL;
|
|
|
|
|
|
|
|
|
|
if (isc_refcount_decrement(&transport->references) == 1) {
|
|
|
|
|
transport_destroy(transport);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dns_transport_t *
|
|
|
|
|
dns_transport_find(const dns_transport_type_t type, const dns_name_t *name,
|
|
|
|
|
dns_transport_list_t *list) {
|
|
|
|
|
isc_result_t result;
|
|
|
|
|
dns_transport_t *transport = NULL;
|
2023-08-16 00:04:54 -04:00
|
|
|
isc_hashmap_t *hm = NULL;
|
2021-01-14 06:51:25 -05:00
|
|
|
|
|
|
|
|
REQUIRE(VALID_TRANSPORT_LIST(list));
|
|
|
|
|
REQUIRE(list->transports[type] != NULL);
|
|
|
|
|
|
2023-08-16 00:04:54 -04:00
|
|
|
hm = list->transports[type];
|
2021-01-14 06:51:25 -05:00
|
|
|
|
|
|
|
|
RWLOCK(&list->lock, isc_rwlocktype_read);
|
2023-08-28 04:08:59 -04:00
|
|
|
result = isc_hashmap_find(hm, dns_name_hash(name), transport_match,
|
|
|
|
|
name, (void **)&transport);
|
2021-01-14 06:51:25 -05:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
|
isc_refcount_increment(&transport->references);
|
|
|
|
|
}
|
|
|
|
|
RWUNLOCK(&list->lock, isc_rwlocktype_read);
|
|
|
|
|
|
|
|
|
|
return transport;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dns_transport_list_t *
|
|
|
|
|
dns_transport_list_new(isc_mem_t *mctx) {
|
|
|
|
|
dns_transport_list_t *list = isc_mem_get(mctx, sizeof(*list));
|
|
|
|
|
|
|
|
|
|
*list = (dns_transport_list_t){ 0 };
|
|
|
|
|
|
Add the reader-writer synchronization with modified C-RW-WP
This changes the internal isc_rwlock implementation to:
Irina Calciu, Dave Dice, Yossi Lev, Victor Luchangco, Virendra
J. Marathe, and Nir Shavit. 2013. NUMA-aware reader-writer locks.
SIGPLAN Not. 48, 8 (August 2013), 157–166.
DOI:https://doi.org/10.1145/2517327.24425
(The full article available from:
http://mcg.cs.tau.ac.il/papers/ppopp2013-rwlocks.pdf)
The implementation is based on the The Writer-Preference Lock (C-RW-WP)
variant (see the 3.4 section of the paper for the rationale).
The implemented algorithm has been modified for simplicity and for usage
patterns in rbtdb.c.
The changes compared to the original algorithm:
* We haven't implemented the cohort locks because that would require a
knowledge of NUMA nodes, instead a simple atomic_bool is used as
synchronization point for writer lock.
* The per-thread reader counters are not being used - this would
require the internal thread id (isc_tid_v) to be always initialized,
even in the utilities; the change has a slight performance penalty,
so we might revisit this change in the future. However, this change
also saves a lot of memory, because cache-line aligned counters were
used, so on 32-core machine, the rwlock would be 4096+ bytes big.
* The readers use a writer_barrier that will raise after a while when
readers lock can't be acquired to prevent readers starvation.
* Separate ingress and egress readers counters queues to reduce both
inter and intra-thread contention.
2021-03-24 12:52:56 -04:00
|
|
|
isc_rwlock_init(&list->lock);
|
2021-01-14 06:51:25 -05:00
|
|
|
|
|
|
|
|
isc_mem_attach(mctx, &list->mctx);
|
|
|
|
|
isc_refcount_init(&list->references, 1);
|
|
|
|
|
|
|
|
|
|
list->magic = TRANSPORT_LIST_MAGIC;
|
|
|
|
|
|
|
|
|
|
for (size_t type = 0; type < DNS_TRANSPORT_COUNT; type++) {
|
2023-08-28 04:08:59 -04:00
|
|
|
isc_hashmap_create(list->mctx, 10, &list->transports[type]);
|
2021-01-14 06:51:25 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return list;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
dns_transport_list_attach(dns_transport_list_t *source,
|
|
|
|
|
dns_transport_list_t **targetp) {
|
|
|
|
|
REQUIRE(VALID_TRANSPORT_LIST(source));
|
|
|
|
|
REQUIRE(targetp != NULL && *targetp == NULL);
|
|
|
|
|
|
|
|
|
|
isc_refcount_increment(&source->references);
|
|
|
|
|
|
|
|
|
|
*targetp = source;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
transport_list_destroy(dns_transport_list_t *list) {
|
|
|
|
|
isc_refcount_destroy(&list->references);
|
|
|
|
|
list->magic = 0;
|
|
|
|
|
|
|
|
|
|
for (size_t type = 0; type < DNS_TRANSPORT_COUNT; type++) {
|
2023-08-16 00:04:54 -04:00
|
|
|
isc_result_t result;
|
|
|
|
|
isc_hashmap_iter_t *it = NULL;
|
|
|
|
|
|
|
|
|
|
if (list->transports[type] == NULL) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
isc_hashmap_iter_create(list->transports[type], &it);
|
|
|
|
|
for (result = isc_hashmap_iter_first(it);
|
|
|
|
|
result == ISC_R_SUCCESS;
|
|
|
|
|
result = isc_hashmap_iter_delcurrent_next(it))
|
|
|
|
|
{
|
|
|
|
|
dns_transport_t *transport = NULL;
|
|
|
|
|
isc_hashmap_iter_current(it, (void **)&transport);
|
|
|
|
|
dns_transport_detach(&transport);
|
2021-01-14 06:51:25 -05:00
|
|
|
}
|
2023-08-16 00:04:54 -04:00
|
|
|
isc_hashmap_iter_destroy(&it);
|
|
|
|
|
isc_hashmap_destroy(&list->transports[type]);
|
2021-01-14 06:51:25 -05:00
|
|
|
}
|
|
|
|
|
isc_rwlock_destroy(&list->lock);
|
|
|
|
|
isc_mem_putanddetach(&list->mctx, list, sizeof(*list));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
dns_transport_list_detach(dns_transport_list_t **listp) {
|
|
|
|
|
dns_transport_list_t *list = NULL;
|
|
|
|
|
|
|
|
|
|
REQUIRE(listp != NULL);
|
|
|
|
|
REQUIRE(VALID_TRANSPORT_LIST(*listp));
|
|
|
|
|
|
|
|
|
|
list = *listp;
|
|
|
|
|
*listp = NULL;
|
|
|
|
|
|
|
|
|
|
if (isc_refcount_decrement(&list->references) == 1) {
|
|
|
|
|
transport_list_destroy(list);
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-10-03 22:51:20 -04:00
|
|
|
|
|
|
|
|
const char *
|
|
|
|
|
dns_transport_totext(dns_transport_type_t type) {
|
|
|
|
|
switch (type) {
|
|
|
|
|
case DNS_TRANSPORT_UDP:
|
|
|
|
|
return "udp";
|
|
|
|
|
case DNS_TRANSPORT_TCP:
|
|
|
|
|
return "tcp";
|
|
|
|
|
case DNS_TRANSPORT_TLS:
|
|
|
|
|
return "tls";
|
|
|
|
|
case DNS_TRANSPORT_HTTP:
|
|
|
|
|
return "https";
|
|
|
|
|
default:
|
|
|
|
|
UNREACHABLE();
|
|
|
|
|
}
|
|
|
|
|
}
|