Skip to content

Commit 1dba2cd

Browse files
author
Mathias Chunnoo
committed
Apply insecure proxy option to websockets
1 parent bc84a17 commit 1dba2cd

File tree

4 files changed

+108
-5
lines changed

4 files changed

+108
-5
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ lol_html = "1.2.1"
4545
mime_guess = "2.0.4"
4646
minify-html = "0.15.0"
4747
minify-js = "0.5.6" # stick with 0.5.x as 0.6 seems to create broken JS
48+
native-tls = { version = "0.2", default-features = false, optional = true }
4849
notify = "8"
4950
notify-debouncer-full = "0.5"
5051
once_cell = "1"
@@ -54,6 +55,7 @@ rand = "0.9.0"
5455
regex = "1"
5556
remove_dir_all = "1"
5657
reqwest = { version = "0.12", default-features = false, features = ["stream", "trust-dns"] }
58+
rustls = { version = "0.23", default-features = false, optional = true }
5759
schemars = { version = "0.8", features = ["derive"] }
5860
seahash = { version = "4", features = ["use_std"] }
5961
semver = "1"
@@ -103,6 +105,7 @@ rustls = [
103105
"reqwest/rustls-tls-native-roots",
104106
"tokio-tungstenite/rustls",
105107
"tokio-tungstenite/rustls-tls-native-roots",
108+
"dep:rustls",
106109
]
107110

