mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-05-07 18:24:36 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7afbd52fa6 | |||
| 0ee551a285 |
@@ -158,14 +158,12 @@ async fn set_tun_fd(fd: i32) -> Result<(), String> {
|
||||
let Some(instance_manager) = INSTANCE_MANAGER.read().await.clone() else {
|
||||
return Err("set_tun_fd is not supported in remote mode".to_string());
|
||||
};
|
||||
if let Some(uuid) = get_client_manager!()?
|
||||
let instance_ids: Vec<_> = get_client_manager!()?
|
||||
.get_enabled_instances_with_tun_ids()
|
||||
.next()
|
||||
{
|
||||
.collect();
|
||||
instance_manager
|
||||
.set_tun_fd(&uuid, fd)
|
||||
.set_tun_fd_for_instances(instance_ids, fd)
|
||||
.map_err(|e| e.to_string())?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ pub type NetworkIdentity = crate::common::config::NetworkIdentity;
|
||||
pub enum GlobalCtxEvent {
|
||||
TunDeviceReady(String),
|
||||
TunDeviceError(String),
|
||||
TunDeviceFallback(String),
|
||||
|
||||
PeerAdded(PeerId),
|
||||
PeerRemoved(PeerId),
|
||||
|
||||
@@ -536,6 +536,7 @@ impl MagicDnsServerInstance {
|
||||
None
|
||||
};
|
||||
let ifcfg = IfConfiger {};
|
||||
let _g = peer_mgr.get_global_ctx().net_ns.guard();
|
||||
ifcfg
|
||||
.add_ipv4_route(tun_dev_name, fake_ip, 32, cost)
|
||||
.await?;
|
||||
@@ -590,6 +591,7 @@ impl MagicDnsServerInstance {
|
||||
&& let Some(tun_dev_name) = &self.data.tun_dev
|
||||
{
|
||||
let ifcfg = IfConfiger {};
|
||||
let _g = self.peer_mgr.get_global_ctx().net_ns.guard();
|
||||
let _ = ifcfg
|
||||
.remove_ipv4_route(tun_dev_name, self.data.fake_ip, 32)
|
||||
.await;
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#[cfg(feature = "tun")]
|
||||
use std::any::Any;
|
||||
use std::collections::HashSet;
|
||||
use std::net::{IpAddr, Ipv4Addr};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
@@ -65,6 +63,10 @@ use crate::vpn_portal::{self, VpnPortal};
|
||||
#[cfg(feature = "magic-dns")]
|
||||
use super::dns_server::{MAGIC_DNS_FAKE_IP, runner::DnsRunner};
|
||||
use super::listeners::ListenerManager;
|
||||
#[cfg(feature = "tun")]
|
||||
use super::shared_tun::{
|
||||
SharedTunAccess, SharedTunAttachError, SharedTunMemberHandle, try_attach_shared_tun,
|
||||
};
|
||||
|
||||
#[cfg(feature = "socks5")]
|
||||
use crate::gateway::socks5::Socks5Server;
|
||||
@@ -133,6 +135,13 @@ impl IpProxy {
|
||||
#[cfg(feature = "tun")]
|
||||
type NicCtx = super::virtual_nic::NicCtx;
|
||||
|
||||
#[cfg(feature = "tun")]
|
||||
enum NicRuntime {
|
||||
Dedicated(NicCtx),
|
||||
Shared(SharedTunMemberHandle),
|
||||
Dummy(JoinSet<()>),
|
||||
}
|
||||
|
||||
#[cfg(feature = "magic-dns")]
|
||||
struct MagicDnsContainer {
|
||||
dns_runner_task: ScopedTask<()>,
|
||||
@@ -142,7 +151,7 @@ struct MagicDnsContainer {
|
||||
// nic container will be cleared when dhcp ip changed
|
||||
#[cfg(feature = "tun")]
|
||||
pub struct NicCtxContainer {
|
||||
nic_ctx: Option<Box<dyn Any + 'static + Send>>,
|
||||
nic_ctx: Option<NicRuntime>,
|
||||
#[cfg(feature = "magic-dns")]
|
||||
magic_dns: Option<MagicDnsContainer>,
|
||||
}
|
||||
@@ -150,14 +159,14 @@ pub struct NicCtxContainer {
|
||||
#[cfg(feature = "tun")]
|
||||
impl NicCtxContainer {
|
||||
#[cfg(not(feature = "magic-dns"))]
|
||||
fn new(nic_ctx: NicCtx) -> Self {
|
||||
fn new_dedicated(nic_ctx: NicCtx) -> Self {
|
||||
Self {
|
||||
nic_ctx: Some(Box::new(nic_ctx)),
|
||||
nic_ctx: Some(NicRuntime::Dedicated(nic_ctx)),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "magic-dns")]
|
||||
fn new(nic_ctx: NicCtx, dns_runner: Option<DnsRunner>) -> Self {
|
||||
fn new_dedicated(nic_ctx: NicCtx, dns_runner: Option<DnsRunner>) -> Self {
|
||||
if let Some(mut dns_runner) = dns_runner {
|
||||
let token = CancellationToken::new();
|
||||
let token_clone = token.clone();
|
||||
@@ -165,7 +174,7 @@ impl NicCtxContainer {
|
||||
let _ = dns_runner.run(token_clone).await;
|
||||
});
|
||||
Self {
|
||||
nic_ctx: Some(Box::new(nic_ctx)),
|
||||
nic_ctx: Some(NicRuntime::Dedicated(nic_ctx)),
|
||||
magic_dns: Some(MagicDnsContainer {
|
||||
dns_runner_task: task.into(),
|
||||
dns_runner_cancel_token: token,
|
||||
@@ -173,15 +182,45 @@ impl NicCtxContainer {
|
||||
}
|
||||
} else {
|
||||
Self {
|
||||
nic_ctx: Some(Box::new(nic_ctx)),
|
||||
nic_ctx: Some(NicRuntime::Dedicated(nic_ctx)),
|
||||
magic_dns: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn new_with_any<T: 'static + Send>(ctx: T) -> Self {
|
||||
#[cfg(not(feature = "magic-dns"))]
|
||||
fn new_shared(handle: SharedTunMemberHandle) -> Self {
|
||||
Self {
|
||||
nic_ctx: Some(Box::new(ctx)),
|
||||
nic_ctx: Some(NicRuntime::Shared(handle)),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "magic-dns")]
|
||||
fn new_shared(handle: SharedTunMemberHandle, dns_runner: Option<DnsRunner>) -> Self {
|
||||
if let Some(mut dns_runner) = dns_runner {
|
||||
let token = CancellationToken::new();
|
||||
let token_clone = token.clone();
|
||||
let task = tokio::spawn(async move {
|
||||
let _ = dns_runner.run(token_clone).await;
|
||||
});
|
||||
Self {
|
||||
nic_ctx: Some(NicRuntime::Shared(handle)),
|
||||
magic_dns: Some(MagicDnsContainer {
|
||||
dns_runner_task: task.into(),
|
||||
dns_runner_cancel_token: token,
|
||||
}),
|
||||
}
|
||||
} else {
|
||||
Self {
|
||||
nic_ctx: Some(NicRuntime::Shared(handle)),
|
||||
magic_dns: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn new_dummy(tasks: JoinSet<()>) -> Self {
|
||||
Self {
|
||||
nic_ctx: Some(NicRuntime::Dummy(tasks)),
|
||||
#[cfg(feature = "magic-dns")]
|
||||
magic_dns: None,
|
||||
}
|
||||
@@ -666,19 +705,31 @@ impl Instance {
|
||||
|
||||
// use a mock nic ctx to consume packets.
|
||||
#[cfg(feature = "tun")]
|
||||
async fn clear_nic_ctx(
|
||||
arc_nic_ctx: ArcNicCtx,
|
||||
packet_recv: Arc<Mutex<PacketRecvChanReceiver>>,
|
||||
) {
|
||||
async fn cleanup_nic_ctx(mut old_ctx: NicCtxContainer) {
|
||||
if let Some(runtime) = old_ctx.nic_ctx.take() {
|
||||
match runtime {
|
||||
NicRuntime::Shared(handle) => handle.shutdown().await,
|
||||
NicRuntime::Dedicated(_) | NicRuntime::Dummy(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "magic-dns")]
|
||||
if let Some(old_ctx) = arc_nic_ctx.lock().await.take()
|
||||
&& let Some(dns_runner) = old_ctx.magic_dns
|
||||
{
|
||||
if let Some(dns_runner) = old_ctx.magic_dns.take() {
|
||||
dns_runner.dns_runner_cancel_token.cancel();
|
||||
tracing::debug!("cancelling dns runner task");
|
||||
let ret = dns_runner.dns_runner_task.await;
|
||||
tracing::debug!("dns runner task cancelled, ret: {:?}", ret);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "tun")]
|
||||
async fn clear_nic_ctx(
|
||||
arc_nic_ctx: ArcNicCtx,
|
||||
packet_recv: Arc<Mutex<PacketRecvChanReceiver>>,
|
||||
) {
|
||||
if let Some(old_ctx) = arc_nic_ctx.lock().await.take() {
|
||||
Self::cleanup_nic_ctx(old_ctx).await;
|
||||
}
|
||||
|
||||
let mut tasks = JoinSet::new();
|
||||
tasks.spawn(async move {
|
||||
@@ -690,7 +741,7 @@ impl Instance {
|
||||
arc_nic_ctx
|
||||
.lock()
|
||||
.await
|
||||
.replace(NicCtxContainer::new_with_any(tasks));
|
||||
.replace(NicCtxContainer::new_dummy(tasks));
|
||||
|
||||
tracing::debug!("nic ctx cleared.");
|
||||
}
|
||||
@@ -716,13 +767,13 @@ impl Instance {
|
||||
}
|
||||
|
||||
#[cfg(feature = "tun")]
|
||||
async fn use_new_nic_ctx(
|
||||
async fn use_new_dedicated_nic_ctx(
|
||||
arc_nic_ctx: ArcNicCtx,
|
||||
nic_ctx: NicCtx,
|
||||
#[cfg(feature = "magic-dns")] magic_dns: Option<DnsRunner>,
|
||||
) {
|
||||
let mut g = arc_nic_ctx.lock().await;
|
||||
*g = Some(NicCtxContainer::new(
|
||||
*g = Some(NicCtxContainer::new_dedicated(
|
||||
nic_ctx,
|
||||
#[cfg(feature = "magic-dns")]
|
||||
magic_dns,
|
||||
@@ -730,6 +781,90 @@ impl Instance {
|
||||
tracing::debug!("nic ctx updated.");
|
||||
}
|
||||
|
||||
#[cfg(feature = "tun")]
|
||||
async fn use_new_shared_nic_ctx(
|
||||
arc_nic_ctx: ArcNicCtx,
|
||||
handle: SharedTunMemberHandle,
|
||||
#[cfg(feature = "magic-dns")] magic_dns: Option<DnsRunner>,
|
||||
) {
|
||||
let mut g = arc_nic_ctx.lock().await;
|
||||
*g = Some(NicCtxContainer::new_shared(
|
||||
handle,
|
||||
#[cfg(feature = "magic-dns")]
|
||||
magic_dns,
|
||||
));
|
||||
tracing::debug!("shared nic ctx updated.");
|
||||
}
|
||||
|
||||
#[cfg(all(not(mobile), feature = "tun"))]
|
||||
async fn setup_dedicated_nic_ctx(
|
||||
arc_nic_ctx: ArcNicCtx,
|
||||
global_ctx: ArcGlobalCtx,
|
||||
peer_mgr: Arc<PeerManager>,
|
||||
peer_packet_receiver: Arc<Mutex<PacketRecvChanReceiver>>,
|
||||
close_notifier: Arc<Notify>,
|
||||
ipv4_addr: Option<Ipv4Inet>,
|
||||
ipv6_addr: Option<cidr::Ipv6Inet>,
|
||||
) -> Result<(), Error> {
|
||||
let mut new_nic_ctx =
|
||||
NicCtx::new(global_ctx, &peer_mgr, peer_packet_receiver, close_notifier);
|
||||
new_nic_ctx.run(ipv4_addr, ipv6_addr).await?;
|
||||
|
||||
#[cfg(feature = "magic-dns")]
|
||||
{
|
||||
let ifname = new_nic_ctx.ifname().await;
|
||||
let dns_runner =
|
||||
ipv4_addr.and_then(|ipv4| Self::create_magic_dns_runner(peer_mgr, ifname, ipv4));
|
||||
Self::use_new_dedicated_nic_ctx(arc_nic_ctx, new_nic_ctx, dns_runner).await;
|
||||
}
|
||||
#[cfg(not(feature = "magic-dns"))]
|
||||
Self::use_new_dedicated_nic_ctx(arc_nic_ctx, new_nic_ctx).await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(all(not(mobile), feature = "tun"))]
|
||||
async fn try_setup_shared_tun(
|
||||
arc_nic_ctx: ArcNicCtx,
|
||||
global_ctx: ArcGlobalCtx,
|
||||
peer_mgr: Arc<PeerManager>,
|
||||
peer_packet_receiver: Arc<Mutex<PacketRecvChanReceiver>>,
|
||||
close_notifier: Arc<Notify>,
|
||||
ipv4_addr: Option<Ipv4Inet>,
|
||||
) -> Result<bool, Error> {
|
||||
match try_attach_shared_tun(
|
||||
global_ctx.clone(),
|
||||
peer_mgr.clone(),
|
||||
peer_packet_receiver,
|
||||
close_notifier,
|
||||
SharedTunAccess::Native,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(attached) => {
|
||||
global_ctx.issue_event(GlobalCtxEvent::TunDeviceReady(attached.ifname.clone()));
|
||||
#[cfg(feature = "magic-dns")]
|
||||
let dns_runner = ipv4_addr.and_then(|ip| {
|
||||
Self::create_magic_dns_runner(peer_mgr, Some(attached.ifname.clone()), ip)
|
||||
});
|
||||
Self::use_new_shared_nic_ctx(
|
||||
arc_nic_ctx,
|
||||
attached.handle,
|
||||
#[cfg(feature = "magic-dns")]
|
||||
dns_runner,
|
||||
)
|
||||
.await;
|
||||
Ok(true)
|
||||
}
|
||||
Err(SharedTunAttachError::Fallback(reason)) => {
|
||||
tracing::info!(instance_id = %global_ctx.get_id(), %reason, "shared tun unavailable, falling back to dedicated tun");
|
||||
global_ctx.issue_event(GlobalCtxEvent::TunDeviceFallback(reason));
|
||||
Ok(false)
|
||||
}
|
||||
Err(SharedTunAttachError::Fatal(err)) => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
// Warning, if there is an IP conflict in the network when using DHCP, the IP will be automatically changed.
|
||||
fn check_dhcp_ip_conflict(&self) {
|
||||
use rand::Rng;
|
||||
@@ -813,15 +948,33 @@ impl Instance {
|
||||
continue;
|
||||
}
|
||||
|
||||
global_ctx_c.set_ipv4(Some(ip));
|
||||
|
||||
#[cfg(all(not(mobile), feature = "tun"))]
|
||||
{
|
||||
let mut new_nic_ctx = NicCtx::new(
|
||||
match Self::try_setup_shared_tun(
|
||||
nic_ctx.clone(),
|
||||
global_ctx_c.clone(),
|
||||
&peer_manager_c,
|
||||
peer_manager_c.clone(),
|
||||
_peer_packet_receiver.clone(),
|
||||
nic_closed_notifier.clone(),
|
||||
);
|
||||
if let Err(e) = new_nic_ctx.run(Some(ip), global_ctx_c.get_ipv6()).await {
|
||||
Some(ip),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(true) => {}
|
||||
Ok(false) => {
|
||||
if let Err(e) = Self::setup_dedicated_nic_ctx(
|
||||
nic_ctx.clone(),
|
||||
global_ctx_c.clone(),
|
||||
peer_manager_c.clone(),
|
||||
_peer_packet_receiver.clone(),
|
||||
nic_closed_notifier.clone(),
|
||||
Some(ip),
|
||||
global_ctx_c.get_ipv6(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
tracing::error!(
|
||||
?current_dhcp_ip,
|
||||
?candidate_ipv4_addr,
|
||||
@@ -831,19 +984,21 @@ impl Instance {
|
||||
global_ctx_c.set_ipv4(None);
|
||||
continue;
|
||||
}
|
||||
#[cfg(feature = "magic-dns")]
|
||||
let ifname = new_nic_ctx.ifname().await;
|
||||
Self::use_new_nic_ctx(
|
||||
nic_ctx.clone(),
|
||||
new_nic_ctx,
|
||||
#[cfg(feature = "magic-dns")]
|
||||
Self::create_magic_dns_runner(peer_manager_c.clone(), ifname, ip),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!(
|
||||
?current_dhcp_ip,
|
||||
?candidate_ipv4_addr,
|
||||
?e,
|
||||
"shared tun attach failed"
|
||||
);
|
||||
global_ctx_c.set_ipv4(None);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
current_dhcp_ip = Some(ip);
|
||||
global_ctx_c.set_ipv4(Some(ip));
|
||||
global_ctx_c.issue_event(GlobalCtxEvent::DhcpIpv4Changed(last_ip, Some(ip)));
|
||||
} else {
|
||||
current_dhcp_ip = None;
|
||||
@@ -883,14 +1038,42 @@ impl Instance {
|
||||
return;
|
||||
};
|
||||
|
||||
let mut new_nic_ctx = NicCtx::new(
|
||||
let shared_ready = match Self::try_setup_shared_tun(
|
||||
nic_ctx.clone(),
|
||||
peer_mgr.get_global_ctx(),
|
||||
&peer_mgr,
|
||||
peer_mgr.clone(),
|
||||
peer_packet_receiver.clone(),
|
||||
close_notifier.clone(),
|
||||
);
|
||||
ipv4_addr,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(ready) => ready,
|
||||
Err(e) => {
|
||||
if let Some(output_tx) = output_tx.take() {
|
||||
let _ = output_tx.send(Err(e));
|
||||
return;
|
||||
}
|
||||
tracing::error!("failed to attach shared tun, err: {:?}", e);
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(e) = new_nic_ctx.run(ipv4_addr, ipv6_addr).await {
|
||||
if shared_ready {
|
||||
// shared nic context is installed
|
||||
} else {
|
||||
if let Err(e) = Self::setup_dedicated_nic_ctx(
|
||||
nic_ctx.clone(),
|
||||
peer_mgr.get_global_ctx(),
|
||||
peer_mgr.clone(),
|
||||
peer_packet_receiver.clone(),
|
||||
close_notifier.clone(),
|
||||
ipv4_addr,
|
||||
ipv6_addr,
|
||||
)
|
||||
.await
|
||||
{
|
||||
if let Some(output_tx) = output_tx.take() {
|
||||
let _ = output_tx.send(Err(e));
|
||||
return;
|
||||
@@ -899,20 +1082,7 @@ impl Instance {
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create Magic DNS runner only if we have IPv4
|
||||
#[cfg(feature = "magic-dns")]
|
||||
{
|
||||
let ifname = new_nic_ctx.ifname().await;
|
||||
let dns_runner = if let Some(ipv4) = ipv4_addr {
|
||||
Self::create_magic_dns_runner(peer_mgr, ifname, ipv4)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
Self::use_new_nic_ctx(nic_ctx.clone(), new_nic_ctx, dns_runner).await;
|
||||
}
|
||||
#[cfg(not(feature = "magic-dns"))]
|
||||
Self::use_new_nic_ctx(nic_ctx.clone(), new_nic_ctx).await;
|
||||
}
|
||||
|
||||
if let Some(output_tx) = output_tx.take() {
|
||||
@@ -1480,13 +1650,38 @@ impl Instance {
|
||||
return Ok(());
|
||||
}
|
||||
let close_notifier = Arc::new(Notify::new());
|
||||
let mut new_nic_ctx = NicCtx::new(
|
||||
match try_attach_shared_tun(
|
||||
global_ctx.clone(),
|
||||
peer_manager.clone(),
|
||||
peer_packet_receiver.clone(),
|
||||
close_notifier.clone(),
|
||||
SharedTunAccess::MobileFd(fd),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(attached) => {
|
||||
global_ctx.issue_event(GlobalCtxEvent::TunDeviceReady(attached.ifname.clone()));
|
||||
let magic_dns_runner = if let Some(ipv4) = global_ctx.get_ipv4() {
|
||||
Self::create_magic_dns_runner(
|
||||
peer_manager.clone(),
|
||||
Some(attached.ifname.clone()),
|
||||
ipv4,
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
Self::use_new_shared_nic_ctx(nic_ctx, attached.handle, magic_dns_runner).await;
|
||||
}
|
||||
Err(SharedTunAttachError::Fallback(reason)) => {
|
||||
tracing::info!(instance_id = %global_ctx.get_id(), %reason, "shared mobile tun unavailable, falling back to dedicated tun");
|
||||
global_ctx.issue_event(GlobalCtxEvent::TunDeviceFallback(reason));
|
||||
let mut dedicated_nic_ctx = NicCtx::new(
|
||||
global_ctx.clone(),
|
||||
&peer_manager,
|
||||
peer_packet_receiver.clone(),
|
||||
close_notifier.clone(),
|
||||
);
|
||||
new_nic_ctx
|
||||
dedicated_nic_ctx
|
||||
.run_for_mobile(fd)
|
||||
.await
|
||||
.with_context(|| "add ip failed")?;
|
||||
@@ -1496,14 +1691,19 @@ impl Instance {
|
||||
} else {
|
||||
None
|
||||
};
|
||||
Self::use_new_nic_ctx(nic_ctx.clone(), new_nic_ctx, magic_dns_runner).await;
|
||||
Self::use_new_dedicated_nic_ctx(nic_ctx, dedicated_nic_ctx, magic_dns_runner).await;
|
||||
}
|
||||
Err(SharedTunAttachError::Fatal(err)) => return Err(err.into()),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn clear_resources(&mut self) {
|
||||
self.peer_manager.clear_resources().await;
|
||||
#[cfg(feature = "tun")]
|
||||
let _ = self.nic_ctx.lock().await.take();
|
||||
if let Some(old_ctx) = self.nic_ctx.lock().await.take() {
|
||||
Self::cleanup_nic_ctx(old_ctx).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1515,7 +1715,9 @@ impl Drop for Instance {
|
||||
let nic_ctx = self.nic_ctx.clone();
|
||||
tokio::spawn(async move {
|
||||
#[cfg(feature = "tun")]
|
||||
nic_ctx.lock().await.take();
|
||||
if let Some(old_ctx) = nic_ctx.lock().await.take() {
|
||||
Instance::cleanup_nic_ctx(old_ctx).await;
|
||||
}
|
||||
if let Some(pm) = pm.upgrade() {
|
||||
pm.clear_resources().await;
|
||||
};
|
||||
|
||||
@@ -6,5 +6,8 @@ pub mod listeners;
|
||||
|
||||
pub mod proxy_cidrs_monitor;
|
||||
|
||||
#[cfg(feature = "tun")]
|
||||
pub mod shared_tun;
|
||||
|
||||
#[cfg(feature = "tun")]
|
||||
pub mod virtual_nic;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -742,6 +742,22 @@ impl VirtualNic {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn remove_route(&self, address: Ipv4Addr, cidr: u8) -> Result<(), Error> {
|
||||
let _g = self.global_ctx.net_ns.guard();
|
||||
self.ifcfg
|
||||
.remove_ipv4_route(self.ifname(), address, cidr)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn remove_ipv6_route(&self, address: Ipv6Addr, cidr: u8) -> Result<(), Error> {
|
||||
let _g = self.global_ctx.net_ns.guard();
|
||||
self.ifcfg
|
||||
.remove_ipv6_route(self.ifname(), address, cidr)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn remove_ip(&self, ip: Option<Ipv4Inet>) -> Result<(), Error> {
|
||||
let _g = self.global_ctx.net_ns.guard();
|
||||
self.ifcfg.remove_ip(self.ifname(), ip).await?;
|
||||
@@ -770,6 +786,12 @@ impl VirtualNic {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn set_mtu(&self, mtu: u16) -> Result<(), Error> {
|
||||
let _g = self.global_ctx.net_ns.guard();
|
||||
self.ifcfg.set_mtu(self.ifname(), mtu as u32).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_ifcfg(&self) -> impl IfConfiguerTrait + use<> {
|
||||
IfConfiger {}
|
||||
}
|
||||
@@ -943,6 +965,10 @@ impl NicCtx {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn forward_nic_packet_to_peers(ret: ZCPacket, mgr: &PeerManager) {
|
||||
Self::do_forward_nic_to_peers(ret, mgr).await;
|
||||
}
|
||||
|
||||
fn do_forward_nic_to_peers_task(
|
||||
&mut self,
|
||||
mut stream: Pin<Box<dyn ZCPacketStream>>,
|
||||
|
||||
@@ -241,6 +241,17 @@ impl NetworkInstanceManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_tun_fd_for_instances<I>(&self, instance_ids: I, fd: i32) -> Result<(), anyhow::Error>
|
||||
where
|
||||
I: IntoIterator<Item = uuid::Uuid>,
|
||||
{
|
||||
for instance_id in instance_ids {
|
||||
self.set_tun_fd(&instance_id, fd)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_config_dir(&self) -> Option<&PathBuf> {
|
||||
self.config_dir.as_ref()
|
||||
}
|
||||
@@ -363,6 +374,10 @@ fn handle_event(
|
||||
event!(error, %err, "[{}] tun device error", instance_id);
|
||||
}
|
||||
|
||||
GlobalCtxEvent::TunDeviceFallback(reason) => {
|
||||
event!(warn, %reason, "[{}] tun device fallback", instance_id);
|
||||
}
|
||||
|
||||
GlobalCtxEvent::Connecting(dst) => {
|
||||
event!(info, category: "CONNECTION", %dst, "[{}] connecting to peer", instance_id);
|
||||
}
|
||||
@@ -461,6 +476,7 @@ impl Display for proto::api::instance::PeerConnInfo {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::common::config::*;
|
||||
use crate::launcher::{EasyTierLauncher, NetworkInstance};
|
||||
|
||||
#[tokio::test]
|
||||
#[serial_test::serial]
|
||||
@@ -612,6 +628,70 @@ mod tests {
|
||||
assert_eq!(manager.instance_stop_tasks.len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_tun_fd_for_instances_allows_empty_target_list() {
|
||||
let manager = NetworkInstanceManager::new();
|
||||
assert!(manager.set_tun_fd_for_instances(Vec::new(), 1234).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_tun_fd_for_instances_errors_on_missing_instance() {
|
||||
let manager = NetworkInstanceManager::new();
|
||||
let err = manager
|
||||
.set_tun_fd_for_instances(vec![uuid::Uuid::new_v4()], 1234)
|
||||
.unwrap_err();
|
||||
assert!(err.to_string().contains("instance not found"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_tun_fd_for_instances_broadcasts_to_all_targets() {
|
||||
let manager = NetworkInstanceManager::new();
|
||||
let instance_ids = [
|
||||
uuid::Uuid::new_v4(),
|
||||
uuid::Uuid::new_v4(),
|
||||
uuid::Uuid::new_v4(),
|
||||
];
|
||||
|
||||
for instance_id in instance_ids {
|
||||
let cfg = TomlConfigLoader::default();
|
||||
cfg.set_id(instance_id);
|
||||
cfg.set_inst_name(format!("inst-{instance_id}"));
|
||||
cfg.set_listeners(vec![]);
|
||||
|
||||
manager.instance_map.insert(
|
||||
instance_id,
|
||||
NetworkInstance::with_launcher_for_test(
|
||||
cfg,
|
||||
ConfigFileControl::STATIC_CONFIG,
|
||||
EasyTierLauncher::new(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
let mut receivers = instance_ids
|
||||
.iter()
|
||||
.map(|instance_id| {
|
||||
manager
|
||||
.instance_map
|
||||
.get(instance_id)
|
||||
.unwrap()
|
||||
.take_tun_fd_receiver_for_test()
|
||||
.unwrap()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
manager
|
||||
.set_tun_fd_for_instances(instance_ids[..2].to_vec(), 1234)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(receivers[0].try_recv().unwrap(), Some(1234));
|
||||
assert_eq!(receivers[1].try_recv().unwrap(), Some(1234));
|
||||
assert!(matches!(
|
||||
receivers[2].try_recv(),
|
||||
Err(tokio::sync::mpsc::error::TryRecvError::Empty)
|
||||
));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial_test::serial]
|
||||
async fn test_single_instance_failed() {
|
||||
|
||||
@@ -260,6 +260,11 @@ impl EasyTierLauncher {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn take_tun_fd_receiver_for_test(&self) -> Option<mpsc::Receiver<TunFd>> {
|
||||
self.data.tun_fd.1.lock().unwrap().take()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for EasyTierLauncher {
|
||||
@@ -447,6 +452,26 @@ impl NetworkInstance {
|
||||
.as_ref()
|
||||
.and_then(|launcher| launcher.get_api_service())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn with_launcher_for_test(
|
||||
config: TomlConfigLoader,
|
||||
config_file_control: ConfigFileControl,
|
||||
launcher: EasyTierLauncher,
|
||||
) -> Self {
|
||||
Self {
|
||||
config,
|
||||
launcher: Some(launcher),
|
||||
config_file_control,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn take_tun_fd_receiver_for_test(&self) -> Option<mpsc::Receiver<TunFd>> {
|
||||
self.launcher
|
||||
.as_ref()
|
||||
.and_then(|launcher| launcher.take_tun_fd_receiver_for_test())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_proxy_network_to_config(
|
||||
|
||||
@@ -13,6 +13,9 @@ use x25519_dalek::StaticSecret;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[cfg(feature = "magic-dns")]
|
||||
use crate::instance::dns_server::MAGIC_DNS_INSTANCE_ADDR;
|
||||
|
||||
// TODO: 需要加一个单测,确保 socks5 + exit node == self || proxy_cidr == 0.0.0.0/0 时,可以实现出口节点的能力。
|
||||
|
||||
use crate::{
|
||||
@@ -258,6 +261,261 @@ pub async fn drop_insts(insts: Vec<Instance>) {
|
||||
while set.join_next().await.is_some() {}
|
||||
}
|
||||
|
||||
async fn wait_for_tun_ready_event(
|
||||
receiver: &mut tokio::sync::broadcast::Receiver<crate::common::global_ctx::GlobalCtxEvent>,
|
||||
) -> String {
|
||||
tokio::time::timeout(Duration::from_secs(5), async {
|
||||
loop {
|
||||
if let crate::common::global_ctx::GlobalCtxEvent::TunDeviceReady(ifname) =
|
||||
receiver.recv().await.unwrap()
|
||||
{
|
||||
return ifname;
|
||||
}
|
||||
}
|
||||
})
|
||||
.await
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
async fn assert_no_tun_ready_event(
|
||||
receiver: &mut tokio::sync::broadcast::Receiver<crate::common::global_ctx::GlobalCtxEvent>,
|
||||
timeout: Duration,
|
||||
) {
|
||||
tokio::time::timeout(timeout, async {
|
||||
loop {
|
||||
if let crate::common::global_ctx::GlobalCtxEvent::TunDeviceReady(ifname) =
|
||||
receiver.recv().await.unwrap()
|
||||
{
|
||||
panic!("unexpected TunDeviceReady event: {ifname}");
|
||||
}
|
||||
}
|
||||
})
|
||||
.await
|
||||
.ok();
|
||||
}
|
||||
|
||||
async fn assert_no_tun_fallback_event(
|
||||
receiver: &mut tokio::sync::broadcast::Receiver<crate::common::global_ctx::GlobalCtxEvent>,
|
||||
timeout: Duration,
|
||||
) {
|
||||
tokio::time::timeout(timeout, async {
|
||||
loop {
|
||||
if let crate::common::global_ctx::GlobalCtxEvent::TunDeviceFallback(reason) =
|
||||
receiver.recv().await.unwrap()
|
||||
{
|
||||
panic!("unexpected TunDeviceFallback event: {reason}");
|
||||
}
|
||||
}
|
||||
})
|
||||
.await
|
||||
.ok();
|
||||
}
|
||||
|
||||
async fn wait_for_tun_fallback_event(
|
||||
receiver: &mut tokio::sync::broadcast::Receiver<crate::common::global_ctx::GlobalCtxEvent>,
|
||||
) -> String {
|
||||
tokio::time::timeout(Duration::from_secs(8), async {
|
||||
loop {
|
||||
if let crate::common::global_ctx::GlobalCtxEvent::TunDeviceFallback(reason) =
|
||||
receiver.recv().await.unwrap()
|
||||
{
|
||||
return reason;
|
||||
}
|
||||
}
|
||||
})
|
||||
.await
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
async fn wait_for_dhcp_ipv4_changed_event(
|
||||
receiver: &mut tokio::sync::broadcast::Receiver<crate::common::global_ctx::GlobalCtxEvent>,
|
||||
) -> cidr::Ipv4Inet {
|
||||
tokio::time::timeout(Duration::from_secs(15), async {
|
||||
loop {
|
||||
if let crate::common::global_ctx::GlobalCtxEvent::DhcpIpv4Changed(_, Some(ip)) =
|
||||
receiver.recv().await.unwrap()
|
||||
{
|
||||
return ip;
|
||||
}
|
||||
}
|
||||
})
|
||||
.await
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
async fn link_exists_in_netns(netns: &str, ifname: &str) -> bool {
|
||||
let _g = NetNS::new(Some(ROOT_NETNS_NAME.to_owned())).guard();
|
||||
let code = tokio::process::Command::new("ip")
|
||||
.args(["netns", "exec", netns, "ip", "link", "show", "dev", ifname])
|
||||
.stdout(std::process::Stdio::null())
|
||||
.stderr(std::process::Stdio::null())
|
||||
.status()
|
||||
.await
|
||||
.unwrap();
|
||||
code.success()
|
||||
}
|
||||
|
||||
fn assert_tcp_proxy_metric_has_protocol(
|
||||
inst: &Instance,
|
||||
protocol: TcpProxyEntryTransportType,
|
||||
min_value: u64,
|
||||
) {
|
||||
let metrics = inst
|
||||
.get_global_ctx()
|
||||
.stats_manager()
|
||||
.get_metrics_by_prefix(&MetricName::TcpProxyConnect.to_string());
|
||||
|
||||
assert!(
|
||||
metrics.iter().any(|metric| {
|
||||
metric.value >= min_value
|
||||
&& metric.labels.labels().iter().any(|l| {
|
||||
let t = LabelType::Protocol(protocol.as_str_name().to_string());
|
||||
t.key() == l.key && t.value() == l.value
|
||||
})
|
||||
}),
|
||||
"metrics: {:?}",
|
||||
metrics
|
||||
);
|
||||
}
|
||||
|
||||
async fn shared_tun_subnet_proxy_transport_test(
|
||||
transport: TcpProxyEntryTransportType,
|
||||
source_shared: bool,
|
||||
) {
|
||||
prepare_linux_namespaces();
|
||||
|
||||
let center_cfg = get_inst_config("center", Some("net_b"), "10.144.144.100", "fd00::64/64");
|
||||
center_cfg.set_listeners(vec![]);
|
||||
let mut center = Instance::new(center_cfg);
|
||||
|
||||
let mut shared_events = Vec::new();
|
||||
let mut insts = Vec::new();
|
||||
let dst_idx;
|
||||
|
||||
if source_shared {
|
||||
let source_cfg = get_inst_config("src_shared", Some("net_a"), "10.144.144.1", "fd00::1/64");
|
||||
source_cfg.set_listeners(vec![]);
|
||||
source_cfg.set_socks5_portal(None);
|
||||
let mut source_flags = source_cfg.get_flags();
|
||||
source_flags.dev_name = "et_ssrc0".to_string();
|
||||
match transport {
|
||||
TcpProxyEntryTransportType::Kcp => source_flags.enable_kcp_proxy = true,
|
||||
TcpProxyEntryTransportType::Quic => source_flags.enable_quic_proxy = true,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
source_cfg.set_flags(source_flags.clone());
|
||||
let source = Instance::new(source_cfg);
|
||||
shared_events.push(source.get_global_ctx().subscribe());
|
||||
|
||||
let source_peer = get_inst_config("src_peer", Some("net_a"), "10.144.144.2", "fd00::2/64");
|
||||
source_peer.set_listeners(vec![]);
|
||||
source_peer.set_socks5_portal(None);
|
||||
source_peer.set_flags(source_flags);
|
||||
let source_peer = Instance::new(source_peer);
|
||||
shared_events.push(source_peer.get_global_ctx().subscribe());
|
||||
|
||||
let dst_cfg = get_inst_config("dst", Some("net_c"), "10.144.144.3", "fd00::3/64");
|
||||
dst_cfg.set_listeners(vec![]);
|
||||
dst_cfg.set_socks5_portal(None);
|
||||
dst_cfg
|
||||
.add_proxy_cidr("10.1.2.0/24".parse().unwrap(), None)
|
||||
.unwrap();
|
||||
let dst = Instance::new(dst_cfg);
|
||||
|
||||
insts.push(source);
|
||||
insts.push(source_peer);
|
||||
insts.push(dst);
|
||||
dst_idx = 2;
|
||||
} else {
|
||||
let src_cfg = get_inst_config("src", Some("net_a"), "10.144.144.1", "fd00::1/64");
|
||||
src_cfg.set_listeners(vec![]);
|
||||
src_cfg.set_socks5_portal(None);
|
||||
let mut src_flags = src_cfg.get_flags();
|
||||
match transport {
|
||||
TcpProxyEntryTransportType::Kcp => src_flags.enable_kcp_proxy = true,
|
||||
TcpProxyEntryTransportType::Quic => src_flags.enable_quic_proxy = true,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
src_cfg.set_flags(src_flags);
|
||||
let src = Instance::new(src_cfg);
|
||||
|
||||
let dst_cfg = get_inst_config("dst_shared", Some("net_c"), "10.144.144.3", "fd00::3/64");
|
||||
dst_cfg.set_listeners(vec![]);
|
||||
dst_cfg.set_socks5_portal(None);
|
||||
dst_cfg
|
||||
.add_proxy_cidr("10.1.2.0/24".parse().unwrap(), None)
|
||||
.unwrap();
|
||||
let mut dst_flags = dst_cfg.get_flags();
|
||||
dst_flags.dev_name = "et_sdst0".to_string();
|
||||
dst_cfg.set_flags(dst_flags.clone());
|
||||
let dst = Instance::new(dst_cfg);
|
||||
shared_events.push(dst.get_global_ctx().subscribe());
|
||||
|
||||
let dst_peer = get_inst_config("dst_peer", Some("net_c"), "10.144.144.4", "fd00::4/64");
|
||||
dst_peer.set_listeners(vec![]);
|
||||
dst_peer.set_socks5_portal(None);
|
||||
dst_peer.set_flags(dst_flags);
|
||||
let dst_peer = Instance::new(dst_peer);
|
||||
shared_events.push(dst_peer.get_global_ctx().subscribe());
|
||||
|
||||
insts.push(src);
|
||||
insts.push(dst);
|
||||
insts.push(dst_peer);
|
||||
dst_idx = 1;
|
||||
}
|
||||
|
||||
center.run().await.unwrap();
|
||||
for inst in &mut insts {
|
||||
inst.run().await.unwrap();
|
||||
}
|
||||
|
||||
let ifname = wait_for_tun_ready_event(&mut shared_events[0]).await;
|
||||
for receiver in shared_events.iter_mut().skip(1) {
|
||||
assert_eq!(ifname, wait_for_tun_ready_event(receiver).await);
|
||||
}
|
||||
|
||||
insts[0]
|
||||
.get_conn_manager()
|
||||
.add_connector(RingTunnelConnector::new(
|
||||
format!("ring://{}", center.id()).parse().unwrap(),
|
||||
));
|
||||
insts[dst_idx]
|
||||
.get_conn_manager()
|
||||
.add_connector(RingTunnelConnector::new(
|
||||
format!("ring://{}", center.id()).parse().unwrap(),
|
||||
));
|
||||
|
||||
wait_for_condition(
|
||||
|| async {
|
||||
insts[0].get_peer_manager().list_routes().await.len() >= 2
|
||||
&& insts[dst_idx].get_peer_manager().list_routes().await.len() >= 2
|
||||
},
|
||||
Duration::from_secs(8),
|
||||
)
|
||||
.await;
|
||||
|
||||
wait_proxy_route_appear(
|
||||
&insts[0].get_peer_manager(),
|
||||
"10.144.144.3/24",
|
||||
insts[dst_idx].peer_id(),
|
||||
"10.1.2.0/24",
|
||||
)
|
||||
.await;
|
||||
|
||||
subnet_proxy_test_icmp("10.1.2.4", Duration::from_secs(8)).await;
|
||||
subnet_proxy_test_tcp("10.1.2.4", "10.1.2.4", Duration::from_secs(8)).await;
|
||||
subnet_proxy_test_udp("10.1.2.4", "10.1.2.4", Duration::from_secs(8)).await;
|
||||
|
||||
assert_tcp_proxy_metric_has_protocol(&insts[0], transport, 1);
|
||||
for receiver in &mut shared_events {
|
||||
assert_no_tun_fallback_event(receiver, Duration::from_secs(2)).await;
|
||||
}
|
||||
|
||||
let mut all_insts = vec![center];
|
||||
all_insts.extend(insts);
|
||||
drop_insts(all_insts).await;
|
||||
}
|
||||
|
||||
async fn ping_test(from_netns: &str, target_ip: &str, payload_size: Option<usize>) -> bool {
|
||||
let _g = NetNS::new(Some(ROOT_NETNS_NAME.to_owned())).guard();
|
||||
let code = tokio::process::Command::new("ip")
|
||||
@@ -994,6 +1252,695 @@ pub async fn foreign_network_forward_nic_data() {
|
||||
drop_insts(vec![center_inst, inst1, inst2]).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial_test::serial]
|
||||
pub async fn shared_tun_same_namespace_real_tun() {
|
||||
prepare_linux_namespaces();
|
||||
|
||||
let center_cfg = get_inst_config("center", Some("net_a"), "10.144.144.1", "fd00::1/64");
|
||||
center_cfg.set_listeners(vec![]);
|
||||
let mut center = Instance::new(center_cfg);
|
||||
|
||||
let shared_cfg_1 = get_inst_config("shared_1", Some("net_b"), "10.144.144.2", "fd00::2/64");
|
||||
shared_cfg_1.set_listeners(vec![]);
|
||||
shared_cfg_1.set_socks5_portal(None);
|
||||
let mut shared_flags = shared_cfg_1.get_flags();
|
||||
shared_flags.dev_name = "et_shared0".to_string();
|
||||
shared_cfg_1.set_flags(shared_flags.clone());
|
||||
let mut shared_1 = Instance::new(shared_cfg_1);
|
||||
|
||||
let shared_cfg_2 = get_inst_config("shared_2", Some("net_b"), "10.144.144.3", "fd00::3/64");
|
||||
shared_cfg_2.set_listeners(vec![]);
|
||||
shared_cfg_2.set_socks5_portal(None);
|
||||
shared_cfg_2.set_flags(shared_flags);
|
||||
let mut shared_2 = Instance::new(shared_cfg_2);
|
||||
|
||||
let remote_cfg = get_inst_config("remote", Some("net_c"), "10.144.144.4", "fd00::4/64");
|
||||
remote_cfg.set_listeners(vec![]);
|
||||
let mut remote = Instance::new(remote_cfg);
|
||||
|
||||
let mut shared_1_events = shared_1.get_global_ctx().subscribe();
|
||||
let mut shared_2_events = shared_2.get_global_ctx().subscribe();
|
||||
|
||||
center.run().await.unwrap();
|
||||
shared_1.run().await.unwrap();
|
||||
shared_2.run().await.unwrap();
|
||||
remote.run().await.unwrap();
|
||||
|
||||
let shared_1_tun = wait_for_tun_ready_event(&mut shared_1_events).await;
|
||||
let shared_2_tun = wait_for_tun_ready_event(&mut shared_2_events).await;
|
||||
assert_eq!(shared_1_tun, shared_2_tun);
|
||||
|
||||
shared_1
|
||||
.get_conn_manager()
|
||||
.add_connector(RingTunnelConnector::new(
|
||||
format!("ring://{}", center.id()).parse().unwrap(),
|
||||
));
|
||||
shared_2
|
||||
.get_conn_manager()
|
||||
.add_connector(RingTunnelConnector::new(
|
||||
format!("ring://{}", center.id()).parse().unwrap(),
|
||||
));
|
||||
remote
|
||||
.get_conn_manager()
|
||||
.add_connector(RingTunnelConnector::new(
|
||||
format!("ring://{}", center.id()).parse().unwrap(),
|
||||
));
|
||||
|
||||
wait_for_condition(
|
||||
|| async {
|
||||
shared_1.get_peer_manager().list_routes().await.len() == 3
|
||||
&& shared_2.get_peer_manager().list_routes().await.len() == 3
|
||||
&& remote.get_peer_manager().list_routes().await.len() == 3
|
||||
},
|
||||
Duration::from_secs(8),
|
||||
)
|
||||
.await;
|
||||
|
||||
wait_for_condition(
|
||||
|| async { ping_test("net_c", "10.144.144.2", None).await },
|
||||
Duration::from_secs(8),
|
||||
)
|
||||
.await;
|
||||
wait_for_condition(
|
||||
|| async { ping_test("net_c", "10.144.144.3", None).await },
|
||||
Duration::from_secs(8),
|
||||
)
|
||||
.await;
|
||||
wait_for_condition(
|
||||
|| async { ping_test("net_b", "10.144.144.4", None).await },
|
||||
Duration::from_secs(8),
|
||||
)
|
||||
.await;
|
||||
wait_for_condition(
|
||||
|| async { ping6_test("net_c", "fd00::2", None).await },
|
||||
Duration::from_secs(8),
|
||||
)
|
||||
.await;
|
||||
wait_for_condition(
|
||||
|| async { ping6_test("net_c", "fd00::3", None).await },
|
||||
Duration::from_secs(8),
|
||||
)
|
||||
.await;
|
||||
wait_for_condition(
|
||||
|| async { ping6_test("net_b", "fd00::4", None).await },
|
||||
Duration::from_secs(8),
|
||||
)
|
||||
.await;
|
||||
|
||||
drop_insts(vec![center, shared_1, shared_2, remote]).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial_test::serial]
|
||||
pub async fn shared_tun_dev_name_mismatch_falls_back_to_dedicated_tun() {
|
||||
prepare_linux_namespaces();
|
||||
|
||||
let shared_cfg_1 = get_inst_config("shared_1", Some("net_b"), "10.144.144.2", "fd00::2/64");
|
||||
shared_cfg_1.set_listeners(vec![]);
|
||||
shared_cfg_1.set_socks5_portal(None);
|
||||
let mut flags_1 = shared_cfg_1.get_flags();
|
||||
flags_1.dev_name = "et_sdm0".to_string();
|
||||
shared_cfg_1.set_flags(flags_1);
|
||||
let mut shared_1 = Instance::new(shared_cfg_1);
|
||||
|
||||
let shared_cfg_2 = get_inst_config("shared_2", Some("net_b"), "10.144.144.3", "fd00::3/64");
|
||||
shared_cfg_2.set_listeners(vec![]);
|
||||
shared_cfg_2.set_socks5_portal(None);
|
||||
let mut flags_2 = shared_cfg_2.get_flags();
|
||||
flags_2.dev_name = "et_sdm1".to_string();
|
||||
shared_cfg_2.set_flags(flags_2);
|
||||
let mut shared_2 = Instance::new(shared_cfg_2);
|
||||
|
||||
let mut shared_1_events = shared_1.get_global_ctx().subscribe();
|
||||
let mut shared_2_events = shared_2.get_global_ctx().subscribe();
|
||||
|
||||
shared_1.run().await.unwrap();
|
||||
shared_2.run().await.unwrap();
|
||||
|
||||
let ifname = wait_for_tun_ready_event(&mut shared_1_events).await;
|
||||
assert_eq!(ifname, "et_sdm0");
|
||||
|
||||
let reason = wait_for_tun_fallback_event(&mut shared_2_events).await;
|
||||
assert!(reason.contains("does not match requested dev_name"));
|
||||
wait_for_condition(
|
||||
|| async { link_exists_in_netns("net_b", "et_sdm1").await },
|
||||
Duration::from_secs(8),
|
||||
)
|
||||
.await;
|
||||
assert_no_tun_fallback_event(&mut shared_1_events, Duration::from_secs(2)).await;
|
||||
|
||||
drop_insts(vec![shared_1, shared_2]).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial_test::serial]
|
||||
pub async fn shared_tun_cleans_up_device_after_last_member_leaves() {
|
||||
prepare_linux_namespaces();
|
||||
|
||||
let shared_cfg_1 = get_inst_config("shared_1", Some("net_b"), "10.144.144.2", "fd00::2/64");
|
||||
shared_cfg_1.set_listeners(vec![]);
|
||||
shared_cfg_1.set_socks5_portal(None);
|
||||
let mut shared_flags = shared_cfg_1.get_flags();
|
||||
shared_flags.dev_name = "et_shared_gc0".to_string();
|
||||
shared_cfg_1.set_flags(shared_flags.clone());
|
||||
let mut shared_1 = Instance::new(shared_cfg_1);
|
||||
|
||||
let shared_cfg_2 = get_inst_config("shared_2", Some("net_b"), "10.144.144.3", "fd00::3/64");
|
||||
shared_cfg_2.set_listeners(vec![]);
|
||||
shared_cfg_2.set_socks5_portal(None);
|
||||
shared_cfg_2.set_flags(shared_flags);
|
||||
let mut shared_2 = Instance::new(shared_cfg_2);
|
||||
|
||||
let mut shared_1_events = shared_1.get_global_ctx().subscribe();
|
||||
let mut shared_2_events = shared_2.get_global_ctx().subscribe();
|
||||
|
||||
shared_1.run().await.unwrap();
|
||||
shared_2.run().await.unwrap();
|
||||
|
||||
let ifname = wait_for_tun_ready_event(&mut shared_1_events).await;
|
||||
assert_eq!(ifname, wait_for_tun_ready_event(&mut shared_2_events).await);
|
||||
assert!(link_exists_in_netns("net_b", &ifname).await);
|
||||
|
||||
shared_1.clear_resources().await;
|
||||
drop(shared_1);
|
||||
wait_for_condition(
|
||||
|| async { link_exists_in_netns("net_b", &ifname).await },
|
||||
Duration::from_secs(5),
|
||||
)
|
||||
.await;
|
||||
|
||||
shared_2.clear_resources().await;
|
||||
drop(shared_2);
|
||||
wait_for_condition(
|
||||
|| async { !link_exists_in_netns("net_b", &ifname).await },
|
||||
Duration::from_secs(8),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial_test::serial]
|
||||
pub async fn shared_tun_proxy_cidr_same_namespace_real_tun() {
|
||||
prepare_linux_namespaces();
|
||||
|
||||
let center_cfg = get_inst_config("center", Some("net_a"), "10.144.144.1", "fd00::1/64");
|
||||
center_cfg.set_listeners(vec![]);
|
||||
let mut center = Instance::new(center_cfg);
|
||||
|
||||
let shared_cfg_1 = get_inst_config("shared_1", Some("net_c"), "10.144.144.2", "fd00::2/64");
|
||||
shared_cfg_1.set_listeners(vec![]);
|
||||
shared_cfg_1.set_socks5_portal(None);
|
||||
shared_cfg_1
|
||||
.add_proxy_cidr("10.1.2.0/24".parse().unwrap(), None)
|
||||
.unwrap();
|
||||
let mut shared_flags = shared_cfg_1.get_flags();
|
||||
shared_flags.dev_name = "et_shp0".to_string();
|
||||
shared_cfg_1.set_flags(shared_flags.clone());
|
||||
let mut shared_1 = Instance::new(shared_cfg_1);
|
||||
|
||||
let shared_cfg_2 = get_inst_config("shared_2", Some("net_c"), "10.144.144.3", "fd00::3/64");
|
||||
shared_cfg_2.set_listeners(vec![]);
|
||||
shared_cfg_2.set_socks5_portal(None);
|
||||
shared_cfg_2.set_flags(shared_flags);
|
||||
let mut shared_2 = Instance::new(shared_cfg_2);
|
||||
|
||||
let remote_cfg = get_inst_config("remote", Some("net_b"), "10.144.144.4", "fd00::4/64");
|
||||
remote_cfg.set_listeners(vec![]);
|
||||
let mut remote = Instance::new(remote_cfg);
|
||||
|
||||
let mut shared_1_events = shared_1.get_global_ctx().subscribe();
|
||||
let mut shared_2_events = shared_2.get_global_ctx().subscribe();
|
||||
|
||||
center.run().await.unwrap();
|
||||
shared_1.run().await.unwrap();
|
||||
shared_2.run().await.unwrap();
|
||||
remote.run().await.unwrap();
|
||||
|
||||
let shared_1_tun = wait_for_tun_ready_event(&mut shared_1_events).await;
|
||||
let shared_2_tun = wait_for_tun_ready_event(&mut shared_2_events).await;
|
||||
assert_eq!(shared_1_tun, shared_2_tun);
|
||||
|
||||
shared_1
|
||||
.get_conn_manager()
|
||||
.add_connector(RingTunnelConnector::new(
|
||||
format!("ring://{}", center.id()).parse().unwrap(),
|
||||
));
|
||||
shared_2
|
||||
.get_conn_manager()
|
||||
.add_connector(RingTunnelConnector::new(
|
||||
format!("ring://{}", center.id()).parse().unwrap(),
|
||||
));
|
||||
remote
|
||||
.get_conn_manager()
|
||||
.add_connector(RingTunnelConnector::new(
|
||||
format!("ring://{}", center.id()).parse().unwrap(),
|
||||
));
|
||||
|
||||
wait_for_condition(
|
||||
|| async {
|
||||
shared_1.get_peer_manager().list_routes().await.len() == 3
|
||||
&& shared_2.get_peer_manager().list_routes().await.len() == 3
|
||||
&& remote.get_peer_manager().list_routes().await.len() == 3
|
||||
},
|
||||
Duration::from_secs(8),
|
||||
)
|
||||
.await;
|
||||
|
||||
wait_proxy_route_appear(
|
||||
¢er.get_peer_manager(),
|
||||
"10.144.144.2/24",
|
||||
shared_1.peer_id(),
|
||||
"10.1.2.0/24",
|
||||
)
|
||||
.await;
|
||||
wait_proxy_route_appear(
|
||||
&remote.get_peer_manager(),
|
||||
"10.144.144.2/24",
|
||||
shared_1.peer_id(),
|
||||
"10.1.2.0/24",
|
||||
)
|
||||
.await;
|
||||
|
||||
wait_for_condition(
|
||||
|| async { ping_test("net_a", "10.1.2.4", None).await },
|
||||
Duration::from_secs(8),
|
||||
)
|
||||
.await;
|
||||
wait_for_condition(
|
||||
|| async { ping_test("net_b", "10.1.2.4", None).await },
|
||||
Duration::from_secs(8),
|
||||
)
|
||||
.await;
|
||||
|
||||
assert_no_tun_fallback_event(&mut shared_1_events, Duration::from_secs(2)).await;
|
||||
assert_no_tun_fallback_event(&mut shared_2_events, Duration::from_secs(2)).await;
|
||||
|
||||
drop_insts(vec![center, shared_1, shared_2, remote]).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial_test::serial]
|
||||
pub async fn shared_tun_dhcp_same_namespace_real_tun() {
|
||||
prepare_linux_namespaces();
|
||||
|
||||
let center_cfg = get_inst_config("center", Some("net_a"), "10.144.144.1", "fd00::1/64");
|
||||
center_cfg.set_listeners(vec![]);
|
||||
let mut center = Instance::new(center_cfg);
|
||||
|
||||
let dhcp_cfg_1 = get_inst_config("dhcp_1", Some("net_b"), "10.144.144.2", "fd00::2/64");
|
||||
dhcp_cfg_1.set_listeners(vec![]);
|
||||
dhcp_cfg_1.set_socks5_portal(None);
|
||||
dhcp_cfg_1.set_ipv4(None);
|
||||
dhcp_cfg_1.set_dhcp(true);
|
||||
let mut dhcp_flags = dhcp_cfg_1.get_flags();
|
||||
dhcp_flags.dev_name = "et_shdh0".to_string();
|
||||
dhcp_cfg_1.set_flags(dhcp_flags.clone());
|
||||
let mut dhcp_1 = Instance::new(dhcp_cfg_1);
|
||||
|
||||
let dhcp_cfg_2 = get_inst_config("dhcp_2", Some("net_b"), "10.144.144.3", "fd00::3/64");
|
||||
dhcp_cfg_2.set_listeners(vec![]);
|
||||
dhcp_cfg_2.set_socks5_portal(None);
|
||||
dhcp_cfg_2.set_ipv4(None);
|
||||
dhcp_cfg_2.set_dhcp(true);
|
||||
dhcp_cfg_2.set_flags(dhcp_flags);
|
||||
let mut dhcp_2 = Instance::new(dhcp_cfg_2);
|
||||
|
||||
let remote_cfg = get_inst_config("remote", Some("net_c"), "10.144.144.4", "fd00::4/64");
|
||||
remote_cfg.set_listeners(vec![]);
|
||||
let mut remote = Instance::new(remote_cfg);
|
||||
|
||||
let mut dhcp_1_tun_events = dhcp_1.get_global_ctx().subscribe();
|
||||
let mut dhcp_2_tun_events = dhcp_2.get_global_ctx().subscribe();
|
||||
let mut dhcp_1_dhcp_events = dhcp_1.get_global_ctx().subscribe();
|
||||
let mut dhcp_2_dhcp_events = dhcp_2.get_global_ctx().subscribe();
|
||||
|
||||
center.run().await.unwrap();
|
||||
dhcp_1.run().await.unwrap();
|
||||
|
||||
dhcp_1
|
||||
.get_conn_manager()
|
||||
.add_connector(RingTunnelConnector::new(
|
||||
format!("ring://{}", center.id()).parse().unwrap(),
|
||||
));
|
||||
|
||||
let dhcp_1_tun = wait_for_tun_ready_event(&mut dhcp_1_tun_events).await;
|
||||
let dhcp_1_ip = wait_for_dhcp_ipv4_changed_event(&mut dhcp_1_dhcp_events).await;
|
||||
|
||||
wait_for_condition(
|
||||
|| async { dhcp_1.get_peer_manager().list_routes().await.len() == 1 },
|
||||
Duration::from_secs(8),
|
||||
)
|
||||
.await;
|
||||
|
||||
dhcp_2.run().await.unwrap();
|
||||
remote.run().await.unwrap();
|
||||
|
||||
dhcp_2
|
||||
.get_conn_manager()
|
||||
.add_connector(RingTunnelConnector::new(
|
||||
format!("ring://{}", center.id()).parse().unwrap(),
|
||||
));
|
||||
remote
|
||||
.get_conn_manager()
|
||||
.add_connector(RingTunnelConnector::new(
|
||||
format!("ring://{}", center.id()).parse().unwrap(),
|
||||
));
|
||||
|
||||
let dhcp_2_tun = wait_for_tun_ready_event(&mut dhcp_2_tun_events).await;
|
||||
let dhcp_2_ip = wait_for_dhcp_ipv4_changed_event(&mut dhcp_2_dhcp_events).await;
|
||||
|
||||
assert_eq!(dhcp_1_tun, dhcp_2_tun);
|
||||
assert_ne!(dhcp_1_ip.address(), dhcp_2_ip.address());
|
||||
assert_eq!(dhcp_1_ip.network(), dhcp_2_ip.network());
|
||||
|
||||
wait_for_condition(
|
||||
|| async {
|
||||
dhcp_1.get_peer_manager().list_routes().await.len() == 3
|
||||
&& dhcp_2.get_peer_manager().list_routes().await.len() == 3
|
||||
&& remote.get_peer_manager().list_routes().await.len() == 3
|
||||
},
|
||||
Duration::from_secs(12),
|
||||
)
|
||||
.await;
|
||||
|
||||
let dhcp_1_ip_str = dhcp_1_ip.address().to_string();
|
||||
let dhcp_2_ip_str = dhcp_2_ip.address().to_string();
|
||||
wait_for_condition(
|
||||
|| async { ping_test("net_c", &dhcp_1_ip_str, None).await },
|
||||
Duration::from_secs(12),
|
||||
)
|
||||
.await;
|
||||
wait_for_condition(
|
||||
|| async { ping_test("net_c", &dhcp_2_ip_str, None).await },
|
||||
Duration::from_secs(12),
|
||||
)
|
||||
.await;
|
||||
wait_for_condition(
|
||||
|| async { ping_test("net_b", "10.144.144.4", None).await },
|
||||
Duration::from_secs(12),
|
||||
)
|
||||
.await;
|
||||
|
||||
assert_no_tun_fallback_event(&mut dhcp_1_tun_events, Duration::from_secs(2)).await;
|
||||
assert_no_tun_fallback_event(&mut dhcp_2_tun_events, Duration::from_secs(2)).await;
|
||||
|
||||
drop_insts(vec![center, dhcp_1, dhcp_2, remote]).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial_test::serial]
|
||||
pub async fn shared_tun_dynamic_proxy_conflict_falls_back() {
|
||||
use crate::proto::api::config::{ConfigPatchAction, InstanceConfigPatch, ProxyNetworkPatch};
|
||||
|
||||
prepare_linux_namespaces();
|
||||
|
||||
let center_cfg = get_inst_config("center", Some("net_a"), "10.144.144.1", "fd00::1/64");
|
||||
center_cfg.set_listeners(vec![]);
|
||||
let mut center = Instance::new(center_cfg);
|
||||
|
||||
let shared_cfg_1 = get_inst_config("shared_1", Some("net_c"), "10.144.144.2", "fd00::2/64");
|
||||
shared_cfg_1.set_listeners(vec![]);
|
||||
shared_cfg_1.set_socks5_portal(None);
|
||||
shared_cfg_1
|
||||
.add_proxy_cidr("10.1.2.0/24".parse().unwrap(), None)
|
||||
.unwrap();
|
||||
let mut shared_flags = shared_cfg_1.get_flags();
|
||||
shared_flags.dev_name = "et_srf0".to_string();
|
||||
shared_cfg_1.set_flags(shared_flags.clone());
|
||||
let mut shared_1 = Instance::new(shared_cfg_1);
|
||||
|
||||
let shared_cfg_2 = get_inst_config("shared_2", Some("net_c"), "10.144.144.3", "fd00::3/64");
|
||||
shared_cfg_2.set_listeners(vec![]);
|
||||
shared_cfg_2.set_socks5_portal(None);
|
||||
shared_cfg_2.set_flags(shared_flags);
|
||||
let mut shared_2 = Instance::new(shared_cfg_2);
|
||||
|
||||
let remote_cfg = get_inst_config("remote", Some("net_b"), "10.144.144.4", "fd00::4/64");
|
||||
remote_cfg.set_listeners(vec![]);
|
||||
let mut remote = Instance::new(remote_cfg);
|
||||
|
||||
let mut shared_1_events = shared_1.get_global_ctx().subscribe();
|
||||
let mut shared_2_events = shared_2.get_global_ctx().subscribe();
|
||||
|
||||
center.run().await.unwrap();
|
||||
shared_1.run().await.unwrap();
|
||||
shared_2.run().await.unwrap();
|
||||
remote.run().await.unwrap();
|
||||
|
||||
let shared_1_tun = wait_for_tun_ready_event(&mut shared_1_events).await;
|
||||
let shared_2_tun = wait_for_tun_ready_event(&mut shared_2_events).await;
|
||||
assert_eq!(shared_1_tun, shared_2_tun);
|
||||
|
||||
shared_1
|
||||
.get_conn_manager()
|
||||
.add_connector(RingTunnelConnector::new(
|
||||
format!("ring://{}", center.id()).parse().unwrap(),
|
||||
));
|
||||
shared_2
|
||||
.get_conn_manager()
|
||||
.add_connector(RingTunnelConnector::new(
|
||||
format!("ring://{}", center.id()).parse().unwrap(),
|
||||
));
|
||||
remote
|
||||
.get_conn_manager()
|
||||
.add_connector(RingTunnelConnector::new(
|
||||
format!("ring://{}", center.id()).parse().unwrap(),
|
||||
));
|
||||
|
||||
wait_for_condition(
|
||||
|| async {
|
||||
shared_1.get_peer_manager().list_routes().await.len() == 3
|
||||
&& shared_2.get_peer_manager().list_routes().await.len() == 3
|
||||
&& remote.get_peer_manager().list_routes().await.len() == 3
|
||||
},
|
||||
Duration::from_secs(8),
|
||||
)
|
||||
.await;
|
||||
|
||||
shared_2
|
||||
.get_config_patcher()
|
||||
.apply_patch(InstanceConfigPatch {
|
||||
proxy_networks: vec![ProxyNetworkPatch {
|
||||
action: ConfigPatchAction::Add as i32,
|
||||
cidr: Some("10.1.2.0/24".parse().unwrap()),
|
||||
mapped_cidr: None,
|
||||
}],
|
||||
..Default::default()
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let reason = wait_for_tun_fallback_event(&mut shared_2_events).await;
|
||||
assert!(reason.contains("route prefix"));
|
||||
wait_for_condition(
|
||||
|| async { ping_test("net_b", "10.1.2.4", None).await },
|
||||
Duration::from_secs(10),
|
||||
)
|
||||
.await;
|
||||
wait_for_condition(
|
||||
|| async { ping_test("net_b", "10.144.144.3", None).await },
|
||||
Duration::from_secs(10),
|
||||
)
|
||||
.await;
|
||||
assert_no_tun_fallback_event(&mut shared_1_events, Duration::from_secs(2)).await;
|
||||
|
||||
drop_insts(vec![center, shared_1, shared_2, remote]).await;
|
||||
}
|
||||
|
||||
#[cfg(feature = "magic-dns")]
|
||||
#[tokio::test]
|
||||
#[serial_test::serial]
|
||||
pub async fn shared_tun_magic_dns_same_namespace_real_tun() {
|
||||
prepare_linux_namespaces();
|
||||
|
||||
let center_cfg = get_inst_config("center", Some("net_a"), "10.144.144.1", "fd00::1/64");
|
||||
center_cfg.set_listeners(vec![]);
|
||||
let mut center = Instance::new(center_cfg);
|
||||
|
||||
let shared_cfg_1 = get_inst_config("shared_1", Some("net_b"), "10.144.144.2", "fd00::2/64");
|
||||
shared_cfg_1.set_listeners(vec![]);
|
||||
shared_cfg_1.set_socks5_portal(None);
|
||||
let mut shared_flags = shared_cfg_1.get_flags();
|
||||
shared_flags.dev_name = "et_shared_dns0".to_string();
|
||||
shared_flags.accept_dns = true;
|
||||
shared_cfg_1.set_flags(shared_flags.clone());
|
||||
let mut shared_1 = Instance::new(shared_cfg_1);
|
||||
|
||||
let shared_cfg_2 = get_inst_config("shared_2", Some("net_b"), "10.144.144.3", "fd00::3/64");
|
||||
shared_cfg_2.set_listeners(vec![]);
|
||||
shared_cfg_2.set_socks5_portal(None);
|
||||
shared_cfg_2.set_flags(shared_flags);
|
||||
let mut shared_2 = Instance::new(shared_cfg_2);
|
||||
|
||||
let remote_cfg = get_inst_config("remote", Some("net_c"), "10.144.144.4", "fd00::4/64");
|
||||
remote_cfg.set_listeners(vec![]);
|
||||
let mut remote = Instance::new(remote_cfg);
|
||||
|
||||
let mut shared_1_events = shared_1.get_global_ctx().subscribe();
|
||||
let mut shared_2_events = shared_2.get_global_ctx().subscribe();
|
||||
|
||||
center.run().await.unwrap();
|
||||
shared_1.run().await.unwrap();
|
||||
shared_2.run().await.unwrap();
|
||||
remote.run().await.unwrap();
|
||||
|
||||
let shared_1_tun = wait_for_tun_ready_event(&mut shared_1_events).await;
|
||||
let shared_2_tun = wait_for_tun_ready_event(&mut shared_2_events).await;
|
||||
assert_eq!(shared_1_tun, shared_2_tun);
|
||||
|
||||
shared_1
|
||||
.get_conn_manager()
|
||||
.add_connector(RingTunnelConnector::new(
|
||||
format!("ring://{}", center.id()).parse().unwrap(),
|
||||
));
|
||||
shared_2
|
||||
.get_conn_manager()
|
||||
.add_connector(RingTunnelConnector::new(
|
||||
format!("ring://{}", center.id()).parse().unwrap(),
|
||||
));
|
||||
remote
|
||||
.get_conn_manager()
|
||||
.add_connector(RingTunnelConnector::new(
|
||||
format!("ring://{}", center.id()).parse().unwrap(),
|
||||
));
|
||||
|
||||
wait_for_condition(
|
||||
|| async {
|
||||
shared_1.get_peer_manager().list_routes().await.len() == 3
|
||||
&& shared_2.get_peer_manager().list_routes().await.len() == 3
|
||||
&& remote.get_peer_manager().list_routes().await.len() == 3
|
||||
},
|
||||
Duration::from_secs(8),
|
||||
)
|
||||
.await;
|
||||
|
||||
wait_for_condition(
|
||||
|| async { ping_test("net_c", "10.144.144.2", None).await },
|
||||
Duration::from_secs(8),
|
||||
)
|
||||
.await;
|
||||
wait_for_condition(
|
||||
|| async { ping_test("net_c", "10.144.144.3", None).await },
|
||||
Duration::from_secs(8),
|
||||
)
|
||||
.await;
|
||||
wait_for_condition(
|
||||
|| async { ping_test("net_b", "10.144.144.4", None).await },
|
||||
Duration::from_secs(8),
|
||||
)
|
||||
.await;
|
||||
let _ = MAGIC_DNS_INSTANCE_ADDR;
|
||||
|
||||
assert_no_tun_fallback_event(&mut shared_1_events, Duration::from_secs(2)).await;
|
||||
assert_no_tun_fallback_event(&mut shared_2_events, Duration::from_secs(2)).await;
|
||||
|
||||
drop_insts(vec![center, shared_1, shared_2, remote]).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial_test::serial]
|
||||
pub async fn shared_tun_kcp_proxy_with_source_shared_tun() {
|
||||
shared_tun_subnet_proxy_transport_test(TcpProxyEntryTransportType::Kcp, true).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial_test::serial]
|
||||
pub async fn shared_tun_quic_proxy_with_source_shared_tun() {
|
||||
shared_tun_subnet_proxy_transport_test(TcpProxyEntryTransportType::Quic, true).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial_test::serial]
|
||||
pub async fn shared_tun_kcp_proxy_with_destination_shared_tun() {
|
||||
shared_tun_subnet_proxy_transport_test(TcpProxyEntryTransportType::Kcp, false).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial_test::serial]
|
||||
pub async fn shared_tun_quic_proxy_with_destination_shared_tun() {
|
||||
shared_tun_subnet_proxy_transport_test(TcpProxyEntryTransportType::Quic, false).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial_test::serial]
|
||||
pub async fn same_namespace_no_tun_skips_shared_tun_and_keeps_connectivity() {
|
||||
prepare_linux_namespaces();
|
||||
|
||||
let center_cfg = get_inst_config("center", Some("net_a"), "10.144.144.1", "fd00::1/64");
|
||||
center_cfg.set_listeners(vec![]);
|
||||
let mut center = Instance::new(center_cfg);
|
||||
|
||||
let no_tun_cfg_1 = get_inst_config("no_tun_1", Some("net_b"), "10.144.144.2", "fd00::2/64");
|
||||
no_tun_cfg_1.set_listeners(vec![]);
|
||||
no_tun_cfg_1.set_socks5_portal(None);
|
||||
let mut no_tun_flags = no_tun_cfg_1.get_flags();
|
||||
no_tun_flags.dev_name = "et_shared_disabled0".to_string();
|
||||
no_tun_flags.no_tun = true;
|
||||
no_tun_cfg_1.set_flags(no_tun_flags.clone());
|
||||
let mut no_tun_1 = Instance::new(no_tun_cfg_1);
|
||||
|
||||
let no_tun_cfg_2 = get_inst_config("no_tun_2", Some("net_b"), "10.144.144.3", "fd00::3/64");
|
||||
no_tun_cfg_2.set_listeners(vec![]);
|
||||
no_tun_cfg_2.set_socks5_portal(None);
|
||||
no_tun_cfg_2.set_flags(no_tun_flags);
|
||||
let mut no_tun_2 = Instance::new(no_tun_cfg_2);
|
||||
|
||||
let remote_cfg = get_inst_config("remote", Some("net_c"), "10.144.144.4", "fd00::4/64");
|
||||
remote_cfg.set_listeners(vec![]);
|
||||
let mut remote = Instance::new(remote_cfg);
|
||||
|
||||
let mut no_tun_1_events = no_tun_1.get_global_ctx().subscribe();
|
||||
let mut no_tun_2_events = no_tun_2.get_global_ctx().subscribe();
|
||||
|
||||
center.run().await.unwrap();
|
||||
no_tun_1.run().await.unwrap();
|
||||
no_tun_2.run().await.unwrap();
|
||||
remote.run().await.unwrap();
|
||||
|
||||
assert_no_tun_ready_event(&mut no_tun_1_events, Duration::from_secs(2)).await;
|
||||
assert_no_tun_ready_event(&mut no_tun_2_events, Duration::from_secs(2)).await;
|
||||
|
||||
no_tun_1
|
||||
.get_conn_manager()
|
||||
.add_connector(RingTunnelConnector::new(
|
||||
format!("ring://{}", center.id()).parse().unwrap(),
|
||||
));
|
||||
no_tun_2
|
||||
.get_conn_manager()
|
||||
.add_connector(RingTunnelConnector::new(
|
||||
format!("ring://{}", center.id()).parse().unwrap(),
|
||||
));
|
||||
remote
|
||||
.get_conn_manager()
|
||||
.add_connector(RingTunnelConnector::new(
|
||||
format!("ring://{}", center.id()).parse().unwrap(),
|
||||
));
|
||||
|
||||
wait_for_condition(
|
||||
|| async {
|
||||
no_tun_1.get_peer_manager().list_routes().await.len() == 3
|
||||
&& no_tun_2.get_peer_manager().list_routes().await.len() == 3
|
||||
&& remote.get_peer_manager().list_routes().await.len() == 3
|
||||
},
|
||||
Duration::from_secs(8),
|
||||
)
|
||||
.await;
|
||||
|
||||
wait_for_condition(
|
||||
|| async { ping_test("net_c", "10.144.144.2", None).await },
|
||||
Duration::from_secs(8),
|
||||
)
|
||||
.await;
|
||||
wait_for_condition(
|
||||
|| async { ping_test("net_c", "10.144.144.3", None).await },
|
||||
Duration::from_secs(8),
|
||||
)
|
||||
.await;
|
||||
|
||||
drop_insts(vec![center, no_tun_1, no_tun_2, remote]).await;
|
||||
}
|
||||
|
||||
use std::{net::SocketAddr, str::FromStr};
|
||||
|
||||
use defguard_wireguard_rs::{
|
||||
|
||||
Reference in New Issue
Block a user