summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md6
-rw-r--r--talpid-core/src/firewall/linux.rs38
-rw-r--r--talpid-core/src/firewall/macos.rs46
3 files changed, 63 insertions, 27 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0ea79cf321..cff66c23d4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -50,6 +50,12 @@ Line wrap the file at 100 chars. Th
- Fix crash that happened in certain situations when retrieving the relay list.
- Fix crash caused by initialization race condition.
+### Security
+- Stop DNS leak that could happen on Linux and macOS if local network sharing was enabled
+ and the user's default DNS was on the local private network. The leak could happen during these
+ states: While connecting, when blocked due to an error happening and when disconnected if the
+ "block when disconnected" setting was enabled.
+
## [2020.1] - 2020-02-10
This release is identical to 2020.1-beta1
diff --git a/talpid-core/src/firewall/linux.rs b/talpid-core/src/firewall/linux.rs
index e2f6f4f736..e291cc9050 100644
--- a/talpid-core/src/firewall/linux.rs
+++ b/talpid-core/src/firewall/linux.rs
@@ -351,6 +351,9 @@ impl<'a> PolicyBatch<'a> {
} => {
self.add_allow_icmp_pingable_hosts(&pingable_hosts);
self.add_allow_endpoint_rules(peer_endpoint);
+ // Important to block DNS after allow relay rule (so the relay can operate
+ // over port 53) but before allow LAN (so DNS does not leak to the LAN)
+ self.add_drop_dns_rule();
*allow_lan
}
FirewallPolicy::Connected {
@@ -359,15 +362,22 @@ impl<'a> PolicyBatch<'a> {
allow_lan,
} => {
self.add_allow_endpoint_rules(peer_endpoint);
- self.add_dns_rule(tunnel, TransportProtocol::Udp)?;
- self.add_dns_rule(tunnel, TransportProtocol::Tcp)?;
+ self.add_allow_dns_rules(tunnel, TransportProtocol::Udp)?;
+ self.add_allow_dns_rules(tunnel, TransportProtocol::Tcp)?;
+ // Important to block DNS *before* we allow the tunnel and allow LAN. So DNS
+ // can't leak to the wrong IPs in the tunnel or on the LAN.
+ self.add_drop_dns_rule();
self.add_allow_tunnel_rules(tunnel)?;
if *allow_lan {
self.add_block_cve_2019_14899(tunnel);
}
*allow_lan
}
- FirewallPolicy::Blocked { allow_lan } => *allow_lan,
+ FirewallPolicy::Blocked { allow_lan } => {
+ // Important to drop DNS before allowing LAN (to stop DNS leaking to the LAN)
+ self.add_drop_dns_rule();
+ *allow_lan
+ }
};
if allow_lan {
@@ -419,21 +429,16 @@ impl<'a> PolicyBatch<'a> {
}
}
- fn add_dns_rule(
+ fn add_allow_dns_rules(
&mut self,
tunnel: &tunnel::TunnelMetadata,
protocol: TransportProtocol,
) -> Result<()> {
- // allow DNS traffic to the tunnel gateway
+ // allow DNS traffic to the tunnel gateway(s)
self.add_allow_dns_rule(&tunnel.interface, protocol, tunnel.ipv4_gateway.into())?;
if let Some(ipv6_gateway) = tunnel.ipv6_gateway {
self.add_allow_dns_rule(&tunnel.interface, protocol, ipv6_gateway.into())?;
};
- let mut block_rule = Rule::new(&self.out_chain);
- check_port(&mut block_rule, protocol, End::Dst, 53);
- add_verdict(&mut block_rule, &Verdict::Drop);
- self.batch.add(&block_rule, nftnl::MsgType::Add);
-
Ok(())
}
@@ -461,6 +466,19 @@ impl<'a> PolicyBatch<'a> {
Ok(())
}
+ /// Blocks all outgoing DNS (port 53) on both TCP and UDP
+ fn add_drop_dns_rule(&mut self) {
+ let mut block_udp_rule = Rule::new(&self.out_chain);
+ check_port(&mut block_udp_rule, TransportProtocol::Udp, End::Dst, 53);
+ add_verdict(&mut block_udp_rule, &Verdict::Drop);
+ self.batch.add(&block_udp_rule, nftnl::MsgType::Add);
+
+ let mut block_tcp_rule = Rule::new(&self.out_chain);
+ check_port(&mut block_tcp_rule, TransportProtocol::Tcp, End::Dst, 53);
+ add_verdict(&mut block_tcp_rule, &Verdict::Drop);
+ self.batch.add(&block_tcp_rule, nftnl::MsgType::Add);
+ }
+
fn add_allow_tunnel_rules(&mut self, tunnel: &tunnel::TunnelMetadata) -> Result<()> {
self.batch.add(
&allow_interface_rule(&self.out_chain, Direction::Out, &tunnel.interface[..])?,
diff --git a/talpid-core/src/firewall/macos.rs b/talpid-core/src/firewall/macos.rs
index acf9b68cc6..41898f36cd 100644
--- a/talpid-core/src/firewall/macos.rs
+++ b/talpid-core/src/firewall/macos.rs
@@ -94,6 +94,9 @@ impl Firewall {
let mut rules = vec![self.get_allow_relay_rule(peer_endpoint)?];
rules.extend(self.get_allow_pingable_hosts(&pingable_hosts)?);
if allow_lan {
+ // Important to block DNS after allow relay rule (so the relay can operate
+ // over port 53) but before allow LAN (so DNS does not leak to the LAN)
+ rules.append(&mut self.get_block_dns_rules()?);
rules.append(&mut self.get_allow_lan_rules()?);
}
Ok(rules)
@@ -144,24 +147,12 @@ impl Firewall {
rules.push(v6_dns_rule_udp);
}
- let block_tcp_dns_rule = self
- .create_rule_builder(FilterRuleAction::Drop)
- .direction(pfctl::Direction::Out)
- .quick(true)
- .proto(pfctl::Proto::Tcp)
- .to(pfctl::Port::from(53))
- .build()?;
- rules.push(block_tcp_dns_rule);
- let block_udp_dns_rule = self
- .create_rule_builder(FilterRuleAction::Drop)
- .direction(pfctl::Direction::Out)
- .quick(true)
- .proto(pfctl::Proto::Udp)
- .to(pfctl::Port::from(53))
- .build()?;
-
- rules.push(block_udp_dns_rule);
rules.push(self.get_allow_relay_rule(peer_endpoint)?);
+
+ // Important to block DNS *before* we allow the tunnel and allow LAN. So DNS
+ // can't leak to the wrong IPs in the tunnel or on the LAN.
+ rules.append(&mut self.get_block_dns_rules()?);
+
rules.push(self.get_allow_tunnel_rule(tunnel.interface.as_str())?);
if allow_lan {
@@ -173,6 +164,8 @@ impl Firewall {
FirewallPolicy::Blocked { allow_lan } => {
let mut rules = Vec::new();
if allow_lan {
+ // Important to block DNS before allow LAN (so DNS does not leak to the LAN)
+ rules.append(&mut self.get_block_dns_rules()?);
rules.append(&mut self.get_allow_lan_rules()?);
}
Ok(rules)
@@ -194,6 +187,25 @@ impl Firewall {
.build()?)
}
+ fn get_block_dns_rules(&self) -> Result<Vec<pfctl::FilterRule>> {
+ let block_tcp_dns_rule = self
+ .create_rule_builder(FilterRuleAction::Drop)
+ .direction(pfctl::Direction::Out)
+ .quick(true)
+ .proto(pfctl::Proto::Tcp)
+ .to(pfctl::Port::from(53))
+ .build()?;
+ let block_udp_dns_rule = self
+ .create_rule_builder(FilterRuleAction::Drop)
+ .direction(pfctl::Direction::Out)
+ .quick(true)
+ .proto(pfctl::Proto::Udp)
+ .to(pfctl::Port::from(53))
+ .build()?;
+
+ Ok(vec![block_tcp_dns_rule, block_udp_dns_rule])
+ }
+
fn get_allow_pingable_hosts(
&self,
pingable_hosts: &[IpAddr],