diff options
| author | Markus Pettersson <markus.pettersson@mullvad.net> | 2024-10-18 11:08:31 +0200 |
|---|---|---|
| committer | Markus Pettersson <markus.pettersson@mullvad.net> | 2024-10-23 14:59:43 +0200 |
| commit | 9e99d2aa2d9df2d39002c15e75ccf44ccb7ead20 (patch) | |
| tree | 269885bcb0735cf3ac1a3538e4619d69ed0387bd | |
| parent | 4d51fe6c0df45ee6ec911a67421d7994d9993cc5 (diff) | |
| download | mullvadvpn-9e99d2aa2d9df2d39002c15e75ccf44ccb7ead20.tar.xz mullvadvpn-9e99d2aa2d9df2d39002c15e75ccf44ccb7ead20.zip | |
Enable Encrypted DNS proxy access method in the daemon
| -rw-r--r-- | Cargo.lock | 2 | ||||
| -rw-r--r-- | mullvad-api/src/https_client_with_sni.rs | 4 | ||||
| -rw-r--r-- | mullvad-api/src/proxy.rs | 9 | ||||
| -rw-r--r-- | mullvad-daemon/Cargo.toml | 1 | ||||
| -rw-r--r-- | mullvad-daemon/src/api.rs | 55 | ||||
| -rw-r--r-- | mullvad-encrypted-dns-proxy/Cargo.toml | 1 | ||||
| -rw-r--r-- | mullvad-encrypted-dns-proxy/src/config/mod.rs | 5 | ||||
| -rw-r--r-- | mullvad-encrypted-dns-proxy/src/config/xor.rs | 4 | ||||
| -rw-r--r-- | mullvad-types/src/access_method.rs | 1 |
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) } |
