summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2020-09-21 12:26:41 +0200
committerDavid Lönnhager <david.l@mullvad.net>2020-09-21 12:26:41 +0200
commitf72b56b65e1f962dbd2530661112e389d1f54e7e (patch)
tree8788a5c7fc716dc5fb1f2319d779b930ad8ba8e0
parenta6a1f7ca37e7ca967b22977da8234d0f392afcfa (diff)
parent6735f7dc8ecec4fec340e11bf825cece54fdf5a1 (diff)
downloadmullvadvpn-f72b56b65e1f962dbd2530661112e389d1f54e7e.tar.xz
mullvadvpn-f72b56b65e1f962dbd2530661112e389d1f54e7e.zip
Merge branch 'linux-no-ip-subprocess'
-rw-r--r--talpid-core/src/routing/linux.rs91
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::*;