diff --git a/Cargo.toml b/Cargo.toml index 2e85def..095ed9b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,10 @@ smoltcp = { version = "0.9", git = "https://github.com/blechschmidt/smoltcp", br thiserror = "1.0" url = "2.3" +[target.'cfg(target_os="android")'.dependencies] +android_logger = "0.13" +jni = { version = "0.21", default-features = false } + [dev-dependencies] ctor = "0.1" reqwest = { version = "0.11", features = ["blocking", "json"] } diff --git a/src/android.rs b/src/android.rs new file mode 100644 index 0000000..ea7f165 --- /dev/null +++ b/src/android.rs @@ -0,0 +1,74 @@ +#![cfg(target_os = "android")] + +use crate::{error::Error, main_entry, shutdown, NetworkInterface, Options, Proxy}; +use jni::{ + objects::{JClass, JString}, + sys::{jboolean, jint}, + JNIEnv, +}; + +/// # Safety +/// +/// Running tun2proxy +#[no_mangle] +pub unsafe extern "C" fn Java_com_github_shadowsocks_bg_Tun2proxy_run( + mut env: JNIEnv, + _clazz: JClass, + proxy_url: JString, + tun_fd: jint, + tun_mtu: jint, + verbose: jboolean, +) -> jint { + let log_level = if verbose != 0 { "trace" } else { "info" }; + let filter_str = &format!("off,tun2proxy={log_level}"); + let filter = android_logger::FilterBuilder::new() + .parse(filter_str) + .build(); + android_logger::init_once( + android_logger::Config::default() + .with_tag("tun2proxy") + .with_max_level(log::LevelFilter::Trace) + .with_filter(filter), + ); + + let mut block = || -> Result<(), Error> { + let proxy_url = get_java_string(&mut env, &proxy_url)?; + let proxy = Proxy::from_url(proxy_url)?; + + let addr = proxy.addr; + let proxy_type = proxy.proxy_type; + log::info!("Proxy {proxy_type} server: {addr}"); + + let options = Options::new().with_virtual_dns().with_mtu(tun_mtu as usize); + + let interface = NetworkInterface::Fd(tun_fd); + _ = main_entry(&interface, &proxy, options)?; + Ok::<(), Error>(()) + }; + if let Err(error) = block() { + log::error!("failed to run tun2proxy with error: {:?}", error); + } + 0 +} + +/// # Safety +/// +/// Shutdown tun2proxy +#[no_mangle] +pub unsafe extern "C" fn Java_com_github_shadowsocks_bg_Tun2proxy_stop( + _env: JNIEnv, + _clazz: JClass, +) -> jint { + if let Err(e) = shutdown() { + log::error!("failed to shutdown tun2proxy with error: {:?}", e); + 1 + } else { + 0 + } +} + +unsafe fn get_java_string<'a>(env: &'a mut JNIEnv, string: &'a JString) -> Result<&'a str, Error> { + let str_ptr = env.get_string(string)?.as_ptr(); + let s: &str = std::ffi::CStr::from_ptr(str_ptr).to_str()?; + Ok(s) +} diff --git a/src/error.rs b/src/error.rs index 0b48fcd..de014e8 100644 --- a/src/error.rs +++ b/src/error.rs @@ -27,6 +27,13 @@ pub enum Error { #[error("smoltcp::socket::tcp::SendError {0:?}")] Send(#[from] smoltcp::socket::tcp::SendError), + #[error("std::str::Utf8Error {0:?}")] + Utf8(#[from] std::str::Utf8Error), + + #[cfg(target_os = "android")] + #[error("jni::errors::Error {0:?}")] + Jni(#[from] jni::errors::Error), + #[error("&str {0}")] Str(String), diff --git a/src/lib.rs b/src/lib.rs index c0a5c30..6f5a740 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ use crate::socks5::SocksVersion; use crate::{http::HttpManager, socks5::SocksManager, tun2proxy::TunToProxy}; use std::net::{SocketAddr, ToSocketAddrs}; +mod android; pub mod error; mod http; pub mod setup;