summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMarkus Pettersson <markus.pettersson@mullvad.net>2023-09-13 17:22:38 +0200
committerDavid Lönnhager <david.l@mullvad.net>2023-10-09 14:40:04 +0200
commit158d9496a7b1e96a77781646ce4f1a26fda27f92 (patch)
tree4d58fa76ae9ac7c5601a9fd66465da1f395685e2
parent5a54835d4ead23be5dcda581dddb2719fbc4370f (diff)
downloadmullvadvpn-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.rs4
-rw-r--r--mullvad-api/src/proxy.rs27
-rw-r--r--mullvad-daemon/src/api.rs86
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
}
}