refactor FFI

This commit is contained in:
ssrlive 2024-02-07 23:32:51 +08:00
parent 8067394003
commit 8a67915388
9 changed files with 84 additions and 31 deletions

View file

@ -1,6 +1,6 @@
[package] [package]
name = "tun2proxy" name = "tun2proxy"
version = "0.2.3" version = "0.2.4"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -23,7 +23,7 @@ ipstack = { version = "0.0", features = ["log"] }
log = { version = "0.4", features = ["std"] } log = { version = "0.4", features = ["std"] }
socks5-impl = { version = "0.5" } socks5-impl = { version = "0.5" }
thiserror = "1.0" thiserror = "1.0"
tokio = { version = "1.35", features = ["full"] } tokio = { version = "1.36", features = ["full"] }
tproxy-config = { version = "0.1", features = ["log"] } tproxy-config = { version = "0.1", features = ["log"] }
trust-dns-proto = "0.23" trust-dns-proto = "0.23"
tun2 = { version = "1.0", features = ["async"] } tun2 = { version = "1.0", features = ["async"] }

View file

@ -17,5 +17,5 @@ cd tun2proxy
cargo build --release --target aarch64-apple-ios cargo build --release --target aarch64-apple-ios
cargo build --release --target x86_64-apple-ios cargo build --release --target x86_64-apple-ios
lipo -create target/aarch64-apple-ios/release/libtun2proxy.a target/x86_64-apple-ios/release/libtun2proxy.a -output target/libtun2proxy.a lipo -create target/aarch64-apple-ios/release/libtun2proxy.a target/x86_64-apple-ios/release/libtun2proxy.a -output target/libtun2proxy.a
cbindgen --config cbindgen.toml -l C -o target/tun2proxy-sys.h cbindgen --config cbindgen.toml -l C -o target/tun2proxy-ffi.h
``` ```

View file

@ -161,7 +161,7 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/bash; shellPath = /bin/bash;
shellScript = "set -e\nPATH=\"$PATH:${HOME}/.cargo/bin\"\nRUST_PROJ=${PROJECT_DIR}/..\ncd \"${RUST_PROJ}\"\ncargo build --release --target aarch64-apple-ios\ncargo build --release --target x86_64-apple-ios\nlipo -create target/aarch64-apple-ios/release/libtun2proxy.a target/x86_64-apple-ios/release/libtun2proxy.a -output target/libtun2proxy.a\ncbindgen --config cbindgen.toml -l C -o target/tun2proxy-sys.h\n"; shellScript = "set -e\nPATH=\"$PATH:${HOME}/.cargo/bin\"\nRUST_PROJ=${PROJECT_DIR}/..\ncd \"${RUST_PROJ}\"\ncargo build --release --target aarch64-apple-ios\ncargo build --release --target x86_64-apple-ios\nlipo -create target/aarch64-apple-ios/release/libtun2proxy.a target/x86_64-apple-ios/release/libtun2proxy.a -output target/libtun2proxy.a\ncbindgen --config cbindgen.toml -l C -o target/tun2proxy-ffi.h\n";
}; };
/* End PBXShellScriptBuildPhase section */ /* End PBXShellScriptBuildPhase section */

View file

