mirror of
https://github.com/tun2proxy/tun2proxy.git
synced 2025-04-21 14:29:10 +00:00
Ffi (#89)
This commit is contained in:
parent
e9c378099e
commit
a26621bbcd
11 changed files with 224 additions and 26 deletions
|
@ -18,8 +18,8 @@
|
||||||
dns_over_tcp:(bool)dns_over_tcp
|
dns_over_tcp:(bool)dns_over_tcp
|
||||||
verbose:(bool)verbose {
|
verbose:(bool)verbose {
|
||||||
ArgDns dns_strategy = dns_over_tcp ? OverTcp : Direct;
|
ArgDns dns_strategy = dns_over_tcp ? OverTcp : Direct;
|
||||||
ArgVerbosity verbosity = verbose ? Trace : Info;
|
ArgVerbosity v = verbose ? Trace : Info;
|
||||||
tun2proxy_run(proxy_url.UTF8String, tun_fd, tun_mtu, dns_strategy, verbosity);
|
tun2proxy_run_with_fd(proxy_url.UTF8String, tun_fd, tun_mtu, dns_strategy, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)shutdown {
|
+ (void)shutdown {
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
[export]
|
[export]
|
||||||
include = ["tun2proxy_run", "tun2proxy_stop", "tun2proxy_set_log_callback"]
|
include = [
|
||||||
|
"tun2proxy_run_with_fd",
|
||||||
|
"tun2proxy_run_with_name",
|
||||||
|
"tun2proxy_stop",
|
||||||
|
"tun2proxy_set_log_callback",
|
||||||
|
]
|
||||||
exclude = [
|
exclude = [
|
||||||
"Java_com_github_shadowsocks_bg_Tun2proxy_run",
|
"Java_com_github_shadowsocks_bg_Tun2proxy_run",
|
||||||
"Java_com_github_shadowsocks_bg_Tun2proxy_stop",
|
"Java_com_github_shadowsocks_bg_Tun2proxy_stop",
|
||||||
|
|
|
@ -37,7 +37,8 @@ pub unsafe extern "C" fn Java_com_github_shadowsocks_bg_Tun2proxy_run(
|
||||||
let proxy_url = get_java_string(&mut env, &proxy_url).unwrap();
|
let proxy_url = get_java_string(&mut env, &proxy_url).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 mut args = Args::default();
|
||||||
|
args.proxy(proxy).tun_fd(Some(tun_fd)).dns(dns).verbosity(verbosity);
|
||||||
crate::api::tun2proxy_internal_run(args, tun_mtu)
|
crate::api::tun2proxy_internal_run(args, tun_mtu)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
12
src/api.rs
12
src/api.rs
|
@ -18,10 +18,18 @@ pub(crate) fn tun2proxy_internal_run(args: Args, tun_mtu: u16) -> c_int {
|
||||||
}
|
}
|
||||||
|
|
||||||
let block = async move {
|
let block = async move {
|
||||||
log::info!("Proxying {}", args.proxy);
|
log::info!("Proxy {} server: {}", args.proxy.proxy_type, args.proxy.addr);
|
||||||
|
|
||||||
let mut config = tun2::Configuration::default();
|
let mut config = tun2::Configuration::default();
|
||||||
config.raw_fd(args.tun_fd.ok_or(crate::Error::from("tun_fd"))?);
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
if let Some(fd) = args.tun_fd {
|
||||||
|
config.raw_fd(fd);
|
||||||
|
} else {
|
||||||
|
config.name(&args.tun);
|
||||||
|
}
|
||||||
|
#[cfg(windows)]
|
||||||
|
config.name(&args.tun);
|
||||||
|
|
||||||
let device = tun2::create_as_async(&config).map_err(std::io::Error::from)?;
|
let device = tun2::create_as_async(&config).map_err(std::io::Error::from)?;
|
||||||
let join_handle = tokio::spawn(crate::run(device, tun_mtu, args, shutdown_token));
|
let join_handle = tokio::spawn(crate::run(device, tun_mtu, args, shutdown_token));
|
||||||
|
|
52
src/args.rs
52
src/args.rs
|
@ -70,14 +70,50 @@ impl Args {
|
||||||
Self::parse()
|
Self::parse()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(tun_fd: Option<i32>, proxy: ArgProxy, dns: ArgDns, verbosity: ArgVerbosity) -> Self {
|
pub fn proxy(&mut self, proxy: ArgProxy) -> &mut Self {
|
||||||
Args {
|
self.proxy = proxy;
|
||||||
proxy,
|
self
|
||||||
tun_fd,
|
}
|
||||||
dns,
|
|
||||||
verbosity,
|
pub fn dns(&mut self, dns: ArgDns) -> &mut Self {
|
||||||
..Args::default()
|
self.dns = dns;
|
||||||
}
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tun_fd(&mut self, tun_fd: Option<i32>) -> &mut Self {
|
||||||
|
self.tun_fd = tun_fd;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verbosity(&mut self, verbosity: ArgVerbosity) -> &mut Self {
|
||||||
|
self.verbosity = verbosity;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tun(&mut self, tun: String) -> &mut Self {
|
||||||
|
self.tun = tun;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dns_addr(&mut self, dns_addr: IpAddr) -> &mut Self {
|
||||||
|
self.dns_addr = dns_addr;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bypass(&mut self, bypass: IpAddr) -> &mut Self {
|
||||||
|
self.bypass.push(bypass);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ipv6_enabled(&mut self, ipv6_enabled: bool) -> &mut Self {
|
||||||
|
self.ipv6_enabled = ipv6_enabled;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
pub fn setup(&mut self, setup: bool) -> &mut Self {
|
||||||
|
self.setup = setup;
|
||||||
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,11 +63,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
tproxy_config::tproxy_setup(&tproxy_args)?;
|
tproxy_config::tproxy_setup(&tproxy_args)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
log::info!("Proxying {}", args.proxy);
|
log::info!("Proxy {} server: {}", args.proxy.proxy_type, args.proxy.addr);
|
||||||
|
|
||||||
let shutdown_token = CancellationToken::new();
|
let shutdown_token = CancellationToken::new();
|
||||||
let cloned_token = shutdown_token.clone();
|
let join_handle = tokio::spawn(tun2proxy::run(device, MTU, args, shutdown_token.clone()));
|
||||||
let join_handle = tokio::spawn(tun2proxy::run(device, MTU, args, cloned_token));
|
|
||||||
|
|
||||||
ctrlc2::set_async_handler(async move {
|
ctrlc2::set_async_handler(async move {
|
||||||
log::info!("Ctrl-C received, exiting...");
|
log::info!("Ctrl-C received, exiting...");
|
||||||
|
|
|
@ -6,19 +6,18 @@ use std::{
|
||||||
|
|
||||||
pub(crate) static DUMP_CALLBACK: Mutex<Option<DumpCallback>> = Mutex::new(None);
|
pub(crate) static DUMP_CALLBACK: Mutex<Option<DumpCallback>> = Mutex::new(None);
|
||||||
|
|
||||||
|
pub type RawCallback = unsafe extern "C" fn(ArgVerbosity, *const c_char, *mut c_void);
|
||||||
|
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// 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<RawCallback>, ctx: *mut c_void) {
|
||||||
callback: Option<unsafe extern "C" fn(ArgVerbosity, *const c_char, *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(ArgVerbosity, *const c_char, *mut c_void)>, *mut c_void);
|
pub struct DumpCallback(Option<RawCallback>, *mut c_void);
|
||||||
|
|
||||||
impl DumpCallback {
|
impl DumpCallback {
|
||||||
unsafe fn call(self, dump_level: ArgVerbosity, info: *const c_char) {
|
unsafe fn call(self, dump_level: ArgVerbosity, info: *const c_char) {
|
||||||
|
|
|
@ -68,4 +68,6 @@ impl From<Error> for std::io::Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type BoxError = Box<dyn std::error::Error + Send + Sync + 'static>;
|
||||||
|
|
||||||
pub type Result<T, E = Error> = std::result::Result<T, E>;
|
pub type Result<T, E = Error> = std::result::Result<T, E>;
|
||||||
|
|
140
src/ffi.rs
Normal file
140
src/ffi.rs
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
#![cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))]
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
args::{ArgDns, ArgProxy},
|
||||||
|
ArgVerbosity, Args,
|
||||||
|
};
|
||||||
|
use std::os::raw::{c_char, c_int};
|
||||||
|
use tokio_util::sync::CancellationToken;
|
||||||
|
use tproxy_config::{TproxyArgs, TUN_GATEWAY, TUN_IPV4, TUN_NETMASK};
|
||||||
|
use tun2::DEFAULT_MTU as MTU;
|
||||||
|
|
||||||
|
static TUN_QUIT: std::sync::Mutex<Option<CancellationToken>> = std::sync::Mutex::new(None);
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// Run the tun2proxy component with some arguments.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn tun2proxy_run_with_name(
|
||||||
|
proxy_url: *const c_char,
|
||||||
|
tun: *const c_char,
|
||||||
|
bypass: *const c_char,
|
||||||
|
dns_strategy: ArgDns,
|
||||||
|
_root_privilege: bool,
|
||||||
|
verbosity: ArgVerbosity,
|
||||||
|
) -> c_int {
|
||||||
|
let shutdown_token = CancellationToken::new();
|
||||||
|
{
|
||||||
|
if let Ok(mut lock) = TUN_QUIT.lock() {
|
||||||
|
if lock.is_some() {
|
||||||
|
log::error!("tun2proxy already started");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*lock = Some(shutdown_token.clone());
|
||||||
|
} else {
|
||||||
|
log::error!("tun2proxy unknown error");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log::set_max_level(verbosity.into());
|
||||||
|
log::set_boxed_logger(Box::<crate::dump_logger::DumpLogger>::default()).unwrap();
|
||||||
|
|
||||||
|
let proxy_url = std::ffi::CStr::from_ptr(proxy_url).to_str().unwrap();
|
||||||
|
let proxy = ArgProxy::from_url(proxy_url).unwrap();
|
||||||
|
let tun = std::ffi::CStr::from_ptr(tun).to_str().unwrap().to_string();
|
||||||
|
|
||||||
|
let mut args = Args::default();
|
||||||
|
args.proxy(proxy).tun(tun).dns(dns_strategy).verbosity(verbosity);
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
args.setup(_root_privilege);
|
||||||
|
|
||||||
|
if let Ok(bypass) = std::ffi::CStr::from_ptr(bypass).to_str() {
|
||||||
|
args.bypass(bypass.parse().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
let block = async move {
|
||||||
|
let bypass_ips = args.bypass.clone();
|
||||||
|
|
||||||
|
let mut config = tun2::Configuration::default();
|
||||||
|
config.address(TUN_IPV4).netmask(TUN_NETMASK).mtu(MTU).up();
|
||||||
|
config.destination(TUN_GATEWAY);
|
||||||
|
if let Some(tun_fd) = args.tun_fd {
|
||||||
|
config.raw_fd(tun_fd);
|
||||||
|
} else {
|
||||||
|
config.name(&args.tun);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
config.platform_config(|config| {
|
||||||
|
#[allow(deprecated)]
|
||||||
|
config.packet_information(true);
|
||||||
|
config.ensure_root_privileges(args.setup);
|
||||||
|
});
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
config.platform_config(|config| {
|
||||||
|
config.device_guid(Some(12324323423423434234_u128));
|
||||||
|
});
|
||||||
|
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
let mut tproxy_args = TproxyArgs::new()
|
||||||
|
.tun_dns(args.dns_addr)
|
||||||
|
.proxy_addr(args.proxy.addr)
|
||||||
|
.bypass_ips(&bypass_ips);
|
||||||
|
#[allow(unused_assignments)]
|
||||||
|
if args.tun_fd.is_none() {
|
||||||
|
tproxy_args = tproxy_args.tun_name(&args.tun);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
tproxy_config::tproxy_setup(&tproxy_args)?;
|
||||||
|
|
||||||
|
let device = tun2::create_as_async(&config)?;
|
||||||
|
|
||||||
|
#[cfg(any(target_os = "windows", target_os = "macos"))]
|
||||||
|
tproxy_config::tproxy_setup(&tproxy_args)?;
|
||||||
|
|
||||||
|
log::info!("Proxy {} server: {}", args.proxy.proxy_type, args.proxy.addr);
|
||||||
|
|
||||||
|
let join_handle = tokio::spawn(crate::run(device, MTU, args, shutdown_token));
|
||||||
|
join_handle.await.map_err(std::io::Error::from)??;
|
||||||
|
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))]
|
||||||
|
if _root_privilege {
|
||||||
|
tproxy_config::tproxy_remove(&tproxy_args)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok::<(), crate::BoxError>(())
|
||||||
|
};
|
||||||
|
|
||||||
|
let exit_code = match tokio::runtime::Builder::new_multi_thread().enable_all().build() {
|
||||||
|
Err(_e) => -1,
|
||||||
|
Ok(rt) => match rt.block_on(block) {
|
||||||
|
Ok(_) => 0,
|
||||||
|
Err(_e) => -2,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// release shutdown token before exit.
|
||||||
|
if let Ok(mut lock) = TUN_QUIT.lock() {
|
||||||
|
let _ = lock.take();
|
||||||
|
}
|
||||||
|
|
||||||
|
exit_code
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// Shutdown the tun2proxy component.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn tun2proxy_stop() -> c_int {
|
||||||
|
if let Ok(lock) = TUN_QUIT.lock() {
|
||||||
|
if let Some(shutdown_token) = lock.as_ref() {
|
||||||
|
shutdown_token.cancel();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
-1
|
||||||
|
}
|
|
@ -10,7 +10,7 @@ use std::os::raw::{c_char, c_int, c_ushort};
|
||||||
///
|
///
|
||||||
/// Run the tun2proxy component with some arguments.
|
/// Run the tun2proxy component with some arguments.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn tun2proxy_run(
|
pub unsafe extern "C" fn tun2proxy_run_with_fd(
|
||||||
proxy_url: *const c_char,
|
proxy_url: *const c_char,
|
||||||
tun_fd: c_int,
|
tun_fd: c_int,
|
||||||
tun_mtu: c_ushort,
|
tun_mtu: c_ushort,
|
||||||
|
@ -23,7 +23,8 @@ pub unsafe extern "C" fn tun2proxy_run(
|
||||||
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_strategy, verbosity);
|
let mut args = Args::default();
|
||||||
|
args.proxy(proxy).tun_fd(Some(tun_fd)).dns(dns_strategy).verbosity(verbosity);
|
||||||
|
|
||||||
crate::api::tun2proxy_internal_run(args, tun_mtu)
|
crate::api::tun2proxy_internal_run(args, tun_mtu)
|
||||||
}
|
}
|
||||||
|
|
11
src/lib.rs
11
src/lib.rs
|
@ -14,13 +14,13 @@ use tokio::{
|
||||||
net::TcpStream,
|
net::TcpStream,
|
||||||
sync::Mutex,
|
sync::Mutex,
|
||||||
};
|
};
|
||||||
use tokio_util::sync::CancellationToken;
|
pub use tokio_util::sync::CancellationToken;
|
||||||
use tproxy_config::is_private_ip;
|
use tproxy_config::is_private_ip;
|
||||||
use udp_stream::UdpStream;
|
use udp_stream::UdpStream;
|
||||||
|
|
||||||
pub use {
|
pub use {
|
||||||
args::{ArgDns, ArgProxy, ArgVerbosity, Args, ProxyType},
|
args::{ArgDns, ArgProxy, ArgVerbosity, Args, ProxyType},
|
||||||
error::{Error, Result},
|
error::{BoxError, Error, Result},
|
||||||
};
|
};
|
||||||
|
|
||||||
mod android;
|
mod android;
|
||||||
|
@ -30,6 +30,7 @@ mod directions;
|
||||||
mod dns;
|
mod dns;
|
||||||
mod dump_logger;
|
mod dump_logger;
|
||||||
mod error;
|
mod error;
|
||||||
|
mod ffi;
|
||||||
mod http;
|
mod http;
|
||||||
mod ios;
|
mod ios;
|
||||||
mod proxy_handler;
|
mod proxy_handler;
|
||||||
|
@ -44,6 +45,12 @@ const MAX_SESSIONS: u64 = 200;
|
||||||
static TASK_COUNT: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
|
static TASK_COUNT: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
|
||||||
use std::sync::atomic::Ordering::Relaxed;
|
use std::sync::atomic::Ordering::Relaxed;
|
||||||
|
|
||||||
|
/// Run the proxy server
|
||||||
|
/// # Arguments
|
||||||
|
/// * `device` - The network device to use
|
||||||
|
/// * `mtu` - The MTU of the network device
|
||||||
|
/// * `args` - The arguments to use
|
||||||
|
/// * `shutdown_token` - The token to exit the server
|
||||||
pub async fn run<D>(device: D, mtu: u16, args: Args, shutdown_token: CancellationToken) -> crate::Result<()>
|
pub async fn run<D>(device: D, mtu: u16, args: Args, shutdown_token: CancellationToken) -> crate::Result<()>
|
||||||
where
|
where
|
||||||
D: AsyncRead + AsyncWrite + Unpin + Send + 'static,
|
D: AsyncRead + AsyncWrite + Unpin + Send + 'static,
|
||||||
|
|
Loading…
Add table
Reference in a new issue