diff options
| -rw-r--r-- | talpid-core/src/firewall/macos.rs | 141 |
1 files changed, 100 insertions, 41 deletions
diff --git a/talpid-core/src/firewall/macos.rs b/talpid-core/src/firewall/macos.rs index 140829a10a..7fed307244 100644 --- a/talpid-core/src/firewall/macos.rs +++ b/talpid-core/src/firewall/macos.rs @@ -114,50 +114,12 @@ impl Firewall { peer_endpoint, tunnel, allow_lan, + dns_servers, } => { let mut rules = vec![]; - let allow_tcp_dns_to_relay_rule = self - .create_rule_builder(FilterRuleAction::Pass) - .direction(pfctl::Direction::Out) - .quick(true) - .interface(&tunnel.interface) - .proto(pfctl::Proto::Tcp) - .keep_state(pfctl::StatePolicy::Keep) - .tcp_flags(Self::get_tcp_flags()) - .to(pfctl::Endpoint::new(tunnel.ipv4_gateway, 53)) - .build()?; - rules.push(allow_tcp_dns_to_relay_rule); - let allow_udp_dns_to_relay_rule = self - .create_rule_builder(FilterRuleAction::Pass) - .direction(pfctl::Direction::Out) - .quick(true) - .interface(&tunnel.interface) - .proto(pfctl::Proto::Udp) - .to(pfctl::Endpoint::new(tunnel.ipv4_gateway, 53)) - .build()?; - rules.push(allow_udp_dns_to_relay_rule); - if let Some(ipv6_gateway) = tunnel.ipv6_gateway { - let v6_dns_rule_tcp = self - .create_rule_builder(FilterRuleAction::Pass) - .direction(pfctl::Direction::Out) - .quick(true) - .interface(&tunnel.interface) - .proto(pfctl::Proto::Tcp) - .keep_state(pfctl::StatePolicy::Keep) - .tcp_flags(Self::get_tcp_flags()) - .to(pfctl::Endpoint::new(ipv6_gateway, 53)) - .build()?; - rules.push(v6_dns_rule_tcp); - let v6_dns_rule_udp = self - .create_rule_builder(FilterRuleAction::Pass) - .direction(pfctl::Direction::Out) - .quick(true) - .interface(&tunnel.interface) - .proto(pfctl::Proto::Udp) - .to(pfctl::Endpoint::new(ipv6_gateway, 53)) - .build()?; - rules.push(v6_dns_rule_udp); + for server in &dns_servers { + rules.append(&mut self.get_allow_dns_rules(&tunnel, *server)?); } rules.push(self.get_allow_relay_rule(peer_endpoint)?); @@ -186,6 +148,90 @@ impl Firewall { } } + fn get_allow_dns_rules( + &self, + tunnel: &crate::tunnel::TunnelMetadata, + server: IpAddr, + ) -> Result<Vec<pfctl::FilterRule>> { + let mut rules = Vec::with_capacity(4); + + let is_local = is_local_address(&server) + && server != tunnel.ipv4_gateway + && !tunnel + .ipv6_gateway + .map(|ref gateway| &server == gateway) + .unwrap_or(false); + + if is_local { + // Block requests on the tunnel interface + let block_tunnel_tcp = self + .create_rule_builder(FilterRuleAction::Drop(DropAction::Return)) + .direction(pfctl::Direction::Out) + .quick(true) + .interface(&tunnel.interface) + .proto(pfctl::Proto::Tcp) + .keep_state(pfctl::StatePolicy::None) + .to(pfctl::Endpoint::new(server, 53)) + .build()?; + rules.push(block_tunnel_tcp); + let block_tunnel_udp = self + .create_rule_builder(FilterRuleAction::Drop(DropAction::Return)) + .direction(pfctl::Direction::Out) + .quick(true) + .interface(&tunnel.interface) + .proto(pfctl::Proto::Udp) + .keep_state(pfctl::StatePolicy::None) + .to(pfctl::Endpoint::new(server, 53)) + .build()?; + rules.push(block_tunnel_udp); + + // Allow requests on other interfaces + let allow_nontunnel_tcp = self + .create_rule_builder(FilterRuleAction::Pass) + .direction(pfctl::Direction::Out) + .quick(true) + .proto(pfctl::Proto::Tcp) + .keep_state(pfctl::StatePolicy::Keep) + .tcp_flags(Self::get_tcp_flags()) + .to(pfctl::Endpoint::new(server, 53)) + .build()?; + rules.push(allow_nontunnel_tcp); + let allow_nontunnel_udp = self + .create_rule_builder(FilterRuleAction::Pass) + .direction(pfctl::Direction::Out) + .quick(true) + .proto(pfctl::Proto::Udp) + .keep_state(pfctl::StatePolicy::Keep) + .to(pfctl::Endpoint::new(server, 53)) + .build()?; + rules.push(allow_nontunnel_udp); + } else { + // Allow outgoing requests on the tunnel interface only + let allow_tunnel_tcp = self + .create_rule_builder(FilterRuleAction::Pass) + .direction(pfctl::Direction::Out) + .quick(true) + .interface(&tunnel.interface) + .proto(pfctl::Proto::Tcp) + .keep_state(pfctl::StatePolicy::Keep) + .tcp_flags(Self::get_tcp_flags()) + .to(pfctl::Endpoint::new(server, 53)) + .build()?; + rules.push(allow_tunnel_tcp); + let allow_tunnel_udp = self + .create_rule_builder(FilterRuleAction::Pass) + .direction(pfctl::Direction::Out) + .quick(true) + .interface(&tunnel.interface) + .proto(pfctl::Proto::Udp) + .to(pfctl::Endpoint::new(server, 53)) + .build()?; + rules.push(allow_tunnel_udp); + }; + + Ok(rules) + } + fn get_allow_relay_rule(&self, relay_endpoint: net::Endpoint) -> Result<pfctl::FilterRule> { let pfctl_proto = as_pfctl_proto(relay_endpoint.protocol); @@ -482,3 +528,16 @@ enum RuleLogging { Drop, All, } + +fn is_local_address(address: &IpAddr) -> bool { + let address = address.clone(); + for net in (&*super::ALLOWED_LAN_NETS) + .iter() + .chain(&*super::LOOPBACK_NETS) + { + if net.contains(address) { + return true; + } + } + false +} |
