支持无tun模式
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
[package]
|
||||
name = "vn-link"
|
||||
version = "1.2.10"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
lwip-rs = { git = "https://github.com/lbl8603/lwip-rs" }
|
||||
vnt = { path = "../vnt", package = "vnt", default-features = false }
|
||||
log = "0.4.17"
|
||||
anyhow = "1.0.82"
|
||||
parking_lot = "0.12.1"
|
||||
|
||||
tokio = { version = "1.37.0", features = ["full"] }
|
||||
crossbeam-utils = "0.8"
|
||||
|
||||
[features]
|
||||
default = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "port_mapping", "lz4_compress"]
|
||||
openssl = ["vnt/openssl"]
|
||||
openssl-vendored = ["vnt/openssl-vendored"]
|
||||
ring-cipher = ["vnt/ring-cipher"]
|
||||
aes_cbc = ["vnt/aes_cbc"]
|
||||
aes_ecb = ["vnt/aes_ecb"]
|
||||
sm4_cbc = ["vnt/sm4_cbc"]
|
||||
aes_gcm = ["vnt/aes_gcm"]
|
||||
chacha20_poly1305 = ["vnt/chacha20_poly1305"]
|
||||
server_encrypt = ["vnt/server_encrypt"]
|
||||
port_mapping = ["vnt/port_mapping"]
|
||||
lz4_compress = ["vnt/lz4_compress"]
|
||||
zstd_compress = ["vnt/zstd_compress"]
|
||||
@@ -0,0 +1,85 @@
|
||||
use anyhow::Context;
|
||||
use std::net::SocketAddr;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct VnLinkConfig {
|
||||
pub mapping: Vec<LinkItem>,
|
||||
}
|
||||
|
||||
impl VnLinkConfig {
|
||||
pub fn new(mapping: Vec<LinkItem>) -> Self {
|
||||
Self { mapping }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
pub enum LinkProtocol {
|
||||
Tcp,
|
||||
Udp,
|
||||
}
|
||||
|
||||
impl LinkProtocol {
|
||||
pub fn is_tcp(&self) -> bool {
|
||||
self == &LinkProtocol::Tcp
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct LinkItem {
|
||||
pub protocol: LinkProtocol,
|
||||
pub src_port: u16,
|
||||
pub dest: SocketAddr,
|
||||
}
|
||||
|
||||
impl LinkItem {
|
||||
pub fn new(protocol: LinkProtocol, src_port: u16, dest: SocketAddr) -> Self {
|
||||
Self {
|
||||
protocol,
|
||||
src_port,
|
||||
dest,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn convert(vec: Vec<String>) -> anyhow::Result<Vec<LinkItem>> {
|
||||
let mut rs = Vec::with_capacity(vec.len());
|
||||
for x in vec {
|
||||
let string = x.trim().to_lowercase();
|
||||
if let Some(udp_mapping) = string.strip_prefix("udp:") {
|
||||
let mut split = udp_mapping.split("-");
|
||||
let bind_port = split
|
||||
.next()
|
||||
.with_context(|| format!("vnt-mapping error {:?},eg: udp:80-10.26.0.10:8080", x))?;
|
||||
let bind_port = u16::from_str(bind_port)
|
||||
.with_context(|| format!("udp_mapping error {}", bind_port))?;
|
||||
let dest = split
|
||||
.next()
|
||||
.with_context(|| format!("vnt-mapping error {:?},eg: udp:80-10.26.0.10:8080", x))?;
|
||||
let dest_addr = SocketAddr::from_str(dest)
|
||||
.with_context(|| format!("udp_mapping error {}", dest))?;
|
||||
rs.push(LinkItem::new(LinkProtocol::Udp, bind_port, dest_addr));
|
||||
continue;
|
||||
}
|
||||
if let Some(tcp_mapping) = string.strip_prefix("tcp:") {
|
||||
let mut split = tcp_mapping.split("-");
|
||||
let bind_port = split
|
||||
.next()
|
||||
.with_context(|| format!("vnt-mapping error {:?},eg: tcp:80-10.26.0.10:8080", x))?;
|
||||
let bind_port = u16::from_str(bind_port)
|
||||
.with_context(|| format!("tcp_mapping error {}", bind_port))?;
|
||||
let dest = split
|
||||
.next()
|
||||
.with_context(|| format!("vnt-mapping error {:?},eg: tcp:80-10.26.0.10:8080", x))?;
|
||||
let dest_addr = SocketAddr::from_str(dest)
|
||||
.with_context(|| format!("tcp_mapping error {}", dest))?;
|
||||
rs.push(LinkItem::new(LinkProtocol::Tcp, bind_port, dest_addr));
|
||||
continue;
|
||||
}
|
||||
Err(anyhow::anyhow!(
|
||||
"vnt-mapping error {:?},eg: tcp:80-10.26.0.10:8080",
|
||||
x
|
||||
))?;
|
||||
}
|
||||
Ok(rs)
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
pub mod tcp;
|
||||
pub mod udp;
|
||||
@@ -0,0 +1,46 @@
|
||||
use crate::out_mapping::tcp::tcp_copy;
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use lwip_rs::tcp_stream::TcpStream as LwIpTcpStream;
|
||||
use std::net::{IpAddr, SocketAddr};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tokio::net::TcpListener;
|
||||
use vnt::handle::CurrentDeviceInfo;
|
||||
|
||||
pub async fn tcp_mapping_listen(
|
||||
tcp_listener: TcpListener,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
dest: SocketAddr,
|
||||
) {
|
||||
loop {
|
||||
let (stream, addr) = match tcp_listener.accept().await {
|
||||
Ok((stream, addr)) => (stream, addr),
|
||||
Err(e) => {
|
||||
log::warn!("tcp_mapping_listen {:?} dest {}", e, dest);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let current_info = current_device.load();
|
||||
if current_info.virtual_ip.is_unspecified() {
|
||||
continue;
|
||||
}
|
||||
if let IpAddr::V4(ip) = dest.ip() {
|
||||
if ip == current_info.virtual_ip {
|
||||
//防止用错参数的
|
||||
log::warn!("目的地址不能是本地虚拟ip tcp->{}", dest);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
let src = SocketAddr::new(IpAddr::V4(current_info.virtual_ip), addr.port());
|
||||
tokio::spawn(async move {
|
||||
match LwIpTcpStream::connect(src, dest, Duration::from_secs(5)).await {
|
||||
Ok(lw_tcp) => {
|
||||
tcp_copy(lw_tcp, stream);
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("{} {}->{} {}", addr, src, dest, e);
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
use std::collections::HashMap;
|
||||
use std::net::{IpAddr, SocketAddr};
|
||||
use std::sync::Arc;
|
||||
use std::time::Instant;
|
||||
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use parking_lot::Mutex;
|
||||
use tokio::net::UdpSocket;
|
||||
|
||||
use lwip_rs::udp::UdpSocketWrite;
|
||||
use vnt::handle::CurrentDeviceInfo;
|
||||
|
||||
pub async fn udp_mapping_start(
|
||||
udp: UdpSocket,
|
||||
lwip_udp_write: UdpSocketWrite,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
in_udp_map: &Arc<
|
||||
Mutex<
|
||||
HashMap<
|
||||
(SocketAddr, SocketAddr),
|
||||
(Arc<UdpSocket>, Option<SocketAddr>, Arc<AtomicCell<Instant>>),
|
||||
>,
|
||||
>,
|
||||
>,
|
||||
|
||||
dest: SocketAddr,
|
||||
) {
|
||||
let udp = Arc::new(udp);
|
||||
let mut buf = [0u8; 65536];
|
||||
loop {
|
||||
let (len, addr) = match udp.recv_from(&mut buf).await {
|
||||
Ok(rs) => rs,
|
||||
Err(e) => {
|
||||
log::warn!("recv_from {} {}", dest, e);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let current_info = current_device.load();
|
||||
if current_info.virtual_ip.is_unspecified() {
|
||||
continue;
|
||||
}
|
||||
if let IpAddr::V4(ip) = dest.ip() {
|
||||
if ip == current_info.virtual_ip {
|
||||
//防止用错参数的
|
||||
log::warn!("目的地址不能是本地虚拟ip udp->{}", dest);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
let src = SocketAddr::new(IpAddr::V4(current_info.virtual_ip), addr.port());
|
||||
in_udp_map.lock().insert(
|
||||
(dest, src),
|
||||
(
|
||||
udp.clone(),
|
||||
Some(addr),
|
||||
Arc::new(AtomicCell::new(Instant::now())),
|
||||
),
|
||||
);
|
||||
|
||||
if let Err(e) = lwip_udp_write.send(&buf[..len], &src, &dest) {
|
||||
log::warn!("lwip_udp_write {}->{} {}", src, dest, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
pub mod config;
|
||||
mod in_mapping;
|
||||
mod out_mapping;
|
||||
mod vnt_link;
|
||||
|
||||
pub use vnt;
|
||||
|
||||
pub use vnt_link::*;
|
||||
@@ -0,0 +1,2 @@
|
||||
pub mod tcp;
|
||||
pub mod udp;
|
||||
@@ -0,0 +1,64 @@
|
||||
use std::net::{IpAddr, Ipv4Addr};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use tokio::net::TcpStream;
|
||||
|
||||
use lwip_rs::tcp_listener::TcpListener;
|
||||
use lwip_rs::tcp_stream::TcpStream as LwIpTcpStream;
|
||||
use vnt::handle::CurrentDeviceInfo;
|
||||
|
||||
pub async fn tcp_mapping_listen(
|
||||
mut tcp_listener: TcpListener,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
) {
|
||||
loop {
|
||||
let stream = match tcp_listener.accept().await {
|
||||
Ok(stream) => stream,
|
||||
Err(e) => {
|
||||
log::warn!("tcp_mapping_listen err {:?}", e);
|
||||
break;
|
||||
}
|
||||
};
|
||||
let device_info = current_device.load();
|
||||
tokio::spawn(async move {
|
||||
let dest = stream.dest_addr();
|
||||
let src = stream.src_addr();
|
||||
if let Err(e) = tcp_mapping_handle(stream, device_info).await {
|
||||
log::warn!("tcp_mapping_handle {}->{} {:?}", src, dest, e)
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async fn tcp_mapping_handle(
|
||||
tcp_stream: LwIpTcpStream,
|
||||
device_info: CurrentDeviceInfo,
|
||||
) -> anyhow::Result<()> {
|
||||
let mut dest = tcp_stream.dest_addr();
|
||||
// let src = tcp_stream.src_addr();
|
||||
if let IpAddr::V4(ip) = dest.ip() {
|
||||
if ip.is_unspecified()
|
||||
|| ip.is_broadcast()
|
||||
|| ip.is_multicast()
|
||||
|| ip == device_info.virtual_ip
|
||||
|| ip == device_info.broadcast_ip
|
||||
{
|
||||
//是自己
|
||||
dest.set_ip(IpAddr::V4(Ipv4Addr::LOCALHOST));
|
||||
}
|
||||
}
|
||||
let peer_stream = TcpStream::connect(dest).await?;
|
||||
if dest.port() == peer_stream.local_addr()?.port() {
|
||||
return Err(anyhow::anyhow!("tcp port loop"));
|
||||
}
|
||||
tcp_copy(tcp_stream, peer_stream);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tcp_copy(lw_tcp: LwIpTcpStream, tokio_tcp: TcpStream) {
|
||||
let (mut write, mut read) = lw_tcp.into_split();
|
||||
let (mut peer_read, mut peer_write) = tokio_tcp.into_split();
|
||||
tokio::spawn(async move { tokio::io::copy(&mut read, &mut peer_write).await });
|
||||
tokio::spawn(async move { tokio::io::copy(&mut peer_read, &mut write).await });
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use lwip_rs::udp::{UdpSocketRead, UdpSocketWrite};
|
||||
use parking_lot::Mutex;
|
||||
use std::collections::HashMap;
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
use tokio::net::UdpSocket;
|
||||
use vnt::handle::CurrentDeviceInfo;
|
||||
|
||||
pub async fn udp_mapping_start(
|
||||
lwip_udp_write: UdpSocketWrite,
|
||||
mut lwip_udp_read: UdpSocketRead,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
in_udp_map: Arc<
|
||||
Mutex<
|
||||
HashMap<
|
||||
(SocketAddr, SocketAddr),
|
||||
(Arc<UdpSocket>, Option<SocketAddr>, Arc<AtomicCell<Instant>>),
|
||||
>,
|
||||
>,
|
||||
>,
|
||||
) {
|
||||
loop {
|
||||
let (buf, src, dest) = match lwip_udp_read.recv().await {
|
||||
Ok(rs) => rs,
|
||||
Err(e) => {
|
||||
log::warn!("udp_mapping err {:?}", e);
|
||||
break;
|
||||
}
|
||||
};
|
||||
if let Err(e) = handle(
|
||||
¤t_device,
|
||||
&lwip_udp_write,
|
||||
&in_udp_map,
|
||||
buf,
|
||||
src,
|
||||
dest,
|
||||
)
|
||||
.await
|
||||
{
|
||||
log::warn!("udp_mapping err {}->{} {:?}", src, dest, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle(
|
||||
current_device: &AtomicCell<CurrentDeviceInfo>,
|
||||
lwip_udp_write: &UdpSocketWrite,
|
||||
map: &Arc<
|
||||
Mutex<
|
||||
HashMap<
|
||||
(SocketAddr, SocketAddr),
|
||||
(Arc<UdpSocket>, Option<SocketAddr>, Arc<AtomicCell<Instant>>),
|
||||
>,
|
||||
>,
|
||||
>,
|
||||
buf: Vec<u8>,
|
||||
src: SocketAddr,
|
||||
dest: SocketAddr,
|
||||
) -> anyhow::Result<()> {
|
||||
let option = map.lock().get(&(src, dest)).cloned();
|
||||
|
||||
if let Some((dest_udp, addr, time)) = option {
|
||||
time.store(Instant::now());
|
||||
if let Some(addr) = addr {
|
||||
dest_udp.send_to(&buf, addr).await?;
|
||||
} else {
|
||||
dest_udp.send(&buf).await?;
|
||||
}
|
||||
} else {
|
||||
let mut real_dest = dest;
|
||||
let peer_udp_socket = match UdpSocket::bind(format!("0.0.0.0:{}", src.port())).await {
|
||||
Ok(udp) => udp,
|
||||
Err(_) => UdpSocket::bind("0.0.0.0:0").await?,
|
||||
};
|
||||
if let IpAddr::V4(ip) = dest.ip() {
|
||||
let device_info = current_device.load();
|
||||
if ip.is_unspecified()
|
||||
|| ip.is_broadcast()
|
||||
|| ip.is_multicast()
|
||||
|| ip == device_info.virtual_ip
|
||||
|| ip == device_info.broadcast_ip
|
||||
{
|
||||
//是自己
|
||||
real_dest.set_ip(IpAddr::V4(Ipv4Addr::LOCALHOST));
|
||||
}
|
||||
}
|
||||
peer_udp_socket.connect(real_dest).await?;
|
||||
peer_udp_socket.send(&buf).await?;
|
||||
let peer_udp_socket = Arc::new(peer_udp_socket);
|
||||
let time = Arc::new(AtomicCell::new(Instant::now()));
|
||||
let map = map.clone();
|
||||
map.lock()
|
||||
.insert((src, dest), (peer_udp_socket.clone(), None, time.clone()));
|
||||
let lwip_udp_write = lwip_udp_write.clone();
|
||||
tokio::spawn(async move {
|
||||
peer_udp_handle(peer_udp_socket, lwip_udp_write, src, dest, time).await;
|
||||
map.lock().remove(&(src, dest));
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn peer_udp_handle(
|
||||
peer_udp_socket: Arc<UdpSocket>,
|
||||
lwip_udp_write: UdpSocketWrite,
|
||||
src: SocketAddr,
|
||||
dest: SocketAddr,
|
||||
time: Arc<AtomicCell<Instant>>,
|
||||
) {
|
||||
let mut buf = [0u8; 65536];
|
||||
loop {
|
||||
match tokio::time::timeout(Duration::from_secs(600), peer_udp_socket.recv(&mut buf)).await {
|
||||
Ok(rs) => match rs {
|
||||
Ok(len) => match lwip_udp_write.send(&buf[..len], &dest, &src) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
log::warn!("udp proxy {}->{} {:?}", dest, src, e);
|
||||
break;
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
log::warn!("udp proxy {}->{} {:?}", dest, src, e);
|
||||
break;
|
||||
}
|
||||
},
|
||||
Err(_) => {
|
||||
if time.load().elapsed() > Duration::from_secs(580) {
|
||||
//超时关闭
|
||||
log::warn!("udp proxy timeout {}->{}", dest, src,);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
use std::collections::HashMap;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
use std::time::Instant;
|
||||
|
||||
use anyhow::Context;
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use parking_lot::Mutex;
|
||||
use tokio::net::{TcpListener, UdpSocket};
|
||||
use tokio::sync::watch::{channel, Sender};
|
||||
|
||||
use lwip_rs::stack::{NetStack, NetStackWrite};
|
||||
use lwip_rs::tcp_listener::TcpListener as LwIPTcpListener;
|
||||
use lwip_rs::udp::{UdpSocket as LwIpUdpSocket, UdpSocketWrite};
|
||||
use vnt::channel::BUFFER_SIZE;
|
||||
use vnt::core::{Config, Vnt};
|
||||
use vnt::packet::ip::ipv4::packet::IpV4Packet;
|
||||
use vnt::protocol::HEAD_LEN;
|
||||
use vnt::vnt_device::DeviceWrite;
|
||||
use vnt::VntCallback;
|
||||
|
||||
use crate::config::{LinkItem, LinkProtocol, VnLinkConfig};
|
||||
use crate::{in_mapping, out_mapping};
|
||||
|
||||
pub struct VnLink {
|
||||
vnt: Vnt,
|
||||
in_udp_map: Arc<
|
||||
Mutex<
|
||||
HashMap<
|
||||
(SocketAddr, SocketAddr),
|
||||
(Arc<UdpSocket>, Option<SocketAddr>, Arc<AtomicCell<Instant>>),
|
||||
>,
|
||||
>,
|
||||
>,
|
||||
lwip_udp_write: UdpSocketWrite,
|
||||
shutdown_tx: Sender<bool>,
|
||||
}
|
||||
|
||||
impl VnLink {
|
||||
pub async fn new<Call: VntCallback>(
|
||||
vnt_config: Config,
|
||||
vn_link_config: VnLinkConfig,
|
||||
callback: Call,
|
||||
) -> anyhow::Result<Self> {
|
||||
let stack = NetStack::new(HEAD_LEN, 1024, vnt_config.mtu.unwrap_or(1420) as u16).await;
|
||||
let udp = LwIpUdpSocket::new()?;
|
||||
let tcp_listener = LwIPTcpListener::new()?;
|
||||
let (shutdown_tx, shutdown_rx) = channel(false);
|
||||
let (net_stack_write, mut net_stack_read) = stack.into_split();
|
||||
let vnt = Vnt::new_device(vnt_config, callback, VntDevice { net_stack_write })?;
|
||||
let shutdown_tx_ = shutdown_tx.clone();
|
||||
let w = vnt.add_stop_listener("vnt-link".into(), move || {
|
||||
let _ = shutdown_tx_.send(true);
|
||||
})?;
|
||||
let ip_sender = vnt.ipv4_packet_sender().unwrap();
|
||||
let mut shutdown_rx_ = shutdown_rx.clone();
|
||||
tokio::spawn(async move {
|
||||
let mut extend = [0; BUFFER_SIZE];
|
||||
loop {
|
||||
tokio::select! {
|
||||
_ = shutdown_rx_.changed() => {
|
||||
break;
|
||||
}
|
||||
rs = net_stack_read.recv_ip() => {
|
||||
match rs{
|
||||
Ok((mut buf, start_index, len)) => {
|
||||
let ipv4_packet = if let Ok(packet) =
|
||||
IpV4Packet::new(&buf[start_index..len])
|
||||
{
|
||||
packet
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
let destination_ip = ipv4_packet.destination_ip();
|
||||
let source_ip = ipv4_packet.source_ip();
|
||||
|
||||
if let Err(e) = ip_sender.send_ip(&mut buf, len, &mut extend, destination_ip) {
|
||||
log::warn!("{}->{},{}", source_ip, destination_ip, e);
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!("net_stack_read {:?}", e);
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
w.stop_all();
|
||||
});
|
||||
|
||||
let (lwip_udp_write, lwip_udp_read) = udp.into_split();
|
||||
let in_udp_map: Arc<
|
||||
Mutex<
|
||||
HashMap<
|
||||
(SocketAddr, SocketAddr),
|
||||
(Arc<UdpSocket>, Option<SocketAddr>, Arc<AtomicCell<Instant>>),
|
||||
>,
|
||||
>,
|
||||
> = Arc::new(Mutex::new(HashMap::new()));
|
||||
|
||||
let current_device_info = vnt.current_device_info();
|
||||
let in_udp_map_ = in_udp_map.clone();
|
||||
let lwip_udp_write_ = lwip_udp_write.clone();
|
||||
let vnt_ = vnt.clone();
|
||||
let mut shutdown_rx_ = shutdown_rx.clone();
|
||||
tokio::spawn(async move {
|
||||
tokio::select! {
|
||||
_ = shutdown_rx_.changed() => {}
|
||||
_ = out_mapping::udp::udp_mapping_start(
|
||||
lwip_udp_write_,
|
||||
lwip_udp_read,
|
||||
current_device_info,
|
||||
in_udp_map_,
|
||||
) => {}
|
||||
}
|
||||
|
||||
vnt_.stop();
|
||||
});
|
||||
let current_device_info = vnt.current_device_info();
|
||||
let vnt_ = vnt.clone();
|
||||
let mut shutdown_rx_ = shutdown_rx.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
tokio::select! {
|
||||
_ = shutdown_rx_.changed() => {}
|
||||
_ = out_mapping::tcp::tcp_mapping_listen(tcp_listener, current_device_info) => {}
|
||||
}
|
||||
vnt_.stop();
|
||||
});
|
||||
let link = Self {
|
||||
vnt,
|
||||
in_udp_map,
|
||||
lwip_udp_write,
|
||||
shutdown_tx,
|
||||
};
|
||||
link.add_mapping(vn_link_config.mapping).await?;
|
||||
Ok(link)
|
||||
}
|
||||
pub async fn add_mapping(&self, mapping: Vec<LinkItem>) -> anyhow::Result<()> {
|
||||
for item in mapping {
|
||||
let current_device_info = self.vnt.current_device_info();
|
||||
if item.dest.ip().is_unspecified() {
|
||||
Err(anyhow::anyhow!("dest_address {:?} is_unspecified", item))?
|
||||
}
|
||||
let mut shutdown_rx_ = self.shutdown_tx.subscribe();
|
||||
if *shutdown_rx_.borrow() {
|
||||
Err(anyhow::anyhow!("mapping stop"))?
|
||||
}
|
||||
if item.protocol == LinkProtocol::Udp {
|
||||
let lwip_udp_write = self.lwip_udp_write.clone();
|
||||
let in_udp_map = self.in_udp_map.clone();
|
||||
//只能本机访问,不然不同IP的相同来源端口会有问题
|
||||
let udp = UdpSocket::bind(format!("127.0.0.1:{}", item.src_port))
|
||||
.await
|
||||
.with_context(|| format!("udp bind failed {}", item.src_port))?;
|
||||
tokio::spawn(async move {
|
||||
tokio::select! {
|
||||
_ = shutdown_rx_.changed() => {}
|
||||
_ = in_mapping::udp::udp_mapping_start(
|
||||
udp,
|
||||
lwip_udp_write,
|
||||
current_device_info,
|
||||
&in_udp_map,
|
||||
item.dest,
|
||||
) => {}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
let listener = TcpListener::bind(format!("127.0.0.1:{}", item.src_port))
|
||||
.await
|
||||
.with_context(|| format!("tcp bind failed {}", item.src_port))?;
|
||||
tokio::spawn(async move {
|
||||
tokio::select! {
|
||||
_ = shutdown_rx_.changed() => {}
|
||||
_ = in_mapping::tcp::tcp_mapping_listen(
|
||||
listener,
|
||||
current_device_info,
|
||||
item.dest,
|
||||
) => {}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub fn stop(&self) {
|
||||
self.as_vnt().stop()
|
||||
}
|
||||
pub async fn wait(&self) {
|
||||
loop {
|
||||
let mut receiver = self.shutdown_tx.subscribe();
|
||||
if *receiver.borrow() {
|
||||
return;
|
||||
}
|
||||
if receiver.changed().await.is_err() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_vnt(&self) -> &Vnt {
|
||||
&self.vnt
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct VntDevice {
|
||||
net_stack_write: NetStackWrite,
|
||||
}
|
||||
|
||||
impl DeviceWrite for VntDevice {
|
||||
fn write(&self, buf: &[u8]) -> std::io::Result<usize> {
|
||||
self.net_stack_write.send_ip(buf)?;
|
||||
Ok(buf.len())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user