mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-09-03 01:25:37 +00:00
feat(credential): enforce signed credential distribution across mixed admin/shared topology (#1972)
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
use std::{sync::Arc, time::Instant};
|
||||
|
||||
use dashmap::DashMap;
|
||||
use hmac::Mac;
|
||||
use prost::Message;
|
||||
use snow::params::NoiseParams;
|
||||
use tokio::sync::{oneshot, Mutex, OwnedMutexGuard};
|
||||
use tokio::time::{timeout, Duration};
|
||||
|
||||
use crate::peers::foreign_network_client::ForeignNetworkClient;
|
||||
use crate::{
|
||||
common::error::Error,
|
||||
common::{global_ctx::ArcGlobalCtx, PeerId},
|
||||
@@ -43,6 +43,7 @@ impl Default for RelayPeerState {
|
||||
|
||||
pub struct RelayPeerMap {
|
||||
peer_map: Arc<PeerMap>,
|
||||
foreign_network_client: Option<Arc<ForeignNetworkClient>>,
|
||||
global_ctx: ArcGlobalCtx,
|
||||
my_peer_id: PeerId,
|
||||
peer_session_store: Arc<PeerSessionStore>,
|
||||
@@ -50,17 +51,26 @@ pub struct RelayPeerMap {
|
||||
pending_handshakes: DashMap<PeerId, oneshot::Sender<ZCPacket>>,
|
||||
handshake_locks: DashMap<PeerId, Arc<Mutex<()>>>,
|
||||
pub(crate) pending_packets: DashMap<PeerId, Vec<(ZCPacket, NextHopPolicy)>>,
|
||||
|
||||
is_secure_mode_enabled: bool,
|
||||
}
|
||||
|
||||
impl RelayPeerMap {
|
||||
pub fn new(
|
||||
peer_map: Arc<PeerMap>,
|
||||
foreign_network_client: Option<Arc<ForeignNetworkClient>>,
|
||||
global_ctx: ArcGlobalCtx,
|
||||
my_peer_id: PeerId,
|
||||
peer_session_store: Arc<PeerSessionStore>,
|
||||
) -> Arc<Self> {
|
||||
let is_secure_mode_enabled = global_ctx
|
||||
.config
|
||||
.get_secure_mode()
|
||||
.map(|cfg| cfg.enabled)
|
||||
.unwrap_or(false);
|
||||
Arc::new(Self {
|
||||
peer_map,
|
||||
foreign_network_client,
|
||||
global_ctx,
|
||||
my_peer_id,
|
||||
peer_session_store,
|
||||
@@ -68,15 +78,12 @@ impl RelayPeerMap {
|
||||
pending_handshakes: DashMap::new(),
|
||||
handshake_locks: DashMap::new(),
|
||||
pending_packets: DashMap::new(),
|
||||
is_secure_mode_enabled,
|
||||
})
|
||||
}
|
||||
|
||||
fn is_secure_mode_enabled(&self) -> bool {
|
||||
self.global_ctx
|
||||
.config
|
||||
.get_secure_mode()
|
||||
.map(|cfg| cfg.enabled)
|
||||
.unwrap_or(false)
|
||||
pub fn is_secure_mode_enabled(&self) -> bool {
|
||||
self.is_secure_mode_enabled
|
||||
}
|
||||
|
||||
fn get_local_keypair(&self) -> Result<(Vec<u8>, Vec<u8>), Error> {
|
||||
@@ -134,12 +141,19 @@ impl RelayPeerMap {
|
||||
policy: NextHopPolicy,
|
||||
) -> Result<(), Error> {
|
||||
let Some(next_hop) = self.peer_map.get_gateway_peer_id(dst_peer_id, policy).await else {
|
||||
return Err(Error::RouteError(None));
|
||||
return Err(Error::RouteError(Some(format!(
|
||||
"next hop not found in route for peer {dst_peer_id:?}"
|
||||
))));
|
||||
};
|
||||
if !self.peer_map.has_peer(next_hop) {
|
||||
return Err(Error::RouteError(None));
|
||||
if self.peer_map.has_peer(next_hop) {
|
||||
self.peer_map.send_msg_directly(msg, next_hop).await
|
||||
} else if let Some(foreign_network_client) = &self.foreign_network_client {
|
||||
foreign_network_client.send_msg(msg, next_hop).await
|
||||
} else {
|
||||
Err(Error::RouteError(Some(format!(
|
||||
"next hop not found in direct peer map: {next_hop:?}"
|
||||
))))
|
||||
}
|
||||
self.peer_map.send_msg_directly(msg, next_hop).await
|
||||
}
|
||||
|
||||
pub async fn send_msg(
|
||||
@@ -321,7 +335,6 @@ impl RelayPeerMap {
|
||||
let a_conn_id = uuid::Uuid::new_v4();
|
||||
let msg1_pb = RelayNoiseMsg1Pb {
|
||||
version: RELAY_NOISE_VERSION,
|
||||
a_network_name: network.network_name.clone(),
|
||||
a_session_generation,
|
||||
a_conn_id: Some(a_conn_id.into()),
|
||||
client_encryption_algorithm: self.global_ctx.get_flags().encryption_algorithm.clone(),
|
||||
@@ -331,7 +344,6 @@ impl RelayPeerMap {
|
||||
let out_len = hs
|
||||
.write_message(&payload, &mut out)
|
||||
.map_err(|e| Error::RouteError(Some(format!("noise write msg1 failed: {e:?}"))))?;
|
||||
let server_handshake_hash = hs.get_handshake_hash().to_vec();
|
||||
let (tx, rx) = oneshot::channel();
|
||||
self.pending_handshakes.insert(dst_peer_id, tx);
|
||||
|
||||
@@ -374,27 +386,6 @@ impl RelayPeerMap {
|
||||
"relay msg2 conn_id_echo mismatch".to_string(),
|
||||
)));
|
||||
}
|
||||
if msg2_pb.b_network_name == network.network_name {
|
||||
if msg2_pb.role_hint != 1 {
|
||||
return Err(Error::RouteError(Some(
|
||||
"role_hint must be 1 when network_name is same".to_string(),
|
||||
)));
|
||||
}
|
||||
let Some(secret_proof_32) = msg2_pb.secret_proof_32 else {
|
||||
return Err(Error::RouteError(Some(
|
||||
"secret_proof_32 must be present when role_hint is 1".to_string(),
|
||||
)));
|
||||
};
|
||||
let verify_result = self
|
||||
.global_ctx
|
||||
.get_secret_proof(&server_handshake_hash)
|
||||
.map(|mac| mac.verify_slice(&secret_proof_32).is_ok());
|
||||
if verify_result != Some(true) {
|
||||
return Err(Error::RouteError(Some(
|
||||
"secret_proof_32 verify failed".to_string(),
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
let action = PeerConnSessionActionPb::try_from(msg2_pb.action)
|
||||
.map_err(|_| Error::RouteError(Some("invalid session action".to_string())))?;
|
||||
@@ -539,7 +530,6 @@ impl RelayPeerMap {
|
||||
&mut hs,
|
||||
msg1,
|
||||
)?;
|
||||
let remote_network_name = msg1_pb.a_network_name.clone();
|
||||
let remote_static = hs
|
||||
.get_remote_static()
|
||||
.map(|x: &[u8]| x.to_vec())
|
||||
@@ -564,16 +554,6 @@ impl RelayPeerMap {
|
||||
}
|
||||
|
||||
let server_network_name = self.global_ctx.get_network_name();
|
||||
let (role_hint, secret_proof_32) = if remote_network_name == server_network_name {
|
||||
let proof = self
|
||||
.global_ctx
|
||||
.get_secret_proof(hs.get_handshake_hash())
|
||||
.map(|mac| mac.finalize().into_bytes().to_vec());
|
||||
(1, proof)
|
||||
} else {
|
||||
(2, None)
|
||||
};
|
||||
|
||||
let algo = self.global_ctx.get_flags().encryption_algorithm.clone();
|
||||
let key = SessionKey::new(server_network_name.clone(), remote_peer_id);
|
||||
let upsert = self
|
||||
@@ -587,8 +567,6 @@ impl RelayPeerMap {
|
||||
)
|
||||
.map_err(|e| Error::RouteError(Some(format!("{e:?}"))))?;
|
||||
let msg2_pb = RelayNoiseMsg2Pb {
|
||||
b_network_name: server_network_name,
|
||||
role_hint,
|
||||
action: match upsert.action {
|
||||
PeerSessionAction::Join => PeerConnSessionActionPb::Join as i32,
|
||||
PeerSessionAction::Sync => PeerConnSessionActionPb::Sync as i32,
|
||||
@@ -599,7 +577,6 @@ impl RelayPeerMap {
|
||||
initial_epoch: upsert.initial_epoch,
|
||||
b_conn_id: Some(uuid::Uuid::new_v4().into()),
|
||||
a_conn_id_echo: msg1_pb.a_conn_id,
|
||||
secret_proof_32,
|
||||
server_encryption_algorithm: algo,
|
||||
};
|
||||
let payload = msg2_pb.encode_to_vec();
|
||||
@@ -625,7 +602,7 @@ impl RelayPeerMap {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn decrypt_if_needed(&self, packet: &mut ZCPacket) -> Result<bool, Error> {
|
||||
pub async fn decrypt_if_needed(self: &Arc<Self>, packet: &mut ZCPacket) -> Result<bool, Error> {
|
||||
if !self.is_secure_mode_enabled() {
|
||||
return Ok(false);
|
||||
}
|
||||
@@ -636,6 +613,12 @@ impl RelayPeerMap {
|
||||
let network = self.global_ctx.get_network_identity();
|
||||
let key = SessionKey::new(network.network_name.clone(), from_peer_id);
|
||||
let Some(session) = self.peer_session_store.get(&key) else {
|
||||
tracing::debug!(
|
||||
"relay session not found for peer {}, try handshake",
|
||||
from_peer_id
|
||||
);
|
||||
self.ensure_session(from_peer_id, NextHopPolicy::LeastHop)
|
||||
.await?;
|
||||
return Ok(false);
|
||||
};
|
||||
let now = Instant::now();
|
||||
|
||||
Reference in New Issue
Block a user