}
static isc_result_t
-xfrin_start(dns_xfrin_ctx_t *xfr) {
- isc_result_t result;
- dns_xfrin_ctx_t *connect_xfr = NULL;
- dns_transport_type_t transport_type = DNS_TRANSPORT_TCP;
+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;
- (void)isc_refcount_increment0(&xfr->connects);
- dns_xfrin_attach(xfr, &connect_xfr);
+ REQUIRE(psess_cache != NULL && *psess_cache == NULL);
+ REQUIRE(pctx != NULL && *pctx == NULL);
- if (xfr->transport != NULL) {
- transport_type = dns_transport_get_type(xfr->transport);
- }
+ INSIST(xfr->transport != NULL);
+ tlsname = dns_transport_get_tlsname(xfr->transport);
+ INSIST(tlsname != NULL && *tlsname != '\0');
/*
- * XXX: timeouts are hard-coded to 30 seconds; this needs to be
- * configurable.
+ * 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.
*/
- switch (transport_type) {
- case DNS_TRANSPORT_TCP:
- isc_nm_tcpdnsconnect(xfr->netmgr, &xfr->sourceaddr,
- &xfr->primaryaddr, xfrin_connect_done,
- connect_xfr, 30000);
- break;
- case DNS_TRANSPORT_TLS: {
- 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;
-
- INSIST(xfr->transport != NULL);
- tlsname = dns_transport_get_tlsname(xfr->transport);
- INSIST(tlsname != NULL && *tlsname != '\0');
-
+ 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;
/*
- * 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.
+ * 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_cache_find(
- xfr->tlsctx_cache, tlsname, isc_tlsctx_cache_tls,
- family, &tlsctx, &found_store, &found_sess_cache);
+ result = isc_tlsctx_createclient(&tlsctx);
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.
- */
- CHECK(isc_tlsctx_createclient(&tlsctx));
- 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);
- }
+ 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 (hostname != NULL || ca_file != NULL) {
- 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;
- }
+ if (dns_transport_get_prefer_server_ciphers(
+ xfr->transport, &prefer_server_ciphers))
+ {
+ isc_tlsctx_prefer_server_ciphers(tlsctx,
+ prefer_server_ciphers);
+ }
- 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;
- }
+ 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) {
/*
- * According to RFC 8310, Subject field MUST NOT
- * be inspected when verifying hostname for DoT.
- * Only SubjectAltName must be checked.
+ * 'ca_file' can equal 'NULL' here, in
+ * that case the store with system-wide
+ * CA certificates will be created, just
+ * as planned.
*/
- hostname_ignore_subject = true;
- result = isc_tlsctx_enable_peer_verification(
- tlsctx, false, store, hostname,
- hostname_ignore_subject);
+ 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) {
/*
- * 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 CA bundle file is specified, but
+ * hostname is not, then use the primary
+ * IP address for validation, just like
+ * dig does.
*/
- 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;
- }
+ 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_enable_dot_client_alpn(tlsctx);
- sess_cache = isc_tlsctx_client_session_cache_new(
- xfr->mctx, tlsctx,
- ISC_TLSCTX_CLIENT_SESSION_CACHE_DEFAULT_SIZE);
+ sess_cache = isc_tlsctx_client_session_cache_new(
+ xfr->mctx, tlsctx,
+ ISC_TLSCTX_CLIENT_SESSION_CACHE_DEFAULT_SIZE);
- 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 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);
- isc_tls_cert_store_free(&store);
- isc_tlsctx_client_session_cache_detach(
- &sess_cache);
- tlsctx = found;
- sess_cache = found_sess_cache;
- } else {
- INSIST(result == ISC_R_SUCCESS);
- }
+ 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);
+ 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;
}
- isc_nm_tlsdnsconnect(xfr->netmgr, &xfr->sourceaddr,
- &xfr->primaryaddr, xfrin_connect_done,
- connect_xfr, 30000, tlsctx, sess_cache);
- } break;
- default:
- UNREACHABLE();
+ } 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:
- /*
- * The 'found' context is being managed by the TLS context cache.
- * Thus, we should keep it as it is, as it will get destroyed
- * alongside the cache.
- */
- if (tlsctx != NULL && found != tlsctx) {
+ 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);
}
- if (sess_cache != NULL && sess_cache != found_sess_cache) {
- isc_tlsctx_client_session_cache_detach(&sess_cache);
+ return (result);
+}
+
+static isc_result_t
+xfrin_start(dns_xfrin_ctx_t *xfr) {
+ isc_result_t result;
+ dns_xfrin_ctx_t *connect_xfr = NULL;
+ dns_transport_type_t transport_type = DNS_TRANSPORT_TCP;
+ isc_tlsctx_t *tlsctx = NULL;
+ isc_tlsctx_client_session_cache_t *sess_cache = NULL;
+
+ (void)isc_refcount_increment0(&xfr->connects);
+ dns_xfrin_attach(xfr, &connect_xfr);
+
+ if (xfr->transport != NULL) {
+ transport_type = dns_transport_get_type(xfr->transport);
+ }
+
+ /*
+ * XXX: timeouts are hard-coded to 30 seconds; this needs to be
+ * configurable.
+ */
+ switch (transport_type) {
+ case DNS_TRANSPORT_TCP:
+ isc_nm_tcpdnsconnect(xfr->netmgr, &xfr->sourceaddr,
+ &xfr->primaryaddr, xfrin_connect_done,
+ connect_xfr, 30000);
+ break;
+ case DNS_TRANSPORT_TLS: {
+ result = get_create_tlsctx(xfr, &tlsctx, &sess_cache);
+ if (result != ISC_R_SUCCESS) {
+ goto failure;
+ }
+ INSIST(tlsctx != NULL);
+ isc_nm_tlsdnsconnect(xfr->netmgr, &xfr->sourceaddr,
+ &xfr->primaryaddr, xfrin_connect_done,
+ connect_xfr, 30000, tlsctx, sess_cache);
+ } break;
+ default:
+ UNREACHABLE();
}
+ return (ISC_R_SUCCESS);
+
+failure:
isc_refcount_decrement0(&xfr->connects);
dns_xfrin_detach(&connect_xfr);
return (result);