Files
Easytier/easytier/src/tests/mod.rs
T
KKRainbow c4eacf4591 feat(credential): implement credential peer auth and trust propagation (#1968)
- add credential manager and RPC/CLI for generate/list/revoke
- support credential-based Noise authentication and revocation handling
- propagate trusted credential metadata through OSPF route sync
- classify direct peers by auth level in session maintenance
- normalize sender credential flag for legacy non-secure compatibility
- add unit/integration tests for credential join, relay and revocation
2026-03-07 22:58:15 +08:00

253 lines
6.8 KiB
Rust

#[cfg(target_os = "linux")]
mod three_node;
mod ipv6_test;
#[cfg(target_os = "linux")]
mod credential_tests;
use std::io::IsTerminal as _;
use crate::common::PeerId;
use crate::peers::peer_manager::PeerManager;
pub fn get_guest_veth_name(net_ns: &str) -> &str {
Box::leak(format!("veth_{}_g", net_ns).into_boxed_str())
}
pub fn get_host_veth_name(net_ns: &str) -> &str {
Box::leak(format!("veth_{}_h", net_ns).into_boxed_str())
}
pub fn del_netns(name: &str) {
// del veth host
let _ = std::process::Command::new("ip")
.args(["link", "del", get_host_veth_name(name)])
.output();
let _ = std::process::Command::new("ip")
.args(["netns", "del", name])
.output();
}
pub fn create_netns(name: &str, ipv4: &str, ipv6: &str) {
// create netns
let _ = std::process::Command::new("ip")
.args(["netns", "add", name])
.output()
.unwrap();
// set lo up
let _ = std::process::Command::new("ip")
.args(["netns", "exec", name, "ip", "link", "set", "lo", "up"])
.output()
.unwrap();
let _ = std::process::Command::new("ip")
.args([
"link",
"add",
get_host_veth_name(name),
"type",
"veth",
"peer",
"name",
get_guest_veth_name(name),
])
.output()
.unwrap();
let _ = std::process::Command::new("ip")
.args(["link", "set", get_guest_veth_name(name), "netns", name])
.output()
.unwrap();
let _ = std::process::Command::new("ip")
.args([
"netns",
"exec",
name,
"ip",
"link",
"set",
get_guest_veth_name(name),
"up",
])
.output()
.unwrap();
let _ = std::process::Command::new("ip")
.args(["link", "set", get_host_veth_name(name), "up"])
.output()
.unwrap();
for ip in [ipv4, ipv6] {
let _ = std::process::Command::new("ip")
.args([
"netns",
"exec",
name,
"ip",
"addr",
"add",
ip,
"dev",
get_guest_veth_name(name),
])
.output()
.unwrap();
}
}
pub fn prepare_bridge(name: &str) {
// del bridge with brctl
let _ = std::process::Command::new("brctl")
.args(["delbr", name])
.output();
// create new br
let _ = std::process::Command::new("brctl")
.args(["addbr", name])
.output();
}
pub fn add_ns_to_bridge(br_name: &str, ns_name: &str) {
// use brctl to add ns to bridge
let _ = std::process::Command::new("brctl")
.args(["addif", br_name, get_host_veth_name(ns_name)])
.output()
.unwrap();
// set bridge up
let _ = std::process::Command::new("ip")
.args(["link", "set", br_name, "up"])
.output()
.unwrap();
}
pub fn enable_log() {
let filter = tracing_subscriber::EnvFilter::builder()
.with_default_directive(tracing::level_filters::LevelFilter::TRACE.into())
.from_env()
.unwrap()
.add_directive("tarpc=error".parse().unwrap());
let use_ansi = std::io::stderr().is_terminal();
tracing_subscriber::fmt::fmt()
.pretty()
.with_ansi(use_ansi)
.with_env_filter(filter)
.with_writer(std::io::stderr)
.init();
}
fn check_route(ipv4: &str, dst_peer_id: PeerId, routes: Vec<crate::proto::api::instance::Route>) {
let mut found = false;
for r in routes.iter() {
if r.ipv4_addr == Some(ipv4.parse().unwrap()) {
found = true;
assert_eq!(r.peer_id, dst_peer_id, "{:?}", routes);
}
}
assert!(
found,
"routes: {:?}, dst_peer_id: {}, ipv4: {}",
routes, dst_peer_id, ipv4
);
}
fn check_route_ex(
routes: Vec<crate::proto::api::instance::Route>,
peer_id: PeerId,
checker: impl Fn(&crate::proto::api::instance::Route) -> bool,
) {
let mut found = false;
for r in routes.iter() {
if r.peer_id == peer_id {
found = true;
assert!(checker(r), "{:?}", routes);
}
}
assert!(found, "routes: {:?}, dst_peer_id: {}", routes, peer_id);
}
async fn wait_proxy_route_appear(
mgr: &std::sync::Arc<PeerManager>,
ipv4: &str,
dst_peer_id: PeerId,
proxy_cidr: &str,
) {
let now = std::time::Instant::now();
loop {
for r in mgr.list_routes().await.iter() {
if r.proxy_cidrs.contains(&proxy_cidr.to_owned()) {
assert_eq!(r.peer_id, dst_peer_id);
assert_eq!(r.ipv4_addr, Some(ipv4.parse().unwrap()));
return;
}
}
if now.elapsed().as_secs() > 5 {
panic!("wait proxy route appear timeout");
}
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
}
}
fn set_link_status(net_ns: &str, up: bool) {
let ret = std::process::Command::new("ip")
.args([
"netns",
"exec",
net_ns,
"ip",
"link",
"set",
get_guest_veth_name(net_ns),
if up { "up" } else { "down" },
])
.output()
.unwrap();
tracing::info!("set link status: {:?}, net_ns: {}, up: {}", ret, net_ns, up);
}
pub async fn drop_insts(insts: Vec<crate::instance::instance::Instance>) {
let mut set = tokio::task::JoinSet::new();
for mut inst in insts {
set.spawn(async move {
inst.clear_resources().await;
let pm = std::sync::Arc::downgrade(&inst.get_peer_manager());
drop(inst);
let now = std::time::Instant::now();
while now.elapsed().as_secs() < 5 && pm.strong_count() > 0 {
tokio::time::sleep(std::time::Duration::from_millis(50)).await;
}
assert_eq!(pm.strong_count(), 0, "PeerManager should be dropped");
});
}
while set.join_next().await.is_some() {}
}
pub async fn ping_test(from_netns: &str, target_ip: &str, payload_size: Option<usize>) -> bool {
use crate::common::netns::{NetNS, ROOT_NETNS_NAME};
let _g = NetNS::new(Some(ROOT_NETNS_NAME.to_owned())).guard();
let code = tokio::process::Command::new("ip")
.args([
"netns",
"exec",
from_netns,
"ping",
"-c",
"1",
"-s",
payload_size.unwrap_or(56).to_string().as_str(),
"-W",
"1",
target_ip.to_string().as_str(),
])
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.status()
.await
.unwrap();
code.code().unwrap() == 0
}