diff options
| author | Markus Pettersson <markus.pettersson@mullvad.net> | 2023-09-13 17:22:38 +0200 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2023-10-09 14:40:04 +0200 |
| commit | 158d9496a7b1e96a77781646ce4f1a26fda27f92 (patch) | |
| tree | 4d58fa76ae9ac7c5601a9fd66465da1f395685e2 | |
| parent | 5a54835d4ead23be5dcda581dddb2719fbc4370f (diff) | |
| download | mullvadvpn-158d9496a7b1e96a77781646ce4f1a26fda27f92.tar.xz mullvadvpn-158d9496a7b1e96a77781646ce4f1a26fda27f92.zip | |
Allowing traffic to and from a SOCKS5-proxy running on localhost.
The daemon has to add a rule to allow traffix to/from the remote server
which the locally running SOCKS5-proxy communicates with.
| -rw-r--r-- | mullvad-api/src/https_client_with_sni.rs | 4 | ||||
| -rw-r--r-- | mullvad-api/src/proxy.rs | 27 | ||||
| -rw-r--r-- | mullvad-daemon/src/api.rs | 86 |
3 files changed, 78 insertions, 39 deletions
diff --git a/mullvad-api/src/https_client_with_sni.rs b/mullvad-api/src/https_client_with_sni.rs index 5bffa3d32b..76130de185 100644 --- a/mullvad-api/src/https_client_with_sni.rs +++ b/mullvad-api/src/https_client_with_sni.rs @@ -223,7 +223,9 @@ impl TryFrom<ApiConnectionMode> for InnerConnectionMode { } ProxyConfig::Socks(config) => match config { mullvad_types::api_access_method::Socks5::Local(config) => { - InnerConnectionMode::Socks5(SocksConfig { peer: config.peer }) + InnerConnectionMode::Socks5(SocksConfig { + peer: SocketAddr::new("127.0.0.1".parse().unwrap(), config.port), + }) } mullvad_types::api_access_method::Socks5::Remote(config) => { InnerConnectionMode::Socks5(SocksConfig { peer: config.peer }) diff --git a/mullvad-api/src/proxy.rs b/mullvad-api/src/proxy.rs index 112a747f04..186eea2919 100644 --- a/mullvad-api/src/proxy.rs +++ b/mullvad-api/src/proxy.rs @@ -40,13 +40,28 @@ pub enum ProxyConfig { Socks(api_access_method::Socks5), } +impl ProxyConfig { + /// Returns the remote address to reach the proxy. + fn get_endpoint(&self) -> SocketAddr { + match self { + ProxyConfig::Shadowsocks(ss) => ss.peer, + ProxyConfig::Socks(socks) => match socks { + api_access_method::Socks5::Local(s) => s.peer, + api_access_method::Socks5::Remote(s) => s.peer, + }, + } + } +} + impl fmt::Display for ProxyConfig { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { match self { // TODO: Do not hardcode TCP ProxyConfig::Shadowsocks(ss) => write!(f, "Shadowsocks {}/TCP", ss.peer), ProxyConfig::Socks(socks) => match socks { - api_access_method::Socks5::Local(s) => write!(f, "Socks5 {}/TCP", s.peer), + api_access_method::Socks5::Local(s) => { + write!(f, "Socks5 localhost:{} => {}/TCP", s.port, s.peer) + } api_access_method::Socks5::Remote(s) => write!(f, "Socks5 {}/TCP", s.peer), }, } @@ -113,17 +128,11 @@ impl ApiConnectionMode { } } - /// Returns the remote address, or `None` for `ApiConnectionMode::Direct`. + /// Returns the remote address required to reach the API, or `None` for `ApiConnectionMode::Direct`. pub fn get_endpoint(&self) -> Option<SocketAddr> { match self { ApiConnectionMode::Direct => None, - ApiConnectionMode::Proxied(proxy_config) => match proxy_config { - ProxyConfig::Shadowsocks(ss) => Some(ss.peer), - ProxyConfig::Socks(socks) => match socks { - api_access_method::Socks5::Local(s) => Some(s.peer), - api_access_method::Socks5::Remote(s) => Some(s.peer), - }, - }, + ApiConnectionMode::Proxied(proxy_config) => Some(proxy_config.get_endpoint()), } } diff --git a/mullvad-daemon/src/api.rs b/mullvad-daemon/src/api.rs index 18e77d5a28..1bcc77f44b 100644 --- a/mullvad-daemon/src/api.rs +++ b/mullvad-daemon/src/api.rs @@ -108,32 +108,59 @@ impl ApiConnectionModeProvider { /// /// TODO: Figure out an appropriate algorithm for selecting between the available AccessMethods. /// We need to be able to poll the daemon's settings to find out which access methods are available & active. - /// For now, we a - fn new_task(&self, retry_attempt: u32) -> ApiConnectionMode { - if Self::should_use_direct(retry_attempt) { - ApiConnectionMode::Direct - } else { - self.relay_selector - .get_bridge_forced() - .and_then(|settings| match settings { - ProxySettings::Shadowsocks(ss_settings) => { - let ss_settings: api_access_method::Shadowsocks = - api_access_method::Shadowsocks::new( - ss_settings.peer, - ss_settings.cipher, - ss_settings.password, - ); - println!("Using bridge mode to access the API! {:?}", ss_settings); - Some(ApiConnectionMode::Proxied(ProxyConfig::Shadowsocks( - ss_settings, - ))) - } - _ => { - log::error!("Received unexpected proxy settings type"); - None - } - }) - .unwrap_or(ApiConnectionMode::Direct) + /// For now, [`ApiConnectionModeProvider`] is only instanciated once during daemon startup, and does not change it's + /// available access methods based on any "Settings-changed" events. + fn new_connection_mode(&mut self) -> ApiConnectionMode { + log::debug!("Rotating Access mode!"); + let access_method = { + let mut access_methods_picker = self.connection_modes.lock().unwrap(); + // Rotate through the cycle of access methods. + // Safety: It is always safe to unwrap after calling `next` on a [`std::iter::Cycle`] + access_methods_picker.next().unwrap() + }; + let connection_mode = self.from(&access_method); + log::info!("New API connection mode selected: {}", connection_mode); + connection_mode + } + + /// Ad-hoc version of [`std::convert::From::from`], but since some + /// [`ApiConnectionMode`]s require extra logic/data from + /// [`ApiConnectionModeProvider`] the standard [`std::convert::From`] trait can not be used. + fn from(&mut self, access_method: &AccessMethod) -> ApiConnectionMode { + match access_method { + AccessMethod::BuiltIn(access_method) => match access_method { + BuiltInAccessMethod::Direct => ApiConnectionMode::Direct, + BuiltInAccessMethod::Bridge => self + .relay_selector + .get_bridge_forced() + .and_then(|settings| match settings { + ProxySettings::Shadowsocks(ss_settings) => { + let ss_settings: api_access_method::Shadowsocks = + api_access_method::Shadowsocks::new( + ss_settings.peer, + ss_settings.cipher, + ss_settings.password, + *enabled, + ); + Some(ApiConnectionMode::Proxied(ProxyConfig::Shadowsocks( + ss_settings, + ))) + } + _ => { + log::error!("Received unexpected proxy settings type"); + None + } + }) + .unwrap_or(ApiConnectionMode::Direct), + }, + AccessMethod::Custom(access_method) => match &access_method.access_method { + api_access_method::ObfuscationProtocol::Shadowsocks(shadowsocks_config) => { + ApiConnectionMode::Proxied(ProxyConfig::Shadowsocks(shadowsocks_config.clone())) + } + api_access_method::ObfuscationProtocol::Socks5(socks_config) => { + ApiConnectionMode::Proxied(ProxyConfig::Socks(socks_config.clone())) + } + }, } } } @@ -161,22 +188,23 @@ impl ApiEndpointUpdaterHandle { move |address: SocketAddr| { let inner_tx = tunnel_tx.clone(); async move { - let tunnel_tx = if let Some(Some(tunnel_tx)) = { inner_tx.lock().unwrap().as_ref() } - .map(|tx: &Weak<mpsc::UnboundedSender<TunnelCommand>>| tx.upgrade()) + let tunnel_tx = if let Some(tunnel_tx) = { inner_tx.lock().unwrap().as_ref() } + .and_then(|tx: &Weak<mpsc::UnboundedSender<TunnelCommand>>| tx.upgrade()) { tunnel_tx } else { log::error!("Rejecting allowed endpoint: Tunnel state machine is not running"); return false; }; + let (result_tx, result_rx) = oneshot::channel(); let _ = tunnel_tx.unbounded_send(TunnelCommand::AllowEndpoint( get_allowed_endpoint(address), result_tx, )); - // Wait for the firewall policy to be updated. let _ = result_rx.await; log::debug!("API endpoint: {}", address); + true } } |
