Files
Easytier_lkddi/easytier/src/tests/three_node.rs

551 lines
17 KiB
Rust
Raw Normal View History

2024-03-23 22:20:19 +08:00
use std::{
sync::{atomic::AtomicU32, Arc},
time::Duration,
};
2024-03-06 23:09:15 +08:00
use tokio::{net::UdpSocket, task::JoinSet};
2023-09-23 01:53:45 +00:00
use super::*;
use crate::{
2024-03-23 00:56:27 +08:00
common::{
2024-05-03 07:55:00 +08:00
config::{ConfigLoader, NetworkIdentity, TomlConfigLoader},
2024-03-23 00:56:27 +08:00
netns::{NetNS, ROOT_NETNS_NAME},
},
instance::instance::Instance,
2024-03-23 22:20:19 +08:00
peers::tests::wait_for_condition,
2024-05-03 07:55:00 +08:00
tunnel::{ring::RingTunnelConnector, tcp::TcpTunnelConnector, udp::UdpTunnelConnector},
};
#[cfg(feature = "wireguard")]
use crate::{
common::config::VpnPortalConfig,
tunnel::wireguard::{WgConfig, WgTunnelConnector},
vpn_portal::wireguard::get_wg_config_for_portal,
2023-09-23 01:53:45 +00:00
};
pub fn prepare_linux_namespaces() {
del_netns("net_a");
del_netns("net_b");
del_netns("net_c");
del_netns("net_d");
create_netns("net_a", "10.1.1.1/24");
create_netns("net_b", "10.1.1.2/24");
create_netns("net_c", "10.1.2.3/24");
create_netns("net_d", "10.1.2.4/24");
prepare_bridge("br_a");
prepare_bridge("br_b");
add_ns_to_bridge("br_a", "net_a");
add_ns_to_bridge("br_a", "net_b");
add_ns_to_bridge("br_b", "net_c");
add_ns_to_bridge("br_b", "net_d");
}
2024-03-23 00:56:27 +08:00
pub fn get_inst_config(inst_name: &str, ns: Option<&str>, ipv4: &str) -> TomlConfigLoader {
let config = TomlConfigLoader::default();
config.set_inst_name(inst_name.to_owned());
config.set_netns(ns.map(|s| s.to_owned()));
config.set_ipv4(ipv4.parse().unwrap());
config.set_listeners(vec![
"tcp://0.0.0.0:11010".parse().unwrap(),
"udp://0.0.0.0:11010".parse().unwrap(),
"wg://0.0.0.0:11011".parse().unwrap(),
2024-05-11 22:46:23 +08:00
"ws://0.0.0.0:11011".parse().unwrap(),
"wss://0.0.0.0:11012".parse().unwrap(),
2024-03-23 00:56:27 +08:00
]);
config
2023-09-23 01:53:45 +00:00
}
pub async fn init_three_node(proto: &str) -> Vec<Instance> {
log::set_max_level(log::LevelFilter::Info);
prepare_linux_namespaces();
2024-03-23 00:56:27 +08:00
let mut inst1 = Instance::new(get_inst_config("inst1", Some("net_a"), "10.144.144.1"));
let mut inst2 = Instance::new(get_inst_config("inst2", Some("net_b"), "10.144.144.2"));
let mut inst3 = Instance::new(get_inst_config("inst3", Some("net_c"), "10.144.144.3"));
2023-09-23 01:53:45 +00:00
inst1.run().await.unwrap();
inst2.run().await.unwrap();
inst3.run().await.unwrap();
if proto == "tcp" {
inst2
.get_conn_manager()
.add_connector(TcpTunnelConnector::new(
"tcp://10.1.1.1:11010".parse().unwrap(),
));
} else if proto == "udp" {
2023-09-23 01:53:45 +00:00
inst2
.get_conn_manager()
.add_connector(UdpTunnelConnector::new(
"udp://10.1.1.1:11010".parse().unwrap(),
));
} else if proto == "wg" {
2024-05-03 07:55:00 +08:00
#[cfg(feature = "wireguard")]
inst2
.get_conn_manager()
.add_connector(WgTunnelConnector::new(
"wg://10.1.1.1:11011".parse().unwrap(),
WgConfig::new_from_network_identity(
&inst1.get_global_ctx().get_network_identity().network_name,
2024-04-27 13:44:59 +08:00
&inst1
.get_global_ctx()
.get_network_identity()
.network_secret
.unwrap_or_default(),
),
));
2024-05-11 22:46:23 +08:00
} else if proto == "ws" {
#[cfg(feature = "websocket")]
inst2
.get_conn_manager()
.add_connector(crate::tunnel::websocket::WSTunnelConnector::new(
"ws://10.1.1.1:11011".parse().unwrap(),
));
} else if proto == "wss" {
#[cfg(feature = "websocket")]
inst2
.get_conn_manager()
.add_connector(crate::tunnel::websocket::WSTunnelConnector::new(
"wss://10.1.1.1:11012".parse().unwrap(),
));
2023-09-23 01:53:45 +00:00
}
inst2
.get_conn_manager()
.add_connector(RingTunnelConnector::new(
format!("ring://{}", inst3.id()).parse().unwrap(),
));
// wait inst2 have two route.
2024-05-11 22:46:23 +08:00
wait_for_condition(
|| async { inst2.get_peer_manager().list_routes().await.len() == 2 },
Duration::from_secs(5000),
)
.await;
wait_for_condition(
|| async { inst1.get_peer_manager().list_routes().await.len() == 2 },
Duration::from_secs(5000),
)
.await;
2023-09-23 01:53:45 +00:00
vec![inst1, inst2, inst3]
}
async fn ping_test(from_netns: &str, target_ip: &str) -> bool {
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",
"-W",
"1",
target_ip.to_string().as_str(),
])
.status()
.await
.unwrap();
code.code().unwrap() == 0
}
#[rstest::rstest]
2023-09-23 01:53:45 +00:00
#[tokio::test]
#[serial_test::serial]
2024-05-11 22:46:23 +08:00
pub async fn basic_three_node_test(#[values("tcp", "udp", "wg", "ws", "wss")] proto: &str) {
let insts = init_three_node(proto).await;
2023-09-23 01:53:45 +00:00
check_route(
"10.144.144.2",
2024-03-13 00:15:22 +08:00
insts[1].peer_id(),
2023-09-23 01:53:45 +00:00
insts[0].get_peer_manager().list_routes().await,
);
check_route(
"10.144.144.3",
2024-03-13 00:15:22 +08:00
insts[2].peer_id(),
2023-09-23 01:53:45 +00:00
insts[0].get_peer_manager().list_routes().await,
);
wait_for_condition(
|| async { ping_test("net_c", "10.144.144.1").await },
2024-04-25 23:25:37 +08:00
Duration::from_secs(5000),
)
.await;
2023-09-23 01:53:45 +00:00
}
#[rstest::rstest]
2023-09-23 01:53:45 +00:00
#[tokio::test]
#[serial_test::serial]
pub async fn tcp_proxy_three_node_test(#[values("tcp", "udp", "wg")] proto: &str) {
use crate::tunnel::{common::tests::_tunnel_pingpong_netns, tcp::TcpTunnelListener};
2024-05-13 20:34:43 +08:00
let mut insts = init_three_node(proto).await;
2023-09-23 01:53:45 +00:00
insts[2]
.get_global_ctx()
.add_proxy_cidr("10.1.2.0/24".parse().unwrap())
.unwrap();
2024-05-13 20:34:43 +08:00
insts[2].run_ip_proxy().await.unwrap();
2023-09-23 01:53:45 +00:00
assert_eq!(insts[2].get_global_ctx().get_proxy_cidrs().len(), 1);
wait_proxy_route_appear(
&insts[0].get_peer_manager(),
"10.144.144.3",
2024-03-13 00:15:22 +08:00
insts[2].peer_id(),
2023-09-23 01:53:45 +00:00
"10.1.2.0/24",
)
.await;
// wait updater
tokio::time::sleep(tokio::time::Duration::from_secs(6)).await;
let tcp_listener = TcpTunnelListener::new("tcp://10.1.2.4:22223".parse().unwrap());
let tcp_connector = TcpTunnelConnector::new("tcp://10.1.2.4:22223".parse().unwrap());
_tunnel_pingpong_netns(
tcp_listener,
tcp_connector,
NetNS::new(Some("net_d".into())),
NetNS::new(Some("net_a".into())),
)
.await;
}
#[rstest::rstest]
2023-09-23 01:53:45 +00:00
#[tokio::test]
#[serial_test::serial]
pub async fn icmp_proxy_three_node_test(#[values("tcp", "udp", "wg")] proto: &str) {
2024-05-13 20:34:43 +08:00
let mut insts = init_three_node(proto).await;
2023-09-23 01:53:45 +00:00
insts[2]
.get_global_ctx()
.add_proxy_cidr("10.1.2.0/24".parse().unwrap())
.unwrap();
2024-05-13 20:34:43 +08:00
insts[2].run_ip_proxy().await.unwrap();
2023-09-23 01:53:45 +00:00
assert_eq!(insts[2].get_global_ctx().get_proxy_cidrs().len(), 1);
wait_proxy_route_appear(
&insts[0].get_peer_manager(),
"10.144.144.3",
2024-03-13 00:15:22 +08:00
insts[2].peer_id(),
2023-09-23 01:53:45 +00:00
"10.1.2.0/24",
)
.await;
wait_for_condition(
|| async { ping_test("net_a", "10.1.2.4").await },
Duration::from_secs(5),
)
.await;
2023-09-23 01:53:45 +00:00
}
2024-05-03 07:55:00 +08:00
#[cfg(feature = "wireguard")]
#[rstest::rstest]
2023-09-23 01:53:45 +00:00
#[tokio::test]
#[serial_test::serial]
pub async fn proxy_three_node_disconnect_test(#[values("tcp", "wg")] proto: &str) {
use crate::tunnel::wireguard::{WgConfig, WgTunnelConnector};
let insts = init_three_node(proto).await;
2024-03-23 00:56:27 +08:00
let mut inst4 = Instance::new(get_inst_config("inst4", Some("net_d"), "10.144.144.4"));
if proto == "tcp" {
inst4
.get_conn_manager()
.add_connector(TcpTunnelConnector::new(
"tcp://10.1.2.3:11010".parse().unwrap(),
));
} else if proto == "wg" {
inst4
.get_conn_manager()
.add_connector(WgTunnelConnector::new(
"wg://10.1.2.3:11011".parse().unwrap(),
WgConfig::new_from_network_identity(
&inst4.get_global_ctx().get_network_identity().network_name,
2024-04-27 13:44:59 +08:00
&inst4
.get_global_ctx()
.get_network_identity()
.network_secret
.unwrap_or_default(),
),
));
} else {
unreachable!("not support");
}
2023-09-23 01:53:45 +00:00
inst4.run().await.unwrap();
let task = tokio::spawn(async move {
for _ in 1..=2 {
tokio::time::sleep(tokio::time::Duration::from_secs(8)).await;
// inst4 should be in inst1's route list
let routes = insts[0].get_peer_manager().list_routes().await;
assert!(
routes
.iter()
.find(|r| r.peer_id == inst4.peer_id())
.is_some(),
"inst4 should be in inst1's route list, {:?}",
routes
);
2023-09-23 01:53:45 +00:00
set_link_status("net_d", false);
tokio::time::sleep(tokio::time::Duration::from_secs(8)).await;
let routes = insts[0].get_peer_manager().list_routes().await;
assert!(
routes
.iter()
.find(|r| r.peer_id == inst4.peer_id())
.is_none(),
"inst4 should not be in inst1's route list, {:?}",
routes
);
2023-09-23 01:53:45 +00:00
set_link_status("net_d", true);
}
});
let (ret,) = tokio::join!(task);
assert!(ret.is_ok());
2023-09-23 01:53:45 +00:00
}
2024-03-01 21:37:45 +08:00
#[rstest::rstest]
2024-03-01 21:37:45 +08:00
#[tokio::test]
#[serial_test::serial]
pub async fn udp_proxy_three_node_test(#[values("tcp", "udp", "wg")] proto: &str) {
use crate::tunnel::{common::tests::_tunnel_pingpong_netns, udp::UdpTunnelListener};
2024-05-13 20:34:43 +08:00
let mut insts = init_three_node(proto).await;
2024-03-01 21:37:45 +08:00
insts[2]
.get_global_ctx()
.add_proxy_cidr("10.1.2.0/24".parse().unwrap())
.unwrap();
2024-05-13 20:34:43 +08:00
insts[2].run_ip_proxy().await.unwrap();
2024-03-01 21:37:45 +08:00
assert_eq!(insts[2].get_global_ctx().get_proxy_cidrs().len(), 1);
wait_proxy_route_appear(
&insts[0].get_peer_manager(),
"10.144.144.3",
2024-03-13 00:15:22 +08:00
insts[2].peer_id(),
2024-03-01 21:37:45 +08:00
"10.1.2.0/24",
)
.await;
// wait updater
tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
let tcp_listener = UdpTunnelListener::new("udp://10.1.2.4:22233".parse().unwrap());
let tcp_connector = UdpTunnelConnector::new("udp://10.1.2.4:22233".parse().unwrap());
_tunnel_pingpong_netns(
tcp_listener,
tcp_connector,
NetNS::new(Some("net_d".into())),
NetNS::new(Some("net_a".into())),
)
.await;
}
2024-03-06 23:09:15 +08:00
#[tokio::test]
#[serial_test::serial]
pub async fn udp_broadcast_test() {
let _insts = init_three_node("tcp").await;
let udp_broadcast_responder = |net_ns: NetNS, counter: Arc<AtomicU32>| async move {
let _g = net_ns.guard();
let socket: UdpSocket = UdpSocket::bind("0.0.0.0:22111").await.unwrap();
socket.set_broadcast(true).unwrap();
println!("Awaiting responses..."); // self.recv_buff is a [u8; 8092]
let mut recv_buff = [0; 8092];
while let Ok((n, addr)) = socket.recv_from(&mut recv_buff).await {
println!("{} bytes response from {:?}", n, addr);
counter.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
// Remaining code not directly relevant to the question
}
};
let mut tasks = JoinSet::new();
let counter = Arc::new(AtomicU32::new(0));
tasks.spawn(udp_broadcast_responder(
NetNS::new(Some("net_b".into())),
counter.clone(),
));
tasks.spawn(udp_broadcast_responder(
NetNS::new(Some("net_c".into())),
counter.clone(),
));
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
// send broadcast
let net_ns = NetNS::new(Some("net_a".into()));
let _g = net_ns.guard();
let socket: UdpSocket = UdpSocket::bind("0.0.0.0:0").await.unwrap();
socket.set_broadcast(true).unwrap();
// socket.connect(("10.144.144.255", 22111)).await.unwrap();
let call: Vec<u8> = vec![1; 1024];
println!("Sending call, {} bytes", call.len());
match socket.send_to(&call, "10.144.144.255:22111").await {
Err(e) => panic!("Error sending call: {:?}", e),
_ => {}
}
tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;
assert_eq!(counter.load(std::sync::atomic::Ordering::Relaxed), 2);
}
2024-03-23 22:20:19 +08:00
#[tokio::test]
#[serial_test::serial]
pub async fn foreign_network_forward_nic_data() {
prepare_linux_namespaces();
let center_node_config = get_inst_config("inst1", Some("net_a"), "10.144.144.1");
2024-04-27 13:44:59 +08:00
center_node_config
.set_network_identity(NetworkIdentity::new("center".to_string(), "".to_string()));
2024-03-23 22:20:19 +08:00
let mut center_inst = Instance::new(center_node_config);
let mut inst1 = Instance::new(get_inst_config("inst1", Some("net_b"), "10.144.145.1"));
let mut inst2 = Instance::new(get_inst_config("inst2", Some("net_c"), "10.144.145.2"));
center_inst.run().await.unwrap();
inst1.run().await.unwrap();
inst2.run().await.unwrap();
assert_ne!(inst1.id(), center_inst.id());
assert_ne!(inst2.id(), center_inst.id());
inst1
.get_conn_manager()
.add_connector(RingTunnelConnector::new(
format!("ring://{}", center_inst.id()).parse().unwrap(),
));
inst2
.get_conn_manager()
.add_connector(RingTunnelConnector::new(
format!("ring://{}", center_inst.id()).parse().unwrap(),
));
wait_for_condition(
|| async {
inst1.get_peer_manager().list_routes().await.len() == 1
&& inst2.get_peer_manager().list_routes().await.len() == 1
},
Duration::from_secs(5),
)
.await;
wait_for_condition(
|| async { ping_test("net_b", "10.144.145.2").await },
Duration::from_secs(5),
)
.await;
}
use std::{net::SocketAddr, str::FromStr};
use defguard_wireguard_rs::{
host::Peer, key::Key, net::IpAddrMask, InterfaceConfiguration, WGApi, WireguardInterfaceApi,
};
fn run_wireguard_client(
endpoint: SocketAddr,
peer_public_key: Key,
client_private_key: Key,
allowed_ips: Vec<String>,
client_ip: String,
) -> Result<(), Box<dyn std::error::Error>> {
// Create new API object for interface
let ifname: String = if cfg!(target_os = "linux") || cfg!(target_os = "freebsd") {
"wg0".into()
} else {
"utun3".into()
};
let wgapi = WGApi::new(ifname.clone(), false)?;
// create interface
wgapi.create_interface()?;
// Peer secret key
let mut peer = Peer::new(peer_public_key.clone());
log::info!("endpoint");
// Peer endpoint and interval
peer.endpoint = Some(endpoint);
2024-04-27 13:44:59 +08:00
peer.persistent_keepalive_interval = Some(1);
for ip in allowed_ips {
peer.allowed_ips.push(IpAddrMask::from_str(ip.as_str())?);
}
// interface configuration
let interface_config = InterfaceConfiguration {
name: ifname.clone(),
prvkey: client_private_key.to_string(),
address: client_ip,
port: 12345,
peers: vec![peer],
};
#[cfg(not(windows))]
wgapi.configure_interface(&interface_config)?;
#[cfg(windows)]
wgapi.configure_interface(&interface_config, &[])?;
wgapi.configure_peer_routing(&interface_config.peers)?;
Ok(())
}
2024-05-03 07:55:00 +08:00
#[cfg(feature = "wireguard")]
#[tokio::test]
#[serial_test::serial]
pub async fn wireguard_vpn_portal() {
let mut insts = init_three_node("tcp").await;
let net_ns = NetNS::new(Some("net_d".into()));
let _g = net_ns.guard();
insts[2]
.get_global_ctx()
.config
.set_vpn_portal_config(VpnPortalConfig {
wireguard_listen: "0.0.0.0:22121".parse().unwrap(),
client_cidr: "10.14.14.0/24".parse().unwrap(),
});
insts[2].run_vpn_portal().await.unwrap();
let net_ns = NetNS::new(Some("net_d".into()));
let _g = net_ns.guard();
let wg_cfg = get_wg_config_for_portal(&insts[2].get_global_ctx().get_network_identity());
run_wireguard_client(
"10.1.2.3:22121".parse().unwrap(),
Key::try_from(wg_cfg.my_public_key()).unwrap(),
Key::try_from(wg_cfg.peer_secret_key()).unwrap(),
vec!["10.14.14.0/24".to_string(), "10.144.144.0/24".to_string()],
"10.14.14.2".to_string(),
)
.unwrap();
// ping other node in network
wait_for_condition(
|| async { ping_test("net_d", "10.144.144.1").await },
2024-04-27 23:10:28 +08:00
Duration::from_secs(5),
)
.await;
wait_for_condition(
|| async { ping_test("net_d", "10.144.144.2").await },
Duration::from_secs(5),
)
.await;
// ping portal node
wait_for_condition(
|| async { ping_test("net_d", "10.144.144.3").await },
2024-04-27 13:44:59 +08:00
Duration::from_secs(5),
)
.await;
2024-03-23 22:20:19 +08:00
}