mirror of
https://mirror.suhoan.cn/https://github.com/EasyTier/EasyTier.git
synced 2025-12-12 20:57:26 +08:00
improve user experience
1. add config generator to easytier-web 2. add command to show tcp/kcp proxy entries
This commit is contained in:
@@ -6,6 +6,7 @@ use std::{
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use anyhow::Context;
|
||||
use pnet::packet::{
|
||||
icmp::{self, echo_reply::MutableEchoReplyPacket, IcmpCode, IcmpTypes, MutableIcmpPacket},
|
||||
ip::IpNextHeaderProtocols,
|
||||
@@ -212,7 +213,7 @@ impl IcmpProxy {
|
||||
Err(e) => {
|
||||
tracing::warn!("create icmp socket failed: {:?}", e);
|
||||
if !self.global_ctx.no_tun() {
|
||||
return Err(e);
|
||||
return Err(anyhow::anyhow!("create icmp socket failed: {:?}", e).into());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -281,10 +282,15 @@ impl IcmpProxy {
|
||||
dst_ip: Ipv4Addr,
|
||||
icmp_packet: &icmp::echo_request::EchoRequestPacket,
|
||||
) -> Result<(), Error> {
|
||||
self.socket.lock().unwrap().as_ref().unwrap().send_to(
|
||||
icmp_packet.packet(),
|
||||
&SocketAddrV4::new(dst_ip.into(), 0).into(),
|
||||
)?;
|
||||
self.socket
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.with_context(|| "icmp socket not created")?
|
||||
.send_to(
|
||||
icmp_packet.packet(),
|
||||
&SocketAddrV4::new(dst_ip.into(), 0).into(),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
use std::{
|
||||
net::{IpAddr, Ipv4Addr, SocketAddr},
|
||||
sync::Arc,
|
||||
sync::{Arc, Weak},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use anyhow::Context;
|
||||
use bytes::Bytes;
|
||||
use dashmap::DashMap;
|
||||
use kcp_sys::{
|
||||
endpoint::{KcpEndpoint, KcpPacketReceiver},
|
||||
endpoint::{ConnId, KcpEndpoint, KcpPacketReceiver},
|
||||
ffi_safe::KcpConfig,
|
||||
packet_def::KcpPacket,
|
||||
stream::KcpStream,
|
||||
@@ -31,7 +32,14 @@ use crate::{
|
||||
global_ctx::{ArcGlobalCtx, GlobalCtx},
|
||||
},
|
||||
peers::{peer_manager::PeerManager, NicPacketFilter, PeerPacketFilter},
|
||||
proto::peer_rpc::KcpConnData,
|
||||
proto::{
|
||||
cli::{
|
||||
ListTcpProxyEntryRequest, ListTcpProxyEntryResponse, TcpProxyEntry, TcpProxyEntryState,
|
||||
TcpProxyEntryTransportType, TcpProxyRpc,
|
||||
},
|
||||
peer_rpc::KcpConnData,
|
||||
rpc_types::{self, controller::BaseController},
|
||||
},
|
||||
tunnel::packet_def::{PacketType, PeerManagerHeader, ZCPacket},
|
||||
};
|
||||
|
||||
@@ -106,8 +114,9 @@ pub struct NatDstKcpConnector {
|
||||
impl NatDstConnector for NatDstKcpConnector {
|
||||
type DstStream = KcpStream;
|
||||
|
||||
async fn connect(&self, nat_dst: SocketAddr) -> Result<Self::DstStream> {
|
||||
async fn connect(&self, src: SocketAddr, nat_dst: SocketAddr) -> Result<Self::DstStream> {
|
||||
let conn_data = KcpConnData {
|
||||
src: Some(src.into()),
|
||||
dst: Some(nat_dst.into()),
|
||||
};
|
||||
|
||||
@@ -153,9 +162,12 @@ impl NatDstConnector for NatDstKcpConnector {
|
||||
hdr: &PeerManagerHeader,
|
||||
_ipv4: &Ipv4Packet,
|
||||
) -> bool {
|
||||
// TODO: how to support net to net kcp proxy?
|
||||
return hdr.from_peer_id == hdr.to_peer_id;
|
||||
}
|
||||
|
||||
fn transport_type(&self) -> TcpProxyEntryTransportType {
|
||||
TcpProxyEntryTransportType::Kcp
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -191,15 +203,10 @@ impl NicPacketFilter for TcpProxyForKcpSrc {
|
||||
return true;
|
||||
}
|
||||
|
||||
let Some(my_ipv4) = self.0.get_global_ctx().get_ipv4() else {
|
||||
return false;
|
||||
};
|
||||
|
||||
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_source() != my_ipv4.address()
|
||||
|| ip_packet.get_next_level_protocol() != IpNextHeaderProtocols::Tcp
|
||||
|| !self.check_dst_allow_kcp_input(&ip_packet.get_destination()).await
|
||||
{
|
||||
@@ -212,7 +219,7 @@ impl NicPacketFilter for TcpProxyForKcpSrc {
|
||||
&& tcp_packet.get_flags() & TcpFlags::ACK == 0;
|
||||
if !is_syn
|
||||
&& !self.0.is_tcp_proxy_connection(SocketAddr::new(
|
||||
IpAddr::V4(my_ipv4.address()),
|
||||
IpAddr::V4(ip_packet.get_source()),
|
||||
tcp_packet.get_source(),
|
||||
))
|
||||
{
|
||||
@@ -272,11 +279,16 @@ impl KcpProxySrc {
|
||||
.await;
|
||||
self.tcp_proxy.0.start(false).await.unwrap();
|
||||
}
|
||||
|
||||
pub fn get_tcp_proxy(&self) -> Arc<TcpProxy<NatDstKcpConnector>> {
|
||||
self.tcp_proxy.0.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct KcpProxyDst {
|
||||
kcp_endpoint: Arc<KcpEndpoint>,
|
||||
peer_manager: Arc<PeerManager>,
|
||||
proxy_entries: Arc<DashMap<ConnId, TcpProxyEntry>>,
|
||||
tasks: JoinSet<()>,
|
||||
}
|
||||
|
||||
@@ -296,6 +308,7 @@ impl KcpProxyDst {
|
||||
Self {
|
||||
kcp_endpoint: Arc::new(kcp_endpoint),
|
||||
peer_manager,
|
||||
proxy_entries: Arc::new(DashMap::new()),
|
||||
tasks,
|
||||
}
|
||||
}
|
||||
@@ -304,6 +317,7 @@ impl KcpProxyDst {
|
||||
async fn handle_one_in_stream(
|
||||
mut kcp_stream: KcpStream,
|
||||
global_ctx: ArcGlobalCtx,
|
||||
proxy_entries: Arc<DashMap<ConnId, TcpProxyEntry>>,
|
||||
) -> Result<()> {
|
||||
let mut conn_data = kcp_stream.conn_data().clone();
|
||||
let parsed_conn_data = KcpConnData::decode(&mut conn_data)
|
||||
@@ -316,6 +330,21 @@ impl KcpProxyDst {
|
||||
))?
|
||||
.into();
|
||||
|
||||
let conn_id = kcp_stream.conn_id();
|
||||
proxy_entries.insert(
|
||||
conn_id,
|
||||
TcpProxyEntry {
|
||||
src: parsed_conn_data.src,
|
||||
dst: parsed_conn_data.dst,
|
||||
start_time: chrono::Local::now().timestamp() as u64,
|
||||
state: TcpProxyEntryState::ConnectingDst.into(),
|
||||
transport_type: TcpProxyEntryTransportType::Kcp.into(),
|
||||
},
|
||||
);
|
||||
crate::defer! {
|
||||
proxy_entries.remove(&conn_id);
|
||||
}
|
||||
|
||||
if Some(dst_socket.ip()) == global_ctx.get_ipv4().map(|ip| IpAddr::V4(ip.address())) {
|
||||
dst_socket = format!("127.0.0.1:{}", dst_socket.port()).parse().unwrap();
|
||||
}
|
||||
@@ -324,7 +353,13 @@ impl KcpProxyDst {
|
||||
|
||||
let _g = global_ctx.net_ns.guard();
|
||||
let connector = NatDstTcpConnector {};
|
||||
let mut ret = connector.connect(dst_socket).await?;
|
||||
let mut ret = connector
|
||||
.connect("0.0.0.0:0".parse().unwrap(), dst_socket)
|
||||
.await?;
|
||||
|
||||
if let Some(mut e) = proxy_entries.get_mut(&kcp_stream.conn_id()) {
|
||||
e.state = TcpProxyEntryState::Connected.into();
|
||||
}
|
||||
|
||||
copy_bidirectional(&mut ret, &mut kcp_stream).await?;
|
||||
Ok(())
|
||||
@@ -333,6 +368,7 @@ impl KcpProxyDst {
|
||||
async fn run_accept_task(&mut self) {
|
||||
let kcp_endpoint = self.kcp_endpoint.clone();
|
||||
let global_ctx = self.peer_manager.get_global_ctx().clone();
|
||||
let proxy_entries = self.proxy_entries.clone();
|
||||
self.tasks.spawn(async move {
|
||||
while let Ok(conn) = kcp_endpoint.accept().await {
|
||||
let stream = KcpStream::new(&kcp_endpoint, conn)
|
||||
@@ -340,8 +376,9 @@ impl KcpProxyDst {
|
||||
.unwrap();
|
||||
|
||||
let global_ctx = global_ctx.clone();
|
||||
let proxy_entries = proxy_entries.clone();
|
||||
tokio::spawn(async move {
|
||||
let _ = Self::handle_one_in_stream(stream, global_ctx).await;
|
||||
let _ = Self::handle_one_in_stream(stream, global_ctx, proxy_entries).await;
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -357,3 +394,30 @@ impl KcpProxyDst {
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct KcpProxyDstRpcService(Weak<DashMap<ConnId, TcpProxyEntry>>);
|
||||
|
||||
impl KcpProxyDstRpcService {
|
||||
pub fn new(kcp_proxy_dst: &KcpProxyDst) -> Self {
|
||||
Self(Arc::downgrade(&kcp_proxy_dst.proxy_entries))
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl TcpProxyRpc for KcpProxyDstRpcService {
|
||||
type Controller = BaseController;
|
||||
async fn list_tcp_proxy_entry(
|
||||
&self,
|
||||
_: BaseController,
|
||||
_request: ListTcpProxyEntryRequest, // Accept request of type HelloRequest
|
||||
) -> std::result::Result<ListTcpProxyEntryResponse, rpc_types::error::Error> {
|
||||
let mut reply = ListTcpProxyEntryResponse::default();
|
||||
if let Some(tcp_proxy) = self.0.upgrade() {
|
||||
for item in tcp_proxy.iter() {
|
||||
reply.entries.push(item.value().clone());
|
||||
}
|
||||
}
|
||||
Ok(reply)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ use pnet::packet::MutablePacket;
|
||||
use pnet::packet::Packet;
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4};
|
||||
use std::sync::atomic::{AtomicBool, AtomicU16};
|
||||
use std::sync::Arc;
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::time::{Duration, Instant};
|
||||
use tokio::io::{copy_bidirectional, AsyncRead, AsyncWrite};
|
||||
use tokio::net::{TcpListener, TcpSocket, TcpStream};
|
||||
@@ -24,6 +24,12 @@ use crate::common::join_joinset_background;
|
||||
|
||||
use crate::peers::peer_manager::PeerManager;
|
||||
use crate::peers::{NicPacketFilter, PeerPacketFilter};
|
||||
use crate::proto::cli::{
|
||||
ListTcpProxyEntryRequest, ListTcpProxyEntryResponse, TcpProxyEntry, TcpProxyEntryState,
|
||||
TcpProxyEntryTransportType, TcpProxyRpc,
|
||||
};
|
||||
use crate::proto::rpc_types;
|
||||
use crate::proto::rpc_types::controller::BaseController;
|
||||
use crate::tunnel::packet_def::{PacketType, PeerManagerHeader, ZCPacket};
|
||||
|
||||
use super::CidrSet;
|
||||
@@ -35,7 +41,7 @@ use super::tokio_smoltcp::{self, channel_device, Net, NetConfig};
|
||||
pub(crate) trait NatDstConnector: Send + Sync + Clone + 'static {
|
||||
type DstStream: AsyncRead + AsyncWrite + Unpin + Send;
|
||||
|
||||
async fn connect(&self, dst: SocketAddr) -> Result<Self::DstStream>;
|
||||
async fn connect(&self, src: SocketAddr, dst: SocketAddr) -> Result<Self::DstStream>;
|
||||
fn check_packet_from_peer_fast(&self, cidr_set: &CidrSet, global_ctx: &GlobalCtx) -> bool;
|
||||
fn check_packet_from_peer(
|
||||
&self,
|
||||
@@ -44,6 +50,7 @@ pub(crate) trait NatDstConnector: Send + Sync + Clone + 'static {
|
||||
hdr: &PeerManagerHeader,
|
||||
ipv4: &Ipv4Packet,
|
||||
) -> bool;
|
||||
fn transport_type(&self) -> TcpProxyEntryTransportType;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -53,7 +60,7 @@ pub struct NatDstTcpConnector;
|
||||
impl NatDstConnector for NatDstTcpConnector {
|
||||
type DstStream = TcpStream;
|
||||
|
||||
async fn connect(&self, nat_dst: SocketAddr) -> Result<Self::DstStream> {
|
||||
async fn connect(&self, _src: SocketAddr, nat_dst: SocketAddr) -> Result<Self::DstStream> {
|
||||
let socket = TcpSocket::new_v4().unwrap();
|
||||
if let Err(e) = socket.set_nodelay(true) {
|
||||
tracing::warn!("set_nodelay failed, ignore it: {:?}", e);
|
||||
@@ -90,19 +97,13 @@ impl NatDstConnector for NatDstTcpConnector {
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn transport_type(&self) -> TcpProxyEntryTransportType {
|
||||
TcpProxyEntryTransportType::Tcp
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
enum NatDstEntryState {
|
||||
// receive syn packet but not start connecting to dst
|
||||
SynReceived,
|
||||
// connecting to dst
|
||||
ConnectingDst,
|
||||
// connected to dst
|
||||
Connected,
|
||||
// connection closed
|
||||
Closed,
|
||||
}
|
||||
type NatDstEntryState = TcpProxyEntryState;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NatDstEntry {
|
||||
@@ -110,6 +111,7 @@ pub struct NatDstEntry {
|
||||
src: SocketAddr,
|
||||
dst: SocketAddr,
|
||||
start_time: Instant,
|
||||
start_time_local: chrono::DateTime<chrono::Local>,
|
||||
tasks: Mutex<JoinSet<()>>,
|
||||
state: AtomicCell<NatDstEntryState>,
|
||||
}
|
||||
@@ -121,10 +123,21 @@ impl NatDstEntry {
|
||||
src,
|
||||
dst,
|
||||
start_time: Instant::now(),
|
||||
start_time_local: chrono::Local::now(),
|
||||
tasks: Mutex::new(JoinSet::new()),
|
||||
state: AtomicCell::new(NatDstEntryState::SynReceived),
|
||||
}
|
||||
}
|
||||
|
||||
fn into_pb(&self, transport_type: TcpProxyEntryTransportType) -> TcpProxyEntry {
|
||||
TcpProxyEntry {
|
||||
src: Some(self.src.clone().into()),
|
||||
dst: Some(self.dst.clone().into()),
|
||||
start_time: self.start_time_local.timestamp() as u64,
|
||||
state: self.state.load().into(),
|
||||
transport_type: transport_type.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum ProxyTcpStream {
|
||||
@@ -644,7 +657,7 @@ impl<C: NatDstConnector> TcpProxy<C> {
|
||||
};
|
||||
|
||||
let _guard = global_ctx.net_ns.guard();
|
||||
let Ok(dst_tcp_stream) = connector.connect(nat_dst).await else {
|
||||
let Ok(dst_tcp_stream) = connector.connect(nat_entry.src, nat_dst).await else {
|
||||
tracing::error!("connect to dst failed: {:?}", nat_entry);
|
||||
nat_entry.state.store(NatDstEntryState::Closed);
|
||||
Self::remove_entry_from_all_conn_map(conn_map, addr_conn_map, nat_entry);
|
||||
@@ -802,4 +815,45 @@ impl<C: NatDstConnector> TcpProxy<C> {
|
||||
pub fn is_tcp_proxy_connection(&self, src: SocketAddr) -> bool {
|
||||
self.syn_map.contains_key(&src) || self.addr_conn_map.contains_key(&src)
|
||||
}
|
||||
|
||||
pub fn list_proxy_entries(&self) -> Vec<TcpProxyEntry> {
|
||||
let mut entries: Vec<TcpProxyEntry> = Vec::new();
|
||||
let transport_type = self.connector.transport_type();
|
||||
for entry in self.syn_map.iter() {
|
||||
entries.push(entry.value().as_ref().into_pb(transport_type));
|
||||
}
|
||||
for entry in self.conn_map.iter() {
|
||||
entries.push(entry.value().as_ref().into_pb(transport_type));
|
||||
}
|
||||
entries
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TcpProxyRpcService<C: NatDstConnector> {
|
||||
tcp_proxy: Weak<TcpProxy<C>>,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<C: NatDstConnector> TcpProxyRpc for TcpProxyRpcService<C> {
|
||||
type Controller = BaseController;
|
||||
async fn list_tcp_proxy_entry(
|
||||
&self,
|
||||
_: BaseController,
|
||||
_request: ListTcpProxyEntryRequest, // Accept request of type HelloRequest
|
||||
) -> std::result::Result<ListTcpProxyEntryResponse, rpc_types::error::Error> {
|
||||
let mut reply = ListTcpProxyEntryResponse::default();
|
||||
if let Some(tcp_proxy) = self.tcp_proxy.upgrade() {
|
||||
reply.entries = tcp_proxy.list_proxy_entries();
|
||||
}
|
||||
Ok(reply)
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: NatDstConnector> TcpProxyRpcService<C> {
|
||||
pub fn new(tcp_proxy: Arc<TcpProxy<C>>) -> Self {
|
||||
Self {
|
||||
tcp_proxy: Arc::downgrade(&tcp_proxy),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user