vpncloud/src/device.rs

514 lines
17 KiB
Rust
Raw Normal View History

// VpnCloud - Peer-to-Peer VPN
2021-02-08 09:11:20 +00:00
// Copyright (C) 2015-2021 Dennis Schwerdel
// This software is licensed under GPL-3 or newer (see LICENSE.md)
2021-03-02 15:31:40 +00:00
use async_trait::async_trait;
2021-02-19 23:17:06 +00:00
use parking_lot::Mutex;
2019-12-04 08:32:35 +00:00
use std::{
2020-09-24 17:48:13 +00:00
cmp,
2019-12-04 08:32:35 +00:00
collections::VecDeque,
2021-01-24 16:47:02 +00:00
convert::TryInto,
2020-09-24 17:48:13 +00:00
fmt,
2021-03-02 15:31:40 +00:00
io::{self, Cursor, Error as IoError},
2020-09-24 17:48:13 +00:00
net::{Ipv4Addr, UdpSocket},
2021-03-02 15:31:40 +00:00
os::unix::io::AsRawFd,
2020-07-13 22:03:08 +00:00
str,
2021-02-19 23:17:06 +00:00
str::FromStr,
2021-03-02 15:31:40 +00:00
sync::Arc,
2019-12-04 08:32:35 +00:00
};
2021-03-02 15:31:40 +00:00
use tokio::fs::{self, File};
use tokio::io::{AsyncBufReadExt, AsyncReadExt, AsyncWriteExt, BufReader};
2015-11-22 18:00:56 +00:00
2020-09-24 17:48:13 +00:00
use crate::{crypto, error::Error, util::MsgBuffer};
2015-11-22 18:00:56 +00:00
2020-09-24 17:48:13 +00:00
static TUNSETIFF: libc::c_ulong = 1074025674;
2020-07-13 22:03:08 +00:00
#[repr(C)]
union IfReqData {
2020-09-24 17:48:13 +00:00
flags: libc::c_short,
value: libc::c_int,
addr: (libc::c_short, Ipv4Addr),
2021-03-02 15:31:40 +00:00
_dummy: [u8; 24],
2020-07-13 22:03:08 +00:00
}
#[repr(C)]
struct IfReq {
2020-09-24 17:48:13 +00:00
ifr_name: [u8; libc::IF_NAMESIZE],
2021-03-02 15:31:40 +00:00
data: IfReqData,
2020-07-13 22:03:08 +00:00
}
impl IfReq {
2020-09-24 17:48:13 +00:00
fn new(name: &str) -> Self {
assert!(name.len() < libc::IF_NAMESIZE);
2021-01-23 19:29:15 +00:00
let mut ifr_name = [0; libc::IF_NAMESIZE];
2020-07-13 22:03:08 +00:00
ifr_name[..name.len()].clone_from_slice(name.as_bytes());
2020-09-24 17:48:13 +00:00
Self { ifr_name, data: IfReqData { _dummy: [0; 24] } }
2020-07-13 22:03:08 +00:00
}
2015-11-22 18:00:56 +00:00
}
2016-06-26 17:18:38 +00:00
/// The type of a tun/tap device
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq)]
2016-06-26 17:18:38 +00:00
pub enum Type {
/// Tun interface: This interface transports IP packets.
#[serde(rename = "tun")]
2016-06-26 17:18:38 +00:00
Tun,
2020-05-29 06:37:29 +00:00
/// Tap interface: This interface transports Ethernet frames.
#[serde(rename = "tap")]
2021-03-02 15:31:40 +00:00
Tap,
2016-06-26 17:18:38 +00:00
}
impl fmt::Display for Type {
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
Type::Tun => write!(formatter, "tun"),
2021-03-02 15:31:40 +00:00
Type::Tap => write!(formatter, "tap"),
2016-06-26 17:18:38 +00:00
}
}
}
2020-05-29 06:37:29 +00:00
impl FromStr for Type {
type Err = &'static str;
fn from_str(text: &str) -> Result<Self, Self::Err> {
Ok(match &text.to_lowercase() as &str {
"tun" => Self::Tun,
"tap" => Self::Tap,
2021-03-02 15:31:40 +00:00
_ => return Err("Unknown device type"),
2020-05-29 06:37:29 +00:00
})
}
}
2016-06-26 17:18:38 +00:00
2021-03-02 15:31:40 +00:00
#[async_trait]
pub trait Device: Send + 'static + Sized {
2019-02-26 00:21:15 +00:00
/// Returns the type of this device
fn get_type(&self) -> Type;
/// Returns the interface name of this device.
fn ifname(&self) -> &str;
/// Reads a packet/frame from the device
///
/// This method reads one packet or frame (depending on the device type) into the `buffer`.
/// The `buffer` must be large enough to hold a packet/frame of maximum size, otherwise the
/// packet/frame will be split.
/// The method will block until a packet/frame is ready to be read.
/// On success, the method will return the starting position and the amount of bytes read into
/// the buffer.
///
/// # Errors
/// This method will return an error if the underlying read call fails.
2021-03-02 15:31:40 +00:00
async fn read(&mut self, buffer: &mut MsgBuffer) -> Result<(), Error>;
2019-02-26 00:21:15 +00:00
/// Writes a packet/frame to the device
///
/// This method writes one packet or frame (depending on the device type) from `data` to the
/// device. The data starts at the position `start` in the buffer. The buffer should have at
/// least 4 bytes of space before the start of the packet.
/// The method will block until the packet/frame has been written.
///
/// # Errors
/// This method will return an error if the underlying read call fails.
2021-03-02 15:31:40 +00:00
async fn write(&mut self, buffer: &mut MsgBuffer) -> Result<(), Error>;
async fn duplicate(&self) -> Result<Self, Error>;
2020-09-24 17:48:13 +00:00
fn get_ip(&self) -> Result<Ipv4Addr, Error>;
2019-02-26 00:21:15 +00:00
}
2016-06-26 17:18:38 +00:00
/// Represents a tun/tap device
2019-02-26 00:21:15 +00:00
pub struct TunTapDevice {
2020-09-24 17:48:13 +00:00
fd: File,
2016-06-26 17:18:38 +00:00
ifname: String,
2021-03-02 15:31:40 +00:00
type_: Type,
2021-02-19 23:17:06 +00:00
}
2019-02-26 00:21:15 +00:00
impl TunTapDevice {
2016-06-26 17:18:38 +00:00
/// Creates a new tun/tap device
///
/// This method creates a new device of the `type_` kind with the name `ifname`.
///
/// The `ifname` must be an interface name not longer than 31 bytes. It can contain the string
/// `%d` which will be replaced with the next free index number that guarantees that the
/// interface name will be free. In this case, the `ifname()` method can be used to obtain the
/// final interface name.
///
/// # Errors
/// This method will return an error when the underlying system call fails. Common cases are:
2019-12-04 08:32:35 +00:00
/// - The special device file `/dev/net/tun` does not exist or is not accessible by the current user.
2016-06-26 17:18:38 +00:00
/// - The interface name is invalid or already in use.
2019-12-04 08:32:35 +00:00
/// - The current user does not have enough permissions to create tun/tap devices (this requires root permissions).
2016-06-26 17:18:38 +00:00
///
/// # Panics
/// This method panics if the interface name is longer than 31 bytes.
2020-11-02 21:32:27 +00:00
#[allow(clippy::useless_conversion)]
2021-03-02 15:31:40 +00:00
pub async fn new(ifname: &str, type_: Type, path: Option<&str>) -> io::Result<Self> {
2019-02-12 18:30:38 +00:00
let path = path.unwrap_or_else(|| Self::default_path(type_));
2021-03-02 15:31:40 +00:00
let fd = fs::OpenOptions::new().read(true).write(true).open(path).await?;
2020-07-13 22:03:08 +00:00
let flags = match type_ {
2020-09-24 17:48:13 +00:00
Type::Tun => libc::IFF_TUN | libc::IFF_NO_PI,
2021-03-02 15:31:40 +00:00
Type::Tap => libc::IFF_TAP | libc::IFF_NO_PI,
2015-11-23 00:40:47 +00:00
};
2020-09-24 17:48:13 +00:00
let mut ifreq = IfReq::new(ifname);
ifreq.data.flags = flags as libc::c_short;
2020-11-02 21:32:27 +00:00
let res = unsafe { libc::ioctl(fd.as_raw_fd(), TUNSETIFF.try_into().unwrap(), &mut ifreq) };
2015-11-22 18:00:56 +00:00
match res {
0 => {
2020-09-24 17:48:13 +00:00
let mut ifname = String::with_capacity(32);
let mut cursor = Cursor::new(ifreq.ifr_name);
2021-03-02 15:31:40 +00:00
cursor.read_to_string(&mut ifname).await?;
2020-09-24 17:48:13 +00:00
ifname = ifname.trim_end_matches('\0').to_owned();
2020-07-13 22:03:08 +00:00
Ok(Self { fd, ifname, type_ })
2019-12-04 08:32:35 +00:00
}
2021-03-02 15:31:40 +00:00
_ => Err(IoError::last_os_error()),
2015-11-22 18:00:56 +00:00
}
}
2019-02-12 18:30:38 +00:00
/// Returns the default device path for a given type
#[inline]
pub fn default_path(type_: Type) -> &'static str {
match type_ {
2021-03-02 15:31:40 +00:00
Type::Tun | Type::Tap => "/dev/net/tun",
2019-02-12 18:30:38 +00:00
}
}
#[cfg(any(target_os = "linux", target_os = "android"))]
#[inline]
2020-09-24 17:48:13 +00:00
fn correct_data_after_read(&mut self, _buffer: &mut MsgBuffer) {}
2019-12-04 08:32:35 +00:00
#[cfg(any(
target_os = "bitrig",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"
))]
#[inline]
2020-09-24 17:48:13 +00:00
fn correct_data_after_read(&mut self, buffer: &mut MsgBuffer) {
if self.type_ == Type::Tun {
// BSD-based systems add a 4-byte header containing the Ethertype for TUN
2020-09-24 17:48:13 +00:00
buffer.set_start(buffer.get_start() + 4);
} else {
}
2015-11-22 18:00:56 +00:00
}
#[cfg(any(target_os = "linux", target_os = "android"))]
#[inline]
2020-09-24 17:48:13 +00:00
fn correct_data_before_write(&mut self, _buffer: &mut MsgBuffer) {}
2019-12-04 08:32:35 +00:00
#[cfg(any(
target_os = "bitrig",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"
))]
#[inline]
2020-09-24 17:48:13 +00:00
fn correct_data_before_write(&mut self, buffer: &mut MsgBuffer) {
if self.type_ == Type::Tun {
// BSD-based systems add a 4-byte header containing the Ethertype for TUN
2020-09-24 17:48:13 +00:00
buffer.set_start(buffer.get_start() - 4);
match buffer.message()[4] >> 4 {
2019-12-04 08:32:35 +00:00
// IP version
2020-09-24 17:48:13 +00:00
4 => buffer.message_mut()[0..4].copy_from_slice(&[0x00, 0x00, 0x08, 0x00]),
6 => buffer.message_mut()[0..4].copy_from_slice(&[0x00, 0x00, 0x86, 0xdd]),
2021-03-02 15:31:40 +00:00
_ => unreachable!(),
}
}
}
2020-09-24 17:48:13 +00:00
pub fn get_overhead(&self) -> usize {
40 /* for outer IPv6 header, can't be sure to only have IPv4 peers */
+ 8 /* for outer UDP header */
+ crypto::EXTRA_LEN + crypto::TAG_LEN /* crypto overhead */
+ 1 /* message type header */
+ match self.type_ {
2020-11-03 17:49:35 +00:00
Type::Tap => 14, /* inner ethernet header */
2020-11-28 22:47:43 +00:00
Type::Tun => 0
2020-09-24 17:48:13 +00:00
}
}
2021-03-02 15:31:40 +00:00
pub async fn set_mtu(&self, value: Option<usize>) -> io::Result<()> {
2020-09-24 17:48:13 +00:00
let value = match value {
Some(value) => value,
None => {
2021-03-02 15:31:40 +00:00
let default_device = get_default_device().await?;
2020-09-24 17:48:13 +00:00
get_device_mtu(&default_device)? - self.get_overhead()
}
};
info!("Setting MTU {} on device {}", value, self.ifname);
set_device_mtu(&self.ifname, value)
}
pub fn configure(&self, addr: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
set_device_addr(&self.ifname, addr)?;
set_device_netmask(&self.ifname, netmask)?;
set_device_enabled(&self.ifname, true)
}
2021-03-02 15:31:40 +00:00
pub async fn get_rp_filter(&self) -> io::Result<u8> {
Ok(cmp::max(get_rp_filter("all").await?, get_rp_filter(&self.ifname).await?))
2020-09-24 17:48:13 +00:00
}
2021-03-02 15:31:40 +00:00
pub async fn fix_rp_filter(&self) -> io::Result<()> {
if get_rp_filter("all").await? > 1 {
2020-09-24 17:48:13 +00:00
info!("Setting net.ipv4.conf.all.rp_filter=1");
2021-03-02 15:31:40 +00:00
set_rp_filter("all", 1).await?
2020-09-24 17:48:13 +00:00
}
2021-03-02 15:31:40 +00:00
if get_rp_filter(&self.ifname).await? != 1 {
2020-09-24 17:48:13 +00:00
info!("Setting net.ipv4.conf.{}.rp_filter=1", self.ifname);
2021-03-02 15:31:40 +00:00
set_rp_filter(&self.ifname, 1).await?
2020-09-24 17:48:13 +00:00
}
Ok(())
}
2015-11-22 18:00:56 +00:00
}
2015-11-24 11:12:15 +00:00
2021-03-02 15:31:40 +00:00
#[async_trait]
2019-02-26 00:21:15 +00:00
impl Device for TunTapDevice {
fn get_type(&self) -> Type {
self.type_
}
fn ifname(&self) -> &str {
&self.ifname
}
2021-03-02 15:31:40 +00:00
async fn duplicate(&self) -> Result<Self, Error> {
Ok(Self {
fd: self.fd.try_clone().await.map_err(|e| Error::DeviceIo("Failed to clone device", e))?,
ifname: self.ifname.clone(),
type_: self.type_,
})
}
async fn read(&mut self, buffer: &mut MsgBuffer) -> Result<(), Error> {
2020-09-24 17:48:13 +00:00
buffer.clear();
2021-03-02 15:31:40 +00:00
let read = self.fd.read(buffer.buffer()).await.map_err(|e| Error::DeviceIo("Read error", e))?;
2020-09-24 17:48:13 +00:00
buffer.set_length(read);
self.correct_data_after_read(buffer);
Ok(())
2019-02-26 00:21:15 +00:00
}
2021-03-02 15:31:40 +00:00
async fn write(&mut self, buffer: &mut MsgBuffer) -> Result<(), Error> {
2020-09-24 17:48:13 +00:00
self.correct_data_before_write(buffer);
2021-03-02 15:31:40 +00:00
match self.fd.write_all(buffer.message()).await {
Ok(_) => self.fd.flush().await.map_err(|e| Error::DeviceIo("Flush error", e)),
Err(e) => Err(Error::DeviceIo("Write error", e)),
2019-02-26 00:21:15 +00:00
}
}
2020-09-24 17:48:13 +00:00
fn get_ip(&self) -> Result<Ipv4Addr, Error> {
get_device_addr(&self.ifname).map_err(|e| Error::DeviceIo("Error getting IP address", e))
}
2019-02-26 00:21:15 +00:00
}
2021-02-19 23:17:06 +00:00
#[derive(Clone)]
2019-02-26 00:21:15 +00:00
pub struct MockDevice {
2021-02-19 23:17:06 +00:00
inbound: Arc<Mutex<VecDeque<Vec<u8>>>>,
2021-03-02 15:31:40 +00:00
outbound: Arc<Mutex<VecDeque<Vec<u8>>>>,
2019-02-26 00:21:15 +00:00
}
impl MockDevice {
pub fn new() -> Self {
2019-03-01 22:25:42 +00:00
Default::default()
2019-02-26 00:21:15 +00:00
}
pub fn put_inbound(&mut self, data: Vec<u8>) {
2021-02-19 23:17:06 +00:00
self.inbound.lock().push_back(data)
2019-02-26 00:21:15 +00:00
}
pub fn pop_outbound(&mut self) -> Option<Vec<u8>> {
2021-02-19 23:17:06 +00:00
self.outbound.lock().pop_front()
2019-02-26 00:21:15 +00:00
}
2019-02-26 17:36:54 +00:00
pub fn has_inbound(&self) -> bool {
2021-02-19 23:17:06 +00:00
!self.inbound.lock().is_empty()
2019-02-26 00:21:15 +00:00
}
}
2021-03-02 15:31:40 +00:00
#[async_trait]
2019-02-26 00:21:15 +00:00
impl Device for MockDevice {
2021-03-02 15:31:40 +00:00
async fn duplicate(&self) -> Result<Self, Error> {
Ok(self.clone())
}
2019-02-26 00:21:15 +00:00
fn get_type(&self) -> Type {
2020-11-28 22:47:43 +00:00
Type::Tun
2019-02-26 00:21:15 +00:00
}
fn ifname(&self) -> &str {
2021-01-24 16:47:02 +00:00
"mock0"
2019-02-26 00:21:15 +00:00
}
2021-03-02 15:31:40 +00:00
async fn read(&mut self, buffer: &mut MsgBuffer) -> Result<(), Error> {
2021-02-19 23:17:06 +00:00
if let Some(data) = self.inbound.lock().pop_front() {
2020-09-24 17:48:13 +00:00
buffer.clear();
buffer.set_length(data.len());
buffer.message_mut().copy_from_slice(&data);
Ok(())
2019-02-26 00:21:15 +00:00
} else {
2020-09-24 17:48:13 +00:00
Err(Error::Device("empty"))
2019-02-26 00:21:15 +00:00
}
}
2021-03-02 15:31:40 +00:00
async fn write(&mut self, buffer: &mut MsgBuffer) -> Result<(), Error> {
2021-02-19 23:17:06 +00:00
self.outbound.lock().push_back(buffer.message().into());
2019-02-26 00:21:15 +00:00
Ok(())
}
2020-09-24 17:48:13 +00:00
fn get_ip(&self) -> Result<Ipv4Addr, Error> {
Err(Error::Device("Dummy devices have no IP address"))
}
2019-02-26 00:21:15 +00:00
}
2019-03-01 22:25:42 +00:00
impl Default for MockDevice {
fn default() -> Self {
2021-02-19 23:17:06 +00:00
Self {
outbound: Arc::new(Mutex::new(VecDeque::with_capacity(10))),
2021-03-02 15:31:40 +00:00
inbound: Arc::new(Mutex::new(VecDeque::with_capacity(10))),
2021-02-19 23:17:06 +00:00
}
2019-03-01 22:25:42 +00:00
}
}
2020-11-02 21:32:27 +00:00
#[allow(clippy::useless_conversion)]
2020-09-24 17:48:13 +00:00
fn set_device_mtu(ifname: &str, mtu: usize) -> io::Result<()> {
let sock = UdpSocket::bind("0.0.0.0:0")?;
let mut ifreq = IfReq::new(ifname);
ifreq.data.value = mtu as libc::c_int;
2020-11-02 21:32:27 +00:00
let res = unsafe { libc::ioctl(sock.as_raw_fd(), libc::SIOCSIFMTU.try_into().unwrap(), &mut ifreq) };
2020-09-24 17:48:13 +00:00
match res {
0 => Ok(()),
2021-03-02 15:31:40 +00:00
_ => Err(IoError::last_os_error()),
2020-09-24 17:48:13 +00:00
}
}
2020-11-02 21:32:27 +00:00
#[allow(clippy::useless_conversion)]
2020-09-24 17:48:13 +00:00
fn get_device_mtu(ifname: &str) -> io::Result<usize> {
let sock = UdpSocket::bind("0.0.0.0:0")?;
let mut ifreq = IfReq::new(ifname);
2020-11-02 21:32:27 +00:00
let res = unsafe { libc::ioctl(sock.as_raw_fd(), libc::SIOCGIFMTU.try_into().unwrap(), &mut ifreq) };
2020-09-24 17:48:13 +00:00
match res {
0 => Ok(unsafe { ifreq.data.value as usize }),
2021-03-02 15:31:40 +00:00
_ => Err(IoError::last_os_error()),
2020-09-24 17:48:13 +00:00
}
}
2020-11-02 21:32:27 +00:00
#[allow(clippy::useless_conversion)]
2020-09-24 17:48:13 +00:00
fn get_device_addr(ifname: &str) -> io::Result<Ipv4Addr> {
let sock = UdpSocket::bind("0.0.0.0:0")?;
let mut ifreq = IfReq::new(ifname);
2020-11-02 21:32:27 +00:00
let res = unsafe { libc::ioctl(sock.as_raw_fd(), libc::SIOCGIFADDR.try_into().unwrap(), &mut ifreq) };
2020-09-24 17:48:13 +00:00
match res {
0 => {
let af = unsafe { ifreq.data.addr.0 };
if af as libc::c_int != libc::AF_INET {
2021-03-02 15:31:40 +00:00
return Err(io::Error::new(io::ErrorKind::AddrNotAvailable, "Invalid address family".to_owned()));
2020-09-24 17:48:13 +00:00
}
let ip = unsafe { ifreq.data.addr.1 };
Ok(ip)
}
2021-03-02 15:31:40 +00:00
_ => Err(IoError::last_os_error()),
2020-09-24 17:48:13 +00:00
}
}
2020-11-02 21:32:27 +00:00
#[allow(clippy::useless_conversion)]
2020-09-24 17:48:13 +00:00
fn set_device_addr(ifname: &str, addr: Ipv4Addr) -> io::Result<()> {
let sock = UdpSocket::bind("0.0.0.0:0")?;
let mut ifreq = IfReq::new(ifname);
ifreq.data.addr = (libc::AF_INET as libc::c_short, addr);
2020-11-02 21:32:27 +00:00
let res = unsafe { libc::ioctl(sock.as_raw_fd(), libc::SIOCSIFADDR.try_into().unwrap(), &mut ifreq) };
2020-09-24 17:48:13 +00:00
match res {
0 => Ok(()),
2021-03-02 15:31:40 +00:00
_ => Err(IoError::last_os_error()),
2020-09-24 17:48:13 +00:00
}
}
#[allow(dead_code)]
2020-11-02 21:32:27 +00:00
#[allow(clippy::useless_conversion)]
2020-09-24 17:48:13 +00:00
fn get_device_netmask(ifname: &str) -> io::Result<Ipv4Addr> {
let sock = UdpSocket::bind("0.0.0.0:0")?;
let mut ifreq = IfReq::new(ifname);
2020-11-02 21:32:27 +00:00
let res = unsafe { libc::ioctl(sock.as_raw_fd(), libc::SIOCGIFNETMASK.try_into().unwrap(), &mut ifreq) };
2020-09-24 17:48:13 +00:00
match res {
0 => {
let af = unsafe { ifreq.data.addr.0 };
if af as libc::c_int != libc::AF_INET {
2021-03-02 15:31:40 +00:00
return Err(io::Error::new(io::ErrorKind::AddrNotAvailable, "Invalid address family".to_owned()));
2020-09-24 17:48:13 +00:00
}
let ip = unsafe { ifreq.data.addr.1 };
Ok(ip)
}
2021-03-02 15:31:40 +00:00
_ => Err(IoError::last_os_error()),
2020-09-24 17:48:13 +00:00
}
}
2020-11-02 21:32:27 +00:00
#[allow(clippy::useless_conversion)]
2020-09-24 17:48:13 +00:00
fn set_device_netmask(ifname: &str, addr: Ipv4Addr) -> io::Result<()> {
let sock = UdpSocket::bind("0.0.0.0:0")?;
let mut ifreq = IfReq::new(ifname);
ifreq.data.addr = (libc::AF_INET as libc::c_short, addr);
2020-11-02 21:32:27 +00:00
let res = unsafe { libc::ioctl(sock.as_raw_fd(), libc::SIOCSIFNETMASK.try_into().unwrap(), &mut ifreq) };
2020-09-24 17:48:13 +00:00
match res {
0 => Ok(()),
2021-03-02 15:31:40 +00:00
_ => Err(IoError::last_os_error()),
2020-09-24 17:48:13 +00:00
}
}
2020-11-02 21:32:27 +00:00
#[allow(clippy::useless_conversion)]
2020-09-24 17:48:13 +00:00
fn set_device_enabled(ifname: &str, up: bool) -> io::Result<()> {
let sock = UdpSocket::bind("0.0.0.0:0")?;
let mut ifreq = IfReq::new(ifname);
2020-11-02 21:32:27 +00:00
if unsafe { libc::ioctl(sock.as_raw_fd(), libc::SIOCGIFFLAGS.try_into().unwrap(), &mut ifreq) } != 0 {
2021-03-02 15:31:40 +00:00
return Err(IoError::last_os_error());
2020-09-24 17:48:13 +00:00
}
if up {
unsafe { ifreq.data.value |= libc::IFF_UP | libc::IFF_RUNNING }
} else {
unsafe { ifreq.data.value &= !libc::IFF_UP }
}
2020-11-02 21:32:27 +00:00
let res = unsafe { libc::ioctl(sock.as_raw_fd(), libc::SIOCSIFFLAGS.try_into().unwrap(), &mut ifreq) };
2020-09-24 17:48:13 +00:00
match res {
0 => Ok(()),
2021-03-02 15:31:40 +00:00
_ => Err(IoError::last_os_error()),
2020-09-24 17:48:13 +00:00
}
}
2021-03-02 15:31:40 +00:00
async fn get_default_device() -> io::Result<String> {
let mut fd = BufReader::new(File::open("/proc/net/route").await?);
2020-09-24 17:48:13 +00:00
let mut best = None;
2021-03-02 15:31:40 +00:00
let mut line = String::with_capacity(80);
while let Ok(read) = fd.read_line(&mut line).await {
if read == 0 {
break;
}
2020-09-24 17:48:13 +00:00
let parts = line.split('\t').collect::<Vec<_>>();
if parts[1] == "00000000" {
best = Some(parts[0].to_string());
2021-03-02 15:31:40 +00:00
break;
2020-09-24 17:48:13 +00:00
}
if parts[2] != "00000000" {
best = Some(parts[0].to_string())
}
}
if let Some(ifname) = best {
Ok(ifname)
} else {
Err(io::Error::new(io::ErrorKind::NotFound, "No default interface found".to_string()))
}
}
2021-03-02 15:31:40 +00:00
async fn get_rp_filter(device: &str) -> io::Result<u8> {
let mut fd = File::open(format!("/proc/sys/net/ipv4/conf/{}/rp_filter", device)).await?;
2020-09-24 17:48:13 +00:00
let mut contents = String::with_capacity(10);
2021-03-02 15:31:40 +00:00
fd.read_to_string(&mut contents).await?;
2020-09-24 17:48:13 +00:00
u8::from_str(contents.trim()).map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "Invalid rp_filter value"))
}
2021-03-02 15:31:40 +00:00
async fn set_rp_filter(device: &str, val: u8) -> io::Result<()> {
let mut fd = File::create(format!("/proc/sys/net/ipv4/conf/{}/rp_filter", device)).await?;
fd.write_all(format!("{}", val).as_bytes()).await
2020-09-24 17:48:13 +00:00
}