diff options
| author | Emīls Piņķis <emils@mullvad.net> | 2019-02-27 21:47:47 +0000 |
|---|---|---|
| committer | Emīls Piņķis <emils@mullvad.net> | 2019-02-27 21:47:47 +0000 |
| commit | 94efa3bd621ede90485a5e5a9e8da933495ca2af (patch) | |
| tree | 442d165cba1faeb87e5d36ca933d23a514fceab4 | |
| parent | 502bf6fa28820fcfe9f1a16bf208d09191792cd7 (diff) | |
| parent | 976cc61f561095cd6fd9fb0d0c2cd0aba65dcb5d (diff) | |
| download | mullvadvpn-94efa3bd621ede90485a5e5a9e8da933495ca2af.tar.xz mullvadvpn-94efa3bd621ede90485a5e5a9e8da933495ca2af.zip | |
Merge branch 'allow-icmp-to-gateways-when-connecting'
| -rw-r--r-- | talpid-core/src/firewall/linux.rs | 27 | ||||
| -rw-r--r-- | talpid-core/src/firewall/macos.rs | 41 | ||||
| -rw-r--r-- | talpid-core/src/firewall/mod.rs | 12 | ||||
| -rw-r--r-- | talpid-core/src/firewall/windows.rs | 2 | ||||
| -rw-r--r-- | talpid-core/src/tunnel/wireguard/mod.rs | 7 | ||||
| -rw-r--r-- | talpid-core/src/tunnel_state_machine/connecting_state.rs | 32 |
6 files changed, 104 insertions, 17 deletions
diff --git a/talpid-core/src/firewall/linux.rs b/talpid-core/src/firewall/linux.rs index 2743b9d318..ffec0bc1fd 100644 --- a/talpid-core/src/firewall/linux.rs +++ b/talpid-core/src/firewall/linux.rs @@ -273,8 +273,10 @@ impl<'a> PolicyBatch<'a> { let allow_lan = match policy { FirewallPolicy::Connecting { peer_endpoint, + pingable_hosts, allow_lan, } => { + self.add_allow_icmp_pingable_hosts(&pingable_hosts)?; self.add_allow_endpoint_rules(peer_endpoint)?; *allow_lan } @@ -320,6 +322,31 @@ impl<'a> PolicyBatch<'a> { Ok(()) } + fn add_allow_icmp_pingable_hosts(&mut self, pingable_hosts: &[IpAddr]) -> Result<()> { + for host in pingable_hosts { + let icmp_proto = match &host { + &IpAddr::V4(_) => libc::IPPROTO_ICMP as u8, + &IpAddr::V6(_) => libc::IPPROTO_ICMPV6 as u8, + }; + + let mut out_rule = Rule::new(&self.out_chain)?; + check_ip(&mut out_rule, End::Dst, *host)?; + out_rule.add_expr(&nft_expr!(meta l4proto))?; + out_rule.add_expr(&nft_expr!(cmp == icmp_proto))?; + add_verdict(&mut out_rule, &Verdict::Accept)?; + self.batch.add(&out_rule, nftnl::MsgType::Add)?; + + let mut in_rule = Rule::new(&self.in_chain)?; + check_ip(&mut in_rule, End::Src, *host)?; + in_rule.add_expr(&nft_expr!(meta l4proto))?; + in_rule.add_expr(&nft_expr!(cmp == icmp_proto))?; + add_verdict(&mut in_rule, &Verdict::Accept)?; + self.batch.add(&in_rule, nftnl::MsgType::Add)?; + } + + Ok(()) + } + fn add_dns_rule( &mut self, tunnel: &tunnel::TunnelMetadata, diff --git a/talpid-core/src/firewall/macos.rs b/talpid-core/src/firewall/macos.rs index 6662539dc9..b411c58a9a 100644 --- a/talpid-core/src/firewall/macos.rs +++ b/talpid-core/src/firewall/macos.rs @@ -1,6 +1,9 @@ use super::{FirewallPolicy, FirewallT}; use pfctl::FilterRuleAction; -use std::{env, net::Ipv4Addr}; +use std::{ + env, + net::{IpAddr, Ipv4Addr}, +}; use talpid_types::net; pub use pfctl::Error; @@ -85,8 +88,10 @@ impl Firewall { FirewallPolicy::Connecting { peer_endpoint, allow_lan, + pingable_hosts, } => { let mut rules = vec![self.get_allow_relay_rule(peer_endpoint)?]; + rules.extend(self.get_allow_pingable_hosts(&pingable_hosts)?); if allow_lan { rules.append(&mut self.get_allow_lan_rules()?); } @@ -166,6 +171,40 @@ impl Firewall { .build()?) } + fn get_allow_pingable_hosts( + &self, + pingable_hosts: &[IpAddr], + ) -> Result<Vec<pfctl::FilterRule>> { + let mut rules = vec![]; + for host in pingable_hosts.iter() { + let icmp_proto = match &host { + IpAddr::V4(_) => pfctl::Proto::Icmp, + IpAddr::V6(_) => pfctl::Proto::IcmpV6, + }; + + let out_rule = self + .create_rule_builder(FilterRuleAction::Pass) + .direction(pfctl::Direction::Out) + .to(pfctl::Endpoint::new(*host, 0)) + .proto(icmp_proto) + .keep_state(pfctl::StatePolicy::Keep) + .quick(true) + .build()?; + rules.push(out_rule); + + let in_rule = self + .create_rule_builder(FilterRuleAction::Pass) + .direction(pfctl::Direction::In) + .from(pfctl::Endpoint::new(*host, 0)) + .proto(icmp_proto) + .keep_state(pfctl::StatePolicy::Keep) + .quick(true) + .build()?; + rules.push(in_rule); + } + Ok(rules) + } + fn get_allow_tunnel_rule(&self, tunnel_interface: &str) -> Result<pfctl::FilterRule> { Ok(self .create_rule_builder(FilterRuleAction::Pass) diff --git a/talpid-core/src/firewall/mod.rs b/talpid-core/src/firewall/mod.rs index b7977bc2cd..059a49e326 100644 --- a/talpid-core/src/firewall/mod.rs +++ b/talpid-core/src/firewall/mod.rs @@ -3,6 +3,8 @@ use ipnetwork::{IpNetwork, Ipv4Network, Ipv6Network}; #[cfg(unix)] use lazy_static::lazy_static; use std::fmt; +#[cfg(windows)] +use std::net::IpAddr; #[cfg(unix)] use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use talpid_types::net::Endpoint; @@ -51,6 +53,8 @@ pub enum FirewallPolicy { Connecting { /// The peer endpoint that should be allowed. peer_endpoint: Endpoint, + /// Hosts that should be pingable whilst connecting. + pingable_hosts: Vec<IpAddr>, /// Flag setting if communication with LAN networks should be possible. allow_lan: bool, }, @@ -77,11 +81,17 @@ impl fmt::Display for FirewallPolicy { match self { FirewallPolicy::Connecting { peer_endpoint, + pingable_hosts, allow_lan, } => write!( f, - "Connecting to {}, {} LAN", + "Connecting to {} with gateways {}, {} LAN", peer_endpoint, + pingable_hosts + .iter() + .map(ToString::to_string) + .collect::<Vec<String>>() + .join(","), if *allow_lan { "Allowing" } else { "Blocking" } ), FirewallPolicy::Connected { diff --git a/talpid-core/src/firewall/windows.rs b/talpid-core/src/firewall/windows.rs index d77a9a3dbd..16702b62f9 100644 --- a/talpid-core/src/firewall/windows.rs +++ b/talpid-core/src/firewall/windows.rs @@ -71,6 +71,8 @@ impl FirewallT for Firewall { match policy { FirewallPolicy::Connecting { peer_endpoint, + // TODO: Allow ICMP traffic to a list of hosts for wireguard + pingable_hosts: _, allow_lan, } => { let cfg = &WinFwSettings::new(allow_lan); diff --git a/talpid-core/src/tunnel/wireguard/mod.rs b/talpid-core/src/tunnel/wireguard/mod.rs index 1707f8170e..71ccee1b44 100644 --- a/talpid-core/src/tunnel/wireguard/mod.rs +++ b/talpid-core/src/tunnel/wireguard/mod.rs @@ -78,6 +78,13 @@ impl WireguardMonitor { monitor.start_pinger(&config); monitor.tunnel_up(&config); + ping_monitor::ping( + config.gateway, + PING_TIMEOUT, + &monitor.tunnel.get_interface_name().to_string(), + ) + .chain_err(|| ErrorKind::PingTimeoutError)?; + Ok(monitor) } diff --git a/talpid-core/src/tunnel_state_machine/connecting_state.rs b/talpid-core/src/tunnel_state_machine/connecting_state.rs index 305fb24383..10c693f5ef 100644 --- a/talpid-core/src/tunnel_state_machine/connecting_state.rs +++ b/talpid-core/src/tunnel_state_machine/connecting_state.rs @@ -1,5 +1,6 @@ use std::{ ffi::OsString, + net::IpAddr, path::{Path, PathBuf}, thread, time::{Duration, Instant}, @@ -12,7 +13,7 @@ use futures::{ }; use log::{debug, error, info, trace, warn}; use talpid_types::{ - net::{openvpn, Endpoint, TunnelParameters}, + net::{openvpn, TunnelParameters}, tunnel::BlockReason, }; @@ -48,10 +49,11 @@ pub struct ConnectingState { impl ConnectingState { fn set_firewall_policy( shared_values: &mut SharedTunnelStateValues, - proxy: &Option<openvpn::ProxySettings>, - endpoint: Endpoint, + params: &TunnelParameters, ) -> Result<()> { - // If a proxy is specified we need to pass it on as the peer endpoint. + let proxy = &get_openvpn_proxy_settings(¶ms); + let endpoint = params.get_tunnel_endpoint().endpoint; + let peer_endpoint = match proxy { Some(proxy_settings) => proxy_settings.get_endpoint(), None => endpoint, @@ -59,6 +61,7 @@ impl ConnectingState { let policy = FirewallPolicy::Connecting { peer_endpoint, + pingable_hosts: gateway_list_from_params(params), allow_lan: shared_values.allow_lan, }; shared_values @@ -175,11 +178,7 @@ impl ConnectingState { match try_handle_event!(self, commands.poll()) { Ok(TunnelCommand::AllowLan(allow_lan)) => { shared_values.allow_lan = allow_lan; - match Self::set_firewall_policy( - shared_values, - &get_openvpn_proxy_settings(&self.tunnel_parameters), - self.tunnel_parameters.get_tunnel_endpoint().endpoint, - ) { + match Self::set_firewall_policy(shared_values, &self.tunnel_parameters) { Ok(()) => SameState(self), Err(error) => { error!("{}", error.display_chain()); @@ -326,12 +325,7 @@ impl TunnelState for ConnectingState { { None => BlockedState::enter(shared_values, BlockReason::NoMatchingRelay), Some(tunnel_parameters) => { - let endpoint = tunnel_parameters.get_tunnel_endpoint().endpoint; - if let Err(error) = Self::set_firewall_policy( - shared_values, - &get_openvpn_proxy_settings(&tunnel_parameters), - endpoint, - ) { + if let Err(error) = Self::set_firewall_policy(shared_values, &tunnel_parameters) { error!("{}", error.display_chain()); BlockedState::enter(shared_values, BlockReason::StartTunnelError) } else { @@ -375,3 +369,11 @@ impl TunnelState for ConnectingState { .or_else(Self::handle_tunnel_close_event, shared_values) } } + +fn gateway_list_from_params(params: &TunnelParameters) -> Vec<IpAddr> { + match params { + TunnelParameters::Wireguard(params) => vec![params.connection.gateway], + // No gateway list required when connecting to openvpn + TunnelParameters::OpenVpn(_) => vec![], + } +} |
