diff options
| author | Linus Färnstrand <linus@mullvad.net> | 2019-02-01 15:44:33 +0100 |
|---|---|---|
| committer | Linus Färnstrand <linus@mullvad.net> | 2019-02-01 15:44:33 +0100 |
| commit | f97c5621fad66ae9768dad8cc422bc3a61f76ef6 (patch) | |
| tree | 78e77793349dc7ff325c08ece8b918d36a029b44 /talpid-core/src | |
| parent | 2139dfb9c37f0d7d6b5e823631bac23b511b38f6 (diff) | |
| parent | 7479f4e46724f7e32e9e34e6c20f32975d7c9dac (diff) | |
| download | mullvadvpn-f97c5621fad66ae9768dad8cc422bc3a61f76ef6.tar.xz mullvadvpn-f97c5621fad66ae9768dad8cc422bc3a61f76ef6.zip | |
Merge branch 'separate-dns-and-firewall'
Diffstat (limited to 'talpid-core/src')
| -rw-r--r-- | talpid-core/src/dns/linux/mod.rs (renamed from talpid-core/src/security/linux/dns/mod.rs) | 2 | ||||
| -rw-r--r-- | talpid-core/src/dns/linux/network_manager.rs (renamed from talpid-core/src/security/linux/dns/network_manager.rs) | 0 | ||||
| -rw-r--r-- | talpid-core/src/dns/linux/resolvconf.rs (renamed from talpid-core/src/security/linux/dns/resolvconf.rs) | 0 | ||||
| -rw-r--r-- | talpid-core/src/dns/linux/static_resolv_conf.rs (renamed from talpid-core/src/security/linux/dns/static_resolv_conf.rs) | 0 | ||||
| -rw-r--r-- | talpid-core/src/dns/linux/systemd_resolved.rs (renamed from talpid-core/src/security/linux/dns/systemd_resolved.rs) | 3 | ||||
| -rw-r--r-- | talpid-core/src/dns/macos.rs (renamed from talpid-core/src/security/macos/dns.rs) | 2 | ||||
| -rw-r--r-- | talpid-core/src/dns/mod.rs | 58 | ||||
| -rw-r--r-- | talpid-core/src/dns/windows/mod.rs (renamed from talpid-core/src/security/windows/dns.rs) | 6 | ||||
| -rw-r--r-- | talpid-core/src/dns/windows/system_state.rs (renamed from talpid-core/src/security/windows/system_state.rs) | 9 | ||||
| -rw-r--r-- | talpid-core/src/ffi.rs (renamed from talpid-core/src/security/windows/ffi.rs) | 0 | ||||
| -rw-r--r-- | talpid-core/src/firewall/linux.rs (renamed from talpid-core/src/security/linux/mod.rs) | 49 | ||||
| -rw-r--r-- | talpid-core/src/firewall/macos.rs (renamed from talpid-core/src/security/macos/mod.rs) | 30 | ||||
| -rw-r--r-- | talpid-core/src/firewall/mod.rs (renamed from talpid-core/src/security/mod.rs) | 100 | ||||
| -rw-r--r-- | talpid-core/src/firewall/windows.rs (renamed from talpid-core/src/security/windows/mod.rs) | 30 | ||||
| -rw-r--r-- | talpid-core/src/lib.rs | 16 | ||||
| -rw-r--r-- | talpid-core/src/linux.rs | 27 | ||||
| -rw-r--r-- | talpid-core/src/tunnel_state_machine/blocked_state.rs | 16 | ||||
| -rw-r--r-- | talpid-core/src/tunnel_state_machine/connected_state.rs | 18 | ||||
| -rw-r--r-- | talpid-core/src/tunnel_state_machine/connecting_state.rs | 16 | ||||
| -rw-r--r-- | talpid-core/src/tunnel_state_machine/disconnected_state.rs | 20 | ||||
| -rw-r--r-- | talpid-core/src/tunnel_state_machine/mod.rs | 16 |
21 files changed, 218 insertions, 200 deletions
diff --git a/talpid-core/src/security/linux/dns/mod.rs b/talpid-core/src/dns/linux/mod.rs index 74267e2c19..17ec6b7e39 100644 --- a/talpid-core/src/security/linux/dns/mod.rs +++ b/talpid-core/src/dns/linux/mod.rs @@ -31,7 +31,7 @@ pub struct DnsMonitor { inner: Option<DnsMonitorHolder>, } -impl super::super::DnsMonitorT for DnsMonitor { +impl super::DnsMonitorT for DnsMonitor { type Error = Error; fn new(_cache_dir: impl AsRef<Path>) -> Result<Self> { diff --git a/talpid-core/src/security/linux/dns/network_manager.rs b/talpid-core/src/dns/linux/network_manager.rs index 73d49eb1a8..73d49eb1a8 100644 --- a/talpid-core/src/security/linux/dns/network_manager.rs +++ b/talpid-core/src/dns/linux/network_manager.rs diff --git a/talpid-core/src/security/linux/dns/resolvconf.rs b/talpid-core/src/dns/linux/resolvconf.rs index 32b8fcd6b9..32b8fcd6b9 100644 --- a/talpid-core/src/security/linux/dns/resolvconf.rs +++ b/talpid-core/src/dns/linux/resolvconf.rs diff --git a/talpid-core/src/security/linux/dns/static_resolv_conf.rs b/talpid-core/src/dns/linux/static_resolv_conf.rs index cea1b1ac2f..cea1b1ac2f 100644 --- a/talpid-core/src/security/linux/dns/static_resolv_conf.rs +++ b/talpid-core/src/dns/linux/static_resolv_conf.rs diff --git a/talpid-core/src/security/linux/dns/systemd_resolved.rs b/talpid-core/src/dns/linux/systemd_resolved.rs index f4eac9e486..6734a1819c 100644 --- a/talpid-core/src/security/linux/dns/systemd_resolved.rs +++ b/talpid-core/src/dns/linux/systemd_resolved.rs @@ -1,4 +1,5 @@ -use super::{super::iface_index, RESOLV_CONF_PATH}; +use super::RESOLV_CONF_PATH; +use crate::linux::iface_index; use dbus::{ arg::RefArg, stdintf::*, BusType, Interface, Member, Message, MessageItem, MessageItemArray, Signature, diff --git a/talpid-core/src/security/macos/dns.rs b/talpid-core/src/dns/macos.rs index a1fad021de..d65fdbf6c0 100644 --- a/talpid-core/src/security/macos/dns.rs +++ b/talpid-core/src/dns/macos.rs @@ -126,7 +126,7 @@ pub struct DnsMonitor { state: Arc<Mutex<Option<State>>>, } -impl super::super::DnsMonitorT for DnsMonitor { +impl super::DnsMonitorT for DnsMonitor { type Error = Error; /// Creates and returns a new `DnsMonitor`. This spawns a background thread that will monitor diff --git a/talpid-core/src/dns/mod.rs b/talpid-core/src/dns/mod.rs new file mode 100644 index 0000000000..5353167ea9 --- /dev/null +++ b/talpid-core/src/dns/mod.rs @@ -0,0 +1,58 @@ +use std::{net::IpAddr, path::Path}; + +#[cfg(target_os = "macos")] +#[path = "macos.rs"] +mod imp; + +#[cfg(target_os = "linux")] +#[path = "linux/mod.rs"] +mod imp; + +#[cfg(windows)] +#[path = "windows/mod.rs"] +mod imp; + +pub use self::imp::Error; + +/// Sets and monitors system DNS settings. Makes sure the desired DNS servers are being used. +pub struct DnsMonitor { + inner: imp::DnsMonitor, +} + +impl DnsMonitor { + /// Returns a new `DnsMonitor` that can set and monitor the system DNS. + pub fn new(cache_dir: impl AsRef<Path>) -> Result<Self, Error> { + Ok(DnsMonitor { + inner: imp::DnsMonitor::new(cache_dir)?, + }) + } + + /// Set DNS to the given servers. And start monitoring the system for changes. + pub fn set(&mut self, interface: &str, servers: &[IpAddr]) -> Result<(), Error> { + log::info!( + "Setting DNS servers to {}", + servers + .iter() + .map(|ip| ip.to_string()) + .collect::<Vec<String>>() + .join(", ") + ); + self.inner.set(interface, servers) + } + + /// Reset system DNS settings to what it was before being set by this instance. + pub fn reset(&mut self) -> Result<(), Error> { + log::info!("Resetting DNS"); + self.inner.reset() + } +} + +trait DnsMonitorT: Sized { + type Error: ::std::error::Error; + + fn new(cache_dir: impl AsRef<Path>) -> Result<Self, Self::Error>; + + fn set(&mut self, interface: &str, servers: &[IpAddr]) -> Result<(), Self::Error>; + + fn reset(&mut self) -> Result<(), Self::Error>; +} diff --git a/talpid-core/src/security/windows/dns.rs b/talpid-core/src/dns/windows/mod.rs index 6c04c03e57..dfa239cb81 100644 --- a/talpid-core/src/security/windows/dns.rs +++ b/talpid-core/src/dns/windows/mod.rs @@ -7,10 +7,12 @@ use std::{ ptr, slice, }; +mod system_state; +use self::system_state::SystemStateWriter; + use error_chain::ChainedError; use widestring::WideCString; -use super::system_state::SystemStateWriter; const DNS_STATE_FILENAME: &'static str = "dns-state-backup"; @@ -47,7 +49,7 @@ pub struct DnsMonitor { backup_writer: SystemStateWriter, } -impl super::super::DnsMonitorT for DnsMonitor { +impl super::DnsMonitorT for DnsMonitor { type Error = Error; fn new(cache_dir: impl AsRef<Path>) -> Result<Self> { diff --git a/talpid-core/src/security/windows/system_state.rs b/talpid-core/src/dns/windows/system_state.rs index f5e1d073dd..f2557e7cf7 100644 --- a/talpid-core/src/security/windows/system_state.rs +++ b/talpid-core/src/dns/windows/system_state.rs @@ -8,7 +8,7 @@ use std::{ }; /// This struct is responsible for saving a binary blob to disk. The binary blob is intended to -/// store system state that should be resotred when the security policy is reset. +/// store system DNS settings that should be restored when the DNS settings are reset. pub struct SystemStateWriter { /// Full path to the system state backup file pub backup_path: Box<Path>, @@ -16,15 +16,15 @@ pub struct SystemStateWriter { impl SystemStateWriter { /// Creates a new SystemStateWriter which will use a file in the cache directory to store system - /// state that has to be restored. + /// DNS state that has to be restored. pub fn new<P: AsRef<Path>>(backup_path: P) -> Self { Self { backup_path: backup_path.as_ref().to_owned().into_boxed_path(), } } - /// Writes a binary blob representing the system state to the backup location before any - /// security policies are applied. + /// Writes a binary blob representing the system DNS settings to the backup location before any + /// DNS changes are applied. pub fn write_backup(&self, data: &[u8]) -> io::Result<()> { let mut backup_file = File::create(&self.backup_path)?; backup_file.write_all(data)?; @@ -41,7 +41,6 @@ impl SystemStateWriter { } } - /// Removes a previously created state backup if it exists. pub fn remove_backup(&self) -> io::Result<()> { match fs::remove_file(&self.backup_path) { diff --git a/talpid-core/src/security/windows/ffi.rs b/talpid-core/src/ffi.rs index 6c4d8381d4..6c4d8381d4 100644 --- a/talpid-core/src/security/windows/ffi.rs +++ b/talpid-core/src/ffi.rs diff --git a/talpid-core/src/security/linux/mod.rs b/talpid-core/src/firewall/linux.rs index 76bfef07ac..2743b9d318 100644 --- a/talpid-core/src/security/linux/mod.rs +++ b/talpid-core/src/firewall/linux.rs @@ -1,4 +1,4 @@ -use super::{NetworkSecurityT, SecurityPolicy}; +use super::{FirewallPolicy, FirewallT}; use crate::tunnel; use ipnetwork::IpNetwork; use lazy_static::lazy_static; @@ -11,15 +11,10 @@ use nftnl::{ use std::{ env, ffi::{CStr, CString}, - io, net::{IpAddr, Ipv4Addr}, }; use talpid_types::net::{Endpoint, TransportProtocol}; - -mod dns; -pub use self::dns::{DnsMonitor, Error as DnsError}; - error_chain! { errors { /// Unable to open netlink socket to netfilter @@ -33,15 +28,13 @@ error_chain! { /// Failed to verify that our tables are set. Probably means that /// it's the host does not support nftables properly. NetfilterTableNotSetError{ description("Failed to set firewall rules") } - /// The name is not a valid Linux network interface name - InvalidInterfaceName(name: String) { - description("Invalid network interface name") - display("Invalid network interface name: {}", name) - } } links { Nftnl(nftnl::Error, nftnl::ErrorKind) #[doc = "Error in nftnl"]; } + foreign_links { + IfaceIndexLookupError(crate::linux::IfaceIndexLookupError); + } } lazy_static! { @@ -71,20 +64,20 @@ enum End { } /// The Linux implementation for the firewall and DNS. -pub struct NetworkSecurity { +pub struct Firewall { table_name: CString, } -impl NetworkSecurityT for NetworkSecurity { +impl FirewallT for Firewall { type Error = Error; fn new() -> Result<Self> { - Ok(NetworkSecurity { + Ok(Firewall { table_name: TABLE_NAME.clone(), }) } - fn apply_policy(&mut self, policy: SecurityPolicy) -> Result<()> { + fn apply_policy(&mut self, policy: FirewallPolicy) -> Result<()> { let table = Table::new(&self.table_name, ProtoFamily::Inet)?; let batch = PolicyBatch::new(&table)?.finalize(&policy)?; self.send_and_process(&batch)?; @@ -107,7 +100,7 @@ impl NetworkSecurityT for NetworkSecurity { } } -impl NetworkSecurity { +impl Firewall { fn send_and_process(&self, batch: &FinalizedBatch) -> Result<()> { let socket = mnl::Socket::new(mnl::Bus::Netfilter).chain_err(|| ErrorKind::NetlinkOpenError)?; @@ -213,7 +206,7 @@ impl<'a> PolicyBatch<'a> { /// Finalize the nftnl message batch by adding every firewall rule needed to satisfy the given /// policy. - pub fn finalize(mut self, policy: &SecurityPolicy) -> Result<FinalizedBatch> { + pub fn finalize(mut self, policy: &FirewallPolicy) -> Result<FinalizedBatch> { self.add_loopback_rules()?; self.add_dhcp_rules()?; self.add_policy_specific_rules(policy)?; @@ -276,16 +269,16 @@ impl<'a> PolicyBatch<'a> { Ok(()) } - fn add_policy_specific_rules(&mut self, policy: &SecurityPolicy) -> Result<()> { + fn add_policy_specific_rules(&mut self, policy: &FirewallPolicy) -> Result<()> { let allow_lan = match policy { - SecurityPolicy::Connecting { + FirewallPolicy::Connecting { peer_endpoint, allow_lan, } => { self.add_allow_endpoint_rules(peer_endpoint)?; *allow_lan } - SecurityPolicy::Connected { + FirewallPolicy::Connected { peer_endpoint, tunnel, allow_lan, @@ -296,7 +289,7 @@ impl<'a> PolicyBatch<'a> { self.add_allow_tunnel_rules(tunnel)?; *allow_lan } - SecurityPolicy::Blocked { allow_lan } => *allow_lan, + FirewallPolicy::Blocked { allow_lan } => *allow_lan, }; if allow_lan { @@ -420,7 +413,7 @@ fn allow_interface_rule<'a>( } fn check_iface(rule: &mut Rule, direction: Direction, iface: &str) -> Result<()> { - let iface_index = iface_index(iface)?; + let iface_index = crate::linux::iface_index(iface)?; rule.add_expr(&match direction { Direction::In => nft_expr!(meta iif), Direction::Out => nft_expr!(meta oif), @@ -429,18 +422,6 @@ fn check_iface(rule: &mut Rule, direction: Direction, iface: &str) -> Result<()> Ok(()) } -fn iface_index(name: &str) -> Result<libc::c_uint> { - let c_name = - CString::new(name).chain_err(|| ErrorKind::InvalidInterfaceName(name.to_owned()))?; - let index = unsafe { libc::if_nametoindex(c_name.as_ptr()) }; - if index == 0 { - let error = io::Error::last_os_error(); - Err(error).chain_err(|| ErrorKind::InvalidInterfaceName(name.to_owned())) - } else { - Ok(index) - } -} - fn check_net(rule: &mut Rule, end: End, net: IpNetwork) -> Result<()> { // Must check network layer protocol before loading network layer payload check_l3proto(rule, net.ip())?; diff --git a/talpid-core/src/security/macos/mod.rs b/talpid-core/src/firewall/macos.rs index cc14fbfd6e..6662539dc9 100644 --- a/talpid-core/src/security/macos/mod.rs +++ b/talpid-core/src/firewall/macos.rs @@ -1,14 +1,8 @@ -use super::{NetworkSecurityT, SecurityPolicy}; +use super::{FirewallPolicy, FirewallT}; use pfctl::FilterRuleAction; -use std::{ - env, - net::{Ipv4Addr, SocketAddr}, -}; +use std::{env, net::Ipv4Addr}; use talpid_types::net; -mod dns; -pub use self::dns::{DnsMonitor, Error as DnsError}; - pub use pfctl::Error; type Result<T> = ::std::result::Result<T, Error>; @@ -18,13 +12,13 @@ type Result<T> = ::std::result::Result<T, Error>; const ANCHOR_NAME: &'static str = "mullvad"; /// The macOS firewall and DNS implementation. -pub struct NetworkSecurity { +pub struct Firewall { pf: pfctl::PfCtl, pf_was_enabled: Option<bool>, rule_logging: RuleLogging, } -impl NetworkSecurityT for NetworkSecurity { +impl FirewallT for Firewall { type Error = Error; fn new() -> Result<Self> { @@ -39,14 +33,14 @@ impl NetworkSecurityT for NetworkSecurity { }; log::trace!("Firewall debug log policy: {:?}", rule_logging); - Ok(NetworkSecurity { + Ok(Firewall { pf: pfctl::PfCtl::new()?, pf_was_enabled: None, rule_logging, }) } - fn apply_policy(&mut self, policy: SecurityPolicy) -> Result<()> { + fn apply_policy(&mut self, policy: FirewallPolicy) -> Result<()> { self.enable()?; self.add_anchor()?; self.set_rules(policy) @@ -64,8 +58,8 @@ impl NetworkSecurityT for NetworkSecurity { } } -impl NetworkSecurity { - fn set_rules(&mut self, policy: SecurityPolicy) -> Result<()> { +impl Firewall { + fn set_rules(&mut self, policy: FirewallPolicy) -> Result<()> { let mut new_filter_rules = vec![]; new_filter_rules.append(&mut self.get_allow_loopback_rules()?); @@ -85,10 +79,10 @@ impl NetworkSecurity { fn get_policy_specific_rules( &mut self, - policy: SecurityPolicy, + policy: FirewallPolicy, ) -> Result<Vec<pfctl::FilterRule>> { match policy { - SecurityPolicy::Connecting { + FirewallPolicy::Connecting { peer_endpoint, allow_lan, } => { @@ -98,7 +92,7 @@ impl NetworkSecurity { } Ok(rules) } - SecurityPolicy::Connected { + FirewallPolicy::Connected { peer_endpoint, tunnel, allow_lan, @@ -148,7 +142,7 @@ impl NetworkSecurity { } Ok(rules) } - SecurityPolicy::Blocked { allow_lan } => { + FirewallPolicy::Blocked { allow_lan } => { let mut rules = Vec::new(); if allow_lan { rules.append(&mut self.get_allow_lan_rules()?); diff --git a/talpid-core/src/security/mod.rs b/talpid-core/src/firewall/mod.rs index 892041b363..b7977bc2cd 100644 --- a/talpid-core/src/security/mod.rs +++ b/talpid-core/src/firewall/mod.rs @@ -2,25 +2,25 @@ use ipnetwork::{IpNetwork, Ipv4Network, Ipv6Network}; #[cfg(unix)] use lazy_static::lazy_static; +use std::fmt; #[cfg(unix)] -use std::net::{Ipv4Addr, Ipv6Addr}; -use std::{fmt, net::IpAddr, path::Path}; +use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use talpid_types::net::Endpoint; #[cfg(target_os = "macos")] -#[path = "macos/mod.rs"] +#[path = "macos.rs"] mod imp; #[cfg(target_os = "linux")] -#[path = "linux/mod.rs"] +#[path = "linux.rs"] mod imp; #[cfg(windows)] -#[path = "windows/mod.rs"] +#[path = "windows.rs"] mod imp; -pub use self::imp::{DnsError, Error}; +pub use self::imp::Error; #[cfg(unix)] @@ -46,7 +46,7 @@ lazy_static! { /// A enum that describes network security strategy #[derive(Debug, Clone, Eq, PartialEq)] -pub enum SecurityPolicy { +pub enum FirewallPolicy { /// Allow traffic only to server Connecting { /// The peer endpoint that should be allowed. @@ -72,10 +72,10 @@ pub enum SecurityPolicy { }, } -impl fmt::Display for SecurityPolicy { +impl fmt::Display for FirewallPolicy { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { match self { - SecurityPolicy::Connecting { + FirewallPolicy::Connecting { peer_endpoint, allow_lan, } => write!( @@ -84,7 +84,7 @@ impl fmt::Display for SecurityPolicy { peer_endpoint, if *allow_lan { "Allowing" } else { "Blocking" } ), - SecurityPolicy::Connected { + FirewallPolicy::Connected { peer_endpoint, tunnel, allow_lan, @@ -102,7 +102,7 @@ impl fmt::Display for SecurityPolicy { tunnel.gateway, if *allow_lan { "Allowing" } else { "Blocking" } ), - SecurityPolicy::Blocked { allow_lan } => write!( + FirewallPolicy::Blocked { allow_lan } => write!( f, "Blocked, {} LAN", if *allow_lan { "Allowing" } else { "Blocking" } @@ -111,91 +111,47 @@ impl fmt::Display for SecurityPolicy { } } -/// Manages network security of the computer/device. Can apply and enforce security policies +/// Manages network security of the computer/device. Can apply and enforce firewall policies /// by manipulating the OS firewall and DNS settings. -pub struct NetworkSecurity { - inner: imp::NetworkSecurity, +pub struct Firewall { + inner: imp::Firewall, } -impl NetworkSecurity { - /// Returns a new `NetworkSecurity`, ready to apply policies. +impl Firewall { + /// Returns a new `Firewall`, ready to apply policies. pub fn new() -> Result<Self, Error> { - Ok(NetworkSecurity { - inner: imp::NetworkSecurity::new()?, + Ok(Firewall { + inner: imp::Firewall::new()?, }) } - /// Applies and starts enforcing the given `SecurityPolicy` Makes sure it is being kept in place + /// Applies and starts enforcing the given `FirewallPolicy` Makes sure it is being kept in place /// until this method is called again with another policy, or until `reset_policy` is called. - pub fn apply_policy(&mut self, policy: SecurityPolicy) -> Result<(), Error> { - log::info!("Applying security policy: {}", policy); + pub fn apply_policy(&mut self, policy: FirewallPolicy) -> Result<(), Error> { + log::info!("Applying firewall policy: {}", policy); self.inner.apply_policy(policy) } - /// Resets/removes any currently enforced `SecurityPolicy`. Returns the system to the same state - /// it had before any policy was applied through this `NetworkSecurity` instance. + /// Resets/removes any currently enforced `FirewallPolicy`. Returns the system to the same state + /// it had before any policy was applied through this `Firewall` instance. pub fn reset_policy(&mut self) -> Result<(), Error> { - log::info!("Resetting security policy"); + log::info!("Resetting firewall policy"); self.inner.reset_policy() } } -/// Sets and monitors system DNS settings. Makes sure the desired DNS servers are being used. -pub struct DnsMonitor { - inner: imp::DnsMonitor, -} - -impl DnsMonitor { - /// Returns a new `DnsMonitor` that can set and monitor the system DNS. - pub fn new(cache_dir: impl AsRef<Path>) -> Result<Self, DnsError> { - Ok(DnsMonitor { - inner: imp::DnsMonitor::new(cache_dir)?, - }) - } - - /// Set DNS to the given servers. And start monitoring the system for changes. - pub fn set(&mut self, interface: &str, servers: &[IpAddr]) -> Result<(), DnsError> { - log::info!( - "Setting DNS servers to {}", - servers - .iter() - .map(|ip| ip.to_string()) - .collect::<Vec<String>>() - .join(", ") - ); - self.inner.set(interface, servers) - } - - /// Reset system DNS settings to what it was before being set by this instance. - pub fn reset(&mut self) -> Result<(), DnsError> { - log::info!("Resetting DNS"); - self.inner.reset() - } -} - - /// Abstract firewall interaction trait. Used by the OS specific implementations. -trait NetworkSecurityT: Sized { +trait FirewallT: Sized { /// The error type thrown by the implementer of this trait type Error: ::std::error::Error; /// Create new instance fn new() -> ::std::result::Result<Self, Self::Error>; - /// Enable the given SecurityPolicy - fn apply_policy(&mut self, policy: SecurityPolicy) -> ::std::result::Result<(), Self::Error>; + /// Enable the given FirewallPolicy + fn apply_policy(&mut self, policy: FirewallPolicy) -> ::std::result::Result<(), Self::Error>; - /// Revert the system network security state to what it was before this instance started + /// Revert the system firewall state to what it was before this instance started /// modifying the system. fn reset_policy(&mut self) -> ::std::result::Result<(), Self::Error>; } - -trait DnsMonitorT: Sized { - type Error: ::std::error::Error; - - fn new(cache_dir: impl AsRef<Path>) -> Result<Self, Self::Error>; - - fn set(&mut self, interface: &str, servers: &[IpAddr]) -> Result<(), Self::Error>; - - fn reset(&mut self) -> Result<(), Self::Error>; -} diff --git a/talpid-core/src/security/windows/mod.rs b/talpid-core/src/firewall/windows.rs index 1a021d593a..d77a9a3dbd 100644 --- a/talpid-core/src/security/windows/mod.rs +++ b/talpid-core/src/firewall/windows.rs @@ -1,20 +1,12 @@ use std::{net::IpAddr, ptr}; use self::winfw::*; -use super::{NetworkSecurityT, SecurityPolicy}; +use super::{FirewallPolicy, FirewallT}; use crate::winnet; use log::{debug, error, trace}; use talpid_types::net::Endpoint; use widestring::WideCString; -#[macro_use] -mod ffi; - -mod dns; -pub use self::dns::{DnsMonitor, Error as DnsError}; - -mod system_state; - error_chain! { errors { /// Failure to initialize windows firewall module @@ -39,7 +31,7 @@ error_chain! { /// Failure to apply firewall _blocked_ policy ApplyingBlockedPolicy { - description("Failed to apply blocked security policy") + description("Failed to apply blocked firewall policy") } /// Failure to reset firewall policies @@ -57,9 +49,9 @@ error_chain! { const WINFW_TIMEOUT_SECONDS: u32 = 2; /// The Windows implementation for the firewall and DNS. -pub struct NetworkSecurity(()); +pub struct Firewall(()); -impl NetworkSecurityT for NetworkSecurity { +impl FirewallT for Firewall { type Error = Error; fn new() -> Result<Self> { @@ -72,19 +64,19 @@ impl NetworkSecurityT for NetworkSecurity { .into_result()? }; trace!("Successfully initialized windows firewall module"); - Ok(NetworkSecurity(())) + Ok(Firewall(())) } - fn apply_policy(&mut self, policy: SecurityPolicy) -> Result<()> { + fn apply_policy(&mut self, policy: FirewallPolicy) -> Result<()> { match policy { - SecurityPolicy::Connecting { + FirewallPolicy::Connecting { peer_endpoint, allow_lan, } => { let cfg = &WinFwSettings::new(allow_lan); self.set_connecting_state(&peer_endpoint, &cfg) } - SecurityPolicy::Connected { + FirewallPolicy::Connected { peer_endpoint, tunnel, allow_lan, @@ -92,7 +84,7 @@ impl NetworkSecurityT for NetworkSecurity { let cfg = &WinFwSettings::new(allow_lan); self.set_connected_state(&peer_endpoint, &cfg, &tunnel) } - SecurityPolicy::Blocked { allow_lan } => { + FirewallPolicy::Blocked { allow_lan } => { let cfg = &WinFwSettings::new(allow_lan); self.set_blocked_state(&cfg) } @@ -105,7 +97,7 @@ impl NetworkSecurityT for NetworkSecurity { } } -impl Drop for NetworkSecurity { +impl Drop for Firewall { fn drop(&mut self) { if unsafe { WinFw_Deinitialize().into_result().is_ok() } { trace!("Successfully deinitialized windows firewall module"); @@ -115,7 +107,7 @@ impl Drop for NetworkSecurity { } } -impl NetworkSecurity { +impl Firewall { fn set_connecting_state( &mut self, endpoint: &Endpoint, diff --git a/talpid-core/src/lib.rs b/talpid-core/src/lib.rs index 437fb2ff6f..8e63d2bfa8 100644 --- a/talpid-core/src/lib.rs +++ b/talpid-core/src/lib.rs @@ -13,6 +13,11 @@ #[macro_use] extern crate error_chain; +/// Misc FFI utilities. +#[cfg(windows)] +#[macro_use] +mod ffi; + #[cfg(windows)] mod winnet; @@ -37,10 +42,17 @@ pub mod logging; /// Abstractions and extra features on `std::mpsc` pub mod mpsc; -/// Abstractions over operating system network security settings. -pub mod security; +/// Abstractions over operating system firewalls. +pub mod firewall; + +/// Abstractions over operating system DNS settings. +pub mod dns; /// State machine to handle tunnel configuration. pub mod tunnel_state_machine; mod mktemp; + +/// Misc utilities for the Linux platform. +#[cfg(target_os = "linux")] +mod linux; diff --git a/talpid-core/src/linux.rs b/talpid-core/src/linux.rs new file mode 100644 index 0000000000..c1e3a97e07 --- /dev/null +++ b/talpid-core/src/linux.rs @@ -0,0 +1,27 @@ +use std::{ + ffi::{self, CString}, + io, +}; + +/// Converts an interface name into the corresponding index. +pub fn iface_index(name: &str) -> Result<libc::c_uint, IfaceIndexLookupError> { + let c_name = CString::new(name) + .map_err(|e| IfaceIndexLookupError::InvalidInterfaceName(name.to_owned(), e))?; + let index = unsafe { libc::if_nametoindex(c_name.as_ptr()) }; + if index == 0 { + Err(IfaceIndexLookupError::InterfaceLookupError( + name.to_owned(), + io::Error::last_os_error(), + )) + } else { + Ok(index) + } +} + +#[derive(Debug, err_derive::Error)] +pub enum IfaceIndexLookupError { + #[error(display = "Invalid network interface name: {}", _0)] + InvalidInterfaceName(String, #[error(cause)] ffi::NulError), + #[error(display = "Failed to get index for interface {}", _0)] + InterfaceLookupError(String, #[error(cause)] io::Error), +} diff --git a/talpid-core/src/tunnel_state_machine/blocked_state.rs b/talpid-core/src/tunnel_state_machine/blocked_state.rs index abc782cd24..4fd992dd4d 100644 --- a/talpid-core/src/tunnel_state_machine/blocked_state.rs +++ b/talpid-core/src/tunnel_state_machine/blocked_state.rs @@ -6,7 +6,7 @@ use super::{ ConnectingState, DisconnectedState, EventConsequence, ResultExt, SharedTunnelStateValues, TunnelCommand, TunnelState, TunnelStateTransition, TunnelStateWrapper, }; -use crate::security::SecurityPolicy; +use crate::firewall::FirewallPolicy; /// No tunnel is running and all network connections are blocked. pub struct BlockedState { @@ -14,20 +14,20 @@ pub struct BlockedState { } impl BlockedState { - fn set_security_policy(shared_values: &mut SharedTunnelStateValues) -> Option<BlockReason> { - let policy = SecurityPolicy::Blocked { + fn set_firewall_policy(shared_values: &mut SharedTunnelStateValues) -> Option<BlockReason> { + let policy = FirewallPolicy::Blocked { allow_lan: shared_values.allow_lan, }; match shared_values - .security + .firewall .apply_policy(policy) - .chain_err(|| "Failed to apply security policy for blocked state") + .chain_err(|| "Failed to apply firewall policy for blocked state") { Ok(()) => None, Err(error) => { log::error!("{}", error.display_chain()); - Some(BlockReason::SetSecurityPolicyError) + Some(BlockReason::SetFirewallPolicyError) } } } @@ -40,7 +40,7 @@ impl TunnelState for BlockedState { shared_values: &mut SharedTunnelStateValues, block_reason: Self::Bootstrap, ) -> (TunnelStateWrapper, TunnelStateTransition) { - let block_reason = Self::set_security_policy(shared_values).unwrap_or_else(|| block_reason); + let block_reason = Self::set_firewall_policy(shared_values).unwrap_or_else(|| block_reason); ( TunnelStateWrapper::from(BlockedState { @@ -60,7 +60,7 @@ impl TunnelState for BlockedState { match try_handle_event!(self, commands.poll()) { Ok(TunnelCommand::AllowLan(allow_lan)) => { shared_values.allow_lan = allow_lan; - Self::set_security_policy(shared_values); + Self::set_firewall_policy(shared_values); SameState(self) } Ok(TunnelCommand::BlockWhenDisconnected(block_when_disconnected)) => { diff --git a/talpid-core/src/tunnel_state_machine/connected_state.rs b/talpid-core/src/tunnel_state_machine/connected_state.rs index b5a88c7181..1a979476e7 100644 --- a/talpid-core/src/tunnel_state_machine/connected_state.rs +++ b/talpid-core/src/tunnel_state_machine/connected_state.rs @@ -14,7 +14,7 @@ use super::{ TunnelStateWrapper, }; use crate::{ - security::SecurityPolicy, + firewall::FirewallPolicy, tunnel::{CloseHandle, TunnelEvent, TunnelMetadata}, }; @@ -46,19 +46,19 @@ impl ConnectedState { } } - fn set_security_policy(&self, shared_values: &mut SharedTunnelStateValues) -> Result<()> { + fn set_firewall_policy(&self, shared_values: &mut SharedTunnelStateValues) -> Result<()> { // If a proxy is specified we need to pass it on as the peer endpoint. let peer_endpoint = self.get_endpoint_from_params(); - let policy = SecurityPolicy::Connected { + let policy = FirewallPolicy::Connected { peer_endpoint, tunnel: self.metadata.clone(), allow_lan: shared_values.allow_lan, }; shared_values - .security + .firewall .apply_policy(policy) - .chain_err(|| "Failed to apply security policy for connected state") + .chain_err(|| "Failed to apply firewall policy for connected state") } fn get_endpoint_from_params(&self) -> Endpoint { @@ -111,13 +111,13 @@ impl ConnectedState { Ok(TunnelCommand::AllowLan(allow_lan)) => { shared_values.allow_lan = allow_lan; - match self.set_security_policy(shared_values) { + match self.set_firewall_policy(shared_values) { Ok(()) => SameState(self), Err(error) => { log::error!("{}", error.display_chain()); self.disconnect( shared_values, - AfterDisconnect::Block(BlockReason::SetSecurityPolicyError), + AfterDisconnect::Block(BlockReason::SetFirewallPolicyError), ) } } @@ -195,14 +195,14 @@ impl TunnelState for ConnectedState { let connected_state = ConnectedState::from(bootstrap); let tunnel_endpoint = connected_state.tunnel_parameters.get_tunnel_endpoint(); - if let Err(error) = connected_state.set_security_policy(shared_values) { + if let Err(error) = connected_state.set_firewall_policy(shared_values) { log::error!("{}", error.display_chain()); DisconnectingState::enter( shared_values, ( connected_state.close_handle, connected_state.tunnel_close_event, - AfterDisconnect::Block(BlockReason::SetSecurityPolicyError), + AfterDisconnect::Block(BlockReason::SetFirewallPolicyError), ), ) } else if let Err(error) = connected_state.set_dns(shared_values) { diff --git a/talpid-core/src/tunnel_state_machine/connecting_state.rs b/talpid-core/src/tunnel_state_machine/connecting_state.rs index ad3712144a..0896fd18cf 100644 --- a/talpid-core/src/tunnel_state_machine/connecting_state.rs +++ b/talpid-core/src/tunnel_state_machine/connecting_state.rs @@ -22,8 +22,8 @@ use super::{ TunnelStateWrapper, }; use crate::{ + firewall::FirewallPolicy, logging, - security::SecurityPolicy, tunnel::{self, CloseHandle, TunnelEvent, TunnelMetadata, TunnelMonitor}, }; @@ -60,7 +60,7 @@ pub struct ConnectingState { } impl ConnectingState { - fn set_security_policy( + fn set_firewall_policy( shared_values: &mut SharedTunnelStateValues, proxy: &Option<openvpn::ProxySettings>, endpoint: Endpoint, @@ -71,14 +71,14 @@ impl ConnectingState { None => endpoint, }; - let policy = SecurityPolicy::Connecting { + let policy = FirewallPolicy::Connecting { peer_endpoint, allow_lan: shared_values.allow_lan, }; shared_values - .security + .firewall .apply_policy(policy) - .chain_err(|| "Failed to apply security policy for connecting state") + .chain_err(|| "Failed to apply firewall policy for connecting state") } fn start_tunnel( @@ -217,7 +217,7 @@ impl ConnectingState { match try_handle_event!(self, commands.poll()) { Ok(TunnelCommand::AllowLan(allow_lan)) => { shared_values.allow_lan = allow_lan; - match Self::set_security_policy( + match Self::set_firewall_policy( shared_values, &get_openvpn_proxy_settings(&self.tunnel_parameters), self.tunnel_parameters.get_tunnel_endpoint().endpoint, @@ -231,7 +231,7 @@ impl ConnectingState { ( self.close_handle, self.tunnel_close_event, - AfterDisconnect::Block(BlockReason::SetSecurityPolicyError), + AfterDisconnect::Block(BlockReason::SetFirewallPolicyError), ), )) } @@ -369,7 +369,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_security_policy( + if let Err(error) = Self::set_firewall_policy( shared_values, &get_openvpn_proxy_settings(&tunnel_parameters), endpoint, diff --git a/talpid-core/src/tunnel_state_machine/disconnected_state.rs b/talpid-core/src/tunnel_state_machine/disconnected_state.rs index 0634c75da4..299d00d303 100644 --- a/talpid-core/src/tunnel_state_machine/disconnected_state.rs +++ b/talpid-core/src/tunnel_state_machine/disconnected_state.rs @@ -2,7 +2,7 @@ use super::{ BlockedState, ConnectingState, EventConsequence, ResultExt, SharedTunnelStateValues, TunnelCommand, TunnelState, TunnelStateTransition, TunnelStateWrapper, }; -use crate::security::SecurityPolicy; +use crate::firewall::FirewallPolicy; use error_chain::ChainedError; use futures::{sync::mpsc, Stream}; @@ -10,20 +10,20 @@ use futures::{sync::mpsc, Stream}; pub struct DisconnectedState; impl DisconnectedState { - fn set_security_policy(shared_values: &mut SharedTunnelStateValues) { + fn set_firewall_policy(shared_values: &mut SharedTunnelStateValues) { let result = if shared_values.block_when_disconnected { - let policy = SecurityPolicy::Blocked { + let policy = FirewallPolicy::Blocked { allow_lan: shared_values.allow_lan, }; shared_values - .security + .firewall .apply_policy(policy) - .chain_err(|| "Failed to apply blocking security policy for disconnected state") + .chain_err(|| "Failed to apply blocking firewall policy for disconnected state") } else { shared_values - .security + .firewall .reset_policy() - .chain_err(|| "Failed to reset security policy") + .chain_err(|| "Failed to reset firewall policy") }; if let Err(error) = result { log::error!("{}", error.display_chain()); @@ -38,7 +38,7 @@ impl TunnelState for DisconnectedState { shared_values: &mut SharedTunnelStateValues, _: Self::Bootstrap, ) -> (TunnelStateWrapper, TunnelStateTransition) { - Self::set_security_policy(shared_values); + Self::set_firewall_policy(shared_values); ( TunnelStateWrapper::from(DisconnectedState), TunnelStateTransition::Disconnected, @@ -56,14 +56,14 @@ impl TunnelState for DisconnectedState { Ok(TunnelCommand::AllowLan(allow_lan)) => { if shared_values.allow_lan != allow_lan { shared_values.allow_lan = allow_lan; - Self::set_security_policy(shared_values); + Self::set_firewall_policy(shared_values); } SameState(self) } Ok(TunnelCommand::BlockWhenDisconnected(block_when_disconnected)) => { if shared_values.block_when_disconnected != block_when_disconnected { shared_values.block_when_disconnected = block_when_disconnected; - Self::set_security_policy(shared_values); + Self::set_firewall_policy(shared_values); } SameState(self) } diff --git a/talpid-core/src/tunnel_state_machine/mod.rs b/talpid-core/src/tunnel_state_machine/mod.rs index 8e20e3a159..4e85e9a0be 100644 --- a/talpid-core/src/tunnel_state_machine/mod.rs +++ b/talpid-core/src/tunnel_state_machine/mod.rs @@ -29,17 +29,13 @@ use self::{ disconnected_state::DisconnectedState, disconnecting_state::{AfterDisconnect, DisconnectingState}, }; -use crate::{ - mpsc::IntoSender, - offline, - security::{DnsMonitor, NetworkSecurity}, -}; +use crate::{dns::DnsMonitor, firewall::Firewall, mpsc::IntoSender, offline}; error_chain! { errors { /// An error occurred while setting up the network security. - NetworkSecurityError { - description("Network security error") + FirewallError { + description("Firewall error") } /// Unable to start the DNS settings monitor and enforcer. DnsMonitorError { @@ -185,10 +181,10 @@ impl TunnelStateMachine { cache_dir: impl AsRef<Path>, commands: mpsc::UnboundedReceiver<TunnelCommand>, ) -> Result<Self> { - let security = NetworkSecurity::new().chain_err(|| ErrorKind::NetworkSecurityError)?; + let firewall = Firewall::new().chain_err(|| ErrorKind::FirewallError)?; let dns_monitor = DnsMonitor::new(cache_dir).chain_err(|| ErrorKind::DnsMonitorError)?; let mut shared_values = SharedTunnelStateValues { - security, + firewall, dns_monitor, allow_lan, block_when_disconnected, @@ -266,7 +262,7 @@ pub trait TunnelParametersGenerator: Send + 'static { /// Values that are common to all tunnel states. struct SharedTunnelStateValues { - security: NetworkSecurity, + firewall: Firewall, dns_monitor: DnsMonitor, /// Should LAN access be allowed outside the tunnel. allow_lan: bool, |
