diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6e9d3e965..c9a85e862 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,6 +15,7 @@ env: PACKAGE: "clash" REGISTRY: "ghcr.io" IMAGE_NAME: "clash-rs" + RUST_LOG: "clash=TRACE" # Arm builder https://github.blog/changelog/2024-09-03-github-actions-arm64-linux-and-windows-runners-are-now-generally-available/ @@ -221,13 +222,17 @@ jobs: use-cross: ${{ matrix.cross }} command: fmt args: --all -- --check - + env: + CLASH_DOCKER_TEST: "true" + - name: Cargo clippy uses: clechasseur/rs-cargo@v2 with: use-cross: ${{ matrix.cross }} command: clippy args: --all --target ${{ matrix.target }} ${{ matrix.extra-args }} -- -D warnings + env: + CLASH_DOCKER_TEST: "true" - name: Cargo test (docker test on linux) uses: clechasseur/rs-cargo@v2 @@ -306,7 +311,9 @@ jobs: # Deleted latest tag and push it git tag -d latest || true git push origin :refs/tags/latest || true - # Deleted all drafts + # Create local tag + git tag latest + # Delete all drafts gh release list | grep Draft | awk '{print $1 " \t"}' | while read -r line; do gh release delete -y "$line"; done env: GH_TOKEN: ${{ github.token }} diff --git a/Cargo.lock b/Cargo.lock index 5fb608ed5..b8a529fdc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -991,6 +991,7 @@ dependencies = [ "crc32fast", "criterion", "dhcproto", + "env_logger", "erased-serde", "filetime", "foreign-types-shared", @@ -1797,6 +1798,29 @@ dependencies = [ "syn 2.0.77", ] +[[package]] +name = "env_filter" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -4736,8 +4760,9 @@ dependencies = [ [[package]] name = "shadowsocks" -version = "1.20.3" -source = "git+https://github.com/Watfaq/shadowsocks-rust?rev=c6cb7fd906fe9f4126f724ae252f8a67cc1926b1#c6cb7fd906fe9f4126f724ae252f8a67cc1926b1" +version = "1.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ecb3780dfbc654de9383758015b9bb95c6e32fecace36ebded09d67e854d130" dependencies = [ "aes", "arc-swap", diff --git a/Cross.toml b/Cross.toml index a05dc5b64..9e6aea464 100644 --- a/Cross.toml +++ b/Cross.toml @@ -6,7 +6,7 @@ pre-build = [ [build.env] volumes = ["/var/run/docker.sock=/var/run/docker.sock"] # Docker in docker -passthrough = ["CLASH_GIT_REF", "CLASH_GIT_SHA", "RUSTFLAGS", "CLASH_DOCKER_TEST"] +passthrough = ["CLASH_GIT_REF", "CLASH_GIT_SHA", "RUSTFLAGS", "RUST_LOG", "CLASH_DOCKER_TEST"] [target.x86_64-unknown-linux-gnu] image = "ghcr.io/cross-rs/x86_64-unknown-linux-gnu:main" diff --git a/clash/tests/data/config/ss.yaml b/clash/tests/data/config/ss.yaml index 84abda0f5..4c9aff0d0 100644 --- a/clash/tests/data/config/ss.yaml +++ b/clash/tests/data/config/ss.yaml @@ -61,6 +61,12 @@ proxies: password: "password" udp: true +proxy-groups: + - name: "udp-relay" + type: relay + proxies: + - ss-01 + - ss-02 rules: - - MATCH, ss-01 + - MATCH, udp-relay ... diff --git a/clash_lib/Cargo.toml b/clash_lib/Cargo.toml index 76a303576..f5324e414 100644 --- a/clash_lib/Cargo.toml +++ b/clash_lib/Cargo.toml @@ -112,7 +112,7 @@ tracing-subscriber = { version = "0.3", features = ["env-filter"] } tracing-oslog = { branch = "main", git = "https://github.com/Absolucy/tracing-oslog.git" } tracing-appender = "0.2" -shadowsocks = { git = "https://github.com/Watfaq/shadowsocks-rust", rev = "c6cb7fd906fe9f4126f724ae252f8a67cc1926b1", optional = true, features=["aead-cipher-2022","stream-cipher"] } +shadowsocks = { version="1.21", optional = true, features=["aead-cipher-2022","stream-cipher"] } maxminddb = "0.24" public-suffix = "0.1" murmur3 = "0.5" @@ -138,7 +138,8 @@ mockall = "0.13.0" tokio-test = "0.4.4" axum-macros = "0.4.0" bollard = "0.17" -serial_test = "3.1.1" +serial_test = "3.1" +env_logger = "0.11" [build-dependencies] prost-build = "0.13" diff --git a/clash_lib/src/app/inbound/network_listener.rs b/clash_lib/src/app/inbound/network_listener.rs index 9ca2bea1c..729021fad 100644 --- a/clash_lib/src/app/inbound/network_listener.rs +++ b/clash_lib/src/app/inbound/network_listener.rs @@ -107,21 +107,21 @@ impl NetworkInboundListener { fn build_and_insert_listener(&self, runners: &mut Vec, ip: Ipv4Addr) { let listener: AnyInboundListener = match self.listener_type { - ListenerType::Http => http::Listener::new( + ListenerType::Http => Arc::new(http::Listener::new( (ip, self.port).into(), self.dispatcher.clone(), self.authenticator.clone(), - ), - ListenerType::Socks5 => socks::Listener::new( + )), + ListenerType::Socks5 => Arc::new(socks::Listener::new( (ip, self.port).into(), self.dispatcher.clone(), self.authenticator.clone(), - ), - ListenerType::Mixed => mixed::Listener::new( + )), + ListenerType::Mixed => Arc::new(mixed::Listener::new( (ip, self.port).into(), self.dispatcher.clone(), self.authenticator.clone(), - ), + )), }; if listener.handle_tcp() { diff --git a/clash_lib/src/lib.rs b/clash_lib/src/lib.rs index 838b65ef8..0d660a892 100644 --- a/clash_lib/src/lib.rs +++ b/clash_lib/src/lib.rs @@ -513,7 +513,15 @@ async fn start_async(opts: Options) -> Result<(), Error> { #[cfg(test)] mod tests { use crate::{shutdown, start, Config, Options}; - use std::{thread, time::Duration}; + use std::{sync::Once, thread, time::Duration}; + + static INIT: Once = Once::new(); + + pub fn initialize() { + INIT.call_once(|| { + env_logger::init(); + }); + } #[test] fn start_and_stop() { diff --git a/clash_lib/src/proxy/datagram.rs b/clash_lib/src/proxy/datagram.rs index f768ca683..dfd519d35 100644 --- a/clash_lib/src/proxy/datagram.rs +++ b/clash_lib/src/proxy/datagram.rs @@ -1,7 +1,7 @@ use crate::{ app::dns::ThreadSafeDNSResolver, common::errors::new_io_error, - proxy::{socks::Socks5UDPCodec, AnyOutboundDatagram, InboundDatagram}, + proxy::{socks::Socks5UDPCodec, InboundDatagram}, session::SocksAddr, }; use bytes::Bytes; @@ -149,6 +149,8 @@ impl Sink for InboundUdp> { impl InboundDatagram for InboundUdp> {} #[must_use = "sinks do nothing unless polled"] +// TODO: maybe we should use abstract datagram IO interface instead of the +// Stream + Sink trait pub struct OutboundDatagramImpl { inner: UdpSocket, resolver: ThreadSafeDNSResolver, @@ -157,18 +159,13 @@ pub struct OutboundDatagramImpl { } impl OutboundDatagramImpl { - #[allow(clippy::new_ret_no_self)] - pub fn new( - udp: UdpSocket, - resolver: ThreadSafeDNSResolver, - ) -> AnyOutboundDatagram { - let s = Self { + pub fn new(udp: UdpSocket, resolver: ThreadSafeDNSResolver) -> Self { + Self { inner: udp, resolver, flushed: true, pkt: None, - }; - Box::new(s) as _ + } } } diff --git a/clash_lib/src/proxy/http/inbound/mod.rs b/clash_lib/src/proxy/http/inbound/mod.rs index 8c8cc5dcd..3f73d15a5 100644 --- a/clash_lib/src/proxy/http/inbound/mod.rs +++ b/clash_lib/src/proxy/http/inbound/mod.rs @@ -4,7 +4,7 @@ mod proxy; use crate::{ common::auth::ThreadSafeAuthenticator, - proxy::{utils::apply_tcp_options, AnyInboundListener, InboundListener}, + proxy::{utils::apply_tcp_options, InboundListener}, Dispatcher, }; use async_trait::async_trait; @@ -29,17 +29,16 @@ impl Drop for Listener { } impl Listener { - #[allow(clippy::new_ret_no_self)] pub fn new( addr: SocketAddr, dispatcher: Arc, authenticator: ThreadSafeAuthenticator, - ) -> AnyInboundListener { - Arc::new(Self { + ) -> Self { + Self { addr, dispatcher, authenticator, - }) as _ + } } } diff --git a/clash_lib/src/proxy/mixed/mod.rs b/clash_lib/src/proxy/mixed/mod.rs index ce5ae863e..4fb9ac1bd 100644 --- a/clash_lib/src/proxy/mixed/mod.rs +++ b/clash_lib/src/proxy/mixed/mod.rs @@ -1,6 +1,6 @@ use crate::{ common::auth::ThreadSafeAuthenticator, - proxy::{AnyInboundListener, InboundListener}, + proxy::InboundListener, session::{Network, Session}, Dispatcher, }; @@ -25,17 +25,16 @@ impl Drop for Listener { } impl Listener { - #[allow(clippy::new_ret_no_self)] pub fn new( addr: SocketAddr, dispatcher: Arc, authenticator: ThreadSafeAuthenticator, - ) -> AnyInboundListener { - Arc::new(Self { + ) -> Self { + Self { addr, dispatcher, authenticator, - }) as _ + } } } diff --git a/clash_lib/src/proxy/relay/mod.rs b/clash_lib/src/proxy/relay/mod.rs index 0889dbc89..bb4287623 100644 --- a/clash_lib/src/proxy/relay/mod.rs +++ b/clash_lib/src/proxy/relay/mod.rs @@ -250,11 +250,9 @@ mod tests { provider.expect_touch().returning(|| ()); provider.expect_healthcheck().returning(|| ()); - provider.expect_proxies().returning(move || { - let mut proxies = Vec::new(); - proxies.push(ss_handler.clone()); - proxies - }); + provider + .expect_proxies() + .returning(move || vec![ss_handler.clone()]); let handler = Handler::new(Default::default(), vec![Arc::new(RwLock::new(provider))]); @@ -288,12 +286,9 @@ mod tests { provider.expect_touch().returning(|| ()); provider.expect_healthcheck().returning(|| ()); - provider.expect_proxies().returning(move || { - let mut proxies = Vec::new(); - proxies.push(ss_handler.clone()); - proxies.push(ss_handler.clone()); - proxies - }); + provider + .expect_proxies() + .returning(move || vec![ss_handler.clone(), ss_handler.clone()]); let handler = Handler::new(Default::default(), vec![Arc::new(RwLock::new(provider))]); diff --git a/clash_lib/src/proxy/shadowsocks/datagram.rs b/clash_lib/src/proxy/shadowsocks/datagram.rs index b20e392bb..af96acdc1 100644 --- a/clash_lib/src/proxy/shadowsocks/datagram.rs +++ b/clash_lib/src/proxy/shadowsocks/datagram.rs @@ -4,8 +4,16 @@ use std::{ task::{Context, Poll}, }; -use futures::{ready, Sink, SinkExt, Stream, StreamExt}; -use shadowsocks::ProxySocket; +use bytes::BytesMut; +use futures::{ + ready, + stream::{SplitSink, SplitStream}, + Sink, SinkExt, Stream, StreamExt, +}; +use shadowsocks::{ + relay::udprelay::{DatagramReceive, DatagramSend}, + ProxySocket, +}; use tokio::io::ReadBuf; use tracing::{debug, instrument, trace}; @@ -16,9 +24,10 @@ use crate::{ session::SocksAddr, }; -/// the outbound datagram for that shadowsocks returns to us -pub struct OutboundDatagramShadowsocks { - inner: ProxySocket, +/// OutboundDatagram wrapper for shadowsocks socket, that takes ShadowsocksUdpIo +/// as underlying I/O +pub struct OutboundDatagramShadowsocks { + inner: ProxySocket, remote_addr: SocksAddr, flushed: bool, pkt: Option, @@ -26,26 +35,27 @@ pub struct OutboundDatagramShadowsocks { resolver: ThreadSafeDNSResolver, } -impl OutboundDatagramShadowsocks { - #[allow(clippy::new_ret_no_self)] +impl OutboundDatagramShadowsocks { pub fn new( - inner: ProxySocket, + inner: ProxySocket, remote_addr: (String, u16), resolver: ThreadSafeDNSResolver, - ) -> AnyOutboundDatagram { - let s = Self { + ) -> Self { + Self { inner, flushed: true, pkt: None, remote_addr: remote_addr.try_into().expect("must into socks addr"), buf: vec![0u8; 65535], resolver, - }; - Box::new(s) as _ + } } } -impl Sink for OutboundDatagramShadowsocks { +impl Sink for OutboundDatagramShadowsocks +where + S: DatagramSend + Unpin, +{ type Error = io::Error; fn poll_ready( @@ -156,29 +166,35 @@ impl Sink for OutboundDatagramShadowsocks { } } -impl Stream for OutboundDatagramShadowsocks { +impl Stream for OutboundDatagramShadowsocks +where + S: DatagramReceive + Unpin, +{ type Item = UdpPacket; #[instrument(skip(self, cx))] fn poll_next( - mut self: Pin<&mut Self>, + self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll> { let Self { ref mut buf, ref inner, .. - } = *self; + } = self.get_mut(); let mut buf = ReadBuf::new(buf); - let rv = ready!(inner.poll_recv_from(cx, &mut buf)); + let rv = ready!(inner.poll_recv(cx, &mut buf)); debug!("recv udp packet from remote ss server: {:?}", rv); match rv { Ok((n, src, ..)) => Poll::Ready(Some(UdpPacket { data: buf.filled()[..n].to_vec(), - src_addr: src.into(), + src_addr: match src { + shadowsocks::relay::Address::SocketAddress(a) => a.into(), + _ => SocksAddr::any_ipv4(), + }, dst_addr: SocksAddr::any_ipv4(), })), Err(_) => Poll::Ready(None), @@ -186,77 +202,96 @@ impl Stream for OutboundDatagramShadowsocks { } } -/// Shadowsocks UDP I/O that is passed to shadowsocks relay +/// Shadowsocks UDP I/O that ProxySocket required pub(crate) struct ShadowsocksUdpIo { - inner: AnyOutboundDatagram, + w: tokio::sync::Mutex>, + r: tokio::sync::Mutex<(SplitStream, BytesMut)>, } impl ShadowsocksUdpIo { pub fn new(inner: AnyOutboundDatagram) -> Self { - Self { inner } + let (w, r) = inner.split(); + Self { + w: tokio::sync::Mutex::new(w), + r: tokio::sync::Mutex::new((r, BytesMut::new())), + } } } -impl Sink - for ShadowsocksUdpIo -{ - type Error = io::Error; - - fn poll_ready( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll> { - self.inner.poll_ready_unpin(cx) - } - - fn start_send( - mut self: Pin<&mut Self>, - item: shadowsocks::relay::udprelay::proxy_socket::UdpPacket, - ) -> Result<(), Self::Error> { - self.inner.start_send_unpin(UdpPacket { - data: item.data.to_vec(), - src_addr: item.src.map(|x| x.into()).unwrap_or_default(), - dst_addr: item.dst.map(|x| x.into()).unwrap_or_default(), - }) +impl DatagramSend for ShadowsocksUdpIo { + fn poll_send(&self, _: &mut Context<'_>, _: &[u8]) -> Poll> { + Poll::Ready(Err(new_io_error("not supported for shadowsocks udp io"))) } - fn poll_flush( - mut self: Pin<&mut Self>, + fn poll_send_to( + &self, cx: &mut Context<'_>, - ) -> Poll> { - self.inner.poll_flush_unpin(cx) + buf: &[u8], + target: std::net::SocketAddr, + ) -> Poll> { + let mut w = self.w.try_lock().expect("must acquire"); + match w.start_send_unpin(UdpPacket { + data: buf.to_vec(), + src_addr: SocksAddr::any_ipv4(), + dst_addr: target.into(), + }) { + Ok(_) => {} + Err(e) => return Poll::Ready(Err(new_io_error(e.to_string()))), + } + match w.poll_flush_unpin(cx) { + Poll::Ready(Ok(())) => Poll::Ready(Ok(buf.len())), + Poll::Ready(Err(e)) => Poll::Ready(Err(new_io_error(e.to_string()))), + Poll::Pending => Poll::Pending, + } } - fn poll_close( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll> { - self.inner.poll_close_unpin(cx) + fn poll_send_ready(&self, cx: &mut Context<'_>) -> Poll> { + let mut w = self.w.try_lock().expect("must acquire"); + w.poll_ready_unpin(cx) + .map_err(|e| new_io_error(e.to_string())) } } -impl Stream for ShadowsocksUdpIo { - type Item = shadowsocks::relay::udprelay::proxy_socket::UdpPacket; - - fn poll_next( - mut self: Pin<&mut Self>, +impl DatagramReceive for ShadowsocksUdpIo { + fn poll_recv( + &self, cx: &mut Context<'_>, - ) -> Poll> { - match ready!(self.inner.poll_next_unpin(cx)) { - Some(pkt) => { - let (src, dst) = ( - pkt.src_addr.must_into_socket_addr(), - pkt.dst_addr.must_into_socket_addr(), - ); - Poll::Ready(Some( - shadowsocks::relay::udprelay::proxy_socket::UdpPacket { - data: pkt.data.into(), - src: src.into(), - dst: dst.into(), - }, - )) + buf: &mut ReadBuf<'_>, + ) -> Poll> { + let mut g = self.r.try_lock().expect("must acquire"); + let (r, remained) = &mut *g; + + if !remained.is_empty() { + let to_consume = buf.remaining().min(remained.len()); + let consume = remained.split_to(to_consume); + buf.put_slice(&consume); + Poll::Ready(Ok(())) + } else { + match r.poll_next_unpin(cx) { + Poll::Ready(Some(pkt)) => { + let to_comsume = buf.remaining().min(pkt.data.len()); + let consume = pkt.data[..to_comsume].to_vec(); + buf.put_slice(&consume); + if to_comsume < pkt.data.len() { + remained.extend_from_slice(&pkt.data[to_comsume..]); + } + Poll::Ready(Ok(())) + } + Poll::Pending => Poll::Pending, + Poll::Ready(None) => Poll::Ready(Ok(())), } - None => Poll::Ready(None), } } + + fn poll_recv_from( + &self, + _: &mut Context<'_>, + _: &mut ReadBuf<'_>, + ) -> Poll> { + Poll::Ready(Err(new_io_error("not supported for shadowsocks udp io"))) + } + + fn poll_recv_ready(&self, _: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } } diff --git a/clash_lib/src/proxy/shadowsocks/mod.rs b/clash_lib/src/proxy/shadowsocks/mod.rs index 5e93903c3..1de33dbd4 100644 --- a/clash_lib/src/proxy/shadowsocks/mod.rs +++ b/clash_lib/src/proxy/shadowsocks/mod.rs @@ -271,14 +271,11 @@ impl OutboundHandler for Handler { ) .await?; - let socket = ProxySocket::from_io( + let socket = ProxySocket::from_socket( UdpSocketType::Client, ctx, &cfg, - Box::new(ShadowsocksUdpIo::new(socket)), - None, - #[cfg(unix)] - None, + ShadowsocksUdpIo::new(socket), ); let d = OutboundDatagramShadowsocks::new( socket, @@ -297,9 +294,12 @@ mod tests { use super::super::utils::test_utils::{ consts::*, docker_runner::DockerTestRunner, }; - use crate::proxy::utils::test_utils::{ - docker_runner::{DockerTestRunnerBuilder, MultiDockerTestRunner}, - run_test_suites_and_cleanup, Suite, + use crate::{ + proxy::utils::test_utils::{ + docker_runner::{DockerTestRunnerBuilder, MultiDockerTestRunner}, + run_test_suites_and_cleanup, Suite, + }, + tests::initialize, }; use super::*; @@ -320,8 +320,8 @@ mod tests { #[tokio::test] #[serial_test::serial] - async fn test_ss() -> anyhow::Result<()> { - let _ = tracing_subscriber::fmt().try_init(); + async fn test_ss_plain() -> anyhow::Result<()> { + initialize(); let opts = HandlerOptions { name: "test-ss".to_owned(), common_opts: Default::default(), @@ -469,9 +469,6 @@ mod tests { #[serial_test::serial] async fn test_ss_obfs_tls() -> anyhow::Result<()> { if cfg!(target_arch = "x86_64") { - let _ = tracing_subscriber::fmt() - .with_max_level(tracing::Level::DEBUG) - .try_init(); test_ss_obfs_inner(SimpleOBFSMode::Tls).await } else { eprintln!("test_ss_obfs_tls is ignored on non-x86_64 platform"); diff --git a/clash_lib/src/proxy/socks/inbound/mod.rs b/clash_lib/src/proxy/socks/inbound/mod.rs index ddfa682cb..4062eb7a0 100644 --- a/clash_lib/src/proxy/socks/inbound/mod.rs +++ b/clash_lib/src/proxy/socks/inbound/mod.rs @@ -3,7 +3,7 @@ mod stream; use crate::{ common::auth::ThreadSafeAuthenticator, - proxy::{utils::apply_tcp_options, AnyInboundListener, InboundListener}, + proxy::{utils::apply_tcp_options, InboundListener}, session::{Network, Session, Type}, Dispatcher, }; @@ -28,17 +28,16 @@ impl Drop for Listener { } impl Listener { - #[allow(clippy::new_ret_no_self)] pub fn new( addr: SocketAddr, dispatcher: Arc, authenticator: ThreadSafeAuthenticator, - ) -> AnyInboundListener { - Arc::new(Self { + ) -> Self { + Self { addr, dispatcher, authenticator, - }) as _ + } } } diff --git a/clash_lib/src/proxy/socks/outbound/mod.rs b/clash_lib/src/proxy/socks/outbound/mod.rs index 321eed690..75877db18 100644 --- a/clash_lib/src/proxy/socks/outbound/mod.rs +++ b/clash_lib/src/proxy/socks/outbound/mod.rs @@ -326,7 +326,6 @@ mod tests { #[tokio::test] #[serial_test::serial] async fn test_socks5_no_auth() -> anyhow::Result<()> { - let _ = tracing_subscriber::fmt().try_init(); let opts = HandlerOptions { name: "test-socks5-no-auth".to_owned(), common_opts: Default::default(), @@ -352,7 +351,6 @@ mod tests { async fn test_socks5_auth() -> anyhow::Result<()> { use crate::proxy::DialWithConnector; - let _ = tracing_subscriber::fmt().try_init(); let opts = HandlerOptions { name: "test-socks5-no-auth".to_owned(), common_opts: Default::default(), diff --git a/clash_lib/src/proxy/trojan/mod.rs b/clash_lib/src/proxy/trojan/mod.rs index feb60bd24..0ed834fb4 100644 --- a/clash_lib/src/proxy/trojan/mod.rs +++ b/clash_lib/src/proxy/trojan/mod.rs @@ -288,10 +288,6 @@ mod tests { #[tokio::test] #[serial_test::serial] async fn test_trojan_ws() -> anyhow::Result<()> { - let _ = tracing_subscriber::fmt() - // any additional configuration of the subscriber you might want here.. - .try_init(); - let span = tracing::info_span!("test_trojan_ws"); let _enter = span.enter(); diff --git a/clash_lib/src/proxy/tun/mod.rs b/clash_lib/src/proxy/tun/mod.rs index 54de9084f..3693292a4 100644 --- a/clash_lib/src/proxy/tun/mod.rs +++ b/clash_lib/src/proxy/tun/mod.rs @@ -87,7 +87,7 @@ mod tests { let log_path = cwd + "/" + &log_file + "." + &today.to_string(); let logs = std::fs::read_to_string(&log_path) - .expect(format!("failed to read log file: {}", log_path).as_str()); + .unwrap_or_else(|_| panic!("failed to read log file: {}", log_path)); assert!(logs.contains("1.1.1.1:53 to MATCH")); @@ -161,7 +161,7 @@ mod tests { let log_path = cwd + "/" + &log_file + "." + &today.to_string(); let logs = std::fs::read_to_string(&log_path) - .expect(format!("failed to read log file: {}", log_path).as_str()); + .unwrap_or_else(|_| panic!("failed to read log file: {}", log_path)); assert!(logs.contains("route_all is enabled")); assert!(logs.contains(format!("{} to MATCH", echo_addr).as_str())); diff --git a/clash_lib/src/proxy/utils/socket_helpers.rs b/clash_lib/src/proxy/utils/socket_helpers.rs index 41176e9e8..cd83d641c 100644 --- a/clash_lib/src/proxy/utils/socket_helpers.rs +++ b/clash_lib/src/proxy/utils/socket_helpers.rs @@ -148,41 +148,3 @@ pub async fn new_udp_socket( UdpSocket::from_std(socket.into()) } - -#[cfg(test)] -mod tests { - use std::{net::IpAddr, time::Duration}; - - use tokio::{net::TcpSocket, time::timeout}; - - #[tokio::test] - #[ignore = "not a real test"] - async fn test_connect_tcp() { - let mut futs = vec![]; - - for i in 0..100 { - futs.push(tokio::spawn(async move { - let now = std::time::Instant::now(); - let socket = socket2::Socket::new( - socket2::Domain::IPV4, - socket2::Type::DGRAM, - None, - ) - .unwrap(); - - timeout( - Duration::from_secs(10), - TcpSocket::from_std_stream(socket.into()) - .connect(("1.1.1.1".parse::().unwrap(), 443).into()), - ) - .await - .unwrap() - .unwrap(); - - println!("fut {} took {:?}", i, now.elapsed().as_millis()); - })); - } - - futures::future::join_all(futs).await; - } -} diff --git a/clash_lib/src/proxy/utils/test_utils/docker_runner.rs b/clash_lib/src/proxy/utils/test_utils/docker_runner.rs index 3e9b583dc..462d294c4 100644 --- a/clash_lib/src/proxy/utils/test_utils/docker_runner.rs +++ b/clash_lib/src/proxy/utils/test_utils/docker_runner.rs @@ -305,32 +305,30 @@ impl DockerTestRunnerBuilder { } pub fn get_host_config(port: u16) -> HostConfig { - let mut host_config = HostConfig::default(); - // we need to use the host mode to enable the benchmark function - #[cfg(not(target_os = "macos"))] - { - host_config.network_mode = Some("host".to_owned()); + HostConfig { + port_bindings: Some( + [ + ( + (format!("{}/tcp", port)), + Some(vec![PortBinding { + host_ip: Some("0.0.0.0".to_owned()), + host_port: Some(format!("{}", port)), + }]), + ), + ( + (format!("{}/udp", port)), + Some(vec![PortBinding { + host_ip: Some("0.0.0.0".to_owned()), + host_port: Some(format!("{}", port)), + }]), + ), + ] + .into_iter() + .collect::>(), + ), + // we need to use the host mode to enable the benchmark function + #[cfg(not(target_os = "macos"))] + network_mode: Some("host".to_owned()), + ..Default::default() } - host_config.port_bindings = Some( - [ - ( - (format!("{}/tcp", port)), - Some(vec![PortBinding { - host_ip: Some("0.0.0.0".to_owned()), - host_port: Some(format!("{}", port)), - }]), - ), - ( - (format!("{}/udp", port)), - Some(vec![PortBinding { - host_ip: Some("0.0.0.0".to_owned()), - host_port: Some(format!("{}", port)), - }]), - ), - ] - .into_iter() - .collect::>(), - ); - - host_config } diff --git a/clash_lib/src/proxy/utils/test_utils/mod.rs b/clash_lib/src/proxy/utils/test_utils/mod.rs index cbab50b12..bc3ab71f4 100644 --- a/clash_lib/src/proxy/utils/test_utils/mod.rs +++ b/clash_lib/src/proxy/utils/test_utils/mod.rs @@ -33,7 +33,14 @@ pub async fn ping_pong_test( // server(127.0.0.1:port) let sess = Session { - destination: ("127.0.0.1".to_owned(), port) + destination: ( + if cfg!(target_os = "linux") { + "127.0.0.1".to_owned() + } else { + "host.docker.internal".to_owned() + }, + port, + ) .try_into() .unwrap_or_else(|_| panic!("")), ..Default::default() @@ -144,7 +151,14 @@ pub async fn ping_pong_udp_test( let src = ("127.0.0.1".to_owned(), 10005) .try_into() .unwrap_or_else(|_| panic!("")); - let dst: SocksAddr = ("127.0.0.1".to_owned(), port) + let dst: SocksAddr = ( + if cfg!(target_os = "linux") { + "127.0.0.1".to_owned() + } else { + "host.docker.internal".to_owned() + }, + port, + ) .try_into() .unwrap_or_else(|_| panic!("")); @@ -341,8 +355,8 @@ pub async fn run_test_suites_and_cleanup( } Suite::DnsUdp => { let rv = dns_test(handler.clone()).await; - if rv.is_err() { - return Err(rv.unwrap_err()); + if let Err(rv) = rv { + return Err(rv); } else { tracing::info!("dns_test success"); } diff --git a/clash_lib/src/proxy/vmess/mod.rs b/clash_lib/src/proxy/vmess/mod.rs index ae5736f3b..bcf20dda6 100644 --- a/clash_lib/src/proxy/vmess/mod.rs +++ b/clash_lib/src/proxy/vmess/mod.rs @@ -317,10 +317,6 @@ mod tests { #[tokio::test] #[serial_test::serial] async fn test_vmess_ws() -> anyhow::Result<()> { - let _ = tracing_subscriber::fmt() - // any additional configuration of the subscriber you might want here.. - .try_init(); - let span = tracing::info_span!("test_vmess_ws"); let _enter = span.enter();