mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-05-07 10:14:35 +00:00
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:
@@ -1,5 +1,7 @@
|
||||
use std::{
|
||||
collections::{BTreeMap, BTreeSet},
|
||||
collections::{
|
||||
HashMap, {BTreeMap, BTreeSet},
|
||||
},
|
||||
fmt::Debug,
|
||||
net::{Ipv4Addr, Ipv6Addr},
|
||||
sync::{
|
||||
@@ -33,6 +35,7 @@ use crate::{
|
||||
},
|
||||
peers::route_trait::{Route, RouteInterfaceBox},
|
||||
proto::{
|
||||
acl::GroupIdentity,
|
||||
common::{Ipv4Inet, NatType, StunInfo},
|
||||
peer_rpc::{
|
||||
route_foreign_network_infos, route_foreign_network_summary,
|
||||
@@ -127,6 +130,7 @@ impl RoutePeerInfo {
|
||||
network_length: 24,
|
||||
quic_port: None,
|
||||
ipv6_addr: None,
|
||||
groups: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,6 +172,8 @@ impl RoutePeerInfo {
|
||||
|
||||
quic_port: global_ctx.get_quic_proxy_port().map(|x| x as u32),
|
||||
ipv6_addr: global_ctx.get_ipv6().map(|x| x.into()),
|
||||
|
||||
groups: global_ctx.get_acl_groups(my_peer_id),
|
||||
};
|
||||
|
||||
let need_update_periodically = if let Ok(Ok(d)) =
|
||||
@@ -296,6 +302,8 @@ struct SyncedRouteInfo {
|
||||
raw_peer_infos: DashMap<PeerId, DynamicMessage>,
|
||||
conn_map: DashMap<PeerId, (BTreeSet<PeerId>, AtomicVersion)>,
|
||||
foreign_network: DashMap<ForeignNetworkRouteInfoKey, ForeignNetworkRouteInfoEntry>,
|
||||
group_trust_map: DashMap<PeerId, HashMap<String, Vec<u8>>>,
|
||||
group_trust_map_cache: DashMap<PeerId, Arc<Vec<String>>>, // cache for group trust map, should sync with group_trust_map
|
||||
|
||||
version: AtomicVersion,
|
||||
}
|
||||
@@ -306,6 +314,7 @@ impl Debug for SyncedRouteInfo {
|
||||
.field("peer_infos", &self.peer_infos)
|
||||
.field("conn_map", &self.conn_map)
|
||||
.field("foreign_network", &self.foreign_network)
|
||||
.field("group_trust_map", &self.group_trust_map)
|
||||
.field("version", &self.version.get())
|
||||
.finish()
|
||||
}
|
||||
@@ -324,6 +333,8 @@ impl SyncedRouteInfo {
|
||||
self.raw_peer_infos.remove(&peer_id);
|
||||
self.conn_map.remove(&peer_id);
|
||||
self.foreign_network.retain(|k, _| k.peer_id != peer_id);
|
||||
self.group_trust_map.remove(&peer_id);
|
||||
self.group_trust_map_cache.remove(&peer_id);
|
||||
self.version.inc();
|
||||
}
|
||||
|
||||
@@ -613,6 +624,85 @@ impl SyncedRouteInfo {
|
||||
self.is_peer_bidirectly_connected(src_peer_id, dst_peer_id)
|
||||
|| self.is_peer_bidirectly_connected(dst_peer_id, src_peer_id)
|
||||
}
|
||||
|
||||
fn verify_and_update_group_trusts(
|
||||
&self,
|
||||
peer_infos: &[RoutePeerInfo],
|
||||
local_group_declarations: &[GroupIdentity],
|
||||
) {
|
||||
let local_group_declarations = local_group_declarations
|
||||
.iter()
|
||||
.map(|g| (g.group_name.as_str(), g.group_secret.as_str()))
|
||||
.collect::<std::collections::HashMap<&str, &str>>();
|
||||
|
||||
let verify_groups = |old_trusted_groups: Option<&HashMap<String, Vec<u8>>>,
|
||||
info: &RoutePeerInfo|
|
||||
-> HashMap<String, Vec<u8>> {
|
||||
let mut trusted_groups_for_peer: HashMap<String, Vec<u8>> = HashMap::new();
|
||||
|
||||
for group_proof in &info.groups {
|
||||
let name = &group_proof.group_name;
|
||||
let proof_bytes = group_proof.group_proof.clone();
|
||||
|
||||
// If we already trusted this group and the proof hasn't changed, reuse it.
|
||||
if old_trusted_groups
|
||||
.and_then(|g| g.get(name))
|
||||
.map(|old| old == &proof_bytes)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
trusted_groups_for_peer.insert(name.clone(), proof_bytes);
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(&local_secret) =
|
||||
local_group_declarations.get(group_proof.group_name.as_str())
|
||||
{
|
||||
if group_proof.verify(local_secret, info.peer_id) {
|
||||
trusted_groups_for_peer.insert(name.clone(), proof_bytes);
|
||||
} else {
|
||||
tracing::warn!(
|
||||
peer_id = info.peer_id,
|
||||
group = %group_proof.group_name,
|
||||
"Group proof verification failed"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trusted_groups_for_peer
|
||||
};
|
||||
|
||||
for info in peer_infos {
|
||||
match self.group_trust_map.entry(info.peer_id) {
|
||||
dashmap::mapref::entry::Entry::Occupied(mut entry) => {
|
||||
let old_trusted_groups = entry.get().clone();
|
||||
let trusted_groups_for_peer = verify_groups(Some(&old_trusted_groups), info);
|
||||
|
||||
if trusted_groups_for_peer.is_empty() {
|
||||
entry.remove();
|
||||
self.group_trust_map_cache.remove(&info.peer_id);
|
||||
} else {
|
||||
self.group_trust_map_cache.insert(
|
||||
info.peer_id,
|
||||
Arc::new(trusted_groups_for_peer.keys().cloned().collect()),
|
||||
);
|
||||
*entry.get_mut() = trusted_groups_for_peer;
|
||||
}
|
||||
}
|
||||
dashmap::mapref::entry::Entry::Vacant(entry) => {
|
||||
let trusted_groups_for_peer = verify_groups(None, info);
|
||||
|
||||
if !trusted_groups_for_peer.is_empty() {
|
||||
self.group_trust_map_cache.insert(
|
||||
info.peer_id,
|
||||
Arc::new(trusted_groups_for_peer.keys().cloned().collect()),
|
||||
);
|
||||
entry.insert(trusted_groups_for_peer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type PeerGraph = Graph<PeerId, usize, Directed>;
|
||||
@@ -1154,6 +1244,8 @@ impl PeerRouteServiceImpl {
|
||||
raw_peer_infos: DashMap::new(),
|
||||
conn_map: DashMap::new(),
|
||||
foreign_network: DashMap::new(),
|
||||
group_trust_map: DashMap::new(),
|
||||
group_trust_map_cache: DashMap::new(),
|
||||
version: AtomicVersion::new(),
|
||||
},
|
||||
cached_local_conn_map: std::sync::Mutex::new(RouteConnBitmap::new()),
|
||||
@@ -1679,6 +1771,14 @@ impl PeerRouteServiceImpl {
|
||||
fn get_peer_info_last_update(&self) -> std::time::Instant {
|
||||
self.peer_info_last_update.load()
|
||||
}
|
||||
|
||||
fn get_peer_groups(&self, peer_id: PeerId) -> Arc<Vec<String>> {
|
||||
self.synced_route_info
|
||||
.group_trust_map_cache
|
||||
.get(&peer_id)
|
||||
.map(|groups| groups.value().clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for PeerRouteServiceImpl {
|
||||
@@ -2016,6 +2116,12 @@ impl RouteSessionManager {
|
||||
peer_infos,
|
||||
raw_peer_infos.as_ref().unwrap(),
|
||||
)?;
|
||||
service_impl
|
||||
.synced_route_info
|
||||
.verify_and_update_group_trusts(
|
||||
peer_infos,
|
||||
&service_impl.global_ctx.get_acl_group_declarations(),
|
||||
);
|
||||
session.update_dst_saved_peer_info_version(peer_infos);
|
||||
need_update_route_table = true;
|
||||
}
|
||||
@@ -2364,6 +2470,10 @@ impl Route for PeerRoute {
|
||||
async fn get_peer_info_last_update_time(&self) -> Instant {
|
||||
self.service_impl.get_peer_info_last_update()
|
||||
}
|
||||
|
||||
fn get_peer_groups(&self, peer_id: PeerId) -> Arc<Vec<String>> {
|
||||
self.service_impl.get_peer_groups(peer_id)
|
||||
}
|
||||
}
|
||||
|
||||
impl PeerPacketFilter for Arc<PeerRoute> {}
|
||||
|
||||
Reference in New Issue
Block a user