feat(acl): add group-based ACL rules and related structures (#1265)

* feat(acl): add group-based ACL rules and related structures

* refactor(acl): optimize group handling with Arc and improve cache management

* refactor(acl): clippy

* feat(tests): add performance tests for generate_with_proof and verify methods

* feat: update group_trust_map to use HashMap for more secure group proofs

* refactor: refactor the logic of the trusted group getting and setting

* feat(acl): support kcp/quic use group acl

* feat(proxy): optimize group retrieval by IP in Kcp and Quic proxy handlers

* feat(tests): add group-based ACL tree node test

* always allow quic proxy traffic

---------

Co-authored-by: Sijie.Sun <sunsijie@buaa.edu.cn>
Co-authored-by: sijie.sun <sijie.sun@smartx.com>
This commit is contained in:
Mg Pig
2025-08-22 22:25:00 +08:00
committed by GitHub
parent 34560af141
commit 08a92a53c3
18 changed files with 1042 additions and 29 deletions

View File

@@ -440,12 +440,13 @@ impl KcpProxyDst {
}
}
#[tracing::instrument(ret)]
#[tracing::instrument(ret, skip(route))]
async fn handle_one_in_stream(
kcp_stream: KcpStream,
global_ctx: ArcGlobalCtx,
proxy_entries: Arc<DashMap<ConnId, TcpProxyEntry>>,
cidr_set: Arc<CidrSet>,
route: Arc<(dyn crate::peers::route_trait::Route + Send + Sync + 'static)>,
) -> Result<()> {
let mut conn_data = kcp_stream.conn_data().clone();
let parsed_conn_data = KcpConnData::decode(&mut conn_data)
@@ -481,6 +482,13 @@ impl KcpProxyDst {
proxy_entries.remove(&conn_id);
}
let src_ip = src_socket.ip();
let dst_ip = dst_socket.ip();
let (src_groups, dst_groups) = tokio::join!(
route.get_peer_groups_by_ip(&src_ip),
route.get_peer_groups_by_ip(&dst_ip)
);
let send_to_self =
Some(dst_socket.ip()) == global_ctx.get_ipv4().map(|ip| IpAddr::V4(ip.address()));
@@ -491,12 +499,14 @@ impl KcpProxyDst {
let acl_handler = ProxyAclHandler {
acl_filter: global_ctx.get_acl_filter().clone(),
packet_info: PacketInfo {
src_ip: src_socket.ip(),
dst_ip: dst_socket.ip(),
src_ip,
dst_ip,
src_port: Some(src_socket.port()),
dst_port: Some(dst_socket.port()),
protocol: Protocol::Tcp,
packet_size: conn_data.len(),
src_groups,
dst_groups,
},
chain_type: if send_to_self {
ChainType::Inbound
@@ -530,6 +540,7 @@ impl KcpProxyDst {
let global_ctx = self.peer_manager.get_global_ctx().clone();
let proxy_entries = self.proxy_entries.clone();
let cidr_set = self.cidr_set.clone();
let route = Arc::new(self.peer_manager.get_route());
self.tasks.spawn(async move {
while let Ok(conn) = kcp_endpoint.accept().await {
let stream = KcpStream::new(&kcp_endpoint, conn)
@@ -539,9 +550,16 @@ impl KcpProxyDst {
let global_ctx = global_ctx.clone();
let proxy_entries = proxy_entries.clone();
let cidr_set = cidr_set.clone();
let route = route.clone();
tokio::spawn(async move {
let _ = Self::handle_one_in_stream(stream, global_ctx, proxy_entries, cidr_set)
.await;
let _ = Self::handle_one_in_stream(
stream,
global_ctx,
proxy_entries,
cidr_set,
route,
)
.await;
});
}
});

View File

@@ -247,10 +247,14 @@ pub struct QUICProxyDst {
endpoint: Arc<quinn::Endpoint>,
proxy_entries: Arc<DashMap<SocketAddr, TcpProxyEntry>>,
tasks: Arc<Mutex<JoinSet<()>>>,
route: Arc<(dyn crate::peers::route_trait::Route + Send + Sync + 'static)>,
}
impl QUICProxyDst {
pub fn new(global_ctx: ArcGlobalCtx) -> Result<Self> {
pub fn new(
global_ctx: ArcGlobalCtx,
route: Arc<(dyn crate::peers::route_trait::Route + Send + Sync + 'static)>,
) -> Result<Self> {
let _g = global_ctx.net_ns.guard();
let (endpoint, _) = make_server_endpoint("0.0.0.0:0".parse().unwrap())
.map_err(|e| anyhow::anyhow!("failed to create QUIC endpoint: {}", e))?;
@@ -261,6 +265,7 @@ impl QUICProxyDst {
endpoint: Arc::new(endpoint),
proxy_entries: Arc::new(DashMap::new()),
tasks,
route,
})
}
@@ -270,6 +275,7 @@ impl QUICProxyDst {
let ctx = self.global_ctx.clone();
let cidr_set = Arc::new(CidrSet::new(ctx.clone()));
let proxy_entries = self.proxy_entries.clone();
let route = self.route.clone();
let task = async move {
loop {
@@ -289,6 +295,7 @@ impl QUICProxyDst {
ctx.clone(),
cidr_set.clone(),
proxy_entries.clone(),
route.clone(),
));
}
None => {
@@ -312,6 +319,7 @@ impl QUICProxyDst {
ctx: Arc<GlobalCtx>,
cidr_set: Arc<CidrSet>,
proxy_entries: Arc<DashMap<SocketAddr, TcpProxyEntry>>,
route: Arc<(dyn crate::peers::route_trait::Route + Send + Sync + 'static)>,
) {
let remote_addr = conn.remote_address();
defer!(
@@ -319,7 +327,14 @@ impl QUICProxyDst {
);
let ret = timeout(
std::time::Duration::from_secs(10),
Self::handle_connection(conn, ctx, cidr_set, remote_addr, proxy_entries.clone()),
Self::handle_connection(
conn,
ctx,
cidr_set,
remote_addr,
proxy_entries.clone(),
route,
),
)
.await;
@@ -348,6 +363,7 @@ impl QUICProxyDst {
cidr_set: Arc<CidrSet>,
proxy_entry_key: SocketAddr,
proxy_entries: Arc<DashMap<SocketAddr, TcpProxyEntry>>,
route: Arc<(dyn crate::peers::route_trait::Route + Send + Sync + 'static)>,
) -> Result<(QUICStream, TcpStream, ProxyAclHandler)> {
let conn = incoming.await.with_context(|| "accept failed")?;
let addr = conn.remote_address();
@@ -379,6 +395,13 @@ impl QUICProxyDst {
dst_socket.set_ip(real_ip);
}
let src_ip = addr.ip();
let dst_ip = *dst_socket.ip();
let (src_groups, dst_groups) = tokio::join!(
route.get_peer_groups_by_ip(&src_ip),
route.get_peer_groups_by_ipv4(&dst_ip)
);
let send_to_self = Some(*dst_socket.ip()) == ctx.get_ipv4().map(|ip| ip.address());
if send_to_self && ctx.no_tun() {
dst_socket = format!("127.0.0.1:{}", dst_socket.port()).parse().unwrap();
@@ -398,12 +421,14 @@ impl QUICProxyDst {
let acl_handler = ProxyAclHandler {
acl_filter: ctx.get_acl_filter().clone(),
packet_info: PacketInfo {
src_ip: addr.ip(),
dst_ip: (*dst_socket.ip()).into(),
src_ip,
dst_ip: dst_ip.into(),
src_port: Some(addr.port()),
dst_port: Some(dst_socket.port()),
protocol: Protocol::Tcp,
packet_size: len as usize,
src_groups,
dst_groups,
},
chain_type: if send_to_self {
ChainType::Inbound