summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--talpid-core/src/firewall/macos.rs141
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
+}