Skip to content

Commit

Permalink
linux nat support
Browse files Browse the repository at this point in the history
  • Loading branch information
Joinhack committed Jul 28, 2024
1 parent cda1605 commit b26220e
Showing 1 changed file with 73 additions and 1 deletion.
74 changes: 73 additions & 1 deletion crates/wasi/src/nat/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::{
fs::OpenOptions, io::{self, Write}, process::{Command, Stdio}
fs::{self, OpenOptions}, io::{self, Write}, process::{Command, Stdio}
};
use thiserror::Error;

Expand All @@ -11,6 +11,8 @@ pub enum NatError {
IoError(io::Error),
#[error("utf8 code error.")]
Utf8CodeError,
#[error("no interface found")]
NoInterfaceFound,
}

pub(crate)struct Nat {
Expand All @@ -25,6 +27,76 @@ impl Nat {
}
}

#[cfg(target_os="windows")]
impl Nat {
pub fn enable(&self) -> Result<(), NatError> {
Ok(())
}
}

macro_rules! io_wrap {
($io_op:expr) => {
$io_op.map_err(|e| NatError::IoError(e))?
};
}

#[cfg(target_os="linux")]
impl Nat {
fn forward(enable: bool) -> Result<(), NatError> {
let mut ip_fwf = io_wrap!(fs::OpenOptions::new()
.write(true)
.open("/proc/sys/net/ipv4/ip_forward"));
let enable = if enable { b"1" } else { b"0" };
io_wrap!(ip_fwf.write(enable));
Ok(())
}

fn find_active_if() -> Result<String, NatError> {
let net_path = std::path::Path::new("/sys/class/net");
let read_dir = io_wrap!(fs::read_dir(&net_path));
for entry in read_dir {
let entry = io_wrap!(entry);
let path = entry.path();
if path.is_symlink() {
let path = io_wrap!(fs::read_link(&path));
let path_str = path.to_str();
if let Some(s) = path_str {
if s.contains("virtual") {
continue;
}
let split = s.split("/");
if let Some(s) = split.last() {
return Ok(s.into());
}
}
}
}
Err(NatError::NoInterfaceFound)
}

fn iptable() -> Result<(), NatError> {
let active_if = Self::find_active_if()?;
let mut command = Command::new("iptables");
command.args(&["-t", "nat", "-A", "POSTROUTING", "-j", "MASQUERADE", "-o", &active_if]);
command.stdout(Stdio::piped());
command.stderr(Stdio::piped());
let child = command.spawn().map_err(|e| NatError::IoError(e))?;
let output = child.wait_with_output()
.map_err(|e| NatError::IoError(e))?;
if output.status.success() {
Ok(())
} else {
Err(NatError::CommandError)
}
}

pub fn enable(&self) -> Result<(), NatError> {
Self::forward(true)?;
Self::iptable()?;
Ok(())
}
}

#[cfg(target_os="macos")]
impl Nat {
fn sysctl(enable: bool) -> Result<(), NatError> {
Expand Down

0 comments on commit b26220e

Please sign in to comment.