Merge pull request #425 from fufesou/refact/tls_fallback_rustls_native_tls

refact: tls fallback, rustls -> native-tls
This commit is contained in:
RustDesk authored and GitHub committed 2025-11-03 22:53:17 +08:00
commit a4053b929b
2 files changed
+79 -70

No files matched your search

+71 -62
View File
@@ -411,9 +411,9 @@ impl Proxy {
let url = format!("https://{}", self.intercept.get_host_and_port()?); let url = format!("https://{}", self.intercept.get_host_and_port()?);
let tls_type = get_cached_tls_type(&url); let tls_type = get_cached_tls_type(&url);
let danger_accept_invalid_cert = get_cached_tls_accept_invalid_cert(&url); let danger_accept_invalid_cert = get_cached_tls_accept_invalid_cert(&url);
let stream = match tls_type.unwrap_or(TlsType::NativeTls) { let stream = match tls_type.unwrap_or(TlsType::Rustls) {
TlsType::NativeTls => { TlsType::Rustls => {
self.https_connect_nativetls_wrap_danger( self.https_connect_rustls_wrap_danger(
&url, &url,
local, local,
proxy, proxy,
@@ -425,8 +425,8 @@ impl Proxy {
) )
.await? .await?
} }
TlsType::Rustls => { TlsType::NativeTls => {
self.https_connect_rustls_wrap_danger( self.https_connect_nativetls_wrap_danger(
&url, &url,
local, local,
proxy, proxy,
@@ -477,78 +477,31 @@ impl Proxy {
}; };
} }
#[async_recursion]
async fn https_connect_nativetls_wrap_danger<'a>( async fn https_connect_nativetls_wrap_danger<'a>(
&self, &self,
url: &str, url: &str,
local: SocketAddr, local: SocketAddr,
proxy: SocketAddr, proxy: SocketAddr,
stream: Option<tokio::net::TcpStream>,
target_addr: &TargetAddr<'a>, target_addr: &TargetAddr<'a>,
is_tls_type_cached: bool,
danger_accept_invalid_cert: Option<bool>, danger_accept_invalid_cert: Option<bool>,
origin_danger_accept_invalid_cert: Option<bool>,
) -> ResultType<DynTcpStream> { ) -> ResultType<DynTcpStream> {
let stream = stream.unwrap_or(self.new_stream(local, proxy).await?); let stream = self.new_stream(local, proxy).await?;
match super::timeout( let s = super::timeout(
self.ms_timeout, self.ms_timeout,
self.https_connect_nativetls( self.https_connect_nativetls(
stream, stream,
target_addr, &target_addr,
danger_accept_invalid_cert.unwrap_or(false), danger_accept_invalid_cert.unwrap_or(false),
), ),
) )
.await? .await??;
{
Ok(s) => {
upsert_tls_cache( upsert_tls_cache(
&url, url,
TlsType::NativeTls, TlsType::NativeTls,
danger_accept_invalid_cert.unwrap_or(false), danger_accept_invalid_cert.unwrap_or(false),
); );
Ok(DynTcpStream(Box::new(s))) Ok(DynTcpStream(Box::new(s)))
} }
Err(ProxyError::NativeTlsError(e)) => {
let s = if danger_accept_invalid_cert.is_none() {
log::warn!(
"Falling back to native-tls (accept invalid cert) for HTTPS proxy server."
);
self.https_connect_nativetls_wrap_danger(
&url,
local,
proxy,
None,
target_addr,
is_tls_type_cached,
Some(true),
origin_danger_accept_invalid_cert,
)
.await?
} else if !is_tls_type_cached {
log::warn!("Falling back to rustls for HTTPS proxy server.");
self.https_connect_rustls_wrap_danger(
&url,
local,
proxy,
&target_addr,
origin_danger_accept_invalid_cert,
)
.await?
} else {
log::error!(
"Failed to connect to HTTPS proxy server with native-tls: {:?}.",
e
);
bail!(e)
};
Ok(s)
}
Err(e) => {
log::error!("Failed to connect to HTTPS proxy server: {:?}.", e);
bail!(e)
}
}
}
pub async fn https_connect_nativetls<'a, Input>( pub async fn https_connect_nativetls<'a, Input>(
&self, &self,
@@ -570,31 +523,87 @@ impl Proxy {
self.http_connect(stream, target_addr).await self.http_connect(stream, target_addr).await
} }
#[async_recursion]
async fn https_connect_rustls_wrap_danger<'a>( async fn https_connect_rustls_wrap_danger<'a>(
&self, &self,
url: &str, url: &str,
local: SocketAddr, local: SocketAddr,
proxy: SocketAddr, proxy: SocketAddr,
stream: Option<tokio::net::TcpStream>,
target_addr: &TargetAddr<'a>, target_addr: &TargetAddr<'a>,
is_tls_type_cached: bool,
danger_accept_invalid_cert: Option<bool>, danger_accept_invalid_cert: Option<bool>,
origin_danger_accept_invalid_cert: Option<bool>,
) -> ResultType<DynTcpStream> { ) -> ResultType<DynTcpStream> {
let stream = self.new_stream(local, proxy).await?; let stream = stream.unwrap_or(self.new_stream(local, proxy).await?);
let s = super::timeout( match super::timeout(
self.ms_timeout, self.ms_timeout,
self.https_connect_rustls( self.https_connect_rustls(
stream, stream,
&target_addr, target_addr,
danger_accept_invalid_cert.unwrap_or(false), danger_accept_invalid_cert.unwrap_or(false),
), ),
) )
.await??; .await?
{
Ok(s) => {
upsert_tls_cache( upsert_tls_cache(
url, &url,
TlsType::Rustls, TlsType::Rustls,
danger_accept_invalid_cert.unwrap_or(false), danger_accept_invalid_cert.unwrap_or(false),
); );
Ok(DynTcpStream(Box::new(s))) Ok(DynTcpStream(Box::new(s)))
} }
Err(e) => {
// NOTE: Maybe it's better to check if the error is related to TLS here. (ProxyError::IoError(e), or ProxyError::NativeTlsError(e))
// But we can only get the error when the TLS protocol is TLSv1.1.
// The error message of the following is unclear:
// https://github.com/rustdesk/rustdesk-server-pro/issues/189#issuecomment-1895701480
// So we just try to fallback unconditionally here.
//
// If the protocol is TLS 1.1, the error is:
// 1. "IO Error: received fatal alert: ProtocolVersion"
// 2. "IO Error: An existing connection was forcibly closed by the remote host. (os error 10054)" on Windows sometimes.
//
// If the cert verification fails, the error is:
// "IO Error: invalid peer certificate: UnknownIssuer"
let s = if danger_accept_invalid_cert.is_none() {
log::warn!(
"Falling back to rustls-tls (accept invalid cert) for HTTPS proxy server."
);
self.https_connect_rustls_wrap_danger(
&url,
local,
proxy,
None,
target_addr,
is_tls_type_cached,
Some(true),
origin_danger_accept_invalid_cert,
)
.await?
} else if !is_tls_type_cached {
log::warn!("Falling back to native-tls for HTTPS proxy server.");
self.https_connect_nativetls_wrap_danger(
&url,
local,
proxy,
&target_addr,
origin_danger_accept_invalid_cert,
)
.await?
} else {
log::error!(
"Failed to connect to HTTPS proxy server with native-tls: {:?}.",
e
);
bail!(e)
};
Ok(s)
}
}
}
pub async fn https_connect_rustls<'a, Input>( pub async fn https_connect_rustls<'a, Input>(
&self, &self,
+8 -8
View File
@@ -73,7 +73,7 @@ impl WsFramedStream {
let tls_type = get_cached_tls_type(url); let tls_type = get_cached_tls_type(url);
let is_tls_type_cached = tls_type.is_some(); let is_tls_type_cached = tls_type.is_some();
let tls_type = tls_type.unwrap_or(TlsType::NativeTls); let tls_type = tls_type.unwrap_or(TlsType::Rustls);
let danger_accept_invalid_cert = get_cached_tls_accept_invalid_cert(&url); let danger_accept_invalid_cert = get_cached_tls_accept_invalid_cert(&url);
Self::try_connect( Self::try_connect(
url, url,
@@ -113,9 +113,9 @@ impl WsFramedStream {
Ok(ws_stream) Ok(ws_stream)
} }
Err(e) => match (tls_type, is_tls_type_cached, danger_accept_invalid_cert) { Err(e) => match (tls_type, is_tls_type_cached, danger_accept_invalid_cert) {
(TlsType::NativeTls, _, None) => { (TlsType::Rustls, _, None) => {
log::warn!( log::warn!(
"WebSocket connection with native-tls failed, try accept invalid certs: {}, {:?}", "WebSocket connection with rustls-tls failed, try accept invalid certs: {}, {:?}",
url, url,
e e
); );
@@ -129,25 +129,25 @@ impl WsFramedStream {
) )
.await .await
} }
(TlsType::NativeTls, false, Some(_)) => { (TlsType::Rustls, false, Some(_)) => {
log::warn!( log::warn!(
"WebSocket connection with native-tls failed, try rustls: {}, {:?}", "WebSocket connection with rustls-tls failed, try native-tls: {}, {:?}",
url, url,
e e
); );
Self::try_connect( Self::try_connect(
url, url,
ms_timeout, ms_timeout,
TlsType::Rustls, TlsType::NativeTls,
is_tls_type_cached, is_tls_type_cached,
original_danger_accept_invalid_certs, original_danger_accept_invalid_certs,
original_danger_accept_invalid_certs, original_danger_accept_invalid_certs,
) )
.await .await
} }
(TlsType::Rustls, _, None) => { (TlsType::NativeTls, _, None) => {
log::warn!( log::warn!(
"WebSocket connection with rustls failed, try accept invalid certs: {}, {:?}", "WebSocket connection with native-tls failed, try accept invalid certs: {}, {:?}",
url, url,
e e
); );