Browse Source

Refactor: enable session info via username marker (+info) instead of separate flag

- Remove embed_session_info field from Args (fixes semver breaking change)
- Remove runWithSessionInfo JNI function
- Detect +info suffix in username to enable session info embedding
- Format: username+info becomes username|protocol|src_ip|src_port
pull/245/head
Alexander Olkhovoy 2 months ago
parent
commit
bc8ff4cf38
  1. 52
      src/android.rs
  2. 13
      src/args.rs
  3. 5
      src/lib.rs
  4. 16
      src/socks.rs

52
src/android.rs

@ -58,58 +58,6 @@ pub unsafe extern "C" fn Java_com_github_shadowsocks_bg_Tun2proxy_run(
.resolve::<jni::errors::LogErrorAndDefault>()
}
/// # Safety
///
/// Running tun2proxy with some arguments including embed_session_info option
/// Parameters:
/// - proxy_url: the proxy url, e.g. "socks5://user:[email protected]:1080"
/// - tun_fd: the tun file descriptor, it will be owned by tun2proxy
/// - close_fd_on_drop: whether close the tun_fd on drop
/// - tun_mtu: the tun mtu
/// - dns_strategy: the dns strategy, see ArgDns enum
/// - verbosity: the verbosity level, see ArgVerbosity enum
/// - embed_session_info: if true, embeds session info in SOCKS5 username field
/// Format: "original_username|protocol|src_ip|src_port"
/// Use this with getConnectionOwnerUid() for per-app routing on Android 10+
#[unsafe(no_mangle)]
pub unsafe extern "C" fn Java_com_github_shadowsocks_bg_Tun2proxy_runWithSessionInfo(
mut env: EnvUnowned<'_>,
_clazz: JClass<'_>,
proxy_url: JString<'_>,
tun_fd: jint,
close_fd_on_drop: jboolean,
tun_mtu: jchar,
verbosity: jint,
dns_strategy: jint,
embed_session_info: jboolean,
) -> jint {
let dns = dns_strategy.try_into().unwrap();
let verbosity = verbosity.try_into().unwrap();
let filter_str = &format!("off,tun2proxy={verbosity}");
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),
);
env.with_env(|env: &mut Env| -> Result<jint> {
let proxy_url = get_java_string(env, &proxy_url).unwrap();
let proxy = ArgProxy::try_from(proxy_url.as_str()).unwrap();
let mut args = Args::default();
args.proxy(proxy)
.tun_fd(Some(tun_fd))
.close_fd_on_drop(close_fd_on_drop)
.dns(dns)
.verbosity(verbosity)
.embed_session_info(embed_session_info != jboolean::from(false));
let v = crate::general_api::general_run_for_api(args, tun_mtu, false);
Ok::<jint, Error>(v)
})
.resolve::<jni::errors::LogErrorAndDefault>()
}
/// # Safety
///
/// Shutdown tun2proxy

13
src/args.rs

