diff --git a/Cargo.toml b/Cargo.toml index 70caa10..e5c597e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,7 @@ anyhow = "1.0.70" lazy_static = "1.4.0" rand = "0.8" chrono = "0.4" +thiserror = "1.0.63" [workspace.package] version = "0.0.3" diff --git a/crates/wasi/Cargo.toml b/crates/wasi/Cargo.toml index 0c89080..c718605 100644 --- a/crates/wasi/Cargo.toml +++ b/crates/wasi/Cargo.toml @@ -21,6 +21,7 @@ json = {workspace = true} crossbeam-channel = {workspace = true} tuntap = {workspace = true, optional = true} anyhow = {workspace = true} +thiserror = {workspace = true} diff --git a/crates/wasi/src/emulator.rs b/crates/wasi/src/emulator.rs index 0393bc7..6148a8e 100644 --- a/crates/wasi/src/emulator.rs +++ b/crates/wasi/src/emulator.rs @@ -1,15 +1,16 @@ #![allow(unused)] use std::{ + time, cell::Cell, - collections::HashMap, rc::{Rc, Weak}, - sync::mpsc::{self, Receiver, Sender}, + collections::HashMap, thread::{JoinHandle, Thread}, - time, + sync::mpsc::{self, Receiver, Sender}, }; - use tokio::sync::mpsc::channel; -use wasmtime::{Extern, Instance, Linker, Store, Table}; +use wasmtime::{ + Extern, Instance, Linker, Store, Table +}; use crate::{ io::IO, @@ -26,24 +27,24 @@ use crate::{ vga::VGAScreen, log::{self, LOG}, ws_thr::WsThread, - adapter::{NetAdapter, NetTermAdapter}, floppy::FloppyController, jit::{JitMsg, JitWorker}, - ContextTrait, Setting, StoreT, CPU, WASM_TABLE_OFFSET, virtio::VirtIO, virtio9p::Virtio9p, + adapter::{NetAdapter, NetTermAdapter}, + ContextTrait, Setting, StoreT, CPU, WASM_TABLE_OFFSET, }; #[cfg(feature = "tap")] use crate::tun_thr::TunThread; pub(crate) struct InnerEmulator { - start_time: time::Instant, setting: Setting, cpu: Option, bus: Option, table: Option, bios: Option>, vga_bios: Option>, + start_time: time::Instant, jit_tx: Option>, tick_trigger: Vec, net_adapter: Option, diff --git a/crates/wasi/src/lib.rs b/crates/wasi/src/lib.rs index dfc3924..4331066 100644 --- a/crates/wasi/src/lib.rs +++ b/crates/wasi/src/lib.rs @@ -1,24 +1,17 @@ #![allow(dead_code)] -#[macro_use] -mod log; - use std::rc::Weak; use std::slice; +use wasmtime::*; -const ALL_DEBUG: bool = true; +#[macro_use] +mod log; -type StoreT = Weak>; -use adapter::NetAdapter; -use virtio::VirtIO; -use virtio9p::Virtio9p; -use wasmtime::*; mod run; mod io; mod bus; mod cpu; mod dev; mod dma; - mod jit; mod mem; mod pic; @@ -44,6 +37,7 @@ mod filesystem; mod setting; mod emulator; mod utils; +mod nat; pub mod consts; use io::IO; @@ -72,7 +66,12 @@ pub use run::run_with_setting; pub use log::set_log_file_name; pub use log::set_log_mask; +use adapter::NetAdapter; +use virtio::VirtIO; +use virtio9p::Virtio9p; +type StoreT = Weak>; +const ALL_DEBUG: bool = true; trait ContextTrait { diff --git a/crates/wasi/src/nat/mod.rs b/crates/wasi/src/nat/mod.rs new file mode 100644 index 0000000..a5c9bff --- /dev/null +++ b/crates/wasi/src/nat/mod.rs @@ -0,0 +1,75 @@ +use std::{ + fs::OpenOptions, io::{self, Write}, process::{Command, Stdio} +}; +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum NatError { + #[error("execute command error.")] + CommandError, + #[error("io error. detail: {0}.")] + IoError(io::Error), + #[error("utf8 code error.")] + Utf8CodeError, +} + +pub(crate)struct Nat { + tap_name: String, +} + +impl Nat { + pub fn new(name: &str) -> Self { + Self { + tap_name: name.to_string() + } + } +} + +#[cfg(target_os="macos")] +impl Nat { + fn sysctl(enable: bool) -> Result<(), NatError> { + let mut command = Command::new("sysctl"); + let enable = if enable { 1 } else { 0 }; + command.args(&["-w", &format!("net.inet.ip.forwarding={enable}")]); + command.stdout(Stdio::piped()); + command.stderr(Stdio::piped()); + let mut child = command.spawn().map_err(|e| NatError::IoError(e))?; + let exit_code = child.wait().map_err(|e| NatError::IoError(e))?; + if exit_code.success() { + Ok(()) + } else { + Err(NatError::CommandError) + } + } + + fn pfctl() -> Result<(), NatError> { + let mut command = Command::new("pfctl"); + let child = command.args( &["-f", "/etc/pf.anchors/bls-vm-nat", "-e" ]) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn().map_err(|e| NatError::IoError(e))?; + let output = child.wait_with_output().map_err(|e| NatError::IoError(e))?; + if output.status.success() { + return Ok(()); + } else { + let out_string = String::from_utf8(output.stderr).map_err(|_| NatError::Utf8CodeError)?; + if let Some(_) = out_string.find("pf already enabled") { + return Ok(()); + } + } + Err(NatError::CommandError) + } + + + pub fn enable(&self) -> anyhow::Result<()> { + let mut pfctl = OpenOptions::new() + .write(true) + .create(true) + .open("/etc/pf.anchors/bls-vm-nat")?; + let cmd = format!("nat on en0 from {}:network to any -> (en0)\n", &self.tap_name); + pfctl.write_all(cmd.as_bytes())?; + Self::sysctl(true)?; + Self::pfctl()?; + Ok(()) + } +} \ No newline at end of file diff --git a/crates/wasi/src/tun_thr.rs b/crates/wasi/src/tun_thr.rs index 0a79aa5..61f5801 100644 --- a/crates/wasi/src/tun_thr.rs +++ b/crates/wasi/src/tun_thr.rs @@ -8,8 +8,8 @@ use crossbeam_channel::{ use tuntap::{ Tap, - Device, Token, + Device, Events, Interest, EtherAddr, @@ -19,6 +19,8 @@ use tuntap::{ #[allow(unused_imports)] use crate::ContextTrait; +use crate::nat::Nat; + #[repr(C)] #[derive(Debug)] struct EtherHdr { @@ -102,6 +104,11 @@ impl TunThread { return; }, }; + // after open tap, enable the nat. + let nat = Nat::new(tap.name()); + if nat.enable().is_err() { + eprintln!("Nat start fail."); + } tap.set_nonblock().unwrap(); let mut tap_poll = tuntap::Poller::new(); let mut events = Events::with_capacity(10);