summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2020-10-29 09:50:09 +0100
committerDavid Lönnhager <david.l@mullvad.net>2020-10-29 09:50:09 +0100
commit3ab99dc9e117a8e245e37d996a6ece451d1f5cb0 (patch)
treece1ab6c1cd184643f61e4cdc158bfd40d8db37b7
parent5c9d8652fc670a24887ecc6a90d9f452ba5bd343 (diff)
parent29c0cec58c7ea252309d9036bf5cd1d5140659db (diff)
downloadmullvadvpn-3ab99dc9e117a8e245e37d996a6ece451d1f5cb0.tar.xz
mullvadvpn-3ab99dc9e117a8e245e37d996a6ece451d1f5cb0.zip
Merge branch 'fix-rule-duplication'
-rw-r--r--CHANGELOG.md1
-rw-r--r--talpid-core/src/routing/linux.rs49
2 files changed, 50 insertions, 0 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1a994a6384..f0d1db2ac3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -78,6 +78,7 @@ Line wrap the file at 100 chars. Th
- Handle statically added routes.
- Stop reconnecting when using WireGuard and NetworkManager.
- Apply DNS config quicker when managing DNS via NetworkManager.
+- Fix routing rules sometimes being duplicated.
### Security
diff --git a/talpid-core/src/routing/linux.rs b/talpid-core/src/routing/linux.rs
index 278ec8afbf..8d5b76d2fe 100644
--- a/talpid-core/src/routing/linux.rs
+++ b/talpid-core/src/routing/linux.rs
@@ -216,6 +216,10 @@ impl RouteManagerImpl {
// TODO: IPv6
use netlink_packet_route::constants::*;
+ if let Ok(true) = self.exclusions_rule_exists().await {
+ return Ok(());
+ }
+
let mut req = NetlinkMessage::from(RtnlMessage::NewRule(self.fwmark_rule_message()));
req.header.flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_REPLACE;
@@ -252,6 +256,51 @@ impl RouteManagerImpl {
}
}
+ async fn exclusions_rule_exists(&mut self) -> Result<bool> {
+ use netlink_packet_route::constants::*;
+
+ let mut req = NetlinkMessage::from(RtnlMessage::GetRule(RuleMessage {
+ header: RuleHeader {
+ family: AF_INET as u8,
+ ..RuleHeader::default()
+ },
+ nlas: vec![],
+ }));
+ req.header.flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP;
+
+ let mut response = self.handle.request(req).map_err(Error::NetlinkError)?;
+
+ while let Some(message) = response.next().await {
+ match message.payload {
+ NetlinkPayload::InnerMessage(inner) => {
+ if let RtnlMessage::NewRule(rule) = RtnlMessage::from(inner) {
+ let mut match_mark = false;
+ let mut match_table = false;
+ for nla in &rule.nlas {
+ match nla {
+ _x if _x == &RuleNla::FwMark(split_tunnel::MARK as u32) => {
+ match_mark = true;
+ }
+ _x if _x == &RuleNla::Table(self.split_table_id) => {
+ match_table = true;
+ }
+ _ => (),
+ }
+ }
+ if match_mark && match_table {
+ return Ok(true);
+ }
+ }
+ }
+ NetlinkPayload::Error(error) => {
+ return Err(Error::NetlinkError(rtnetlink::Error::NetlinkError(error)));
+ }
+ _ => (),
+ }
+ }
+ Ok(false)
+ }
+
fn fwmark_rule_message(&self) -> RuleMessage {
use netlink_packet_route::constants::*;