Relax private mode foreign network secret checks (#2022)

This commit is contained in:
KKRainbow
2026-03-28 22:19:23 +08:00
committed by GitHub
parent b5f475cd4c
commit b037ea9c3f
5 changed files with 323 additions and 18 deletions
+226
View File
@@ -13,6 +13,7 @@ use crate::{
stats_manager::{LabelSet, LabelType, MetricName},
PeerId,
},
proto::api::instance::TrustedKeySourcePb,
tunnel::{
common::tests::wait_for_condition,
packet_def::{PacketType, ZCPacket},
@@ -63,6 +64,92 @@ pub async fn create_mock_peer_manager_secure(
peer_mgr
}
fn set_private_mode(peer_mgr: &PeerManager, enabled: bool) {
let global_ctx = peer_mgr.get_global_ctx();
let mut flags = global_ctx.get_flags();
flags.private_mode = enabled;
global_ctx.set_flags(flags);
}
async fn connect_client_and_server(
client: Arc<PeerManager>,
server: Arc<PeerManager>,
) -> (Result<(), Error>, Result<(), Error>) {
let (client_ring, server_ring) = create_ring_tunnel_pair();
tokio::join!(
{
let client = client.clone();
async move {
client.add_client_tunnel(client_ring, false).await?;
Ok(())
}
},
{
let server = server.clone();
async move { server.add_tunnel_as_server(server_ring, true).await }
}
)
}
async fn wait_for_foreign_network(server: Arc<PeerManager>, network_name: &'static str) {
wait_for_condition(
|| {
let server = server.clone();
async move {
server
.get_foreign_network_manager()
.list_foreign_networks()
.await
.foreign_networks
.contains_key(network_name)
}
},
Duration::from_secs(10),
)
.await;
}
async fn wait_for_foreign_network_peer_count_at_least(
server: Arc<PeerManager>,
network_name: &'static str,
min_peer_count: usize,
) {
wait_for_condition(
|| {
let server = server.clone();
async move {
server
.get_foreign_network_manager()
.list_foreign_networks()
.await
.foreign_networks
.get(network_name)
.map(|entry| entry.peers.len() >= min_peer_count)
.unwrap_or(false)
}
},
Duration::from_secs(10),
)
.await;
}
async fn wait_for_public_peers_empty(client: Arc<PeerManager>) {
wait_for_condition(
|| {
let client = client.clone();
async move {
client
.get_foreign_network_client()
.list_public_peers()
.await
.is_empty()
}
},
Duration::from_secs(5),
)
.await;
}
pub async fn connect_peer_manager(client: Arc<PeerManager>, server: Arc<PeerManager>) {
let (a_ring, b_ring) = create_ring_tunnel_pair();
let a_mgr_copy = client;
@@ -205,6 +292,145 @@ async fn relay_peer_map_secure_session_decrypt() {
assert_eq!(packet.payload(), b"relay-hello");
}
#[tokio::test]
async fn private_mode_allows_foreign_network_with_same_secret() {
let server = create_mock_peer_manager_secure("public".to_string(), "shared".to_string()).await;
let client =
create_mock_peer_manager_secure("tenant-a".to_string(), "shared".to_string()).await;
set_private_mode(&server, true);
let (client_ret, server_ret) = connect_client_and_server(client, server.clone()).await;
assert!(client_ret.is_ok(), "client should connect in private mode");
assert!(
server_ret.is_ok(),
"server should accept foreign network with matching secret: {:?}",
server_ret
);
wait_for_foreign_network(server, "tenant-a").await;
}
#[tokio::test]
async fn private_mode_rejects_foreign_network_with_different_secret() {
let server = create_mock_peer_manager_secure("public".to_string(), "shared".to_string()).await;
let client = create_mock_peer_manager_secure("tenant-a".to_string(), "other".to_string()).await;
set_private_mode(&server, true);
let (client_ret, server_ret) = connect_client_and_server(client.clone(), server.clone()).await;
assert!(
server_ret.is_err(),
"server should reject foreign network with mismatched secret in private mode"
);
let _ = client_ret;
wait_for_public_peers_empty(client).await;
assert!(server
.get_foreign_network_manager()
.list_foreign_networks()
.await
.foreign_networks
.is_empty());
}
#[tokio::test]
async fn private_mode_allows_trusted_foreign_credential() {
let server = create_mock_peer_manager_secure("public".to_string(), "shared".to_string()).await;
let admin = create_mock_peer_manager_secure("tenant-a".to_string(), "shared".to_string()).await;
set_private_mode(&server, true);
let (_cred_id, cred_secret) = admin
.get_global_ctx()
.get_credential_manager()
.generate_credential(vec![], false, vec![], Duration::from_secs(3600));
let privkey_bytes: [u8; 32] = base64::engine::general_purpose::STANDARD
.decode(&cred_secret)
.unwrap()
.try_into()
.unwrap();
let private = x25519_dalek::StaticSecret::from(privkey_bytes);
let public = x25519_dalek::PublicKey::from(&private);
let credential = create_mock_peer_manager_credential("tenant-a".to_string(), &private).await;
connect_peer_manager(admin.clone(), server.clone()).await;
wait_for_condition(
|| {
let server = server.clone();
let pubkey = public.as_bytes().to_vec();
async move {
server
.get_foreign_network_manager()
.list_foreign_networks_with_options(true)
.await
.foreign_networks
.get("tenant-a")
.map(|entry| {
entry.trusted_keys.iter().any(|trusted_key| {
trusted_key.pubkey == pubkey
&& trusted_key.source == TrustedKeySourcePb::OspfCredential as i32
})
})
.unwrap_or(false)
}
},
Duration::from_secs(10),
)
.await;
let (client_ret, server_ret) = connect_client_and_server(credential, server.clone()).await;
assert!(
client_ret.is_ok(),
"trusted foreign credential client should connect in private mode"
);
assert!(
server_ret.is_ok(),
"server should allow trusted foreign credential in private mode: {:?}",
server_ret
);
wait_for_foreign_network_peer_count_at_least(server, "tenant-a", 2).await;
}
#[tokio::test]
async fn private_mode_rejects_untrusted_foreign_credential() {
let server = create_mock_peer_manager_secure("public".to_string(), "shared".to_string()).await;
let admin = create_mock_peer_manager_secure("tenant-a".to_string(), "shared".to_string()).await;
set_private_mode(&server, true);
let random_private = x25519_dalek::StaticSecret::random_from_rng(rand::rngs::OsRng);
let unknown_credential =
create_mock_peer_manager_credential("tenant-a".to_string(), &random_private).await;
connect_peer_manager(admin.clone(), server.clone()).await;
wait_for_foreign_network(server.clone(), "tenant-a").await;
let (client_ret, server_ret) =
connect_client_and_server(unknown_credential, server.clone()).await;
let _ = client_ret;
assert!(
server_ret.is_err(),
"server should reject untrusted foreign credential in private mode"
);
wait_for_condition(
|| {
let server = server.clone();
async move {
server
.get_foreign_network_manager()
.list_foreign_networks()
.await
.foreign_networks
.get("tenant-a")
.map(|entry| entry.peers.len() == 1)
.unwrap_or(false)
}
},
Duration::from_secs(10),
)
.await;
}
#[tokio::test]
async fn relay_peer_map_retry_backoff_and_evict() {
let (s, _r) = create_packet_recv_chan();