Resolver query forwarding to DoT-enabled upstream servers

Implement TLS transport usage in the resolver.

Use the configured TLS transport for the forwarders in the resolver.
This commit is contained in:
Aram Sargsyan 2022-12-08 14:18:22 +00:00
parent 3aa2d84880
commit 6ea05ac3fe
12 changed files with 96 additions and 27 deletions

View file

@ -41,6 +41,7 @@
#include <isc/string.h>
#include <isc/task.h>
#include <isc/timer.h>
#include <isc/tls.h>
#include <isc/util.h>
#include <dns/byaddr.h>
@ -85,6 +86,9 @@ static isc_nm_t *netmgr = NULL;
static isc_loopmgr_t *loopmgr = NULL;
static isc_taskmgr_t *taskmgr = NULL;
/* TLS */
static isc_tlsctx_cache_t *tlsctx_client_cache = NULL;
/* Configurables */
static char *server = NULL;
static const char *port = "53";
@ -1835,8 +1839,10 @@ main(int argc, char *argv[]) {
setup_logging(stderr);
/* Create client */
result = dns_client_create(mctx, loopmgr, taskmgr, netmgr, 0, &client,
srcaddr4, srcaddr6);
isc_tlsctx_cache_create(mctx, &tlsctx_client_cache);
result = dns_client_create(mctx, loopmgr, taskmgr, netmgr, 0,
tlsctx_client_cache, &client, srcaddr4,
srcaddr6);
if (result != ISC_R_SUCCESS) {
delv_log(ISC_LOG_ERROR, "dns_client_create: %s",
isc_result_totext(result));
@ -1869,6 +1875,9 @@ cleanup:
if (style != NULL) {
dns_master_styledestroy(&style, mctx);
}
if (tlsctx_client_cache != NULL) {
isc_tlsctx_cache_detach(&tlsctx_client_cache);
}
isc_log_destroy(&lctx);

View file

@ -4758,7 +4758,8 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
ndisp = 4 * ISC_MIN(named_g_udpdisp, MAX_UDP_DISPATCH);
CHECK(dns_view_createresolver(
view, named_g_loopmgr, named_g_taskmgr, ndisp, named_g_netmgr,
resopts, named_g_dispatchmgr, dispatch4, dispatch6));
resopts, named_g_server->tlsctx_client_cache,
named_g_dispatchmgr, dispatch4, dispatch6));
if (resstats == NULL) {
CHECK(isc_stats_create(mctx, &resstats,

View file

@ -2884,8 +2884,12 @@ authoritative and does not have the answer in its cache.
This specifies a list of IP addresses to which queries are forwarded. The
default is the empty list (no forwarding). Each address in the list can be
associated with an optional port number. A default port number can be set
for the entire list.
associated with an optional port number and a TLS transport. A default port
number and a TLS transport can be set for the entire list.
If a TLS configuration is specified, :iscman:`named` will use DNS-over-TLS
(DoT) connections when connecting to the specified IP address(es), using the
TLS configuration referenced by the :any:`tls` statement.
Forwarding can also be configured on a per-domain basis, allowing for
the global forwarding options to be overridden in a variety of ways.

View file

@ -49,6 +49,7 @@
#include <dns/rdatatype.h>
#include <dns/resolver.h>
#include <dns/stats.h>
#include <dns/transport.h>
#define DNS_ADB_MAGIC ISC_MAGIC('D', 'a', 'd', 'b')
#define DNS_ADB_VALID(x) ISC_MAGIC_VALID(x, DNS_ADB_MAGIC)
@ -1321,6 +1322,9 @@ free_adbaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **ainfo) {
ai->magic = 0;
if (ai->transport != NULL) {
dns_transport_detach(&ai->transport);
}
dns_adbentry_detach(&ai->entry);
isc_mem_put(adb->mctx, ai, sizeof(*ai));

View file

@ -204,9 +204,10 @@ getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr,
static isc_result_t
createview(isc_mem_t *mctx, dns_rdataclass_t rdclass, isc_loopmgr_t *loopmgr,
isc_taskmgr_t *taskmgr, isc_nm_t *nm, dns_dispatchmgr_t *dispatchmgr,
dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6,
dns_view_t **viewp) {
isc_taskmgr_t *taskmgr, isc_nm_t *nm,
isc_tlsctx_cache_t *tlsctx_client_cache,
dns_dispatchmgr_t *dispatchmgr, dns_dispatch_t *dispatchv4,
dns_dispatch_t *dispatchv6, dns_view_t **viewp) {
isc_result_t result;
dns_view_t *view = NULL;
@ -222,7 +223,8 @@ createview(isc_mem_t *mctx, dns_rdataclass_t rdclass, isc_loopmgr_t *loopmgr,
}
result = dns_view_createresolver(view, loopmgr, taskmgr, 1, nm, 0,
dispatchmgr, dispatchv4, dispatchv6);
tlsctx_client_cache, dispatchmgr,
dispatchv4, dispatchv6);
if (result != ISC_R_SUCCESS) {
goto cleanup_view;
}
@ -244,6 +246,7 @@ cleanup_view:
isc_result_t
dns_client_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr,
isc_taskmgr_t *taskmgr, isc_nm_t *nm, unsigned int options,
isc_tlsctx_cache_t *tlsctx_client_cache,
dns_client_t **clientp, const isc_sockaddr_t *localaddr4,
const isc_sockaddr_t *localaddr6) {
isc_result_t result;
@ -255,6 +258,7 @@ dns_client_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr,
REQUIRE(mctx != NULL);
REQUIRE(taskmgr != NULL);
REQUIRE(nm != NULL);
REQUIRE(tlsctx_client_cache != NULL);
REQUIRE(clientp != NULL && *clientp == NULL);
UNUSED(options);
@ -309,7 +313,8 @@ dns_client_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr,
/* Create the default view for class IN */
result = createview(mctx, dns_rdataclass_in, loopmgr, taskmgr, nm,
client->dispatchmgr, dispatchv4, dispatchv6, &view);
tlsctx_client_cache, client->dispatchmgr,
dispatchv4, dispatchv6, &view);
if (result != ISC_R_SUCCESS) {
goto cleanup_references;
}

View file

@ -204,8 +204,9 @@ struct dns_adbfind {
struct dns_adbaddrinfo {
unsigned int magic; /*%< private */
isc_sockaddr_t sockaddr; /*%< [rw] */
unsigned int srtt; /*%< [rw] microsecs */
isc_sockaddr_t sockaddr; /*%< [rw] */
unsigned int srtt; /*%< [rw] microsecs */
dns_transport_t *transport;
unsigned int flags; /*%< [rw] */
dns_adbentry_t *entry; /*%< private */

View file

@ -91,6 +91,7 @@ typedef struct dns_clientresevent {
isc_result_t
dns_client_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr,
isc_taskmgr_t *taskmgr, isc_nm_t *nm, unsigned int options,
isc_tlsctx_cache_t *tlsctx_client_cache,
dns_client_t **clientp, const isc_sockaddr_t *localaddr4,
const isc_sockaddr_t *localaddr6);
/*%<
@ -113,7 +114,7 @@ dns_client_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr,
*
*\li 'nm' is a valid network manager.
*
*\li 'timermgr' is a valid timer manager.
*\li 'tlsctx_client_cache' is a valid TLS context cache.
*
*\li clientp != NULL && *clientp == NULL.
*

View file

@ -52,6 +52,7 @@
#include <isc/lang.h>
#include <isc/refcount.h>
#include <isc/stats.h>
#include <isc/types.h>
#include <dns/fixedname.h>
#include <dns/types.h>
@ -171,9 +172,9 @@ typedef enum { dns_quotatype_zone = 0, dns_quotatype_server } dns_quotatype_t;
isc_result_t
dns_resolver_create(dns_view_t *view, isc_loopmgr_t *loopmgr,
isc_taskmgr_t *taskmgr, unsigned int ndisp, isc_nm_t *nm,
unsigned int options, dns_dispatchmgr_t *dispatchmgr,
dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6,
dns_resolver_t **resp);
unsigned int options, isc_tlsctx_cache_t *tlsctx_cache,
dns_dispatchmgr_t *dispatchmgr, dns_dispatch_t *dispatchv4,
dns_dispatch_t *dispatchv6, dns_resolver_t **resp);
/*%<
* Create a resolver.
@ -193,6 +194,10 @@ dns_resolver_create(dns_view_t *view, isc_loopmgr_t *loopmgr,
*
*\li 'nm' is a valid network manager.
*
*\li 'tlsctx_cache' != NULL.
*
*\li 'dispatchmgr' != NULL.
*
*\li 'dispatchv4' is a dispatch with an IPv4 UDP socket, or is NULL.
* If not NULL, 'ndisp' clones of it will be created by the resolver.
*

View file

@ -390,7 +390,8 @@ isc_result_t
dns_view_createresolver(dns_view_t *view, isc_loopmgr_t *loopmgr,
isc_taskmgr_t *taskmgr, unsigned int ndisp,
isc_nm_t *netmgr, unsigned int options,
dns_dispatchmgr_t *dispatchmgr,
isc_tlsctx_cache_t *tlsctx_cache,
dns_dispatchmgr_t *dispatchmgr,
dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6);
/*%<
* Create a resolver and address database for the view.
@ -402,7 +403,8 @@ dns_view_createresolver(dns_view_t *view, isc_loopmgr_t *loopmgr,
*\li 'view' does not have a resolver already.
*
*\li The requirements of dns_resolver_create() apply to 'taskmgr',
* 'ndisp', 'netmgr', 'options', 'dispatchv4', and 'dispatchv6'.
* 'ndisp', 'netmgr', 'options', 'tlsctx_cache', 'dispatchv4', and
* 'dispatchv6'.
*
* Returns:
*

View file

@ -548,6 +548,7 @@ struct dns_resolver {
dns_view_t *view;
bool frozen;
unsigned int options;
isc_tlsctx_cache_t *tlsctx_cache;
dns_dispatchmgr_t *dispatchmgr;
dns_dispatchset_t *dispatches4;
dns_dispatchset_t *dispatches6;
@ -2134,6 +2135,7 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
isc_sockaddr_t addr;
bool have_addr = false;
unsigned int srtt;
isc_tlsctx_cache_t *tlsctx_cache = NULL;
FCTXTRACE("query");
@ -2141,6 +2143,21 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
srtt = addrinfo->srtt;
if (addrinfo->transport != NULL) {
switch (dns_transport_get_type(addrinfo->transport)) {
case DNS_TRANSPORT_TLS:
options |= DNS_FETCHOPT_TCP;
tlsctx_cache = res->tlsctx_cache;
break;
case DNS_TRANSPORT_TCP:
case DNS_TRANSPORT_HTTP:
options |= DNS_FETCHOPT_TCP;
break;
default:
break;
}
}
/*
* Allow an additional second for the kernel to resend the SYN
* (or SYN without ECN in the case of stupid firewalls blocking
@ -2301,9 +2318,9 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
/* Set up the dispatch and set the query ID */
result = dns_dispatch_add(
query->dispatch, 0, isc_interval_ms(&fctx->interval),
&query->addrinfo->sockaddr, NULL, NULL, resquery_connected,
resquery_senddone, resquery_response, query, &query->id,
&query->dispentry);
&query->addrinfo->sockaddr, addrinfo->transport, tlsctx_cache,
resquery_connected, resquery_senddone, resquery_response, query,
&query->id, &query->dispentry);
if (result != ISC_R_SUCCESS) {
goto cleanup_udpfetch;
}
@ -3679,6 +3696,15 @@ fctx_getaddresses(fetchctx_t *fctx, bool badcache) {
if (result == ISC_R_SUCCESS) {
dns_adbaddrinfo_t *cur;
ai->flags |= FCTX_ADDRINFO_FORWARDER;
if (fwd->tlsname != NULL) {
result = dns_view_gettransport(
res->view, DNS_TRANSPORT_TLS,
fwd->tlsname, &ai->transport);
if (result != ISC_R_SUCCESS) {
dns_adb_freeaddrinfo(fctx->adb, &ai);
goto next;
}
}
cur = ISC_LIST_HEAD(fctx->forwaddrs);
while (cur != NULL && cur->srtt < ai->srtt) {
cur = ISC_LIST_NEXT(cur, publink);
@ -3690,6 +3716,7 @@ fctx_getaddresses(fetchctx_t *fctx, bool badcache) {
ISC_LIST_APPEND(fctx->forwaddrs, ai, publink);
}
}
next:
fwd = ISC_LIST_NEXT(fwd, link);
}
@ -10095,9 +10122,9 @@ spillattimer_countdown(void *arg) {
isc_result_t
dns_resolver_create(dns_view_t *view, isc_loopmgr_t *loopmgr,
isc_taskmgr_t *taskmgr, unsigned int ndisp, isc_nm_t *nm,
unsigned int options, dns_dispatchmgr_t *dispatchmgr,
dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6,
dns_resolver_t **resp) {
unsigned int options, isc_tlsctx_cache_t *tlsctx_cache,
dns_dispatchmgr_t *dispatchmgr, dns_dispatch_t *dispatchv4,
dns_dispatch_t *dispatchv6, dns_resolver_t **resp) {
isc_result_t result = ISC_R_SUCCESS;
char name[sizeof("res4294967295")];
dns_resolver_t *res = NULL;
@ -10109,6 +10136,7 @@ dns_resolver_create(dns_view_t *view, isc_loopmgr_t *loopmgr,
REQUIRE(DNS_VIEW_VALID(view));
REQUIRE(ndisp > 0);
REQUIRE(resp != NULL && *resp == NULL);
REQUIRE(tlsctx_cache != NULL);
REQUIRE(dispatchmgr != NULL);
REQUIRE(dispatchv4 != NULL || dispatchv6 != NULL);
@ -10122,6 +10150,7 @@ dns_resolver_create(dns_view_t *view, isc_loopmgr_t *loopmgr,
.taskmgr = taskmgr,
.dispatchmgr = dispatchmgr,
.options = options,
.tlsctx_cache = tlsctx_cache,
.spillatmin = 10,
.spillat = 10,
.spillatmax = 100,

View file

@ -655,6 +655,7 @@ isc_result_t
dns_view_createresolver(dns_view_t *view, isc_loopmgr_t *loopmgr,
isc_taskmgr_t *taskmgr, unsigned int ndisp,
isc_nm_t *netmgr, unsigned int options,
isc_tlsctx_cache_t *tlsctx_cache,
dns_dispatchmgr_t *dispatchmgr,
dns_dispatch_t *dispatchv4,
dns_dispatch_t *dispatchv6) {
@ -672,8 +673,8 @@ dns_view_createresolver(dns_view_t *view, isc_loopmgr_t *loopmgr,
isc_task_setname(view->task, "view", view);
result = dns_resolver_create(view, loopmgr, taskmgr, ndisp, netmgr,
options, dispatchmgr, dispatchv4,
dispatchv6, &view->resolver);
options, tlsctx_cache, dispatchmgr,
dispatchv4, dispatchv6, &view->resolver);
if (result != ISC_R_SUCCESS) {
isc_task_detach(&view->task);
return (result);

View file

@ -26,6 +26,7 @@
#include <isc/print.h>
#include <isc/task.h>
#include <isc/timer.h>
#include <isc/tls.h>
#include <isc/util.h>
#include <dns/dispatch.h>
@ -38,6 +39,7 @@
static dns_dispatchmgr_t *dispatchmgr = NULL;
static dns_dispatch_t *dispatch = NULL;
static dns_view_t *view = NULL;
static isc_tlsctx_cache_t *tlsctx_cache = NULL;
static int
setup_test(void **state) {
@ -73,8 +75,10 @@ static void
mkres(dns_resolver_t **resolverp) {
isc_result_t result;
isc_tlsctx_cache_create(mctx, &tlsctx_cache);
result = dns_resolver_create(view, loopmgr, taskmgr, 1, netmgr, 0,
dispatchmgr, dispatch, NULL, resolverp);
tlsctx_cache, dispatchmgr, dispatch, NULL,
resolverp);
assert_int_equal(result, ISC_R_SUCCESS);
}
@ -82,6 +86,9 @@ static void
destroy_resolver(dns_resolver_t **resolverp) {
dns_resolver_shutdown(*resolverp);
dns_resolver_detach(resolverp);
if (tlsctx_cache != NULL) {
isc_tlsctx_cache_detach(&tlsctx_cache);
}
}
/* dns_resolver_create */