Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: tun auto route #350

Closed
wants to merge 18 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions clash_lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ console-subscriber = { version = "0.2.0" }
tracing-timing = { version = "0.6.0" }
criterion = { version = "0.5", features = ["html_reports", "async_tokio"], optional = true }

cmd_lib = "1"

[dev-dependencies]
tempfile = "3.10"
ctor = "0.2"
Expand Down
2 changes: 1 addition & 1 deletion clash_lib/src/app/dispatcher/dispatcher_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ impl Dispatcher {
match remote_w.send(packet).await {
Ok(_) => {}
Err(err) => {
warn!("failed to send packet to remote: {}", err);
warn!("failed to send packet to remote: {:?}", err);
}
}
}
Expand Down
1 change: 0 additions & 1 deletion clash_lib/src/app/dns/dhcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,6 @@ async fn listen_dhcp_client(iface: &str) -> io::Result<UdpSocket> {
new_udp_socket(
Some(&listen_addr.parse().expect("must parse")),
Some(&Interface::Name(iface.to_string())),
#[cfg(any(target_os = "linux", target_os = "android"))]
None,
)
.await
Expand Down
1 change: 0 additions & 1 deletion clash_lib/src/common/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ impl Service<Uri> for LocalConnector {
},
}),
None,
#[cfg(any(target_os = "linux", target_os = "android"))]
None,
)
.await
Expand Down
1 change: 1 addition & 0 deletions clash_lib/src/config/internal/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ pub struct TunConfig {
/// default: 198.18.0.0/16
pub network: Option<String>,
pub gateway: Option<IpAddr>,
pub auto_route: Option<bool>,
}

