From 6691a1530d976c36133166662d7291fe63e1ef83 Mon Sep 17 00:00:00 2001 From: Artem Boldariev Date: Tue, 17 Dec 2024 15:52:18 +0200 Subject: [PATCH] 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. --- bin/dig/dighost.c | 8 ++++---- bin/tests/test_client.c | 17 ++++++++++------- lib/dns/dispatch.c | 2 +- lib/isc/include/isc/netmgr.h | 6 ++++-- lib/isc/netmgr/http.c | 14 +++++++------- lib/isc/netmgr/netmgr-int.h | 1 + lib/isc/netmgr/proxystream.c | 6 ++++-- lib/isc/netmgr/streamdns.c | 15 ++++++++------- lib/isc/netmgr/tlsstream.c | 20 ++++++++++++++++++-- tests/isc/doh_test.c | 8 ++++---- tests/isc/netmgr_common.c | 15 ++++++++------- tests/isc/tcpdns_test.c | 6 +++--- tests/isc/tlsdns_test.c | 8 ++++---- 13 files changed, 76 insertions(+), 50 deletions(-) diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c index efe4837e91..09b677e87b 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 2787b3d990..25a341d177 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 0e33870229..74080270ac 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 21babdebad..887e256519 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 9d153a0f2e..9fd1097f1f 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 c7f721b2a0..d790590ec4 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 ab1eb5c7fe..883e8cf942 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 d2cd1325f3..30b3903986 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 c045ebe96d..c599600f10 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 d9001468bc..339f4559d1 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 bf7a31d400..7372af4ab0 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 0d3b76d22d..f2d3eed9dd 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 d2b290f070..e8da5b04fd 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) {