diff --git a/easytier/locales/app.yml b/easytier/locales/app.yml index d4a115a..e288bf7 100644 --- a/easytier/locales/app.yml +++ b/easytier/locales/app.yml @@ -100,8 +100,8 @@ core_clap: en: "do not create TUN device, can use subnet proxy to access node" zh-CN: "不创建TUN设备,可以使用子网代理访问节点" use_smoltcp: - en: "enable smoltcp stack for subnet proxy" - zh-CN: "为子网代理启用smoltcp堆栈" + en: "enable smoltcp stack for subnet proxy and kcp proxy" + zh-CN: "为子网代理和 KCP 代理启用smoltcp堆栈" manual_routes: en: "assign routes cidr manually, will disable subnet proxy and wireguard routes propagated from peers. e.g.: 192.168.0.0/16" zh-CN: "手动分配路由CIDR,将禁用子网代理和从对等节点传播的wireguard路由。例如:192.168.0.0/16" diff --git a/easytier/src/easytier-cli.rs b/easytier/src/easytier-cli.rs index 761cc2b..0b16a89 100644 --- a/easytier/src/easytier-cli.rs +++ b/easytier/src/easytier-cli.rs @@ -51,14 +51,23 @@ struct Cli { #[derive(Subcommand, Debug)] enum SubCommand { + #[command(about = "show peers info")] Peer(PeerArgs), + #[command(about = "manage connectors")] Connector(ConnectorArgs), + #[command(about = "do stun test")] Stun, + #[command(about = "show route info")] Route(RouteArgs), + #[command(about = "show global peers info")] PeerCenter, + #[command(about = "show vpn portal (wireguard) info")] VpnPortal, + #[command(about = "inspect self easytier-core status")] Node(NodeArgs), + #[command(about = "manage easytier-core as a system service")] Service(ServiceArgs), + #[command(about = "show tcp/kcp proxy status")] Proxy, } @@ -116,7 +125,9 @@ enum ConnectorSubCommand { #[derive(Subcommand, Debug)] enum NodeSubCommand { + #[command(about = "show node info")] Info, + #[command(about = "show node config")] Config, } @@ -137,10 +148,15 @@ struct ServiceArgs { #[derive(Subcommand, Debug)] enum ServiceSubCommand { + #[command(about = "register easytier-core as a system service")] Install(InstallArgs), + #[command(about = "unregister easytier-core system service")] Uninstall, + #[command(about = "check easytier-core system service status")] Status, + #[command(about = "start easytier-core system service")] Start, + #[command(about = "stop easytier-core system service")] Stop, } @@ -155,13 +171,17 @@ struct InstallArgs { #[arg(long, default_value = "false")] disable_autostart: bool, - #[arg(long)] + #[arg(long, help = "path to easytier-core binary")] core_path: Option, #[arg(long)] service_work_dir: Option, - #[arg(trailing_var_arg = true, allow_hyphen_values = true)] + #[arg( + trailing_var_arg = true, + allow_hyphen_values = true, + help = "args to pass to easytier-core" + )] core_args: Option>, } @@ -662,12 +682,22 @@ impl Service { environment: None, }; if self.status()? != ServiceStatus::NotInstalled { - return Err(anyhow::anyhow!("Service is already installed")); + return Err(anyhow::anyhow!( + "Service is already installed! Service Name: {}", + self.lable + )); } self.service_manager - .install(ctx) - .map_err(|e| anyhow::anyhow!("failed to install service: {}", e)) + .install(ctx.clone()) + .map_err(|e| anyhow::anyhow!("failed to install service: {:?}", e))?; + + println!( + "Service installed successfully! Service Name: {}", + self.lable + ); + + Ok(()) } pub fn uninstall(&self) -> Result<(), Error> { @@ -784,7 +814,8 @@ impl Service { writeln!(unit_content, "Type=simple")?; writeln!(unit_content, "WorkingDirectory={work_dir}")?; writeln!(unit_content, "ExecStart={target_app} {args}")?; - writeln!(unit_content, "Restart=Always")?; + writeln!(unit_content, "Restart=always")?; + writeln!(unit_content, "RestartSec=1")?; writeln!(unit_content, "LimitNOFILE=infinity")?; writeln!(unit_content)?; writeln!(unit_content, "[Install]")?; @@ -1141,6 +1172,8 @@ async fn main() -> Result<(), Error> { (e.start_time * 1000) as i64, ) .unwrap() + .with_timezone(&chrono::Local) + .format("%Y-%m-%d %H:%M:%S") .to_string(), state: format!("{:?}", TcpProxyEntryState::try_from(e.state).unwrap()), transport_type: format!( diff --git a/easytier/src/gateway/kcp_proxy.rs b/easytier/src/gateway/kcp_proxy.rs index 6e3e7ad..8246a19 100644 --- a/easytier/src/gateway/kcp_proxy.rs +++ b/easytier/src/gateway/kcp_proxy.rs @@ -206,9 +206,7 @@ impl NicPacketFilter for TcpProxyForKcpSrc { let data = zc_packet.payload(); let ip_packet = Ipv4Packet::new(data).unwrap(); if ip_packet.get_version() != 4 - // TODO: how to support net to net kcp proxy? || ip_packet.get_next_level_protocol() != IpNextHeaderProtocols::Tcp - || !self.check_dst_allow_kcp_input(&ip_packet.get_destination()).await { return false; } @@ -217,15 +215,33 @@ impl NicPacketFilter for TcpProxyForKcpSrc { let tcp_packet = TcpPacket::new(ip_packet.payload()).unwrap(); let is_syn = tcp_packet.get_flags() & TcpFlags::SYN != 0 && tcp_packet.get_flags() & TcpFlags::ACK == 0; - if !is_syn - && !self.0.is_tcp_proxy_connection(SocketAddr::new( + if is_syn { + // only check dst feature flag when SYN packet + if !self + .check_dst_allow_kcp_input(&ip_packet.get_destination()) + .await + { + return false; + } + } else { + // if not syn packet, only allow established connection + if !self.0.is_tcp_proxy_connection(SocketAddr::new( IpAddr::V4(ip_packet.get_source()), tcp_packet.get_source(), - )) - { - return false; + )) { + return false; + } } + if let Some(my_ipv4) = self.0.get_global_ctx().get_ipv4() { + // this is a net-to-net packet, only allow it when smoltcp is enabled + // because the syn-ack packet will not be through and handled by the tun device when + // the source ip is in the local network + if ip_packet.get_source() != my_ipv4.address() && !self.0.is_smoltcp_enabled() { + return false; + } + }; + zc_packet.mut_peer_manager_header().unwrap().to_peer_id = self.0.get_my_peer_id().into(); true diff --git a/easytier/src/gateway/tokio_smoltcp/socket_allocator.rs b/easytier/src/gateway/tokio_smoltcp/socket_allocator.rs index 89c5fc9..a95602f 100644 --- a/easytier/src/gateway/tokio_smoltcp/socket_allocator.rs +++ b/easytier/src/gateway/tokio_smoltcp/socket_allocator.rs @@ -2,6 +2,7 @@ use parking_lot::Mutex; use smoltcp::{ iface::{SocketHandle as InnerSocketHandle, SocketSet}, socket::tcp, + time::Duration, }; use std::{ ops::{Deref, DerefMut}, @@ -53,6 +54,8 @@ impl SocketAlloctor { let tx_buffer = tcp::SocketBuffer::new(vec![0; self.buffer_size.tcp_tx_size]); let mut tcp = tcp::Socket::new(rx_buffer, tx_buffer); tcp.set_nagle_enabled(false); + tcp.set_keep_alive(Some(Duration::from_secs(10))); + tcp.set_timeout(Some(Duration::from_secs(60))); tcp }