]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
CID 352848: split xfrin_start() and remove dead code
authorArtem Boldariev <artem@boldariev.com>
Tue, 24 May 2022 08:39:26 +0000 (11:39 +0300)
committerArtem Boldariev <artem@boldariev.com>
Wed, 25 May 2022 09:38:38 +0000 (12:38 +0300)
This commit separates TLS context creation code from xfrin_start() as
it has become too large and hard to follow into a new
function (similarly how it is done in dighost.c)

The dead code has been removed from the cleanup section of the TLS
creation code:

* there is no way 'tlsctx' can equal 'found';
* there is no way 'sess_cache' can be non-NULL in the cleanup section.

Also, it fixes a bug in the older version of the code, where TLS
client session context fetched from the cache would not get passed to
isc_nm_tlsdnsconnect().

lib/dns/xfrin.c
lib/isc/include/isc/tls.h

index c3971b8ffa1a11da37a53eecb28603fdd67041bf..4f3afd216ef510f0196f218b351d0124df17a7bb 100644 (file)
@@ -928,222 +928,257 @@ xfrin_create(isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db, isc_nm_t *netmgr,
 }
 
 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);
index 86265ddb7c9d225c0a2fdbd26711218c20f8b574..e960e049139fdae8d28047ff3f492630d5c52cd7 100644 (file)
@@ -558,5 +558,7 @@ isc_tlsctx_cache_find(
  *
  * Returns:
  *\li  #ISC_R_SUCCESS - the context has been found;
- *\li  #ISC_R_NOTFOUND - the context has not been found.
+ *\li  #ISC_R_NOTFOUND - the context has not been found. In such a case,
+ *             'pstore' still might get initialised as there is one to many
+ *             relation between stores and contexts.
  */