diff options
| author | Linus Färnstrand <linus@mullvad.net> | 2018-01-11 10:47:41 +0100 |
|---|---|---|
| committer | Linus Färnstrand <linus@mullvad.net> | 2018-01-15 15:54:16 +0100 |
| commit | fc4178d7e3329fb1fd0014e4ce349a79eafeca51 (patch) | |
| tree | e6e557827dd417a626ba1a44a9045c3a8d95b435 /mullvad-daemon/src | |
| parent | c50febb59f6f36f829fe56935fd2b0cdcf3ad92f (diff) | |
| download | mullvadvpn-fc4178d7e3329fb1fd0014e4ce349a79eafeca51.tar.xz mullvadvpn-fc4178d7e3329fb1fd0014e4ce349a79eafeca51.zip | |
Download geoip data from am.i.mullvad on request
Diffstat (limited to 'mullvad-daemon/src')
| -rw-r--r-- | mullvad-daemon/src/geoip.rs | 32 | ||||
| -rw-r--r-- | mullvad-daemon/src/main.rs | 76 | ||||
| -rw-r--r-- | mullvad-daemon/src/management_interface.rs | 24 | ||||
| -rw-r--r-- | mullvad-daemon/src/relays.rs | 6 |
4 files changed, 84 insertions, 54 deletions
diff --git a/mullvad-daemon/src/geoip.rs b/mullvad-daemon/src/geoip.rs new file mode 100644 index 0000000000..4118ed7871 --- /dev/null +++ b/mullvad-daemon/src/geoip.rs @@ -0,0 +1,32 @@ +use futures::{self, Future}; +use mullvad_rpc; +use mullvad_types::location::GeoIpLocation; +use serde_json; + + +static URI: &str = "https://am.i.mullvad.net/json"; + +error_chain! { + errors { + NoResponse { description("The request was dropped without any response") } + } + links { + Transport(mullvad_rpc::rest::Error, mullvad_rpc::rest::ErrorKind); + } + foreign_links { + Deserialize(serde_json::error::Error); + } +} + +pub fn send_location_request( + request_sender: mullvad_rpc::rest::RequestSender, +) -> Box<Future<Item = GeoIpLocation, Error = Error>> { + let (response_tx, response_rx) = futures::sync::oneshot::channel(); + let request = mullvad_rpc::rest::create_get_request(URI.parse().unwrap()); + let future = futures::Sink::send(request_sender, (request, response_tx)) + .map_err(|e| Error::with_chain(e, ErrorKind::NoResponse)) + .and_then(|_| response_rx.map_err(|e| Error::with_chain(e, ErrorKind::NoResponse))) + .and_then(|response_result| response_result.map_err(Error::from)) + .and_then(|response| serde_json::from_slice(&response).map_err(Error::from)); + Box::new(future) +} diff --git a/mullvad-daemon/src/main.rs b/mullvad-daemon/src/main.rs index 32c86330f2..0668d09b6e 100644 --- a/mullvad-daemon/src/main.rs +++ b/mullvad-daemon/src/main.rs @@ -30,6 +30,7 @@ extern crate jsonrpc_ws_server; #[macro_use] extern crate lazy_static; extern crate rand; +extern crate tokio_core; extern crate tokio_timer; extern crate uuid; @@ -39,13 +40,14 @@ extern crate talpid_core; extern crate talpid_ipc; extern crate talpid_types; +mod account_history; mod cli; +mod geoip; mod management_interface; mod relays; mod rpc_info; mod settings; mod shutdown; -mod account_history; use app_dirs::AppInfo; @@ -57,14 +59,14 @@ use management_interface::{BoxFuture, ManagementInterfaceServer, TunnelCommand}; use mullvad_rpc::{AccountsProxy, HttpHandle}; use mullvad_types::account::{AccountData, AccountToken}; -use mullvad_types::location::Location; +use mullvad_types::location::GeoIpLocation; use mullvad_types::relay_constraints::{RelaySettings, RelaySettingsUpdate}; use mullvad_types::relay_list::{Relay, RelayList}; use mullvad_types::states::{DaemonState, SecurityState, TargetState}; use std::env; use std::io; -use std::net::{IpAddr, Ipv4Addr}; +use std::net::IpAddr; use std::path::{Path, PathBuf}; use std::sync::{mpsc, Arc, Mutex}; use std::thread; @@ -188,6 +190,8 @@ struct Daemon { management_interface_broadcaster: management_interface::EventBroadcaster, settings: settings::Settings, accounts_proxy: AccountsProxy<HttpHandle>, + http_handle: mullvad_rpc::rest::RequestSender, + tokio_remote: tokio_core::reactor::Remote, relay_selector: relays::RelaySelector, firewall: FirewallProxy, current_relay: Option<Relay>, @@ -201,11 +205,18 @@ impl Daemon { pub fn new(tunnel_log: Option<PathBuf>) -> Result<Self> { let resource_dir = get_resource_dir(); - let rpc_http_handle = mullvad_rpc::event_loop::create(|core| { - mullvad_rpc::shared(&core.handle()) - }).chain_err(|| "Unable to initialize network event loop")?; + let (rpc_handle, http_handle, tokio_remote) = + mullvad_rpc::event_loop::create(|core| { + let handle = core.handle(); + let rpc = mullvad_rpc::shared(&handle); + let http = mullvad_rpc::rest::create_http_client(&handle); + let remote = core.remote(); + (rpc, http, remote) + }).chain_err(|| "Unable to initialize network event loop")?; + let rpc_handle = rpc_handle.chain_err(|| "Unable to create RPC client")?; + let http_handle = http_handle.chain_err(|| "Unable to create HTTP client")?; - let relay_selector = Self::create_relay_selector(rpc_http_handle.clone(), &resource_dir)?; + let relay_selector = Self::create_relay_selector(rpc_handle.clone(), &resource_dir)?; let (tx, rx) = mpsc::channel(); let management_interface_broadcaster = Self::start_management_interface(tx.clone())?; @@ -224,7 +235,9 @@ impl Daemon { tx, management_interface_broadcaster, settings: settings::Settings::load().chain_err(|| "Unable to read settings")?, - accounts_proxy: AccountsProxy::new(rpc_http_handle), + accounts_proxy: AccountsProxy::new(rpc_handle), + http_handle, + tokio_remote, relay_selector, firewall: FirewallProxy::new().chain_err(|| ErrorKind::FirewallError)?, current_relay: None, @@ -236,10 +249,10 @@ impl Daemon { } fn create_relay_selector( - rpc_http_handle: mullvad_rpc::HttpHandle, + rpc_handle: mullvad_rpc::HttpHandle, resource_dir: &Path, ) -> Result<relays::RelaySelector> { - let mut relay_selector = relays::RelaySelector::new(rpc_http_handle, &resource_dir) + let mut relay_selector = relays::RelaySelector::new(rpc_handle, &resource_dir) .chain_err(|| "Unable to initialize relay list cache")?; if let Ok(elapsed) = relay_selector.get_last_updated().elapsed() { if elapsed > *MAX_RELAY_CACHE_AGE { @@ -351,7 +364,6 @@ impl Daemon { match event { SetTargetState(state) => self.on_set_target_state(state), GetState(tx) => Ok(self.on_get_state(tx)), - GetPublicIp(tx) => Ok(self.on_get_ip(tx)), GetCurrentLocation(tx) => Ok(self.on_get_current_location(tx)), GetAccountData(tx, account_token) => Ok(self.on_get_account_data(tx, account_token)), GetRelayLocations(tx) => Ok(self.on_get_relay_locations(tx)), @@ -378,28 +390,28 @@ impl Daemon { Self::oneshot_send(tx, self.last_broadcasted_state, "current state"); } - fn on_get_ip(&self, tx: OneshotSender<IpAddr>) { - let ip = if let Some(ref relay) = self.current_relay { - IpAddr::V4(relay.ipv4_addr_exit) + fn on_get_current_location(&self, tx: OneshotSender<GeoIpLocation>) { + if let Some(ref relay) = self.current_relay { + let location = relay.location.as_ref().cloned().unwrap(); + let geo_ip_location = GeoIpLocation { + ip: IpAddr::V4(relay.ipv4_addr_exit), + country: location.country, + city: Some(location.city), + latitude: location.latitude, + longitude: location.longitude, + mullvad_exit_ip: true, + }; + Self::oneshot_send(tx, geo_ip_location, "current location"); } else { - IpAddr::V4(Ipv4Addr::new(1, 3, 3, 7)) - }; - Self::oneshot_send(tx, ip, "current ip"); - } - - fn on_get_current_location(&self, tx: OneshotSender<Location>) { - let location = if let Some(ref relay) = self.current_relay { - relay.location.as_ref().cloned().unwrap() - } else { - Location { - country: String::from("Narnia"), - country_code: String::from("na"), - city: String::from("Le City"), - city_code: String::from("le"), - position: [13.37, 0.0], - } - }; - Self::oneshot_send(tx, location, "current location"); + let http_handle = self.http_handle.clone(); + self.tokio_remote.spawn(move |_| { + geoip::send_location_request(http_handle) + .map(move |location| Self::oneshot_send(tx, location, "current location")) + .map_err(|e| { + warn!("Unable to fetch GeoIP location: {}", e.display_chain()); + }) + }); + } } fn on_get_account_data( diff --git a/mullvad-daemon/src/management_interface.rs b/mullvad-daemon/src/management_interface.rs index 5bb79e8d14..3f3795183c 100644 --- a/mullvad-daemon/src/management_interface.rs +++ b/mullvad-daemon/src/management_interface.rs @@ -9,7 +9,7 @@ use jsonrpc_pubsub::{PubSubHandler, PubSubMetadata, Session, SubscriptionId}; use jsonrpc_ws_server; use mullvad_rpc; use mullvad_types::account::{AccountData, AccountToken}; -use mullvad_types::location::Location; +use mullvad_types::location::GeoIpLocation; use mullvad_types::relay_constraints::{RelaySettings, RelaySettingsUpdate}; use mullvad_types::relay_list::RelayList; @@ -19,7 +19,6 @@ use serde; use std::collections::HashMap; use std::collections::hash_map::Entry; -use std::net::IpAddr; use std::sync::{Arc, Mutex, RwLock}; use std::sync::atomic::{AtomicBool, Ordering}; use talpid_core::mpsc::IntoSender; @@ -99,14 +98,10 @@ build_rpc_trait! { #[rpc(meta, name = "get_state")] fn get_state(&self, Self::Metadata) -> BoxFuture<DaemonState, Error>; - /// Returns the current public IP of this computer. - #[rpc(meta, name = "get_public_ip")] - fn get_public_ip(&self, Self::Metadata) -> BoxFuture<IpAddr, Error>; - /// Performs a geoIP lookup and returns the current location as perceived by the public /// internet. #[rpc(meta, name = "get_current_location")] - fn get_current_location(&self, Self::Metadata) -> BoxFuture<Location, Error>; + fn get_current_location(&self, Self::Metadata) -> BoxFuture<GeoIpLocation, Error>; /// Makes the daemon exit its main loop and quit. #[rpc(meta, name = "shutdown")] @@ -149,10 +144,8 @@ pub enum TunnelCommand { SetTargetState(TargetState), /// Request the current state. GetState(OneshotSender<DaemonState>), - /// Get the current IP as viewed from the internet. - GetPublicIp(OneshotSender<IpAddr>), /// Get the current geographical location. - GetCurrentLocation(OneshotSender<Location>), + GetCurrentLocation(OneshotSender<GeoIpLocation>), /// Request the metadata for an account. GetAccountData( OneshotSender<BoxFuture<AccountData, mullvad_rpc::Error>>, @@ -505,16 +498,7 @@ impl<T: From<TunnelCommand> + 'static + Send> ManagementInterfaceApi for Managem Box::new(future) } - fn get_public_ip(&self, meta: Self::Metadata) -> BoxFuture<IpAddr, Error> { - trace!("get_public_ip"); - try_future!(self.check_auth(&meta)); - let (tx, rx) = sync::oneshot::channel(); - let future = self.send_command_to_daemon(TunnelCommand::GetPublicIp(tx)) - .and_then(|_| rx.map_err(|_| Error::internal_error())); - Box::new(future) - } - - fn get_current_location(&self, meta: Self::Metadata) -> BoxFuture<Location, Error> { + fn get_current_location(&self, meta: Self::Metadata) -> BoxFuture<GeoIpLocation, Error> { trace!("get_current_location"); try_future!(self.check_auth(&meta)); let (tx, rx) = sync::oneshot::channel(); diff --git a/mullvad-daemon/src/relays.rs b/mullvad-daemon/src/relays.rs index 299a0f940b..f19feb8edb 100644 --- a/mullvad-daemon/src/relays.rs +++ b/mullvad-daemon/src/relays.rs @@ -269,14 +269,16 @@ impl RelaySelector { city.has_active_relays = !city.relays.is_empty(); let city_name = city.name.clone(); let city_code = city.code.clone(); - let position = city.position; + let latitude = city.latitude; + let longitude = city.longitude; relays.extend(city.relays.drain(..).map(|mut relay| { relay.location = Some(Location { country: country_name.clone(), country_code: country_code.clone(), city: city_name.clone(), city_code: city_code.clone(), - position, + latitude, + longitude, }); relay })); |
