fix net2net kcp proxy

This commit is contained in:
sijie.sun
2025-02-08 19:14:21 +08:00
committed by Sijie.Sun
parent 51e0fac72c
commit 53c449b9fb
4 changed files with 67 additions and 15 deletions

View File

@@ -100,8 +100,8 @@ core_clap:
en: "do not create TUN device, can use subnet proxy to access node" en: "do not create TUN device, can use subnet proxy to access node"
zh-CN: "不创建TUN设备可以使用子网代理访问节点" zh-CN: "不创建TUN设备可以使用子网代理访问节点"
use_smoltcp: use_smoltcp:
en: "enable smoltcp stack for subnet proxy" en: "enable smoltcp stack for subnet proxy and kcp proxy"
zh-CN: "为子网代理启用smoltcp堆栈" zh-CN: "为子网代理和 KCP 代理启用smoltcp堆栈"
manual_routes: manual_routes:
en: "assign routes cidr manually, will disable subnet proxy and wireguard routes propagated from peers. e.g.: 192.168.0.0/16" 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" zh-CN: "手动分配路由CIDR将禁用子网代理和从对等节点传播的wireguard路由。例如192.168.0.0/16"

View File

@@ -51,14 +51,23 @@ struct Cli {
#[derive(Subcommand, Debug)] #[derive(Subcommand, Debug)]
enum SubCommand { enum SubCommand {
#[command(about = "show peers info")]
Peer(PeerArgs), Peer(PeerArgs),
#[command(about = "manage connectors")]
Connector(ConnectorArgs), Connector(ConnectorArgs),
#[command(about = "do stun test")]
Stun, Stun,
#[command(about = "show route info")]
Route(RouteArgs), Route(RouteArgs),
#[command(about = "show global peers info")]
PeerCenter, PeerCenter,
#[command(about = "show vpn portal (wireguard) info")]
VpnPortal, VpnPortal,
#[command(about = "inspect self easytier-core status")]
Node(NodeArgs), Node(NodeArgs),
#[command(about = "manage easytier-core as a system service")]
Service(ServiceArgs), Service(ServiceArgs),
#[command(about = "show tcp/kcp proxy status")]
Proxy, Proxy,
} }
@@ -116,7 +125,9 @@ enum ConnectorSubCommand {
#[derive(Subcommand, Debug)] #[derive(Subcommand, Debug)]
enum NodeSubCommand { enum NodeSubCommand {
#[command(about = "show node info")]
Info, Info,
#[command(about = "show node config")]
Config, Config,
} }
@@ -137,10 +148,15 @@ struct ServiceArgs {
#[derive(Subcommand, Debug)] #[derive(Subcommand, Debug)]
enum ServiceSubCommand { enum ServiceSubCommand {
#[command(about = "register easytier-core as a system service")]
Install(InstallArgs), Install(InstallArgs),
#[command(about = "unregister easytier-core system service")]
Uninstall, Uninstall,
#[command(about = "check easytier-core system service status")]
Status, Status,
#[command(about = "start easytier-core system service")]
Start, Start,
#[command(about = "stop easytier-core system service")]
Stop, Stop,
} }
@@ -155,13 +171,17 @@ struct InstallArgs {
#[arg(long, default_value = "false")] #[arg(long, default_value = "false")]
disable_autostart: bool, disable_autostart: bool,
#[arg(long)] #[arg(long, help = "path to easytier-core binary")]
core_path: Option<PathBuf>, core_path: Option<PathBuf>,
#[arg(long)] #[arg(long)]
service_work_dir: Option<PathBuf>, service_work_dir: Option<PathBuf>,
#[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<Vec<OsString>>, core_args: Option<Vec<OsString>>,
} }
@@ -662,12 +682,22 @@ impl Service {
environment: None, environment: None,
}; };
if self.status()? != ServiceStatus::NotInstalled { 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 self.service_manager
.install(ctx) .install(ctx.clone())
.map_err(|e| anyhow::anyhow!("failed to install service: {}", e)) .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> { pub fn uninstall(&self) -> Result<(), Error> {
@@ -784,7 +814,8 @@ impl Service {
writeln!(unit_content, "Type=simple")?; writeln!(unit_content, "Type=simple")?;
writeln!(unit_content, "WorkingDirectory={work_dir}")?; writeln!(unit_content, "WorkingDirectory={work_dir}")?;
writeln!(unit_content, "ExecStart={target_app} {args}")?; 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, "LimitNOFILE=infinity")?;
writeln!(unit_content)?; writeln!(unit_content)?;
writeln!(unit_content, "[Install]")?; writeln!(unit_content, "[Install]")?;
@@ -1141,6 +1172,8 @@ async fn main() -> Result<(), Error> {
(e.start_time * 1000) as i64, (e.start_time * 1000) as i64,
) )
.unwrap() .unwrap()
.with_timezone(&chrono::Local)
.format("%Y-%m-%d %H:%M:%S")
.to_string(), .to_string(),
state: format!("{:?}", TcpProxyEntryState::try_from(e.state).unwrap()), state: format!("{:?}", TcpProxyEntryState::try_from(e.state).unwrap()),
transport_type: format!( transport_type: format!(

View File

@@ -206,9 +206,7 @@ impl NicPacketFilter for TcpProxyForKcpSrc {
let data = zc_packet.payload(); let data = zc_packet.payload();
let ip_packet = Ipv4Packet::new(data).unwrap(); let ip_packet = Ipv4Packet::new(data).unwrap();
if ip_packet.get_version() != 4 if ip_packet.get_version() != 4
// TODO: how to support net to net kcp proxy?
|| ip_packet.get_next_level_protocol() != IpNextHeaderProtocols::Tcp || ip_packet.get_next_level_protocol() != IpNextHeaderProtocols::Tcp
|| !self.check_dst_allow_kcp_input(&ip_packet.get_destination()).await
{ {
return false; return false;
} }
@@ -217,15 +215,33 @@ impl NicPacketFilter for TcpProxyForKcpSrc {
let tcp_packet = TcpPacket::new(ip_packet.payload()).unwrap(); let tcp_packet = TcpPacket::new(ip_packet.payload()).unwrap();
let is_syn = tcp_packet.get_flags() & TcpFlags::SYN != 0 let is_syn = tcp_packet.get_flags() & TcpFlags::SYN != 0
&& tcp_packet.get_flags() & TcpFlags::ACK == 0; && tcp_packet.get_flags() & TcpFlags::ACK == 0;
if !is_syn if is_syn {
&& !self.0.is_tcp_proxy_connection(SocketAddr::new( // 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()), IpAddr::V4(ip_packet.get_source()),
tcp_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(); zc_packet.mut_peer_manager_header().unwrap().to_peer_id = self.0.get_my_peer_id().into();
true true

View File

@@ -2,6 +2,7 @@ use parking_lot::Mutex;
use smoltcp::{ use smoltcp::{
iface::{SocketHandle as InnerSocketHandle, SocketSet}, iface::{SocketHandle as InnerSocketHandle, SocketSet},
socket::tcp, socket::tcp,
time::Duration,
}; };
use std::{ use std::{
ops::{Deref, DerefMut}, ops::{Deref, DerefMut},
@@ -53,6 +54,8 @@ impl SocketAlloctor {
let tx_buffer = tcp::SocketBuffer::new(vec![0; self.buffer_size.tcp_tx_size]); let tx_buffer = tcp::SocketBuffer::new(vec![0; self.buffer_size.tcp_tx_size]);
let mut tcp = tcp::Socket::new(rx_buffer, tx_buffer); let mut tcp = tcp::Socket::new(rx_buffer, tx_buffer);
tcp.set_nagle_enabled(false); tcp.set_nagle_enabled(false);
tcp.set_keep_alive(Some(Duration::from_secs(10)));
tcp.set_timeout(Some(Duration::from_secs(60)));
tcp tcp
} }