mirror of
https://mirror.suhoan.cn/https://github.com/EasyTier/EasyTier.git
synced 2025-12-12 12:47:25 +08:00
support p2p-only mode (#1598)
This commit is contained in:
@@ -157,6 +157,7 @@ const bool_flags: BoolFlag[] = [
|
|||||||
{ field: 'enable_quic_proxy', help: 'enable_quic_proxy_help' },
|
{ field: 'enable_quic_proxy', help: 'enable_quic_proxy_help' },
|
||||||
{ field: 'disable_quic_input', help: 'disable_quic_input_help' },
|
{ field: 'disable_quic_input', help: 'disable_quic_input_help' },
|
||||||
{ field: 'disable_p2p', help: 'disable_p2p_help' },
|
{ field: 'disable_p2p', help: 'disable_p2p_help' },
|
||||||
|
{ field: 'p2p_only', help: 'p2p_only_help' },
|
||||||
{ field: 'bind_device', help: 'bind_device_help' },
|
{ field: 'bind_device', help: 'bind_device_help' },
|
||||||
{ field: 'no_tun', help: 'no_tun_help' },
|
{ field: 'no_tun', help: 'no_tun_help' },
|
||||||
{ field: 'enable_exit_node', help: 'enable_exit_node_help' },
|
{ field: 'enable_exit_node', help: 'enable_exit_node_help' },
|
||||||
|
|||||||
@@ -106,6 +106,9 @@ disable_quic_input_help: 禁用 QUIC 入站流量,其他开启 QUIC 代理的
|
|||||||
disable_p2p: 禁用 P2P
|
disable_p2p: 禁用 P2P
|
||||||
disable_p2p_help: 禁用 P2P 模式,所有流量通过手动指定的服务器中转。
|
disable_p2p_help: 禁用 P2P 模式,所有流量通过手动指定的服务器中转。
|
||||||
|
|
||||||
|
p2p_only: 仅 P2P
|
||||||
|
p2p_only_help: 仅与已经建立P2P连接的对等节点通信,不通过其他节点中转。
|
||||||
|
|
||||||
bind_device: 仅使用物理网卡
|
bind_device: 仅使用物理网卡
|
||||||
bind_device_help: 仅使用物理网卡,避免 EasyTier 通过其他虚拟网建立连接。
|
bind_device_help: 仅使用物理网卡,避免 EasyTier 通过其他虚拟网建立连接。
|
||||||
|
|
||||||
|
|||||||
@@ -105,6 +105,9 @@ disable_quic_input_help: Disable inbound QUIC traffic, while nodes with QUIC pro
|
|||||||
disable_p2p: Disable P2P
|
disable_p2p: Disable P2P
|
||||||
disable_p2p_help: Disable P2P mode; route all traffic through a manually specified relay server.
|
disable_p2p_help: Disable P2P mode; route all traffic through a manually specified relay server.
|
||||||
|
|
||||||
|
p2p_only: P2P Only
|
||||||
|
p2p_only_help: Only communicate with peers that have already established P2P connections, do not relay through other nodes.
|
||||||
|
|
||||||
bind_device: Bind to Physical Device Only
|
bind_device: Bind to Physical Device Only
|
||||||
bind_device_help: Use only the physical network interface to prevent EasyTier from connecting via virtual networks.
|
bind_device_help: Use only the physical network interface to prevent EasyTier from connecting via virtual networks.
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ export interface NetworkConfig {
|
|||||||
enable_quic_proxy?: boolean
|
enable_quic_proxy?: boolean
|
||||||
disable_quic_input?: boolean
|
disable_quic_input?: boolean
|
||||||
disable_p2p?: boolean
|
disable_p2p?: boolean
|
||||||
|
p2p_only?: boolean
|
||||||
bind_device?: boolean
|
bind_device?: boolean
|
||||||
no_tun?: boolean
|
no_tun?: boolean
|
||||||
enable_exit_node?: boolean
|
enable_exit_node?: boolean
|
||||||
@@ -111,6 +112,7 @@ export function DEFAULT_NETWORK_CONFIG(): NetworkConfig {
|
|||||||
enable_quic_proxy: false,
|
enable_quic_proxy: false,
|
||||||
disable_quic_input: false,
|
disable_quic_input: false,
|
||||||
disable_p2p: false,
|
disable_p2p: false,
|
||||||
|
p2p_only: false,
|
||||||
bind_device: true,
|
bind_device: true,
|
||||||
no_tun: false,
|
no_tun: false,
|
||||||
enable_exit_node: false,
|
enable_exit_node: false,
|
||||||
|
|||||||
@@ -151,6 +151,9 @@ core_clap:
|
|||||||
disable_p2p:
|
disable_p2p:
|
||||||
en: "disable p2p communication, will only relay packets with peers specified by --peers"
|
en: "disable p2p communication, will only relay packets with peers specified by --peers"
|
||||||
zh-CN: "禁用P2P通信,只通过--peers指定的节点转发数据包"
|
zh-CN: "禁用P2P通信,只通过--peers指定的节点转发数据包"
|
||||||
|
p2p_only:
|
||||||
|
en: "only communicate with peers that already establish p2p connection"
|
||||||
|
zh-CN: "仅与已经建立P2P连接的对等节点通信"
|
||||||
disable_udp_hole_punching:
|
disable_udp_hole_punching:
|
||||||
en: "disable udp hole punching"
|
en: "disable udp hole punching"
|
||||||
zh-CN: "禁用UDP打洞功能"
|
zh-CN: "禁用UDP打洞功能"
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ pub fn gen_default_flags() -> Flags {
|
|||||||
use_smoltcp: false,
|
use_smoltcp: false,
|
||||||
relay_network_whitelist: "*".to_string(),
|
relay_network_whitelist: "*".to_string(),
|
||||||
disable_p2p: false,
|
disable_p2p: false,
|
||||||
|
p2p_only: false,
|
||||||
relay_all_peer_rpc: false,
|
relay_all_peer_rpc: false,
|
||||||
disable_udp_hole_punching: false,
|
disable_udp_hole_punching: false,
|
||||||
multi_thread: true,
|
multi_thread: true,
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ pub struct GlobalCtx {
|
|||||||
enable_exit_node: bool,
|
enable_exit_node: bool,
|
||||||
proxy_forward_by_system: bool,
|
proxy_forward_by_system: bool,
|
||||||
no_tun: bool,
|
no_tun: bool,
|
||||||
|
p2p_only: bool,
|
||||||
|
|
||||||
feature_flags: AtomicCell<PeerFeatureFlag>,
|
feature_flags: AtomicCell<PeerFeatureFlag>,
|
||||||
|
|
||||||
@@ -138,6 +139,7 @@ impl GlobalCtx {
|
|||||||
let enable_exit_node = config_fs.get_flags().enable_exit_node || cfg!(target_env = "ohos");
|
let enable_exit_node = config_fs.get_flags().enable_exit_node || cfg!(target_env = "ohos");
|
||||||
let proxy_forward_by_system = config_fs.get_flags().proxy_forward_by_system;
|
let proxy_forward_by_system = config_fs.get_flags().proxy_forward_by_system;
|
||||||
let no_tun = config_fs.get_flags().no_tun;
|
let no_tun = config_fs.get_flags().no_tun;
|
||||||
|
let p2p_only = config_fs.get_flags().p2p_only;
|
||||||
|
|
||||||
let feature_flags = PeerFeatureFlag {
|
let feature_flags = PeerFeatureFlag {
|
||||||
kcp_input: !config_fs.get_flags().disable_kcp_input,
|
kcp_input: !config_fs.get_flags().disable_kcp_input,
|
||||||
@@ -172,6 +174,7 @@ impl GlobalCtx {
|
|||||||
enable_exit_node,
|
enable_exit_node,
|
||||||
proxy_forward_by_system,
|
proxy_forward_by_system,
|
||||||
no_tun,
|
no_tun,
|
||||||
|
p2p_only,
|
||||||
|
|
||||||
feature_flags: AtomicCell::new(feature_flags),
|
feature_flags: AtomicCell::new(feature_flags),
|
||||||
quic_proxy_port: AtomicCell::new(None),
|
quic_proxy_port: AtomicCell::new(None),
|
||||||
@@ -421,6 +424,15 @@ impl GlobalCtx {
|
|||||||
.and_then(|acl_v1| acl_v1.group)
|
.and_then(|acl_v1| acl_v1.group)
|
||||||
.map_or_else(Vec::new, |group| group.declares.to_vec())
|
.map_or_else(Vec::new, |group| group.declares.to_vec())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn p2p_only(&self) -> bool {
|
||||||
|
self.p2p_only
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn latency_first(&self) -> bool {
|
||||||
|
// NOTICE: p2p only is conflict with latency first
|
||||||
|
self.config.get_flags().latency_first && !self.p2p_only
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -420,6 +420,15 @@ struct NetworkOptions {
|
|||||||
)]
|
)]
|
||||||
disable_p2p: Option<bool>,
|
disable_p2p: Option<bool>,
|
||||||
|
|
||||||
|
#[arg(
|
||||||
|
long,
|
||||||
|
env = "ET_P2P_ONLY",
|
||||||
|
help = t!("core_clap.p2p_only").to_string(),
|
||||||
|
num_args = 0..=1,
|
||||||
|
default_missing_value = "true"
|
||||||
|
)]
|
||||||
|
p2p_only: Option<bool>,
|
||||||
|
|
||||||
#[arg(
|
#[arg(
|
||||||
long,
|
long,
|
||||||
env = "ET_DISABLE_UDP_HOLE_PUNCHING",
|
env = "ET_DISABLE_UDP_HOLE_PUNCHING",
|
||||||
@@ -934,6 +943,7 @@ impl NetworkOptions {
|
|||||||
f.relay_network_whitelist = wl.join(" ");
|
f.relay_network_whitelist = wl.join(" ");
|
||||||
}
|
}
|
||||||
f.disable_p2p = self.disable_p2p.unwrap_or(f.disable_p2p);
|
f.disable_p2p = self.disable_p2p.unwrap_or(f.disable_p2p);
|
||||||
|
f.p2p_only = self.p2p_only.unwrap_or(f.p2p_only);
|
||||||
f.disable_udp_hole_punching = self
|
f.disable_udp_hole_punching = self
|
||||||
.disable_udp_hole_punching
|
.disable_udp_hole_punching
|
||||||
.unwrap_or(f.disable_udp_hole_punching);
|
.unwrap_or(f.disable_udp_hole_punching);
|
||||||
|
|||||||
@@ -275,7 +275,7 @@ impl IcmpProxy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let peer_manager = self.peer_manager.clone();
|
let peer_manager = self.peer_manager.clone();
|
||||||
let is_latency_first = self.global_ctx.get_flags().latency_first;
|
let is_latency_first = self.global_ctx.latency_first();
|
||||||
self.tasks.lock().await.spawn(
|
self.tasks.lock().await.spawn(
|
||||||
async move {
|
async move {
|
||||||
while let Some(mut msg) = receiver.recv().await {
|
while let Some(mut msg) = receiver.recv().await {
|
||||||
|
|||||||
@@ -437,7 +437,7 @@ impl UdpProxy {
|
|||||||
// forward packets to peer manager
|
// forward packets to peer manager
|
||||||
let mut receiver = self.receiver.lock().await.take().unwrap();
|
let mut receiver = self.receiver.lock().await.take().unwrap();
|
||||||
let peer_manager = self.peer_manager.clone();
|
let peer_manager = self.peer_manager.clone();
|
||||||
let is_latency_first = self.global_ctx.get_flags().latency_first;
|
let is_latency_first = self.global_ctx.latency_first();
|
||||||
self.tasks.lock().await.spawn(async move {
|
self.tasks.lock().await.spawn(async move {
|
||||||
while let Some(mut msg) = receiver.recv().await {
|
while let Some(mut msg) = receiver.recv().await {
|
||||||
let hdr = msg.mut_peer_manager_header().unwrap();
|
let hdr = msg.mut_peer_manager_header().unwrap();
|
||||||
|
|||||||
@@ -700,6 +700,10 @@ impl NetworkConfig {
|
|||||||
flags.disable_p2p = disable_p2p;
|
flags.disable_p2p = disable_p2p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(p2p_only) = self.p2p_only {
|
||||||
|
flags.p2p_only = p2p_only;
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(bind_device) = self.bind_device {
|
if let Some(bind_device) = self.bind_device {
|
||||||
flags.bind_device = bind_device;
|
flags.bind_device = bind_device;
|
||||||
}
|
}
|
||||||
@@ -874,6 +878,7 @@ impl NetworkConfig {
|
|||||||
result.disable_quic_input = Some(flags.disable_quic_input);
|
result.disable_quic_input = Some(flags.disable_quic_input);
|
||||||
result.quic_listen_port = Some(flags.quic_listen_port as i32);
|
result.quic_listen_port = Some(flags.quic_listen_port as i32);
|
||||||
result.disable_p2p = Some(flags.disable_p2p);
|
result.disable_p2p = Some(flags.disable_p2p);
|
||||||
|
result.p2p_only = Some(flags.p2p_only);
|
||||||
result.bind_device = Some(flags.bind_device);
|
result.bind_device = Some(flags.bind_device);
|
||||||
result.no_tun = Some(flags.no_tun);
|
result.no_tun = Some(flags.no_tun);
|
||||||
result.enable_exit_node = Some(flags.enable_exit_node);
|
result.enable_exit_node = Some(flags.enable_exit_node);
|
||||||
@@ -1109,6 +1114,7 @@ mod tests {
|
|||||||
flags.enable_quic_proxy = rng.gen_bool(0.5);
|
flags.enable_quic_proxy = rng.gen_bool(0.5);
|
||||||
flags.disable_quic_input = rng.gen_bool(0.3);
|
flags.disable_quic_input = rng.gen_bool(0.3);
|
||||||
flags.disable_p2p = rng.gen_bool(0.2);
|
flags.disable_p2p = rng.gen_bool(0.2);
|
||||||
|
flags.p2p_only = rng.gen_bool(0.2);
|
||||||
flags.bind_device = rng.gen_bool(0.3);
|
flags.bind_device = rng.gen_bool(0.3);
|
||||||
flags.no_tun = rng.gen_bool(0.1);
|
flags.no_tun = rng.gen_bool(0.1);
|
||||||
flags.enable_exit_node = rng.gen_bool(0.4);
|
flags.enable_exit_node = rng.gen_bool(0.4);
|
||||||
|
|||||||
@@ -997,11 +997,20 @@ impl PeerManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_p2p_only_before_send(&self, dst_peer_id: PeerId) -> Result<(), Error> {
|
||||||
|
if self.global_ctx.p2p_only() && !self.peers.has_peer(dst_peer_id) {
|
||||||
|
return Err(Error::RouteError(None));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn send_msg_for_proxy(
|
pub async fn send_msg_for_proxy(
|
||||||
&self,
|
&self,
|
||||||
mut msg: ZCPacket,
|
mut msg: ZCPacket,
|
||||||
dst_peer_id: PeerId,
|
dst_peer_id: PeerId,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
|
self.check_p2p_only_before_send(dst_peer_id)?;
|
||||||
|
|
||||||
self.self_tx_counters
|
self.self_tx_counters
|
||||||
.compress_tx_bytes_before
|
.compress_tx_bytes_before
|
||||||
.add(msg.buf_len() as u64);
|
.add(msg.buf_len() as u64);
|
||||||
@@ -1199,7 +1208,7 @@ impl PeerManager {
|
|||||||
.compress_tx_bytes_after
|
.compress_tx_bytes_after
|
||||||
.add(msg.buf_len() as u64);
|
.add(msg.buf_len() as u64);
|
||||||
|
|
||||||
let is_latency_first = self.global_ctx.get_flags().latency_first;
|
let is_latency_first = self.global_ctx.latency_first();
|
||||||
msg.mut_peer_manager_header()
|
msg.mut_peer_manager_header()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.set_latency_first(is_latency_first)
|
.set_latency_first(is_latency_first)
|
||||||
@@ -1209,6 +1218,11 @@ impl PeerManager {
|
|||||||
let mut msg = Some(msg);
|
let mut msg = Some(msg);
|
||||||
let total_dst_peers = dst_peers.len();
|
let total_dst_peers = dst_peers.len();
|
||||||
for (i, peer_id) in dst_peers.iter().enumerate() {
|
for (i, peer_id) in dst_peers.iter().enumerate() {
|
||||||
|
if let Err(e) = self.check_p2p_only_before_send(*peer_id) {
|
||||||
|
errs.push(e);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let mut msg = if i == total_dst_peers - 1 {
|
let mut msg = if i == total_dst_peers - 1 {
|
||||||
msg.take().unwrap()
|
msg.take().unwrap()
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -76,6 +76,8 @@ message NetworkConfig {
|
|||||||
repeated PortForwardConfig port_forwards = 48;
|
repeated PortForwardConfig port_forwards = 48;
|
||||||
|
|
||||||
optional bool disable_sym_hole_punching = 49;
|
optional bool disable_sym_hole_punching = 49;
|
||||||
|
|
||||||
|
optional bool p2p_only = 51;
|
||||||
}
|
}
|
||||||
|
|
||||||
message PortForwardConfig {
|
message PortForwardConfig {
|
||||||
|
|||||||
@@ -60,6 +60,8 @@ message FlagsInConfig {
|
|||||||
|
|
||||||
// tld dns zone for magic dns
|
// tld dns zone for magic dns
|
||||||
string tld_dns_zone = 31;
|
string tld_dns_zone = 31;
|
||||||
|
|
||||||
|
bool p2p_only = 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
message RpcDescriptor {
|
message RpcDescriptor {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use core::panic;
|
use core::panic;
|
||||||
use std::{
|
use std::{
|
||||||
|
future::Future,
|
||||||
sync::{atomic::AtomicU32, Arc},
|
sync::{atomic::AtomicU32, Arc},
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
@@ -1950,6 +1951,107 @@ pub async fn acl_rule_test_subnet_proxy(
|
|||||||
drop_insts(insts).await;
|
drop_insts(insts).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn assert_panics_ext<F, Fut>(f: F, expect_panic: bool)
|
||||||
|
where
|
||||||
|
F: FnOnce() -> Fut + Send + 'static,
|
||||||
|
Fut: Future + Send + 'static,
|
||||||
|
{
|
||||||
|
// Run the async function in a separate task so panics surface as JoinError
|
||||||
|
let res = tokio::spawn(async move {
|
||||||
|
f().await;
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
|
if expect_panic {
|
||||||
|
assert!(
|
||||||
|
res.is_err() && res.as_ref().unwrap_err().is_panic(),
|
||||||
|
"Expected function to panic, but it didn't",
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
assert!(res.is_ok(), "Expected function not to panic, but it did");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest::rstest]
|
||||||
|
#[tokio::test]
|
||||||
|
#[serial_test::serial]
|
||||||
|
pub async fn p2p_only_test(
|
||||||
|
#[values(true, false)] has_p2p_conn: bool,
|
||||||
|
#[values(true, false)] enable_kcp_proxy: bool,
|
||||||
|
#[values(true, false)] enable_quic_proxy: bool,
|
||||||
|
) {
|
||||||
|
use crate::peers::tests::wait_route_appear_with_cost;
|
||||||
|
|
||||||
|
let insts = init_three_node_ex(
|
||||||
|
"udp",
|
||||||
|
|cfg| {
|
||||||
|
if cfg.get_inst_name() == "inst1" {
|
||||||
|
let mut flags = cfg.get_flags();
|
||||||
|
flags.enable_kcp_proxy = enable_kcp_proxy;
|
||||||
|
flags.enable_quic_proxy = enable_quic_proxy;
|
||||||
|
flags.disable_p2p = true;
|
||||||
|
flags.p2p_only = true;
|
||||||
|
cfg.set_flags(flags);
|
||||||
|
} else if cfg.get_inst_name() == "inst3" {
|
||||||
|
// 添加子网代理配置
|
||||||
|
cfg.add_proxy_cidr("10.1.2.0/24".parse().unwrap(), None)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
cfg
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
if has_p2p_conn {
|
||||||
|
insts[2]
|
||||||
|
.get_conn_manager()
|
||||||
|
.add_connector(RingTunnelConnector::new(
|
||||||
|
format!("ring://{}", insts[0].id()).parse().unwrap(),
|
||||||
|
));
|
||||||
|
wait_route_appear_with_cost(
|
||||||
|
insts[2].get_peer_manager(),
|
||||||
|
insts[0].get_peer_manager().my_peer_id(),
|
||||||
|
Some(1),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let target_ip = "10.1.2.4";
|
||||||
|
|
||||||
|
for target_ip in ["10.144.144.3", target_ip] {
|
||||||
|
assert_panics_ext(
|
||||||
|
|| async {
|
||||||
|
subnet_proxy_test_icmp(target_ip).await;
|
||||||
|
},
|
||||||
|
!has_p2p_conn,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let listen_ip = if target_ip == "10.144.144.3" {
|
||||||
|
"0.0.0.0"
|
||||||
|
} else {
|
||||||
|
"10.1.2.4"
|
||||||
|
};
|
||||||
|
assert_panics_ext(
|
||||||
|
|| async {
|
||||||
|
subnet_proxy_test_tcp(listen_ip, target_ip).await;
|
||||||
|
},
|
||||||
|
!has_p2p_conn,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert_panics_ext(
|
||||||
|
|| async {
|
||||||
|
subnet_proxy_test_udp(listen_ip, target_ip).await;
|
||||||
|
},
|
||||||
|
!has_p2p_conn,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[rstest::rstest]
|
#[rstest::rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[serial_test::serial]
|
#[serial_test::serial]
|
||||||
|
|||||||
@@ -269,6 +269,7 @@ no_tun = false
|
|||||||
use_smoltcp = false
|
use_smoltcp = false
|
||||||
foreign_network_whitelist = "*"
|
foreign_network_whitelist = "*"
|
||||||
disable_p2p = false
|
disable_p2p = false
|
||||||
|
p2p_only = false
|
||||||
relay_all_peer_rpc = false
|
relay_all_peer_rpc = false
|
||||||
disable_udp_hole_punching = false
|
disable_udp_hole_punching = false
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user