diff --git a/easytier/locales/app.yml b/easytier/locales/app.yml index b132c3f..0c23824 100644 --- a/easytier/locales/app.yml +++ b/easytier/locales/app.yml @@ -184,6 +184,9 @@ core_clap: disable_quic_input: en: "do not allow other nodes to use QUIC to proxy tcp streams to this node. when a node with QUIC proxy enabled accesses this node, the original tcp connection is preserved." zh-CN: "不允许其他节点使用 QUIC 代理 TCP 流到此节点。开启 QUIC 代理的节点访问此节点时,依然使用原始 TCP 连接。" + quic_listen_port: + en: "the port to listen for quic connections, default is 0 (random port)" + zh-CN: "监听 QUIC 连接的端口,默认值为0(随机端口)。" port_forward: en: "forward local port to remote port in virtual network. e.g.: udp://0.0.0.0:12345/10.126.126.1:23456, means forward local udp port 12345 to 10.126.126.1:23456 in the virtual network. can specify multiple." zh-CN: "将本地端口转发到虚拟网络中的远程端口。例如:udp://0.0.0.0:12345/10.126.126.1:23456,表示将本地UDP端口12345转发到虚拟网络中的10.126.126.1:23456。可以指定多个。" diff --git a/easytier/src/common/config.rs b/easytier/src/common/config.rs index bbc2ea7..85d17e7 100644 --- a/easytier/src/common/config.rs +++ b/easytier/src/common/config.rs @@ -47,6 +47,7 @@ pub fn gen_default_flags() -> Flags { private_mode: false, enable_quic_proxy: false, disable_quic_input: false, + quic_listen_port: 0, foreign_relay_bps_limit: u64::MAX, multi_thread_count: 2, encryption_algorithm: "aes-gcm".to_string(), diff --git a/easytier/src/easytier-core.rs b/easytier/src/easytier-core.rs index a7985cf..50e42be 100644 --- a/easytier/src/easytier-core.rs +++ b/easytier/src/easytier-core.rs @@ -387,7 +387,7 @@ struct NetworkOptions { // if not in relay_network_whitelist: // for foreign virtual network, will refuse the incoming connection - // for local virtual network, will refuse relaying tun packet + // for local virtual network, will refuse to relay tun packets #[arg( long, env = "ET_RELAY_NETWORK_WHITELIST", @@ -491,6 +491,14 @@ struct NetworkOptions { )] disable_quic_input: Option, + #[arg( + long, + env = "ET_QUIC_LISTEN_PORT", + help = t!("core_clap.quic_listen_port").to_string(), + num_args = 0..=1, + )] + quic_listen_port: Option, + #[arg( long, env = "ET_PORT_FORWARD", @@ -645,10 +653,10 @@ impl Cli { return Ok(vec![]); } - let origin_listners = listeners; + let origin_listeners = listeners; let mut listeners: Vec = Vec::new(); - if origin_listners.len() == 1 { - if let Ok(port) = origin_listners[0].parse::() { + if origin_listeners.len() == 1 { + if let Ok(port) = origin_listeners[0].parse::() { for (proto, offset) in PROTO_PORT_OFFSET { listeners.push(format!("{}://0.0.0.0:{}", proto, port + *offset)); } @@ -656,7 +664,7 @@ impl Cli { } } - for l in &origin_listners { + for l in &origin_listeners { let proto_port: Vec<&str> = l.split(':').collect(); if proto_port.len() > 2 { if let Ok(url) = l.parse::() { @@ -930,6 +938,9 @@ impl NetworkOptions { f.disable_kcp_input = self.disable_kcp_input.unwrap_or(f.disable_kcp_input); f.enable_quic_proxy = self.enable_quic_proxy.unwrap_or(f.enable_quic_proxy); f.disable_quic_input = self.disable_quic_input.unwrap_or(f.disable_quic_input); + if let Some(quic_listen_port) = self.quic_listen_port { + f.quic_listen_port = quic_listen_port as u32; + } f.accept_dns = self.accept_dns.unwrap_or(f.accept_dns); f.private_mode = self.private_mode.unwrap_or(f.private_mode); f.foreign_relay_bps_limit = self @@ -1343,7 +1354,7 @@ async fn main() -> ExitCode { } async fn validate_config(cli: &Cli) -> anyhow::Result<()> { - // Check if config file is provided + // Check if a config file is provided let config_files = cli .config_file .as_ref() diff --git a/easytier/src/gateway/quic_proxy.rs b/easytier/src/gateway/quic_proxy.rs index 7ccca2a..1e693f1 100644 --- a/easytier/src/gateway/quic_proxy.rs +++ b/easytier/src/gateway/quic_proxy.rs @@ -1,18 +1,18 @@ -use std::net::{IpAddr, Ipv4Addr}; -use std::sync::{Arc, Mutex, Weak}; -use std::{net::SocketAddr, pin::Pin}; - use anyhow::Context; use dashmap::DashMap; use pnet::packet::ipv4::Ipv4Packet; use prost::Message as _; use quinn::{Endpoint, Incoming}; +use std::net::{IpAddr, Ipv4Addr}; +use std::sync::{Arc, Mutex, Weak}; +use std::{net::SocketAddr, pin::Pin}; use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite}; use tokio::net::TcpStream; use tokio::task::JoinSet; use tokio::time::timeout; use crate::common::acl_processor::PacketInfo; +use crate::common::config::ConfigLoader; use crate::common::error::Result; use crate::common::global_ctx::{ArcGlobalCtx, GlobalCtx}; use crate::common::join_joinset_background; @@ -261,8 +261,12 @@ impl QUICProxyDst { route: Arc, ) -> Result { let _g = global_ctx.net_ns.guard(); - let (endpoint, _) = make_server_endpoint("0.0.0.0:0".parse().unwrap()) - .map_err(|e| anyhow::anyhow!("failed to create QUIC endpoint: {}", e))?; + let (endpoint, _) = make_server_endpoint( + format!("0.0.0.0:{}", global_ctx.config.get_flags().quic_listen_port) + .parse() + .unwrap(), + ) + .map_err(|e| anyhow::anyhow!("failed to create QUIC endpoint: {}", e))?; let tasks = Arc::new(Mutex::new(JoinSet::new())); join_joinset_background(tasks.clone(), "QUICProxyDst tasks".to_string()); Ok(Self { diff --git a/easytier/src/launcher.rs b/easytier/src/launcher.rs index 0d300b1..2b6b99c 100644 --- a/easytier/src/launcher.rs +++ b/easytier/src/launcher.rs @@ -697,6 +697,10 @@ impl NetworkConfig { flags.disable_quic_input = disable_quic_input; } + if let Some(quic_listen_port) = self.quic_listen_port { + flags.quic_listen_port = quic_listen_port as u32; + } + if let Some(disable_p2p) = self.disable_p2p { flags.disable_p2p = disable_p2p; } @@ -873,6 +877,7 @@ impl NetworkConfig { result.disable_kcp_input = Some(flags.disable_kcp_input); result.enable_quic_proxy = Some(flags.enable_quic_proxy); result.disable_quic_input = Some(flags.disable_quic_input); + result.quic_listen_port = Some(flags.quic_listen_port as i32); result.disable_p2p = Some(flags.disable_p2p); result.bind_device = Some(flags.bind_device); result.no_tun = Some(flags.no_tun); diff --git a/easytier/src/proto/api_manage.proto b/easytier/src/proto/api_manage.proto index 73cf922..923a9e8 100644 --- a/easytier/src/proto/api_manage.proto +++ b/easytier/src/proto/api_manage.proto @@ -72,6 +72,7 @@ message NetworkConfig { optional bool enable_quic_proxy = 45; optional bool disable_quic_input = 46; + optional int32 quic_listen_port = 50; repeated PortForwardConfig port_forwards = 48; optional bool disable_sym_hole_punching = 49; diff --git a/easytier/src/proto/common.proto b/easytier/src/proto/common.proto index 5915b89..e59be2e 100644 --- a/easytier/src/proto/common.proto +++ b/easytier/src/proto/common.proto @@ -41,6 +41,8 @@ message FlagsInConfig { bool enable_quic_proxy = 24; // does this peer allow quic input bool disable_quic_input = 25; + // quic listen port + uint32 quic_listen_port = 33; // a global relay limit, only work for foreign network uint64 foreign_relay_bps_limit = 26;