diff options
| author | David Lönnhager <david.l@mullvad.net> | 2022-11-17 16:10:52 +0100 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2022-11-28 12:54:48 +0100 |
| commit | 182fcafab5c9448c3dfe2672d1d96eb66a4550c4 (patch) | |
| tree | 126123871caa9240cee6073537fc39a3e9dc326b | |
| parent | 04fdb6a9f11e167404a1dd36552b2348bc1035d3 (diff) | |
| download | mullvadvpn-182fcafab5c9448c3dfe2672d1d96eb66a4550c4.tar.xz mullvadvpn-182fcafab5c9448c3dfe2672d1d96eb66a4550c4.zip | |
Add support for non-TLS API connections
| -rw-r--r-- | mullvad-api/src/https_client_with_sni.rs | 21 | ||||
| -rw-r--r-- | mullvad-api/src/lib.rs | 2 | ||||
| -rw-r--r-- | mullvad-api/src/proxy.rs | 99 |
3 files changed, 83 insertions, 39 deletions
diff --git a/mullvad-api/src/https_client_with_sni.rs b/mullvad-api/src/https_client_with_sni.rs index 0d85ddd790..632d325ff3 100644 --- a/mullvad-api/src/https_client_with_sni.rs +++ b/mullvad-api/src/https_client_with_sni.rs @@ -1,8 +1,8 @@ use crate::{ abortable_stream::{AbortableStream, AbortableStreamHandle}, - proxy::{ApiConnection, ApiConnectionMode, ProxyConfig}, + proxy::{ApiConnection, ApiConnectionMode, ConnectionDecorator, ProxyConfig}, tls_stream::TlsStream, - AddressCache, + AddressCache, API, }; use futures::{channel::mpsc, future, pin_mut, StreamExt}; #[cfg(target_os = "android")] @@ -303,8 +303,13 @@ impl Service<Uri> for HttpsConnectorWithSni { socket_bypass_tx.clone(), ) .await?; - let tls_stream = TlsStream::connect_https(socket, &hostname).await?; - Ok::<_, io::Error>(ApiConnection::Direct(Box::new(tls_stream))) + if API.disable_tls { + Ok::<_, io::Error>(ApiConnection::new(Box::new(socket))) + } else { + let tls_stream = + TlsStream::connect_https(socket, &hostname).await?; + Ok(ApiConnection::new(Box::new(tls_stream))) + } } InnerConnectionMode::Proxied(proxy_config) => { let socket = Self::open_socket( @@ -319,8 +324,12 @@ impl Service<Uri> for HttpsConnectorWithSni { &ServerConfig::from(proxy_config), addr, ); - let tls_stream = TlsStream::connect_https(proxy, &hostname).await?; - Ok(ApiConnection::Proxied(Box::new(tls_stream))) + if API.disable_tls { + Ok(ApiConnection::new(Box::new(ConnectionDecorator(proxy)))) + } else { + let tls_stream = TlsStream::connect_https(proxy, &hostname).await?; + Ok(ApiConnection::new(Box::new(tls_stream))) + } } } }; diff --git a/mullvad-api/src/lib.rs b/mullvad-api/src/lib.rs index 1237007ff3..68239665e4 100644 --- a/mullvad-api/src/lib.rs +++ b/mullvad-api/src/lib.rs @@ -70,6 +70,7 @@ struct ApiEndpoint { host: String, addr: SocketAddr, disable_address_cache: bool, + disable_tls: bool, } impl ApiEndpoint { @@ -100,6 +101,7 @@ impl ApiEndpoint { host: API_HOST_DEFAULT.to_owned(), addr: SocketAddr::new(API_IP_DEFAULT, API_PORT_DEFAULT), disable_address_cache: false, + disable_tls: false, }; if cfg!(feature = "api-override") { diff --git a/mullvad-api/src/proxy.rs b/mullvad-api/src/proxy.rs index 2f3764e7e6..fa1da913ba 100644 --- a/mullvad-api/src/proxy.rs +++ b/mullvad-api/src/proxy.rs @@ -1,8 +1,6 @@ -use crate::tls_stream::TlsStream; use futures::Stream; -use hyper::client::connect::{Connected, Connection}; +use hyper::client::connect::Connected; use serde::{Deserialize, Serialize}; -use shadowsocks::relay::tcprelay::ProxyClientStream; use std::{ fmt, io, net::SocketAddr, @@ -14,7 +12,6 @@ use talpid_types::{net::openvpn::ShadowsocksProxySettings, ErrorExt}; use tokio::{ fs, io::{AsyncRead, AsyncWrite, AsyncWriteExt, ReadBuf}, - net::TcpStream, }; const CURRENT_CONFIG_FILENAME: &str = "api-endpoint.json"; @@ -130,57 +127,93 @@ impl ApiConnectionMode { } } -/// Stream that is either a regular TLS stream or TLS via shadowsocks -pub enum ApiConnection { - Direct(Box<TlsStream<TcpStream>>), - Proxied(Box<TlsStream<ProxyClientStream<TcpStream>>>), +/// Implements `hyper::client::connect::Connection` by wrapping a type. +pub struct ConnectionDecorator<T: AsyncRead + AsyncWrite>(pub T); + +impl<T: AsyncRead + AsyncWrite + Unpin> AsyncRead for ConnectionDecorator<T> { + fn poll_read( + mut self: Pin<&mut Self>, + cx: &mut task::Context<'_>, + buf: &mut ReadBuf<'_>, + ) -> Poll<io::Result<()>> { + Pin::new(&mut self.0).poll_read(cx, buf) + } +} + +impl<T: AsyncRead + AsyncWrite + Unpin> AsyncWrite for ConnectionDecorator<T> { + fn poll_write( + mut self: Pin<&mut Self>, + cx: &mut task::Context<'_>, + buf: &[u8], + ) -> Poll<io::Result<usize>> { + Pin::new(&mut self.0).poll_write(cx, buf) + } + + fn poll_flush(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> { + Pin::new(&mut self.0).poll_flush(cx) + } + + fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> { + Pin::new(&mut self.0).poll_shutdown(cx) + } +} + +impl<T: AsyncRead + AsyncWrite> hyper::client::connect::Connection for ConnectionDecorator<T> { + fn connected(&self) -> Connected { + Connected::new() + } +} + +trait Connection: AsyncRead + AsyncWrite + Unpin + hyper::client::connect::Connection + Send {} + +impl<T: AsyncRead + AsyncWrite + Unpin + hyper::client::connect::Connection + Send> Connection + for T +{ +} + +/// Stream that represents a Mullvad API connection +pub struct ApiConnection(Box<dyn Connection>); + +impl ApiConnection { + pub fn new< + T: AsyncRead + AsyncWrite + Unpin + hyper::client::connect::Connection + Send + 'static, + >( + conn: Box<T>, + ) -> Self { + Self(conn) + } } impl AsyncRead for ApiConnection { fn poll_read( - self: Pin<&mut Self>, + mut self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &mut ReadBuf<'_>, ) -> Poll<io::Result<()>> { - match Pin::get_mut(self) { - ApiConnection::Direct(s) => Pin::new(s).poll_read(cx, buf), - ApiConnection::Proxied(s) => Pin::new(s).poll_read(cx, buf), - } + Pin::new(&mut self.0).poll_read(cx, buf) } } impl AsyncWrite for ApiConnection { fn poll_write( - self: Pin<&mut Self>, + mut self: Pin<&mut Self>, cx: &mut task::Context<'_>, buf: &[u8], ) -> Poll<io::Result<usize>> { - match Pin::get_mut(self) { - ApiConnection::Direct(s) => Pin::new(s).poll_write(cx, buf), - ApiConnection::Proxied(s) => Pin::new(s).poll_write(cx, buf), - } + Pin::new(&mut self.0).poll_write(cx, buf) } - fn poll_flush(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> { - match Pin::get_mut(self) { - ApiConnection::Direct(s) => Pin::new(s).poll_flush(cx), - ApiConnection::Proxied(s) => Pin::new(s).poll_flush(cx), - } + fn poll_flush(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> { + Pin::new(&mut self.0).poll_flush(cx) } - fn poll_shutdown(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> { - match Pin::get_mut(self) { - ApiConnection::Direct(s) => Pin::new(s).poll_shutdown(cx), - ApiConnection::Proxied(s) => Pin::new(s).poll_shutdown(cx), - } + fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<io::Result<()>> { + Pin::new(&mut self.0).poll_shutdown(cx) } } -impl Connection for ApiConnection { +impl hyper::client::connect::Connection for ApiConnection { fn connected(&self) -> Connected { - match self { - ApiConnection::Direct(s) => s.connected(), - ApiConnection::Proxied(s) => s.connected(), - } + self.0.connected() } } |
