summaryrefslogtreecommitdiffhomepage
path: root/mullvad-daemon/src
diff options
context:
space:
mode:
authorLinus Färnstrand <linus@mullvad.net>2018-01-11 10:47:41 +0100
committerLinus Färnstrand <linus@mullvad.net>2018-01-15 15:54:16 +0100
commitfc4178d7e3329fb1fd0014e4ce349a79eafeca51 (patch)
treee6e557827dd417a626ba1a44a9045c3a8d95b435 /mullvad-daemon/src
parentc50febb59f6f36f829fe56935fd2b0cdcf3ad92f (diff)
downloadmullvadvpn-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.rs32
-rw-r--r--mullvad-daemon/src/main.rs76
-rw-r--r--mullvad-daemon/src/management_interface.rs24
-rw-r--r--mullvad-daemon/src/relays.rs6
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
}));