summaryrefslogtreecommitdiffhomepage
path: root/talpid-core/src
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@mullvad.net>2017-08-17 19:35:00 +0100
committerAndrej Mihajlov <and@mullvad.net>2017-08-17 19:35:00 +0100
commit3416c0c69d33c3247a7e5687dc6778a18d2a693f (patch)
treed8dd11c5947b3db9cb663343025e11e37f48732b /talpid-core/src
parentd49fb3baa06f482f3e839de7a1cda989b884e8f2 (diff)
parentec89d6571d68c07db9b9380aaf4c7bb21ca1b26a (diff)
downloadmullvadvpn-3416c0c69d33c3247a7e5687dc6778a18d2a693f.tar.xz
mullvadvpn-3416c0c69d33c3247a7e5687dc6778a18d2a693f.zip
Merge branch 'spm'
Diffstat (limited to 'talpid-core/src')
-rw-r--r--talpid-core/src/firewall/macos.rs150
-rw-r--r--talpid-core/src/firewall/mod.rs67
-rw-r--r--talpid-core/src/firewall/unix.rs21
-rw-r--r--talpid-core/src/firewall/windows.rs21
-rw-r--r--talpid-core/src/lib.rs6
5 files changed, 265 insertions, 0 deletions
diff --git a/talpid-core/src/firewall/macos.rs b/talpid-core/src/firewall/macos.rs
new file mode 100644
index 0000000000..3bf6bc8db6
--- /dev/null
+++ b/talpid-core/src/firewall/macos.rs
@@ -0,0 +1,150 @@
+use super::{Firewall, SecurityPolicy};
+use net;
+use pfctl;
+
+// alias used to instantiate firewall implementation
+pub type ConcreteFirewall = PacketFilter;
+pub use pfctl::{Error, ErrorKind, Result};
+
+const ANCHOR_NAME: &'static str = "talpid_core";
+
+impl From<net::Endpoint> for pfctl::Endpoint {
+ fn from(endpoint: net::Endpoint) -> Self {
+ pfctl::Endpoint(
+ pfctl::Ip::from(endpoint.address.ip()),
+ pfctl::Port::from(endpoint.address.port()),
+ )
+ }
+}
+
+impl From<net::Endpoint> for pfctl::Proto {
+ fn from(endpoint: net::Endpoint) -> Self {
+ match endpoint.protocol {
+ net::TransportProtocol::Udp => pfctl::Proto::Udp,
+ net::TransportProtocol::Tcp => pfctl::Proto::Tcp,
+ }
+ }
+}
+
+pub struct PacketFilter {
+ pf: pfctl::PfCtl,
+ pf_was_enabled: Option<bool>,
+}
+
+impl Firewall<Error> for PacketFilter {
+ fn new() -> Result<Self> {
+ Ok(
+ PacketFilter {
+ pf: pfctl::PfCtl::new()?,
+ pf_was_enabled: None,
+ },
+ )
+ }
+
+ fn apply_policy(&mut self, policy: SecurityPolicy) -> Result<()> {
+ self.enable()?;
+ self.add_anchor()?;
+ self.set_rules(policy)
+ }
+
+ fn reset_policy(&mut self) -> Result<()> {
+ vec![
+ self.remove_rules(),
+ self.remove_anchor(),
+ self.restore_state(),
+ ]
+ .into_iter()
+ .collect::<Result<Vec<_>>>()
+ .map(|_| ())
+ }
+}
+
+impl PacketFilter {
+ fn set_rules(&mut self, policy: SecurityPolicy) -> Result<()> {
+ let drop_all_rule = pfctl::FilterRuleBuilder::default()
+ .action(pfctl::RuleAction::Drop)
+ .quick(true)
+ .build()?;
+ let allow_dns_rule = pfctl::FilterRuleBuilder::default()
+ .action(pfctl::RuleAction::Pass)
+ .direction(pfctl::Direction::Out)
+ .quick(true)
+ .to(pfctl::Port::One(53, pfctl::PortUnaryModifier::Equal))
+ .keep_state(pfctl::StatePolicy::Keep)
+ .build()?;
+ let mut new_rules = self.get_loopback_rules()?;
+
+ match policy {
+ SecurityPolicy::Connecting(relay_endpoint) => {
+ new_rules.push(Self::get_relay_rule(relay_endpoint)?);
+ }
+ SecurityPolicy::Connected(relay_endpoint, tunnel_interface) => {
+ new_rules.push(Self::get_relay_rule(relay_endpoint)?);
+ new_rules.push(Self::get_tunnel_rule(tunnel_interface)?);
+ }
+ };
+
+ new_rules.push(allow_dns_rule);
+ new_rules.push(drop_all_rule);
+
+ self.pf.set_rules(ANCHOR_NAME, &new_rules)
+ }
+
+ fn get_relay_rule(relay_endpoint: net::Endpoint) -> Result<pfctl::FilterRule> {
+ pfctl::FilterRuleBuilder::default()
+ .action(pfctl::RuleAction::Pass)
+ .direction(pfctl::Direction::Out)
+ .to(relay_endpoint)
+ .proto(relay_endpoint)
+ .keep_state(pfctl::StatePolicy::Keep)
+ .quick(true)
+ .build()
+ }
+
+ fn get_tunnel_rule(tunnel_interface: String) -> Result<pfctl::FilterRule> {
+ pfctl::FilterRuleBuilder::default()
+ .action(pfctl::RuleAction::Pass)
+ .interface(tunnel_interface)
+ .keep_state(pfctl::StatePolicy::Keep)
+ .quick(true)
+ .build()
+ }
+
+ fn get_loopback_rules(&self) -> Result<Vec<pfctl::FilterRule>> {
+ let lo0_rule = pfctl::FilterRuleBuilder::default()
+ .action(pfctl::RuleAction::Pass)
+ .interface("lo0")
+ .keep_state(pfctl::StatePolicy::Keep)
+ .quick(true)
+ .build()?;
+ Ok(vec![lo0_rule])
+ }
+
+ fn remove_rules(&mut self) -> Result<()> {
+ // remove_anchor() does not deactivate active rules
+ self.pf.flush_rules(ANCHOR_NAME, pfctl::RulesetKind::Filter)
+ }
+
+ fn enable(&mut self) -> Result<()> {
+ if self.pf_was_enabled.is_none() {
+ self.pf_was_enabled = Some(self.pf.is_enabled()?);
+ }
+ self.pf.try_enable()
+ }
+
+ fn restore_state(&mut self) -> Result<()> {
+ match self.pf_was_enabled.take() {
+ Some(true) => self.pf.try_enable(),
+ Some(false) => self.pf.try_disable(),
+ None => Ok(()),
+ }
+ }
+
+ fn add_anchor(&mut self) -> Result<()> {
+ self.pf.try_add_anchor(ANCHOR_NAME, pfctl::AnchorKind::Filter)
+ }
+
+ fn remove_anchor(&mut self) -> Result<()> {
+ self.pf.try_remove_anchor(ANCHOR_NAME, pfctl::AnchorKind::Filter)
+ }
+}
diff --git a/talpid-core/src/firewall/mod.rs b/talpid-core/src/firewall/mod.rs
new file mode 100644
index 0000000000..16b8139453
--- /dev/null
+++ b/talpid-core/src/firewall/mod.rs
@@ -0,0 +1,67 @@
+use net::Endpoint;
+
+#[cfg(target_os = "macos")]
+#[path = "macos.rs"]
+mod imp;
+
+#[cfg(all(unix, not(target_os = "macos")))]
+#[path = "unix.rs"]
+mod imp;
+
+#[cfg(windows)]
+#[path = "windows.rs"]
+mod imp;
+
+error_chain!{
+ errors {
+ /// Initialization error
+ FirewallInitError {
+ description("Failed to initialize firewall")
+ }
+ /// Firewall configuration error
+ FirewallConfigurationError {
+ description("Failed to configure firewall")
+ }
+ }
+}
+
+/// A enum that describes firewall rules strategy
+#[derive(Debug, Clone, Eq, PartialEq)]
+pub enum SecurityPolicy {
+ /// Allow traffic only to relay server
+ Connecting(Endpoint),
+
+ /// Allow traffic only to relay server and over tunnel interface
+ Connected(Endpoint, String),
+}
+
+/// Abstract firewall interaction trait
+pub trait Firewall<E: ::std::error::Error> {
+ /// Create new instance of Firewall
+ fn new() -> ::std::result::Result<Self, E> where Self: Sized;
+
+ /// Enable firewall and set firewall rules based on SecurityPolicy
+ fn apply_policy(&mut self, policy: SecurityPolicy) -> ::std::result::Result<(), E>;
+
+ /// Remove firewall rules applied by active SecurityPolicy and
+ /// revert firewall to its original state
+ fn reset_policy(&mut self) -> ::std::result::Result<(), E>;
+}
+
+/// An abstraction around platform specific firewall implementation
+pub struct FirewallProxy(Box<Firewall<imp::Error>>);
+
+impl Firewall<Error> for FirewallProxy {
+ fn new() -> Result<Self> {
+ let firewall = imp::ConcreteFirewall::new().chain_err(|| ErrorKind::FirewallInitError)?;
+ Ok(FirewallProxy(Box::new(firewall) as Box<Firewall<_>>))
+ }
+
+ fn apply_policy(&mut self, policy: SecurityPolicy) -> Result<()> {
+ self.0.apply_policy(policy).chain_err(|| ErrorKind::FirewallConfigurationError)
+ }
+
+ fn reset_policy(&mut self) -> Result<()> {
+ self.0.reset_policy().chain_err(|| ErrorKind::FirewallConfigurationError)
+ }
+}
diff --git a/talpid-core/src/firewall/unix.rs b/talpid-core/src/firewall/unix.rs
new file mode 100644
index 0000000000..7550c3c051
--- /dev/null
+++ b/talpid-core/src/firewall/unix.rs
@@ -0,0 +1,21 @@
+use super::{Firewall, SecurityPolicy};
+
+// alias used to instantiate firewall implementation
+pub type ConcreteFirewall = Netfilter;
+
+error_chain!{}
+
+pub struct Netfilter;
+impl Firewall<Error> for Netfilter {
+ fn new() -> Result<Self> {
+ Ok(Netfilter)
+ }
+
+ fn apply_policy(&mut self, _policy: SecurityPolicy) -> Result<()> {
+ Ok(())
+ }
+
+ fn reset_policy(&mut self) -> Result<()> {
+ Ok(())
+ }
+}
diff --git a/talpid-core/src/firewall/windows.rs b/talpid-core/src/firewall/windows.rs
new file mode 100644
index 0000000000..3405ba12c0
--- /dev/null
+++ b/talpid-core/src/firewall/windows.rs
@@ -0,0 +1,21 @@
+use super::{Firewall, SecurityPolicy};
+
+// alias used to instantiate firewall implementation
+pub type ConcreteFirewall = WindowsFirewall;
+
+error_chain!{}
+
+pub struct WindowsFirewall;
+impl Firewall<Error> for WindowsFirewall {
+ fn new() -> Result<Self> {
+ Ok(WindowsFirewall)
+ }
+
+ fn apply_policy(&mut self, _policy: SecurityPolicy) -> Result<()> {
+ Ok(())
+ }
+
+ fn reset_policy(&mut self) -> Result<()> {
+ Ok(())
+ }
+}
diff --git a/talpid-core/src/lib.rs b/talpid-core/src/lib.rs
index 29ab0377e5..cbdc08886e 100644
--- a/talpid-core/src/lib.rs
+++ b/talpid-core/src/lib.rs
@@ -23,6 +23,9 @@ extern crate jsonrpc_macros;
extern crate talpid_ipc;
extern crate openvpn_plugin;
+#[cfg(target_os = "macos")]
+extern crate pfctl;
+
/// Working with processes.
pub mod process;
@@ -34,3 +37,6 @@ pub mod tunnel;
/// Abstractions and extra features on `std::mpsc`
pub mod mpsc;
+
+/// Abstractions over different firewalls
+pub mod firewall;