Skip to content

Commit

Permalink
vmess non aead
Browse files Browse the repository at this point in the history
  • Loading branch information
ibigbug committed Aug 27, 2023
1 parent e55cf11 commit d154e54
Show file tree
Hide file tree
Showing 16 changed files with 178 additions and 84 deletions.
13 changes: 11 additions & 2 deletions clash/tests/data/config/rules.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
21 changes: 15 additions & 6 deletions clash_lib/src/app/dns/dhcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -48,7 +49,12 @@ impl Debug for DhcpClient {
impl Client for DhcpClient {
async fn exchange(&mut self, msg: &Message) -> anyhow::Result<Message> {
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?
}
}
Expand Down Expand Up @@ -166,7 +172,7 @@ async fn listen_dhcp_client(iface: &str) -> io::Result<UdpSocket> {
}

async fn probe_dns_server(iface: &str) -> io::Result<Vec<Ipv4Addr>> {
debug!("probing NS servers from DHCP");
dns_debug!("probing NS servers from DHCP");
let socket = listen_dhcp_client(iface).await?;

let mac_address: Vec<u8> = network_interface::NetworkInterface::show()
Expand Down Expand Up @@ -236,7 +242,10 @@ async fn probe_dns_server(iface: &str) -> io::Result<Vec<Ipv4Addr>> {
{
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,
Expand All @@ -254,8 +263,8 @@ async fn probe_dns_server(iface: &str) -> io::Result<Vec<Ipv4Addr>> {
};

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(),
}
});

Expand All @@ -268,7 +277,7 @@ async fn probe_dns_server(iface: &str) -> io::Result<Vec<Ipv4Addr>> {
},

_ = 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"));
}
}
Expand Down
7 changes: 4 additions & 3 deletions clash_lib/src/app/dns/helper.rs
Original file line number Diff line number Diff line change
@@ -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<NameServer>,
Expand All @@ -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")
Expand All @@ -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),
}
}

Expand Down
22 changes: 22 additions & 0 deletions clash_lib/src/app/dns/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<op::Message>;
}

Expand Down
11 changes: 7 additions & 4 deletions clash_lib/src/app/logging.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -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::<Directive>()
.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()
Expand Down
4 changes: 2 additions & 2 deletions clash_lib/src/app/proxy_manager/healthcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down
22 changes: 18 additions & 4 deletions clash_lib/src/app/proxy_manager/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand All @@ -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<Utc>,
Expand Down Expand Up @@ -125,7 +139,7 @@ impl ProxyManager {
url: &str,
timeout: Option<Duration>,
) -> std::io::Result<(u16, u16)> {
debug!(
pm_debug!(
"testing {} with url {}, timeout {:?}",
proxy.name(),
url,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
}
Expand Down
4 changes: 3 additions & 1 deletion clash_lib/src/common/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<u8>) -> 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,
Expand All @@ -23,6 +23,7 @@ pub fn aes_cfb_encrypt(key: &[u8], iv: &[u8], data: &mut Vec<u8>) -> 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 _,
Expand All @@ -44,6 +45,7 @@ pub fn aes_cfb_encrypt(key: &[u8], iv: &[u8], data: &mut Vec<u8>) -> 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 _,
Expand Down
12 changes: 12 additions & 0 deletions clash_lib/src/config/def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
9 changes: 9 additions & 0 deletions clash_lib/src/proxy/transport/websocket/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<String, String>,
Expand Down Expand Up @@ -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,
Expand Down
Loading

0 comments on commit d154e54

Please sign in to comment.