108111
rustls-aws-lc = [
@@ -120,10 +123,11 @@ native-tls = [
120123
"axum-server/tls-openssl",
121124
"reqwest/native-tls",
122125
"tokio-tungstenite/native-tls",
126+
"dep:native-tls",
123127
]
124128

125129
# enable the update check on startup
126130
update_check = ["crates_io_api"]
127131

128132
# enable vendoring on crates supporting that
129-
vendored = ["openssl?/vendored"]
133+
vendored = ["openssl?/vendored", "native-tls?/vendored"]

src/proxy.rs

Lines changed: 92 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@ use futures_util::{sink::SinkExt, stream::StreamExt, TryStreamExt};
1515
use http::{header::HOST, HeaderMap};
1616
use std::sync::Arc;
1717
use tokio_tungstenite::{
18-
connect_async,
18+
connect_async, connect_async_tls_with_config,
1919
tungstenite::{protocol::CloseFrame, Message as MsgTng},
20+
Connector,
2021
};
2122
use tower_http::trace::TraceLayer;
2223

@@ -144,6 +145,84 @@ fn make_outbound_request(
144145
Ok(request)
145146
}
146147

148+
fn make_insecure_connector() -> Option<Connector> {
149+
#[cfg(feature = "native-tls")]
150+
{
151+
match native_tls::TlsConnector::builder()
152+
.danger_accept_invalid_certs(true)
153+
.build()
154+
{
155+
Ok(connector) => Some(Connector::NativeTls(connector)),
156+
Err(err) => {
157+
tracing::error!(error = ?err, "error building native TLS connector");
158+
None
159+
}
160+
}
161+
}
162+
#[cfg(feature = "rustls")]
163+
{
164+
use rustls::{
165+
client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier},
166+
pki_types::{CertificateDer, ServerName, UnixTime},
167+
ClientConfig, DigitallySignedStruct, SignatureScheme,
168+
};
169+
170+
#[derive(Debug)]
171+
struct NoCertVerification;
172+
173+
impl ServerCertVerifier for NoCertVerification {
174+
fn verify_server_cert(
175+
&self,
176+
_: &CertificateDer<'_>,
177+
_: &[CertificateDer<'_>],
178+
_: &ServerName<'_>,
179+
_: &[u8],
180+
_: UnixTime,
181+
) -> Result<ServerCertVerified, rustls::Error> {
182+
Ok(ServerCertVerified::assertion())
183+
}
184+
185+
fn verify_tls12_signature(
186+
&self,
187+
_: &[u8],
188+
_: &CertificateDer<'_>,
189+
_: &DigitallySignedStruct,
190+
) -> Result<HandshakeSignatureValid, rustls::Error> {
191+
Ok(HandshakeSignatureValid::assertion())
192+
}
193+
194+
fn verify_tls13_signature(
195+
&self,
196+
_: &[u8],
197+
_: &CertificateDer<'_>,
198+
_: &DigitallySignedStruct,
199+
) -> Result<HandshakeSignatureValid, rustls::Error> {
200+
Ok(HandshakeSignatureValid::assertion())
201+
}
202+
203+
fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
204+
vec![
205+
SignatureScheme::ED25519,
206+
SignatureScheme::ECDSA_NISTP256_SHA256,
207+
SignatureScheme::ECDSA_NISTP384_SHA384,
208+
SignatureScheme::ECDSA_NISTP521_SHA512,
209+
SignatureScheme::RSA_PSS_SHA256,
210+
SignatureScheme::RSA_PSS_SHA384,
211+
SignatureScheme::RSA_PSS_SHA512,
212+
SignatureScheme::ED448,
213+
]
214+
}
215+
}
216+
217+
Some(Connector::Rustls(std::sync::Arc::new(
218+
ClientConfig::builder()
219+
.dangerous()
220+
.with_custom_certificate_verifier(Arc::new(NoCertVerification {}))
221+
.with_no_client_auth(),
222+
)))
223+
}
224+
}
225+
147226
impl ProxyHandlerHttp {
148227
/// Construct a new instance.
149228
pub fn new(
@@ -243,6 +322,8 @@ pub struct ProxyHandlerWebSocket {
243322
rewrite: Option<String>,
244323
/// The headers to inject with the request
245324
request_headers: HeaderMap,
325+
/// Allow insecure TLS websocket connections.
326+
insecure: bool,
246327
}
247328

248329
impl ProxyHandlerWebSocket {
@@ -252,12 +333,14 @@ impl ProxyHandlerWebSocket {
252333
backend: Uri,
253334
headers: HeaderMap,
254335
rewrite: Option<String>,
336+
insecure: bool,
255337
) -> Arc<Self> {
256338
Arc::new(Self {
257339
proto,
258340
backend,
259341
rewrite,
260342
request_headers: headers,
343+
insecure,
261344
})
262345
}
263346

@@ -337,8 +420,15 @@ impl ProxyHandlerWebSocket {
337420
}
338421
};
339422

423+
let connect_result = if self.insecure {
424+
connect_async_tls_with_config(outbound_request, None, false, make_insecure_connector())
425+
.await
426+
} else {
427+
connect_async(outbound_request).await
428+
};
429+
340430
// Establish WS connection to backend.
341-
let (backend, _res) = match connect_async(outbound_request).await {
431+
let (backend, _res) = match connect_result {
342432
Ok(backend) => backend,
343433
Err(err) => {
344434
tracing::error!(error = ?err, "error establishing WebSocket connection to backend {:?} for proxy", &outbound_uri);

src/serve/proxy.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,17 +45,24 @@ impl ProxyBuilder {
4545
.to_string();
4646

4747
if ws {
48+
let insecure = opts.insecure;
4849
let handler = ProxyHandlerWebSocket::new(
4950
proto,
5051
backend.clone(),
5152
request_headers.clone(),
5253
rewrite,
54+
insecure,
5355
);
5456
tracing::info!(
55-
"{}proxying websocket {} -> {}",
57+
"{}proxying websocket {} -> {} {}",
5658
SERVER,
5759
handler.path(),
58-
&backend
60+
&backend,
61+
if insecure {
62+
format!("; {DANGER}️ insecure TLS")
63+
} else {
64+
Default::default()
65+
}
5966
);
6067
self.router = handler.register(self.router);
6168
Ok(self)

0 commit comments

Comments
 (0)