445 lines
14 KiB
Rust
445 lines
14 KiB
Rust
use std::collections::HashMap;
|
|
use std::net::Ipv4Addr;
|
|
use std::sync::Arc;
|
|
use std::time::Duration;
|
|
|
|
use crossbeam_utils::atomic::AtomicCell;
|
|
use parking_lot::{Mutex, RwLock};
|
|
use rand::Rng;
|
|
|
|
use crate::channel::context::ChannelContext;
|
|
use crate::channel::idle::Idle;
|
|
use crate::channel::punch::{NatInfo, Punch};
|
|
use crate::channel::{init_channel, init_context, Route, RouteKey};
|
|
use crate::cipher::Cipher;
|
|
#[cfg(feature = "server_encrypt")]
|
|
use crate::cipher::RsaCipher;
|
|
use crate::core::Config;
|
|
use crate::external_route::{AllowExternalRoute, ExternalRoute};
|
|
use crate::handle::handshaker::Handshake;
|
|
use crate::handle::maintain::PunchReceiver;
|
|
use crate::handle::recv_data::RecvDataHandler;
|
|
use crate::handle::{maintain, BaseConfigInfo, ConnectStatus, CurrentDeviceInfo, PeerDeviceInfo};
|
|
use crate::nat::NatTest;
|
|
#[cfg(feature = "inner_tun")]
|
|
use crate::tun_tap_device::tun_create_helper::{DeviceAdapter, TunDeviceHelper};
|
|
use crate::tun_tap_device::vnt_device::DeviceWrite;
|
|
use crate::util::{
|
|
Scheduler, SingleU64Adder, StopManager, U64Adder, WatchSingleU64Adder, WatchU64Adder,
|
|
};
|
|
use crate::{nat, VntCallback};
|
|
|
|
#[derive(Clone)]
|
|
pub struct Vnt {
|
|
stop_manager: StopManager,
|
|
config: Config,
|
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
|
nat_test: NatTest,
|
|
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
|
context: Arc<Mutex<Option<ChannelContext>>>,
|
|
peer_nat_info_map: Arc<RwLock<HashMap<Ipv4Addr, NatInfo>>>,
|
|
down_count_watcher: WatchU64Adder,
|
|
up_count_watcher: WatchSingleU64Adder,
|
|
client_secret_hash: Option<[u8; 16]>,
|
|
}
|
|
|
|
impl Vnt {
|
|
#[cfg(feature = "inner_tun")]
|
|
pub fn new<Call: VntCallback>(config: Config, callback: Call) -> anyhow::Result<Self> {
|
|
Vnt::new_device0(config, callback, DeviceAdapter::default())
|
|
}
|
|
#[cfg(not(feature = "inner_tun"))]
|
|
pub fn new_device<Call: VntCallback, Device: DeviceWrite>(
|
|
config: Config,
|
|
callback: Call,
|
|
device: Device,
|
|
) -> anyhow::Result<Self> {
|
|
Vnt::new_device0(config, callback, device)
|
|
}
|
|
fn new_device0<Call: VntCallback, Device: DeviceWrite>(
|
|
config: Config,
|
|
callback: Call,
|
|
device: Device,
|
|
) -> anyhow::Result<Self> {
|
|
log::info!("config.toml:{:?}", config);
|
|
//服务端非对称加密
|
|
#[cfg(feature = "server_encrypt")]
|
|
let rsa_cipher: Arc<Mutex<Option<RsaCipher>>> = Arc::new(Mutex::new(None));
|
|
//服务端对称加密
|
|
let server_cipher: Cipher = if config.server_encrypt {
|
|
let mut key = [0u8; 32];
|
|
rand::thread_rng().fill(&mut key);
|
|
Cipher::new_key(key, config.token.clone())?
|
|
} else {
|
|
Cipher::None
|
|
};
|
|
let finger = if config.finger {
|
|
Some(config.token.clone())
|
|
} else {
|
|
None
|
|
};
|
|
//客户端对称加密
|
|
let client_cipher =
|
|
Cipher::new_password(config.cipher_model, config.password.clone(), finger)?;
|
|
//当前设备信息
|
|
let current_device = Arc::new(AtomicCell::new(CurrentDeviceInfo::new0(
|
|
config.server_address,
|
|
)));
|
|
//设备列表
|
|
let device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>> =
|
|
Arc::new(Mutex::new((0, Vec::with_capacity(16))));
|
|
//基础信息
|
|
let config_info = BaseConfigInfo::new(
|
|
config.name.clone(),
|
|
config.token.clone(),
|
|
config.ip,
|
|
config.password_hash(),
|
|
config.server_encrypt,
|
|
config.device_id.clone(),
|
|
config.server_address_str.clone(),
|
|
config.name_servers.clone(),
|
|
config.mtu.unwrap_or(1420),
|
|
#[cfg(target_os = "windows")]
|
|
config.tap,
|
|
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
|
config.device_name.clone(),
|
|
);
|
|
// 服务停止管理器
|
|
let stop_manager = {
|
|
let callback = callback.clone();
|
|
StopManager::new(move || callback.stop())
|
|
};
|
|
#[cfg(feature = "port_mapping")]
|
|
crate::port_mapping::start_port_mapping(
|
|
stop_manager.clone(),
|
|
config.port_mapping_list.clone(),
|
|
)?;
|
|
let mut ports = config.ports.as_ref().map_or(vec![0, 0], |v| {
|
|
if v.is_empty() {
|
|
vec![0, 0]
|
|
} else {
|
|
v.clone()
|
|
}
|
|
});
|
|
if config.use_channel_type.is_only_relay() {
|
|
//中继模式下只监听一个端口就够了
|
|
ports.truncate(1);
|
|
}
|
|
//通道上下文
|
|
let (context, tcp_listener) = init_context(
|
|
ports,
|
|
config.use_channel_type,
|
|
config.first_latency,
|
|
config.tcp,
|
|
config.packet_loss_rate,
|
|
config.packet_delay,
|
|
)?;
|
|
let local_ipv4 = nat::local_ipv4();
|
|
let local_ipv6 = nat::local_ipv6();
|
|
let udp_ports = context.main_local_udp_port()?;
|
|
let tcp_port = tcp_listener.local_addr()?.port();
|
|
//nat检测工具
|
|
let nat_test = NatTest::new(
|
|
context.channel_num(),
|
|
config.stun_server.clone(),
|
|
local_ipv4,
|
|
local_ipv6,
|
|
udp_ports,
|
|
tcp_port,
|
|
);
|
|
// 定时器
|
|
let scheduler = Scheduler::new(stop_manager.clone())?;
|
|
let external_route = ExternalRoute::new(config.in_ips.clone());
|
|
let out_external_route = AllowExternalRoute::new(config.out_ips.clone());
|
|
|
|
#[cfg(feature = "ip_proxy")]
|
|
let proxy_map = if !config.out_ips.is_empty() && !config.no_proxy {
|
|
Some(crate::ip_proxy::init_proxy(
|
|
context.clone(),
|
|
stop_manager.clone(),
|
|
current_device.clone(),
|
|
client_cipher.clone(),
|
|
)?)
|
|
} else {
|
|
None
|
|
};
|
|
let (punch_sender, punch_receiver) = maintain::punch_channel();
|
|
let peer_nat_info_map: Arc<RwLock<HashMap<Ipv4Addr, NatInfo>>> =
|
|
Arc::new(RwLock::new(HashMap::with_capacity(16)));
|
|
let down_counter =
|
|
U64Adder::with_capacity(config.ports.as_ref().map(|v| v.len()).unwrap_or_default() + 8);
|
|
let down_count_watcher = down_counter.watch();
|
|
let handshake = Handshake::new(
|
|
#[cfg(feature = "server_encrypt")]
|
|
rsa_cipher.clone(),
|
|
);
|
|
let up_counter = SingleU64Adder::new();
|
|
let up_count_watcher = up_counter.watch();
|
|
#[cfg(feature = "inner_tun")]
|
|
let tun_device_helper = {
|
|
TunDeviceHelper::new(
|
|
stop_manager.clone(),
|
|
context.clone(),
|
|
current_device.clone(),
|
|
external_route.clone(),
|
|
#[cfg(feature = "ip_proxy")]
|
|
proxy_map.clone(),
|
|
client_cipher.clone(),
|
|
server_cipher.clone(),
|
|
up_counter,
|
|
device_list.clone(),
|
|
config.compressor,
|
|
device.clone().into_device_adapter(),
|
|
)
|
|
};
|
|
|
|
let handler = RecvDataHandler::new(
|
|
#[cfg(feature = "server_encrypt")]
|
|
rsa_cipher,
|
|
server_cipher.clone(),
|
|
client_cipher.clone(),
|
|
current_device.clone(),
|
|
device,
|
|
device_list.clone(),
|
|
config_info.clone(),
|
|
nat_test.clone(),
|
|
callback.clone(),
|
|
punch_sender,
|
|
peer_nat_info_map.clone(),
|
|
external_route.clone(),
|
|
out_external_route,
|
|
#[cfg(feature = "ip_proxy")]
|
|
proxy_map.clone(),
|
|
down_counter,
|
|
handshake.clone(),
|
|
#[cfg(feature = "inner_tun")]
|
|
tun_device_helper,
|
|
);
|
|
|
|
//初始化网络数据通道
|
|
let (udp_socket_sender, tcp_socket_sender) =
|
|
init_channel(tcp_listener, context.clone(), stop_manager.clone(), handler)?;
|
|
// 打洞逻辑
|
|
let punch = Punch::new(
|
|
context.clone(),
|
|
config.punch_model,
|
|
config.tcp,
|
|
tcp_socket_sender.clone(),
|
|
external_route.clone(),
|
|
nat_test.clone(),
|
|
);
|
|
|
|
// #[cfg(not(target_os = "android"))]
|
|
// tun_helper.start(device)?;
|
|
|
|
maintain::idle_gateway(
|
|
&scheduler,
|
|
context.clone(),
|
|
current_device.clone(),
|
|
config_info.clone(),
|
|
tcp_socket_sender.clone(),
|
|
callback.clone(),
|
|
0,
|
|
handshake,
|
|
);
|
|
{
|
|
let context = context.clone();
|
|
let nat_test = nat_test.clone();
|
|
let device_list = device_list.clone();
|
|
let down_count_watcher = down_count_watcher.clone();
|
|
let up_count_watcher = up_count_watcher.clone();
|
|
let config_info = config_info.clone();
|
|
let current_device = current_device.clone();
|
|
if !config.use_channel_type.is_only_relay() {
|
|
// 定时nat探测
|
|
maintain::retrieve_nat_type(
|
|
&scheduler,
|
|
context.clone(),
|
|
nat_test.clone(),
|
|
udp_socket_sender,
|
|
);
|
|
}
|
|
//延迟启动
|
|
scheduler.timeout(Duration::from_secs(3), move |scheduler| {
|
|
start(
|
|
scheduler,
|
|
context,
|
|
nat_test,
|
|
device_list,
|
|
current_device,
|
|
client_cipher,
|
|
server_cipher,
|
|
punch_receiver,
|
|
config_info,
|
|
punch,
|
|
callback,
|
|
down_count_watcher,
|
|
up_count_watcher,
|
|
);
|
|
});
|
|
}
|
|
|
|
Ok(Self {
|
|
stop_manager,
|
|
config,
|
|
current_device,
|
|
nat_test,
|
|
device_list,
|
|
context: Arc::new(Mutex::new(Some(context))),
|
|
peer_nat_info_map,
|
|
down_count_watcher,
|
|
up_count_watcher,
|
|
client_secret_hash: config_info.client_secret_hash,
|
|
})
|
|
}
|
|
}
|
|
|
|
pub fn start<Call: VntCallback>(
|
|
scheduler: &Scheduler,
|
|
context: ChannelContext,
|
|
nat_test: NatTest,
|
|
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
|
client_cipher: Cipher,
|
|
server_cipher: Cipher,
|
|
punch_receiver: PunchReceiver,
|
|
config_info: BaseConfigInfo,
|
|
punch: Punch,
|
|
callback: Call,
|
|
down_count_watcher: WatchU64Adder,
|
|
up_count_watcher: WatchSingleU64Adder,
|
|
) {
|
|
// 定时心跳
|
|
maintain::heartbeat(
|
|
&scheduler,
|
|
context.clone(),
|
|
current_device.clone(),
|
|
device_list.clone(),
|
|
client_cipher.clone(),
|
|
server_cipher.clone(),
|
|
);
|
|
// 路由空闲检测逻辑
|
|
let idle = Idle::new(Duration::from_secs(10), context.clone());
|
|
// 定时空闲检查
|
|
maintain::idle_route(
|
|
&scheduler,
|
|
idle,
|
|
context.clone(),
|
|
current_device.clone(),
|
|
callback,
|
|
);
|
|
// 定时客户端中继检测
|
|
if !context.use_channel_type().is_only_p2p() {
|
|
maintain::client_relay(
|
|
&scheduler,
|
|
context.clone(),
|
|
current_device.clone(),
|
|
device_list.clone(),
|
|
client_cipher.clone(),
|
|
);
|
|
}
|
|
|
|
if !context.use_channel_type().is_only_relay() {
|
|
// 定时地址探测
|
|
maintain::addr_request(
|
|
&scheduler,
|
|
context.clone(),
|
|
current_device.clone(),
|
|
server_cipher.clone(),
|
|
nat_test.clone(),
|
|
config_info.clone(),
|
|
);
|
|
// 定时打洞
|
|
maintain::punch(
|
|
&scheduler,
|
|
context.clone(),
|
|
nat_test.clone(),
|
|
device_list.clone(),
|
|
current_device.clone(),
|
|
client_cipher.clone(),
|
|
punch_receiver,
|
|
punch,
|
|
);
|
|
}
|
|
maintain::up_status(
|
|
scheduler,
|
|
context.clone(),
|
|
current_device.clone(),
|
|
down_count_watcher,
|
|
up_count_watcher,
|
|
)
|
|
}
|
|
|
|
impl Vnt {
|
|
pub fn name(&self) -> &str {
|
|
&self.config.name
|
|
}
|
|
pub fn server_encrypt(&self) -> bool {
|
|
self.config.server_encrypt
|
|
}
|
|
pub fn client_encrypt(&self) -> bool {
|
|
self.config.password.is_some()
|
|
}
|
|
pub fn client_encrypt_hash(&self) -> Option<&[u8]> {
|
|
self.client_secret_hash.as_ref().map(|v| v.as_ref())
|
|
}
|
|
pub fn current_device(&self) -> CurrentDeviceInfo {
|
|
self.current_device.load()
|
|
}
|
|
pub fn peer_nat_info(&self, ip: &Ipv4Addr) -> Option<NatInfo> {
|
|
self.peer_nat_info_map.read().get(ip).cloned()
|
|
}
|
|
pub fn connection_status(&self) -> ConnectStatus {
|
|
self.current_device.load().status
|
|
}
|
|
pub fn nat_info(&self) -> NatInfo {
|
|
self.nat_test.nat_info()
|
|
}
|
|
pub fn device_list(&self) -> Vec<PeerDeviceInfo> {
|
|
let device_list_lock = self.device_list.lock();
|
|
let (_epoch, device_list) = device_list_lock.clone();
|
|
drop(device_list_lock);
|
|
device_list
|
|
}
|
|
pub fn route(&self, ip: &Ipv4Addr) -> Option<Route> {
|
|
self.context.lock().as_ref()?.route_table.route_one(ip)
|
|
}
|
|
pub fn is_gateway(&self, ip: &Ipv4Addr) -> bool {
|
|
self.current_device.load().is_gateway(ip)
|
|
}
|
|
pub fn route_key(&self, route_key: &RouteKey) -> Option<Ipv4Addr> {
|
|
self.context
|
|
.lock()
|
|
.as_ref()?
|
|
.route_table
|
|
.route_to_id(route_key)
|
|
}
|
|
pub fn route_table(&self) -> Vec<(Ipv4Addr, Vec<Route>)> {
|
|
if let Some(context) = self.context.lock().as_ref() {
|
|
context.route_table.route_table()
|
|
} else {
|
|
vec![]
|
|
}
|
|
}
|
|
pub fn up_stream(&self) -> u64 {
|
|
self.up_count_watcher.get()
|
|
}
|
|
pub fn down_stream(&self) -> u64 {
|
|
self.down_count_watcher.get()
|
|
}
|
|
pub fn stop(&self) {
|
|
//退出协助回收资源
|
|
let _ = self.context.lock().take();
|
|
self.stop_manager.stop()
|
|
}
|
|
pub fn wait(&self) {
|
|
self.stop_manager.wait()
|
|
}
|
|
pub fn wait_timeout(&self, dur: Duration) -> bool {
|
|
self.stop_manager.wait_timeout(dur)
|
|
}
|
|
pub fn config(&self) -> &Config {
|
|
&self.config
|
|
}
|
|
}
|