v2
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
use crate::context::{NetworkAddr, TrafficStats};
|
||||
use crate::enhanced_tunnel::quic_over::quic_inbound::EnhancedQuicInbound;
|
||||
use crate::nat::internal_nat::InternalNatInbound;
|
||||
use crate::protocol::ip_packet_protocol::{HEAD_LENGTH, MsgType, NetPacket};
|
||||
use crate::protocol::transmission::TransmissionBytes;
|
||||
use crate::tun::enhanced_tun::EnhancedTunInbound;
|
||||
use anyhow::{Context, bail};
|
||||
use pnet_packet::ipv4::Ipv4Packet;
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct EnhancedInbound {
|
||||
tun_data_inbound: EnhancedTunInbound,
|
||||
quic_inbound: EnhancedQuicInbound,
|
||||
internal_nat_inbound: Option<InternalNatInbound>,
|
||||
traffic_stats: TrafficStats,
|
||||
}
|
||||
|
||||
impl EnhancedInbound {
|
||||
pub fn new(
|
||||
tun_data_inbound: EnhancedTunInbound,
|
||||
quic_inbound: EnhancedQuicInbound,
|
||||
internal_nat_inbound: Option<InternalNatInbound>,
|
||||
traffic_stats: TrafficStats,
|
||||
) -> Self {
|
||||
Self {
|
||||
tun_data_inbound,
|
||||
quic_inbound,
|
||||
internal_nat_inbound,
|
||||
traffic_stats,
|
||||
}
|
||||
}
|
||||
pub async fn inbound(
|
||||
&self,
|
||||
network_addr: &NetworkAddr,
|
||||
msg_type: MsgType,
|
||||
src: Ipv4Addr,
|
||||
packet: NetPacket<TransmissionBytes>,
|
||||
) -> anyhow::Result<()> {
|
||||
let mut buf = packet.into_buffer();
|
||||
self.traffic_stats.record_rx(src, buf.len() as u64);
|
||||
buf.advance_head(HEAD_LENGTH)?;
|
||||
|
||||
match msg_type {
|
||||
MsgType::Turn => {
|
||||
if let Some(internal_nat_inbound) = self.internal_nat_inbound.as_ref() {
|
||||
let Some(ipv4) = Ipv4Packet::new(&buf) else {
|
||||
bail!("EnhancedInbound not ipv4")
|
||||
};
|
||||
let dest = ipv4.get_destination();
|
||||
if dest != network_addr.ip && !network_addr.network().contains(&dest) {
|
||||
internal_nat_inbound.send(&buf, network_addr).await?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
self.tun_data_inbound.inbound(buf, network_addr).await?;
|
||||
}
|
||||
MsgType::Broadcast | MsgType::ExcludeBroadcast => {
|
||||
self.tun_data_inbound.inbound(buf, network_addr).await?;
|
||||
}
|
||||
MsgType::Quic => {
|
||||
let payload = buf.into_bytes().freeze();
|
||||
self.quic_inbound
|
||||
.inbound(payload, src)
|
||||
.await
|
||||
.context("inbound quic")?;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
use crate::context::AppState;
|
||||
use crate::enhanced_tunnel::inbound::EnhancedInbound;
|
||||
use crate::enhanced_tunnel::outbound::EnhancedOutbound;
|
||||
use crate::nat::SubnetExternalRoute;
|
||||
use crate::nat::internal_nat::{InternalNatInbound, PortMappingManager};
|
||||
use crate::port_mapping::PortMapping;
|
||||
use crate::tun::enhanced_tun::EnhancedTunInbound;
|
||||
use crate::tunnel_core::outbound::HybridOutbound;
|
||||
use crate::utils::task_control::TaskGroup;
|
||||
|
||||
pub(crate) mod quic_over;
|
||||
|
||||
pub(crate) mod inbound;
|
||||
pub(crate) mod outbound;
|
||||
|
||||
pub(crate) struct TunnelConfig {
|
||||
pub mtu: u16,
|
||||
pub password: Option<String>,
|
||||
pub open_quic_client: bool,
|
||||
pub port_mapping: Vec<PortMapping>,
|
||||
}
|
||||
|
||||
pub(crate) struct TunnelComponents {
|
||||
pub hybrid_outbound: HybridOutbound,
|
||||
pub external_route: SubnetExternalRoute,
|
||||
pub internal_nat_inbound: Option<InternalNatInbound>,
|
||||
pub port_mapping_manager: PortMappingManager,
|
||||
}
|
||||
|
||||
pub(crate) async fn enhanced_ipv4_tunnel(
|
||||
app_state: AppState,
|
||||
task_group: TaskGroup,
|
||||
tun_data_sender: EnhancedTunInbound,
|
||||
config: TunnelConfig,
|
||||
components: TunnelComponents,
|
||||
) -> anyhow::Result<(EnhancedInbound, Option<EnhancedOutbound>)> {
|
||||
let password = config.password.unwrap_or_else(|| "password".to_string());
|
||||
let tun = match &tun_data_sender {
|
||||
EnhancedTunInbound::Tun(tun) => Some(tun.clone()),
|
||||
EnhancedTunInbound::Nat(_) => None,
|
||||
};
|
||||
let (inbound, outbound) = quic_over::boot::quic_tunnel_start(
|
||||
app_state.clone(),
|
||||
task_group,
|
||||
tun,
|
||||
quic_over::boot::QuicTunnelConfig {
|
||||
mtu: config.mtu,
|
||||
password,
|
||||
open_quic_client: config.open_quic_client,
|
||||
port_mapping: config.port_mapping,
|
||||
},
|
||||
quic_over::boot::QuicTunnelComponents {
|
||||
hybrid_outbound: components.hybrid_outbound.clone(),
|
||||
external_route: components.external_route,
|
||||
internal_nat_manager: components.internal_nat_inbound.clone(),
|
||||
port_mapping_manager: components.port_mapping_manager,
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
let enhanced_inbound = EnhancedInbound::new(
|
||||
tun_data_sender,
|
||||
inbound,
|
||||
components.internal_nat_inbound,
|
||||
app_state.traffic_stats.clone(),
|
||||
);
|
||||
|
||||
let enhanced_outbound = outbound.map(|outbound| {
|
||||
EnhancedOutbound::new(
|
||||
app_state.network.clone(),
|
||||
outbound,
|
||||
components.hybrid_outbound,
|
||||
)
|
||||
});
|
||||
Ok((enhanced_inbound, enhanced_outbound))
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
use crate::context::SharedNetworkAddr;
|
||||
use crate::enhanced_tunnel::quic_over::quic_outbound::EnhancedQuicOutbound;
|
||||
use crate::protocol::transmission::TransmissionBytes;
|
||||
use crate::tunnel_core::outbound::HybridOutbound;
|
||||
use pnet_packet::ipv4::Ipv4Packet;
|
||||
|
||||
pub struct EnhancedOutbound {
|
||||
network: SharedNetworkAddr,
|
||||
enhanced_quic_outbound: EnhancedQuicOutbound,
|
||||
hybrid_outbound: HybridOutbound,
|
||||
}
|
||||
|
||||
impl EnhancedOutbound {
|
||||
pub fn new(
|
||||
network: SharedNetworkAddr,
|
||||
enhanced_quic_outbound: EnhancedQuicOutbound,
|
||||
hybrid_outbound: HybridOutbound,
|
||||
) -> Self {
|
||||
Self {
|
||||
network,
|
||||
enhanced_quic_outbound,
|
||||
hybrid_outbound,
|
||||
}
|
||||
}
|
||||
pub async fn ipv4_outbound(&self, data: TransmissionBytes) {
|
||||
if data.is_empty() || data[0] >> 4 != 4 {
|
||||
return;
|
||||
}
|
||||
if let Err(e) = self.ipv4_outbound_impl(data).await {
|
||||
log::warn!("EnhancedOutbound error: {:?}", e);
|
||||
}
|
||||
}
|
||||
async fn ipv4_outbound_impl(&self, data: TransmissionBytes) -> anyhow::Result<()> {
|
||||
let Some(ipv4) = Ipv4Packet::new(data.as_ref()) else {
|
||||
return Ok(());
|
||||
};
|
||||
let Some(net) = self.network.get() else {
|
||||
return Ok(());
|
||||
};
|
||||
let src = ipv4.get_source();
|
||||
|
||||
let dest = ipv4.get_destination();
|
||||
if dest == src || dest.is_unspecified() {
|
||||
return Ok(());
|
||||
}
|
||||
if dest == net.gateway {
|
||||
// 发送到网关
|
||||
return self.hybrid_outbound.ipv4_gateway_outbound(net, data).await;
|
||||
}
|
||||
if dest.is_multicast() || dest == net.broadcast || dest.is_broadcast() {
|
||||
// 广播
|
||||
return self
|
||||
.hybrid_outbound
|
||||
.ipv4_broadcast_outbound(net, data)
|
||||
.await;
|
||||
}
|
||||
if self
|
||||
.enhanced_quic_outbound
|
||||
.outbound(&net, data.as_ref())
|
||||
.await
|
||||
{
|
||||
// 使用quic 通道传输
|
||||
return Ok(());
|
||||
}
|
||||
// 使用通用通道传输
|
||||
self.hybrid_outbound.ipv4_outbound(net, data).await
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
use crate::context::AppState;
|
||||
use crate::enhanced_tunnel::quic_over::enhanced_io::enhanced_inbound::{
|
||||
QuicDataInbound, create_enhanced_inbound,
|
||||
};
|
||||
use crate::enhanced_tunnel::quic_over::enhanced_io::enhanced_outbound::create_enhanced_outbound;
|
||||
use crate::enhanced_tunnel::quic_over::enhanced_io::socket::ExtendedQuicSocket;
|
||||
use crate::enhanced_tunnel::quic_over::quic_client::QuicTunnelClient;
|
||||
use crate::enhanced_tunnel::quic_over::quic_inbound::EnhancedQuicInbound;
|
||||
use crate::enhanced_tunnel::quic_over::quic_outbound::EnhancedQuicOutbound;
|
||||
use crate::enhanced_tunnel::quic_over::{quic_client, quic_server};
|
||||
use crate::nat::SubnetExternalRoute;
|
||||
use crate::nat::internal_nat::{InternalNatInbound, PortMappingManager};
|
||||
use crate::port_mapping::PortMapping;
|
||||
use crate::tls;
|
||||
use crate::tun::TunDataInbound;
|
||||
use crate::tunnel_core::outbound::HybridOutbound;
|
||||
use crate::utils::task_control::TaskGroup;
|
||||
use anyhow::Context;
|
||||
use quinn::congestion::BbrConfig;
|
||||
use quinn::crypto::rustls::QuicServerConfig;
|
||||
use quinn::{ClientConfig, Endpoint, EndpointConfig, TransportConfig, default_runtime};
|
||||
use rustls::ServerConfig;
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::io;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tcp_ip::{IpStackConfig, IpStackRecv};
|
||||
|
||||
pub(crate) struct QuicTunnelConfig {
|
||||
pub mtu: u16,
|
||||
pub password: String,
|
||||
pub open_quic_client: bool,
|
||||
pub port_mapping: Vec<PortMapping>,
|
||||
}
|
||||
|
||||
pub(crate) struct QuicTunnelComponents {
|
||||
pub hybrid_outbound: HybridOutbound,
|
||||
pub external_route: SubnetExternalRoute,
|
||||
pub internal_nat_manager: Option<InternalNatInbound>,
|
||||
pub port_mapping_manager: PortMappingManager,
|
||||
}
|
||||
|
||||
pub(crate) async fn quic_tunnel_start(
|
||||
app_state: AppState,
|
||||
task_group: TaskGroup,
|
||||
tun_data_sender: Option<TunDataInbound>,
|
||||
config: QuicTunnelConfig,
|
||||
components: QuicTunnelComponents,
|
||||
) -> anyhow::Result<(EnhancedQuicInbound, Option<EnhancedQuicOutbound>)> {
|
||||
let ip_stack_config = IpStackConfig {
|
||||
mtu: config.mtu,
|
||||
..Default::default()
|
||||
};
|
||||
let (ip_stack, ip_socket, quic_outbound) = if let Some(tun_data_sender) = tun_data_sender {
|
||||
let (ip_stack, ip_stack_send, ip_stack_recv) = tcp_ip::ip_stack(ip_stack_config)?;
|
||||
let ip_socket = tcp_ip::ip::IpSocket::bind_all(None, ip_stack.clone()).await?;
|
||||
let ip_socket = Arc::new(ip_socket);
|
||||
task_group.spawn(ip_stack_recv_task(
|
||||
ip_stack_recv,
|
||||
app_state.clone(),
|
||||
tun_data_sender,
|
||||
));
|
||||
let quic_outbound =
|
||||
EnhancedQuicOutbound::new(config.open_quic_client, ip_stack_send, ip_stack.clone());
|
||||
|
||||
(Some(ip_stack), Some(ip_socket), Some(quic_outbound))
|
||||
} else {
|
||||
(None, None, None)
|
||||
};
|
||||
|
||||
let (inbound, endpoint) = create_quic_endpoint(
|
||||
config.password,
|
||||
task_group.clone(),
|
||||
components.hybrid_outbound,
|
||||
)
|
||||
.await?;
|
||||
quic_server::server_listen(
|
||||
&task_group,
|
||||
endpoint.clone(),
|
||||
ip_socket.clone(),
|
||||
ip_stack.clone(),
|
||||
components.internal_nat_manager,
|
||||
components.port_mapping_manager,
|
||||
)
|
||||
.await;
|
||||
if config.open_quic_client {
|
||||
let quic_client =
|
||||
QuicTunnelClient::new(app_state.clone(), endpoint, components.external_route);
|
||||
|
||||
// 客户端使用指纹验证
|
||||
if let (Some(ip_stack), Some(ip_socket)) = (ip_stack, ip_socket) {
|
||||
quic_client::create_client(
|
||||
quic_client.clone(),
|
||||
task_group.clone(),
|
||||
ip_stack.clone(),
|
||||
ip_socket,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
if !config.port_mapping.is_empty() {
|
||||
crate::port_mapping::port_mapping_start(&task_group, config.port_mapping, quic_client)
|
||||
.await?;
|
||||
}
|
||||
} else if !config.port_mapping.is_empty() {
|
||||
let quic_client =
|
||||
QuicTunnelClient::new(app_state.clone(), endpoint, components.external_route);
|
||||
|
||||
crate::port_mapping::port_mapping_start(&task_group, config.port_mapping, quic_client)
|
||||
.await?;
|
||||
}
|
||||
|
||||
let quic_inbound = EnhancedQuicInbound::new(inbound);
|
||||
Ok((quic_inbound, quic_outbound))
|
||||
}
|
||||
async fn create_quic_endpoint(
|
||||
password: String,
|
||||
task_group: TaskGroup,
|
||||
hybrid_outbound: HybridOutbound,
|
||||
) -> anyhow::Result<(QuicDataInbound, Endpoint)> {
|
||||
let (cert, private_key) = crate::tls::cert::generate_deterministic_cert(&password)?;
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(cert.as_ref());
|
||||
let calculated_hash: [u8; 32] = hasher.finalize().into();
|
||||
log::info!("QUIC Cert Fingerprint: {}", hex::encode(calculated_hash));
|
||||
|
||||
let outbound = create_enhanced_outbound(task_group.clone(), hybrid_outbound).await;
|
||||
let (inbound, inbound_receiver) = create_enhanced_inbound();
|
||||
let socket = ExtendedQuicSocket::new(inbound_receiver, outbound);
|
||||
|
||||
let server_config = ServerConfig::builder()
|
||||
.with_no_client_auth()
|
||||
.with_single_cert(vec![cert], private_key)
|
||||
.context("TLS config error")?;
|
||||
|
||||
let server_crypto = QuicServerConfig::try_from(server_config)
|
||||
.map_err(|e| anyhow::anyhow!("QUIC TLS config error: {:?}", e))?;
|
||||
let server_config = quinn::ServerConfig::with_crypto(Arc::new(server_crypto));
|
||||
// 替换运行时
|
||||
let runtime = default_runtime().ok_or_else(|| io::Error::other("no async runtime found"))?;
|
||||
let fingerprint_verifier = tls::verifier::FingerprintVerifier::new(calculated_hash);
|
||||
|
||||
let client_config = rustls::ClientConfig::builder()
|
||||
.dangerous()
|
||||
.with_custom_certificate_verifier(Arc::new(fingerprint_verifier))
|
||||
.with_no_client_auth();
|
||||
let mut client_config = ClientConfig::new(Arc::new(
|
||||
quinn::crypto::rustls::QuicClientConfig::try_from(client_config)
|
||||
.context("Failed to create QUIC client config")?,
|
||||
));
|
||||
client_config.transport_config(build_transport_config());
|
||||
let mut endpoint_config = EndpointConfig::default();
|
||||
endpoint_config.max_udp_payload_size(1300)?;
|
||||
let mut endpoint = quinn::Endpoint::new_with_abstract_socket(
|
||||
endpoint_config,
|
||||
Some(server_config),
|
||||
Arc::new(socket),
|
||||
runtime,
|
||||
)
|
||||
.context("quic server create failed")?;
|
||||
endpoint.set_default_client_config(client_config);
|
||||
Ok((inbound, endpoint))
|
||||
}
|
||||
|
||||
fn build_transport_config() -> Arc<TransportConfig> {
|
||||
let mut transport = TransportConfig::default();
|
||||
transport.congestion_controller_factory(Arc::new(BbrConfig::default()));
|
||||
transport.keep_alive_interval(Some(Duration::from_secs(5)));
|
||||
|
||||
transport.max_idle_timeout(Some(Duration::from_secs(10).try_into().unwrap()));
|
||||
|
||||
Arc::new(transport)
|
||||
}
|
||||
|
||||
async fn ip_stack_recv_task(
|
||||
mut ip_stack_recv: IpStackRecv,
|
||||
app_state: AppState,
|
||||
tun_data_sender: TunDataInbound,
|
||||
) {
|
||||
let mut buf = vec![0u8; 1500];
|
||||
loop {
|
||||
let len = match ip_stack_recv.recv(&mut buf).await {
|
||||
Ok(len) => len,
|
||||
Err(e) => {
|
||||
log::error!("IP stack recv error: {:?}", e);
|
||||
break;
|
||||
}
|
||||
};
|
||||
let Some(net) = app_state.get_network() else {
|
||||
log::error!("not network");
|
||||
break;
|
||||
};
|
||||
match tun_data_sender.send((&buf[..len]).into(), &net).await {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
log::error!("IP stack send error: {:?}", e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
use anyhow::anyhow;
|
||||
use bytes::Bytes;
|
||||
use parking_lot::Mutex;
|
||||
use quinn::udp::RecvMeta;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::io::IoSliceMut;
|
||||
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
|
||||
use std::sync::Arc;
|
||||
use std::task::{Context, Poll};
|
||||
use tokio::sync::mpsc::{Receiver, Sender};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct QuicInnerInboundReceiver {
|
||||
receiver: Arc<Mutex<Receiver<(Bytes, Ipv4Addr)>>>,
|
||||
}
|
||||
#[derive(Clone)]
|
||||
pub struct QuicDataInbound {
|
||||
sender: Sender<(Bytes, Ipv4Addr)>,
|
||||
}
|
||||
impl QuicDataInbound {
|
||||
pub async fn send(&self, data: Bytes, addr: Ipv4Addr) -> anyhow::Result<()> {
|
||||
self.sender
|
||||
.send((data, addr))
|
||||
.await
|
||||
.map_err(|_e| anyhow!("quic data inbound error"))
|
||||
}
|
||||
}
|
||||
impl Debug for QuicInnerInboundReceiver {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("EnhancedInbound").finish()
|
||||
}
|
||||
}
|
||||
pub fn create_enhanced_inbound() -> (QuicDataInbound, QuicInnerInboundReceiver) {
|
||||
let (sender, receiver) = tokio::sync::mpsc::channel(256);
|
||||
(
|
||||
QuicDataInbound { sender },
|
||||
QuicInnerInboundReceiver::new(receiver),
|
||||
)
|
||||
}
|
||||
impl QuicInnerInboundReceiver {
|
||||
pub fn new(receiver: Receiver<(Bytes, Ipv4Addr)>) -> Self {
|
||||
Self {
|
||||
receiver: Arc::new(Mutex::new(receiver)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn poll_recv(
|
||||
&self,
|
||||
cx: &mut Context,
|
||||
bufs: &mut [IoSliceMut<'_>],
|
||||
meta: &mut [RecvMeta],
|
||||
) -> Poll<std::io::Result<usize>> {
|
||||
let mut guard = self.receiver.lock();
|
||||
let rs = guard.poll_recv(cx);
|
||||
drop(guard);
|
||||
match rs {
|
||||
Poll::Ready(Some((buf, ip))) => {
|
||||
let (buf_mut, meta) = match (bufs.get_mut(0), meta.get_mut(0)) {
|
||||
(Some(b), Some(m)) => (b, m),
|
||||
_ => {
|
||||
return Poll::Ready(Err(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidInput,
|
||||
"no buffer available",
|
||||
)));
|
||||
}
|
||||
};
|
||||
|
||||
if buf_mut.len() < buf.len() {
|
||||
return Poll::Ready(Err(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidInput,
|
||||
format!(
|
||||
"buffer too small: need {}, got {}",
|
||||
buf.len(),
|
||||
buf_mut.len()
|
||||
),
|
||||
)));
|
||||
}
|
||||
|
||||
buf_mut[..buf.len()].copy_from_slice(&buf);
|
||||
|
||||
meta.len = buf.len();
|
||||
meta.stride = buf.len();
|
||||
meta.addr = SocketAddr::V4(SocketAddrV4::new(ip, 10000));
|
||||
Poll::Ready(Ok(1))
|
||||
}
|
||||
Poll::Ready(None) => Poll::Ready(Err(std::io::Error::new(
|
||||
std::io::ErrorKind::BrokenPipe,
|
||||
"inbound channel closed",
|
||||
))),
|
||||
Poll::Pending => Poll::Pending,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
use crate::protocol::ip_packet_protocol::{HEAD_LENGTH, MsgType, NetPacket};
|
||||
use crate::protocol::transmission::TransmissionBytes;
|
||||
use crate::tunnel_core::outbound::HybridOutbound;
|
||||
use crate::utils::task_control::TaskGroup;
|
||||
use quinn::UdpPoller;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::io;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use tokio::sync::mpsc::{Sender, error::TrySendError};
|
||||
use tokio_util::sync::PollSender;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct QuicInnerOutbound {
|
||||
sender: Sender<(Ipv4Addr, NetPacket<TransmissionBytes>)>,
|
||||
}
|
||||
|
||||
pub async fn create_enhanced_outbound(
|
||||
task_group: TaskGroup,
|
||||
hybrid_outbound: HybridOutbound,
|
||||
) -> QuicInnerOutbound {
|
||||
let (s, mut r) = tokio::sync::mpsc::channel(256);
|
||||
|
||||
task_group.spawn(async move {
|
||||
while let Some((dst, packet)) = r.recv().await {
|
||||
if let Err(e) = hybrid_outbound.outbound_raw(dst, packet).await {
|
||||
log::debug!("outbound error: {e:?}, dst={dst}");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
QuicInnerOutbound { sender: s }
|
||||
}
|
||||
|
||||
impl QuicInnerOutbound {
|
||||
pub fn try_outbound(&self, buf: &[u8], dest: Ipv4Addr) -> io::Result<()> {
|
||||
let send = match self.sender.try_reserve() {
|
||||
Ok(send) => send,
|
||||
Err(TrySendError::Full(_)) => {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::WouldBlock,
|
||||
"outbound channel full",
|
||||
));
|
||||
}
|
||||
Err(TrySendError::Closed(_)) => {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::BrokenPipe,
|
||||
"outbound channel closed",
|
||||
));
|
||||
}
|
||||
};
|
||||
let mut packet = NetPacket::new(TransmissionBytes::zeroed(HEAD_LENGTH + buf.len()))?;
|
||||
packet.set_ttl(5);
|
||||
packet.set_msg_type(MsgType::Quic);
|
||||
packet.set_dest_id(dest.into());
|
||||
packet.set_payload(buf)?;
|
||||
send.send((dest, packet));
|
||||
Ok(())
|
||||
}
|
||||
pub fn create_io_poller(&self) -> Pin<Box<dyn UdpPoller>> {
|
||||
Box::pin(EnhancedOutboundPoller {
|
||||
sender: PollSender::new(self.sender.clone()),
|
||||
})
|
||||
}
|
||||
}
|
||||
pub struct EnhancedOutboundPoller {
|
||||
sender: PollSender<(Ipv4Addr, NetPacket<TransmissionBytes>)>,
|
||||
}
|
||||
impl Debug for EnhancedOutboundPoller {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("EnhancedOutboundPoller").finish()
|
||||
}
|
||||
}
|
||||
impl UdpPoller for EnhancedOutboundPoller {
|
||||
fn poll_writable(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<io::Result<()>> {
|
||||
match self.sender.poll_reserve(cx) {
|
||||
Poll::Ready(Ok(_)) => {
|
||||
self.sender.abort_send();
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
Poll::Ready(Err(_e)) => Poll::Ready(Err(io::Error::new(
|
||||
io::ErrorKind::BrokenPipe,
|
||||
"outbound channel closed",
|
||||
))),
|
||||
Poll::Pending => Poll::Pending,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
pub mod enhanced_inbound;
|
||||
pub mod enhanced_outbound;
|
||||
pub mod socket;
|
||||
@@ -0,0 +1,55 @@
|
||||
use crate::enhanced_tunnel::quic_over::enhanced_io::enhanced_inbound::QuicInnerInboundReceiver;
|
||||
use crate::enhanced_tunnel::quic_over::enhanced_io::enhanced_outbound::QuicInnerOutbound;
|
||||
use quinn::udp::{RecvMeta, Transmit};
|
||||
use quinn::{AsyncUdpSocket, UdpPoller};
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::io::IoSliceMut;
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4};
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
pub struct ExtendedQuicSocket {
|
||||
inbound: QuicInnerInboundReceiver,
|
||||
outbound: QuicInnerOutbound,
|
||||
}
|
||||
impl Debug for ExtendedQuicSocket {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("QuicSocket").finish()
|
||||
}
|
||||
}
|
||||
impl ExtendedQuicSocket {
|
||||
pub fn new(inbound: QuicInnerInboundReceiver, outbound: QuicInnerOutbound) -> Self {
|
||||
Self { inbound, outbound }
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncUdpSocket for ExtendedQuicSocket {
|
||||
fn create_io_poller(self: Arc<Self>) -> Pin<Box<dyn UdpPoller>> {
|
||||
self.outbound.create_io_poller()
|
||||
}
|
||||
|
||||
fn try_send(&self, transmit: &Transmit) -> std::io::Result<()> {
|
||||
let IpAddr::V4(dest) = transmit.destination.ip() else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
self.outbound.try_outbound(transmit.contents, dest)
|
||||
}
|
||||
|
||||
fn poll_recv(
|
||||
&self,
|
||||
cx: &mut Context,
|
||||
bufs: &mut [IoSliceMut<'_>],
|
||||
meta: &mut [RecvMeta],
|
||||
) -> Poll<std::io::Result<usize>> {
|
||||
self.inbound.poll_recv(cx, bufs, meta)
|
||||
}
|
||||
|
||||
fn local_addr(&self) -> std::io::Result<SocketAddr> {
|
||||
Ok(SocketAddr::V4(SocketAddrV4::new(
|
||||
Ipv4Addr::new(127, 0, 0, 1),
|
||||
10000,
|
||||
)))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
mod enhanced_io;
|
||||
pub(crate) mod quic_client;
|
||||
pub(crate) mod quic_inbound;
|
||||
pub(crate) mod quic_outbound;
|
||||
mod quic_server;
|
||||
|
||||
pub(crate) mod boot;
|
||||
@@ -0,0 +1,309 @@
|
||||
use crate::context::AppState;
|
||||
|
||||
use crate::nat::SubnetExternalRoute;
|
||||
use crate::protocol::client_message::{
|
||||
IpProxyHandshake, QuicProxyHandshake, TcpProxyHandshake, quic_proxy_handshake,
|
||||
};
|
||||
use crate::utils::task_control::TaskGroup;
|
||||
use anyhow::{Context, bail};
|
||||
use bytes::Bytes;
|
||||
use futures::SinkExt;
|
||||
use parking_lot::Mutex;
|
||||
use pnet_packet::ip::IpNextHeaderProtocol;
|
||||
use prost::Message;
|
||||
use quinn::{Connection, Endpoint, RecvStream, SendStream};
|
||||
use std::collections::HashMap;
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||
use std::sync::Arc;
|
||||
use tcp_ip::IpStack;
|
||||
use tcp_ip::ip::IpSocket;
|
||||
use tcp_ip::tcp::TcpStream;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
use tokio::sync::OnceCell;
|
||||
use tokio::sync::mpsc::Sender;
|
||||
use tokio::sync::mpsc::error::TrySendError;
|
||||
use tokio_util::codec::{FramedWrite, LengthDelimitedCodec};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct QuicTunnelClient {
|
||||
app_state: AppState,
|
||||
endpoint: Endpoint,
|
||||
connection_map: Arc<Mutex<HashMap<Ipv4Addr, Arc<OnceCell<Connection>>>>>,
|
||||
external_route: SubnetExternalRoute,
|
||||
}
|
||||
|
||||
impl QuicTunnelClient {
|
||||
pub fn new(
|
||||
app_state: AppState,
|
||||
endpoint: Endpoint,
|
||||
external_route: SubnetExternalRoute,
|
||||
) -> QuicTunnelClient {
|
||||
Self {
|
||||
app_state,
|
||||
endpoint,
|
||||
connection_map: Arc::new(Default::default()),
|
||||
external_route,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn open_bi(&self, mut dest: Ipv4Addr) -> anyhow::Result<(SendStream, RecvStream)> {
|
||||
let Some(net) = self.app_state.get_network() else {
|
||||
bail!("no network found");
|
||||
};
|
||||
if !net.network().contains(&dest) {
|
||||
if let Some(v) = self.external_route.route(&dest) {
|
||||
dest = v;
|
||||
} else {
|
||||
bail!("invalid route found:{dest}");
|
||||
}
|
||||
}
|
||||
let mut count = 0;
|
||||
loop {
|
||||
count += 1;
|
||||
let cell = self
|
||||
.connection_map
|
||||
.lock()
|
||||
.entry(dest)
|
||||
.or_insert_with(|| Arc::new(OnceCell::new()))
|
||||
.clone();
|
||||
let connection = cell
|
||||
.get_or_try_init(|| async {
|
||||
self.endpoint
|
||||
.connect(SocketAddr::new(dest.into(), 10000), "localhost")?
|
||||
.await
|
||||
.context("connect failed")
|
||||
})
|
||||
.await?;
|
||||
|
||||
return match connection.open_bi().await {
|
||||
Ok(rs) => Ok(rs),
|
||||
Err(e) => {
|
||||
self.connection_map.lock().remove(&dest);
|
||||
if count == 1 {
|
||||
continue;
|
||||
}
|
||||
Err(e.into())
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
pub async fn open_uni(&self, mut dest: Ipv4Addr) -> anyhow::Result<SendStream> {
|
||||
let Some(net) = self.app_state.get_network() else {
|
||||
bail!("no network found");
|
||||
};
|
||||
if !net.network().contains(&dest) {
|
||||
if let Some(v) = self.external_route.route(&dest) {
|
||||
dest = v;
|
||||
} else {
|
||||
bail!("invalid route found:{dest}");
|
||||
}
|
||||
}
|
||||
let mut count = 0;
|
||||
loop {
|
||||
count += 1;
|
||||
let cell = self
|
||||
.connection_map
|
||||
.lock()
|
||||
.entry(dest)
|
||||
.or_insert_with(|| Arc::new(OnceCell::new()))
|
||||
.clone();
|
||||
let connection = cell
|
||||
.get_or_try_init(|| async {
|
||||
self.endpoint
|
||||
.connect(SocketAddr::new(dest.into(), 10000), "localhost")?
|
||||
.await
|
||||
.context("connect failed")
|
||||
})
|
||||
.await?;
|
||||
return match connection.open_uni().await {
|
||||
Ok(rs) => Ok(rs),
|
||||
Err(e) => {
|
||||
self.connection_map.lock().remove(&dest);
|
||||
if count == 1 {
|
||||
continue;
|
||||
}
|
||||
Err(e.into())
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
pub(crate) async fn send_handshake(
|
||||
send_stream: &mut SendStream,
|
||||
handshake: QuicProxyHandshake,
|
||||
) -> anyhow::Result<()> {
|
||||
let handshake = handshake.encode_to_vec();
|
||||
send_stream.write_u16(handshake.len() as u16).await?;
|
||||
send_stream.write_all(&handshake).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn create_client(
|
||||
quic_client: QuicTunnelClient,
|
||||
task_group: TaskGroup,
|
||||
ip_stack: IpStack,
|
||||
ip_socket: Arc<IpSocket>,
|
||||
) {
|
||||
task_group.spawn(tcp_listen(
|
||||
task_group.clone(),
|
||||
ip_stack.clone(),
|
||||
quic_client.clone(),
|
||||
));
|
||||
task_group.spawn(ip_listen(task_group.clone(), ip_socket, quic_client));
|
||||
}
|
||||
|
||||
async fn tcp_listen(
|
||||
task_group: TaskGroup,
|
||||
ip_stack: IpStack,
|
||||
quic_tunnel_client: QuicTunnelClient,
|
||||
) {
|
||||
if let Err(e) = tcp_listen_impl(task_group, ip_stack, quic_tunnel_client).await {
|
||||
log::error!("tcp_listen {e:?}");
|
||||
}
|
||||
}
|
||||
|
||||
async fn tcp_listen_impl(
|
||||
task_group: TaskGroup,
|
||||
ip_stack: IpStack,
|
||||
quic_tunnel_client: QuicTunnelClient,
|
||||
) -> anyhow::Result<()> {
|
||||
let mut listener = tcp_ip::tcp::TcpListener::bind_all(ip_stack).await?;
|
||||
loop {
|
||||
let (tcp_stream, addr) = listener.accept().await?;
|
||||
let quic_tunnel_client = quic_tunnel_client.clone();
|
||||
task_group.spawn(async move {
|
||||
if let Err(e) = tcp_stream_handle(tcp_stream, quic_tunnel_client).await {
|
||||
log::error!("TCP stream handle failed with error: {e:?},addr={addr}");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async fn tcp_stream_handle(
|
||||
tcp_stream: TcpStream,
|
||||
quic_tunnel_client: QuicTunnelClient,
|
||||
) -> anyhow::Result<()> {
|
||||
// 连接方向是反过来的,因为自己充当目标做了tcp卸载
|
||||
let SocketAddr::V4(peer_addr) = tcp_stream.local_addr()? else {
|
||||
bail!("invalid IP address");
|
||||
};
|
||||
let SocketAddr::V4(local_addr) = tcp_stream.peer_addr()? else {
|
||||
bail!("invalid IP address");
|
||||
};
|
||||
log::debug!("connect TCP stream {}->{}", local_addr, peer_addr);
|
||||
|
||||
let (mut send_stream, mut recv_stream) = quic_tunnel_client.open_bi(*peer_addr.ip()).await?;
|
||||
let handshake = QuicProxyHandshake {
|
||||
handshake: Some(quic_proxy_handshake::Handshake::Tcp(TcpProxyHandshake {
|
||||
src_ip: (*local_addr.ip()).into(),
|
||||
src_port: local_addr.port().into(),
|
||||
dst_ip: (*peer_addr.ip()).into(),
|
||||
dst_port: peer_addr.port().into(),
|
||||
})),
|
||||
};
|
||||
send_handshake(&mut send_stream, handshake).await?;
|
||||
let (mut tcp_w, mut tcp_r) = tcp_stream.split()?;
|
||||
tokio::select! {
|
||||
_ = tokio::io::copy(&mut recv_stream, &mut tcp_w) => {},
|
||||
_ = tokio::io::copy(&mut tcp_r, &mut send_stream) => {},
|
||||
}
|
||||
log::debug!("disconnect TCP stream {}->{}", local_addr, peer_addr);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn ip_listen(
|
||||
task_group: TaskGroup,
|
||||
ip_socket: Arc<IpSocket>,
|
||||
quic_tunnel_client: QuicTunnelClient,
|
||||
) {
|
||||
if let Err(e) = ip_listen_impl(task_group, ip_socket, quic_tunnel_client).await {
|
||||
log::error!("ip_listen {e:?}");
|
||||
}
|
||||
}
|
||||
#[derive(Eq, PartialEq, Hash, Copy, Clone, Debug)]
|
||||
struct IpKey {
|
||||
protocol: IpNextHeaderProtocol,
|
||||
src: Ipv4Addr,
|
||||
dest: Ipv4Addr,
|
||||
}
|
||||
async fn ip_listen_impl(
|
||||
task_group: TaskGroup,
|
||||
ip_socket: Arc<IpSocket>,
|
||||
quic_tunnel_client: QuicTunnelClient,
|
||||
) -> anyhow::Result<()> {
|
||||
let mut buf = vec![0u8; 65536];
|
||||
let dest_map = Arc::new(Mutex::new(HashMap::<IpKey, Sender<Bytes>>::new()));
|
||||
|
||||
loop {
|
||||
let (len, protocol, src, dest) = ip_socket.recv_protocol_from_to(&mut buf).await?;
|
||||
let (IpAddr::V4(src), IpAddr::V4(dest)) = (src, dest) else {
|
||||
continue;
|
||||
};
|
||||
let key = IpKey {
|
||||
protocol,
|
||||
src,
|
||||
dest,
|
||||
};
|
||||
let bytes = Bytes::copy_from_slice(&buf[..len]);
|
||||
|
||||
let tx = {
|
||||
let mut map = dest_map.lock();
|
||||
if let Some(tx) = map.get(&key) {
|
||||
tx.clone()
|
||||
} else {
|
||||
let (tx, rx) = tokio::sync::mpsc::channel::<Bytes>(128);
|
||||
|
||||
spawn_dest_sender(task_group.clone(), key, rx, quic_tunnel_client.clone());
|
||||
|
||||
map.insert(key, tx.clone());
|
||||
tx
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(err) = tx.try_send(bytes) {
|
||||
match err {
|
||||
TrySendError::Full(_) => {}
|
||||
TrySendError::Closed(_) => {
|
||||
let mut map = dest_map.lock();
|
||||
map.remove(&key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn spawn_dest_sender(
|
||||
task_group: TaskGroup,
|
||||
key: IpKey,
|
||||
mut rx: tokio::sync::mpsc::Receiver<Bytes>,
|
||||
quic_tunnel_client: QuicTunnelClient,
|
||||
) {
|
||||
log::info!("send ip({}) packet {}->{}", key.protocol, key.src, key.dest);
|
||||
task_group.spawn(async move {
|
||||
let result = async {
|
||||
let mut send_stream = quic_tunnel_client.open_uni(key.dest).await?;
|
||||
|
||||
let handshake = QuicProxyHandshake {
|
||||
handshake: Some(quic_proxy_handshake::Handshake::Ip(IpProxyHandshake {
|
||||
ip_next_header_protocol: key.protocol.0 as _,
|
||||
src_ip: key.src.into(),
|
||||
dst_ip: key.dest.into(),
|
||||
})),
|
||||
};
|
||||
send_handshake(&mut send_stream, handshake).await?;
|
||||
|
||||
let mut framed = FramedWrite::new(send_stream, LengthDelimitedCodec::new());
|
||||
|
||||
while let Some(pkt) = rx.recv().await {
|
||||
framed.send(pkt).await?;
|
||||
}
|
||||
|
||||
Ok::<(), anyhow::Error>(())
|
||||
}
|
||||
.await;
|
||||
|
||||
if let Err(e) = result {
|
||||
log::error!("key {:?} sender task exit: {:?}", key, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
use crate::enhanced_tunnel::quic_over::enhanced_io::enhanced_inbound::QuicDataInbound;
|
||||
use bytes::Bytes;
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct EnhancedQuicInbound {
|
||||
quic_data_inbound: QuicDataInbound,
|
||||
}
|
||||
|
||||
impl EnhancedQuicInbound {
|
||||
pub fn new(quic_data_inbound: QuicDataInbound) -> Self {
|
||||
Self { quic_data_inbound }
|
||||
}
|
||||
pub async fn inbound(&self, data: Bytes, src: Ipv4Addr) -> anyhow::Result<()> {
|
||||
self.quic_data_inbound.send(data, src).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
use crate::context::NetworkAddr;
|
||||
use pnet_packet::Packet;
|
||||
use pnet_packet::ip::IpNextHeaderProtocols;
|
||||
use pnet_packet::ipv4::{Ipv4Flags, Ipv4Packet};
|
||||
use pnet_packet::tcp::TcpFlags::{ACK, SYN};
|
||||
use pnet_packet::tcp::TcpPacket;
|
||||
use std::net::SocketAddr;
|
||||
use tcp_ip::{IpStack, IpStackSend};
|
||||
|
||||
pub struct EnhancedQuicOutbound {
|
||||
open_quic_client: bool,
|
||||
ip_stack_send: IpStackSend,
|
||||
ip_stack: IpStack,
|
||||
}
|
||||
|
||||
impl EnhancedQuicOutbound {
|
||||
pub fn new(open_quic_client: bool, ip_stack_send: IpStackSend, ip_stack: IpStack) -> Self {
|
||||
Self {
|
||||
open_quic_client,
|
||||
ip_stack_send,
|
||||
ip_stack,
|
||||
}
|
||||
}
|
||||
pub async fn outbound(&self, _net: &NetworkAddr, data: &[u8]) -> bool {
|
||||
let Some(ipv4) = Ipv4Packet::new(data) else {
|
||||
return true;
|
||||
};
|
||||
|
||||
if self.open_quic_client {
|
||||
// 针对tcp 如果不是从IpStack建立的连接,则不使用IpStack解析
|
||||
if ipv4.get_next_level_protocol() == IpNextHeaderProtocols::Tcp {
|
||||
let more_fragments =
|
||||
ipv4.get_flags() & Ipv4Flags::MoreFragments == Ipv4Flags::MoreFragments;
|
||||
let offset = ipv4.get_fragment_offset();
|
||||
let segmented = more_fragments || offset > 0;
|
||||
if !segmented {
|
||||
let Some(tcp) = TcpPacket::new(ipv4.payload()) else {
|
||||
return true;
|
||||
};
|
||||
// 不是第一个包
|
||||
if !(tcp.get_flags() & SYN == SYN && tcp.get_flags() & ACK != ACK) {
|
||||
let local_addr =
|
||||
SocketAddr::new(ipv4.get_source().into(), tcp.get_source());
|
||||
let peer_addr =
|
||||
SocketAddr::new(ipv4.get_destination().into(), tcp.get_destination());
|
||||
// 在IpStack中找不到连接
|
||||
if !self
|
||||
.ip_stack
|
||||
.has_tcp_connection(local_addr, peer_addr)
|
||||
.unwrap_or(false)
|
||||
&& !self
|
||||
.ip_stack
|
||||
.has_tcp_connection(peer_addr, local_addr)
|
||||
.unwrap_or(false)
|
||||
&& !self
|
||||
.ip_stack
|
||||
.has_tcp_half_open(peer_addr, local_addr)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ = self.ip_stack_send.send_ip_packet(data).await;
|
||||
return true;
|
||||
}
|
||||
// 判断tcp流
|
||||
if ipv4.get_next_level_protocol() == IpNextHeaderProtocols::Tcp {
|
||||
let more_fragments =
|
||||
ipv4.get_flags() & Ipv4Flags::MoreFragments == Ipv4Flags::MoreFragments;
|
||||
let offset = ipv4.get_fragment_offset();
|
||||
let segmented = more_fragments || offset > 0;
|
||||
if !segmented && let Some(tcp) = TcpPacket::new(ipv4.payload()) {
|
||||
// 如果对端使用IpStack连接了自己,则也需要原路回复
|
||||
// 这是连接回复,所以方向是和流方向相反的
|
||||
let peer_addr = SocketAddr::new(ipv4.get_source().into(), tcp.get_source());
|
||||
let local_addr =
|
||||
SocketAddr::new(ipv4.get_destination().into(), tcp.get_destination());
|
||||
|
||||
if self
|
||||
.ip_stack
|
||||
.has_tcp_connection(local_addr, peer_addr)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
_ = self.ip_stack_send.send_ip_packet(data).await;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
use crate::nat::internal_nat::{InternalNatInbound, PortMappingManager};
|
||||
use crate::protocol::client_message::QuicProxyHandshake;
|
||||
use crate::protocol::client_message::quic_proxy_handshake::Handshake;
|
||||
use crate::utils::task_control::TaskGroup;
|
||||
use anyhow::{Context, bail};
|
||||
use futures::StreamExt;
|
||||
use pnet_packet::ip::IpNextHeaderProtocol;
|
||||
use prost::Message;
|
||||
use quinn::{Connection, Endpoint, RecvStream, SendStream};
|
||||
use std::net::{Ipv4Addr, SocketAddr};
|
||||
use std::sync::Arc;
|
||||
use tcp_ip::IpStack;
|
||||
use tcp_ip::ip::IpSocket;
|
||||
use tokio::io::AsyncReadExt;
|
||||
use tokio_util::codec::{FramedRead, LengthDelimitedCodec};
|
||||
|
||||
pub async fn server_listen(
|
||||
task_group: &TaskGroup,
|
||||
endpoint: Endpoint,
|
||||
ip_socket: Option<Arc<IpSocket>>,
|
||||
ip_stack: Option<IpStack>,
|
||||
internal_nat_manager: Option<InternalNatInbound>,
|
||||
port_mapping_manager: PortMappingManager,
|
||||
) {
|
||||
task_group.spawn(quic_endpoint_accept(
|
||||
ip_stack,
|
||||
task_group.clone(),
|
||||
endpoint,
|
||||
ip_socket,
|
||||
internal_nat_manager,
|
||||
port_mapping_manager,
|
||||
));
|
||||
}
|
||||
|
||||
async fn quic_endpoint_accept(
|
||||
ip_stack: Option<IpStack>,
|
||||
task_group: TaskGroup,
|
||||
endpoint: Endpoint,
|
||||
ip_socket: Option<Arc<IpSocket>>,
|
||||
internal_nat_manager: Option<InternalNatInbound>,
|
||||
port_mapping_manager: PortMappingManager,
|
||||
) {
|
||||
while let Some(connecting) = endpoint.accept().await {
|
||||
let remote_addr = connecting.remote_address();
|
||||
let task_group_clone = task_group.clone();
|
||||
let ip_socket = ip_socket.clone();
|
||||
let ip_stack = ip_stack.clone();
|
||||
let internal_nat_manager = internal_nat_manager.clone();
|
||||
let port_mapping_manager = port_mapping_manager.clone();
|
||||
task_group.spawn(async move {
|
||||
match connecting.await {
|
||||
Ok(connection) => {
|
||||
log::info!("QUIC connection: {}", remote_addr);
|
||||
if let Err(e) = quic_accept(
|
||||
ip_stack,
|
||||
task_group_clone,
|
||||
connection,
|
||||
ip_socket,
|
||||
internal_nat_manager,
|
||||
port_mapping_manager,
|
||||
)
|
||||
.await
|
||||
{
|
||||
log::info!("quic close: {remote_addr},{e:?}",);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("connect: {:?},remote_addr={remote_addr}", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
log::warn!("quic server closed");
|
||||
}
|
||||
|
||||
async fn quic_accept(
|
||||
ip_stack: Option<IpStack>,
|
||||
task_group_clone: TaskGroup,
|
||||
connection: Connection,
|
||||
ip_socket: Option<Arc<IpSocket>>,
|
||||
internal_nat_manager: Option<InternalNatInbound>,
|
||||
port_mapping_manager: PortMappingManager,
|
||||
) -> anyhow::Result<()> {
|
||||
loop {
|
||||
tokio::select! {
|
||||
rs = connection.accept_bi()=>{
|
||||
let (send_stream, recv_stream) = rs?;
|
||||
let ip_stack = ip_stack.clone();
|
||||
let internal_nat_manager = internal_nat_manager.clone();
|
||||
let port_mapping_manager = port_mapping_manager.clone();
|
||||
task_group_clone.spawn(async move {
|
||||
if let Err(e) = quic_stream_bi_handle(ip_stack,send_stream, recv_stream,&internal_nat_manager,port_mapping_manager).await{
|
||||
log::error!("quic_stream_bi_handle: {e:?}");
|
||||
}
|
||||
});
|
||||
}
|
||||
rs = connection.accept_uni()=>{
|
||||
let recv_stream = rs?;
|
||||
let ip_socket = ip_socket.clone();
|
||||
let internal_nat_manager = internal_nat_manager.clone();
|
||||
task_group_clone.spawn(async move {
|
||||
if let Err(e) = quic_stream_uni_handle(recv_stream, ip_socket,&internal_nat_manager).await{
|
||||
log::error!("quic_stream_uni_handle: {e:?}");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn quic_stream_bi_handle(
|
||||
ip_stack: Option<IpStack>,
|
||||
mut send_stream: SendStream,
|
||||
mut recv_stream: RecvStream,
|
||||
internal_nat_manager: &Option<InternalNatInbound>,
|
||||
port_mapping_manager: PortMappingManager,
|
||||
) -> anyhow::Result<()> {
|
||||
let handshake = recv_handshake(&mut recv_stream).await?;
|
||||
let Some(handshake) = handshake.handshake else {
|
||||
return Ok(());
|
||||
};
|
||||
match handshake {
|
||||
Handshake::Tcp(handshake) => {
|
||||
let src = SocketAddr::new(
|
||||
Ipv4Addr::from(handshake.src_ip).into(),
|
||||
handshake.src_port as _,
|
||||
);
|
||||
let dst_ip = Ipv4Addr::from(handshake.dst_ip);
|
||||
let dst = SocketAddr::new(dst_ip.into(), handshake.dst_port as _);
|
||||
if src == dst {
|
||||
bail!("tcp handshake failed, ip: {}", src);
|
||||
}
|
||||
log::debug!("accept TCP stream {src}->{dst}");
|
||||
// 如果不是网段内的,并且启用了内置nat,则直接转发
|
||||
if let Some(internal_nat_manager) = internal_nat_manager {
|
||||
if internal_nat_manager.use_nat(&dst_ip) {
|
||||
internal_nat_manager
|
||||
.tcp_nat(recv_stream, send_stream, dst_ip, dst.port())
|
||||
.await?;
|
||||
return Ok(());
|
||||
}
|
||||
if internal_nat_manager.no_tun() {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
if let Some(ip_stack) = ip_stack {
|
||||
let stream = tcp_ip::tcp::TcpStream::bind(ip_stack, src)?
|
||||
.connect_to(dst)
|
||||
.await?;
|
||||
let (mut tcp_w, mut tcp_r) = stream.split()?;
|
||||
tokio::select! {
|
||||
_ = tokio::io::copy(&mut recv_stream, &mut tcp_w) => {},
|
||||
_ = tokio::io::copy(&mut tcp_r, &mut send_stream) => {},
|
||||
}
|
||||
log::debug!("accept close TCP stream {src}->{dst}");
|
||||
}
|
||||
}
|
||||
Handshake::Ip(_) => {}
|
||||
Handshake::TcpPortMapping(handshake) => {
|
||||
port_mapping_manager
|
||||
.tcp_mapping(
|
||||
recv_stream,
|
||||
send_stream,
|
||||
handshake.dst_host,
|
||||
handshake.dst_port as _,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
Handshake::UdpPortMapping(handshake) => {
|
||||
port_mapping_manager
|
||||
.udp_mapping(
|
||||
recv_stream,
|
||||
send_stream,
|
||||
handshake.dst_host,
|
||||
handshake.dst_port as _,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn recv_handshake(recv_stream: &mut RecvStream) -> anyhow::Result<QuicProxyHandshake> {
|
||||
let len = recv_stream.read_u16().await?;
|
||||
let mut buf = vec![0u8; len as usize];
|
||||
recv_stream.read_exact(&mut buf).await?;
|
||||
let handshake = QuicProxyHandshake::decode(&buf[..])?;
|
||||
Ok(handshake)
|
||||
}
|
||||
async fn quic_stream_uni_handle(
|
||||
mut recv_stream: RecvStream,
|
||||
ip_socket: Option<Arc<IpSocket>>,
|
||||
internal_nat_manager: &Option<InternalNatInbound>,
|
||||
) -> anyhow::Result<()> {
|
||||
let handshake = recv_handshake(&mut recv_stream).await?;
|
||||
let Some(handshake) = handshake.handshake else {
|
||||
return Ok(());
|
||||
};
|
||||
match handshake {
|
||||
Handshake::Tcp(_) => {}
|
||||
Handshake::Ip(handshake) => {
|
||||
let ip_next_header_protocol =
|
||||
IpNextHeaderProtocol::new(handshake.ip_next_header_protocol as _);
|
||||
let src_ip = Ipv4Addr::from(handshake.src_ip);
|
||||
let dest_ip = Ipv4Addr::from(handshake.dst_ip);
|
||||
log::debug!("recv IP({ip_next_header_protocol}) packet {src_ip}->{dest_ip}");
|
||||
let mut framed_read = FramedRead::new(recv_stream, LengthDelimitedCodec::new());
|
||||
// 如果不是网段内的,并且启用了内置nat,则直接转发
|
||||
if let Some(internal_nat_manager) = internal_nat_manager {
|
||||
if internal_nat_manager.use_nat(&dest_ip) {
|
||||
loop {
|
||||
let buf = framed_read
|
||||
.next()
|
||||
.await
|
||||
.context("receive quic stream failed")??;
|
||||
internal_nat_manager
|
||||
.send_ipv4_payload(ip_next_header_protocol, src_ip, dest_ip, buf)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
if internal_nat_manager.no_tun() {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
let Some(ip_socket) = ip_socket else {
|
||||
return Ok(());
|
||||
};
|
||||
let src_ip = src_ip.into();
|
||||
let dest_ip = dest_ip.into();
|
||||
loop {
|
||||
let buf = framed_read
|
||||
.next()
|
||||
.await
|
||||
.context("receive quic stream failed")??;
|
||||
|
||||
ip_socket
|
||||
.send_protocol_from_to(&buf, ip_next_header_protocol, src_ip, dest_ip)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
Handshake::TcpPortMapping(_) => {}
|
||||
Handshake::UdpPortMapping(_) => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user