summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2022-11-17 16:10:52 +0100
committerDavid Lönnhager <david.l@mullvad.net>2022-11-28 12:54:48 +0100
commit182fcafab5c9448c3dfe2672d1d96eb66a4550c4 (patch)
tree126123871caa9240cee6073537fc39a3e9dc326b
parent04fdb6a9f11e167404a1dd36552b2348bc1035d3 (diff)
downloadmullvadvpn-182fcafab5c9448c3dfe2672d1d96eb66a4550c4.tar.xz
mullvadvpn-182fcafab5c9448c3dfe2672d1d96eb66a4550c4.zip
Add support for non-TLS API connections
-rw-r--r--mullvad-api/src/https_client_with_sni.rs21
-rw-r--r--mullvad-api/src/lib.rs2
-rw-r--r--mullvad-api/src/proxy.rs99
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()
}
}