@ -8,16 +8,16 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "Tun2proxyWrapper.h" #import "Tun2proxyWrapper.h"
#include "tun2proxy-sys.h" #include "tun2proxy-ffi.h"
@implementation Tun2proxyWrapper @implementation Tun2proxyWrapper
+ (void)startWithConfig:(NSString *)proxy_url + (void)startWithConfig:(NSString *)proxy_url
tun_fd:(int)tun_fd tun_fd:(int)tun_fd
tun_mtu:(uint32_t)tun_mtu tun_mtu:(uint32_t)tun_mtu
dns_over_tcp:(bool)dns_over_tcp dns_strategy:(ArgDns)dns_strategy
verbose:(bool)verbose { verbosity:(ArgVerbosity)verbosity {
tun2proxy_run(proxy_url.UTF8String, tun_fd, tun_mtu, dns_over_tcp, verbose); tun2proxy_run(proxy_url.UTF8String, tun_fd, tun_mtu, dns_strategy, verbosity);
} }
+ (void)shutdown { + (void)shutdown {

View file

@ -1,13 +1,13 @@
#![cfg(target_os = "android")] #![cfg(target_os = "android")]
use crate::{ use crate::{
args::{ArgDns, ArgProxy}, args::ArgProxy,
error::{Error, Result}, error::{Error, Result},
ArgVerbosity, Args, Args,
}; };
use jni::{ use jni::{
objects::{JClass, JString}, objects::{JClass, JString},
sys::{jboolean, jint}, sys::jint,
JNIEnv, JNIEnv,
}; };
@ -21,11 +21,11 @@ pub unsafe extern "C" fn Java_com_github_shadowsocks_bg_Tun2proxy_run(
proxy_url: JString, proxy_url: JString,
tun_fd: jint, tun_fd: jint,
tun_mtu: jint, tun_mtu: jint,
verbose: jboolean, verbosity: jint,
dns_over_tcp: jboolean, dns_strategy: jint,
) -> jint { ) -> jint {
let dns = if dns_over_tcp != 0 { ArgDns::OverTcp } else { ArgDns::Direct }; let dns = dns_strategy.try_into().unwrap();
let verbosity = if verbose != 0 { ArgVerbosity::Trace } else { ArgVerbosity::Info }; let verbosity = verbosity.try_into().unwrap();
let filter_str = &format!("off,tun2proxy={verbosity}"); let filter_str = &format!("off,tun2proxy={verbosity}");
let filter = android_logger::FilterBuilder::new().parse(filter_str).build(); let filter = android_logger::FilterBuilder::new().parse(filter_str).build();
android_logger::init_once( android_logger::init_once(

View file

@ -81,9 +81,10 @@ impl Args {
} }
} }
#[repr(C)]
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, clap::ValueEnum)] #[derive(Default, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, clap::ValueEnum)]
pub enum ArgVerbosity { pub enum ArgVerbosity {
Off, Off = 0,
Error, Error,
Warn, Warn,
#[default] #[default]
@ -92,6 +93,47 @@ pub enum ArgVerbosity {
Trace, Trace,
} }
#[cfg(target_os = "android")]
impl TryFrom<jni::sys::jint> for ArgVerbosity {
type Error = Error;
fn try_from(value: jni::sys::jint) -> Result<Self> {
match value {
0 => Ok(ArgVerbosity::Off),
1 => Ok(ArgVerbosity::Error),
2 => Ok(ArgVerbosity::Warn),
3 => Ok(ArgVerbosity::Info),
4 => Ok(ArgVerbosity::Debug),
5 => Ok(ArgVerbosity::Trace),
_ => Err(Error::from("Invalid verbosity level")),
}
}
}
impl From<ArgVerbosity> for log::LevelFilter {
fn from(verbosity: ArgVerbosity) -> Self {
match verbosity {
ArgVerbosity::Off => log::LevelFilter::Off,
ArgVerbosity::Error => log::LevelFilter::Error,
ArgVerbosity::Warn => log::LevelFilter::Warn,
ArgVerbosity::Info => log::LevelFilter::Info,
ArgVerbosity::Debug => log::LevelFilter::Debug,
ArgVerbosity::Trace => log::LevelFilter::Trace,
}
}
}
impl From<log::Level> for ArgVerbosity {
fn from(level: log::Level) -> Self {
match level {
log::Level::Error => ArgVerbosity::Error,
log::Level::Warn => ArgVerbosity::Warn,
log::Level::Info => ArgVerbosity::Info,
log::Level::Debug => ArgVerbosity::Debug,
log::Level::Trace => ArgVerbosity::Trace,
}
}
}
impl std::fmt::Display for ArgVerbosity { impl std::fmt::Display for ArgVerbosity {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self { match self {
@ -109,14 +151,28 @@ impl std::fmt::Display for ArgVerbosity {
/// - Virtual: Use a virtual DNS server to handle DNS queries, also known as Fake-IP mode /// - Virtual: Use a virtual DNS server to handle DNS queries, also known as Fake-IP mode
/// - OverTcp: Use TCP to send DNS queries to the DNS server /// - OverTcp: Use TCP to send DNS queries to the DNS server
/// - Direct: Do not handle DNS by relying on DNS server bypassing /// - Direct: Do not handle DNS by relying on DNS server bypassing
#[repr(C)]
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, clap::ValueEnum)] #[derive(Default, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, clap::ValueEnum)]
pub enum ArgDns { pub enum ArgDns {
Virtual, Virtual = 0,
OverTcp, OverTcp,
#[default] #[default]
Direct, Direct,
} }
#[cfg(target_os = "android")]
impl TryFrom<jni::sys::jint> for ArgDns {
type Error = Error;
fn try_from(value: jni::sys::jint) -> Result<Self> {
match value {
0 => Ok(ArgDns::Virtual),
1 => Ok(ArgDns::OverTcp),
2 => Ok(ArgDns::Direct),
_ => Err(Error::from("Invalid DNS strategy")),
}
}
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ArgProxy { pub struct ArgProxy {
pub proxy_type: ProxyType, pub proxy_type: ProxyType,

View file

@ -62,7 +62,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
tproxy_config::tproxy_setup(&tproxy_args)?; tproxy_config::tproxy_setup(&tproxy_args)?;
} }
let tun2proxy = Builder::new(device, args).mtu(MTU).build(); let tun2proxy = Builder::new(device, args).mtu(MTU as _).build();
let (join_handle, quit) = tun2proxy.start(); let (join_handle, quit) = tun2proxy.start();
ctrlc2::set_async_handler(async move { ctrlc2::set_async_handler(async move {

View file

@ -1,5 +1,6 @@
use crate::ArgVerbosity;
use std::{ use std::{
os::raw::{c_char, c_int, c_void}, os::raw::{c_char, c_void},
sync::Mutex, sync::Mutex,
}; };
@ -10,17 +11,17 @@ pub(crate) static DUMP_CALLBACK: Mutex<Option<DumpCallback>> = Mutex::new(None);
/// set dump log info callback. /// set dump log info callback.
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn tun2proxy_set_log_callback( pub unsafe extern "C" fn tun2proxy_set_log_callback(
callback: Option<unsafe extern "C" fn(c_int, *const c_char, *mut c_void)>, callback: Option<unsafe extern "C" fn(ArgVerbosity, *const c_char, *mut c_void)>,
ctx: *mut c_void, ctx: *mut c_void,
) { ) {
*DUMP_CALLBACK.lock().unwrap() = Some(DumpCallback(callback, ctx)); *DUMP_CALLBACK.lock().unwrap() = Some(DumpCallback(callback, ctx));
} }
#[derive(Clone)] #[derive(Clone)]
pub struct DumpCallback(Option<unsafe extern "C" fn(c_int, *const c_char, *mut c_void)>, *mut c_void); pub struct DumpCallback(Option<unsafe extern "C" fn(ArgVerbosity, *const c_char, *mut c_void)>, *mut c_void);
impl DumpCallback { impl DumpCallback {
unsafe fn call(self, dump_level: c_int, info: *const c_char) { unsafe fn call(self, dump_level: ArgVerbosity, info: *const c_char) {
if let Some(cb) = self.0 { if let Some(cb) = self.0 {
cb(dump_level, info, self.1); cb(dump_level, info, self.1);
} }
@ -64,7 +65,7 @@ impl DumpLogger {
let ptr = c_msg.as_ptr(); let ptr = c_msg.as_ptr();
if let Some(cb) = DUMP_CALLBACK.lock().unwrap().clone() { if let Some(cb) = DUMP_CALLBACK.lock().unwrap().clone() {
unsafe { unsafe {
cb.call(record.level() as c_int, ptr); cb.call(record.level().into(), ptr);
} }
} }
} }

View file

@ -14,20 +14,16 @@ pub unsafe extern "C" fn tun2proxy_run(
proxy_url: *const c_char, proxy_url: *const c_char,
tun_fd: c_int, tun_fd: c_int,
tun_mtu: c_uint, tun_mtu: c_uint,
dns_over_tcp: c_char, dns_strategy: ArgDns,
verbose: c_char, verbosity: ArgVerbosity,
) -> c_int { ) -> c_int {
use log::LevelFilter; log::set_max_level(verbosity.into());
let log_level = if verbose != 0 { LevelFilter::Trace } else { LevelFilter::Info };
log::set_max_level(log_level);
log::set_boxed_logger(Box::<crate::dump_logger::DumpLogger>::default()).unwrap(); log::set_boxed_logger(Box::<crate::dump_logger::DumpLogger>::default()).unwrap();
let dns = if dns_over_tcp != 0 { ArgDns::OverTcp } else { ArgDns::Direct };
let verbosity = if verbose != 0 { ArgVerbosity::Trace } else { ArgVerbosity::Info };
let proxy_url = std::ffi::CStr::from_ptr(proxy_url).to_str().unwrap(); let proxy_url = std::ffi::CStr::from_ptr(proxy_url).to_str().unwrap();
let proxy = ArgProxy::from_url(proxy_url).unwrap(); let proxy = ArgProxy::from_url(proxy_url).unwrap();
let args = Args::new(Some(tun_fd), proxy, dns, verbosity); let args = Args::new(Some(tun_fd), proxy, dns_strategy, verbosity);
crate::api::tun2proxy_internal_run(args, tun_mtu as _) crate::api::tun2proxy_internal_run(args, tun_mtu as _)
} }