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.
This commit is contained in:
Artem Boldariev 2024-12-17 15:52:18 +02:00
parent 6ce55429f1
commit 6691a1530d
13 changed files with 76 additions and 50 deletions

View file

@ -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;

View file

@ -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:

View file

@ -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;

View file

@ -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);

View file

@ -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();

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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();

View file

@ -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(

View file

@ -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);
}

View file

@ -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 {

View file

@ -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) {

View file

@ -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) {