use std::io; use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; use std::sync::Arc; use std::time::Duration; use crossbeam_utils::atomic::AtomicCell; use dashmap::DashMap; use parking_lot::Mutex; use rand::Rng; use std::net::UdpSocket; use tokio::net::TcpStream; use tokio::sync::mpsc::channel; use crate::channel::channel::{Channel, Context}; use crate::channel::idle::Idle; use crate::channel::punch::{NatInfo, Punch, PunchModel}; use crate::channel::sender::ChannelSender; use crate::channel::{Route, RouteKey}; use crate::cipher::{Cipher, CipherModel, RsaCipher}; use crate::core::status::VntStatusManger; use crate::error::Error; use crate::external_route::{AllowExternalRoute, ExternalRoute}; use crate::handle::handshake_handler::HandshakeEnum; use crate::handle::recv_handler::ChannelDataHandler; use crate::handle::registration_handler::{RegResponse, ReqEnum}; #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))] use crate::handle::tun_tap::tap_handler; use crate::handle::tun_tap::tun_handler; use crate::handle::{ handshake_handler, heartbeat_handler, punch_handler, registration_handler, ConnectStatus, CurrentDeviceInfo, PeerDeviceInfo, }; use crate::igmp_server::IgmpServer; use crate::ip_proxy::DashMapNew; use crate::nat::NatTest; use crate::tun_tap_device; use crate::tun_tap_device::{DeviceReader, DeviceWriter}; pub mod status; pub mod sync; #[derive(Clone)] pub struct Vnt { config: Config, current_device: Arc>, context: Context, vnt_status_manager: VntStatusManger, device_writer: DeviceWriter, /// 0. 机器纪元,每一次上线或者下线都会增1,用于感知网络中机器变化 /// 服务端和客户端的不一致,则服务端会推送新的设备列表 /// 1. 网络中的虚拟ip列表 device_list: Arc)>>, nat_test: NatTest, connect_status: Arc>, peer_nat_info_map: Arc>, } pub struct VntUtil { config: Config, main_channel: UdpSocket, main_channel_ipv6: Option, main_tcp_channel: Option, response: Option, iface: Option<(DeviceWriter, DeviceReader)>, server_cipher: Cipher, rsa_cipher: Option, } impl VntUtil { pub async fn new(config: Config) -> io::Result { //单个udp用同步的性能更好,但是代理和多端口监听用异步更方便,这里将两者结合起来 let main_channel = UdpSocket::bind("0.0.0.0:0")?; main_channel.set_write_timeout(Some(Duration::from_secs(5)))?; main_channel.set_read_timeout(Some(Duration::from_secs(2)))?; let main_channel_ipv6 = if config.punch_model != PunchModel::IPv4 { match UdpSocket::bind("[::]:0") { Ok(main_channel_ipv6) => { main_channel_ipv6.set_write_timeout(Some(Duration::from_secs(5)))?; Some(main_channel_ipv6) } Err(e) => { log::warn!("绑定ipv6地址失败:{}", e); None } } } else { None }; let server_cipher = if config.server_encrypt { let mut key = [0 as u8; 32]; rand::thread_rng().fill(&mut key); Cipher::new_key(key, config.token.clone())? } else { Cipher::None }; Ok(VntUtil { config, main_channel, main_channel_ipv6, main_tcp_channel: None, response: None, iface: None, server_cipher, rsa_cipher: None, }) } ///链接 pub async fn connect(&mut self) -> io::Result<()> { if self.config.tcp { let tcp = TcpStream::connect(self.config.server_address).await?; let _ = self.main_tcp_channel.insert(tcp); } Ok(()) } ///握手 用于获取公钥 pub async fn handshake(&mut self) -> Result, HandshakeEnum> { let rsa_cipher = handshake_handler::handshake( &self.main_channel, self.main_tcp_channel.as_mut(), self.config.server_address, self.config.server_encrypt, ) .await?; self.rsa_cipher = rsa_cipher.clone(); Ok(rsa_cipher) } /// 加密握手 用于同步密钥 pub async fn secret_handshake(&mut self) -> Result<(), HandshakeEnum> { handshake_handler::secret_handshake( &self.main_channel, self.main_tcp_channel.as_mut(), self.config.server_address, self.rsa_cipher.as_ref().unwrap(), &self.server_cipher, self.config.token.clone(), ) .await } /// 注册 pub async fn register(&mut self) -> Result { match registration_handler::registration( &self.main_channel, self.main_tcp_channel.as_mut(), &self.server_cipher, self.config.server_address, self.config.token.clone(), self.config.device_id.clone(), self.config.name.clone(), self.config.ip.unwrap_or(Ipv4Addr::UNSPECIFIED), self.config.password.is_some(), ) .await { Ok(res) => { let _ = self.response.insert(res.clone()); Ok(res) } Err(e) => Err(e), } } #[cfg(any(target_os = "android"))] pub fn create_iface(&mut self, vpn_fd: i32) { let (device_writer, device_reader) = tun_tap_device::create(vpn_fd); let _ = self.iface.insert((device_writer, device_reader)); } #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))] pub fn create_iface(&mut self) -> io::Result { if self.iface.is_some() { return Err(io::Error::from(io::ErrorKind::AlreadyExists)); } let response = match &self.response { None => { return Err(io::Error::from(io::ErrorKind::AlreadyExists)); } Some(res) => res, }; let device_type = if self.config.tap { { //删除tun网卡避免ip冲突,因为非正常退出会保留网卡 tun_tap_device::delete_device(tun_tap_device::DeviceType::Tun); } tun_tap_device::DeviceType::Tap } else { { //删除tap网卡避免ip冲突,非正常退出会保留网卡 tun_tap_device::delete_device(tun_tap_device::DeviceType::Tap); } tun_tap_device::DeviceType::Tun }; let mtu = match self.config.mtu { None => { if self.config.password.is_none() { 1450 } else { 1410 } } Some(mtu) => mtu, }; let in_ips = self .config .in_ips .iter() .map(|(dest, mask, _)| (Ipv4Addr::from(*dest & *mask), Ipv4Addr::from(*mask))) .collect::>(); let (device_writer, device_reader, driver_info) = tun_tap_device::create_device( device_type, response.virtual_ip, response.virtual_netmask, response.virtual_gateway, in_ips, mtu, )?; let _ = self.iface.insert((device_writer, device_reader)); Ok(driver_info) } pub async fn build(self) -> crate::Result { //将读的超时时间清空 self.main_channel.set_read_timeout(None)?; let response = match self.response { None => { return Err(Error::Stop("response None".to_string())); } Some(res) => res, }; let (device_writer, device_reader) = match self.iface { None => { return Err(Error::Stop("iface None".to_string())); } Some(res) => res, }; let config = self.config.clone(); let vnt_status_manager = VntStatusManger::new(); 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 virtual_ip = response.virtual_ip; let virtual_gateway = response.virtual_gateway; let virtual_netmask = response.virtual_netmask; let current_device = Arc::new(AtomicCell::new(CurrentDeviceInfo::new( virtual_ip, virtual_gateway, virtual_netmask, config.server_address, ))); let (cone_sender, cone_receiver) = channel(3); let (symmetric_sender, symmetric_receiver) = channel(2); let (tcp_sender, tcp) = if let Some(main_tcp_channel) = self.main_tcp_channel { let (tcp_sender, tcp_receiver) = channel::>(100); (Some(tcp_sender), Some((main_tcp_channel, tcp_receiver))) } else { (None, None) }; let context = Context::new( Arc::new(self.main_channel), self.main_channel_ipv6.map(|v| Arc::new(v)), tcp_sender, current_device.clone(), 1, ); let punch = Punch::new(context.clone(), config.punch_model); let idle = Idle::new(Duration::from_secs(16), context.clone()); let channel_sender = ChannelSender::new(context.clone()); let register = Arc::new(registration_handler::Register::new( self.server_cipher.clone(), channel_sender.clone(), config.server_address, config.token.clone(), config.device_id.clone(), config.name.clone(), config.password.is_some(), )); let device_list: Arc)>> = Arc::new(Mutex::new((response.epoch, response.device_info_list))); let peer_nat_info_map: Arc> = Arc::new(DashMap::new0()); let connect_status = Arc::new(AtomicCell::new(ConnectStatus::Connected)); let public_ip = response.public_ip; let public_port = response.public_port; let local_port = context.main_local_ipv4_port().unwrap_or(0); let local_ipv4_addr = crate::nat::local_ipv4_addr(local_port); let ipv6_port = context.main_local_ipv6_port().unwrap_or(0); let ipv6_addr = crate::nat::local_ipv6_addr(ipv6_port); // NAT检测 let nat_test = NatTest::new( config.stun_server.clone(), public_ip, public_port, local_ipv4_addr, ipv6_addr, ); let in_external_route = if config.in_ips.is_empty() { None } else { Some(ExternalRoute::new(config.in_ips)) }; let (tcp_proxy, udp_proxy, ip_proxy_map) = if config.out_ips.is_empty() { (None, None, None) } else { let (tcp_proxy, udp_proxy, ip_proxy_map) = crate::ip_proxy::init_proxy( #[cfg(not(target_os = "android"))] channel_sender.clone(), #[cfg(not(target_os = "android"))] current_device.clone(), #[cfg(not(target_os = "android"))] client_cipher.clone(), ) .await?; (Some(tcp_proxy), Some(udp_proxy), Some(ip_proxy_map)) }; let out_external_route = AllowExternalRoute::new(config.out_ips); let igmp_server = if config.simulate_multicast { Some(IgmpServer::new(device_writer.clone())) } else { None }; #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))] if config.tap { tap_handler::start( vnt_status_manager.worker("tap_handler"), channel_sender.clone(), device_reader, device_writer.clone(), igmp_server.clone(), current_device.clone(), in_external_route, ip_proxy_map.clone(), client_cipher.clone(), self.server_cipher.clone(), config.parallel, ); } else { tun_handler::start( vnt_status_manager.worker("tun_handler"), channel_sender.clone(), device_reader, device_writer.clone(), igmp_server.clone(), current_device.clone(), in_external_route, ip_proxy_map.clone(), client_cipher.clone(), self.server_cipher.clone(), config.parallel, ); } #[cfg(any(target_os = "android"))] tun_handler::start( vnt_status_manager.worker("android tun_handler"), channel_sender.clone(), device_reader, device_writer.clone(), igmp_server.clone(), current_device.clone(), in_external_route, ip_proxy_map.clone(), client_cipher.clone(), self.server_cipher.clone(), config.parallel, ); //外部数据接收处理 let channel_recv_handler = ChannelDataHandler::new( current_device.clone(), device_list.clone(), register.clone(), nat_test.clone(), igmp_server, device_writer.clone(), connect_status.clone(), peer_nat_info_map.clone(), ip_proxy_map, out_external_route, cone_sender, symmetric_sender, client_cipher.clone(), self.server_cipher.clone(), self.rsa_cipher.clone(), config.relay, config.token.clone(), ); { let channel = Channel::new(context.clone(), channel_recv_handler); let channel_worker = vnt_status_manager.worker("channel_worker"); let relay = config.relay; tokio::spawn(async move { channel .start(channel_worker, tcp, 14, 65, relay, config.parallel) .await }); } { let nat_test = nat_test.clone(); let device_list = device_list.clone(); let current_device = current_device.clone(); // 定时心跳 heartbeat_handler::start_heartbeat( vnt_status_manager.worker("heartbeat"), channel_sender.clone(), device_list.clone(), current_device.clone(), config.server_address_str, client_cipher.clone(), self.server_cipher.clone(), ); // 空闲检查 heartbeat_handler::start_idle( vnt_status_manager.worker("idle"), idle, channel_sender.clone(), ); if !config.relay { // 打洞处理 punch_handler::start( vnt_status_manager.worker("cone_receiver"), cone_receiver, punch.clone(), current_device.clone(), client_cipher.clone(), ); punch_handler::start( vnt_status_manager.worker("symmetric_receiver"), symmetric_receiver, punch, current_device.clone(), client_cipher.clone(), ); tokio::spawn(punch_handler::start_punch( vnt_status_manager.worker("punch_handler"), nat_test, device_list, channel_sender, current_device, client_cipher.clone(), )); } } { //代理 if let Some(tcp_proxy) = tcp_proxy { tokio::spawn(tcp_proxy.start()); } if let Some(udp_proxy) = udp_proxy { tokio::spawn(udp_proxy.start()); } let context = context.clone(); let nat_test = nat_test.clone(); tokio::spawn(async move { let info = nat_test .re_test(public_ip, public_port, local_ipv4_addr, ipv6_addr) .await; context.switch(info.nat_type); }); } Ok(Vnt { config: self.config, current_device, context, vnt_status_manager, device_writer, nat_test, device_list, connect_status, peer_nat_info_map, }) } } 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 current_device(&self) -> CurrentDeviceInfo { self.current_device.load() } pub fn peer_nat_info(&self, ip: &Ipv4Addr) -> Option { self.peer_nat_info_map.get(ip).map(|e| e.value().clone()) } pub fn connection_status(&self) -> ConnectStatus { self.connect_status.load() } pub fn nat_info(&self) -> NatInfo { self.nat_test.nat_info() } pub fn device_list(&self) -> Vec { 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 { self.context.route_one(ip) } pub fn route_key(&self, route_key: &RouteKey) -> Option { self.context.route_to_id(route_key) } pub fn route_table(&self) -> Vec<(Ipv4Addr, Route)> { self.context.route_table_one() } pub fn stop(&self) -> io::Result<()> { let _ = self.context.close(); self.vnt_status_manager.stop_all(); let _ = self.device_writer.close(); let virtual_gateway = self.current_device.load().virtual_gateway; let _ = UdpSocket::bind("0.0.0.0:0")?.send_to( b"stop", SocketAddr::V4(SocketAddrV4::new(virtual_gateway, 10000)), ); Ok(()) } pub async fn wait_stop(&mut self) { self.vnt_status_manager.wait().await; let _ = self.stop(); } pub async fn wait_stop_ms(&mut self, ms: Duration) -> bool { tokio::select! { _=self.vnt_status_manager.wait()=>{ let _ = self.stop(); return true; } _=tokio::time::sleep(ms)=>{ return false; } } } } impl Drop for Vnt { fn drop(&mut self) { let _ = self.stop(); } } #[derive(Clone, Debug)] pub struct Config { pub tap: bool, pub token: String, pub device_id: String, pub name: String, pub server_address: SocketAddr, pub server_address_str: String, pub stun_server: Vec, pub in_ips: Vec<(u32, u32, Ipv4Addr)>, pub out_ips: Vec<(u32, u32)>, pub password: Option, pub simulate_multicast: bool, pub mtu: Option, pub tcp: bool, pub ip: Option, pub relay: bool, pub server_encrypt: bool, pub parallel: usize, pub cipher_model: CipherModel, pub finger: bool, pub punch_model: PunchModel, } impl Config { pub fn new( tap: bool, token: String, device_id: String, name: String, server_address: SocketAddr, server_address_str: String, mut stun_server: Vec, in_ips: Vec<(u32, u32, Ipv4Addr)>, out_ips: Vec<(u32, u32)>, password: Option, simulate_multicast: bool, mtu: Option, tcp: bool, ip: Option, relay: bool, server_encrypt: bool, parallel: usize, cipher_model: CipherModel, finger: bool, punch_model: PunchModel, ) -> Self { for x in stun_server.iter_mut() { if !x.contains(":") { x.push_str(":3478"); } } Self { tap, token, device_id, name, server_address, server_address_str, stun_server, in_ips, out_ips, password, simulate_multicast, mtu, tcp, ip, relay, server_encrypt, parallel, cipher_model, finger, punch_model, } } }