summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock2
-rw-r--r--mullvad-api/src/https_client_with_sni.rs4
-rw-r--r--mullvad-api/src/proxy.rs9
-rw-r--r--mullvad-daemon/Cargo.toml1
-rw-r--r--mullvad-daemon/src/api.rs55
-rw-r--r--mullvad-encrypted-dns-proxy/Cargo.toml1
-rw-r--r--mullvad-encrypted-dns-proxy/src/config/mod.rs5
-rw-r--r--mullvad-encrypted-dns-proxy/src/config/xor.rs4
-rw-r--r--mullvad-types/src/access_method.rs1
9 files changed, 70 insertions, 12 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 88d6cb9df6..08ef9d4897 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2455,6 +2455,7 @@ dependencies = [
"log",
"log-panics",
"mullvad-api",
+ "mullvad-encrypted-dns-proxy",
"mullvad-fs",
"mullvad-management-interface",
"mullvad-paths",
@@ -2491,6 +2492,7 @@ dependencies = [
"hickory-resolver",
"log",
"rustls 0.21.11",
+ "serde",
"tokio",
"webpki-roots",
]
diff --git a/mullvad-api/src/https_client_with_sni.rs b/mullvad-api/src/https_client_with_sni.rs
index b8b908784c..898927513f 100644
--- a/mullvad-api/src/https_client_with_sni.rs
+++ b/mullvad-api/src/https_client_with_sni.rs
@@ -83,7 +83,6 @@ enum InnerConnectionMode {
Socks5(SocksConfig),
/// Connect to the destination via Mullvad Encrypted DNS proxy.
/// See [`mullvad-encrypted-dns-proxy`] for how the proxy works.
- #[allow(dead_code)] // TODO: Remove this allow
EncryptedDnsProxy(EncryptedDNSConfig),
}
@@ -277,6 +276,9 @@ impl TryFrom<ApiConnectionMode> for InnerConnectionMode {
peer: config.endpoint,
authentication: config.auth,
}),
+ ProxyConfig::EncryptedDnsProxy(config) => {
+ InnerConnectionMode::EncryptedDnsProxy(config)
+ }
},
})
}
diff --git a/mullvad-api/src/proxy.rs b/mullvad-api/src/proxy.rs
index 2fb2c4bf35..3cf38acab0 100644
--- a/mullvad-api/src/proxy.rs
+++ b/mullvad-api/src/proxy.rs
@@ -2,6 +2,7 @@ use hyper_util::client::legacy::connect::{Connected, Connection};
use serde::{Deserialize, Serialize};
use std::{
fmt, io,
+ net::SocketAddr,
path::Path,
pin::Pin,
task::{self, Poll},
@@ -74,6 +75,7 @@ pub enum ProxyConfig {
Shadowsocks(proxy::Shadowsocks),
Socks5Local(proxy::Socks5Local),
Socks5Remote(proxy::Socks5Remote),
+ EncryptedDnsProxy(mullvad_encrypted_dns_proxy::config::ProxyConfig),
}
impl ProxyConfig {
@@ -87,6 +89,10 @@ impl ProxyConfig {
ProxyConfig::Socks5Remote(remote) => {
Endpoint::from_socket_address(remote.endpoint, TransportProtocol::Tcp)
}
+ ProxyConfig::EncryptedDnsProxy(proxy) => {
+ let addr = SocketAddr::V4(proxy.addr);
+ Endpoint::from_socket_address(addr, TransportProtocol::Tcp)
+ }
}
}
}
@@ -100,6 +106,9 @@ impl fmt::Display for ProxyConfig {
ProxyConfig::Socks5Local(local) => {
write!(f, "Socks5 {} via localhost:{}", endpoint, local.local_port)
}
+ ProxyConfig::EncryptedDnsProxy(proxy) => {
+ write!(f, "ApiSusan {}", proxy.addr)
+ }
}
}
}
diff --git a/mullvad-daemon/Cargo.toml b/mullvad-daemon/Cargo.toml
index 9342062d36..778ef02d7f 100644
--- a/mullvad-daemon/Cargo.toml
+++ b/mullvad-daemon/Cargo.toml
@@ -31,6 +31,7 @@ tokio-stream = "0.1"
mullvad-relay-selector = { path = "../mullvad-relay-selector" }
mullvad-types = { path = "../mullvad-types" }
mullvad-api = { path = "../mullvad-api" }
+mullvad-encrypted-dns-proxy = { path = "../mullvad-encrypted-dns-proxy" }
mullvad-fs = { path = "../mullvad-fs" }
mullvad-paths = { path = "../mullvad-paths" }
mullvad-version = { path = "../mullvad-version" }
diff --git a/mullvad-daemon/src/api.rs b/mullvad-daemon/src/api.rs
index 930bba42c6..87bf660a79 100644
--- a/mullvad-daemon/src/api.rs
+++ b/mullvad-daemon/src/api.rs
@@ -15,6 +15,7 @@ use mullvad_api::{
proxy::{ApiConnectionMode, ConnectionModeProvider, ProxyConfig},
AddressCache,
};
+use mullvad_encrypted_dns_proxy::state::EncryptedDnsProxyState;
use mullvad_relay_selector::RelaySelector;
use mullvad_types::access_method::{
AccessMethod, AccessMethodSetting, BuiltInAccessMethod, Id, Settings,
@@ -239,6 +240,8 @@ pub struct AccessModeSelector {
cache_dir: PathBuf,
/// Used for selecting a Bridge when the `Mullvad Bridges` access method is used.
relay_selector: RelaySelector,
+ /// Used for selecting a config for the 'Encrypted DNS proxy' access method.
+ encrypted_dns_proxy_cache: EncryptedDnsProxyState,
access_method_settings: Settings,
address_cache: AddressCache,
access_method_event_sender: DaemonEventSender<(AccessMethodEvent, oneshot::Sender<()>)>,
@@ -267,10 +270,26 @@ impl AccessModeSelector {
}
}
+ // Initialize the Encrypted DNS cache
+ let mut encrypted_dns_proxy_cache = {
+ // Initialize an empty cache
+ let mut cache = EncryptedDnsProxyState::default();
+ // Hydrate the cache by fetching new proxy configs.
+ if let Err(_error) = cache.fetch_configs().await {
+ // TODO: What should we do if we initially fail to fetch configs? Handle later.
+ }
+ cache
+ };
+
// Always start looking from the position of `Direct`.
let (index, next) = Self::find_next_active(0, &access_method_settings);
- let initial_connection_mode =
- Self::resolve_inner(next, &relay_selector, &address_cache).await;
+ let initial_connection_mode = Self::resolve_inner(
+ next,
+ &relay_selector,
+ &mut encrypted_dns_proxy_cache,
+ &address_cache,
+ )
+ .await;
let (change_tx, change_rx) = mpsc::unbounded();
@@ -280,6 +299,7 @@ impl AccessModeSelector {
cmd_rx,
cache_dir,
relay_selector,
+ encrypted_dns_proxy_cache,
access_method_settings,
address_cache,
access_method_event_sender,
@@ -496,16 +516,28 @@ impl AccessModeSelector {
}
async fn resolve(&mut self, access_method: AccessMethodSetting) -> ResolvedConnectionMode {
- Self::resolve_inner(access_method, &self.relay_selector, &self.address_cache).await
+ // TODO: Should we fetch new configs here everytime?
+ // self.encrypted_dns_proxy_cache.fetch_configs().await;
+ Self::resolve_inner(
+ access_method,
+ &self.relay_selector,
+ &mut self.encrypted_dns_proxy_cache,
+ &self.address_cache,
+ )
+ .await
}
async fn resolve_inner(
access_method: AccessMethodSetting,
relay_selector: &RelaySelector,
+ encrypted_dns_proxy_cache: &mut EncryptedDnsProxyState,
address_cache: &AddressCache,
) -> ResolvedConnectionMode {
- let connection_mode =
- resolve_connection_mode(access_method.access_method.clone(), relay_selector);
+ let connection_mode = resolve_connection_mode(
+ access_method.access_method.clone(),
+ relay_selector,
+ encrypted_dns_proxy_cache,
+ );
let endpoint =
resolve_allowed_endpoint(&connection_mode, address_cache.get_address().await);
ResolvedConnectionMode {
@@ -523,6 +555,7 @@ impl AccessModeSelector {
fn resolve_connection_mode(
access_method: AccessMethod,
relay_selector: &RelaySelector,
+ encrypted_dns_proxy_cache: &mut EncryptedDnsProxyState,
) -> ApiConnectionMode {
match access_method {
AccessMethod::BuiltIn(BuiltInAccessMethod::Direct) => ApiConnectionMode::Direct,
@@ -536,9 +569,15 @@ fn resolve_connection_mode(
);
ApiConnectionMode::Direct
}),
- AccessMethod::BuiltIn(BuiltInAccessMethod::EncryptedDnsProxy) => {
- todo!("Implement me!")
- }
+ AccessMethod::BuiltIn(BuiltInAccessMethod::EncryptedDnsProxy) => encrypted_dns_proxy_cache
+ .next_configuration()
+ .map(ProxyConfig::EncryptedDnsProxy)
+ .map(ApiConnectionMode::Proxied)
+ .unwrap_or_else(|| {
+ log::error!("Could not select next Encrypted DNS proxy config");
+ log::error!("Defaulting to direct API connection");
+ ApiConnectionMode::Direct
+ }),
AccessMethod::Custom(config) => ApiConnectionMode::Proxied(ProxyConfig::from(config)),
}
}
diff --git a/mullvad-encrypted-dns-proxy/Cargo.toml b/mullvad-encrypted-dns-proxy/Cargo.toml
index 4f101e3ed0..da2a9c1552 100644
--- a/mullvad-encrypted-dns-proxy/Cargo.toml
+++ b/mullvad-encrypted-dns-proxy/Cargo.toml
@@ -14,6 +14,7 @@ workspace = true
tokio = { workspace = true, features = [ "macros" ] }
log = { workspace = true }
hickory-resolver = { version = "0.24.1", features = [ "dns-over-https-rustls" ]}
+serde = { workspace = true }
webpki-roots = "0.25.0"
rustls = "0.21"
diff --git a/mullvad-encrypted-dns-proxy/src/config/mod.rs b/mullvad-encrypted-dns-proxy/src/config/mod.rs
index bd75fd25eb..70f3b62af4 100644
--- a/mullvad-encrypted-dns-proxy/src/config/mod.rs
+++ b/mullvad-encrypted-dns-proxy/src/config/mod.rs
@@ -7,6 +7,7 @@ use std::net::{Ipv6Addr, SocketAddrV4};
mod plain;
mod xor;
+use serde::{Deserialize, Serialize};
pub use xor::XorKey;
/// All the errors that can happen during deserialization of a [`ProxyConfig`].
@@ -67,7 +68,7 @@ pub trait Obfuscator: Send {
/// Represents a Mullvad Encrypted DNS proxy configuration. Created by parsing
/// the config out of an IPv6 address resolved over DoH.
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct ProxyConfig {
/// The remote address to connect to the proxy over. This is the address
/// on the internet where the proxy is listening.
@@ -77,7 +78,7 @@ pub struct ProxyConfig {
pub obfuscation: Option<ObfuscationConfig>,
}
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub enum ObfuscationConfig {
XorV2(xor::XorKey),
}
diff --git a/mullvad-encrypted-dns-proxy/src/config/xor.rs b/mullvad-encrypted-dns-proxy/src/config/xor.rs
index b4dd2dbdf2..eb4f314e13 100644
--- a/mullvad-encrypted-dns-proxy/src/config/xor.rs
+++ b/mullvad-encrypted-dns-proxy/src/config/xor.rs
@@ -1,6 +1,8 @@
use core::fmt;
use std::net::{Ipv4Addr, SocketAddrV4};
+use serde::{Deserialize, Serialize};
+
/// Parse a proxy config that XORs all traffic with the given key.
///
/// A Xor configuration is represented by the proxy type `ProxyType::XorV2`. There used to be a `XorV1`, but it
@@ -37,7 +39,7 @@ pub fn parse_xor(data: [u8; 12]) -> Result<super::ProxyConfig, super::Error> {
/// A bunch of bytes, representing a "key" Simply meaning a slice of bytes that the data
/// will be XORed with.
-#[derive(Copy, Clone, Eq, PartialEq, Hash)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct XorKey {
data: [u8; 6],
len: usize,
diff --git a/mullvad-types/src/access_method.rs b/mullvad-types/src/access_method.rs
index 1f2e9a85af..6ef3de0ea0 100644
--- a/mullvad-types/src/access_method.rs
+++ b/mullvad-types/src/access_method.rs
@@ -105,6 +105,7 @@ impl Settings {
use std::iter::once;
once(&mut self.direct)
.chain(once(&mut self.mullvad_bridges))
+ .chain(once(&mut self.encrypted_dns_proxy))
.chain(&mut self.custom)
}