summaryrefslogtreecommitdiffhomepage
path: root/mullvad-daemon/src
diff options
context:
space:
mode:
authorMarkus Pettersson <markus.pettersson@mullvad.net>2024-01-09 10:41:08 +0100
committerMarkus Pettersson <markus.pettersson@mullvad.net>2024-01-11 09:18:26 +0100
commit8b0fd0d971e67df8415da1bdac558e366bfd7290 (patch)
treee6b51f09eb39ca4a343c9d21880accb2903122f3 /mullvad-daemon/src
parent75eb89c820f12d488a76934f59ba29fe999cf59c (diff)
downloadmullvadvpn-8b0fd0d971e67df8415da1bdac558e366bfd7290.tar.xz
mullvadvpn-8b0fd0d971e67df8415da1bdac558e366bfd7290.zip
Synchronize `mullvad-api` and `mullvad-daemon` when the `api-override`
feature is enabled Move the logic for using overridden API endpoints for API calls from `mullvad-api::rest` to `mullvad_daemon::api`. This is in line with how the interaction between the two crates work for a normal release build, i.e. when the `api-override` feature is disabled. This commit also removes references to `force_direct_connection` in the Android code. The flag does not exist in the `mullvad-*` rust crates anymore, so it would be erroneous to try to serialize/deserialize the value from the Android client.
Diffstat (limited to 'mullvad-daemon/src')
-rw-r--r--mullvad-daemon/src/api.rs118
-rw-r--r--mullvad-daemon/src/lib.rs76
2 files changed, 106 insertions, 88 deletions
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
}