From: Artem Boldariev Date: Tue, 17 Dec 2024 13:52:18 +0000 (+0200) Subject: TLS SNI - add low level support for SNI to the networking code X-Git-Tag: v9.21.4~12^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6691a1530d976c36133166662d7291fe63e1ef83;p=thirdparty%2Fbind9.git TLS SNI - add low level support for SNI to the networking code This commit adds support for setting SNI hostnames in outgoing connections over TLS. Most of the changes are related to either adapting the code to accept and extra argument in *connect() functions and a couple of changes to the TLS Stream to actually make use of the new SNI hostname information. --- diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c index efe4837e919..09b677e87b5 100644 --- a/bin/dig/dighost.c +++ b/bin/dig/dighost.c @@ -3041,7 +3041,7 @@ start_tcp(dig_query_t *query) { } isc_nm_streamdnsconnect(netmgr, &localaddr, &query->sockaddr, tcp_connected, connectquery, - local_timeout, tlsctx, sess_cache, + local_timeout, tlsctx, NULL, sess_cache, proxy_type, ppi); #if HAVE_LIBNGHTTP2 } else if (query->lookup->https_mode) { @@ -3061,14 +3061,14 @@ start_tcp(dig_query_t *query) { isc_nm_httpconnect(netmgr, &localaddr, &query->sockaddr, uri, !query->lookup->https_get, tcp_connected, - connectquery, tlsctx, sess_cache, + connectquery, tlsctx, NULL, sess_cache, local_timeout, proxy_type, ppi); #endif } else { isc_nm_streamdnsconnect(netmgr, &localaddr, &query->sockaddr, tcp_connected, connectquery, - local_timeout, NULL, NULL, proxy_type, - ppi); + local_timeout, NULL, NULL, NULL, + proxy_type, ppi); } return; diff --git a/bin/tests/test_client.c b/bin/tests/test_client.c index 2787b3d990a..25a341d177c 100644 --- a/bin/tests/test_client.c +++ b/bin/tests/test_client.c @@ -378,16 +378,18 @@ run(void) { connect_cb, NULL, timeout); break; case TCP: - isc_nm_streamdnsconnect( - netmgr, &sockaddr_local, &sockaddr_remote, connect_cb, - NULL, timeout, NULL, NULL, ISC_NM_PROXY_NONE, NULL); + isc_nm_streamdnsconnect(netmgr, &sockaddr_local, + &sockaddr_remote, connect_cb, NULL, + timeout, NULL, NULL, NULL, + ISC_NM_PROXY_NONE, NULL); break; case DOT: { isc_tlsctx_createclient(&tls_ctx); - isc_nm_streamdnsconnect( - netmgr, &sockaddr_local, &sockaddr_remote, connect_cb, - NULL, timeout, tls_ctx, NULL, ISC_NM_PROXY_NONE, NULL); + isc_nm_streamdnsconnect(netmgr, &sockaddr_local, + &sockaddr_remote, connect_cb, NULL, + timeout, tls_ctx, NULL, NULL, + ISC_NM_PROXY_NONE, NULL); break; } #if HAVE_LIBNGHTTP2 @@ -408,7 +410,8 @@ run(void) { } isc_nm_httpconnect(netmgr, &sockaddr_local, &sockaddr_remote, req_url, is_post, connect_cb, NULL, tls_ctx, - NULL, timeout, ISC_NM_PROXY_NONE, NULL); + NULL, NULL, timeout, ISC_NM_PROXY_NONE, + NULL); } break; #endif default: diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index 0e338702298..74080270acc 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -2007,7 +2007,7 @@ tcp_dispatch_connect(dns_dispatch_t *disp, dns_dispentry_t *resp) { isc_nm_streamdnsconnect(disp->mgr->nm, &disp->local, &disp->peer, tcp_connected, disp, - resp->timeout, tlsctx, sess_cache, + resp->timeout, tlsctx, NULL, sess_cache, ISC_NM_PROXY_NONE, NULL); break; diff --git a/lib/isc/include/isc/netmgr.h b/lib/isc/include/isc/netmgr.h index 21babdebadd..887e2565196 100644 --- a/lib/isc/include/isc/netmgr.h +++ b/lib/isc/include/isc/netmgr.h @@ -494,6 +494,7 @@ void isc_nm_proxystreamconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, isc_nm_cb_t cb, void *cbarg, unsigned int timeout, isc_tlsctx_t *tlsctx, + const char *sni_hostname, isc_tlsctx_client_session_cache_t *client_sess_cache, isc_nm_proxyheader_info_t *proxy_info); /*%< @@ -616,6 +617,7 @@ void isc_nm_streamdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, isc_nm_cb_t cb, void *cbarg, unsigned int timeout, isc_tlsctx_t *tlsctx, + const char *sni_hostname, isc_tlsctx_client_session_cache_t *client_sess_cache, isc_nm_proxy_type_t proxy_type, isc_nm_proxyheader_info_t *proxy_info); @@ -672,7 +674,7 @@ isc_nm_listentls(isc_nm_t *mgr, uint32_t workers, isc_sockaddr_t *iface, void isc_nm_tlsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, isc_nm_cb_t connect_cb, void *connect_cbarg, - isc_tlsctx_t *ctx, + isc_tlsctx_t *ctx, const char *sni_hostname, isc_tlsctx_client_session_cache_t *client_sess_cache, unsigned int timeout, bool proxy, isc_nm_proxyheader_info_t *proxy_info); @@ -684,7 +686,7 @@ isc_nm_tlsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, void isc_nm_httpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, const char *uri, bool POST, isc_nm_cb_t cb, void *cbarg, - isc_tlsctx_t *ctx, + isc_tlsctx_t *ctx, const char *sni_hostname, isc_tlsctx_client_session_cache_t *client_sess_cache, unsigned int timeout, isc_nm_proxy_type_t proxy_type, isc_nm_proxyheader_info_t *proxy_info); diff --git a/lib/isc/netmgr/http.c b/lib/isc/netmgr/http.c index 9d153a0f2e7..9fd1097f1f3 100644 --- a/lib/isc/netmgr/http.c +++ b/lib/isc/netmgr/http.c @@ -1464,7 +1464,7 @@ error: void isc_nm_httpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, const char *uri, bool post, isc_nm_cb_t cb, void *cbarg, - isc_tlsctx_t *tlsctx, + isc_tlsctx_t *tlsctx, const char *sni_hostname, isc_tlsctx_client_session_cache_t *client_sess_cache, unsigned int timeout, isc_nm_proxy_type_t proxy_type, isc_nm_proxyheader_info_t *proxy_info) { @@ -1535,8 +1535,8 @@ isc_nm_httpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, if (tlsctx != NULL) { isc_nm_tlsconnect(mgr, local, peer, transport_connect_cb, sock, tlsctx, - client_sess_cache, timeout, false, - NULL); + sni_hostname, client_sess_cache, + timeout, false, NULL); } else { isc_nm_tcpconnect(mgr, local, peer, transport_connect_cb, sock, timeout); @@ -1546,19 +1546,19 @@ isc_nm_httpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, if (tlsctx != NULL) { isc_nm_tlsconnect(mgr, local, peer, transport_connect_cb, sock, tlsctx, - client_sess_cache, timeout, true, - proxy_info); + sni_hostname, client_sess_cache, + timeout, true, proxy_info); } else { isc_nm_proxystreamconnect( mgr, local, peer, transport_connect_cb, sock, - timeout, NULL, NULL, proxy_info); + timeout, NULL, NULL, NULL, proxy_info); } break; case ISC_NM_PROXY_ENCRYPTED: INSIST(tlsctx != NULL); isc_nm_proxystreamconnect( mgr, local, peer, transport_connect_cb, sock, timeout, - tlsctx, client_sess_cache, proxy_info); + tlsctx, sni_hostname, client_sess_cache, proxy_info); break; default: UNREACHABLE(); diff --git a/lib/isc/netmgr/netmgr-int.h b/lib/isc/netmgr/netmgr-int.h index c7f721b2a06..d790590ec40 100644 --- a/lib/isc/netmgr/netmgr-int.h +++ b/lib/isc/netmgr/netmgr-int.h @@ -516,6 +516,7 @@ struct isc_nmsocket { isc_tlsctx_t **listener_tls_ctx; /*%< A context reference per worker */ size_t n_listener_tls_ctx; + char *sni_hostname; isc_tlsctx_client_session_cache_t *client_sess_cache; bool client_session_saved; isc_nmsocket_t *tlslistener; diff --git a/lib/isc/netmgr/proxystream.c b/lib/isc/netmgr/proxystream.c index ab1eb5c7fe0..883e8cf9428 100644 --- a/lib/isc/netmgr/proxystream.c +++ b/lib/isc/netmgr/proxystream.c @@ -459,6 +459,7 @@ void isc_nm_proxystreamconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, isc_nm_cb_t cb, void *cbarg, unsigned int timeout, isc_tlsctx_t *tlsctx, + const char *sni_hostname, isc_tlsctx_client_session_cache_t *client_sess_cache, isc_nm_proxyheader_info_t *proxy_info) { isc_result_t result = ISC_R_FAILURE; @@ -501,8 +502,9 @@ isc_nm_proxystreamconnect(isc_nm_t *mgr, isc_sockaddr_t *local, nsock, nsock->connect_timeout); } else { isc_nm_tlsconnect(mgr, local, peer, proxystream_connect_cb, - nsock, tlsctx, client_sess_cache, - nsock->connect_timeout, false, NULL); + nsock, tlsctx, sni_hostname, + client_sess_cache, nsock->connect_timeout, + false, NULL); } } diff --git a/lib/isc/netmgr/streamdns.c b/lib/isc/netmgr/streamdns.c index d2cd1325f37..30b39039861 100644 --- a/lib/isc/netmgr/streamdns.c +++ b/lib/isc/netmgr/streamdns.c @@ -387,6 +387,7 @@ void isc_nm_streamdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, isc_nm_cb_t cb, void *cbarg, unsigned int timeout, isc_tlsctx_t *tlsctx, + const char *sni_hostname, isc_tlsctx_client_session_cache_t *client_sess_cache, isc_nm_proxy_type_t proxy_type, isc_nm_proxyheader_info_t *proxy_info) { @@ -418,7 +419,7 @@ isc_nm_streamdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, } else { isc_nm_tlsconnect( mgr, local, peer, streamdns_transport_connected, - nsock, tlsctx, client_sess_cache, + nsock, tlsctx, sni_hostname, client_sess_cache, nsock->connect_timeout, false, proxy_info); } break; @@ -427,20 +428,20 @@ isc_nm_streamdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_nm_proxystreamconnect(mgr, local, peer, streamdns_transport_connected, nsock, nsock->connect_timeout, - NULL, NULL, proxy_info); + NULL, NULL, NULL, proxy_info); } else { isc_nm_tlsconnect( mgr, local, peer, streamdns_transport_connected, - nsock, tlsctx, client_sess_cache, + nsock, tlsctx, sni_hostname, client_sess_cache, nsock->connect_timeout, true, proxy_info); } break; case ISC_NM_PROXY_ENCRYPTED: INSIST(tlsctx != NULL); - isc_nm_proxystreamconnect(mgr, local, peer, - streamdns_transport_connected, nsock, - nsock->connect_timeout, tlsctx, - client_sess_cache, proxy_info); + isc_nm_proxystreamconnect( + mgr, local, peer, streamdns_transport_connected, nsock, + nsock->connect_timeout, tlsctx, sni_hostname, + client_sess_cache, proxy_info); break; default: UNREACHABLE(); diff --git a/lib/isc/netmgr/tlsstream.c b/lib/isc/netmgr/tlsstream.c index c045ebe96d5..c599600f10f 100644 --- a/lib/isc/netmgr/tlsstream.c +++ b/lib/isc/netmgr/tlsstream.c @@ -868,6 +868,14 @@ initialize_tls(isc_nmsocket_t *sock, bool server) { sock->tlsstream.server = server; sock->tlsstream.nsending = 0; sock->tlsstream.state = TLS_INIT; + if (sock->tlsstream.sni_hostname != NULL) { + INSIST(sock->client); + const int ret = SSL_set_tlsext_host_name( + sock->tlsstream.tls, sock->tlsstream.sni_hostname); + if (ret != 1) { + goto error; + } + } return ISC_R_SUCCESS; error: isc_tls_free(&sock->tlsstream.tls); @@ -1201,7 +1209,7 @@ tcp_connected(isc_nmhandle_t *handle, isc_result_t result, void *cbarg); void isc_nm_tlsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, isc_nm_cb_t connect_cb, void *connect_cbarg, - isc_tlsctx_t *ctx, + isc_tlsctx_t *ctx, const char *sni_hostname, isc_tlsctx_client_session_cache_t *client_sess_cache, unsigned int timeout, bool proxy, isc_nm_proxyheader_info_t *proxy_info) { @@ -1223,6 +1231,10 @@ isc_nm_tlsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, sock->connect_cbarg = connect_cbarg; sock->connect_timeout = timeout; isc_tlsctx_attach(ctx, &sock->tlsstream.ctx); + if (sni_hostname != NULL) { + sock->tlsstream.sni_hostname = + isc_mem_strdup(sock->worker->mctx, sni_hostname); + } sock->client = true; if (client_sess_cache != NULL) { INSIST(isc_tlsctx_client_session_cache_getctx( @@ -1234,7 +1246,7 @@ isc_nm_tlsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, if (proxy) { isc_nm_proxystreamconnect(mgr, local, peer, tcp_connected, sock, sock->connect_timeout, NULL, NULL, - proxy_info); + NULL, proxy_info); } else { isc_nm_tcpconnect(mgr, local, peer, tcp_connected, sock, sock->connect_timeout); @@ -1334,6 +1346,10 @@ isc__nm_tls_cleanup_data(isc_nmsocket_t *sock) { if (sock->tlsstream.ctx != NULL) { isc_tlsctx_free(&sock->tlsstream.ctx); } + if (sock->tlsstream.sni_hostname != NULL) { + isc_mem_free(sock->worker->mctx, + sock->tlsstream.sni_hostname); + } if (sock->tlsstream.client_sess_cache != NULL) { INSIST(sock->client); isc_tlsctx_client_session_cache_detach( diff --git a/tests/isc/doh_test.c b/tests/isc/doh_test.c index d9001468bcd..339f4559d10 100644 --- a/tests/isc/doh_test.c +++ b/tests/isc/doh_test.c @@ -213,7 +213,7 @@ connect_send_request(isc_nm_t *mgr, const char *uri, bool post, } isc_nm_httpconnect(mgr, NULL, &tcp_listen_addr, uri, post, - connect_send_cb, data, ctx, client_sess_cache, + connect_send_cb, data, ctx, NULL, client_sess_cache, timeout, get_proxy_type(), NULL); } @@ -698,7 +698,7 @@ doh_timeout_recovery(void *arg ISC_ATTR_UNUSED) { ISC_NM_HTTP_DEFAULT_PATH); isc_nm_httpconnect(connect_nm, NULL, &tcp_listen_addr, req_url, atomic_load(&POST), timeout_request_cb, NULL, ctx, - client_sess_cache, T_CONNECT, get_proxy_type(), + NULL, client_sess_cache, T_CONNECT, get_proxy_type(), NULL); } @@ -947,8 +947,8 @@ doh_recv_two(void *arg ISC_ATTR_UNUSED) { isc_nm_httpconnect(connect_nm, NULL, &tcp_listen_addr, req_url, atomic_load(&POST), doh_connect_send_two_requests_cb, - NULL, ctx, client_sess_cache, 5000, get_proxy_type(), - NULL); + NULL, ctx, NULL, client_sess_cache, 5000, + get_proxy_type(), NULL); isc_loop_teardown(mainloop, listen_sock_close, listen_sock); } diff --git a/tests/isc/netmgr_common.c b/tests/isc/netmgr_common.c index bf7a31d400d..7372af4ab00 100644 --- a/tests/isc/netmgr_common.c +++ b/tests/isc/netmgr_common.c @@ -595,7 +595,7 @@ tcp_connect(isc_nm_t *nm) { static void tls_connect(isc_nm_t *nm) { isc_nm_tlsconnect(nm, &tcp_connect_addr, &tcp_listen_addr, - connect_connect_cb, NULL, tcp_connect_tlsctx, + connect_connect_cb, NULL, tcp_connect_tlsctx, NULL, tcp_tlsctx_client_sess_cache, T_CONNECT, stream_use_PROXY, NULL); } @@ -631,7 +631,7 @@ proxystream_connect(isc_nm_t *nm) { isc_nm_proxystreamconnect(nm, &tcp_connect_addr, &tcp_listen_addr, connect_connect_cb, NULL, T_CONNECT, tlsctx, - sess_cache, get_proxyheader_info()); + NULL, sess_cache, get_proxyheader_info()); } stream_connect_function @@ -680,10 +680,11 @@ stream_connect(isc_nm_cb_t cb, void *cbarg, unsigned int timeout) { isc_refcount_increment0(&active_cconnects); if (stream_use_TLS && !stream_PROXY_over_TLS) { - isc_nm_tlsconnect( - connect_nm, &tcp_connect_addr, &tcp_listen_addr, cb, - cbarg, tcp_connect_tlsctx, tcp_tlsctx_client_sess_cache, - timeout, stream_use_PROXY, NULL); + isc_nm_tlsconnect(connect_nm, &tcp_connect_addr, + &tcp_listen_addr, cb, cbarg, + tcp_connect_tlsctx, NULL, + tcp_tlsctx_client_sess_cache, timeout, + stream_use_PROXY, NULL); return; } else if (stream_use_PROXY) { isc_tlsctx_t *tlsctx = stream_PROXY_over_TLS @@ -694,7 +695,7 @@ stream_connect(isc_nm_cb_t cb, void *cbarg, unsigned int timeout) { : NULL; isc_nm_proxystreamconnect(connect_nm, &tcp_connect_addr, &tcp_listen_addr, cb, cbarg, timeout, - tlsctx, sess_cache, + tlsctx, NULL, sess_cache, get_proxyheader_info()); return; } else { diff --git a/tests/isc/tcpdns_test.c b/tests/isc/tcpdns_test.c index 0d3b76d22d2..f2d3eed9dd1 100644 --- a/tests/isc/tcpdns_test.c +++ b/tests/isc/tcpdns_test.c @@ -63,7 +63,7 @@ static void tcpdns_connect(isc_nm_t *nm) { isc_nm_streamdnsconnect(nm, &tcp_connect_addr, &tcp_listen_addr, connect_connect_cb, tcpdns_connect, T_CONNECT, - NULL, NULL, get_proxy_type(), NULL); + NULL, NULL, NULL, get_proxy_type(), NULL); } ISC_LOOP_TEST_IMPL(tcpdns_noop) { @@ -73,7 +73,7 @@ ISC_LOOP_TEST_IMPL(tcpdns_noop) { isc_refcount_increment0(&active_cconnects); isc_nm_streamdnsconnect(connect_nm, &tcp_connect_addr, &tcp_listen_addr, connect_success_cb, tcpdns_connect, T_CONNECT, - NULL, NULL, get_proxy_type(), NULL); + NULL, NULL, NULL, get_proxy_type(), NULL); } ISC_LOOP_TEST_IMPL(tcpdns_noresponse) { @@ -82,7 +82,7 @@ ISC_LOOP_TEST_IMPL(tcpdns_noresponse) { isc_refcount_increment0(&active_cconnects); isc_nm_streamdnsconnect(connect_nm, &tcp_connect_addr, &tcp_listen_addr, connect_connect_cb, tcpdns_connect, T_CONNECT, - NULL, NULL, get_proxy_type(), NULL); + NULL, NULL, NULL, get_proxy_type(), NULL); } ISC_LOOP_TEST_IMPL(tcpdns_timeout_recovery) { diff --git a/tests/isc/tlsdns_test.c b/tests/isc/tlsdns_test.c index d2b290f070f..e8da5b04fd9 100644 --- a/tests/isc/tlsdns_test.c +++ b/tests/isc/tlsdns_test.c @@ -63,7 +63,7 @@ static void tlsdns_connect(isc_nm_t *nm) { isc_nm_streamdnsconnect( nm, &tcp_connect_addr, &tcp_listen_addr, connect_connect_cb, - tlsdns_connect, T_CONNECT, tcp_connect_tlsctx, + tlsdns_connect, T_CONNECT, tcp_connect_tlsctx, NULL, tcp_tlsctx_client_sess_cache, get_proxy_type(), NULL); } @@ -74,7 +74,7 @@ ISC_LOOP_TEST_IMPL(tlsdns_noop) { isc_refcount_increment0(&active_cconnects); isc_nm_streamdnsconnect(connect_nm, &tcp_connect_addr, &tcp_listen_addr, connect_success_cb, tlsdns_connect, T_CONNECT, - tcp_connect_tlsctx, + tcp_connect_tlsctx, NULL, tcp_tlsctx_client_sess_cache, get_proxy_type(), NULL); } @@ -85,7 +85,7 @@ ISC_LOOP_TEST_IMPL(tlsdns_noresponse) { isc_refcount_increment0(&active_cconnects); isc_nm_streamdnsconnect(connect_nm, &tcp_connect_addr, &tcp_listen_addr, connect_connect_cb, tlsdns_connect, T_CONNECT, - tcp_connect_tlsctx, + tcp_connect_tlsctx, NULL, tcp_tlsctx_client_sess_cache, get_proxy_type(), NULL); } @@ -109,7 +109,7 @@ ISC_LOOP_TEST_IMPL(tlsdns_timeout_recovery) { isc_nm_streamdnsconnect( connect_nm, &tcp_connect_addr, &tcp_listen_addr, connect_connect_cb, tlsdns_connect, T_SOFT, tcp_connect_tlsctx, - tcp_tlsctx_client_sess_cache, get_proxy_type(), NULL); + NULL, tcp_tlsctx_client_sess_cache, get_proxy_type(), NULL); } ISC_LOOP_TEST_IMPL(tlsdns_recv_one) {