diff options
| author | David Lönnhager <david.l@mullvad.net> | 2020-09-21 12:26:41 +0200 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2020-09-21 12:26:41 +0200 |
| commit | f72b56b65e1f962dbd2530661112e389d1f54e7e (patch) | |
| tree | 8788a5c7fc716dc5fb1f2319d779b930ad8ba8e0 | |
| parent | a6a1f7ca37e7ca967b22977da8234d0f392afcfa (diff) | |
| parent | 6735f7dc8ecec4fec340e11bf825cece54fdf5a1 (diff) | |
| download | mullvadvpn-f72b56b65e1f962dbd2530661112e389d1f54e7e.tar.xz mullvadvpn-f72b56b65e1f962dbd2530661112e389d1f54e7e.zip | |
Merge branch 'linux-no-ip-subprocess'
| -rw-r--r-- | talpid-core/src/routing/linux.rs | 91 |
1 files changed, 43 insertions, 48 deletions
diff --git a/talpid-core/src/routing/linux.rs b/talpid-core/src/routing/linux.rs index 1cb5fc10e3..a314c4f112 100644 --- a/talpid-core/src/routing/linux.rs +++ b/talpid-core/src/routing/linux.rs @@ -12,7 +12,6 @@ use std::{ fs, io::{self, BufRead, BufReader, Read, Seek, Write}, net::{IpAddr, Ipv4Addr}, - process::Command, }; use futures::{channel::mpsc::UnboundedReceiver, future::FutureExt, StreamExt, TryStreamExt}; @@ -25,6 +24,7 @@ use netlink_packet_route::{ constants::{RTN_UNICAST, RTPROT_STATIC, RT_SCOPE_UNIVERSE, RT_TABLE_MAIN}, RouteFlags, }, + rule::{nlas::Nla as RuleNla, RuleHeader, RuleMessage}, NetlinkMessage, NetlinkPayload, RtnlMessage, }; use rtnetlink::{ @@ -228,29 +228,17 @@ impl RouteManagerImpl { /// Route PID-associated packets through the physical interface. async fn enable_exclusions_routes(&mut self) -> Result<()> { // TODO: IPv6 + use netlink_packet_route::constants::*; - let table_id_str = &self.split_table_id.to_string(); + 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; - // Create the rule if it does not exist - let mut cmd = Command::new("ip"); - cmd.args(&["-4", "rule", "list", "table", table_id_str]); - log::trace!("running cmd - {:?}", &cmd); - let out = cmd.output().map_err(Error::ExecFailed)?; + let mut response = self.handle.request(req).map_err(Error::NetlinkError)?; - let missing_rule = - !out.status.success() || String::from_utf8_lossy(&out.stdout).trim().is_empty(); - if missing_rule { - exec_ip(&[ - "-4", - "rule", - "add", - "from", - "all", - "fwmark", - &split_tunnel::MARK.to_string(), - "lookup", - table_id_str, - ])?; + while let Some(message) = response.next().await { + if let NetlinkPayload::Error(error) = message.payload { + return Err(Error::NetlinkError(rtnetlink::Error::NetlinkError(error))); + } } // Add default route for the exclusions table @@ -264,21 +252,42 @@ impl RouteManagerImpl { } /// Stop routing PID-associated packets through the physical interface. - async fn disable_exclusions_routes(&self) { + async fn disable_exclusions_routes(&mut self) { // TODO: IPv6 + use netlink_packet_route::constants::*; - if let Err(e) = exec_ip(&[ - "-4", - "rule", - "del", - "from", - "all", - "fwmark", - &split_tunnel::MARK.to_string(), - "lookup", - &self.split_table_id.to_string(), - ]) { - log::warn!("Failed to delete routing policy: {}", e); + let mut req = NetlinkMessage::from(RtnlMessage::DelRule(self.fwmark_rule_message())); + req.header.flags = NLM_F_REQUEST | NLM_F_ACK; + + match self.handle.request(req).map_err(Error::NetlinkError) { + Ok(mut response) => { + while let Some(message) = response.next().await { + if let NetlinkPayload::Error(error) = message.payload { + if error.to_io().kind() != io::ErrorKind::NotFound { + log::warn!("Failed to delete routing policy: {}", error); + } + } + } + } + Err(error) => log::warn!("Failed to delete routing policy: {}", error), + } + } + + fn fwmark_rule_message(&self) -> RuleMessage { + use netlink_packet_route::constants::*; + + RuleMessage { + header: RuleHeader { + family: AF_INET as u8, + action: FR_ACT_TO_TBL, + src_len: 0, + ..RuleHeader::default() + }, + nlas: vec![ + RuleNla::Source(ip_to_bytes(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)))), + RuleNla::FwMark(split_tunnel::MARK as u32), + RuleNla::Table(self.split_table_id as u32), + ], } } @@ -867,20 +876,6 @@ fn ip_to_bytes(addr: IpAddr) -> Vec<u8> { } } -fn exec_ip(args: &[&str]) -> Result<()> { - let mut cmd = Command::new("ip"); - cmd.args(args); - - log::trace!("running cmd - {:?}", &cmd); - - let status = cmd.status().map_err(Error::ExecFailed)?; - if status.success() { - Ok(()) - } else { - Err(Error::IpFailed) - } -} - #[cfg(test)] mod test { use super::*; |
