summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMarkus Pettersson <markus.pettersson@mullvad.net>2024-01-11 09:44:03 +0100
committerMarkus Pettersson <markus.pettersson@mullvad.net>2024-01-11 09:44:03 +0100
commitb5decd12a264c3e37092211eb0951dac6c640670 (patch)
treee6b51f09eb39ca4a343c9d21880accb2903122f3
parent75eb89c820f12d488a76934f59ba29fe999cf59c (diff)
parent8b0fd0d971e67df8415da1bdac558e366bfd7290 (diff)
downloadmullvadvpn-b5decd12a264c3e37092211eb0951dac6c640670.tar.xz
mullvadvpn-b5decd12a264c3e37092211eb0951dac6c640670.zip
Merge branch 'firewall-not-updated-when-api-override-is-enabled-550'
-rw-r--r--android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/ApiEndpoint.kt3
-rw-r--r--android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/CustomApiEndpointConfiguration.kt6
-rw-r--r--android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/MockApiTest.kt3
-rw-r--r--mullvad-api/src/access.rs2
-rw-r--r--mullvad-api/src/address_cache.rs4
-rw-r--r--mullvad-api/src/lib.rs206
-rw-r--r--mullvad-api/src/rest.rs28
-rw-r--r--mullvad-daemon/src/api.rs118
-rw-r--r--mullvad-daemon/src/lib.rs76
-rw-r--r--mullvad-jni/src/lib.rs14
-rw-r--r--test/test-manager/src/tests/account.rs6
11 files changed, 266 insertions, 200 deletions
diff --git a/android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/ApiEndpoint.kt b/android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/ApiEndpoint.kt
index 7325e3f61b..4b5beacf49 100644
--- a/android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/ApiEndpoint.kt
+++ b/android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/ApiEndpoint.kt
@@ -8,6 +8,5 @@ import kotlinx.parcelize.Parcelize
data class ApiEndpoint(
val address: InetSocketAddress,
val disableAddressCache: Boolean,
- val disableTls: Boolean,
- val forceDirectConnection: Boolean
+ val disableTls: Boolean
) : Parcelable
diff --git a/android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/CustomApiEndpointConfiguration.kt b/android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/CustomApiEndpointConfiguration.kt
index 5790f8c73f..b1559be777 100644
--- a/android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/CustomApiEndpointConfiguration.kt
+++ b/android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/CustomApiEndpointConfiguration.kt
@@ -10,14 +10,12 @@ data class CustomApiEndpointConfiguration(
val hostname: String,
val port: Int,
val disableAddressCache: Boolean = true,
- val disableTls: Boolean = false,
- val forceDirectConnection: Boolean = true
+ val disableTls: Boolean = false
) : ApiEndpointConfiguration {
override fun apiEndpoint() =
ApiEndpoint(
address = InetSocketAddress(hostname, port),
disableAddressCache = disableAddressCache,
- disableTls = disableTls,
- forceDirectConnection = forceDirectConnection
+ disableTls = disableTls
)
}
diff --git a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/MockApiTest.kt b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/MockApiTest.kt
index f699b3cadc..702aa72db4 100644
--- a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/MockApiTest.kt
+++ b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/MockApiTest.kt
@@ -59,8 +59,7 @@ abstract class MockApiTest {
InetAddress.getLocalHost().hostName,
port,
disableAddressCache = true,
- disableTls = true,
- forceDirectConnection = true
+ disableTls = true
)
}
}
diff --git a/mullvad-api/src/access.rs b/mullvad-api/src/access.rs
index 276cc1f561..569c01f085 100644
--- a/mullvad-api/src/access.rs
+++ b/mullvad-api/src/access.rs
@@ -38,7 +38,7 @@ struct AccountState {
impl AccessTokenStore {
pub(crate) fn new(service: RequestServiceHandle) -> Self {
- let factory = rest::RequestFactory::new(&API.host, None);
+ let factory = rest::RequestFactory::new(API.host(), None);
let (tx, rx) = mpsc::unbounded();
tokio::spawn(Self::service_requests(rx, service, factory));
Self { tx }
diff --git a/mullvad-api/src/address_cache.rs b/mullvad-api/src/address_cache.rs
index e4bcf9bde7..ea93d96e26 100644
--- a/mullvad-api/src/address_cache.rs
+++ b/mullvad-api/src/address_cache.rs
@@ -31,7 +31,7 @@ pub struct AddressCache {
impl AddressCache {
/// Initialize cache using the hardcoded address, and write changes to `write_path`.
pub fn new(write_path: Option<Box<Path>>) -> Result<Self, Error> {
- Self::new_inner(API.addr, write_path)
+ Self::new_inner(API.address(), write_path)
}
/// Initialize cache using `read_path`, and write changes to `write_path`.
@@ -53,7 +53,7 @@ impl AddressCache {
/// Returns the address if the hostname equals `API.host`. Otherwise, returns `None`.
pub async fn resolve_hostname(&self, hostname: &str) -> Option<SocketAddr> {
- if hostname.eq_ignore_ascii_case(&API.host) {
+ if hostname.eq_ignore_ascii_case(API.host()) {
Some(self.get_address().await)
} else {
None
diff --git a/mullvad-api/src/lib.rs b/mullvad-api/src/lib.rs
index 237ed100d4..adba236764 100644
--- a/mullvad-api/src/lib.rs
+++ b/mullvad-api/src/lib.rs
@@ -103,95 +103,169 @@ impl<T> Deref for LazyManual<T> {
/// A hostname and socketaddr to reach the Mullvad REST API over.
#[derive(Debug)]
pub struct ApiEndpoint {
- pub host: String,
- pub addr: SocketAddr,
+ /// An overriden API hostname. Initialized with the value of the environment
+ /// variable `MULLVAD_API_HOST` if it has been set.
+ ///
+ /// Use the associated function [`Self::host`] to read this value with a
+ /// default fallback if `MULLVAD_API_HOST` was not set.
+ pub host: Option<String>,
+ /// An overriden API address. Initialized with the value of the environment
+ /// variable `MULLVAD_API_ADDR` if it has been set.
+ ///
+ /// Use the associated function [`Self::address()`] to read this value with
+ /// a default fallback if `MULLVAD_API_ADDR` was not set.
+ ///
+ /// # Note
+ ///
+ /// If [`Self::address`] is populated with [`Some(SocketAddr)`], it should
+ /// always be respected when establishing API connections.
+ pub address: Option<SocketAddr>,
#[cfg(feature = "api-override")]
pub disable_address_cache: bool,
#[cfg(feature = "api-override")]
pub disable_tls: bool,
- #[cfg(feature = "api-override")]
- pub force_direct_connection: bool,
}
impl ApiEndpoint {
+ const API_HOST_DEFAULT: &'static str = "api.mullvad.net";
+ const API_IP_DEFAULT: IpAddr = IpAddr::V4(Ipv4Addr::new(45, 83, 223, 196));
+ const API_PORT_DEFAULT: u16 = 443;
+
+ const API_HOST_VAR: &'static str = "MULLVAD_API_HOST";
+ const API_ADDR_VAR: &'static str = "MULLVAD_API_ADDR";
+ const DISABLE_TLS_VAR: &'static str = "MULLVAD_API_DISABLE_TLS";
+
/// Returns the endpoint to connect to the API over.
///
/// # Panics
///
- /// Panics if `MULLVAD_API_ADDR` has invalid contents or if only one of
- /// `MULLVAD_API_ADDR` or `MULLVAD_API_HOST` has been set but not the other.
+ /// Panics if `MULLVAD_API_ADDR`, `MULLVAD_API_HOST` or
+ /// `MULLVAD_API_DISABLE_TLS` has invalid contents.
+ #[cfg(feature = "api-override")]
pub fn from_env_vars() -> ApiEndpoint {
- const API_HOST_DEFAULT: &str = "api.mullvad.net";
- const API_IP_DEFAULT: IpAddr = IpAddr::V4(Ipv4Addr::new(45, 83, 223, 196));
- const API_PORT_DEFAULT: u16 = 443;
-
- fn read_var(key: &'static str) -> Option<String> {
- use std::env;
- match env::var(key) {
- Ok(v) => Some(v),
- Err(env::VarError::NotPresent) => None,
- Err(env::VarError::NotUnicode(_)) => panic!("{key} does not contain valid UTF-8"),
- }
- }
-
- let host_var = read_var("MULLVAD_API_HOST");
- let address_var = read_var("MULLVAD_API_ADDR");
- let disable_tls_var = read_var("MULLVAD_API_DISABLE_TLS");
+ let host_var = Self::read_var(ApiEndpoint::API_HOST_VAR);
+ let address_var = Self::read_var(ApiEndpoint::API_ADDR_VAR);
+ let disable_tls_var = Self::read_var(ApiEndpoint::DISABLE_TLS_VAR);
- #[cfg_attr(not(feature = "api-override"), allow(unused_mut))]
let mut api = ApiEndpoint {
- host: API_HOST_DEFAULT.to_owned(),
- addr: SocketAddr::new(API_IP_DEFAULT, API_PORT_DEFAULT),
- #[cfg(feature = "api-override")]
- disable_address_cache: false,
- #[cfg(feature = "api-override")]
+ host: host_var.clone(),
+ address: None,
+ disable_address_cache: true,
disable_tls: false,
- #[cfg(feature = "api-override")]
- force_direct_connection: false,
};
- #[cfg(feature = "api-override")]
- {
- use std::net::ToSocketAddrs;
-
- if host_var.is_none() && address_var.is_none() {
- if disable_tls_var.is_some() {
- log::warn!("MULLVAD_API_DISABLE_TLS is ignored since MULLVAD_API_HOST and MULLVAD_API_ADDR are not set");
- }
- return api;
- }
-
- let scheme = if let Some(disable_tls_var) = disable_tls_var {
- api.disable_tls = disable_tls_var != "0";
- "http://"
- } else {
- "https://"
- };
-
- if let Some(user_host) = host_var {
- api.host = user_host;
+ api.address = match address_var {
+ Some(user_addr) => {
+ let addr = user_addr.parse().unwrap_or_else(|_| {
+ panic!(
+ "{api_addr}={user_addr} is not a valid socketaddr",
+ api_addr = ApiEndpoint::API_ADDR_VAR,
+ )
+ });
+ Some(addr)
}
- if let Some(user_addr) = address_var {
- api.addr = user_addr
- .parse()
- .expect("MULLVAD_API_ADDR is not a valid socketaddr");
- } else {
- log::warn!("Resolving API IP from MULLVAD_API_HOST");
- api.addr = format!("{}:{}", api.host, API_PORT_DEFAULT)
+ None => {
+ use std::net::ToSocketAddrs;
+ log::debug!(
+ "{api_addr} not found. Resolving API IP from {api_host}",
+ api_addr = ApiEndpoint::API_ADDR_VAR,
+ api_host = ApiEndpoint::API_HOST_VAR
+ );
+ format!("{}:{}", api.host(), ApiEndpoint::API_PORT_DEFAULT)
.to_socket_addrs()
.expect("failed to resolve API host")
.next()
- .expect("API host yielded 0 addresses");
}
- api.disable_address_cache = true;
- api.force_direct_connection = true;
- log::debug!("Overriding API. Using {} at {scheme}{}", api.host, api.addr);
+ };
+
+ if api.host.is_none() && api.address.is_none() {
+ if disable_tls_var.is_some() {
+ log::warn!(
+ "{disable_tls} is ignored since {api_host} and {api_addr} are not set",
+ disable_tls = ApiEndpoint::DISABLE_TLS_VAR,
+ api_host = ApiEndpoint::API_HOST_VAR,
+ api_addr = ApiEndpoint::API_ADDR_VAR,
+ );
+ }
+ } else {
+ api.disable_tls = disable_tls_var
+ .as_ref()
+ .map(|disable_tls| disable_tls != "0")
+ .unwrap_or(api.disable_tls);
+
+ log::debug!(
+ "Overriding API. Using {host} at {scheme}{addr}",
+ host = api.host(),
+ addr = api.address(),
+ scheme = if api.disable_tls {
+ "http://"
+ } else {
+ "https://"
+ }
+ );
}
- #[cfg(not(feature = "api-override"))]
+ api
+ }
+
+ /// Returns the endpoint to connect to the API over.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `MULLVAD_API_ADDR`, `MULLVAD_API_HOST` or
+ /// `MULLVAD_API_DISABLE_TLS` has invalid contents.
+ #[cfg(not(feature = "api-override"))]
+ pub fn from_env_vars() -> ApiEndpoint {
+ let host_var = Self::read_var(ApiEndpoint::API_HOST_VAR);
+ let address_var = Self::read_var(ApiEndpoint::API_ADDR_VAR);
+ let disable_tls_var = Self::read_var(ApiEndpoint::DISABLE_TLS_VAR);
+
if host_var.is_some() || address_var.is_some() || disable_tls_var.is_some() {
- log::warn!("These variables are ignored in production builds: MULLVAD_API_HOST, MULLVAD_API_ADDR, MULLVAD_API_DISABLE_TLS");
+ log::warn!(
+ "These variables are ignored in production builds: {api_host}, {api_addr}, {disable_tls}",
+ api_host = ApiEndpoint::API_HOST_VAR,
+ api_addr = ApiEndpoint::API_ADDR_VAR,
+ disable_tls = ApiEndpoint::DISABLE_TLS_VAR
+ );
+ }
+
+ ApiEndpoint {
+ host: None,
+ address: None,
+ }
+ }
+
+ /// Read the [`Self::host`] value, falling back to
+ /// [`Self::API_HOST_DEFAULT`] as default value if it does not exist.
+ pub fn host(&self) -> &str {
+ self.host
+ .as_deref()
+ .unwrap_or(ApiEndpoint::API_HOST_DEFAULT)
+ }
+
+ /// Read the [`Self::address`] value, falling back to
+ /// [`Self::API_IP_DEFAULT`]:[`Self::API_PORT_DEFAULT`] as default if it
+ /// does not exist.
+ pub fn address(&self) -> SocketAddr {
+ self.address.unwrap_or(SocketAddr::new(
+ ApiEndpoint::API_IP_DEFAULT,
+ ApiEndpoint::API_PORT_DEFAULT,
+ ))
+ }
+
+ /// Try to read the value of an environment variable. Returns `None` if the
+ /// environment variable has not been set.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the environment variable was found, but it did not contain
+ /// valid unicode data.
+ fn read_var(key: &'static str) -> Option<String> {
+ use std::env;
+ match env::var(key) {
+ Ok(v) => Some(v),
+ Err(env::VarError::NotPresent) => None,
+ Err(env::VarError::NotUnicode(_)) => panic!("{key} does not contain valid UTF-8"),
}
- api
}
}
@@ -314,14 +388,14 @@ impl Runtime {
) -> rest::MullvadRestHandle {
let service = self
.new_request_service(
- Some(API.host.clone()),
+ Some(API.host().to_string()),
proxy_provider,
#[cfg(target_os = "android")]
self.socket_bypass_tx.clone(),
)
.await;
let token_store = access::AccessTokenStore::new(service.clone());
- let factory = rest::RequestFactory::new(&API.host, Some(token_store));
+ let factory = rest::RequestFactory::new(API.host(), Some(token_store));
rest::MullvadRestHandle::new(
service,
diff --git a/mullvad-api/src/rest.rs b/mullvad-api/src/rest.rs
index 9f1e88a751..d5b82052e5 100644
--- a/mullvad-api/src/rest.rs
+++ b/mullvad-api/src/rest.rs
@@ -26,9 +26,6 @@ use std::{
};
use talpid_types::ErrorExt;
-#[cfg(feature = "api-override")]
-use crate::API;
-
pub use hyper::StatusCode;
const USER_AGENT: &str = "mullvad-app";
@@ -147,14 +144,7 @@ impl<T: Stream<Item = ApiConnectionMode> + Unpin + Send + 'static> RequestServic
socket_bypass_tx.clone(),
);
- #[cfg(feature = "api-override")]
- let force_direct_connection = API.force_direct_connection;
- #[cfg(not(feature = "api-override"))]
- let force_direct_connection = false;
-
- if force_direct_connection {
- log::debug!("API proxies are disabled");
- } else if let Some(config) = proxy_config_provider.next().await {
+ if let Some(config) = proxy_config_provider.next().await {
connector_handle.set_connection_mode(config);
}
@@ -185,17 +175,9 @@ impl<T: Stream<Item = ApiConnectionMode> + Unpin + Send + 'static> RequestServic
self.connector_handle.reset();
}
RequestCommand::NextApiConfig(completion_tx) => {
- #[cfg(feature = "api-override")]
- let force_direct_connection = API.force_direct_connection;
- #[cfg(not(feature = "api-override"))]
- let force_direct_connection = false;
-
- if force_direct_connection {
- log::debug!("Ignoring API connection mode");
- } else if let Some(connection_mode) = self.proxy_config_provider.next().await {
+ if let Some(connection_mode) = self.proxy_config_provider.next().await {
self.connector_handle.set_connection_mode(connection_mode);
}
-
let _ = completion_tx.send(Ok(()));
}
}
@@ -632,8 +614,10 @@ impl MullvadRestHandle {
availability,
};
#[cfg(feature = "api-override")]
- if API.disable_address_cache {
- return handle;
+ {
+ if crate::API.disable_address_cache {
+ return handle;
+ }
}
handle.spawn_api_address_fetcher(address_cache);
handle
diff --git a/mullvad-daemon/src/api.rs b/mullvad-daemon/src/api.rs
index 3f6f1747a6..caf39ec874 100644
--- a/mullvad-daemon/src/api.rs
+++ b/mullvad-daemon/src/api.rs
@@ -32,65 +32,39 @@ pub enum Message {
Resolve(ResponseTx<ResolvedConnectionMode>, AccessMethodSetting),
}
-/// A [`NewAccessMethodEvent`] is emitted when the active access method changes,
-/// which happens in any of the following two scenarios:
-///
-/// * When a [`mullvad_api::rest::RequestService`] requests a new
-/// [`ApiConnectionMode`] from the running [`AccessModeSelector`]. This will
-/// lead to a [`crate::InternalDaemonEvent::AccessMethodEvent`] being sent to
-/// the daemon, which in turn will notify all clients about the new access
-/// method.
-///
-/// * When testing if some [`AccessMethodSetting`] can be used to reach the
-/// Mullvad API. In this scenario, the currently active access method will
-/// temporarily change (approximately for the duration of 1 API call). Since
-/// this is just an internal test which should be opaque to any client, it
-/// should not produce any unwanted noise and as such it is *not* broadcasted
-/// after the daemon is done processing this [`NewAccessMethodEvent`].
-pub struct NewAccessMethodEvent {
- /// The new active [`AccessMethodSetting`].
- pub setting: AccessMethodSetting,
- /// The endpoint which represents how to connect to the Mullvad API and
- /// which clients are allowed to initiate such a connection.
- pub endpoint: AllowedEndpoint,
- /// If the daemon should notify clients about the new access method.
+/// Calling [`AccessMethodEvent::send`] will cause a
+/// [`crate::InternalDaemonEvent::AccessMethodEvent`] being sent to the daemon,
+/// which in turn will handle updating the firewall and notifying clients as
+/// applicable.
+pub enum AccessMethodEvent {
+ /// A [`AccessMethodEvent::New`] event is emitted when the active access
+ /// method changes.
///
- /// Defaults to `true`.
- pub announce: bool,
-}
-
-impl NewAccessMethodEvent {
- /// Create a new [`NewAccessMethodEvent`] for the daemon to process. A
- /// [`oneshot::Receiver`] can be used to await the daemon while it finishes
- /// handling the new event.
- pub fn new(setting: AccessMethodSetting, endpoint: AllowedEndpoint) -> NewAccessMethodEvent {
- NewAccessMethodEvent {
- setting,
- endpoint,
- announce: true,
- }
- }
-
- /// Whether the daemon should notify clients about the new access method or
- /// not.
+ /// This happens when a [`mullvad_api::rest::RequestService`] requests a new
+ /// [`ApiConnectionMode`] from the running [`AccessModeSelector`].
+ New {
+ /// The new active [`AccessMethodSetting`].
+ setting: AccessMethodSetting,
+ /// The endpoint which represents how to connect to the Mullvad API and
+ /// which clients are allowed to initiate such a connection.
+ endpoint: AllowedEndpoint,
+ },
+ /// Emitted when the the firewall should be updated.
///
- /// * If `announce` is set to `true` the daemon will broadcast this event to
- /// clients.
- /// * If `announce` is set to `false` the daemon will *not* broadcast this
- /// event.
- pub fn announce(mut self, announce: bool) -> Self {
- self.announce = announce;
- self
- }
+ /// This is useful for example when testing if some [`AccessMethodSetting`]
+ /// can be used to reach the Mullvad API. In this scenario, the currently
+ /// active access method will temporarily change (approximately for the
+ /// duration of 1 API call). Since this is just an internal test which
+ /// should be opaque to any client, it should not produce any unwanted noise
+ /// and as such it is *not* broadcasted after the daemon is done processing
+ /// this [`AccessMethodEvent::Allow`].
+ Allow { endpoint: AllowedEndpoint },
+}
- /// Send an internal daemon event which will punch a hole in the firewall
- /// for the connection mode we are testing.
- ///
- /// Returns the channel on which the daemon will send a message over when it
- /// is done applying the firewall changes.
+impl AccessMethodEvent {
pub(crate) async fn send(
self,
- daemon_event_sender: DaemonEventSender<(NewAccessMethodEvent, oneshot::Sender<()>)>,
+ daemon_event_sender: DaemonEventSender<(AccessMethodEvent, oneshot::Sender<()>)>,
) -> std::result::Result<(), Canceled> {
// It is up to the daemon to actually allow traffic to/from `api_endpoint`
// by updating the firewall. This [`oneshot::Sender`] allows the daemon to
@@ -251,7 +225,7 @@ pub struct AccessModeSelector {
relay_selector: RelaySelector,
connection_modes: ConnectionModesIterator,
address_cache: AddressCache,
- access_method_event_sender: DaemonEventSender<(NewAccessMethodEvent, oneshot::Sender<()>)>,
+ access_method_event_sender: DaemonEventSender<(AccessMethodEvent, oneshot::Sender<()>)>,
current: ResolvedConnectionMode,
}
@@ -260,7 +234,7 @@ impl AccessModeSelector {
cache_dir: PathBuf,
relay_selector: RelaySelector,
connection_modes: Vec<AccessMethodSetting>,
- access_method_event_sender: DaemonEventSender<(NewAccessMethodEvent, oneshot::Sender<()>)>,
+ access_method_event_sender: DaemonEventSender<(AccessMethodEvent, oneshot::Sender<()>)>,
address_cache: AddressCache,
) -> Result<AccessModeSelectorHandle> {
let (cmd_tx, cmd_rx) = mpsc::unbounded();
@@ -348,6 +322,36 @@ impl AccessModeSelector {
}
async fn next_connection_mode(&mut self) -> Result<ApiConnectionMode> {
+ #[cfg(feature = "api-override")]
+ {
+ use mullvad_api::API;
+ // If the API address has been explicitly overridden, it should
+ // always be used. This implies that a direct API connection mode is
+ // used.
+ if API.address.is_some() {
+ log::debug!("API proxies are disabled");
+ let endpoint = resolve_allowed_endpoint(
+ &ApiConnectionMode::Direct,
+ // Note that the address cache *should* be initialized with
+ // the overridden API endpoint, so we can simply fetch the
+ // endpoint address from it.
+ self.address_cache.get_address().await,
+ );
+ let daemon_sender = self.access_method_event_sender.clone();
+ tokio::spawn(async move {
+ let _ = AccessMethodEvent::Allow { endpoint }
+ .send(daemon_sender)
+ .await;
+ });
+ return Ok(ApiConnectionMode::Direct);
+ }
+
+ log::debug!(
+ "The `api-override` feature is enabled, but the API address \
+ was not overridden. Selecting API access methods as normal"
+ );
+ }
+
let access_method = self.connection_modes.next().ok_or(Error::NoAccessMethods)?;
log::info!(
"A new API access method has been selected: {name}",
@@ -365,7 +369,7 @@ impl AccessModeSelector {
let endpoint = resolved.endpoint.clone();
let daemon_sender = self.access_method_event_sender.clone();
tokio::spawn(async move {
- let _ = NewAccessMethodEvent::new(setting, endpoint)
+ let _ = AccessMethodEvent::New { setting, endpoint }
.send(daemon_sender)
.await;
});
diff --git a/mullvad-daemon/src/lib.rs b/mullvad-daemon/src/lib.rs
index 06e289d22d..bb257ebc60 100644
--- a/mullvad-daemon/src/lib.rs
+++ b/mullvad-daemon/src/lib.rs
@@ -27,7 +27,7 @@ pub mod version;
mod version_check;
use crate::target_state::PersistentTargetState;
-use api::NewAccessMethodEvent;
+use api::AccessMethodEvent;
use device::{AccountEvent, PrivateAccountAndDevice, PrivateDeviceEvent};
use futures::{
channel::{mpsc, oneshot},
@@ -374,7 +374,7 @@ pub(crate) enum InternalDaemonEvent {
DeviceEvent(AccountEvent),
/// Sent when access methods are changed in any way (new active access method).
AccessMethodEvent {
- event: NewAccessMethodEvent,
+ event: AccessMethodEvent,
endpoint_active_tx: oneshot::Sender<()>,
},
/// Handles updates from versions without devices.
@@ -416,8 +416,8 @@ impl From<AccountEvent> for InternalDaemonEvent {
}
}
-impl From<(NewAccessMethodEvent, oneshot::Sender<()>)> for InternalDaemonEvent {
- fn from(event: (NewAccessMethodEvent, oneshot::Sender<()>)) -> Self {
+impl From<(AccessMethodEvent, oneshot::Sender<()>)> for InternalDaemonEvent {
+ fn from(event: (AccessMethodEvent, oneshot::Sender<()>)) -> Self {
InternalDaemonEvent::AccessMethodEvent {
event: event.0,
endpoint_active_tx: event.1,
@@ -1341,28 +1341,39 @@ where
fn handle_access_method_event(
&mut self,
- event: NewAccessMethodEvent,
+ event: AccessMethodEvent,
endpoint_active_tx: oneshot::Sender<()>,
) {
- // Update the firewall to exempt a new API endpoint.
- let (completion_tx, completion_rx) = oneshot::channel();
- self.send_tunnel_command(TunnelCommand::AllowEndpoint(event.endpoint, completion_tx));
- // If the `NewAccessMethodEvent` should be announced to any client
- // listening for updates of the currently active access method, we need
- // to clone the handle to the broadcaster of such events. The
- // announcement should be made after the firewall policy has been
- // updated, since the new access method will be useless before then.
- let event_listener = self.event_listener.clone();
- tokio::spawn(async move {
- // Wait for the firewall policy to be updated.
- let _ = completion_rx.await;
- // Let the emitter of this event know that the firewall has been updated.
- let _ = endpoint_active_tx.send(());
- // Notify clients about the change if necessary.
- if event.announce {
- event_listener.notify_new_access_method_event(event.setting);
+ match event {
+ AccessMethodEvent::Allow { endpoint } => {
+ let (completion_tx, completion_rx) = oneshot::channel();
+ self.send_tunnel_command(TunnelCommand::AllowEndpoint(endpoint, completion_tx));
+ tokio::spawn(async move {
+ // Wait for the firewall policy to be updated.
+ let _ = completion_rx.await;
+ // Let the emitter of this event know that the firewall has been updated.
+ let _ = endpoint_active_tx.send(());
+ });
}
- });
+ AccessMethodEvent::New { setting, endpoint } => {
+ // Update the firewall to exempt a new API endpoint.
+ let (completion_tx, completion_rx) = oneshot::channel();
+ self.send_tunnel_command(TunnelCommand::AllowEndpoint(endpoint, completion_tx));
+ // Announce to all clients listening for updates of the
+ // currently active access method. The announcement should be
+ // made after the firewall policy has been updated, since the
+ // new access method will be useless before then.
+ let event_listener = self.event_listener.clone();
+ tokio::spawn(async move {
+ // Wait for the firewall policy to be updated.
+ let _ = completion_rx.await;
+ // Let the emitter of this event know that the firewall has been updated.
+ let _ = endpoint_active_tx.send(());
+ // Notify clients about the change if necessary.
+ event_listener.notify_new_access_method_event(setting);
+ });
+ }
+ }
}
fn handle_device_migration_event(
@@ -2496,10 +2507,11 @@ where
let result = async move {
// Send an internal daemon event which will punch a hole in the firewall
// for the connection mode we are testing.
- let _ = api::NewAccessMethodEvent::new(test_subject.setting, test_subject.endpoint)
- .announce(false)
- .send(daemon_event_sender.clone())
- .await;
+ let _ = api::AccessMethodEvent::Allow {
+ endpoint: test_subject.endpoint,
+ }
+ .send(daemon_event_sender.clone())
+ .await;
// Send a HEAD request to some Mullvad API endpoint. We issue a HEAD
// request because we are *only* concerned with if we get a reply from
@@ -2515,10 +2527,12 @@ where
.get_current()
.await
.map_err(Error::ApiConnectionModeError)?;
- let _ = api::NewAccessMethodEvent::new(active.setting, active.endpoint)
- .announce(false)
- .send(daemon_event_sender.clone())
- .await;
+
+ let _ = api::AccessMethodEvent::Allow {
+ endpoint: active.endpoint,
+ }
+ .send(daemon_event_sender.clone())
+ .await;
result
}
diff --git a/mullvad-jni/src/lib.rs b/mullvad-jni/src/lib.rs
index 8334ecd1ee..a41b8d6643 100644
--- a/mullvad-jni/src/lib.rs
+++ b/mullvad-jni/src/lib.rs
@@ -307,11 +307,10 @@ fn api_endpoint_from_java(env: &JnixEnv<'_>, object: JObject<'_>) -> mullvad_api
.l()
.expect("ApiEndpoint.address is not an InetSocketAddress");
- endpoint.addr =
- try_socketaddr_from_java(env, address).expect("received unresolved InetSocketAddress");
- if let Some(host) = try_hostname_from_java(env, address) {
- endpoint.host = host;
- }
+ endpoint.address = Some(
+ try_socketaddr_from_java(env, address).expect("received unresolved InetSocketAddress"),
+ );
+ endpoint.host = try_hostname_from_java(env, address);
endpoint.disable_address_cache = env
.call_method(object, "component2", "()Z", &[])
.expect("missing ApiEndpoint.disableAddressCache")
@@ -322,11 +321,6 @@ fn api_endpoint_from_java(env: &JnixEnv<'_>, object: JObject<'_>) -> mullvad_api
.expect("missing ApiEndpoint.disableTls")
.z()
.expect("ApiEndpoint.disableTls is not a bool");
- endpoint.force_direct_connection = env
- .call_method(object, "component4", "()Z", &[])
- .expect("missing ApiEndpoint.forceDirectConnection")
- .z()
- .expect("ApiEndpoint.forceDirectConnection is not a bool");
endpoint
}
diff --git a/test/test-manager/src/tests/account.rs b/test/test-manager/src/tests/account.rs
index 8b30f85768..d30d0330f0 100644
--- a/test/test-manager/src/tests/account.rs
+++ b/test/test-manager/src/tests/account.rs
@@ -221,7 +221,7 @@ pub async fn new_device_client() -> DevicesProxy {
let api_endpoint = mullvad_api::ApiEndpoint::from_env_vars();
let api_host = format!("api.{}", TEST_CONFIG.mullvad_host);
- let api_addr = format!("{api_host}:443")
+ let api_address = format!("{api_host}:443")
.to_socket_addrs()
.expect("failed to resolve API host")
.next()
@@ -229,8 +229,8 @@ pub async fn new_device_client() -> DevicesProxy {
// Override the API endpoint to use the one specified in the test config
let _ = mullvad_api::API.override_init(mullvad_api::ApiEndpoint {
- host: api_host,
- addr: api_addr,
+ host: Some(api_host),
+ address: Some(api_address),
..api_endpoint
});