summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2020-11-19 01:37:02 +0100
committerDavid Lönnhager <david.l@mullvad.net>2020-11-19 01:37:02 +0100
commitb72f29cd885c2e9c02b27f72cd93683aba253e8d (patch)
tree2ae9c173dd125573d34f0d0eb1e8638110390fe5
parente3f66f7dc55fb68efbb605b21aa66336ea653c7a (diff)
parent2c6cd3a4797821984e1c212803890276b0ef3626 (diff)
downloadmullvadvpn-b72f29cd885c2e9c02b27f72cd93683aba253e8d.tar.xz
mullvadvpn-b72f29cd885c2e9c02b27f72cd93683aba253e8d.zip
Merge branch 'update-api-ip-cache'
-rw-r--r--.gitignore1
-rw-r--r--CHANGELOG.md2
-rw-r--r--Cargo.lock1
-rw-r--r--android/build.gradle1
-rwxr-xr-xbuild.sh1
-rw-r--r--dist-assets/linux/before-install.sh1
-rwxr-xr-xdist-assets/pkg-scripts/preinstall5
-rw-r--r--dist-assets/windows/installer.nsh35
-rw-r--r--gui/tasks/distribution.js1
-rw-r--r--mullvad-daemon/src/lib.rs5
-rw-r--r--mullvad-problem-report/src/lib.rs7
-rw-r--r--mullvad-rpc/Cargo.toml4
-rw-r--r--mullvad-rpc/src/address_cache.rs124
-rw-r--r--mullvad-rpc/src/bin/address_cache.rs39
-rw-r--r--mullvad-rpc/src/lib.rs46
-rw-r--r--mullvad-setup/src/main.rs23
-rwxr-xr-xupdate-api-address.sh6
-rw-r--r--windows/nsis-plugins/src/cleanup/cleaningops.cpp14
-rw-r--r--windows/nsis-plugins/src/cleanup/cleaningops.h1
-rw-r--r--windows/nsis-plugins/src/cleanup/cleanup.cpp31
-rw-r--r--windows/nsis-plugins/src/cleanup/cleanup.def1
21 files changed, 283 insertions, 66 deletions
diff --git a/.gitignore b/.gitignore
index 9db2f0d726..3cbba48396 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,6 +11,7 @@
.DS_Store
*.log
/dist-assets/relays.json
+/dist-assets/api-ip-address.txt
/dist-assets/mullvad
/dist-assets/mullvad.exe
/dist-assets/mullvad-daemon
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6706c48985..c7bcd6ad37 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -38,6 +38,8 @@ Line wrap the file at 100 chars. Th
### Changed
- Use the API to fetch API IP addresses instead of DNS.
- Remove WireGuard keys during uninstallation after the firewall is unlocked.
+- Randomly select addresses to use for communicating with the API.
+- Bundle a list of API addresses to use instead of assuming that the primary address can be reached.
#### Android
- Remove the Quit button.
diff --git a/Cargo.lock b/Cargo.lock
index 2819952a10..0d7cbadde1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1385,6 +1385,7 @@ dependencies = [
"ipnetwork",
"log 0.4.11",
"mullvad-types",
+ "rand",
"regex",
"serde",
"serde_json",
diff --git a/android/build.gradle b/android/build.gradle
index e9307b1df6..9bfb4d23c3 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -108,5 +108,6 @@ buildscript {
task copyExtraAssets(type: Copy) {
from "$repoRootPath/dist-assets"
include "relays.json"
+ include "api-ip-address.txt"
into extraAssetsDirectory
}
diff --git a/build.sh b/build.sh
index 6c171998ef..b30e624773 100755
--- a/build.sh
+++ b/build.sh
@@ -210,6 +210,7 @@ fi
./update-relays.sh
+./update-api-address.sh
pushd "$SCRIPT_DIR/gui"
diff --git a/dist-assets/linux/before-install.sh b/dist-assets/linux/before-install.sh
index fc27f787ae..d3f53a1f40 100644
--- a/dist-assets/linux/before-install.sh
+++ b/dist-assets/linux/before-install.sh
@@ -12,3 +12,4 @@ fi
pkill -x "mullvad-gui" || true
rm -f /var/cache/mullvad-vpn/relays.json
+rm -f /var/cache/mullvad-vpn/api-ip-address.txt
diff --git a/dist-assets/pkg-scripts/preinstall b/dist-assets/pkg-scripts/preinstall
index e03ca867a8..5b56185a58 100755
--- a/dist-assets/pkg-scripts/preinstall
+++ b/dist-assets/pkg-scripts/preinstall
@@ -77,9 +77,10 @@ if [ -d "$OLD_CACHE_DIR" ]; then
rm -rf "$OLD_CACHE_DIR"
fi
-# Remove the existing relay list.
-# There is a risk that it's incompatible with the format this version wants
+# Remove the existing relay and API address cache lists.
+# There is a risk that they're incompatible with the format this version wants
rm "$NEW_CACHE_DIR/relays.json" || true
+rm "$NEW_CACHE_DIR/api-ip-address.txt" || true
# Notify the running daemon that we are going to kill it and replace it with a newer version.
# This will make the daemon save it's state to a file and then lock the firewall to prevent
diff --git a/dist-assets/windows/installer.nsh b/dist-assets/windows/installer.nsh
index a8925cd039..93f62f9703 100644
--- a/dist-assets/windows/installer.nsh
+++ b/dist-assets/windows/installer.nsh
@@ -510,6 +510,40 @@
!define RemoveRelayCache '!insertmacro "RemoveRelayCache"'
#
+# RemoveApiAddressCache
+#
+# Call into helper DLL instructing it to remove all API address cache.
+# Currently, errors are only logged and not propagated.
+#
+!macro RemoveApiAddressCache
+
+ log::Log "RemoveApiAddressCache()"
+
+ Push $0
+ Push $1
+
+ cleanup::RemoveApiAddressCache
+
+ Pop $0
+ Pop $1
+
+ ${If} $0 != ${MULLVAD_SUCCESS}
+ log::Log "Failed to remove address cache: $1"
+ Goto RemoveApiAddressCache_return
+ ${EndIf}
+
+ log::Log "RemoveApiAddressCache() completed successfully"
+
+ RemoveApiAddressCache_return:
+
+ Pop $1
+ Pop $0
+
+!macroend
+
+!define RemoveApiAddressCache '!insertmacro "RemoveApiAddressCache"'
+
+#
# AddCLIToEnvironPath
#
# Add "$INSTDIR\resources" to system env PATH,
@@ -703,6 +737,7 @@
RMDir /r "$LOCALAPPDATA\mullvad-vpn-updater"
${RemoveRelayCache}
+ ${RemoveApiAddressCache}
${ExtractTapDriver}
${InstallTapDriver}
diff --git a/gui/tasks/distribution.js b/gui/tasks/distribution.js
index 56fe2d4318..0623c0b660 100644
--- a/gui/tasks/distribution.js
+++ b/gui/tasks/distribution.js
@@ -23,6 +23,7 @@ const config = {
extraResources: [
{ from: distAssets('ca.crt'), to: '.' },
{ from: distAssets('relays.json'), to: '.' },
+ { from: distAssets('api-ip-address.txt'), to: '.' },
{ from: root('CHANGELOG.md'), to: '.' },
],
diff --git a/mullvad-daemon/src/lib.rs b/mullvad-daemon/src/lib.rs
index 0599cb052a..b4e5dd3279 100644
--- a/mullvad-daemon/src/lib.rs
+++ b/mullvad-daemon/src/lib.rs
@@ -494,9 +494,10 @@ where
let (tunnel_state_machine_shutdown_tx, tunnel_state_machine_shutdown_signal) =
oneshot::channel();
- let mut rpc_runtime = mullvad_rpc::MullvadRpcRuntime::with_cache_dir(
+ let mut rpc_runtime = mullvad_rpc::MullvadRpcRuntime::with_cache(
tokio::runtime::Handle::current(),
- &cache_dir,
+ &resource_dir,
+ Some(&cache_dir),
)
.await
.map_err(Error::InitRpcFactory)?;
diff --git a/mullvad-problem-report/src/lib.rs b/mullvad-problem-report/src/lib.rs
index 1c3fa00461..eac0dd4638 100644
--- a/mullvad-problem-report/src/lib.rs
+++ b/mullvad-problem-report/src/lib.rs
@@ -271,7 +271,12 @@ pub fn send_problem_report(
.build()
.map_err(Error::CreateRuntime)?;
- let mut rpc_manager = mullvad_rpc::MullvadRpcRuntime::new(runtime.handle().clone())
+ let mut rpc_manager = runtime
+ .block_on(mullvad_rpc::MullvadRpcRuntime::with_cache(
+ runtime.handle().clone(),
+ &mullvad_paths::get_resource_dir(),
+ None,
+ ))
.map_err(Error::CreateRpcClientError)?;
let rpc_client = mullvad_rpc::ProblemReportProxy::new(rpc_manager.mullvad_rest_handle());
diff --git a/mullvad-rpc/Cargo.toml b/mullvad-rpc/Cargo.toml
index a5acd75be4..cf27d2e287 100644
--- a/mullvad-rpc/Cargo.toml
+++ b/mullvad-rpc/Cargo.toml
@@ -15,6 +15,7 @@ http = "0.2"
hyper = "0.13"
ipnetwork = "0.16"
log = "0.4"
+rand = "0.7"
regex = "1"
serde = "1"
serde_json = "1.0"
@@ -33,3 +34,6 @@ tempfile = "3.0"
[[bin]]
name = "relay_list"
+
+[[bin]]
+name = "address_cache"
diff --git a/mullvad-rpc/src/address_cache.rs b/mullvad-rpc/src/address_cache.rs
index 7c1859173e..b2181c763b 100644
--- a/mullvad-rpc/src/address_cache.rs
+++ b/mullvad-rpc/src/address_cache.rs
@@ -1,6 +1,8 @@
+use super::API_ADDRESS;
+use rand::seq::SliceRandom;
use std::{
io,
- net::{IpAddr, SocketAddr},
+ net::SocketAddr,
path::Path,
sync::{Arc, Mutex},
};
@@ -9,7 +11,18 @@ use tokio::{
io::{AsyncBufReadExt, AsyncWriteExt, BufReader},
};
-const FALLBACK_API_ADDRESS: (IpAddr, u16) = (crate::API_IP, 443);
+#[derive(err_derive::Error, Debug)]
+#[error(no_from)]
+pub enum Error {
+ #[error(display = "Failed to open the address cache file")]
+ OpenAddressCache(#[error(source)] io::Error),
+
+ #[error(display = "Failed to read the address cache file")]
+ ReadAddressCache(#[error(source)] io::Error),
+
+ #[error(display = "The address cache is empty")]
+ EmptyAddressCache,
+}
#[derive(Clone)]
pub struct AddressCache {
@@ -18,20 +31,24 @@ pub struct AddressCache {
}
impl AddressCache {
- pub fn new() -> Self {
- Self {
- inner: Arc::new(Mutex::new(Default::default())),
- cache_path: None,
- }
+ /// Initialize cache using the given list, and write changes to `cache_path`.
+ pub fn new(addresses: Vec<SocketAddr>, cache_path: Option<Box<Path>>) -> Result<Self, Error> {
+ log::trace!("API address cache: {:?}", addresses);
+
+ let cache = AddressCacheInner::from_addresses(addresses)?;
+ log::debug!("Using API address: {:?}", Self::get_address_inner(&cache));
+
+ let address_cache = Self {
+ inner: Arc::new(Mutex::new(cache)),
+ cache_path: cache_path.map(|cache| Arc::from(cache)),
+ };
+ Ok(address_cache)
}
- pub async fn with_cache(cache_path: Box<Path>) -> Self {
- let cache = AddressCacheInner::from_cache_file(&cache_path)
- .await
- .unwrap_or_default();
- let inner = Arc::new(Mutex::new(cache));
- let cache_path = Some(cache_path.into());
- Self { inner, cache_path }
+ /// Initialize cache using `read_path`, and write changes to `cache_path`.
+ pub async fn from_file(read_path: &Path, cache_path: Option<Box<Path>>) -> Result<Self, Error> {
+ log::debug!("Loading API addresses from {:?}", read_path);
+ Self::new(read_address_file(read_path).await?, cache_path)
}
pub fn get_address(&self) -> SocketAddr {
@@ -43,12 +60,12 @@ impl AddressCache {
fn get_address_inner(inner: &AddressCacheInner) -> SocketAddr {
if inner.addresses.is_empty() {
- return FALLBACK_API_ADDRESS.into();
+ return API_ADDRESS.into();
}
*inner
.addresses
.get(inner.choice % inner.addresses.len())
- .unwrap_or(&FALLBACK_API_ADDRESS.into())
+ .unwrap_or(&API_ADDRESS.into())
}
pub fn register_failure(&self, failed_addr: SocketAddr, err: &dyn std::error::Error) {
@@ -62,16 +79,26 @@ impl AddressCache {
.map(|last_try| last_try == inner.choice)
.unwrap_or(false)
{
- log::error!("HTTP request failed: {}, will try next API address", err);
inner.choice = inner.choice.wrapping_add(1);
+ let new_address = Self::get_address_inner(&inner);
+ log::error!(
+ "HTTP request failed: {}, using address {}. Trying next API address: {}",
+ err,
+ failed_addr,
+ new_address
+ );
}
}
- pub async fn set_addresses(&self, addresses: Vec<SocketAddr>) -> io::Result<()> {
+ pub async fn set_addresses(&self, mut addresses: Vec<SocketAddr>) -> io::Result<()> {
let should_update = {
let mut inner = self.inner.lock().unwrap();
- if addresses != inner.addresses {
+ addresses.sort();
+ let mut current_sorted = inner.addresses.clone();
+ current_sorted.sort();
+ if addresses != current_sorted {
inner.addresses = addresses.clone();
+ inner.shuffle();
inner.choice = 0;
true
} else {
@@ -79,6 +106,7 @@ impl AddressCache {
}
};
if should_update {
+ log::trace!("API address cache: {:?}", addresses);
self.save_to_disk(addresses).await?;
}
Ok(())
@@ -120,37 +148,43 @@ struct AddressCacheInner {
}
impl AddressCacheInner {
- async fn from_cache_file(path: &Path) -> io::Result<Self> {
- let file = fs::File::open(path).await?;
- let mut lines = BufReader::new(file).lines();
- let mut addresses = vec![];
- while let Some(line) = lines.next_line().await? {
- // for line in lines.next_line() {
- match line.trim().parse() {
- Ok(address) => addresses.push(address),
- Err(err) => {
- log::error!("Failed to parse cached address line: {}", err);
- }
- }
- }
-
- if !addresses.contains(&FALLBACK_API_ADDRESS.into()) {
- addresses.push(FALLBACK_API_ADDRESS.into());
+ fn from_addresses(addresses: Vec<SocketAddr>) -> Result<Self, Error> {
+ if addresses.is_empty() {
+ return Err(Error::EmptyAddressCache);
}
-
- Ok(Self {
+ let mut cache = Self {
addresses,
- ..Default::default()
- })
+ choice: 0,
+ last_try: None,
+ };
+ cache.shuffle();
+ Ok(cache)
+ }
+
+ fn shuffle(&mut self) {
+ let mut rng = rand::thread_rng();
+ (&mut self.addresses[..]).shuffle(&mut rng);
}
}
-impl Default for AddressCacheInner {
- fn default() -> Self {
- Self {
- addresses: vec![FALLBACK_API_ADDRESS.into()],
- choice: 0,
- last_try: None,
+async fn read_address_file(path: &Path) -> Result<Vec<SocketAddr>, Error> {
+ let file = fs::File::open(path)
+ .await
+ .map_err(|error| Error::OpenAddressCache(error))?;
+ let mut lines = BufReader::new(file).lines();
+ let mut addresses = vec![];
+ while let Some(line) = lines
+ .next_line()
+ .await
+ .map_err(|error| Error::ReadAddressCache(error))?
+ {
+ // for line in lines.next_line() {
+ match line.trim().parse() {
+ Ok(address) => addresses.push(address),
+ Err(err) => {
+ log::error!("Failed to parse cached address line: {}", err);
+ }
}
}
+ Ok(addresses)
}
diff --git a/mullvad-rpc/src/bin/address_cache.rs b/mullvad-rpc/src/bin/address_cache.rs
new file mode 100644
index 0000000000..efb2501ba9
--- /dev/null
+++ b/mullvad-rpc/src/bin/address_cache.rs
@@ -0,0 +1,39 @@
+/// Generate a first list of IP addresses for Mullvad VPN to use to talk to the API.
+use mullvad_rpc::{rest::Error as RestError, ApiProxy, MullvadRpcRuntime};
+use std::process;
+use talpid_types::ErrorExt;
+
+#[tokio::main]
+async fn main() {
+ let mut runtime =
+ MullvadRpcRuntime::new(tokio::runtime::Handle::current()).expect("Failed to load runtime");
+
+ let api_proxy = ApiProxy::new(runtime.mullvad_rest_handle());
+ let request = api_proxy.get_api_addrs().await;
+
+ let api_list = match request {
+ Ok(api_list) => api_list,
+ Err(RestError::TimeoutError(_)) => {
+ eprintln!("Request timed out");
+ process::exit(2);
+ }
+ Err(e @ RestError::DeserializeError(_)) => {
+ eprintln!(
+ "{}",
+ e.display_chain_with_msg("Failed to deserialize API address list")
+ );
+ process::exit(3);
+ }
+ Err(e) => {
+ eprintln!(
+ "{}",
+ e.display_chain_with_msg("Failed to fetch API address list")
+ );
+ process::exit(1);
+ }
+ };
+
+ for address in api_list {
+ println!("{}", address);
+ }
+}
diff --git a/mullvad-rpc/src/lib.rs b/mullvad-rpc/src/lib.rs
index 69f39b6349..d92be6e8be 100644
--- a/mullvad-rpc/src/lib.rs
+++ b/mullvad-rpc/src/lib.rs
@@ -12,7 +12,7 @@ use std::{
net::{IpAddr, Ipv4Addr, SocketAddr},
path::Path,
};
-use talpid_types::net::wireguard;
+use talpid_types::{net::wireguard, ErrorExt};
pub mod rest;
@@ -35,6 +35,7 @@ pub const INVALID_VOUCHER: &str = "INVALID_VOUCHER";
const API_HOST: &str = "api.mullvad.net";
pub const API_IP_CACHE_FILENAME: &str = "api-ip-address.txt";
const API_IP: IpAddr = IpAddr::V4(Ipv4Addr::new(193, 138, 218, 78));
+const API_ADDRESS: (IpAddr, u16) = (crate::API_IP, 443);
/// A type that helps with the creation of RPC connections.
@@ -48,6 +49,9 @@ pub struct MullvadRpcRuntime {
pub enum Error {
#[error(display = "Failed to construct a rest client")]
RestError(#[error(source)] rest::Error),
+
+ #[error(display = "Failed to load address cache")]
+ AddressCacheError(#[error(source)] address_cache::Error),
}
impl MullvadRpcRuntime {
@@ -56,17 +60,41 @@ impl MullvadRpcRuntime {
Ok(MullvadRpcRuntime {
https_connector: HttpsConnectorWithSni::new(),
handle,
- address_cache: AddressCache::new(),
+ address_cache: AddressCache::new(vec![API_ADDRESS.into()], None)?,
})
}
- /// Create a new `MullvadRpcRuntime` using the specified cache directory.
- pub async fn with_cache_dir(
+ /// Create a new `MullvadRpcRuntime` using the specified directories.
+ /// Try to use the cache directory first, and fall back on the resource directory
+ /// if it fails.
+ pub async fn with_cache(
handle: tokio::runtime::Handle,
- cache_dir: &Path,
+ resource_dir: &Path,
+ cache_dir: Option<&Path>,
) -> Result<Self, Error> {
- let cache_file = cache_dir.join(API_IP_CACHE_FILENAME);
- let address_cache = AddressCache::with_cache(cache_file.into_boxed_path()).await;
+ let resource_file = resource_dir.join(API_IP_CACHE_FILENAME);
+
+ let address_cache = if let Some(cache_dir) = cache_dir {
+ let cache_file = cache_dir.join(API_IP_CACHE_FILENAME);
+ let cache_file_boxed = cache_file.clone().into_boxed_path();
+
+ match AddressCache::from_file(&cache_file, Some(cache_file_boxed.clone())).await {
+ Ok(cache) => cache,
+ Err(error) => {
+ if cache_file.exists() {
+ log::error!(
+ "{}",
+ error.display_chain_with_msg(
+ "Failed to load cached API addresses. Falling back on bundled list"
+ )
+ );
+ }
+ AddressCache::from_file(&resource_file, Some(cache_file_boxed)).await?
+ }
+ }
+ } else {
+ AddressCache::from_file(&resource_file, None).await?
+ };
let https_connector = HttpsConnectorWithSni::new();
@@ -426,6 +454,10 @@ pub struct ApiProxy {
}
impl ApiProxy {
+ pub fn new(handle: rest::MullvadRestHandle) -> Self {
+ Self { handle }
+ }
+
pub async fn get_api_addrs(&self) -> Result<Vec<SocketAddr>, rest::Error> {
let service = self.handle.service.clone();
diff --git a/mullvad-setup/src/main.rs b/mullvad-setup/src/main.rs
index 0e0776fe92..396b86fa2b 100644
--- a/mullvad-setup/src/main.rs
+++ b/mullvad-setup/src/main.rs
@@ -109,12 +109,15 @@ async fn reset_firewall() -> Result<(), Error> {
}
async fn clear_history() -> Result<(), Error> {
- let (cache_path, settings_path) = get_paths()?;
+ let (cache_path, resource_path, settings_path) = get_paths()?;
- let mut rpc_runtime =
- MullvadRpcRuntime::with_cache_dir(tokio::runtime::Handle::current(), &cache_path)
- .await
- .map_err(Error::RpcInitializationError)?;
+ let mut rpc_runtime = MullvadRpcRuntime::with_cache(
+ tokio::runtime::Handle::current(),
+ &resource_path,
+ Some(&cache_path),
+ )
+ .await
+ .map_err(Error::RpcInitializationError)?;
let mut account_history = account_history::AccountHistory::new(
&cache_path,
@@ -131,18 +134,20 @@ async fn clear_history() -> Result<(), Error> {
}
#[cfg(not(windows))]
-fn get_paths() -> Result<(PathBuf, PathBuf), Error> {
+fn get_paths() -> Result<(PathBuf, PathBuf, PathBuf), Error> {
let cache_path = mullvad_paths::cache_dir().map_err(Error::CachePathError)?;
+ let resource_path = mullvad_paths::get_resource_dir();
let settings_path = mullvad_paths::settings_dir().map_err(Error::SettingsPathError)?;
- Ok((cache_path, settings_path))
+ Ok((cache_path, resource_path, settings_path))
}
#[cfg(windows)]
-fn get_paths() -> Result<(PathBuf, PathBuf), Error> {
+fn get_paths() -> Result<(PathBuf, PathBuf, PathBuf), Error> {
let settings_path =
daemon_paths::get_mullvad_daemon_settings_path().map_err(Error::CachePathError)?;
+ let resource_path = mullvad_paths::get_resource_dir();
let cache_path =
daemon_paths::get_mullvad_daemon_cache_path().map_err(Error::SettingsPathError)?;
- Ok((cache_path, settings_path))
+ Ok((cache_path, resource_path, settings_path))
}
diff --git a/update-api-address.sh b/update-api-address.sh
new file mode 100755
index 0000000000..5013a56f61
--- /dev/null
+++ b/update-api-address.sh
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash
+
+echo "Updating API address cache..."
+set -e
+
+cargo +stable run --bin address_cache --release > dist-assets/api-ip-address.txt
diff --git a/windows/nsis-plugins/src/cleanup/cleaningops.cpp b/windows/nsis-plugins/src/cleanup/cleaningops.cpp
index 8653bb50a9..475c78d8b7 100644
--- a/windows/nsis-plugins/src/cleanup/cleaningops.cpp
+++ b/windows/nsis-plugins/src/cleanup/cleaningops.cpp
@@ -331,4 +331,18 @@ void RemoveRelayCacheServiceUser()
std::filesystem::remove(cacheFile);
}
+void RemoveApiAddressCacheServiceUser()
+{
+ const auto localAppData = GetSystemUserLocalAppData();
+ const auto mullvadAppData = std::filesystem::path(localAppData).append(L"Mullvad VPN");
+
+ common::fs::ScopedNativeFileSystem nativeFileSystem;
+
+ common::security::AddAdminToObjectDacl(mullvadAppData, SE_FILE_OBJECT);
+
+ const auto cacheFile = std::filesystem::path(mullvadAppData).append(L"api-ip-address.txt");
+
+ std::filesystem::remove(cacheFile);
+}
+
}
diff --git a/windows/nsis-plugins/src/cleanup/cleaningops.h b/windows/nsis-plugins/src/cleanup/cleaningops.h
index 40ce97e81e..057eb305b8 100644
--- a/windows/nsis-plugins/src/cleanup/cleaningops.h
+++ b/windows/nsis-plugins/src/cleanup/cleaningops.h
@@ -12,5 +12,6 @@ void RemoveSettingsServiceUser();
// Remove only the relay cache, leaving other cache files untouched.
// This is useful when updating the app.
void RemoveRelayCacheServiceUser();
+void RemoveApiAddressCacheServiceUser();
}
diff --git a/windows/nsis-plugins/src/cleanup/cleanup.cpp b/windows/nsis-plugins/src/cleanup/cleanup.cpp
index faef07c2f0..528efb2f7a 100644
--- a/windows/nsis-plugins/src/cleanup/cleanup.cpp
+++ b/windows/nsis-plugins/src/cleanup/cleanup.cpp
@@ -100,3 +100,34 @@ void __declspec(dllexport) NSISCALL RemoveRelayCache
pushint(NsisStatus::GENERAL_ERROR);
}
}
+
+void __declspec(dllexport) NSISCALL RemoveApiAddressCache
+(
+ HWND hwndParent,
+ int string_size,
+ LPTSTR variables,
+ stack_t **stacktop,
+ extra_parameters *extra,
+ ...
+)
+{
+ EXDLL_INIT();
+
+ try
+ {
+ cleaningops::RemoveApiAddressCacheServiceUser();
+
+ pushstring(L"");
+ pushint(NsisStatus::SUCCESS);
+ }
+ catch (const std::exception &err)
+ {
+ pushstring(common::string::ToWide(err.what()).c_str());
+ pushint(NsisStatus::GENERAL_ERROR);
+ }
+ catch (...)
+ {
+ pushstring(L"Unspecified error");
+ pushint(NsisStatus::GENERAL_ERROR);
+ }
+}
diff --git a/windows/nsis-plugins/src/cleanup/cleanup.def b/windows/nsis-plugins/src/cleanup/cleanup.def
index 8752772b8d..779e620691 100644
--- a/windows/nsis-plugins/src/cleanup/cleanup.def
+++ b/windows/nsis-plugins/src/cleanup/cleanup.def
@@ -5,3 +5,4 @@ EXPORTS
RemoveLogsAndCache
RemoveSettings
RemoveRelayCache
+RemoveApiAddressCache