@ -20,7 +20,6 @@ fn about_info() -> &'static str {
}
#[derive(Debug, Clone, clap::Parser, serde::Serialize, serde::Deserialize)]
#[non_exhaustive]
#[command(author, version = version_info!(), about = about_info(), long_about = None)]
pub struct Args {
/// Proxy URL in the form proto://[username[:password]@]host:port,
@ -129,12 +128,6 @@ pub struct Args {
#[arg(long, value_name = "number", default_value = "200")]
pub max_sessions: usize,
/// Embed session info (protocol, src_ip, src_port) in SOCKS5 username field.
/// Format: "original_username|protocol|src_ip|src_port"
/// Useful for per-app routing on Android via getConnectionOwnerUid().
#[arg(long)]
pub embed_session_info: bool,
/// UDP gateway server address, forwards UDP packets via specified TCP server
#[cfg(feature = "udpgw")]
#[arg(long, value_name = "IP:PORT")]
@ -195,7 +188,6 @@ impl Default for Args {
daemonize: false,
exit_on_fatal_error: false,
max_sessions: 200,
embed_session_info: false,
#[cfg(feature = "udpgw")]
udpgw_server: None,
#[cfg(feature = "udpgw")]
@ -281,11 +273,6 @@ impl Args {
self.setup = setup;
self
}
pub fn embed_session_info(&mut self, embed_session_info: bool) -> &mut Self {
self.embed_session_info = embed_session_info;
self
}
}
#[repr(C)]

5
src/lib.rs

@ -225,10 +225,9 @@ where
let socket_queue = None;
use socks5_impl::protocol::Version::{V4, V5};
let embed_session_info = args.embed_session_info;
let mgr: Arc<dyn ProxyHandlerManager> = match args.proxy.proxy_type {
ProxyType::Socks5 => Arc::new(SocksProxyManager::new(server_addr, V5, key, embed_session_info)),
ProxyType::Socks4 => Arc::new(SocksProxyManager::new(server_addr, V4, key, embed_session_info)),
ProxyType::Socks5 => Arc::new(SocksProxyManager::new(server_addr, V5, key)),
ProxyType::Socks4 => Arc::new(SocksProxyManager::new(server_addr, V4, key)),
ProxyType::Http => Arc::new(HttpManager::new(server_addr, key)),
ProxyType::None => Arc::new(NoProxyManager::new()),
};

16
src/socks.rs

@ -32,7 +32,6 @@ struct SocksProxyImpl {
credentials: Option<UserKey>,
command: protocol::Command,
udp_associate: Option<SocketAddr>,
embed_session_info: bool,
}
impl SocksProxyImpl {
@ -43,7 +42,6 @@ impl SocksProxyImpl {
credentials: Option<UserKey>,
version: Version,
command: protocol::Command,
embed_session_info: bool,
) -> Result<Self> {
let mut result = Self {
server_addr,
@ -58,7 +56,6 @@ impl SocksProxyImpl {
credentials,
command,
udp_associate: None,
embed_session_info,
};
result.send_client_hello()?;
Ok(result)
@ -173,16 +170,20 @@ impl SocksProxyImpl {
fn send_auth_data(&mut self) -> std::io::Result<()> {
let tmp = UserKey::default();
let credentials = self.credentials.as_ref().unwrap_or(&tmp);
let username = if self.embed_session_info {
const SESSION_INFO_MARKER: &str = "+info";
let username = if credentials.username.ends_with(SESSION_INFO_MARKER) {
let base_username = &credentials.username[..credentials.username.len() - SESSION_INFO_MARKER.len()];
let proto = match self.command {
protocol::Command::Connect => "tcp",
protocol::Command::UdpAssociate => "udp",
_ => "unknown",
};
format!("{}|{}|{}|{}", credentials.username, proto, self.info.src.ip(), self.info.src.port())
format!("{}|{}|{}|{}", base_username, proto, self.info.src.ip(), self.info.src.port())
} else {
credentials.username.clone()
};
let request = password_method::Request::new(&username, &credentials.password);
request.write_to_stream(&mut self.server_outbuf)?;
self.state = SocksState::ReceiveAuthResponse;
@ -345,7 +346,6 @@ pub(crate) struct SocksProxyManager {
server: SocketAddr,
credentials: Option<UserKey>,
version: Version,
embed_session_info: bool,
}
#[async_trait::async_trait]
@ -366,18 +366,16 @@ impl ProxyHandlerManager for SocksProxyManager {
credentials,
self.version,
command,
self.embed_session_info,
)?)))
}
}
impl SocksProxyManager {
pub(crate) fn new(server: SocketAddr, version: Version, credentials: Option<UserKey>, embed_session_info: bool) -> Self {
pub(crate) fn new(server: SocketAddr, version: Version, credentials: Option<UserKey>) -> Self {
Self {
server,
credentials,
version,
embed_session_info,
}
}
}

Loading…
Cancel
Save