diff options
| author | David Lönnhager <david.l@mullvad.net> | 2021-02-15 19:18:52 +0100 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2021-02-15 19:18:52 +0100 |
| commit | bd025c240900012d05eeedc6f04581a021212922 (patch) | |
| tree | 6af05384d9249349694dea64001fe8353e15ff4d | |
| parent | 528b4c434cc2730681b637d3716facb0d9a78e9c (diff) | |
| parent | 5165db7a723911ea7c568e3c0829b81d2baf2f1f (diff) | |
| download | mullvadvpn-bd025c240900012d05eeedc6f04581a021212922.tar.xz mullvadvpn-bd025c240900012d05eeedc6f04581a021212922.zip | |
Merge branch 'relay-list-check'
| -rw-r--r-- | CHANGELOG.md | 1 | ||||
| -rw-r--r-- | mullvad-daemon/src/relays.rs | 20 | ||||
| -rw-r--r-- | mullvad-rpc/src/bin/relay_list.rs | 2 | ||||
| -rw-r--r-- | mullvad-rpc/src/lib.rs | 2 | ||||
| -rw-r--r-- | mullvad-rpc/src/relay_list.rs | 43 | ||||
| -rw-r--r-- | mullvad-rpc/src/rest.rs | 5 | ||||
| -rw-r--r-- | mullvad-types/src/relay_list.rs | 2 |
7 files changed, 57 insertions, 18 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 94c52430ce..ff77257909 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,7 @@ Line wrap the file at 100 chars. Th - Update Electron from 11.0.2 to 11.2.1 which includes a newer Chromium version and security patches. - Allow provider constraint to specify multiple hosting providers. +- Only download a new relay list if it has been modified. #### Android - WireGuard key is now rotated sooner: every four days instead of seven. diff --git a/mullvad-daemon/src/relays.rs b/mullvad-daemon/src/relays.rs index c3c2e7e365..26b855b3b4 100644 --- a/mullvad-daemon/src/relays.rs +++ b/mullvad-daemon/src/relays.rs @@ -140,6 +140,10 @@ impl ParsedRelays { pub fn relays(&self) -> &Vec<Relay> { &self.relays } + + pub fn tag(&self) -> Option<&str> { + self.locations.etag.as_deref() + } } pub struct RelaySelector { @@ -813,7 +817,8 @@ impl RelayListUpdater { futures::select! { _check_update = check_interval.next() => { if download_future.is_terminated() && self.should_update() { - download_future = Box::pin(Self::download_relay_list(self.rpc_client.clone()).fuse()); + let tag = self.parsed_relays.lock().tag().map(|tag| tag.to_string()); + download_future = Box::pin(Self::download_relay_list(self.rpc_client.clone(), tag).fuse()); self.earliest_next_try = Instant::now() + UPDATE_INTERVAL; } }, @@ -826,7 +831,8 @@ impl RelayListUpdater { cmd = cmd_rx.next() => { match cmd { Some(_) => { - self.consume_new_relay_list(self.rpc_client.relay_list().await).await; + let tag = self.parsed_relays.lock().tag().map(|tag| tag.to_string()); + self.consume_new_relay_list(self.rpc_client.relay_list(tag).await).await; }, None => { log::error!("Relay list updater shutting down"); @@ -841,14 +847,15 @@ impl RelayListUpdater { async fn consume_new_relay_list( &mut self, - result: Result<RelayList, mullvad_rpc::rest::Error>, + result: Result<Option<RelayList>, mullvad_rpc::rest::Error>, ) { match result { - Ok(relay_list) => { + Ok(Some(relay_list)) => { if let Err(err) = self.update_cache(relay_list).await { log::error!("Failed to update relay list cache: {}", err); } } + Ok(None) => log::debug!("Relay list is up-to-date"), Err(err) => { log::error!( "Failed to fetch new relay list: {}. Will retry in {} minutes", @@ -875,8 +882,9 @@ impl RelayListUpdater { fn download_relay_list( rpc_handle: RelayListProxy, - ) -> impl Future<Output = Result<RelayList, mullvad_rpc::rest::Error>> + 'static { - let download_futures = move || rpc_handle.relay_list(); + tag: Option<String>, + ) -> impl Future<Output = Result<Option<RelayList>, mullvad_rpc::rest::Error>> + 'static { + let download_futures = move || rpc_handle.relay_list(tag.clone()); let exponential_backoff = ExponentialBackoff::from_millis(EXPONENTIAL_BACKOFF_DELAY_MS) .factor(EXPONENTIAL_BACKOFF_FACTOR) diff --git a/mullvad-rpc/src/bin/relay_list.rs b/mullvad-rpc/src/bin/relay_list.rs index 8213d736da..e3ca00a9bc 100644 --- a/mullvad-rpc/src/bin/relay_list.rs +++ b/mullvad-rpc/src/bin/relay_list.rs @@ -10,7 +10,7 @@ async fn main() { MullvadRpcRuntime::new(tokio::runtime::Handle::current()).expect("Failed to load runtime"); let relay_list_request = RelayListProxy::new(runtime.mullvad_rest_handle()) - .relay_list() + .relay_list(None) .await; let relay_list = match relay_list_request { diff --git a/mullvad-rpc/src/lib.rs b/mullvad-rpc/src/lib.rs index 7fd3a2480f..1b02ec0f2e 100644 --- a/mullvad-rpc/src/lib.rs +++ b/mullvad-rpc/src/lib.rs @@ -365,7 +365,7 @@ impl AppVersionProxy { async move { let mut request = request?; - request.add_header("M-Platform-Version", platform_version)?; + request.add_header("M-Platform-Version", &platform_version)?; let response = service.request(request).await?; let parsed_response = rest::parse_rest_response(response, StatusCode::OK).await?; diff --git a/mullvad-rpc/src/relay_list.rs b/mullvad-rpc/src/relay_list.rs index b6784d3fda..847c0687de 100644 --- a/mullvad-rpc/src/relay_list.rs +++ b/mullvad-rpc/src/relay_list.rs @@ -1,7 +1,7 @@ /// A module dedicated to retrieving the relay list from the master API. use crate::rest; -use hyper::{Method, StatusCode}; +use hyper::{header, Method, StatusCode}; use mullvad_types::{location, relay_list}; use talpid_types::net::wireguard; @@ -27,7 +27,10 @@ impl RelayListProxy { } /// Fetch the relay list - pub fn relay_list(&self) -> impl Future<Output = Result<relay_list::RelayList, rest::Error>> { + pub fn relay_list( + &self, + etag: Option<String>, + ) -> impl Future<Output = Result<Option<relay_list::RelayList>, rest::Error>> { let service = self.handle.service.clone(); let request = self.handle.factory.request("/v1/relays", Method::GET); @@ -35,13 +38,34 @@ impl RelayListProxy { let mut request = request?; request.set_timeout(RELAY_LIST_TIMEOUT); + if let Some(ref tag) = etag { + request.add_header(header::IF_NONE_MATCH, tag)?; + } + let response = service.request(request).await?; + if etag.is_some() && response.status() == StatusCode::NOT_MODIFIED { + return Ok(None); + } if response.status() != StatusCode::OK { return rest::handle_error_response(response).await; } - Ok(rest::deserialize_body::<ServerRelayList>(response) - .await? - .into_relay_list()) + + let etag = response + .headers() + .get(header::ETAG) + .and_then(|tag| match tag.to_str() { + Ok(tag) => Some(tag.to_string()), + Err(_) => { + log::error!("Ignoring invalid tag from server: {:?}", tag.as_bytes()); + None + } + }); + + Ok(Some( + rest::deserialize_body::<ServerRelayList>(response) + .await? + .into_relay_list(etag), + )) }; future } @@ -57,7 +81,7 @@ struct ServerRelayList { } impl ServerRelayList { - fn into_relay_list(self) -> relay_list::RelayList { + fn into_relay_list(self, etag: Option<String>) -> relay_list::RelayList { let mut countries = BTreeMap::new(); let Self { locations, @@ -88,8 +112,13 @@ impl ServerRelayList { Self::add_wireguard_relays(&mut countries, wireguard); Self::add_bridge_relays(&mut countries, bridge); - relay_list::RelayList { + etag: etag.map(|mut tag| { + if tag.starts_with("\"") { + tag.insert_str(0, "W/"); + } + tag + }), countries: countries .into_iter() .map(|(_key, country)| country) diff --git a/mullvad-rpc/src/rest.rs b/mullvad-rpc/src/rest.rs index 07746a3150..d21e20fbcd 100644 --- a/mullvad-rpc/src/rest.rs +++ b/mullvad-rpc/src/rest.rs @@ -342,9 +342,8 @@ impl RestRequest { self.timeout } - pub fn add_header(&mut self, key: &'static str, value: String) -> Result<()> { - let header_value = - http::HeaderValue::from_str(&value).map_err(Error::InvalidHeaderError)?; + pub fn add_header<T: header::IntoHeaderName>(&mut self, key: T, value: &str) -> Result<()> { + let header_value = http::HeaderValue::from_str(value).map_err(Error::InvalidHeaderError)?; self.request.headers_mut().insert(key, header_value); Ok(()) } diff --git a/mullvad-types/src/relay_list.rs b/mullvad-types/src/relay_list.rs index c3bbc33b6f..863e704792 100644 --- a/mullvad-types/src/relay_list.rs +++ b/mullvad-types/src/relay_list.rs @@ -21,12 +21,14 @@ use talpid_types::net::{ #[cfg_attr(target_os = "android", derive(IntoJava))] #[cfg_attr(target_os = "android", jnix(package = "net.mullvad.mullvadvpn.model"))] pub struct RelayList { + pub etag: Option<String>, pub countries: Vec<RelayListCountry>, } impl RelayList { pub fn empty() -> Self { Self { + etag: None, countries: Vec::new(), } } |
