From d154e540f6a9184ee6f75d4b94666b8dcf1f33f0 Mon Sep 17 00:00:00 2001 From: dev0 Date: Mon, 28 Aug 2023 04:30:47 +1000 Subject: [PATCH] vmess non aead --- clash/tests/data/config/rules.yaml | 13 ++- clash_lib/src/app/dns/dhcp.rs | 21 +++-- clash_lib/src/app/dns/helper.rs | 7 +- clash_lib/src/app/dns/mod.rs | 22 ++++++ clash_lib/src/app/logging.rs | 11 ++- .../src/app/proxy_manager/healthcheck.rs | 4 +- clash_lib/src/app/proxy_manager/mod.rs | 22 +++++- clash_lib/src/common/crypto.rs | 4 +- clash_lib/src/config/def.rs | 12 +++ .../src/proxy/transport/websocket/mod.rs | 9 +++ .../proxy/transport/websocket/websocket.rs | 79 ++++++++----------- clash_lib/src/proxy/vmess/mod.rs | 8 +- clash_lib/src/proxy/vmess/vmess_impl/mod.rs | 1 + .../src/proxy/vmess/vmess_impl/stream.rs | 33 ++++---- clash_lib/src/proxy/vmess/vmess_impl/user.rs | 14 +++- docker/docker-compose.yml | 2 + 16 files changed, 178 insertions(+), 84 deletions(-) diff --git a/clash/tests/data/config/rules.yaml b/clash/tests/data/config/rules.yaml index 63041412..d04a9dc8 100644 --- a/clash/tests/data/config/rules.yaml +++ b/clash/tests/data/config/rules.yaml @@ -85,7 +85,7 @@ proxy-groups: - DIRECT strategy: round-robin url: "http://www.gstatic.com/generate_204" - interval: 10 + interval: 300 - name: select type: select @@ -132,10 +132,19 @@ proxies: path: /api/v3/download.getFile headers: Host: www.amazon.com + - name: vmess-altid + type: vmess + server: 10.0.0.13 + port: 16823 + uuid: b831381d-6324-4d53-ad4f-8cda48b30811 + alterId: 64 + cipher: auto + udp: true + skip-cert-verify: true rules: - DOMAIN,ipinfo.io,relay - - DOMAIN-KEYWORD,httpbin,ws-vmess + - DOMAIN-KEYWORD,httpbin,vmess-altid - DOMAIN-SUFFIX,facebook.com,REJECT - DOMAIN-KEYWORD,google,ss - DOMAIN,google.com,ss diff --git a/clash_lib/src/app/dns/dhcp.rs b/clash_lib/src/app/dns/dhcp.rs index 156bef8c..ee06b0c1 100644 --- a/clash_lib/src/app/dns/dhcp.rs +++ b/clash_lib/src/app/dns/dhcp.rs @@ -2,6 +2,7 @@ use crate::dns::dns_client::DNSNetMode; use crate::dns::helper::make_clients; use crate::dns::{Client, NameServer, Resolver, ThreadSafeDNSClient}; use crate::proxy::utils::{new_udp_socket, Interface}; +use crate::{dns_debug, dns_warn}; use async_trait::async_trait; use dhcproto::{Decodable, Encodable}; use futures::FutureExt; @@ -48,7 +49,12 @@ impl Debug for DhcpClient { impl Client for DhcpClient { async fn exchange(&mut self, msg: &Message) -> anyhow::Result { let clients = self.resolve().await?; - debug!("using clients: {:?}", clients); + let mut dbg_str = vec![]; + for c in clients { + let l = c.lock().await; + dbg_str.push(format!("{:?}", l)); + } + debug!("using clients: {:?}", dbg_str); tokio::time::timeout(DHCP_TIMEOUT, Resolver::batch_exchange(clients, msg)).await? } } @@ -166,7 +172,7 @@ async fn listen_dhcp_client(iface: &str) -> io::Result { } async fn probe_dns_server(iface: &str) -> io::Result> { - debug!("probing NS servers from DHCP"); + dns_debug!("probing NS servers from DHCP"); let socket = listen_dhcp_client(iface).await?; let mac_address: Vec = network_interface::NetworkInterface::show() @@ -236,7 +242,10 @@ async fn probe_dns_server(iface: &str) -> io::Result> { { match op { dhcproto::v4::DhcpOption::DomainNameServer(dns) => { - debug!("got NS servers {:?} from DHCP", dns); + dns_debug!( + "got NS servers {:?} from DHCP", + dns + ); return dns.clone(); } _ => yield_now().await, @@ -254,8 +263,8 @@ async fn probe_dns_server(iface: &str) -> io::Result> { }; tokio::select! { - _ = tx.closed() => {debug!("future cancelled, likely other clients won")}, - value = get_response => tx.send(value).map_err(|x| warn!("send error: {:?}", x)).unwrap_or_default(), + _ = tx.closed() => {dns_debug!("future cancelled, likely other clients won")}, + value = get_response => tx.send(value).map_err(|x| dns_warn!("send error: {:?}", x)).unwrap_or_default(), } }); @@ -268,7 +277,7 @@ async fn probe_dns_server(iface: &str) -> io::Result> { }, _ = tokio::time::sleep(Duration::from_secs(10)) => { - debug!("DHCP timeout after 10 secs"); + dns_debug!("DHCP timeout after 10 secs"); return Err(io::Error::new(io::ErrorKind::Other, "dhcp timeout")); } } diff --git a/clash_lib/src/app/dns/helper.rs b/clash_lib/src/app/dns/helper.rs index 9a7db014..2e449728 100644 --- a/clash_lib/src/app/dns/helper.rs +++ b/clash_lib/src/app/dns/helper.rs @@ -1,8 +1,9 @@ use crate::dns::dns_client::{DNSNetMode, DnsClient, Opts}; use crate::dns::{ClashResolver, NameServer, ThreadSafeDNSClient}; +use crate::dns_debug; use crate::proxy::utils::Interface; use std::sync::Arc; -use tracing::{debug, error}; +use tracing::{debug, warn}; pub async fn make_clients( servers: Vec, @@ -11,7 +12,7 @@ pub async fn make_clients( let mut rv = Vec::new(); for s in servers { - debug!("building nameserver: {:?}", s); + dns_debug!("building nameserver: {:?}", s); let (host, port) = if s.net == DNSNetMode::DHCP { (s.address.as_str(), "0") @@ -36,7 +37,7 @@ pub async fn make_clients( .await { Ok(c) => rv.push(c), - Err(e) => error!("initializing DNS client: {}", e), + Err(e) => warn!("initializing DNS client: {}", e), } } diff --git a/clash_lib/src/app/dns/mod.rs b/clash_lib/src/app/dns/mod.rs index ba42aefb..19f4feb8 100644 --- a/clash_lib/src/app/dns/mod.rs +++ b/clash_lib/src/app/dns/mod.rs @@ -21,8 +21,30 @@ use crate::dns::dns_client::DNSNetMode; pub use resolver::ClashResolver; pub use resolver::Resolver; +#[macro_export] +macro_rules! dns_debug { + ($($arg:tt)*) => { + debug!(target: "dns", $($arg)*) + }; +} + +#[macro_export] +macro_rules! dns_info { + ($($arg:tt)*) => { + info!(target: "dns", $($arg)*) + }; +} + +#[macro_export] +macro_rules! dns_warn { + ($($arg:tt)*) => { + warn!(target: "dns", $($arg)*) + }; +} + #[async_trait] pub trait Client: Sync + Send + Debug { + // TODO: make this non mutable async fn exchange(&mut self, msg: &op::Message) -> anyhow::Result; } diff --git a/clash_lib/src/app/logging.rs b/clash_lib/src/app/logging.rs index 8cb39048..2ab5c979 100644 --- a/clash_lib/src/app/logging.rs +++ b/clash_lib/src/app/logging.rs @@ -1,8 +1,7 @@ use crate::def::LogLevel; use tokio::sync::broadcast::Sender; -use tracing::Event; -use tracing_subscriber::filter::Targets; +use tracing_subscriber::filter::Directive; use tracing_subscriber::prelude::*; use tracing_subscriber::Layer; use tracing_subscriber::{filter, EnvFilter}; @@ -62,12 +61,16 @@ where pub fn setup_logging(level: LogLevel, collector: EventCollector) -> anyhow::Result<()> { let filter = EnvFilter::builder() - .with_default_directive(filter::LevelFilter::from(level).into()) + .with_default_directive( + format!("clash={}", level) + .parse::() + .unwrap() + .into(), + ) .from_env_lossy(); let subscriber = tracing_subscriber::registry() .with(filter) - .with(Targets::new().with_target("clash", level)) .with(collector) .with( tracing_subscriber::fmt::Layer::new() diff --git a/clash_lib/src/app/proxy_manager/healthcheck.rs b/clash_lib/src/app/proxy_manager/healthcheck.rs index bf770412..f459f818 100644 --- a/clash_lib/src/app/proxy_manager/healthcheck.rs +++ b/clash_lib/src/app/proxy_manager/healthcheck.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use tokio::time::Instant; use tracing::debug; -use crate::proxy::AnyOutboundHandler; +use crate::{pm_debug, proxy::AnyOutboundHandler}; use super::ThreadSafeProxyManager; @@ -64,7 +64,7 @@ impl HealthCheck { loop { tokio::select! { _ = ticker.tick() => { - debug!("healthcheck ticking: {}", url); + pm_debug!("healthcheck ticking: {}", url); let now = tokio::time::Instant::now(); if !lazy || now.duration_since(inner.lock().await.last_check).as_secs() >= interval { proxy_manager.check(&proxies, &url, None).await; diff --git a/clash_lib/src/app/proxy_manager/mod.rs b/clash_lib/src/app/proxy_manager/mod.rs index 473571f5..35665057 100644 --- a/clash_lib/src/app/proxy_manager/mod.rs +++ b/clash_lib/src/app/proxy_manager/mod.rs @@ -14,7 +14,7 @@ use http::Request; use hyper_boring::HttpsConnector; use serde::Serialize; use tokio::sync::RwLock; -use tracing::{debug, error, warn}; +use tracing::{debug, warn}; use crate::{ common::errors::{map_io_error, new_io_error}, @@ -29,6 +29,20 @@ pub mod healthcheck; mod http_client; pub mod providers; +#[macro_export] +macro_rules! pm_debug { + ($($arg:tt)*) => ({ + debug!(target: "proxy_manager", $($arg)*); + }); +} + +#[macro_export] +macro_rules! pm_warn { + ($($arg:tt)*) => ({ + warn!(target: "proxy_manager", $($arg)*); + }); +} + #[derive(Clone, Serialize)] pub struct DelayHistory { time: DateTime, @@ -125,7 +139,7 @@ impl ProxyManager { url: &str, timeout: Option, ) -> std::io::Result<(u16, u16)> { - debug!( + pm_debug!( "testing {} with url {}, timeout {:?}", proxy.name(), url, @@ -160,7 +174,7 @@ impl ProxyManager { .as_millis() .try_into() .expect("delay is too large"); - debug!( + pm_debug!( "urltest for proxy {} with url {} returned response {} in {}ms", &name, url, @@ -207,7 +221,7 @@ impl ProxyManager { state.delay_history.pop_front(); } - debug!("{} alive: {}, delay: {:?}", name, result.is_ok(), result); + pm_debug!("{} alive: {}, delay: {:?}", name, result.is_ok(), result); result } diff --git a/clash_lib/src/common/crypto.rs b/clash_lib/src/common/crypto.rs index 29246a2a..6ab2535b 100644 --- a/clash_lib/src/common/crypto.rs +++ b/clash_lib/src/common/crypto.rs @@ -4,10 +4,10 @@ use crate::Error; use aes_gcm::aes::cipher::Unsigned; use aes_gcm::{AeadInPlace, KeyInit}; -use bytes::BytesMut; pub fn aes_cfb_encrypt(key: &[u8], iv: &[u8], data: &mut Vec) -> anyhow::Result<()> { unsafe { + data.reserve(boring_sys::EVP_MAX_BLOCK_LENGTH as _); let ctx = boring_sys::EVP_CIPHER_CTX_new(); let rv = boring_sys::EVP_EncryptInit_ex( ctx, @@ -23,6 +23,7 @@ pub fn aes_cfb_encrypt(key: &[u8], iv: &[u8], data: &mut Vec) -> anyhow::Res ); if rv != 1 { + boring_sys::EVP_CIPHER_CTX_free(ctx); return Err(Error::Crypto( CStr::from_ptr( boring_sys::ERR_reason_error_string(boring_sys::ERR_get_error()) as _, @@ -44,6 +45,7 @@ pub fn aes_cfb_encrypt(key: &[u8], iv: &[u8], data: &mut Vec) -> anyhow::Res ); if rv != 1 { + boring_sys::EVP_CIPHER_CTX_free(ctx); return Err(Error::Crypto( CStr::from_ptr( boring_sys::ERR_reason_error_string(boring_sys::ERR_get_error()) as _, diff --git a/clash_lib/src/config/def.rs b/clash_lib/src/config/def.rs index 7bed5ddb..ff465761 100644 --- a/clash_lib/src/config/def.rs +++ b/clash_lib/src/config/def.rs @@ -41,6 +41,18 @@ pub enum LogLevel { Silent, } +impl Display for LogLevel { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + LogLevel::Debug => write!(f, "debug"), + LogLevel::Info => write!(f, "info"), + LogLevel::Warning => write!(f, "warning"), + LogLevel::Error => write!(f, "error"), + LogLevel::Silent => write!(f, "off"), + } + } +} + #[derive(Serialize, Deserialize)] #[serde(rename_all = "kebab-case", default)] pub struct Config { diff --git a/clash_lib/src/proxy/transport/websocket/mod.rs b/clash_lib/src/proxy/transport/websocket/mod.rs index 365a3f9a..e74bd052 100644 --- a/clash_lib/src/proxy/transport/websocket/mod.rs +++ b/clash_lib/src/proxy/transport/websocket/mod.rs @@ -13,6 +13,14 @@ pub use websocket_early_data::WebsocketEarlyDataConn; use crate::{common::errors::map_io_error, proxy::AnyStream}; +use tracing::debug; + +macro_rules! ws_debug { + ($($arg:tt)*) => { + debug!(target: "ws", $($arg)*) + }; +} + pub struct WebsocketStreamBuilder { uri: Uri, headers: HashMap, @@ -79,6 +87,7 @@ impl WebsocketStreamBuilder { let (stream, resp) = client_async_with_config(req, stream, self.ws_config) .await .map_err(map_io_error)?; + ws_debug!("response: {:?}", resp); if resp.status() != StatusCode::SWITCHING_PROTOCOLS { return Err(std::io::Error::new( std::io::ErrorKind::InvalidData, diff --git a/clash_lib/src/proxy/transport/websocket/websocket.rs b/clash_lib/src/proxy/transport/websocket/websocket.rs index eedc4ace..d45097f0 100644 --- a/clash_lib/src/proxy/transport/websocket/websocket.rs +++ b/clash_lib/src/proxy/transport/websocket/websocket.rs @@ -1,6 +1,6 @@ -use std::{fmt::Debug, pin::Pin}; +use std::{fmt::Debug, pin::Pin, task::Poll}; -use bytes::{Buf, Bytes}; +use bytes::{Buf, Bytes, BytesMut}; use futures::{ready, Sink, Stream}; use tokio::io::{AsyncRead, AsyncWrite}; use tokio_tungstenite::{tungstenite::Message, WebSocketStream}; @@ -12,7 +12,7 @@ use crate::{ pub struct WebsocketConn { inner: WebSocketStream, - read_buffer: Option, + read_buffer: BytesMut, } impl Debug for WebsocketConn { @@ -28,7 +28,7 @@ impl WebsocketConn { pub fn from_websocket(stream: WebSocketStream) -> Self { Self { inner: stream, - read_buffer: None, + read_buffer: BytesMut::new(), } } } @@ -39,47 +39,38 @@ impl AsyncRead for WebsocketConn { cx: &mut std::task::Context<'_>, buf: &mut tokio::io::ReadBuf<'_>, ) -> std::task::Poll> { - loop { - if let Some(read_buffer) = &mut self.read_buffer { - if read_buffer.len() <= buf.remaining() { - buf.put_slice(read_buffer); - self.read_buffer = None; - } else { - buf.put_slice(&read_buffer[..buf.remaining()]); - read_buffer.advance(buf.remaining()); - } - return std::task::Poll::Ready(Ok(())); - } - - let message = ready!(Pin::new(&mut self.inner).poll_next(cx)); - - if message.is_none() { - return std::task::Poll::Ready(Err(std::io::Error::new( - std::io::ErrorKind::UnexpectedEof, - "unexpected EOF", - ))); - } - - let message = message.unwrap().map_err(map_io_error)?; - - match message { - tokio_tungstenite::tungstenite::Message::Binary(binary) => { - if binary.len() < buf.remaining() { - buf.put_slice(&binary); - } else { - buf.put_slice(&binary[..buf.remaining()]); - self.read_buffer = Some(Bytes::from(binary[buf.remaining()..].to_vec())); - } - return std::task::Poll::Ready(Ok(())); - } - tokio_tungstenite::tungstenite::Message::Close(_) => { - return std::task::Poll::Ready(Ok(())) - } - _ => { - return std::task::Poll::Ready(Err(new_io_error("unexpected message type"))); - } - } + if !self.read_buffer.is_empty() { + let to_read = std::cmp::min(buf.remaining(), self.read_buffer.len()); + let for_read = self.read_buffer.split_to(to_read); + buf.put_slice(&for_read[..to_read]); + return std::task::Poll::Ready(Ok(())); } + Poll::Ready(ready!(Pin::new(&mut self.inner).poll_next(cx)).map_or( + Err(std::io::Error::new( + std::io::ErrorKind::BrokenPipe, + "ws broken pipe", + )), + |item| { + item.map_or( + Err(std::io::Error::new( + std::io::ErrorKind::BrokenPipe, + "ws broken pipe", + )), + |msg| match msg { + Message::Binary(data) => { + let to_read = std::cmp::min(buf.remaining(), data.len()); + buf.put_slice(&data[..to_read]); + if to_read < data.len() { + self.read_buffer.extend_from_slice(&data[to_read..]); + } + Ok(()) + } + Message::Close(_) => Ok(()), + _ => Err(new_io_error("ws invalid message type")), + }, + ) + }, + )) } } diff --git a/clash_lib/src/proxy/vmess/mod.rs b/clash_lib/src/proxy/vmess/mod.rs index 5666d336..0790545a 100644 --- a/clash_lib/src/proxy/vmess/mod.rs +++ b/clash_lib/src/proxy/vmess/mod.rs @@ -1,7 +1,6 @@ use std::{collections::HashMap, io, net::IpAddr, sync::Arc}; use async_trait::async_trait; -use erased_serde::Serialize; use futures::TryFutureExt; use http::Uri; @@ -22,6 +21,13 @@ use super::{ OutboundType, }; +#[macro_export] +macro_rules! vmess_debug { + ($($arg:tt)*) => { + debug!(target: "vmess", $($arg)*) + }; +} + pub struct HttpOption { pub method: String, pub path: Vec, diff --git a/clash_lib/src/proxy/vmess/vmess_impl/mod.rs b/clash_lib/src/proxy/vmess/vmess_impl/mod.rs index 59525aaf..14f4a404 100644 --- a/clash_lib/src/proxy/vmess/vmess_impl/mod.rs +++ b/clash_lib/src/proxy/vmess/vmess_impl/mod.rs @@ -10,6 +10,7 @@ mod user; pub(crate) const VERSION: u8 = 1; pub(crate) const OPTION_CHUNK_STREAM: u8 = 1; +#[allow(unused)] pub(crate) const OPTION_CHUNK_MASK: u8 = 2; type Security = u8; diff --git a/clash_lib/src/proxy/vmess/vmess_impl/stream.rs b/clash_lib/src/proxy/vmess/vmess_impl/stream.rs index b30d2204..01d0452c 100644 --- a/clash_lib/src/proxy/vmess/vmess_impl/stream.rs +++ b/clash_lib/src/proxy/vmess/vmess_impl/stream.rs @@ -15,6 +15,7 @@ use crate::{ }, proxy::vmess::vmess_impl::MAX_CHUNK_SIZE, session::SocksAddr, + vmess_debug, }; use super::{ @@ -93,7 +94,7 @@ impl ReadExt for VmessStream { ) -> Poll> { self.read_buf.reserve(size); unsafe { self.read_buf.set_len(size) } - debug!( + vmess_debug!( "poll read exact: {}, read_pos: {}, buf: {}", size, self.read_pos, @@ -254,7 +255,7 @@ where if !is_aead { let mut hash = [0u8; boring_sys::EVP_MAX_MD_SIZE as usize]; - let out_len = 0; + let mut out_len: u32 = 0; unsafe { boring_sys::HMAC( @@ -264,10 +265,10 @@ where now.to_be_bytes().as_mut_ptr() as _, 8, &mut hash as _, - out_len as _, + &mut out_len as _, ); } - mbuf.put_slice(&hash[..out_len]) + mbuf.put_slice(&hash[..out_len as _]) } let mut buf = BytesMut::new(); @@ -308,12 +309,12 @@ where mbuf.put_slice(data.as_slice()); let out = mbuf.freeze(); - debug!("send non aead handshake request for user{}", id.uuid); + vmess_debug!("send non aead handshake request for user{}", id.uuid); stream.write_all(&out).await?; } else { let out = header::seal_vmess_aead_header(id.cmd_key, buf.freeze().to_vec(), now) .map_err(map_io_error)?; - debug!("send aead handshake request for user {}", id.uuid); + vmess_debug!("send aead handshake request for user {}", id.uuid); stream.write_all(&out).await?; } @@ -333,14 +334,14 @@ where cx: &mut std::task::Context<'_>, buf: &mut tokio::io::ReadBuf<'_>, ) -> std::task::Poll> { - debug!("poll read with aead"); + vmess_debug!("poll read with aead"); loop { match self.read_state { ReadState::AeadWaitingHeaderSize => { - debug!("recv handshake response header"); + vmess_debug!("recv handshake response header"); let this = &mut *self; - let resp_body_key = this.resp_body_key.clone(); // TODO: get rid of clone + let resp_body_key = this.resp_body_key.clone(); let resp_body_iv = this.resp_body_iv.clone(); let resp_v = this.resp_v; @@ -352,20 +353,20 @@ where if buf[0] != resp_v { return Poll::Ready(Err(std::io::Error::new( std::io::ErrorKind::InvalidData, - "invalid response", + "invalid response - non aead invalid resp_v", ))); } if buf[2] != 0 { return Poll::Ready(Err(std::io::Error::new( std::io::ErrorKind::InvalidData, - "invalid response", + "invalid response - dynamic port not supported", ))); } this.read_state = ReadState::StreamWaitingLength; } else { - debug!("recv handshake response header length"); + vmess_debug!("recv handshake response header length"); ready!(this.poll_read_exact(cx, 18))?; let aead_response_header_length_encryption_key = &kdf::vmess_kdf_1_one_shot( @@ -401,7 +402,7 @@ where } ReadState::AeadWaitingHeader(header_size) => { - debug!("recv handshake header body: {}", header_size); + vmess_debug!("recv handshake header body: {}", header_size); let this = &mut *self; ready!(this.poll_read_exact(cx, header_size + 16))?; @@ -451,7 +452,7 @@ where } ReadState::StreamWaitingLength => { - debug!("recv stream length"); + vmess_debug!("recv stream length"); let this = &mut *self; ready!(this.poll_read_exact(cx, 2))?; let len = u16::from_be_bytes(this.read_buf.split().as_ref().try_into().unwrap()) @@ -468,7 +469,7 @@ where } ReadState::StreamWaitingData(size) => { - debug!("recv stream data: {}", size); + vmess_debug!("recv stream data: {}", size); let this = &mut *self; ready!(this.poll_read_exact(cx, size))?; @@ -483,7 +484,7 @@ where } ReadState::StreamFlushingData(size) => { - debug!("flush stream data: {}", size); + vmess_debug!("flush stream data: {}", size); let to_read = std::cmp::min(buf.remaining(), size); let payload = self.read_buf.split_to(to_read); buf.put_slice(&payload); diff --git a/clash_lib/src/proxy/vmess/vmess_impl/user.rs b/clash_lib/src/proxy/vmess/vmess_impl/user.rs index 2390cfe5..e19fa064 100644 --- a/clash_lib/src/proxy/vmess/vmess_impl/user.rs +++ b/clash_lib/src/proxy/vmess/vmess_impl/user.rs @@ -59,10 +59,11 @@ fn next_id(i: &uuid::Uuid) -> uuid::Uuid { ); boring_sys::MD5_Update( &mut ctx as _, - b"b48619fe-8f02-49e0-b9e9-edf763e17e21".as_ptr() as _, + b"16167dc8-16b6-4e6d-b8bb-65dd68113a81".as_ptr() as _, 36, ); let mut buf = [0u8; MD5_DIGEST_LENGTH as _]; + /* loop { boring_sys::MD5_Final(buf.as_mut_ptr() as _, &mut ctx as _); if i.as_bytes() != buf.as_slice() { @@ -75,6 +76,9 @@ fn next_id(i: &uuid::Uuid) -> uuid::Uuid { 36, ); } + */ + boring_sys::MD5_Final(buf.as_mut_ptr() as _, &mut ctx as _); + uuid::Uuid::from_bytes(buf) } } @@ -90,4 +94,12 @@ mod tests { [181, 13, 145, 106, 192, 206, 192, 103, 152, 26, 248, 229, 243, 138, 117, 143] ); } + + #[test] + fn test_next_id() { + let id = + super::new_id(&uuid::Uuid::parse_str("b831381d-6324-4d53-ad4f-8cda48b30811").unwrap()); + let next_id = super::next_id(&id.uuid); + assert_eq!(next_id.to_string(), "5a071834-12d5-980a-72ac-845d5568d17d"); + } } diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 4e4e1921..414a2113 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -9,6 +9,8 @@ services: v2ray-vmess: image: v2fly/v2fly-core + environment: + - V2RAY_VMESS_AEAD_FORCED=false network_mode: "host" command: ["run", "-c", "/etc/v2ray/config.json"] volumes: