From 1b69b4a8e145c8848ccc604bdfc22d28f2bf394b Mon Sep 17 00:00:00 2001 From: Jett Chen Date: Sun, 27 Aug 2023 10:21:55 +0800 Subject: [PATCH] Add thread spawning FFI --- .../PacketTunnelProvider.swift | 20 ++---- Apple/NetworkExtension/libburrow/libburrow.h | 1 + Cargo.lock | 11 +++ burrow/Cargo.toml | 2 +- burrow/src/lib.rs | 21 ++++++ burrow/src/server.rs | 69 ++++++++++++++++--- tun/src/tokio/mod.rs | 3 - 7 files changed, 98 insertions(+), 29 deletions(-) diff --git a/Apple/NetworkExtension/PacketTunnelProvider.swift b/Apple/NetworkExtension/PacketTunnelProvider.swift index e885d82..23b8606 100644 --- a/Apple/NetworkExtension/PacketTunnelProvider.swift +++ b/Apple/NetworkExtension/PacketTunnelProvider.swift @@ -4,23 +4,15 @@ import OSLog class PacketTunnelProvider: NEPacketTunnelProvider { let logger = Logger(subsystem: "com.hackclub.burrow", category: "General") + var osInitialized = false override func startTunnel(options: [String: NSObject]?, completionHandler: @escaping (Error?) -> Void) { - libburrow.initialize_oslog() - let fild = libburrow.retrieve() - if fild == -1 { - // Not sure if this is the right way to return an error - logger.error("Failed to retrieve file descriptor for burrow.") - let err = NSError( - domain: "com.hackclub.burrow", - code: 1_010, - userInfo: [NSLocalizedDescriptionKey: "Failed to find TunInterface"] - ) - completionHandler(err) + if(!osInitialized){ + libburrow.initialize_oslog() + osInitialized=true } - logger.info("fd: \(fild)") - let network_settings = genNetSec(fild: fild) - logger.info("Network Settings: - ipv4:\(network_settings.ipv4Settings) -mtu: \(network_settings.mtu)") + libburrow.spawn_server() + logger.debug("spawned server") completionHandler(nil) } diff --git a/Apple/NetworkExtension/libburrow/libburrow.h b/Apple/NetworkExtension/libburrow/libburrow.h index 52eb8aa..eba6198 100644 --- a/Apple/NetworkExtension/libburrow/libburrow.h +++ b/Apple/NetworkExtension/libburrow/libburrow.h @@ -9,3 +9,4 @@ typedef struct { NetWorkSettings getNetworkSettings(int); void initialize_oslog(); +void spawn_server(); diff --git a/Cargo.lock b/Cargo.lock index 79a7d93..72e9c1b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1136,6 +1136,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi 0.3.1", + "libc", +] + [[package]] name = "once_cell" version = "1.17.1" @@ -1768,6 +1778,7 @@ dependencies = [ "bytes", "libc", "mio", + "num_cpus", "pin-project-lite", "socket2", "tokio-macros", diff --git a/burrow/Cargo.toml b/burrow/Cargo.toml index 7551e18..5961b83 100644 --- a/burrow/Cargo.toml +++ b/burrow/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" crate-type = ["lib", "staticlib"] [dependencies] -tokio = { version = "1.21", features = ["rt", "macros"] } +tokio = { version = "1.21", features = ["rt", "rt-multi-thread", "macros"] } tun = { version = "0.1", path = "../tun" , features = ["tokio"]} clap = { version = "4.3.2", features = ["derive"] } env_logger = "0.10" diff --git a/burrow/src/lib.rs b/burrow/src/lib.rs index de0af85..471df26 100644 --- a/burrow/src/lib.rs +++ b/burrow/src/lib.rs @@ -16,6 +16,8 @@ use tun::TunInterface; #[cfg(target_vendor = "apple")] pub use apple::{NetWorkSettings, getNetworkSettings, initialize_oslog}; +#[cfg(any(target_os = "linux", target_vendor = "apple"))] +pub use server::spawn_server; // TODO Separate start and retrieve functions #[cfg(any(target_os = "linux", target_vendor = "apple"))] @@ -48,3 +50,22 @@ pub extern "C" fn retrieve() -> i32 { } } } + +pub fn get_iface() -> Option { + (1..100) + .filter_map(|i| { + debug!("Getting TunInterface with fd: {:?}", i); + let iface = unsafe { TunInterface::from_raw_fd(i) }; + match iface.name() { + Ok(name) => { + debug!("Found interface {}", name); + Some(iface) + }, + Err(_) => { + mem::forget(iface); + None + } + } + }) + .next() +} diff --git a/burrow/src/server.rs b/burrow/src/server.rs index 68e7d13..4c7b684 100644 --- a/burrow/src/server.rs +++ b/burrow/src/server.rs @@ -2,25 +2,72 @@ use axum::{body::Bytes, error_handling::HandleErrorLayer, extract::{DefaultBodyL use std::{ borrow::Cow, collections::HashMap, - sync::{Arc, RwLock}, + sync::Arc, time::Duration, }; +use tokio::sync::RwLock; +use tokio::runtime::Runtime; use std::net::{Ipv4Addr, SocketAddr}; use axum::handler::HandlerWithoutStateExt; use serde_json::json; -use tun::TunInterface; // TODO: refactor to tokio TunInterface, which doesn't implement `Send` +use tun::tokio::TunInterface; // TODO: refactor to tokio TunInterface, which doesn't implement `Send` +use std::thread; +use crate::get_iface; +use tracing::{info, debug, error}; type SharedState = Arc>; -pub async fn serve(ti: TunInterface){ - let state = Arc::new(RwLock::new( - ti - )); +#[no_mangle] +pub extern "C" fn spawn_server(){ + info!("Spawning server"); + let ti = get_iface().unwrap(); + debug!("Got interface"); + let rt = Runtime::new().unwrap(); + let _handle = thread::spawn(move || { + rt.spawn(async { + service(ti).await; + }); + }); + debug!("Spawned thread: finish spawn server"); +} + +async fn service(ti: crate::TunInterface){ + info!("Spawning service"); + let shared_state = Arc::new(RwLock::new(TunInterface::new(ti).unwrap())); + info!("Created shared state"); + let state_cl= shared_state.clone(); + let lp = tokio::spawn( + async move { + burrow_loop(state_cl).await; + } + ); + let srv = tokio::spawn( + async move { + serve(shared_state).await; + } + ); + info!("Created threads"); + tokio::join!(lp, srv); +} + +async fn burrow_loop(state: SharedState){ + debug!("loop called"); + let mut buf = [0u8; 1504]; + loop { + let n = state.write().await.read(&mut buf[..]).await.unwrap(); + // do something with the data + info!("read {} bytes", n); + } +} + +async fn serve(state: SharedState){ + debug!("serve called"); let app_router = Router::new() .route("/info", get(network_settings)) .with_state(state); let port = std::env::var("BURROW_PORT").unwrap_or("3000".to_string()); let sock_addr = SocketAddr::new(Ipv4Addr::LOCALHOST.into(), port.parse().unwrap()); + info!("Listening on {}...", sock_addr); axum::Server::bind(&sock_addr) .serve(app_router.into_make_service()) .await @@ -28,11 +75,11 @@ pub async fn serve(ti: TunInterface){ } #[debug_handler] -async fn network_settings(State(state): State) -> impl IntoResponse{ - let st = state.read().unwrap(); - let name = st.name().unwrap(); - let mtu = st.mtu().unwrap(); - let netmask = st.netmask().unwrap(); +async fn network_settings(State(state): State) -> impl IntoResponse { + let st = state.read().await; + let name = st.name().await.unwrap(); + let mtu = st.mtu().await.unwrap(); + let netmask = st.netmask().await.unwrap(); let res = Json(json!({ "name": name, "mtu": mtu, diff --git a/tun/src/tokio/mod.rs b/tun/src/tokio/mod.rs index 7c0c465..35f6dfa 100644 --- a/tun/src/tokio/mod.rs +++ b/tun/src/tokio/mod.rs @@ -5,9 +5,6 @@ pub struct TunInterface { inner: AsyncFd, } -unsafe impl Send for TunInterface { -} - impl TunInterface { pub fn new(tun: crate::TunInterface) -> io::Result { Ok(Self {