mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-05-07 02:09:06 +00:00
fix: avoid panic when validating mapped listeners (#2153)
This commit is contained in:
@@ -21,7 +21,7 @@ use crate::{
|
|||||||
api::manage::ConfigSource as RpcConfigSource,
|
api::manage::ConfigSource as RpcConfigSource,
|
||||||
common::{CompressionAlgoPb, PortForwardConfigPb, SecureModeConfig, SocketType},
|
common::{CompressionAlgoPb, PortForwardConfigPb, SecureModeConfig, SocketType},
|
||||||
},
|
},
|
||||||
tunnel::generate_digest_from_str,
|
tunnel::{IpScheme, TunnelScheme, generate_digest_from_str},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::env_parser;
|
use super::env_parser;
|
||||||
@@ -74,6 +74,36 @@ pub fn gen_default_flags() -> Flags {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn mapped_listener_allows_implicit_port(url: &url::Url) -> bool {
|
||||||
|
TunnelScheme::try_from(url)
|
||||||
|
.ok()
|
||||||
|
.and_then(|scheme| IpScheme::try_from(scheme).ok())
|
||||||
|
.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn validate_mapped_listener_url(url: &url::Url) -> Result<(), anyhow::Error> {
|
||||||
|
if url.port().is_none() && !mapped_listener_allows_implicit_port(url) {
|
||||||
|
anyhow::bail!("mapped listener port is missing: {}", url);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_mapped_listener_urls(
|
||||||
|
mapped_listeners: &[String],
|
||||||
|
) -> Result<Vec<url::Url>, anyhow::Error> {
|
||||||
|
mapped_listeners
|
||||||
|
.iter()
|
||||||
|
.map(|s| {
|
||||||
|
let url: url::Url = s
|
||||||
|
.parse()
|
||||||
|
.with_context(|| format!("mapped listener is not a valid url: {}", s))?;
|
||||||
|
validate_mapped_listener_url(&url)?;
|
||||||
|
Ok(url)
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Display, EnumString, VariantArray)]
|
#[derive(Debug, Clone, PartialEq, Eq, Display, EnumString, VariantArray)]
|
||||||
#[strum(ascii_case_insensitive)]
|
#[strum(ascii_case_insensitive)]
|
||||||
pub enum EncryptionAlgorithm {
|
pub enum EncryptionAlgorithm {
|
||||||
@@ -1226,6 +1256,37 @@ stun_servers = [
|
|||||||
assert_eq!(loaded.get_network_config_source(), ConfigSource::Webhook);
|
assert_eq!(loaded.get_network_config_source(), ConfigSource::Webhook);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_mapped_listener_urls_allows_ws_without_port() {
|
||||||
|
let parsed = parse_mapped_listener_urls(&[
|
||||||
|
"ws://example.com".to_string(),
|
||||||
|
"wss://example.com/path".to_string(),
|
||||||
|
])
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(parsed.len(), 2);
|
||||||
|
assert_eq!(parsed[0].scheme(), "ws");
|
||||||
|
assert_eq!(parsed[0].port(), None);
|
||||||
|
assert_eq!(parsed[1].scheme(), "wss");
|
||||||
|
assert_eq!(parsed[1].port(), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_mapped_listener_urls_allows_tcp_without_port() {
|
||||||
|
let parsed = parse_mapped_listener_urls(&["tcp://127.0.0.1".to_string()]).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(parsed.len(), 1);
|
||||||
|
assert_eq!(parsed[0].scheme(), "tcp");
|
||||||
|
assert_eq!(parsed[0].port(), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_mapped_listener_urls_requires_port_for_non_ip_scheme() {
|
||||||
|
let err = parse_mapped_listener_urls(&["ring://peer-id".to_string()]).unwrap_err();
|
||||||
|
|
||||||
|
assert!(err.to_string().contains("mapped listener port is missing"));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_network_config_source_user_is_implicit() {
|
fn test_network_config_source_user_is_implicit() {
|
||||||
let config = TomlConfigLoader::default();
|
let config = TomlConfigLoader::default();
|
||||||
|
|||||||
@@ -51,6 +51,19 @@ pub const DIRECT_CONNECTOR_BLACKLIST_TIMEOUT_SEC: u64 = 300;
|
|||||||
|
|
||||||
static TESTING: AtomicBool = AtomicBool::new(false);
|
static TESTING: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
|
fn mapped_listener_port(url: &url::Url) -> Option<u16> {
|
||||||
|
url.port().or_else(|| {
|
||||||
|
TunnelScheme::try_from(url)
|
||||||
|
.ok()
|
||||||
|
.and_then(|scheme| IpScheme::try_from(scheme).ok())
|
||||||
|
.map(IpScheme::default_port)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn resolve_mapped_listener_addrs(listener: &url::Url) -> Result<Vec<SocketAddr>, Error> {
|
||||||
|
socket_addrs(listener, || mapped_listener_port(listener)).await
|
||||||
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
pub trait PeerManagerForDirectConnector {
|
pub trait PeerManagerForDirectConnector {
|
||||||
async fn list_peers(&self) -> Vec<PeerId>;
|
async fn list_peers(&self) -> Vec<PeerId>;
|
||||||
@@ -132,7 +145,7 @@ impl DirectConnectorManagerData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let global_ctx = self.peer_manager.get_global_ctx();
|
let global_ctx = self.peer_manager.get_global_ctx();
|
||||||
let listener_port = remote_url.port().ok_or(anyhow::anyhow!(
|
let listener_port = mapped_listener_port(remote_url).ok_or(anyhow::anyhow!(
|
||||||
"failed to parse port from remote url: {}",
|
"failed to parse port from remote url: {}",
|
||||||
remote_url
|
remote_url
|
||||||
))?;
|
))?;
|
||||||
@@ -382,7 +395,7 @@ impl DirectConnectorManagerData {
|
|||||||
listener: &url::Url,
|
listener: &url::Url,
|
||||||
tasks: &mut JoinSet<Result<(), Error>>,
|
tasks: &mut JoinSet<Result<(), Error>>,
|
||||||
) {
|
) {
|
||||||
let Ok(mut addrs) = socket_addrs(listener, || None).await else {
|
let Ok(mut addrs) = resolve_mapped_listener_addrs(listener).await else {
|
||||||
tracing::error!(?listener, "failed to parse socket address from listener");
|
tracing::error!(?listener, "failed to parse socket address from listener");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
@@ -536,7 +549,7 @@ impl DirectConnectorManagerData {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.map(Into::<url::Url>::into)
|
.map(Into::<url::Url>::into)
|
||||||
.filter_map(|l| if l.scheme() != "ring" { Some(l) } else { None })
|
.filter_map(|l| if l.scheme() != "ring" { Some(l) } else { None })
|
||||||
.filter(|l| l.port().is_some() && l.host().is_some())
|
.filter(|l| mapped_listener_port(l).is_some() && l.host().is_some())
|
||||||
.filter(|l| enable_ipv6 || !matches!(l.host().unwrap().to_owned(), Host::Ipv6(_)))
|
.filter(|l| enable_ipv6 || !matches!(l.host().unwrap().to_owned(), Host::Ipv6(_)))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
@@ -762,6 +775,17 @@ impl DirectConnectorManager {
|
|||||||
pub fn run_as_client(&mut self) {
|
pub fn run_as_client(&mut self) {
|
||||||
self.client.start();
|
self.client.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub(crate) async fn try_direct_connect_with_ip_list(
|
||||||
|
&self,
|
||||||
|
dst_peer_id: PeerId,
|
||||||
|
ip_list: GetIpListResponse,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
self.data
|
||||||
|
.do_try_direct_connect_internal(dst_peer_id, ip_list)
|
||||||
|
.await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -780,10 +804,53 @@ mod tests {
|
|||||||
proto::peer_rpc::GetIpListResponse,
|
proto::peer_rpc::GetIpListResponse,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::TESTING;
|
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||||
|
|
||||||
|
use super::{TESTING, mapped_listener_port, resolve_mapped_listener_addrs};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mapped_listener_port_uses_ip_scheme_defaults() {
|
||||||
|
assert_eq!(
|
||||||
|
mapped_listener_port(&"ws://example.com".parse().unwrap()),
|
||||||
|
Some(80)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
mapped_listener_port(&"wss://example.com".parse().unwrap()),
|
||||||
|
Some(443)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
mapped_listener_port(&"tcp://127.0.0.1".parse().unwrap()),
|
||||||
|
Some(11010)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
mapped_listener_port(&"udp://127.0.0.1".parse().unwrap()),
|
||||||
|
Some(11010)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn direct_connector_mapped_listener() {
|
async fn resolve_mapped_listener_addrs_uses_default_ports() {
|
||||||
|
let wss_addrs = resolve_mapped_listener_addrs(&"wss://127.0.0.1".parse().unwrap())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
wss_addrs,
|
||||||
|
vec![SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 443)]
|
||||||
|
);
|
||||||
|
|
||||||
|
let tcp_addrs = resolve_mapped_listener_addrs(&"tcp://127.0.0.1".parse().unwrap())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
tcp_addrs,
|
||||||
|
vec![SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 11010)]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run_direct_connector_mapped_listener_test(
|
||||||
|
mapped_listener: &str,
|
||||||
|
target_listener: &str,
|
||||||
|
) {
|
||||||
TESTING.store(true, std::sync::atomic::Ordering::Relaxed);
|
TESTING.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||||
let p_a = create_mock_peer_manager().await;
|
let p_a = create_mock_peer_manager().await;
|
||||||
let p_b = create_mock_peer_manager().await;
|
let p_b = create_mock_peer_manager().await;
|
||||||
@@ -802,11 +869,11 @@ mod tests {
|
|||||||
|
|
||||||
p_c.get_global_ctx()
|
p_c.get_global_ctx()
|
||||||
.config
|
.config
|
||||||
.set_mapped_listeners(Some(vec!["tcp://127.0.0.1:11334".parse().unwrap()]));
|
.set_mapped_listeners(Some(vec![mapped_listener.parse().unwrap()]));
|
||||||
|
|
||||||
p_x.get_global_ctx()
|
p_x.get_global_ctx()
|
||||||
.config
|
.config
|
||||||
.set_listeners(vec!["tcp://0.0.0.0:11334".parse().unwrap()]);
|
.set_listeners(vec![target_listener.parse().unwrap()]);
|
||||||
let mut lis_x = ListenerManager::new(p_x.get_global_ctx(), p_x.clone());
|
let mut lis_x = ListenerManager::new(p_x.get_global_ctx(), p_x.clone());
|
||||||
lis_x.prepare_listeners().await.unwrap();
|
lis_x.prepare_listeners().await.unwrap();
|
||||||
lis_x.run().await.unwrap();
|
lis_x.run().await.unwrap();
|
||||||
@@ -823,6 +890,12 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn direct_connector_mapped_listener() {
|
||||||
|
run_direct_connector_mapped_listener_test("tcp://127.0.0.1:11334", "tcp://0.0.0.0:11334")
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
#[rstest::rstest]
|
#[rstest::rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn direct_connector_basic_test(
|
async fn direct_connector_basic_test(
|
||||||
|
|||||||
+3
-27
@@ -6,7 +6,8 @@ use crate::{
|
|||||||
config::{
|
config::{
|
||||||
ConfigFileControl, ConfigLoader, ConsoleLoggerConfig, EncryptionAlgorithm,
|
ConfigFileControl, ConfigLoader, ConsoleLoggerConfig, EncryptionAlgorithm,
|
||||||
FileLoggerConfig, LoggingConfigLoader, NetworkIdentity, PeerConfig, PortForwardConfig,
|
FileLoggerConfig, LoggingConfigLoader, NetworkIdentity, PeerConfig, PortForwardConfig,
|
||||||
TomlConfigLoader, VpnPortalConfig, load_config_from_file, process_secure_mode_cfg,
|
TomlConfigLoader, VpnPortalConfig, load_config_from_file, parse_mapped_listener_urls,
|
||||||
|
process_secure_mode_cfg,
|
||||||
},
|
},
|
||||||
constants::EASYTIER_VERSION,
|
constants::EASYTIER_VERSION,
|
||||||
log,
|
log,
|
||||||
@@ -906,32 +907,7 @@ impl NetworkOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !self.mapped_listeners.is_empty() {
|
if !self.mapped_listeners.is_empty() {
|
||||||
let mut errs = Vec::new();
|
cfg.set_mapped_listeners(Some(parse_mapped_listener_urls(&self.mapped_listeners)?));
|
||||||
cfg.set_mapped_listeners(Some(
|
|
||||||
self.mapped_listeners
|
|
||||||
.iter()
|
|
||||||
.map(|s| {
|
|
||||||
s.parse()
|
|
||||||
.with_context(|| format!("mapped listener is not a valid url: {}", s))
|
|
||||||
.unwrap()
|
|
||||||
})
|
|
||||||
.map(|s: url::Url| {
|
|
||||||
if s.port().is_none() {
|
|
||||||
errs.push(anyhow::anyhow!("mapped listener port is missing: {}", s));
|
|
||||||
}
|
|
||||||
s
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
));
|
|
||||||
if !errs.is_empty() {
|
|
||||||
return Err(anyhow::anyhow!(
|
|
||||||
"{}",
|
|
||||||
errs.iter()
|
|
||||||
.map(|x| format!("{}", x))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join("\n")
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for n in self.proxy_networks.iter() {
|
for n in self.proxy_networks.iter() {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::common::config::{
|
use crate::common::config::{
|
||||||
ConfigFileControl, ConfigSource, PortForwardConfig, process_secure_mode_cfg,
|
ConfigFileControl, ConfigSource, PortForwardConfig, parse_mapped_listener_urls,
|
||||||
|
process_secure_mode_cfg,
|
||||||
};
|
};
|
||||||
use crate::proto::api::{self, manage};
|
use crate::proto::api::{self, manage};
|
||||||
use crate::proto::rpc_types::controller::BaseController;
|
use crate::proto::rpc_types::controller::BaseController;
|
||||||
@@ -671,22 +672,8 @@ impl NetworkConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !self.mapped_listeners.is_empty() {
|
if !self.mapped_listeners.is_empty() {
|
||||||
cfg.set_mapped_listeners(Some(
|
let mapped_listeners = parse_mapped_listener_urls(&self.mapped_listeners)?;
|
||||||
self.mapped_listeners
|
cfg.set_mapped_listeners(Some(mapped_listeners));
|
||||||
.iter()
|
|
||||||
.map(|s| {
|
|
||||||
s.parse()
|
|
||||||
.with_context(|| format!("mapped listener is not a valid url: {}", s))
|
|
||||||
.unwrap()
|
|
||||||
})
|
|
||||||
.map(|s: url::Url| {
|
|
||||||
if s.port().is_none() {
|
|
||||||
panic!("mapped listener port is missing: {}", s);
|
|
||||||
}
|
|
||||||
s
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(credential_file) = self
|
if let Some(credential_file) = self
|
||||||
|
|||||||
@@ -108,6 +108,58 @@ pub fn create_netns(name: &str, ipv4: &str, ipv6: &str) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct TestNetnsGuard {
|
||||||
|
name: String,
|
||||||
|
host_ipv4: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestNetnsGuard {
|
||||||
|
fn run_ip(args: &[&str]) {
|
||||||
|
let status = std::process::Command::new("ip")
|
||||||
|
.args(args)
|
||||||
|
.status()
|
||||||
|
.unwrap();
|
||||||
|
assert!(status.success(), "ip command failed: {:?}", args);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(name: &str, guest_ipv4: &str, guest_ipv6: &str) -> Self {
|
||||||
|
del_netns(name);
|
||||||
|
create_netns(name, guest_ipv4, guest_ipv6);
|
||||||
|
Self {
|
||||||
|
name: name.to_string(),
|
||||||
|
host_ipv4: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_host_ipv4(&mut self, host_ipv4: &str) {
|
||||||
|
Self::run_ip(&[
|
||||||
|
"addr",
|
||||||
|
"add",
|
||||||
|
host_ipv4,
|
||||||
|
"dev",
|
||||||
|
get_host_veth_name(&self.name),
|
||||||
|
]);
|
||||||
|
self.host_ipv4 = Some(host_ipv4.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for TestNetnsGuard {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if let Some(host_ipv4) = self.host_ipv4.as_deref() {
|
||||||
|
let _ = std::process::Command::new("ip")
|
||||||
|
.args([
|
||||||
|
"addr",
|
||||||
|
"del",
|
||||||
|
host_ipv4,
|
||||||
|
"dev",
|
||||||
|
get_host_veth_name(&self.name),
|
||||||
|
])
|
||||||
|
.status();
|
||||||
|
}
|
||||||
|
del_netns(&self.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn prepare_bridge(name: &str) {
|
pub fn prepare_bridge(name: &str) {
|
||||||
// del bridge with brctl
|
// del bridge with brctl
|
||||||
let _ = std::process::Command::new("brctl")
|
let _ = std::process::Command::new("brctl")
|
||||||
|
|||||||
@@ -258,6 +258,102 @@ pub async fn drop_insts(insts: Vec<Instance>) {
|
|||||||
while set.join_next().await.is_some() {}
|
while set.join_next().await.is_some() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod direct_connector_mapped_listener_tests {
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
common::{
|
||||||
|
config::{ConfigLoader, TomlConfigLoader},
|
||||||
|
global_ctx::GlobalCtx,
|
||||||
|
stun::MockStunInfoCollector,
|
||||||
|
},
|
||||||
|
connector::direct::DirectConnectorManager,
|
||||||
|
instance::listeners::ListenerManager,
|
||||||
|
peers::{
|
||||||
|
create_packet_recv_chan,
|
||||||
|
peer_manager::{PeerManager, RouteAlgoType},
|
||||||
|
tests::{
|
||||||
|
connect_peer_manager, create_mock_peer_manager, wait_route_appear,
|
||||||
|
wait_route_appear_with_cost,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
proto::{common::NatType, peer_rpc::GetIpListResponse},
|
||||||
|
tests::TestNetnsGuard,
|
||||||
|
};
|
||||||
|
|
||||||
|
async fn create_mock_peer_manager_in_netns(netns: &str) -> Arc<PeerManager> {
|
||||||
|
let (s, _r) = create_packet_recv_chan();
|
||||||
|
let config = TomlConfigLoader::default();
|
||||||
|
config.set_netns(Some(netns.to_owned()));
|
||||||
|
let global_ctx = Arc::new(GlobalCtx::new(config));
|
||||||
|
global_ctx.replace_stun_info_collector(Box::new(MockStunInfoCollector {
|
||||||
|
udp_nat_type: NatType::Unknown,
|
||||||
|
}));
|
||||||
|
|
||||||
|
let peer_mgr = Arc::new(PeerManager::new(RouteAlgoType::Ospf, global_ctx, s));
|
||||||
|
peer_mgr.run().await.unwrap();
|
||||||
|
peer_mgr
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run_direct_connector_mapped_listener_without_port_test(
|
||||||
|
mapped_listener: &str,
|
||||||
|
listener: &str,
|
||||||
|
) {
|
||||||
|
let ns_name = "dmlp";
|
||||||
|
let mut _ns = TestNetnsGuard::new(ns_name, "10.199.0.2/24", "fd99::2/64");
|
||||||
|
_ns.set_host_ipv4("10.199.0.1/24");
|
||||||
|
|
||||||
|
let p_a = create_mock_peer_manager().await;
|
||||||
|
let p_b = create_mock_peer_manager().await;
|
||||||
|
let p_c = create_mock_peer_manager_in_netns(ns_name).await;
|
||||||
|
connect_peer_manager(p_a.clone(), p_b.clone()).await;
|
||||||
|
connect_peer_manager(p_b.clone(), p_c.clone()).await;
|
||||||
|
|
||||||
|
wait_route_appear(p_a.clone(), p_c.clone()).await.unwrap();
|
||||||
|
|
||||||
|
let mut f = p_a.get_global_ctx().get_flags();
|
||||||
|
f.bind_device = false;
|
||||||
|
p_a.get_global_ctx().set_flags(f);
|
||||||
|
|
||||||
|
p_c.get_global_ctx()
|
||||||
|
.config
|
||||||
|
.set_mapped_listeners(Some(vec![mapped_listener.parse().unwrap()]));
|
||||||
|
|
||||||
|
p_c.get_global_ctx()
|
||||||
|
.config
|
||||||
|
.set_listeners(vec![listener.parse().unwrap()]);
|
||||||
|
let mut lis_c = ListenerManager::new(p_c.get_global_ctx(), p_c.clone());
|
||||||
|
lis_c.prepare_listeners().await.unwrap();
|
||||||
|
lis_c.run().await.unwrap();
|
||||||
|
|
||||||
|
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
|
||||||
|
let dm_a = DirectConnectorManager::new(p_a.get_global_ctx(), p_a.clone());
|
||||||
|
let mut ip_list = GetIpListResponse::default();
|
||||||
|
ip_list.listeners.push(mapped_listener.parse().unwrap());
|
||||||
|
dm_a.try_direct_connect_with_ip_list(p_c.my_peer_id(), ip_list)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
wait_route_appear_with_cost(p_a.clone(), p_c.my_peer_id(), Some(1))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest::rstest]
|
||||||
|
#[tokio::test]
|
||||||
|
#[serial_test::serial]
|
||||||
|
async fn direct_connector_mapped_listener_without_port(
|
||||||
|
#[values(
|
||||||
|
("tcp://10.199.0.2", "tcp://0.0.0.0:11010"),
|
||||||
|
("ws://10.199.0.2", "ws://0.0.0.0:80"),
|
||||||
|
("wss://10.199.0.2", "wss://0.0.0.0:443")
|
||||||
|
)]
|
||||||
|
case: (&str, &str),
|
||||||
|
) {
|
||||||
|
run_direct_connector_mapped_listener_without_port_test(case.0, case.1).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn ping_test(from_netns: &str, target_ip: &str, payload_size: Option<usize>) -> bool {
|
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 _g = NetNS::new(Some(ROOT_NETNS_NAME.to_owned())).guard();
|
||||||
let code = tokio::process::Command::new("ip")
|
let code = tokio::process::Command::new("ip")
|
||||||
|
|||||||
Reference in New Issue
Block a user