diff options
| author | David Lönnhager <david.l@mullvad.net> | 2020-10-29 09:50:09 +0100 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2020-10-29 09:50:09 +0100 |
| commit | 3ab99dc9e117a8e245e37d996a6ece451d1f5cb0 (patch) | |
| tree | ce1ab6c1cd184643f61e4cdc158bfd40d8db37b7 | |
| parent | 5c9d8652fc670a24887ecc6a90d9f452ba5bd343 (diff) | |
| parent | 29c0cec58c7ea252309d9036bf5cd1d5140659db (diff) | |
| download | mullvadvpn-3ab99dc9e117a8e245e37d996a6ece451d1f5cb0.tar.xz mullvadvpn-3ab99dc9e117a8e245e37d996a6ece451d1f5cb0.zip | |
Merge branch 'fix-rule-duplication'
| -rw-r--r-- | CHANGELOG.md | 1 | ||||
| -rw-r--r-- | talpid-core/src/routing/linux.rs | 49 |
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::*; |