#[derive(Clone, Default)]
Expand Down
13 changes: 13 additions & 0 deletions clash_lib/src/config/internal/proxy.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::common::utils::default_bool_true;
use crate::config::utils;
use crate::proxy::CommonOption;
use crate::Error;
use serde::de::value::MapDeserializer;
use serde::Deserialize;
Expand Down Expand Up @@ -116,6 +117,8 @@ impl Display for OutboundProxyProtocol {

#[derive(serde::Serialize, serde::Deserialize, Debug, Default)]
pub struct OutboundShadowsocks {
#[serde(flatten)]
pub common_opts: CommonOption,
pub name: String,
pub server: String,
pub port: u16,
Expand All @@ -130,6 +133,8 @@ pub struct OutboundShadowsocks {

#[derive(serde::Serialize, serde::Deserialize, Debug, Default)]
pub struct OutboundSocks5 {
#[serde(flatten)]
pub common_opts: CommonOption,
pub name: String,
pub server: String,
pub port: u16,
Expand All @@ -142,6 +147,8 @@ pub struct OutboundSocks5 {

#[derive(serde::Serialize, serde::Deserialize, Debug, Default)]
pub struct WsOpt {
#[serde(flatten)]
pub common_opts: CommonOption,
pub path: Option<String>,
pub headers: Option<HashMap<String, String>>,
pub max_early_data: Option<i32>,
Expand All @@ -163,6 +170,8 @@ pub struct GrpcOpt {
#[derive(serde::Serialize, serde::Deserialize, Debug, Default)]
#[serde(rename_all = "kebab-case")]
pub struct OutboundTrojan {
#[serde(flatten)]
pub common_opts: CommonOption,
pub name: String,
pub server: String,
pub port: u16,
Expand All @@ -179,6 +188,8 @@ pub struct OutboundTrojan {
#[derive(serde::Serialize, serde::Deserialize, Debug, Default)]
#[serde(rename_all = "kebab-case")]
pub struct OutboundVmess {
#[serde(flatten)]
pub common_opts: CommonOption,
pub name: String,
pub server: String,
pub port: u16,
Expand All @@ -200,6 +211,8 @@ pub struct OutboundVmess {
#[derive(serde::Serialize, serde::Deserialize, Debug, Default, Clone)]
#[serde(rename_all = "kebab-case")]
pub struct OutboundWireguard {
#[serde(flatten)]
pub common_opts: CommonOption,
pub name: String,
pub server: String,
pub port: u16,
Expand Down
36 changes: 28 additions & 8 deletions clash_lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ use common::auth;
use common::http::new_http_client;
use common::mmdb;
use config::def::LogLevel;
use once_cell::sync::OnceCell;
use proxy::tun::get_tun_runner;

use std::io;
use std::path::PathBuf;
use std::sync::{Arc, OnceLock};
use std::sync::Arc;
use thiserror::Error;
use tokio::sync::{broadcast, mpsc, oneshot, Mutex};
use tokio::task::JoinHandle;
Expand All @@ -33,11 +34,11 @@ mod common;
mod config;
mod proxy;
mod session;

pub use config::def::Config as ClashConfigDef;
pub use config::def::DNS as ClashDNSConfigDef;
pub use config::DNSListen as ClashDNSListen;
pub use config::RuntimeConfig as ClashRuntimeConfig;
pub use session::{get_iface, get_somark, set_iface, set_somark};

#[derive(Error, Debug)]
pub enum Error {
Expand Down Expand Up @@ -102,9 +103,10 @@ pub struct GlobalState {

pub struct RuntimeController {
shutdown_tx: mpsc::Sender<()>,
broadcast_shutdown: broadcast::Sender<()>,
}

static RUNTIME_CONTROLLER: OnceLock<std::sync::RwLock<RuntimeController>> = OnceLock::new();
static RUNTIME_CONTROLLER: OnceCell<RuntimeController> = OnceCell::new();

pub fn start(opts: Options) -> Result<(), Error> {
let rt = match opts.rt.as_ref().unwrap_or(&TokioRuntime::MultiThread) {
Expand All @@ -127,17 +129,35 @@ pub fn start(opts: Options) -> Result<(), Error> {
})
}

pub fn shutdown() -> bool {
match RUNTIME_CONTROLLER.get().unwrap().write() {
Ok(rt) => rt.shutdown_tx.blocking_send(()).is_ok(),
_ => false,
pub fn shutdown() -> anyhow::Result<()> {
match RUNTIME_CONTROLLER.get() {
Some(rt) => {
_ = rt.broadcast_shutdown.send(()); // fail when there is no receiver
rt.shutdown_tx.blocking_send(())?;
Ok(())
}
_ => Err(anyhow::anyhow!("Empty RUNTIME_CONTROLLER")),
}
}

pub async fn listen_shutdown() -> anyhow::Result<()> {
match RUNTIME_CONTROLLER.get() {
Some(rt) => {
_ = rt.broadcast_shutdown.subscribe().recv().await; // fail when there is no sender or buffer is full
Ok(())
}
_ => Err(anyhow::anyhow!("Empty RUNTIME_CONTROLLER")),
}
}

async fn start_async(opts: Options) -> Result<(), Error> {
let (shutdown_tx, mut shutdown_rx) = mpsc::channel(1);
let (broadcast_shutdown, _) = broadcast::channel(1);

let _ = RUNTIME_CONTROLLER.set(std::sync::RwLock::new(RuntimeController { shutdown_tx }));
let _ = RUNTIME_CONTROLLER.set(RuntimeController {
shutdown_tx,
broadcast_shutdown,
});

let config: InternalConfig = opts.config.try_parse()?;

Expand Down
4 changes: 2 additions & 2 deletions clash_lib/src/proxy/converters/shadowsocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::{
config::internal::proxy::OutboundShadowsocks,
proxy::{
shadowsocks::{Handler, HandlerOptions, OBFSOption},
AnyOutboundHandler, CommonOption,
AnyOutboundHandler,
},
Error,
};
Expand All @@ -21,7 +21,7 @@ impl TryFrom<&OutboundShadowsocks> for AnyOutboundHandler {
fn try_from(s: &OutboundShadowsocks) -> Result<Self, Self::Error> {
let h = Handler::new(HandlerOptions {
name: s.name.to_owned(),
common_opts: CommonOption::default(),
common_opts: s.common_opts.clone(),
server: s.server.to_owned(),
port: s.port,
password: s.password.to_owned(),
Expand Down
4 changes: 2 additions & 2 deletions clash_lib/src/proxy/converters/trojan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{
proxy::{
options::{GrpcOption, WsOption},
trojan::{Handler, Opts, Transport},
AnyOutboundHandler, CommonOption,
AnyOutboundHandler,
},
Error,
};
Expand All @@ -29,7 +29,7 @@ impl TryFrom<&OutboundTrojan> for AnyOutboundHandler {

let h = Handler::new(Opts {
name: s.name.to_owned(),
common_opts: CommonOption::default(),
common_opts: s.common_opts.clone(),
server: s.server.to_owned(),
port: s.port,
password: s.password.clone(),
Expand Down
16 changes: 13 additions & 3 deletions clash_lib/src/proxy/converters/tuic.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use std::time::Duration;
use std::{
sync::{atomic::AtomicU32, Arc},
time::Duration,
};

use quinn::VarInt;

Expand Down Expand Up @@ -28,16 +31,22 @@
port: s.port,
uuid: s.uuid.to_owned(),
password: s.password.to_owned(),
udp_relay_mode: s.udp_relay_mode.to_owned().unwrap_or("native".to_string()),
udp_relay_mode: s
.udp_relay_mode
.to_owned()
.unwrap_or("native".to_string())
.as_str()
.into(),
disable_sni: s.disable_sni.unwrap_or(false),
alpn: s
.alpn
.clone()
.map(|v| v.into_iter().map(|alpn| alpn.into_bytes()).collect())
.unwrap_or_default(),
heartbeat_interval: Duration::from_millis(s.heartbeat_interval.unwrap_or(3000)),

Check warning on line 46 in clash_lib/src/proxy/converters/tuic.rs

View workflow job for this annotation

GitHub Actions / aarch64-apple-darwin

Diff in /Users/runner/work/clash-rs/clash-rs/clash_lib/src/proxy/converters/tuic.rs

Check warning on line 46 in clash_lib/src/proxy/converters/tuic.rs

View workflow job for this annotation

GitHub Actions / aarch64-apple-darwin-static-crt

Diff in /Users/runner/work/clash-rs/clash-rs/clash_lib/src/proxy/converters/tuic.rs

Check warning on line 46 in clash_lib/src/proxy/converters/tuic.rs

View workflow job for this annotation

GitHub Actions / x86_64-apple-darwin-static-crt

Diff in /Users/runner/work/clash-rs/clash-rs/clash_lib/src/proxy/converters/tuic.rs

Check warning on line 46 in clash_lib/src/proxy/converters/tuic.rs

View workflow job for this annotation

GitHub Actions / x86_64-apple-darwin

Diff in /Users/runner/work/clash-rs/clash-rs/clash_lib/src/proxy/converters/tuic.rs

Check warning on line 46 in clash_lib/src/proxy/converters/tuic.rs

View workflow job for this annotation

GitHub Actions / armv7-unknown-linux-musleabihf

Diff in /home/runner/work/clash-rs/clash-rs/clash_lib/src/proxy/converters/tuic.rs

Check warning on line 46 in clash_lib/src/proxy/converters/tuic.rs

View workflow job for this annotation

GitHub Actions / i686-unknown-linux-gnu

Diff in /home/runner/work/clash-rs/clash-rs/clash_lib/src/proxy/converters/tuic.rs

Check warning on line 46 in clash_lib/src/proxy/converters/tuic.rs

View workflow job for this annotation

GitHub Actions / x86_64-unknown-linux-gnu-static-crt

Diff in /home/runner/work/clash-rs/clash-rs/clash_lib/src/proxy/converters/tuic.rs

Check warning on line 46 in clash_lib/src/proxy/converters/tuic.rs

View workflow job for this annotation

GitHub Actions / aarch64-unknown-linux-gnu-static-crt

Diff in /home/runner/work/clash-rs/clash-rs/clash_lib/src/proxy/converters/tuic.rs

Check warning on line 46 in clash_lib/src/proxy/converters/tuic.rs

View workflow job for this annotation

GitHub Actions / armv7-unknown-linux-gnueabi

Diff in /home/runner/work/clash-rs/clash-rs/clash_lib/src/proxy/converters/tuic.rs

Check warning on line 46 in clash_lib/src/proxy/converters/tuic.rs

View workflow job for this annotation

GitHub Actions / x86_64-unknown-linux-gnu

Diff in /home/runner/work/clash-rs/clash-rs/clash_lib/src/proxy/converters/tuic.rs

Check warning on line 46 in clash_lib/src/proxy/converters/tuic.rs

View workflow job for this annotation

GitHub Actions / aarch64-unknown-linux-gnu

Diff in /home/runner/work/clash-rs/clash-rs/clash_lib/src/proxy/converters/tuic.rs

Check warning on line 46 in clash_lib/src/proxy/converters/tuic.rs

View workflow job for this annotation

GitHub Actions / armv7-unknown-linux-gnueabihf

Diff in /home/runner/work/clash-rs/clash-rs/clash_lib/src/proxy/converters/tuic.rs

Check warning on line 46 in clash_lib/src/proxy/converters/tuic.rs

View workflow job for this annotation

GitHub Actions / armv7-unknown-linux-gnueabi-static-crt

Diff in /home/runner/work/clash-rs/clash-rs/clash_lib/src/proxy/converters/tuic.rs

Check warning on line 46 in clash_lib/src/proxy/converters/tuic.rs

View workflow job for this annotation

GitHub Actions / i686-unknown-linux-gnu-static-crt

Diff in /home/runner/work/clash-rs/clash-rs/clash_lib/src/proxy/converters/tuic.rs

Check warning on line 46 in clash_lib/src/proxy/converters/tuic.rs

View workflow job for this annotation

GitHub Actions / i686-pc-windows-msvc-static-crt

Diff in \\?\D:\a\clash-rs\clash-rs\clash_lib\src\proxy\converters\tuic.rs

Check warning on line 46 in clash_lib/src/proxy/converters/tuic.rs

View workflow job for this annotation

GitHub Actions / x86_64-pc-windows-msvc

Diff in \\?\D:\a\clash-rs\clash-rs\clash_lib\src\proxy\converters\tuic.rs

Check warning on line 46 in clash_lib/src/proxy/converters/tuic.rs

View workflow job for this annotation

GitHub Actions / x86_64-pc-windows-msvc-static-crt

Diff in \\?\D:\a\clash-rs\clash-rs\clash_lib\src\proxy\converters\tuic.rs

Check warning on line 46 in clash_lib/src/proxy/converters/tuic.rs

View workflow job for this annotation

GitHub Actions / i686-pc-windows-msvc

Diff in \\?\D:\a\clash-rs\clash-rs\clash_lib\src\proxy\converters\tuic.rs
reduce_rtt: s.reduce_rtt.unwrap_or(false) || s.fast_open.unwrap_or(false),
request_timeout: Duration::from_millis(s.request_timeout.unwrap_or(8000)),
request_timeout: Duration::from_millis(s.request_timeout.unwrap_or(4000)),
idle_timeout: VarInt::from_u64(s.request_timeout.unwrap_or(4000)).unwrap_or(VarInt::MAX),
congestion_controller: s
.congestion_controller
.clone()
Expand All @@ -54,6 +63,7 @@
send_window: s.send_window.unwrap_or(8 * 1024 * 1024 * 2),
receive_window: VarInt::from_u64(s.receive_window.unwrap_or(8 * 1024 * 1024))
.unwrap_or(VarInt::MAX),
mark: Arc::new(AtomicU32::new(0)),
})
}
}
4 changes: 2 additions & 2 deletions clash_lib/src/proxy/converters/vmess.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::{
options::{GrpcOption, Http2Option, WsOption},
transport::TLSOptions,
vmess::{Handler, HandlerOptions, VmessTransport},
AnyOutboundHandler, CommonOption,
AnyOutboundHandler,
},
Error,
};
Expand All @@ -30,7 +30,7 @@ impl TryFrom<&OutboundVmess> for AnyOutboundHandler {

let h = Handler::new(HandlerOptions {
name: s.name.to_owned(),
common_opts: CommonOption::default(),
common_opts: s.common_opts.clone(),
server: s.server.to_owned(),
port: s.port,
uuid: s.uuid.clone(),
Expand Down
2 changes: 1 addition & 1 deletion clash_lib/src/proxy/converters/wireguard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ impl TryFrom<&OutboundWireguard> for AnyOutboundHandler {
fn try_from(s: &OutboundWireguard) -> Result<Self, Self::Error> {
let h = Handler::new(HandlerOpts {
name: s.name.to_owned(),
common_opts: Default::default(),
common_opts: s.common_opts.clone(),
server: s.server.to_owned(),
port: s.port,
ip: s
Expand Down
Loading
Loading